/* * Cypress APA trackpad with I2C interface * * Author: Dudley Du <dudl@cypress.com> * Further cleanup and restructuring by: * Daniel Kurtz <djkurtz@chromium.org> * Benson Leung <bleung@chromium.org> * * Copyright (C) 2011-2015 Cypress Semiconductor, Inc. * Copyright (C) 2011-2012 Google, 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.
*/
/* * CYAPA trackpad device states. * Used in register 0x00, bit1-0, DeviceStatus field. * Other values indicate device is in an abnormal state and must be reset.
*/ #define CYAPA_DEV_NORMAL 0x03 #define CYAPA_DEV_BUSY 0x01
struct cyapa_touch { /* * high bits or x/y position value * bit 7 - 4: high 4 bits of x position value * bit 3 - 0: high 4 bits of y position value
*/
u8 xy_hi;
u8 x_lo; /* low 8 bits of x position value. */
u8 y_lo; /* low 8 bits of y position value. */
u8 pressure; /* id range is 1 - 15. It is incremented with every new touch. */
u8 id;
} __packed;
struct cyapa_reg_data { /* * bit 0 - 1: device status * bit 3 - 2: power mode * bit 6 - 4: reserved * bit 7: interrupt valid bit
*/
u8 device_status; /* * bit 7 - 4: number of fingers currently touching pad * bit 3: valid data check bit * bit 2: middle mechanism button state if exists * bit 1: right mechanism button state if exists * bit 0: left mechanism button state if exists
*/
u8 finger_btn; /* CYAPA reports up to 5 touches per packet. */ struct cyapa_touch touches[5];
} __packed;
/* * cyapa_smbus_read_block - perform smbus block read command * @cyapa - private data structure of the driver * @cmd - the properly encoded smbus command * @len - expected length of smbus command result * @values - buffer to store smbus command result * * Returns negative errno, else the number of bytes written. * * Note: * In trackpad device, the memory block allocated for I2C register map * is 256 bytes, so the max read block for I2C bus is 256 bytes.
*/
ssize_t cyapa_smbus_read_block(struct cyapa *cyapa, u8 cmd, size_t len,
u8 *values)
{
ssize_t ret;
u8 index;
u8 smbus_cmd;
u8 *buf; struct i2c_client *client = cyapa->client;
if (!(SMBUS_BYTE_BLOCK_CMD_MASK & cmd)) return -EINVAL;
if (SMBUS_GROUP_BLOCK_CMD_MASK & cmd) { /* read specific block registers command. */
smbus_cmd = SMBUS_ENCODE_RW(cmd, SMBUS_READ);
ret = i2c_smbus_read_block_data(client, smbus_cmd, values); goto out;
}
ret = 0; for (index = 0; index * I2C_SMBUS_BLOCK_MAX < len; index++) {
smbus_cmd = SMBUS_ENCODE_IDX(cmd, index);
smbus_cmd = SMBUS_ENCODE_RW(smbus_cmd, SMBUS_READ);
buf = values + I2C_SMBUS_BLOCK_MAX * index;
ret = i2c_smbus_read_block_data(client, smbus_cmd, buf); if (ret < 0) goto out;
}
/* * Enter bootloader by soft resetting the device. * * If device is already in the bootloader, the function just returns. * Otherwise, reset the device; after reset, device enters bootloader idle * state immediately. * * Returns: * 0 on success * -EAGAIN device was reset, but is not now in bootloader idle state * < 0 if the device never responds within the timeout
*/ staticint cyapa_gen3_bl_enter(struct cyapa *cyapa)
{ int error; int waiting_time;
error = cyapa_poll_state(cyapa, 500); if (error) return error; if (cyapa->state == CYAPA_STATE_BL_IDLE) { /* Already in BL_IDLE. Skipping reset. */ return 0;
}
if (cyapa->state != CYAPA_STATE_OP) return -EAGAIN;
usleep_range(25000, 50000);
waiting_time = 2000; /* For some shipset, max waiting time is 1~2s. */ do {
error = cyapa_poll_state(cyapa, 500); if (error) { if (error == -ETIMEDOUT) {
waiting_time -= 500; continue;
} return error;
}
if ((cyapa->state == CYAPA_STATE_BL_IDLE) &&
!(cyapa->status[REG_BL_STATUS] & BL_STATUS_WATCHDOG)) break;
msleep(100);
waiting_time -= 100;
} while (waiting_time > 0);
if ((cyapa->state != CYAPA_STATE_BL_IDLE) ||
(cyapa->status[REG_BL_STATUS] & BL_STATUS_WATCHDOG)) return -EAGAIN;
return 0;
}
staticint cyapa_gen3_bl_activate(struct cyapa *cyapa)
{ int error;
error = cyapa_i2c_reg_write_block(cyapa, 0, sizeof(bl_activate),
bl_activate); if (error) return error;
/* Wait for bootloader to activate; takes between 2 and 12 seconds */
msleep(2000);
error = cyapa_poll_state(cyapa, 11000); if (error) return error; if (cyapa->state != CYAPA_STATE_BL_ACTIVE) return -EAGAIN;
return 0;
}
staticint cyapa_gen3_bl_deactivate(struct cyapa *cyapa)
{ int error;
error = cyapa_i2c_reg_write_block(cyapa, 0, sizeof(bl_deactivate),
bl_deactivate); if (error) return error;
/* Wait for bootloader to switch to idle state; should take < 100ms */
msleep(100);
error = cyapa_poll_state(cyapa, 500); if (error) return error; if (cyapa->state != CYAPA_STATE_BL_IDLE) return -EAGAIN; return 0;
}
/* * Exit bootloader * * Send bl_exit command, then wait 50 - 100 ms to let device transition to * operational mode. If this is the first time the device's firmware is * running, it can take up to 2 seconds to calibrate its sensors. So, poll * the device's new state for up to 2 seconds. * * Returns: * -EIO failure while reading from device * -EAGAIN device is stuck in bootloader, b/c it has invalid firmware * 0 device is supported and in operational mode
*/ staticint cyapa_gen3_bl_exit(struct cyapa *cyapa)
{ int error;
error = cyapa_i2c_reg_write_block(cyapa, 0, sizeof(bl_exit), bl_exit); if (error) return error;
/* * Wait for bootloader to exit, and operation mode to start. * Normally, this takes at least 50 ms.
*/
msleep(50); /* * In addition, when a device boots for the first time after being * updated to new firmware, it must first calibrate its sensors, which * can take up to an additional 2 seconds. If the device power is * running low, this may take even longer.
*/
error = cyapa_poll_state(cyapa, 4000); if (error < 0) return error; if (cyapa->state != CYAPA_STATE_OP) return -EAGAIN;
/* * Verify the integrity of a CYAPA firmware image file. * * The firmware image file is 30848 bytes, composed of 482 64-byte blocks. * * The first 2 blocks are the firmware header. * The next 480 blocks are the firmware image. * * The first two bytes of the header hold the header checksum, computed by * summing the other 126 bytes of the header. * The last two bytes of the header hold the firmware image checksum, computed * by summing the 30720 bytes of the image modulo 0xffff. * * Both checksums are stored little-endian.
*/ staticint cyapa_gen3_check_fw(struct cyapa *cyapa, conststruct firmware *fw)
{ struct device *dev = &cyapa->client->dev;
u16 csum;
u16 csum_expected;
/* Firmware must match exact 30848 bytes = 482 64-byte blocks. */ if (fw->size != CYAPA_FW_SIZE) {
dev_err(dev, "invalid firmware size = %zu, expected %u.\n",
fw->size, CYAPA_FW_SIZE); return -EINVAL;
}
/* * Write a |len| byte long buffer |buf| to the device, by chopping it up into a * sequence of smaller |CYAPA_CMD_LEN|-length write commands. * * The data bytes for a write command are prepended with the 1-byte offset * of the data relative to the start of |buf|.
*/ staticint cyapa_gen3_write_buffer(struct cyapa *cyapa, const u8 *buf, size_t len)
{ int error;
size_t i; unsignedchar cmd[CYAPA_CMD_LEN + 1];
size_t cmd_len;
for (i = 0; i < len; i += CYAPA_CMD_LEN) { const u8 *payload = &buf[i];
cmd_len = (len - i >= CYAPA_CMD_LEN) ? CYAPA_CMD_LEN : len - i;
cmd[0] = i;
memcpy(&cmd[1], payload, cmd_len);
/* * A firmware block write command writes 64 bytes of data to a single flash * page in the device. The 78-byte block write command has the format: * <0xff> <CMD> <Key> <Start> <Data> <Data-Checksum> <CMD Checksum> * * <0xff> - every command starts with 0xff * <CMD> - the write command value is 0x39 * <Key> - write commands include an 8-byte key: { 00 01 02 03 04 05 06 07 } * <Block> - Memory Block number (address / 64) (16-bit, big-endian) * <Data> - 64 bytes of firmware image data * <Data Checksum> - sum of 64 <Data> bytes, modulo 0xff * <CMD Checksum> - sum of 77 bytes, from 0xff to <Data Checksum> * * Each write command is split into 5 i2c write transactions of up to 16 bytes. * Each transaction starts with an i2c register offset: (00, 10, 20, 30, 40).
*/ staticint cyapa_gen3_write_fw_block(struct cyapa *cyapa,
u16 block, const u8 *data)
{ int ret; struct gen3_write_block_cmd write_block_cmd;
u8 status[BL_STATUS_SIZE]; int tries;
u8 bl_status, bl_error;
ret = cyapa_read_byte(cyapa, CYAPA_CMD_DEV_STATUS); if (ret < 0) {
dev_err(dev, "Error reading dev status: %d\n", ret); goto out;
} if ((ret & CYAPA_DEV_NORMAL) != CYAPA_DEV_NORMAL) {
dev_warn(dev, "Trackpad device is busy, device state: 0x%02x\n",
ret);
ret = -EAGAIN; goto out;
}
ret = cyapa_write_byte(cyapa, CYAPA_CMD_SOFT_RESET,
OP_RECALIBRATION_MASK); if (ret < 0) {
dev_err(dev, "Failed to send calibrate command: %d\n",
ret); goto out;
}
/* max recalibration timeout 2s. */
timeout = jiffies + 2 * HZ; do { /* * For this recalibration, the max time will not exceed 2s. * The average time is approximately 500 - 700 ms, and we * will check the status every 100 - 200ms.
*/
msleep(100);
ret = cyapa_read_byte(cyapa, CYAPA_CMD_DEV_STATUS); if (ret < 0) {
dev_err(dev, "Error reading dev status: %d\n", ret); goto out;
} if ((ret & CYAPA_DEV_NORMAL) == CYAPA_DEV_NORMAL) {
dev_dbg(dev, "Calibration successful.\n"); goto out;
}
} while (time_is_after_jiffies(timeout));
dev_err(dev, "Failed to calibrate. Timeout.\n");
ret = -ETIMEDOUT;
out: return ret < 0 ? ret : count;
}
static ssize_t cyapa_gen3_show_baseline(struct device *dev, struct device_attribute *attr, char *buf)
{ struct cyapa *cyapa = dev_get_drvdata(dev); int max_baseline, min_baseline; int tries; int ret;
ret = cyapa_read_byte(cyapa, CYAPA_CMD_DEV_STATUS); if (ret < 0) {
dev_err(dev, "Error reading dev status. err = %d\n", ret); goto out;
} if ((ret & CYAPA_DEV_NORMAL) != CYAPA_DEV_NORMAL) {
dev_warn(dev, "Trackpad device is busy. device state = 0x%x\n",
ret);
ret = -EAGAIN; goto out;
}
ret = cyapa_write_byte(cyapa, CYAPA_CMD_SOFT_RESET,
OP_REPORT_BASELINE_MASK); if (ret < 0) {
dev_err(dev, "Failed to send report baseline command. %d\n",
ret); goto out;
}
tries = 3; /* Try for 30 to 60 ms */ do {
usleep_range(10000, 20000);
ret = cyapa_read_byte(cyapa, CYAPA_CMD_DEV_STATUS); if (ret < 0) {
dev_err(dev, "Error reading dev status. err = %d\n",
ret); goto out;
} if ((ret & CYAPA_DEV_NORMAL) == CYAPA_DEV_NORMAL) break;
} while (--tries);
if (tries == 0) {
dev_err(dev, "Device timed out going to Normal state.\n");
ret = -ETIMEDOUT; goto out;
}
ret = cyapa_read_byte(cyapa, CYAPA_CMD_MAX_BASELINE); if (ret < 0) {
dev_err(dev, "Failed to read max baseline. err = %d\n", ret); goto out;
}
max_baseline = ret;
ret = cyapa_read_byte(cyapa, CYAPA_CMD_MIN_BASELINE); if (ret < 0) {
dev_err(dev, "Failed to read min baseline. err = %d\n", ret); goto out;
}
min_baseline = ret;
/* * cyapa_get_wait_time_for_pwr_cmd * * Compute the amount of time we need to wait after updating the touchpad * power mode. The touchpad needs to consume the incoming power mode set * command at the current clock rate.
*/
static u16 cyapa_get_wait_time_for_pwr_cmd(u8 pwr_mode)
{ switch (pwr_mode) { case PWR_MODE_FULL_ACTIVE: return 20; case PWR_MODE_BTN_ONLY: return 20; case PWR_MODE_OFF: return 20; default: return cyapa_pwr_cmd_to_sleep_time(pwr_mode) + 50;
}
}
/* * Set device power mode * * Write to the field to configure power state. Power states include : * Full : Max scans and report rate. * Idle : Report rate set by user specified time. * ButtonOnly : No scans for fingers. When the button is triggered, * a slave interrupt is asserted to notify host to wake up. * Off : Only awake for i2c commands from host. No function for button * or touch sensors. * * The power_mode command should conform to the following : * Full : 0x3f * Idle : Configurable from 20 to 1000ms. See note below for * cyapa_sleep_time_to_pwr_cmd and cyapa_pwr_cmd_to_sleep_time * ButtonOnly : 0x01 * Off : 0x00 * * Device power mode can only be set when device is in operational mode.
*/ staticint cyapa_gen3_set_power_mode(struct cyapa *cyapa, u8 power_mode,
u16 always_unused, enum cyapa_pm_stage pm_stage)
{ struct input_dev *input = cyapa->input;
u8 power; int tries; int sleep_time; int interval; int ret;
if (cyapa->state != CYAPA_STATE_OP) return 0;
tries = SET_POWER_MODE_TRIES; while (tries--) {
ret = cyapa_read_byte(cyapa, CYAPA_CMD_POWER_MODE); if (ret >= 0) break;
usleep_range(SET_POWER_MODE_DELAY, 2 * SET_POWER_MODE_DELAY);
} if (ret < 0) return ret;
/* * Return early if the power mode to set is the same as the current * one.
*/ if ((ret & PWR_MODE_MASK) == power_mode) return 0;
sleep_time = (int)cyapa_get_wait_time_for_pwr_cmd(ret & PWR_MODE_MASK);
power = ret;
power &= ~PWR_MODE_MASK;
power |= power_mode & PWR_MODE_MASK;
tries = SET_POWER_MODE_TRIES; while (tries--) {
ret = cyapa_write_byte(cyapa, CYAPA_CMD_POWER_MODE, power); if (!ret) break;
usleep_range(SET_POWER_MODE_DELAY, 2 * SET_POWER_MODE_DELAY);
}
/* * Wait for the newly set power command to go in at the previous * clock speed (scanrate) used by the touchpad firmware. Not * doing so before issuing the next command may result in errors * depending on the command's content.
*/ if (cyapa->operational &&
input && input_device_enabled(input) &&
(pm_stage == CYAPA_PM_RUNTIME_SUSPEND ||
pm_stage == CYAPA_PM_RUNTIME_RESUME)) { /* Try to polling in 120Hz, read may fail, just ignore it. */
interval = 1000 / 120; while (sleep_time > 0) { if (sleep_time > interval)
msleep(interval); else
msleep(sleep_time);
sleep_time -= interval;
cyapa_gen3_try_poll_handler(cyapa);
}
} else {
msleep(sleep_time);
}
staticint cyapa_gen3_bl_query_data(struct cyapa *cyapa)
{
u8 bl_data[CYAPA_CMD_LEN]; int ret;
ret = cyapa_i2c_reg_read_block(cyapa, 0, CYAPA_CMD_LEN, bl_data); if (ret != CYAPA_CMD_LEN) return (ret < 0) ? ret : -EIO;
/* * This value will be updated again when entered application mode. * If TP failed to enter application mode, this fw version values * can be used as a reference. * This firmware version valid when fw image checksum is valid.
*/ if (bl_data[REG_BL_STATUS] ==
(BL_STATUS_RUNNING | BL_STATUS_CSUM_VALID)) {
cyapa->fw_maj_ver = bl_data[GEN3_BL_IDLE_FW_MAJ_VER_OFFSET];
cyapa->fw_min_ver = bl_data[GEN3_BL_IDLE_FW_MIN_VER_OFFSET];
}
return 0;
}
/* * Check if device is operational. * * An operational device is responding, has exited bootloader, and has * firmware supported by this driver. * * Returns: * -EBUSY no device or in bootloader * -EIO failure while reading from device * -EAGAIN device is still in bootloader * if ->state = CYAPA_STATE_BL_IDLE, device has invalid firmware * -EINVAL device is in operational mode, but not supported by this driver * 0 device is supported
*/ staticint cyapa_gen3_do_operational_check(struct cyapa *cyapa)
{ struct device *dev = &cyapa->client->dev; int error;
switch (cyapa->state) { case CYAPA_STATE_BL_ACTIVE:
error = cyapa_gen3_bl_deactivate(cyapa); if (error) {
dev_err(dev, "failed to bl_deactivate: %d\n", error); return error;
}
fallthrough; case CYAPA_STATE_BL_IDLE: /* Try to get firmware version in bootloader mode. */
cyapa_gen3_bl_query_data(cyapa);
error = cyapa_gen3_bl_exit(cyapa); if (error) {
dev_err(dev, "failed to bl_exit: %d\n", error); return error;
}
fallthrough; case CYAPA_STATE_OP: /* * Reading query data before going back to the full mode * may cause problems, so we set the power mode first here.
*/
error = cyapa_gen3_set_power_mode(cyapa,
PWR_MODE_FULL_ACTIVE, 0, CYAPA_PM_ACTIVE); if (error)
dev_err(dev, "%s: set full power mode failed: %d\n",
__func__, error);
error = cyapa_gen3_get_query_data(cyapa); if (error < 0) return error;
/* Only support firmware protocol gen3 */ if (cyapa->gen != CYAPA_GEN3) {
dev_err(dev, "unsupported protocol version (%d)",
cyapa->gen); return -EINVAL;
}
/* Only support product ID starting with CYTRA */ if (memcmp(cyapa->product_id, product_id,
strlen(product_id)) != 0) {
dev_err(dev, "unsupported product ID (%s)\n",
cyapa->product_id); return -EINVAL;
}
return 0;
default: return -EIO;
} return 0;
}
/* * Return false, do not continue process * Return true, continue process.
*/ staticbool cyapa_gen3_irq_cmd_handler(struct cyapa *cyapa)
{ /* Not gen3 irq command response, skip for continue. */ if (cyapa->gen != CYAPA_GEN3) returntrue;
if (cyapa->operational) returntrue;
/* * Driver in detecting or other interface function processing, * so, stop cyapa_gen3_irq_handler to continue process to * avoid unwanted to error detecting and processing. * * And also, avoid the periodically asserted interrupts to be processed * as touch inputs when gen3 failed to launch into application mode, * which will cause gen3 stays in bootloader mode.
*/ returnfalse;
}
staticint cyapa_gen3_event_process(struct cyapa *cyapa, struct cyapa_reg_data *data)
{ struct input_dev *input = cyapa->input; int num_fingers; int i;
num_fingers = (data->finger_btn >> 4) & 0x0f; for (i = 0; i < num_fingers; i++) { conststruct cyapa_touch *touch = &data->touches[i]; /* Note: touch->id range is 1 to 15; slots are 0 to 14. */ int slot = touch->id - 1;
/* * This function will be called in the cyapa_gen3_set_power_mode function, * and it's known that it may failed in some situation after the set power * mode command was sent. So this function is aimed to avoid the knwon * and unwanted output I2C and data parse error messages.
*/ staticint cyapa_gen3_try_poll_handler(struct cyapa *cyapa)
{ struct cyapa_reg_data data; int ret;
ret = cyapa_read_block(cyapa, CYAPA_CMD_GROUP_DATA, (u8 *)&data); if (ret != sizeof(data)) return -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.