/* * Cypress APA trackpad with I2C interface * * Author: Dudley Du <dudl@cypress.com> * * Copyright (C) 2015 Cypress Semiconductor, Inc. * * This file is subject to the terms and conditions of the GNU General Public * License. See the file COPYING in the main directory of this archive for * more details.
*/
struct pip_app_cmd_head {
__le16 addr;
__le16 length;
u8 report_id;
u8 resv; /* Reserved, must be 0 */
u8 cmd_code; /* bit7: resv, set to 0; bit6~0: command code.*/
} __packed;
struct pip_app_resp_head {
__le16 length;
u8 report_id;
u8 resv; /* Reserved, must be 0 */
u8 cmd_code; /* bit7: TGL; bit6~0: command code.*/ /* * The value of data_status can be the first byte of data or * the command status or the unsupported command code depending on the * requested command code.
*/
u8 data_status;
} __packed;
/* Get PIP fixed information to determine Gen5 or Gen6. */
memset(&pip_info, 0, sizeof(struct pip_fixed_info));
error = cyapa_get_pip_fixed_info(cyapa, &pip_info, is_bootloader); if (error) return error;
/* Get the real set intervals from response. */
interval_setting->active_interval = get_unaligned_le16(&resp_data[5]);
interval_setting->lp1_interval = get_unaligned_le16(&resp_data[7]);
interval_setting->lp2_interval = get_unaligned_le16(&resp_data[9]);
if (state == PIP_DEEP_SLEEP_STATE_ON) /* * Send ping command to notify device prepare for wake up * when it's in deep sleep mode. At this time, device will * response nothing except an I2C NAK.
*/
cyapa_i2c_pip_write(cyapa, ping, sizeof(ping));
if (cyapa->state != CYAPA_STATE_GEN6_APP) return 0;
if (PIP_DEV_GET_PWR_STATE(cyapa) == UNINIT_PWR_MODE) { /* * Assume TP in deep sleep mode when driver is loaded, * avoid driver unload and reload command IO issue caused by TP * has been set into deep sleep mode when unloading.
*/
PIP_DEV_SET_PWR_STATE(cyapa, PWR_MODE_OFF);
}
if (PIP_DEV_UNINIT_SLEEP_TIME(cyapa) &&
PIP_DEV_GET_PWR_STATE(cyapa) != PWR_MODE_OFF)
PIP_DEV_SET_SLEEP_TIME(cyapa, UNINIT_SLEEP_TIME);
if (PIP_DEV_GET_PWR_STATE(cyapa) == power_mode) { if (power_mode == PWR_MODE_OFF ||
power_mode == PWR_MODE_FULL_ACTIVE ||
power_mode == PWR_MODE_BTN_ONLY ||
PIP_DEV_GET_SLEEP_TIME(cyapa) == sleep_time) { /* Has in correct power mode state, early return. */ return 0;
}
}
if (power_mode == PWR_MODE_OFF) {
cyapa_gen6_config_dev_irq(cyapa, GEN6_DISABLE_CMD_IRQ);
error = cyapa_gen6_deep_sleep(cyapa, PIP_DEEP_SLEEP_STATE_OFF); if (error) {
dev_err(dev, "enter deep sleep fail: %d\n", error); return error;
}
/* * When trackpad in power off mode, it cannot change to other power * state directly, must be wake up from sleep firstly, then * continue to do next power sate change.
*/ if (PIP_DEV_GET_PWR_STATE(cyapa) == PWR_MODE_OFF) {
error = cyapa_gen6_deep_sleep(cyapa, PIP_DEEP_SLEEP_STATE_ON); if (error) {
dev_err(dev, "deep sleep wake fail: %d\n", error); return error;
}
}
/* * Disable device assert interrupts for command response to avoid * disturbing system suspending or hibernating process.
*/
cyapa_gen6_config_dev_irq(cyapa, GEN6_DISABLE_CMD_IRQ);
if (power_mode == PWR_MODE_FULL_ACTIVE) {
error = cyapa_gen6_change_power_state(cyapa,
GEN6_POWER_MODE_ACTIVE); if (error) {
dev_err(dev, "change to active fail: %d\n", error); goto out;
}
/* Sync the interval setting from device. */
cyapa_gen6_get_interval_setting(cyapa, interval_setting);
} elseif (power_mode == PWR_MODE_BTN_ONLY) {
error = cyapa_gen6_change_power_state(cyapa,
GEN6_POWER_MODE_BTN_ONLY); if (error) {
dev_err(dev, "fail to button only mode: %d\n", error); goto out;
}
PIP_DEV_SET_PWR_STATE(cyapa, PWR_MODE_BTN_ONLY);
} else { /* * Gen6 internally supports to 2 low power scan interval time, * so can help to switch power mode quickly. * such as runtime suspend and system suspend.
*/ if (interval_setting->lp1_interval == sleep_time) {
lp_mode = GEN6_POWER_MODE_LP_MODE1;
} elseif (interval_setting->lp2_interval == sleep_time) {
lp_mode = GEN6_POWER_MODE_LP_MODE2;
} else { if (interval_setting->lp1_interval == 0) {
interval_setting->lp1_interval = sleep_time;
lp_mode = GEN6_POWER_MODE_LP_MODE1;
} else {
interval_setting->lp2_interval = sleep_time;
lp_mode = GEN6_POWER_MODE_LP_MODE2;
}
cyapa_gen6_set_interval_setting(cyapa,
interval_setting);
}
error = cyapa_gen6_change_power_state(cyapa, lp_mode); if (error) {
dev_err(dev, "set power state to 0x%02x failed: %d\n",
lp_mode, error); goto out;
}
switch (cyapa->state) { case CYAPA_STATE_GEN6_BL:
error = cyapa_pip_bl_exit(cyapa); if (error) { /* Try to update trackpad product information. */
cyapa_gen6_bl_read_app_info(cyapa); goto out;
}
cyapa->state = CYAPA_STATE_GEN6_APP;
fallthrough;
case CYAPA_STATE_GEN6_APP: /* * If trackpad device in deep sleep mode, * the app command will fail. * So always try to reset trackpad device to full active when * the device state is required.
*/
error = cyapa_gen6_set_power_mode(cyapa,
PWR_MODE_FULL_ACTIVE, 0, CYAPA_PM_ACTIVE); if (error)
dev_warn(dev, "%s: failed to set power active mode.\n",
__func__);
/* By default, the trackpad proximity function is enabled. */
error = cyapa_pip_set_proximity(cyapa, true); if (error)
dev_warn(dev, "%s: failed to enable proximity.\n",
__func__);
/* Get trackpad product information. */
error = cyapa_gen6_read_sys_info(cyapa); if (error) goto out; /* Only support product ID starting with CYTRA */ if (memcmp(cyapa->product_id, product_id,
strlen(product_id)) != 0) {
dev_err(dev, "%s: unknown product ID (%s)\n",
__func__, cyapa->product_id);
error = -EINVAL;
} break; default:
error = -EINVAL;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.