/* * syntm12xx.c * Synaptic TM12XX touchscreen driver * * Copyright (C) 2009 Nokia Corporation * Author: Mika Kuoppala * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published by * the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along with * this program. If not, see . */ #include #include #include #include #include #include #include #include #ifdef CONFIG_HAS_EARLYSUSPEND #include #endif #include #define DRIVER_DESC "Synaptic TM12xx Touchscreen Driver" #define DRIVER_NAME "tm12xx_ts" /* Do validation of firmware image on device */ #define FIRMWARE_VERIFY /* Number of touch points and input devices supported */ #define MAX_TOUCH_POINTS 6 #define REG_PDT_PROPERTIES 0xef #define REG_PAGE_SELECT 0xff #define FUNC_DEVICE_CONTROL 0x01 #define FUNC_BIST 0x08 #define FUNC_2D 0x11 #define FUNC_BUTTONS 0x19 #define FUNC_TIMER 0x32 #define FUNC_FLASH 0x34 #define FUNC_PROXIMITY 0x40 #define MAX_FUNC_DESCS 7 /* Device Control Functionality */ #define DEVICE_CONTROL_DATA_STATUS 0x00 #define DEVICE_CONTROL_DATA_INTR_STATUS 0x01 #define DEVICE_CONTROL_STATUS_SCODE_MASK 0x0f #define STATUS_CODE_NO_ERROR 0x00 #define STATUS_CODE_RESET 0x01 #define STATUS_CODE_INVALID_CONF 0x02 #define STATUS_CODE_DEVICE_FAILURE 0x03 #define DEVICE_CONTROL_CTRL 0 #define DEVICE_CONTROL_CONFIGURED (1 << 7) #define DEVICE_CONTROL_SLEEP_NORMAL 0x00 #define DEVICE_CONTROL_SLEEP_SENSOR 0x01 #define DEVICE_CONTROL_INTR_ENABLE 1 #define INTR_FLASH (1 << 0) #define INTR_STATUS (1 << 1) #define INTR_BIST (1 << 2) #define INTR_2D (1 << 3) #define INTR_BUTTON (1 << 4) #define INTR_UADC (1 << 5) #define INTR_ALL 0x3f #define DEVICE_CONTROL_STATUS_FLASH_PROG (1 << 6) #define DEVICE_CONTROL_STATUS_UNCONFIGURED (1 << 7) #define DEVICE_CONTROL_COMMAND 0x00 #define DEVICE_COMMAND_RESET (1 << 0) #define DEVICE_COMMAND_SHUTDOWN (1 << 1) #define DEVICE_CONTROL_QUERY_MANID 0 #define DEVICE_CONTROL_QUERY_PROD_PROPERTIES 1 #define DEVICE_CONTROL_QUERY_PROD_FAMILY 2 #define DEVICE_CONTROL_QUERY_FW_VER 3 #define DEVICE_CONTROL_QUERY_PROD_ID 11 #define DEVICE_CONTROL_QUERY_PROD_ID_LAST 20 #define PRODUCT_ID_LEN (DEVICE_CONTROL_QUERY_PROD_ID_LAST - \ DEVICE_CONTROL_QUERY_PROD_ID + 1) /* Capasitive Buttons */ #define MAX_BUTTONS 31 #define BUTTON_QUERY_QUERY0 0 #define BUTTON_QUERY_BUTTON_COUNT 1 #define BUTTON_QUERY_BUTTON_MASK 0x1f #define BUTTON_CONFIGURABLE (1 << 0) /* 2D Functionality */ #define TOUCH_QUERY_NUM_SENSORS 0 /* Zero based */ #define TOUCH_QUERY_LEN 6 #define TOUCH_CONTROL_REPORT_MODE 0 #define TOUCH_CONTROL_SENSOR_MAX_X 6 #define TOUCH_CONTROL_SENSOR_MAX_Y 8 #define TOUCH_CONTROL_SENSOR_MAPPING 10 /* This is for now fixed for 2 touch points */ #define TOUCH_DATA_LEN (1 + (MAX_TOUCH_POINTS * 5)) #define FINGER_STATE_NOT_PRESENT 0 #define FINGER_STATE_ACCURATE 1 #define FINGER_STATE_INACCURATE 2 #define FINGER_STATE_RESERVED 3 /* Flashing */ #define FLASH_MAX_SIZE (16*1024) #define FW_MAX_NAME_SIZE 31 #define FLASH_QUERY_BOOTLOADER_ID_0 0 #define FLASH_QUERY_BOOTLOADER_ID_1 1 #define FLASH_QUERY_PROPERTIES 2 #define FLASH_QUERY_BLOCK_SIZE_0 3 #define FLASH_QUERY_BLOCK_SIZE_1 4 #define FLASH_QUERY_FW_BLOCK_COUNT_0 5 #define FLASH_QUERY_FW_BLOCK_COUNT_1 6 #define FLASH_QUERY_CONF_BLOCK_COUNT_0 7 #define FLASH_QUERY_CONF_BLOCK_COUNT_1 8 /* Flash Properties */ #define FLASH_PROPERTY_REGMAP_VERSION (1 << 0) /* Commands for FLASH_DATA_COMMAND */ #define FLASH_CMD_IDLE 0x00 #define FLASH_CMD_FW_CRC_BLOCK 0x01 #define FLASH_CMD_FW_WRITE_BLOCK 0x02 #define FLASH_CMD_ERASE_ALL 0x03 #define FLASH_CMD_CONF_READ_BLOCK 0x05 #define FLASH_CMD_CONF_WRITE_BLOCK 0x06 #define FLASH_CMD_CONF_ERASE_BLOCK 0x07 #define FLASH_CMD_PROGRAM_ENABLE 0x0f #define FLASH_ERROR_SUCCESS 0 #define FLASH_ERROR_RESERVED 1 #define FLASH_ERROR_NOT_ENABLED 2 #define FLASH_ERROR_INVALID_BLOCK 3 #define FLASH_ERROR_BLOCK_NOT_ERASED 4 #define FLASH_ERROR_ERASE_KEY 5 #define FLASH_ERROR_UNKNOWN 6 #define FLASH_ERROR_RESET 7 #define FLASH_ERROR_COUNT 8 #define DEVICE_STATUS_NO_ERROR 0 #define DEVICE_STATUS_RESET_OCCURRED 1 #define DEVICE_STATUS_INVALID_CONFIG 2 #define DEVICE_STATUS_DEVICE_FAILURE 3 #define DEVICE_STATUS_CFG_CRC_FAILURE 4 #define DEVICE_STATUS_FW_CRC_FAILURE 5 #define DEVICE_STATUS_CRC_IN_PROGRESS 6 #define DEVICE_STATUS_UNKNOWN 7 #define DEVICE_STATUS_COUNT 8 /* Selftest */ #define BIST_QUERY_LIMIT_REG_COUNT 0 #define BIST_DATA_TEST_NUMBER_CTRL 0 #define BIST_DATA_OVERALL_RESULT 1 #define BIST_DATA_TEST_RESULT 2 #define BIST_CONTROL_COMMAND 0 static const char *const device_status_str[DEVICE_STATUS_COUNT] = { "no error", "reset occurred", "invalid configuration", "device failure", "configuration crc failure", "firmware crc failure", "crc in progress", "unknown", }; static const char *const flash_error_str[FLASH_ERROR_COUNT] = { "success", "reserved", "programming not enabled", "invalid block number", "block not erased", "erase key incorrect", "unknown", "device reset", }; /* Offsets within firmware image */ #define FW_FILE_CHECKSUM 0x0000 #define FW_VERSION 0x0007 #define FW_FW_SIZE 0x0008 #define FW_CONFIG_SIZE 0x000C #define FW_PRODUCT_ID 0x0010 #define FW_PRODUCT_INFO_0 0x001E #define FW_PRODUCT_INFO_1 0x001F #define FW_FW_DATA 0x0100 /* How many times we try to re-initialize chip in row */ #define MAX_FAILED_INITS 4 /* How much data we can put into single write block */ #define MAX_I2C_WRITE_BLOCK_SIZE 32 #define DFLAG_VERBOSE (1 << 0) #define DFLAG_I2C_DUMP (1 << 1) struct syn; struct func_desc { void (*intr_handler)(struct syn *sd, u8 bits); u8 num; u8 version; u8 query; u8 command; u8 control; u8 data; u8 exists; u8 intr_start_bit; u8 intr_sources; }; struct touch_sensor_caps { unsigned is_configurable:1; unsigned has_gestures:1; unsigned has_abs_mode:1; unsigned has_rel_mode:1; unsigned finger_count:4; unsigned x_electrodes:5; unsigned y_electrodes:5; unsigned max_electrodes:5; unsigned abs_data_size:2; /* XXX These are not yet in use unsigned has_pinch:1; unsigned has_press:1; unsigned has_flick:1; unsigned has_early_tap:1; unsigned has_double_tap:1; unsigned had_tap_and_hold:1; unsigned has_single_tap:1; unsigned has_anchored_finger:1; unsigned has_palm_detect:1; */ u16 max_x; u16 max_y; }; struct button_caps { u8 button_count; }; struct flash_caps { u16 bootloader_id; u16 block_size; u16 fw_block_count; u16 conf_block_count; u8 properties; }; struct fw_image { u32 file_checksum; u8 version; u8 product_id[PRODUCT_ID_LEN + 1]; u8 product_info_0; u8 product_info_1; const u8 *fw_data; u32 fw_size; const u8 *config_data; u32 config_size; u32 config_checksum; }; struct touch_data { u16 x; u16 y; u8 wx; u8 wy; u8 z; u8 finger_state; }; struct touch_point { struct input_dev *idev; struct touch_data cur_td; struct touch_data prev_td; int num; }; struct bist_test_result { u8 failed; /* == 0, if all passed */ u8 result; /* specific error for failed test */ }; struct syn { struct mutex lock; struct i2c_client *client; struct workqueue_struct *wq; struct work_struct isr_work; #ifdef CONFIG_HAS_EARLYSUSPEND struct early_suspend early_suspend; #endif struct func_desc *control; u8 device_control_ctrl; /* saved state */ struct func_desc *touch; struct touch_point tp[MAX_TOUCH_POINTS]; struct touch_sensor_caps touch_caps; struct func_desc *buttons; struct button_caps button_caps; u32 button_state; struct func_desc func_desc[MAX_FUNC_DESCS]; unsigned func_desc_num; unsigned interrupt_sources; struct func_desc *flash; struct flash_caps flash_caps; struct fw_image fw_image; const struct firmware *fw_entry; struct func_desc *bist; struct func_desc *timer; struct func_desc *prox; int gpio_intr; int func_descs_valid; int failed_inits; u32 debug_flag; unsigned long ts_intr; unsigned long ts_work; unsigned long ts_done; unsigned long t_wakeup_min; unsigned long t_wakeup_max; unsigned long t_wakeup_c; unsigned long t_work_min; unsigned long t_work_max; unsigned long t_work_c; unsigned long t_wakeup; unsigned long t_work; unsigned long t_count; unsigned long f_measure; int virtualized; int suspend_mode; }; #ifdef CONFIG_PM #ifdef CONFIG_HAS_EARLYSUSPEND static void syn_ts_early_suspend(struct early_suspend *handler); static void syn_ts_late_resume(struct early_suspend *handler); #endif #endif static int syn_initialize(struct syn *sd); static int syn_reset_device(struct syn *sd); static int syn_read_func_descs(struct syn *sd); static int syn_write_block(struct syn *sd, int reg, const u8 *data, int len) { unsigned char wb[MAX_I2C_WRITE_BLOCK_SIZE + 1]; struct i2c_msg msg; int r; int i; if (len < 1 || len > MAX_I2C_WRITE_BLOCK_SIZE) { dev_info(&sd->client->dev, "too long syn_write_block len %d\n", len); return -EIO; } wb[0] = reg & 0xff; for (i = 0; i < len; i++) wb[i + 1] = data[i]; msg.addr = sd->client->addr; msg.flags = 0; msg.len = len + 1; msg.buf = wb; r = i2c_transfer(sd->client->adapter, &msg, 1); if (sd->debug_flag & DFLAG_I2C_DUMP) { if (r == 1) { for (i = 0; i < len; i++) dev_info(&sd->client->dev, "bw 0x%02x[%d]: 0x%02x\n", reg + i, i, data[i]); } } if (r == 1) return 0; return r; } static int syn_read_block(struct syn *sd, int reg, u8 *data, int len) { unsigned char wb[1]; struct i2c_msg msg[2]; int r; wb[0] = reg & 0xff; msg[0].addr = sd->client->addr; msg[0].flags = 0; msg[0].len = 1; msg[0].buf = wb; msg[1].addr = msg[0].addr; msg[1].flags = I2C_M_RD; msg[1].len = len; msg[1].buf = data; r = i2c_transfer(sd->client->adapter, msg, 2); if (sd->debug_flag & DFLAG_I2C_DUMP) { if (r == 2) { int i; for (i = 0; i < len; i++) dev_info(&sd->client->dev, "br 0x%02x[%d]: 0x%02x\n", reg + i, i, data[i]); } } if (r == 2) return len; return r; } static int syn_read_u8(struct syn *sd, int reg) { unsigned char b[1] = {0}; int r; r = syn_read_block(sd, reg, b, 1); if (r == 1) return (int)b[0]; return r; } static int syn_write_u8(struct syn *sd, u8 reg, u8 value) { return syn_write_block(sd, reg, &value, 1); } static int syn_read_u16(struct syn *sd, int reg) { int r; u8 data[2] = {0}; r = syn_read_block(sd, reg, data, 2); if (r < 0) return r; return (int)data[0] | ((int)(data[1]) << 8); } static int syn_write_u16(struct syn *sd, int reg, u16 value) { u8 data[2]; data[1] = (value & 0xFF00) >> 8; data[0] = value & 0x00FF; return syn_write_block(sd, reg, data, 2); } static int syn_control_query_read(struct syn *sd, int reg) { return syn_read_u8(sd, sd->control->query + reg); } static int syn_control_data_read(struct syn *sd, int reg) { return syn_read_u8(sd, sd->control->data + reg); } static const char *syn_device_status_str(u8 dev_status) { if (dev_status >= DEVICE_STATUS_COUNT) return device_status_str[DEVICE_STATUS_UNKNOWN]; return device_status_str[dev_status]; } static int syn_get_nosleep(struct syn *sd) { int r; r = syn_read_u8(sd, sd->control->control + DEVICE_CONTROL_CTRL); if (r < 0) return r; return (r & 0x04) >> 2; } static int syn_set_nosleep(struct syn *sd, int val) { int r; r = syn_read_u8(sd, sd->control->control + DEVICE_CONTROL_CTRL); if (r < 0) return r; val = (r & (~0x04)) | ((!!val) << 2); r = syn_write_u8(sd, sd->control->control + DEVICE_CONTROL_CTRL, val); return r; } static int syn_get_proximity_state(struct syn *sd) { int r; if (!sd->prox) return -ENODEV; r = syn_read_u8(sd, sd->prox->control); if (r < 0) return r; return (r & (1 << 7)) == 0; } static int syn_set_proximity_state(struct syn *sd, int val) { int r; if (!sd->prox) return -ENODEV; r = syn_read_u8(sd, sd->prox->control); if (r < 0) return r; /* It is called 'inhibit proximity' in register */ val = (r & (~0x80)) | ((!val) << 7); r = syn_write_u8(sd, sd->prox->control, val); if (r < 0) return r; return r; } static void syn_report_device_status(struct syn *sd, u8 dev_status) { struct device *dev = &sd->client->dev; if (dev_status & (1 << 7)) dev_info(dev, "device is unconfigured\n"); if (dev_status & (1 << 6)) dev_info(dev, "device is in flashing mode\n"); dev_info(dev, "device status: 0x%x, %s\n", dev_status, syn_device_status_str(dev_status & 0x0f)); } static void syn_device_change_state(struct syn *sd, u8 dev_status) { int r; /* Unconfigured or reset, we initialize*/ if ((dev_status & (1 << 7)) || (dev_status & 0x0f) == DEVICE_STATUS_RESET_OCCURRED) { r = syn_initialize(sd); if (r) dev_err(&sd->client->dev, "error %d in syn_initialize\n", r); } } static void syn_recalculate_latency_data(struct syn *sd) { if (sd->ts_intr <= sd->ts_work && sd->ts_work < sd->ts_done) { sd->t_wakeup = sd->ts_work - sd->ts_intr; do_div(sd->t_wakeup, 1000); sd->t_work = sd->ts_done - sd->ts_work; do_div(sd->t_work, 1000); if (sd->t_wakeup > sd->t_wakeup_max) sd->t_wakeup_max = sd->t_wakeup; if (sd->t_wakeup < sd->t_wakeup_min) sd->t_wakeup_min = sd->t_wakeup; if (sd->t_work > sd->t_work_max) sd->t_work_max = sd->t_work; if (sd->t_work < sd->t_work_min) sd->t_work_min = sd->t_work; if ((sd->t_work_c + sd->t_work) < sd->t_work_c || (sd->t_wakeup_c + sd->t_wakeup) < sd->t_wakeup_c) { /* Wrap */ sd->t_work_c = sd->t_work; sd->t_wakeup_c = sd->t_wakeup; sd->t_count = 0; } else { sd->t_work_c += sd->t_work; sd->t_wakeup_c += sd->t_wakeup; sd->t_count++; } } else { /* Time wrap or something else, discard */ } } static void syn_isr_device_control(struct syn *sd, u8 bits) { int dev_status; dev_status = syn_control_data_read(sd, DEVICE_CONTROL_DATA_STATUS); if (dev_status < 0) { dev_err(&sd->client->dev, "error %d reading device status\n", dev_status); } syn_report_device_status(sd, dev_status); syn_device_change_state(sd, dev_status); } static void syn_isr_flash(struct syn *sd, u8 bits) { int dev_status; dev_info(&sd->client->dev, "flash interrupt\n"); if (!sd->flash) { dev_warn(&sd->client->dev, "flash interrupt without registered functionality\n"); return; } dev_status = syn_control_data_read(sd, DEVICE_CONTROL_DATA_STATUS); syn_report_device_status(sd, dev_status); syn_device_change_state(sd, dev_status); } static void syn_isr_timer(struct syn *sd, u8 bits) { if (!sd->timer) { dev_warn(&sd->client->dev, "flash interrupt without registered functionality\n"); return; } } static void syn_isr_bist(struct syn *sd, u8 bits) { if (!sd->bist) { dev_warn(&sd->client->dev, "bist interrupt without registered functionality\n"); return; } } static void syn_isr_proximity(struct syn *sd, u8 bits) { unsigned char data[6] = {0}; struct input_dev *idev; int r = 0; idev = sd->tp[0].idev; if (!sd->prox) { dev_warn(&sd->client->dev, "spurious proximity interrupty\n"); return; } r = syn_read_block(sd, sd->prox->data, data, 6); if (r < 0) { dev_warn(&sd->client->dev, "error %d reading proximity data\n", r); return; } if (data[0] & 0x01) { input_report_abs(idev, ABS_RZ, data[1]); input_report_abs(idev, ABS_HAT0X, data[2]); /* BH */ input_report_abs(idev, ABS_HAT0Y, data[4]); /* LH */ input_report_abs(idev, ABS_HAT1X, data[3]); /* TH */ input_report_abs(idev, ABS_HAT1Y, data[5]); /* RH */ } else input_report_abs(idev, ABS_RZ, 0); input_sync(idev); } static void syn_touch_parse_one_touch_data(struct syn *sd, struct touch_data *p, u8 finger_state, const u8 *d) { p->finger_state = finger_state; p->x = (u16)(d[2] & 0x0f) | (u16)(d[0] << 4); p->y = ((u16)(d[2] & 0xf0) >> 4) | (u16)(d[1] << 4); p->wx = d[3] & 0x0f; p->wy = (d[3] & 0xf0) >> 4; p->z = d[4]; } static void syn_touch_parse_touch_data(struct syn *sd, const u8 *d) { struct tm12xx_ts_platform_data *pdata = sd->client->dev.platform_data; unsigned i; u8 fc; u8 fs; struct touch_data *p; fc = sd->touch_caps.finger_count; if (fc > MAX_TOUCH_POINTS) dev_err(&sd->client->dev, "error in finger count %d\n", fc); for (i = 0; i < fc; i++) { p = &sd->tp[pdata->controller_num].cur_td; fs = (d[(i >> 2)] >> ((i % 4) << 1)) & 0x03; /* dev_warn(&sd->client->dev, "fs[%d] = %d\n", i, fs); */ syn_touch_parse_one_touch_data(sd, p, fs, d + ((fc >> 2) + 1) + i * 5); } } static int syn_touch_get_data(struct syn *sd) { int r; u8 data[TOUCH_DATA_LEN]; r = syn_read_block(sd, sd->touch->data, data, TOUCH_DATA_LEN); if (r < 0) return r; if (r != TOUCH_DATA_LEN) return -EIO; syn_touch_parse_touch_data(sd, data); return 0; } static void syn_touch_report_data(struct syn *sd, int dev_number) { struct tm12xx_ts_platform_data *pdata = sd->client->dev.platform_data; struct input_dev *idev; struct touch_data *d; struct touch_data *p; idev = sd->tp[dev_number].idev; d = &sd->tp[dev_number].cur_td; p = &sd->tp[dev_number].prev_td; if (memcmp(p, d, sizeof(struct touch_data)) == 0) return; memcpy(p, d, sizeof(struct touch_data)); switch (d->finger_state) { case FINGER_STATE_ACCURATE: input_report_key(idev, BTN_TOUCH, 1); input_report_key(idev, BTN_MODE, 0); break; case FINGER_STATE_INACCURATE: input_report_key(idev, BTN_TOUCH, 1); input_report_key(idev, BTN_MODE, 1); break; case FINGER_STATE_RESERVED: /* Intentional fall thru */ case FINGER_STATE_NOT_PRESENT: input_report_key(idev, BTN_MODE, 0); input_report_key(idev, BTN_TOUCH, 0); goto out; default: dev_err(&sd->client->dev, "unknown finger state 0x%x\n", d->finger_state); goto out; } if (sd->virtualized && pdata->swap_xy && dev_name(&sd->client->dev)[0] != '2') d->x = sd->touch_caps.max_x + d->x; if (pdata->swap_xy) { input_report_abs(idev, ABS_X, d->y); input_report_abs(idev, ABS_Y, d->x); input_report_abs(idev, ABS_TOOL_WIDTH, d->wy); } else { input_report_abs(idev, ABS_X, d->x); input_report_abs(idev, ABS_Y, d->y); input_report_abs(idev, ABS_TOOL_WIDTH, d->wx); } input_report_abs(idev, ABS_Z, d->z); input_report_abs(idev, ABS_VOLUME, d->wx * d->wy); out: input_sync(idev); } static void syn_isr_2d(struct syn *sd, u8 bits) { struct tm12xx_ts_platform_data *pdata = sd->client->dev.platform_data; int r; if (!sd->touch) { dev_warn(&sd->client->dev, "2d interrupt without registered functionality\n"); return; } r = syn_touch_get_data(sd); if (r) { dev_err(&sd->client->dev, "error getting touch data\n"); return; } if (sd->debug_flag & DFLAG_VERBOSE) { dev_info(&sd->client->dev, "%i: state=0x%x, x=%d, y=%d, z=%d, wx=%d, wy=%d\n", pdata->controller_num, sd->tp[pdata->controller_num].cur_td.finger_state, sd->tp[pdata->controller_num].cur_td.x, sd->tp[pdata->controller_num].cur_td.y, sd->tp[pdata->controller_num].cur_td.z, sd->tp[pdata->controller_num].cur_td.wx, sd->tp[pdata->controller_num].cur_td.wy); } syn_touch_report_data(sd, pdata->controller_num); } static int syn_button_report(struct syn *sd, unsigned button_nr, const int val) { struct tm12xx_ts_platform_data *pdata = sd->client->dev.platform_data; unsigned max_buttons; max_buttons = pdata->num_buttons; if (button_nr >= max_buttons) return -EINVAL; input_report_key(sd->tp[0].idev, pdata->button_map[button_nr], val); input_sync(sd->tp[0].idev); return 0; } static void syn_isr_buttons(struct syn *sd, u8 bits) { int data_reg_count = (sd->button_caps.button_count + 7) / 8; int i = 0; int r; u32 state = 0; u32 last_state; if (!sd->buttons) { dev_warn(&sd->client->dev, "button interrupt without registered functionality\n"); return; } if (data_reg_count > MAX_BUTTONS/8 + 1) data_reg_count = MAX_BUTTONS/8 + 1; while (i < data_reg_count) { r = syn_read_u8(sd, sd->buttons->data + i); if (r < 0) { dev_err(&sd->client->dev, "error reading button state\n"); return; } state |= (u32)r << (i * 8); i++; } last_state = sd->button_state; for (i = 0; i < sd->button_caps.button_count; i++) { const u32 mask = (1 << i); if ((state & mask) ^ (last_state & mask)) { r = syn_button_report(sd, i, state & mask ? 1 : 0); if (r) { dev_warn(&sd->client->dev, "error reporting button " "(no mapping for %d ?)\n", i); } } } sd->button_state = state; } static u8 syn_get_status_bits(u8 *int_status, int start, int bits) { const u16 mask = ((1 << bits) - 1) << start; u8 val; val = (*int_status & mask) >> start; *int_status &= ~mask; return val; } static void syn_isr_call_handlers(struct syn *sd, u8 int_status) { int i; u8 bits; for (i = 0; i < sd->func_desc_num; i++) { struct func_desc * const f = &sd->func_desc[i]; if (!int_status) return; bits = syn_get_status_bits(&int_status, f->intr_start_bit, f->intr_sources); if (likely(bits)) { if (likely(f->intr_handler)) f->intr_handler(sd, bits); else { if (printk_ratelimit()) dev_warn(&sd->client->dev, "no intr handler for %d\n", i); } } } if (unlikely(int_status)) dev_warn(&sd->client->dev, "unhandled attentions: 0x%x\n", int_status); } static void syn_clear_device_state(struct syn *sd) { int i; sd->control = NULL; sd->touch = NULL; /* * We don't clear previous exported devices. * If after firmware upgrade there would be different * amount of touchpoints rmmod/insmod cycle is needed. */ memset(&sd->touch_caps, 0, sizeof(struct touch_sensor_caps)); sd->buttons = NULL; memset(&sd->button_caps, 0, sizeof(struct button_caps)); sd->button_state = 0; for (i = 0; i < MAX_FUNC_DESCS; i++) memset(&sd->func_desc[i], 0, sizeof(struct func_desc)); sd->func_desc_num = 0; sd->interrupt_sources = 0; sd->flash = NULL; memset(&sd->flash_caps, 0, sizeof(struct flash_caps)); memset(&sd->fw_image, 0, sizeof(struct fw_image)); sd->bist = NULL; } static void syn_isr_work(struct work_struct *work) { int is; int r; struct syn *sd = container_of(work, struct syn, isr_work); mutex_lock(&sd->lock); if (sd->f_measure) { sd->ts_work = cpu_clock(get_cpu()); put_cpu(); } if (sd->func_descs_valid == 0) { if (sd->failed_inits < MAX_FAILED_INITS) { r = syn_initialize(sd); if (r) { dev_err(&sd->client->dev, "error initializing\n"); goto out; } } } is = syn_control_data_read(sd, DEVICE_CONTROL_DATA_INTR_STATUS); if (unlikely(is < 0)) { dev_err(&sd->client->dev, "unable to read intr status\n"); syn_reset_device(sd); goto out; } if (likely(is)) syn_isr_call_handlers(sd, is); out: if (sd->f_measure) { sd->ts_done = cpu_clock(get_cpu()); put_cpu(); syn_recalculate_latency_data(sd); sd->f_measure = 0; } enable_irq(gpio_to_irq(sd->gpio_intr)); mutex_unlock(&sd->lock); } static irqreturn_t syn_isr(int irq, void *data) { struct syn *sd = data; if (sd->wq != NULL) { int r; r = queue_work(sd->wq, &sd->isr_work); if (r) { if (sd->f_measure == 0) { sd->ts_intr = cpu_clock(get_cpu()); put_cpu(); sd->f_measure = 1; } disable_irq_nosync(gpio_to_irq(sd->gpio_intr)); } } return IRQ_HANDLED; } static int syn_set_input_dev_params(struct syn *sd, int dev_number) { struct input_dev *dev; struct tm12xx_ts_platform_data *pdata; int i; if (!sd || dev_number < 0 || dev_number >= MAX_TOUCH_POINTS) return -EINVAL; dev = sd->tp[dev_number].idev; if (!dev) return -ENODEV; pdata = sd->client->dev.platform_data; set_bit(EV_KEY, dev->evbit); set_bit(EV_ABS, dev->evbit); set_bit(BTN_TOUCH, dev->keybit); set_bit(BTN_MODE, dev->keybit); set_bit(ABS_X, dev->absbit); set_bit(ABS_Y, dev->absbit); set_bit(ABS_Z, dev->absbit); set_bit(ABS_VOLUME, dev->absbit); set_bit(ABS_TOOL_WIDTH, dev->absbit); if (dev_number == 0) { set_bit(ABS_RZ, dev->absbit); set_bit(ABS_HAT0X, dev->absbit); set_bit(ABS_HAT0Y, dev->absbit); set_bit(ABS_HAT1X, dev->absbit); set_bit(ABS_HAT1Y, dev->absbit); } if (pdata->repeat) set_bit(EV_REP, dev->evbit); for (i = 0; i < pdata->num_buttons; i++) set_bit(pdata->button_map[i], dev->keybit); if (pdata->swap_xy) { input_set_abs_params(dev, ABS_X, 0, sd->touch_caps.max_y, 0, 0); input_set_abs_params(dev, ABS_Y, 0, sd->touch_caps.max_x, 0, 0); } else { input_set_abs_params(dev, ABS_X, 0, sd->touch_caps.max_x, 0, 0); input_set_abs_params(dev, ABS_Y, 0, sd->touch_caps.max_y, 0, 0); } input_set_abs_params(dev, ABS_Z, 0, 255, 0, 0); input_set_abs_params(dev, ABS_VOLUME, 0, 225, 0, 0); input_set_abs_params(dev, ABS_TOOL_WIDTH, 0, 15, 0, 0); if (dev_number == 0) { input_set_abs_params(dev, ABS_RZ, 0, 255, 0, 0); input_set_abs_params(dev, ABS_HAT0X, 0, 255, 0, 0); input_set_abs_params(dev, ABS_HAT0Y, 0, 255, 0, 0); input_set_abs_params(dev, ABS_HAT1X, 0, 255, 0, 0); input_set_abs_params(dev, ABS_HAT1Y, 0, 255, 0, 0); } dev->dev.parent = &sd->client->dev; return 0; } static int syn_register_input_devices(struct syn *sd, int num_devices) { struct tm12xx_ts_platform_data *pdata; int r; if (!sd || num_devices < 0 || num_devices > MAX_TOUCH_POINTS) return -EINVAL; pdata = sd->client->dev.platform_data; /* After firmware upgrade no need to reregister */ if (sd->tp[0].idev != NULL) { if (sd->debug_flag & DFLAG_VERBOSE) dev_info(&sd->client->dev, "input device already existing\n"); return 0; } sd->tp[pdata->controller_num].idev = input_allocate_device(); if (!sd->tp[pdata->controller_num].idev) { dev_err(&sd->client->dev, "not enough memory for input device %d\n", pdata->controller_num); r = -ENOMEM; goto err_alloc; } r = syn_set_input_dev_params(sd, pdata->controller_num); if (r) { dev_err(&sd->client->dev, "%s: Setting input params for controller \ number %i failed.\n", __func__, pdata->controller_num); goto err_alloc; } if (pdata->idev_name[pdata->controller_num]) sd->tp[pdata->controller_num].idev->name = pdata->idev_name[pdata->controller_num]; else { dev_err(&sd->client->dev, "%s: No input device name for controller \ number %i.\n", __func__, pdata->controller_num); goto err_alloc; } r = input_register_device(sd->tp[pdata->controller_num].idev); if (r) { dev_err(&sd->client->dev, "failed to register input device %d\n", pdata->controller_num); goto err_register; } return 0; err_register: input_unregister_device(sd->tp[pdata->controller_num].idev); err_alloc: if (sd->tp[pdata->controller_num].idev) { input_free_device(sd->tp[pdata->controller_num].idev); sd->tp[pdata->controller_num].idev = NULL; } return r; } static struct func_desc *syn_get_func_desc(struct syn *sd, int func) { int i; for (i = 0; i < sd->func_desc_num; i++) { struct func_desc * const f = &sd->func_desc[i]; if (f->num == func) return f; } return NULL; } static int syn_register_intr_handler(struct syn *sd, int func, void (*h)(struct syn *sd, u8 bits)) { struct func_desc * const f = syn_get_func_desc(sd, func); if (!f) return -EINVAL; if (f->intr_handler == NULL) { f->intr_handler = h; return 0; } return -EINVAL; } /* * Flashing support */ static int syn_flash_query_caps(struct syn *sd) { int r; r = syn_read_u16(sd, sd->flash->query + FLASH_QUERY_BOOTLOADER_ID_0); if (r < 0) return r; sd->flash_caps.bootloader_id = r; r = syn_read_u8(sd, sd->flash->query + FLASH_QUERY_PROPERTIES); if (r < 0) return r; sd->flash_caps.properties = r; r = syn_read_u16(sd, sd->flash->query + FLASH_QUERY_BLOCK_SIZE_0); if (r < 0) return r; sd->flash_caps.block_size = r; r = syn_read_u16(sd, sd->flash->query + FLASH_QUERY_FW_BLOCK_COUNT_0); if (r < 0) return r; sd->flash_caps.fw_block_count = r; r = syn_read_u16(sd, sd->flash->query + FLASH_QUERY_CONF_BLOCK_COUNT_0); if (r < 0) return r; sd->flash_caps.conf_block_count = r; return 0; } static u32 syn_crc_fletcher32(const u16 *data, unsigned int len) { u32 sum1 = 0xffff; u32 sum2 = 0xffff; while (len--) { sum1 += *data++; sum2 += sum1; sum1 = (sum1 & 0xffff) + (sum1 >> 16); sum2 = (sum2 & 0xffff) + (sum2 >> 16); } return sum1 | (sum2 << 16); } static int syn_fw_read_bytes(struct syn *sd, u8 *b, int offset, int len) { if (offset + len > sd->fw_entry->size) { dev_err(&sd->client->dev, "fw_read_bytes overflow on offset %d\n", offset); return -EINVAL; } memcpy(b, sd->fw_entry->data + offset, len); return len; } static int syn_fw_read_u32(struct syn *sd, u32 *d, int offset) { const u8 *l; if (offset + 4 > sd->fw_entry->size) { dev_err(&sd->client->dev, "fw_read_u32 overflow on offset %d\n", offset); return -EINVAL; } l = sd->fw_entry->data + offset; *d = l[0] | (l[1] << 8) | (l[2] << 16) | (l[3] << 24); return 4; } static int syn_request_firmware(struct syn *sd, const char *filename) { int r; r = request_firmware(&sd->fw_entry, filename, &sd->client->dev); return r; } static int syn_check_firmware(struct syn *sd) { u32 calc_file_crc; u32 calc_config_crc; struct fw_image *d = &sd->fw_image; int r; /* * Restrict sizes. * Absolute minimum is zero sized fw data and config * areas. */ if (sd->fw_entry->size > FLASH_MAX_SIZE || sd->fw_entry->size < FW_FW_DATA + 4) { dev_err(&sd->client->dev, "illegal firmware size\n"); return -EINVAL; } r = syn_fw_read_u32(sd, &d->file_checksum, FW_FILE_CHECKSUM); if (r < 0) return r; r = syn_fw_read_bytes(sd, &d->version, FW_VERSION, 1); if (r < 0) return r; r = syn_fw_read_u32(sd, &d->fw_size, FW_FW_SIZE); if (r < 0) return r; r = syn_fw_read_u32(sd, &d->config_size, FW_CONFIG_SIZE); if (r < 0) return r; if ((d->fw_size + d->config_size + FW_FW_DATA) > sd->fw_entry->size) { dev_err(&sd->client->dev, "fw size mismatch\n"); return -EINVAL; } /* These have to be u32 aligned */ if ((d->fw_size & 0x0f) || (d->config_size & 0x0f)) { dev_err(&sd->client->dev, "fw areas not aligned to 4 bytes\n"); return -EINVAL; } r = syn_fw_read_bytes(sd, d->product_id, FW_PRODUCT_ID, PRODUCT_ID_LEN); if (r < 10) return r; r = syn_fw_read_bytes(sd, &d->product_info_0, FW_PRODUCT_INFO_0, 1); if (r < 0) return r; r = syn_fw_read_bytes(sd, &d->product_info_1, FW_PRODUCT_INFO_1, 1); if (r < 0) return r; r = syn_fw_read_u32(sd, &d->config_checksum, d->fw_size + FW_FW_DATA + d->config_size - 4); if (r < 0) return r; d->fw_data = sd->fw_entry->data + FW_FW_DATA; d->config_data = sd->fw_entry->data + FW_FW_DATA + d->fw_size; calc_file_crc = syn_crc_fletcher32((u16 *)(sd->fw_entry->data + 4), (sd->fw_entry->size - 4) >> 1); calc_config_crc = syn_crc_fletcher32((u16 *)(d->config_data), (d->config_size - 4) >> 1); if (calc_file_crc != d->file_checksum) { dev_err(&sd->client->dev, "fw file crc failed\n"); return -EINVAL; } if (calc_config_crc != d->config_checksum) { dev_err(&sd->client->dev, "fw config area crc failed\n"); return -EINVAL; } return 0; } static const char *syn_flash_error_str(u8 flash_error) { if (flash_error >= FLASH_ERROR_COUNT) return flash_error_str[FLASH_ERROR_UNKNOWN]; return flash_error_str[flash_error]; } static u8 syn_flash_error(int flash_status) { return ((u8)(flash_status) >> 4) & 0x07; } /* * There are two different ways the flash register are organized */ static u8 syn_flash_data_command_offset(struct syn *sd) { if (sd->flash_caps.properties & FLASH_PROPERTY_REGMAP_VERSION) return 2 + sd->flash_caps.block_size; else return 0; } static u8 syn_flash_block_data_offset(struct syn *sd) { if (sd->flash_caps.properties & FLASH_PROPERTY_REGMAP_VERSION) return 2; else return 3; } static u8 syn_flash_block_num_offset(struct syn *sd) { if (sd->flash_caps.properties & FLASH_PROPERTY_REGMAP_VERSION) return 0; else return 1; } static int syn_flash_status(struct syn *sd) { return syn_read_u8(sd, sd->flash->data + syn_flash_data_command_offset(sd)); } static int syn_wait_for_attn(struct syn *sd, unsigned long timeout_usecs, int state) { const unsigned long one_wait = 20; unsigned long waited = 0; int r; do { r = gpio_get_value(sd->gpio_intr); if (r == state) break; udelay(one_wait); waited += one_wait; } while (waited < timeout_usecs); if (waited > 500000 || waited >= timeout_usecs || (sd->debug_flag & DFLAG_VERBOSE)) dev_info(&sd->client->dev, "waited %lu usecs for attn\n", waited); return r == state ? 0 : -1; } static int syn_flash_command(struct syn *sd, u8 flash_command) { int r; int s; if (flash_command & 0xf0) return -EINVAL; r = syn_wait_for_attn(sd, 200 * 1000, 1); if (r) { dev_err(&sd->client->dev, "timeout: attn didn't clear for 200 ms\n"); return r; } r = syn_write_u8(sd, sd->flash->data + syn_flash_data_command_offset(sd), flash_command); if (r) { dev_err(&sd->client->dev, "flash command error %d\n", r); return r; } r = syn_wait_for_attn(sd, 700 * 1000, 0); if (r) { dev_err(&sd->client->dev, "timeout attn didn't assert for 700 ms\n"); } s = syn_control_data_read(sd, DEVICE_CONTROL_DATA_INTR_STATUS); if (s < 0) dev_err(&sd->client->dev, "error reading int status\n"); if (sd->debug_flag & DFLAG_VERBOSE) { if (s != 0x01) dev_info(&sd->client->dev, "wait for attn intr status 0x%x\n", s); } return r == 0 ? 0 : -1; } static int syn_flash_enable(struct syn *sd) { int r; r = syn_control_data_read(sd, DEVICE_CONTROL_DATA_STATUS); if (r < 0) return r; if (r & (1 << 6)) { dev_err(&sd->client->dev, "flashing mode already enabled\n"); return 0; } r = syn_write_u16(sd, sd->flash->data + syn_flash_block_data_offset(sd), sd->flash_caps.bootloader_id); if (r < 0) return r; r = syn_flash_command(sd, FLASH_CMD_PROGRAM_ENABLE); if (r < 0) return r; r = syn_read_func_descs(sd); if (r < 0) return r; r = syn_flash_status(sd); if (r < 0) { dev_info(&sd->client->dev, "flash error in enable %s\n", syn_flash_error_str(syn_flash_error(r))); return r; } if (syn_flash_error(r) != FLASH_ERROR_SUCCESS && syn_flash_error(r) != FLASH_ERROR_RESET) { dev_err(&sd->client->dev, "flash error: %s\n", syn_flash_error_str(syn_flash_error(r))); return -EINVAL; } if (!(r & 0x80)) { dev_err(&sd->client->dev, "flashing not enabled 0x%02x\n", r); return -EINVAL; } return r; } static int syn_flash_write_block_cmd_old(struct syn *sd, const u8 *data, int blocks, u8 flash_command) { int block; int r; const u8 block_num_offset = syn_flash_block_num_offset(sd); const u8 block_data_offset = syn_flash_block_data_offset(sd); for (block = 0; block < blocks; block++) { if (!(block % 10)) dev_info(&sd->client->dev, "0x%x writing block %d\n", flash_command, block); r = syn_write_u16(sd, sd->flash->data + block_num_offset, block); if (r < 0) return r; r = syn_write_block(sd, sd->flash->data + block_data_offset, data + (block * sd->flash_caps.block_size), sd->flash_caps.block_size); if (r < 0) return r; r = syn_flash_command(sd, flash_command); if (r < 0) return r; r = syn_flash_status(sd); if (r < 0) return r; if (r != 0x80) { dev_err(&sd->client->dev, "flash_write error : %s\n", syn_flash_error_str(syn_flash_error(r))); return syn_flash_error(r); } } return 0; } static int syn_flash_write_block_cmd_fast(struct syn *sd, const u8 *data, int blocks, u8 flash_command) { const u16 block_size = sd->flash_caps.block_size; u8 *d; u16 block; int r; d = kmalloc(block_size + 3, GFP_KERNEL); if (d == NULL) return -ENOMEM; for (block = 0; block < blocks; block++) { if (!(block % 10)) dev_info(&sd->client->dev, "0x%x fast writing block %d\n", flash_command, block); d[0] = block & 0xff; d[1] = (block & 0xff00) >> 8; memcpy(&d[2], data + (block * block_size), block_size); d[2 + block_size] = flash_command; r = syn_wait_for_attn(sd, 200 * 1000, 1); if (r) { dev_err(&sd->client->dev, "timeout: attn didn't clear for 200 ms\n"); goto out; } r = syn_write_block(sd, sd->flash->data, d, block_size + 3); r = syn_wait_for_attn(sd, 700 * 1000, 0); if (r) { dev_err(&sd->client->dev, "timeout attn didn't assert for 700 ms\n"); goto out; } /* We need to do this read to release ATTN */ syn_control_data_read(sd, DEVICE_CONTROL_DATA_INTR_STATUS); } out: kfree(d); return r; } static int syn_flash_write_block_cmd(struct syn *sd, const u8 *data, int blocks, u8 flash_command) { if (sd->flash_caps.properties & FLASH_PROPERTY_REGMAP_VERSION) return syn_flash_write_block_cmd_fast(sd, data, blocks, flash_command); else return syn_flash_write_block_cmd_old(sd, data, blocks, flash_command); } static int syn_flash_read_config(struct syn *sd, u8 *d) { const u8 flash_command = FLASH_CMD_CONF_READ_BLOCK; const u8 block_num_offset = syn_flash_block_num_offset(sd); const u8 block_data_offset = syn_flash_block_data_offset(sd); const int blocks = sd->fw_image.config_size / sd->flash_caps.block_size; int i; int r; for (i = 0; i < blocks; i++) { if (!(i % 10)) dev_info(&sd->client->dev, "0x%x reading conf block %d\n", flash_command, i); r = syn_write_u16(sd, sd->flash->data + block_num_offset, i); if (r < 0) return r; r = syn_flash_command(sd, flash_command); if (r < 0) return r; r = syn_flash_status(sd); if (r < 0) return r; if (r != 0x80) { dev_err(&sd->client->dev, "flash_read error : %s\n", syn_flash_error_str(syn_flash_error(r))); return syn_flash_error(r); } r = syn_read_block(sd, sd->flash->data + block_data_offset, d, sd->flash_caps.block_size); if (r < 0) return r; d += sd->flash_caps.block_size; } return 0; } static int syn_flash_write_config(struct syn *sd) { int r; const int config_size = sd->fw_image.config_size; const int blocks = config_size / sd->flash_caps.block_size; r = syn_flash_write_block_cmd(sd, sd->fw_image.config_data, blocks, FLASH_CMD_CONF_WRITE_BLOCK); if (r < 0) return r; if (r) { dev_err(&sd->client->dev, "flash write fw error : %s\n", syn_flash_error_str(r)); return -EIO; } return 0; } #ifdef FIRMWARE_VERIFY static int syn_flash_validate(struct syn *sd) { int r; const int fw_size = sd->fw_image.fw_size; const int blocks = fw_size / sd->flash_caps.block_size; if (sd->flash_caps.fw_block_count != (fw_size / sd->flash_caps.block_size) || (fw_size % sd->flash_caps.block_size)) { dev_err(&sd->client->dev, "fw size not aligned to block count\n"); return -EINVAL; } r = syn_flash_write_block_cmd(sd, sd->fw_image.fw_data, blocks, FLASH_CMD_FW_CRC_BLOCK); if (r < 0) return r; if (r) { dev_err(&sd->client->dev, "flash validate error : %s\n", syn_flash_error_str(r)); return -EIO; } r = syn_read_u8(sd, sd->flash->data + syn_flash_block_data_offset(sd)); if (r < 0) return r; if (r == 0x00) { dev_info(&sd->client->dev, "flash_validate: image is valid\n"); return 0; } else if (r == 0xff) dev_info(&sd->client->dev, "flash_validate: image is invalid\n"); else dev_info(&sd->client->dev, "flash_validate: image status unknown: 0x%02x\n", r); return -1; } static int syn_flash_compare_config(struct syn *sd) { u32 cfg_crc_c; u32 cfg_crc; u32 cfg_crc_r; u8 *cfg_data_r; int r; cfg_data_r = kmalloc(sd->fw_image.config_size, GFP_KERNEL); if (cfg_data_r == NULL) return -ENOMEM; r = syn_flash_read_config(sd, cfg_data_r); if (r < 0) { kfree(cfg_data_r); return r; } dev_info(&sd->client->dev, "Flash read config done\n"); cfg_crc = sd->fw_image.config_checksum; cfg_crc_c = syn_crc_fletcher32((u16 *)(sd->fw_image.config_data), (sd->fw_image.config_size - 4) >> 1); cfg_crc_r = syn_crc_fletcher32((u16 *)(cfg_data_r), (sd->fw_image.config_size - 4) >> 1); kfree(cfg_data_r); cfg_data_r = NULL; dev_info(&sd->client->dev, "calculated fw image crc 0x%x\n", cfg_crc_c); dev_info(&sd->client->dev, "read fw image crc 0x%x\n", cfg_crc); dev_info(&sd->client->dev, "calculated cfg read crc 0x%x\n", cfg_crc_r); if (cfg_crc != cfg_crc_c) { dev_err(&sd->client->dev, "fw crc differs from calculated\n"); return -EINVAL; } if (cfg_crc != cfg_crc_r) { dev_err(&sd->client->dev, "fw crc differs from read from device\n"); return -EINVAL; } if (cfg_crc_c != cfg_crc_r) { dev_err(&sd->client->dev, "fw calculated crc differs from read from device\n"); return -EINVAL; } return 0; } #else /* FIRMWARE_VERIFY */ static int syn_flash_compare_config(struct syn *sd) { return 0; } static int syn_flash_validate(struct syn *sd) { return 0; } #endif static int syn_flash_erase_all(struct syn *sd) { int r; r = syn_write_u16(sd, sd->flash->data + syn_flash_block_data_offset(sd), sd->flash_caps.bootloader_id); r = syn_flash_command(sd, FLASH_CMD_ERASE_ALL); if (r < 0) return r; r = syn_flash_status(sd); if (r < 0) return r; if (r != 0x80) { dev_err(&sd->client->dev, "flash erase_all error : %d %s\n", syn_flash_error(r), syn_flash_error_str(syn_flash_error(r))); return -EIO; } return 0; } static int syn_flash_write_fw(struct syn *sd) { int r; const int fw_size = sd->fw_image.fw_size; const int blocks = fw_size / sd->flash_caps.block_size; r = syn_flash_write_block_cmd(sd, sd->fw_image.fw_data, blocks, FLASH_CMD_FW_WRITE_BLOCK); if (r < 0) return r; r = syn_flash_status(sd); if (r < 0) return r; if (r != 0x80) { dev_err(&sd->client->dev, "flash write fw : %d %s\n", syn_flash_error(r), syn_flash_error_str(syn_flash_error(r))); return -EIO; } return 0; } static int syn_flash_firmware(struct syn *sd) { int r; int flash_status; /* Restrict interrupts during flashing */ r = syn_write_u8(sd, sd->control->control + DEVICE_CONTROL_INTR_ENABLE, INTR_FLASH | INTR_STATUS); r = syn_flash_enable(sd); if (r < 0) goto flash_out; r = syn_flash_validate(sd); if (r < 0) goto flash_out; r = syn_flash_erase_all(sd); if (r < 0) goto flash_out; r = syn_flash_write_fw(sd); if (r < 0) goto flash_out; r = syn_flash_write_config(sd); if (r < 0) goto flash_out; r = syn_flash_compare_config(sd); if (r < 0) goto flash_out; flash_out: flash_status = syn_flash_status(sd); dev_info(&sd->client->dev, "flash status: %x %s\n", flash_status, syn_flash_error_str(syn_flash_error(flash_status))); /* * We reset and interrupt handler should notice that * everything has changed and reread the page descriptor table. */ syn_reset_device(sd); return syn_flash_error(flash_status) == FLASH_ERROR_SUCCESS ? 0 : -1; } static ssize_t syn_show_attr_flash(struct device *dev, struct device_attribute *attr, char *buf) { struct platform_device *pdev = to_platform_device(dev); struct syn *sd = platform_get_drvdata(pdev); const ssize_t size = PAGE_SIZE; ssize_t l = 0; int r; if (!sd->flash) { l += snprintf(buf + l, size - l, "N/A\n"); return l; } mutex_lock(&sd->lock); r = syn_control_data_read(sd, DEVICE_CONTROL_DATA_STATUS); mutex_unlock(&sd->lock); if (r < 0) dev_err(&sd->client->dev, "read error %d\n", r); else l += snprintf(buf + l, size - l, "%d\n", (r & (1 << 6)) ? 1 : 0); return l; } static ssize_t syn_store_attr_flash(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { const struct platform_device *pdev = to_platform_device(dev); struct syn *sd = platform_get_drvdata(pdev); int r; char name[FW_MAX_NAME_SIZE + 1]; if (count > FW_MAX_NAME_SIZE || count == 0) { dev_err(&sd->client->dev, "firmware name check failure\n"); return 0; } memcpy(name, buf, count); name[count] = 0; mutex_lock(&sd->lock); if (name[count - 1] == '\n') name[count - 1] = 0; if (sd->fw_entry) { dev_err(&sd->client->dev, "firmware already in memory\n"); goto firmware_out; } r = syn_request_firmware(sd, name); if (r < 0) { dev_err(&sd->client->dev, "firmware not found\n"); goto store_out; } memset(&sd->fw_image, 0, sizeof(struct fw_image)); r = syn_check_firmware(sd); if (r != 0) { dev_err(&sd->client->dev, "consistency check of firmware failed\n"); goto firmware_out; } dev_info(&sd->client->dev, "firmware consistency check ok\n"); r = syn_flash_firmware(sd); if (r != 0) { dev_err(&sd->client->dev, "flashing of firmware failed\n"); goto firmware_out; } dev_info(&sd->client->dev, "flashing done with success\n"); firmware_out: memset(&sd->fw_image, 0, sizeof(struct fw_image)); release_firmware(sd->fw_entry); sd->fw_entry = NULL; store_out: mutex_unlock(&sd->lock); return count; } static ssize_t syn_show_attr_product_id(struct device *dev, struct device_attribute *attr, char *buf) { struct platform_device *pdev = to_platform_device(dev); struct syn *sd = platform_get_drvdata(pdev); const ssize_t size = PAGE_SIZE; u8 product_id[PRODUCT_ID_LEN + 1]; ssize_t l = 0; int r; if (!sd->flash) { l += snprintf(buf + l, size - l, "N/A\n"); return l; } mutex_lock(&sd->lock); r = syn_read_block(sd, sd->control->query + DEVICE_CONTROL_QUERY_PROD_ID, product_id, PRODUCT_ID_LEN); mutex_unlock(&sd->lock); product_id[PRODUCT_ID_LEN] = 0; if (r < 0) dev_warn(&sd->client->dev, "error %d reading product id\n", r); else l += snprintf(buf + l, size - l, "%s\n", product_id); return l; } static ssize_t syn_show_attr_product_family(struct device *dev, struct device_attribute *attr, char *buf) { struct platform_device *pdev = to_platform_device(dev); struct syn *sd = platform_get_drvdata(pdev); const ssize_t size = PAGE_SIZE; ssize_t l = 0; int r; if (!sd->flash) { l += snprintf(buf + l, size - l, "N/A\n"); return l; } mutex_lock(&sd->lock); r = syn_control_query_read(sd, DEVICE_CONTROL_QUERY_PROD_FAMILY); mutex_unlock(&sd->lock); if (r < 0) dev_warn(&sd->client->dev, "error %d reading product family\n", r); else l += snprintf(buf + l, size - l, "%d\n", r); return l; } static ssize_t syn_show_attr_firmware_version(struct device *dev, struct device_attribute *attr, char *buf) { struct platform_device *pdev = to_platform_device(dev); struct syn *sd = platform_get_drvdata(pdev); const ssize_t size = PAGE_SIZE; ssize_t l = 0; int r; if (!sd->flash) { l += snprintf(buf + l, size - l, "N/A\n"); return l; } mutex_lock(&sd->lock); r = syn_control_query_read(sd, DEVICE_CONTROL_QUERY_FW_VER); mutex_unlock(&sd->lock); if (r < 0) dev_warn(&sd->client->dev, "error %d reading fw version\n", r); else l += snprintf(buf + l, size - l, "%d\n", r); return l; } /* * BIST (selftest) support */ static int syn_bist_run_test(struct syn *sd, struct bist_test_result *tr, u8 test) { int r; u8 intr_mask = INTR_ALL; if (!sd || !tr || !sd->bist) return -EINVAL; mutex_lock(&sd->lock); r = syn_read_u8(sd, sd->control->control + DEVICE_CONTROL_INTR_ENABLE); if (r < 0) goto out; intr_mask = r & 0xFF; /* Restrict interrupt sources*/ r = syn_write_u8(sd, sd->control->control + DEVICE_CONTROL_INTR_ENABLE, INTR_BIST | INTR_STATUS); r = syn_write_u8(sd, sd->bist->data + BIST_DATA_TEST_NUMBER_CTRL, test); if (r < 0) goto out; r = syn_write_u8(sd, sd->bist->command + BIST_CONTROL_COMMAND, 0x01); if (r < 0) goto out; r = syn_wait_for_attn(sd, 5 * 1000 * 1000, 0); if (r < 0) { dev_err(&sd->client->dev, "timeout running bist test\n"); goto out; } r = syn_control_data_read(sd, DEVICE_CONTROL_DATA_INTR_STATUS); if (r < 0) dev_err(&sd->client->dev, "error reading int status\n"); r = syn_read_u8(sd, sd->bist->command + BIST_CONTROL_COMMAND); if (r < 0) goto out; if (r & (1 << 0)) { r = -EBUSY; goto out; } r = syn_read_u8(sd, sd->bist->data + BIST_DATA_OVERALL_RESULT); if (r < 0) goto out; tr->failed = r; r = syn_read_u8(sd, sd->bist->data + BIST_DATA_TEST_RESULT); if (r < 0) goto out; tr->result = r; out: r = syn_write_u8(sd, sd->control->control + DEVICE_CONTROL_INTR_ENABLE, intr_mask); mutex_unlock(&sd->lock); return r; } static int syn_test_i2c_wr(struct syn *sd, const u8 value) { int r; r = syn_write_u8(sd, sd->bist->data + BIST_DATA_TEST_NUMBER_CTRL, value); if (r < 0) goto out; r = syn_read_u8(sd, sd->bist->data + BIST_DATA_TEST_NUMBER_CTRL); if (r < 0) goto out; if (r != value) { dev_err(&sd->client->dev, "write verify error: wrote 0x%x got 0x%x\n", value, r); r = -EINVAL; goto out; } r = 0; out: return r; } static int syn_test_i2c(struct syn *sd) { int r; int i; mutex_lock(&sd->lock); for (i = 0; i < 8; i++) { r = syn_test_i2c_wr(sd, 1 << i); if (r < 0) goto out; } for (i = 0; i < 256; i++) { r = syn_test_i2c_wr(sd, i); if (r < 0) goto out; } out: mutex_unlock(&sd->lock); return r; } static int syn_bist_selftest(struct syn *sd, struct bist_test_result *tr) { int r; r = syn_test_i2c(sd); if (r != 0) return r; r = syn_bist_run_test(sd, tr, 0x00); return r; } static ssize_t syn_show_attr_selftest(struct device *dev, struct device_attribute *attr, char *buf) { struct platform_device *pdev = to_platform_device(dev); struct syn *sd = platform_get_drvdata(pdev); const ssize_t size = PAGE_SIZE; ssize_t l = 0; struct bist_test_result tr = { 0, }; int r; if (!sd->bist) { l += snprintf(buf + l, size - l, "Not available\n"); return l; } r = syn_bist_selftest(sd, &tr); if (r != 0) l += snprintf(buf + l, size - l, "FAIL (io error %d)\n", r); else { if (tr.failed == 0) l += snprintf(buf + l, size - l, "PASS\n"); else l += snprintf(buf + l, size - l, "FAIL (test %d, result %d)\n", tr.failed, tr.result); } return l; } static ssize_t syn_store_attr_reset(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct platform_device *pdev = to_platform_device(dev); struct syn *sd = platform_get_drvdata(pdev); mutex_lock(&sd->lock); syn_reset_device(sd); mutex_unlock(&sd->lock); return count; } static ssize_t syn_show_attr_doze(struct device *dev, struct device_attribute *attr, char *buf) { struct platform_device *pdev = to_platform_device(dev); struct syn *sd = platform_get_drvdata(pdev); const ssize_t size = PAGE_SIZE; ssize_t l = 0; int r; mutex_lock(&sd->lock); r = syn_get_nosleep(sd); mutex_unlock(&sd->lock); if (r < 0) goto out; l += snprintf(buf + l, size - l, "%d\n", !r); out: return l; } static ssize_t syn_store_attr_doze(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct platform_device *pdev = to_platform_device(dev); struct syn *sd = platform_get_drvdata(pdev); int val; if (sscanf(buf, "%i", &val) != 1) { dev_info(&sd->client->dev, "error parsing debug\n"); return count; } if (val & (~0x01)) return count; mutex_lock(&sd->lock); syn_set_nosleep(sd, !val); mutex_unlock(&sd->lock); return count; } static ssize_t syn_show_attr_sleepmode(struct device *dev, struct device_attribute *attr, char *buf) { struct platform_device *pdev = to_platform_device(dev); struct syn *sd = platform_get_drvdata(pdev); const ssize_t size = PAGE_SIZE; ssize_t l = 0; int r; mutex_lock(&sd->lock); r = syn_read_u8(sd, sd->control->control + DEVICE_CONTROL_CTRL); if (r < 0) goto out; l += snprintf(buf + l, size - l, "%d\n", (r & 0x03)); out: mutex_unlock(&sd->lock); return l; } static ssize_t syn_store_attr_sleepmode(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct platform_device *pdev = to_platform_device(dev); struct syn *sd = platform_get_drvdata(pdev); int val; int r; if (sscanf(buf, "%i", &val) != 1) { dev_info(&sd->client->dev, "error parsing debug\n"); return count; } if (val & (~0x03)) return count; mutex_lock(&sd->lock); r = syn_read_u8(sd, sd->control->control + DEVICE_CONTROL_CTRL); if (r < 0) goto out; val = (r & (~0x03)) | (val & 0x03); r = syn_write_u8(sd, sd->control->control + DEVICE_CONTROL_CTRL, val); out: mutex_unlock(&sd->lock); return count; } static ssize_t syn_show_attr_proximity(struct device *dev, struct device_attribute *attr, char *buf) { struct platform_device *pdev = to_platform_device(dev); struct syn *sd = platform_get_drvdata(pdev); const ssize_t size = PAGE_SIZE; ssize_t l = 0; int r; mutex_lock(&sd->lock); r = syn_get_proximity_state(sd); mutex_unlock(&sd->lock); if (r < 0) r = 0; l += snprintf(buf + l, size - l, "%d\n", r); return l; } static ssize_t syn_store_attr_proximity(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct platform_device *pdev = to_platform_device(dev); struct syn *sd = platform_get_drvdata(pdev); int val; if (sscanf(buf, "%i", &val) != 1) { dev_info(&sd->client->dev, "error parsing debug\n"); return count; } if (val & (~0x01)) return count; mutex_lock(&sd->lock); syn_set_proximity_state(sd, !!val); mutex_unlock(&sd->lock); return count; } static ssize_t syn_show_attr_sensitivity(struct device *dev, struct device_attribute *attr, char *buf) { struct platform_device *pdev = to_platform_device(dev); struct syn *sd = platform_get_drvdata(pdev); const ssize_t size = PAGE_SIZE; ssize_t l = 0; int i; u8 addr; int r; if (!sd->touch) { l += snprintf(buf + l, size - l, "Not available\n"); return l; } addr = sd->touch->control + TOUCH_CONTROL_SENSOR_MAPPING + sd->touch_caps.max_electrodes; if (sd->touch_caps.has_gestures) addr += 2; mutex_lock(&sd->lock); for (i = 0; i < sd->touch_caps.max_electrodes; i++) { r = syn_read_u8(sd, addr + i); if (r < 0) { l += snprintf(buf + l, size - l, "Read error %d\n", r); goto out; } else l += snprintf(buf + l, size - l, "0x%x ", r); } l += snprintf(buf + l, size - l, "\n"); out: mutex_unlock(&sd->lock); return l; } static ssize_t syn_store_attr_sensitivity(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct platform_device *pdev = to_platform_device(dev); struct syn *sd = platform_get_drvdata(pdev); int r; int addr; int base; int value; if (!sd->touch) return count; if (sscanf(buf, "%d %i", &addr, &value) != 2) { dev_info(&sd->client->dev, "error parsing sensitivity info \n"); return count; } if (addr >= sd->touch_caps.max_electrodes) { dev_info(&sd->client->dev, "electorode number out of bounds %d > %d\n", addr, sd->touch_caps.max_electrodes); return count; } base = sd->touch->control + TOUCH_CONTROL_SENSOR_MAPPING + sd->touch_caps.max_electrodes; if (sd->touch_caps.has_gestures) base += 2; mutex_lock(&sd->lock); r = syn_write_u8(sd, base + addr, value); if (r < 0) { dev_err(&sd->client->dev, "write failed with %d\n", r); goto out; } r = syn_read_u8(sd, base + addr); if (r < 0) { dev_err(&sd->client->dev, "read failed with %d\n", r); goto out; } if (r != value) { dev_warn(&sd->client->dev, "value verify error 0x%x != 0x%x\n", r, value); } out: mutex_unlock(&sd->lock); return count; } static ssize_t syn_show_attr_sensormap(struct device *dev, struct device_attribute *attr, char *buf) { struct platform_device *pdev = to_platform_device(dev); struct syn *sd = platform_get_drvdata(pdev); const ssize_t size = PAGE_SIZE; ssize_t l = 0; int i; u8 addr; int r; if (!sd->touch) { l += snprintf(buf + l, size - l, "Not available\n"); return l; } addr = sd->touch->control + TOUCH_CONTROL_SENSOR_MAPPING; if (sd->touch_caps.has_gestures) addr += 2; mutex_lock(&sd->lock); for (i = 0; i < sd->touch_caps.max_electrodes; i++) { r = syn_read_u8(sd, addr + i); if (r < 0) { l += snprintf(buf + l, size - l, "Read error %d\n", r); goto out; } else l += snprintf(buf + l, size - l, "%s: %d\n", r & 0x80 ? "Y" : "X", r & 0x1F); } l += snprintf(buf + l, size - l, "\n"); out: mutex_unlock(&sd->lock); return l; } static ssize_t syn_show_attr_reg_dump(struct device *dev, struct device_attribute *attr, char *buf) { struct platform_device *pdev = to_platform_device(dev); struct syn *sd = platform_get_drvdata(pdev); const ssize_t size = PAGE_SIZE; ssize_t l = 0; int i; int r; if (!sd->touch) { l += snprintf(buf + l, size - l, "Not available\n"); return l; } mutex_lock(&sd->lock); for (i = 0; i < 0xff; i++) { r = syn_read_u8(sd, i); if (r < 0) { l += snprintf(buf + l, size - l, "Read error at 0x%x %d\n", i, r); goto out; } else l += snprintf(buf + l, size - l, "0x%02x: 0x%02x (%d)\n", i, r, r); } l += snprintf(buf + l, size - l, "\n"); out: mutex_unlock(&sd->lock); return l; } static ssize_t syn_store_attr_reg_dump(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct platform_device *pdev = to_platform_device(dev); struct syn *sd = platform_get_drvdata(pdev); int addr; int value; if (!sd->touch) return count; if (sscanf(buf, "%i", &addr) != 1) { dev_info(&sd->client->dev, "error parsing addr\n"); return count; } if (addr < 0 || addr > 0xff) { dev_info(&sd->client->dev, "error 0x%x out of bounds\n", addr); return count; } mutex_lock(&sd->lock); value = syn_read_u8(sd, addr); if (value < 0) { dev_info(&sd->client->dev, "error %d reading from 0x%x\n", value, addr); goto out; } dev_info(&sd->client->dev, "0x%x: 0x%x\n", addr, value); out: mutex_unlock(&sd->lock); return count; } static ssize_t syn_show_attr_debug(struct device *dev, struct device_attribute *attr, char *buf) { struct platform_device *pdev = to_platform_device(dev); struct syn *sd = platform_get_drvdata(pdev); const ssize_t size = PAGE_SIZE; ssize_t l = 0; mutex_lock(&sd->lock); l += snprintf(buf + l, size - l, "0x%02x\n", sd->debug_flag); mutex_unlock(&sd->lock); return l; } static ssize_t syn_store_attr_debug(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct platform_device *pdev = to_platform_device(dev); struct syn *sd = platform_get_drvdata(pdev); int flag = 0; if (sscanf(buf, "%i", &flag) != 1) { dev_info(&sd->client->dev, "error parsing debug\n"); return count; } mutex_lock(&sd->lock); sd->debug_flag = flag; mutex_unlock(&sd->lock); return count; } static ssize_t syn_store_attr_latency(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct platform_device *pdev = to_platform_device(dev); struct syn *sd = platform_get_drvdata(pdev); mutex_lock(&sd->lock); sd->t_work_min = ULONG_MAX; sd->t_work_max = 0; sd->t_work = 0; sd->t_work_c = 0; sd->t_wakeup_min = ULONG_MAX; sd->t_wakeup_max = 0; sd->t_wakeup = 0; sd->t_wakeup_c = 0; sd->t_count = 0; mutex_unlock(&sd->lock); return count; } static ssize_t syn_show_attr_latency(struct device *dev, struct device_attribute *attr, char *buf) { struct platform_device *pdev = to_platform_device(dev); struct syn *sd = platform_get_drvdata(pdev); const ssize_t size = PAGE_SIZE; ssize_t l = 0; mutex_lock(&sd->lock); l += snprintf(buf + l, size - l, "count %lu: wakeup %lu (%lu, %lu, %lu), " "work %lu (%lu, %lu, %lu)\n", sd->t_count, sd->t_wakeup, sd->t_wakeup_min, sd->t_wakeup_max, sd->t_count ? (sd->t_wakeup_c / sd->t_count) : 0, sd->t_work, sd->t_work_min, sd->t_work_max, sd->t_count ? (sd->t_work_c / sd->t_count) : 0); mutex_unlock(&sd->lock); return l; } static ssize_t syn_show_attr_virtualized(struct device *dev, struct device_attribute *attr, char *buf) { struct platform_device *pdev = to_platform_device(dev); struct syn *sd = platform_get_drvdata(pdev); const ssize_t size = PAGE_SIZE; ssize_t l = 0; mutex_lock(&sd->lock); l += snprintf(buf + l, size - l, "%d\n", sd->virtualized); mutex_unlock(&sd->lock); return l; } static ssize_t syn_store_attr_virtualized(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct platform_device *pdev = to_platform_device(dev); struct syn *sd = platform_get_drvdata(pdev); int val; if (sscanf(buf, "%i", &val) != 1) { dev_info(&sd->client->dev, "error parsing virtualized\n"); return count; } if (val & (~0x01)) return count; mutex_lock(&sd->lock); sd->virtualized = val; mutex_unlock(&sd->lock); return count; } static DEVICE_ATTR(flash, S_IWUSR | S_IRUGO, syn_show_attr_flash, syn_store_attr_flash); static DEVICE_ATTR(product_id, S_IRUGO, syn_show_attr_product_id, NULL); static DEVICE_ATTR(product_family, S_IRUGO, syn_show_attr_product_family, NULL); static DEVICE_ATTR(firmware_version, S_IRUGO, syn_show_attr_firmware_version, NULL); static DEVICE_ATTR(selftest, S_IRUGO, syn_show_attr_selftest, NULL); static DEVICE_ATTR(reset, S_IWUSR, NULL, syn_store_attr_reset); static DEVICE_ATTR(doze, S_IRUGO | S_IWUSR, syn_show_attr_doze, syn_store_attr_doze); static DEVICE_ATTR(sleepmode, S_IRUGO | S_IWUSR, syn_show_attr_sleepmode, syn_store_attr_sleepmode); static DEVICE_ATTR(proximity, S_IRUGO | S_IWUSR, syn_show_attr_proximity, syn_store_attr_proximity); static DEVICE_ATTR(sensitivity, S_IRUGO | S_IWUSR, syn_show_attr_sensitivity, syn_store_attr_sensitivity); static DEVICE_ATTR(sensormap, S_IRUGO, syn_show_attr_sensormap, NULL); static DEVICE_ATTR(dump, S_IRUGO | S_IWUSR, syn_show_attr_reg_dump, syn_store_attr_reg_dump); static DEVICE_ATTR(debug, S_IRUGO | S_IWUSR, syn_show_attr_debug, syn_store_attr_debug); static DEVICE_ATTR(latency, S_IRUGO | S_IWUSR, syn_show_attr_latency, syn_store_attr_latency); static DEVICE_ATTR(virtualized, S_IRUGO | S_IWUSR, syn_show_attr_virtualized, syn_store_attr_virtualized); static struct attribute *syn_attrs[] = { &dev_attr_flash.attr, &dev_attr_product_id.attr, &dev_attr_product_family.attr, &dev_attr_firmware_version.attr, &dev_attr_selftest.attr, &dev_attr_reset.attr, &dev_attr_doze.attr, &dev_attr_sleepmode.attr, &dev_attr_proximity.attr, &dev_attr_sensitivity.attr, &dev_attr_sensormap.attr, &dev_attr_dump.attr, &dev_attr_debug.attr, &dev_attr_latency.attr, &dev_attr_virtualized.attr, NULL, }; static struct attribute_group syn_attr_group = { .attrs = syn_attrs, }; static void syn_create_sysfs(struct syn *sd) { int r; r = sysfs_create_group(&sd->client->dev.kobj, &syn_attr_group); if (r) { dev_err(&sd->client->dev, "failed to create flash sysfs files\n"); } } static void syn_remove_sysfs(struct syn *sd) { sysfs_remove_group(&sd->client->dev.kobj, &syn_attr_group); } static int syn_read_func_descs(struct syn *sd) { int properties = 0; int fun = 0; int r = 0; int addr = REG_PDT_PROPERTIES; sd->func_descs_valid = 0; sd->interrupt_sources = 0; properties = syn_read_u8(sd, addr--); if (properties < 0) return properties; /* We don't support non standard page select register addr */ if (properties != 0x00) { dev_err(&sd->client->dev, "unsupported pdt\n"); return -ENODEV; } sd->func_desc_num = 0; while (sd->func_desc_num < MAX_FUNC_DESCS) { struct func_desc * const f = &sd->func_desc[sd->func_desc_num]; u8 regs[5]; fun = syn_read_u8(sd, addr); if (fun < 0) return fun; if (fun == 0x00) goto out; if (sd->debug_flag & DFLAG_VERBOSE) dev_info(&sd->client->dev, "found function 0x%x\n", fun); f->num = fun; addr -= 5; r = syn_read_block(sd, addr, regs, 5); if (r != 5) { dev_err(&sd->client->dev, "error reading pdt\n"); return -ENODEV; } f->query = regs[0]; f->command = regs[1]; f->control = regs[2]; f->data = regs[3]; f->intr_sources = regs[4] & 0x07; f->version = (regs[4] >> 5) & 0x3; if (f->intr_sources) { f->intr_start_bit = sd->interrupt_sources; sd->interrupt_sources += f->intr_sources; } sd->func_desc_num++; addr--; } out: /* Put shortcuts in place */ sd->control = syn_get_func_desc(sd, FUNC_DEVICE_CONTROL); sd->flash = syn_get_func_desc(sd, FUNC_FLASH); sd->touch = syn_get_func_desc(sd, FUNC_2D); sd->buttons = syn_get_func_desc(sd, FUNC_BUTTONS); sd->bist = syn_get_func_desc(sd, FUNC_BIST); sd->prox = syn_get_func_desc(sd, FUNC_PROXIMITY); if (sd->touch == NULL) dev_warn(&sd->client->dev, "no 2d functionality found! (in flash mode ?)\n"); if (sd->flash) { r = syn_flash_query_caps(sd); if (r) return r; } else dev_warn(&sd->client->dev, "no flash functionality found!\n"); if (sd->control) { sd->func_descs_valid = 1; return 0; } return -1; } static int syn_register_handlers(struct syn *sd) { int r; r = syn_register_intr_handler(sd, FUNC_DEVICE_CONTROL, syn_isr_device_control); if (r < 0) { dev_err(&sd->client->dev, "no device control, cant continue\n"); return r; } /* * Don't care about return values here. * Install interrupt handlers for every function * (even if they dont exist) */ syn_register_intr_handler(sd, FUNC_BIST, syn_isr_bist); syn_register_intr_handler(sd, FUNC_BUTTONS, syn_isr_buttons); syn_register_intr_handler(sd, FUNC_TIMER, syn_isr_timer); syn_register_intr_handler(sd, FUNC_2D, syn_isr_2d); syn_register_intr_handler(sd, FUNC_FLASH, syn_isr_flash); syn_register_intr_handler(sd, FUNC_PROXIMITY, syn_isr_proximity); return 0; } static int syn_touch_get_max_pos(struct syn *sd, u8 reg) { int data; data = syn_read_u16(sd, sd->touch->control + reg); if (data < 0) return data; return data & 0x00000fff; } static int syn_touch_get_max_x_pos(struct syn *sd) { return syn_touch_get_max_pos(sd, TOUCH_CONTROL_SENSOR_MAX_X); } static int syn_touch_get_max_y_pos(struct syn *sd) { return syn_touch_get_max_pos(sd, TOUCH_CONTROL_SENSOR_MAX_Y); } static int syn_button_query_caps(struct syn *sd) { int r; r = syn_read_u8(sd, sd->buttons->query + BUTTON_QUERY_BUTTON_COUNT); if (r < 0) return r; if (r > MAX_BUTTONS) return -EINVAL; sd->button_caps.button_count = r & BUTTON_QUERY_BUTTON_MASK; return 0; } static int syn_touch_query_caps(struct syn *sd) { int r; u8 data[TOUCH_QUERY_LEN] = {0}; if (sd->touch == NULL) return -ENODEV; r = syn_read_block(sd, sd->touch->query + TOUCH_QUERY_NUM_SENSORS, data, TOUCH_QUERY_LEN); if (r < 0) return r; if (data[0] != 0) { dev_err(&sd->client->dev, "no support for multiple sensors\n"); return -ENODEV; } sd->touch_caps.is_configurable = (data[1] & (1 << 7)) ? 1 : 0; sd->touch_caps.has_gestures = (data[1] & (1 << 5)) ? 1 : 0; sd->touch_caps.has_abs_mode = (data[1] & (1 << 4)) ? 1 : 0; sd->touch_caps.has_rel_mode = (data[1] & (1 << 3)) ? 1 : 0; sd->touch_caps.finger_count = (data[1] & 0x07) + 1; sd->touch_caps.x_electrodes = (data[2] & 0x1f); sd->touch_caps.y_electrodes = (data[3] & 0x1f); sd->touch_caps.max_electrodes = (data[4] & 0x1f); sd->touch_caps.abs_data_size = (data[5] & 0x03); if (sd->touch_caps.finger_count > MAX_TOUCH_POINTS || sd->touch_caps.has_rel_mode || /* sd->touch_caps.has_gestures || */ sd->touch_caps.abs_data_size) { dev_err(&sd->client->dev, "no support for this sensor\n"); return -ENODEV; } r = syn_touch_get_max_x_pos(sd); if (r < 0) return r; sd->touch_caps.max_x = r; r = syn_touch_get_max_y_pos(sd); if (r < 0) return r; sd->touch_caps.max_y = r; return 0; } static int syn_reset_device(struct syn *sd) { int r; /* * We get called from various contexts, for example after firmware * change. Resetting with state registermap would be disastrous * so we reread everything in order to be sure to write * to correct register. */ r = syn_read_func_descs(sd); if (!sd->control) { dev_err(&sd->client->dev, "no control. can't reset!\n"); return -1; } dev_info(&sd->client->dev, "resetting device (reg 0x%x)\n", sd->control->command + DEVICE_CONTROL_COMMAND); r = syn_write_u8(sd, sd->control->control + DEVICE_CONTROL_INTR_ENABLE, 0); r = syn_control_data_read(sd, DEVICE_CONTROL_DATA_INTR_STATUS); sd->func_descs_valid = 0; r = syn_write_u8(sd, sd->control->command + DEVICE_CONTROL_COMMAND, DEVICE_COMMAND_RESET); r = syn_wait_for_attn(sd, 100 * 1000, 0); r = syn_wait_for_attn(sd, 100 * 1000, 1); r = syn_wait_for_attn(sd, 500 * 1000, 0); return 0; } static int syn_initialize(struct syn *sd) { int r; char prod_id[PRODUCT_ID_LEN + 1]; int prod_family; int prod_fw_version; syn_clear_device_state(sd); r = syn_read_u8(sd, REG_PAGE_SELECT); if (r < 0) { dev_err(&sd->client->dev, "error reading page select\n"); goto err_out; } if (r != 0x00) { dev_err(&sd->client->dev, "page select non zero\n"); r = -ENODEV; goto err_out; } r = syn_read_func_descs(sd); if (r < 0) { dev_err(&sd->client->dev, "error reading func descs\n"); goto err_out; } if (!sd->control) { dev_err(&sd->client->dev, "no control functions found\n"); r = -ENODEV; goto err_out; } /* Clear the Unconfigured bit */ r = syn_write_u8(sd, sd->control->control + DEVICE_CONTROL_CTRL, DEVICE_CONTROL_CONFIGURED); if (!sd->bist) dev_warn(&sd->client->dev, "no bist capabilities found\n"); if (sd->touch) { r = syn_touch_query_caps(sd); if (r < 0) { dev_err(&sd->client->dev, "error reading touch capabilities\n"); sd->touch = NULL; } } else { dev_err(&sd->client->dev, "no touch capabilities found\n"); } if (sd->buttons) { r = syn_button_query_caps(sd); if (r < 0) { dev_err(&sd->client->dev, "error reading button capabilities\n"); sd->buttons = NULL; } } else { dev_err(&sd->client->dev, "no button capabilities found\n"); } r = syn_read_block(sd, sd->control->query + DEVICE_CONTROL_QUERY_PROD_ID, prod_id, PRODUCT_ID_LEN); if (r != PRODUCT_ID_LEN) { dev_err(&sd->client->dev, "unable to read product id\n"); r = -ENODEV; goto err_out; } prod_id[r] = 0; prod_family = syn_control_query_read(sd, DEVICE_CONTROL_QUERY_PROD_FAMILY); if (prod_family < 0) { dev_err(&sd->client->dev, "unable to read product family\n"); goto err_out; } prod_fw_version = syn_control_query_read(sd, DEVICE_CONTROL_QUERY_FW_VER); if (prod_fw_version < 0) { dev_err(&sd->client->dev, "unable to read product family\n"); goto err_out; } printk(KERN_INFO DRIVER_NAME ": product ID: %s family:%d fw:%d\n", prod_id, prod_family, prod_fw_version); r = syn_register_handlers(sd); if (r) { dev_err(&sd->client->dev, "failed to register_handlers\n"); r = -ENODEV; goto err_out; } if (sd->touch) { r = syn_register_input_devices(sd, sd->touch_caps.finger_count); if (r) { dev_err(&sd->client->dev, "failed to register input devices\n"); r = -ENODEV; goto err_out; } } if (sd->prox) { /* By default disable it */ syn_set_proximity_state(sd, 0); } r = syn_control_data_read(sd, DEVICE_CONTROL_DATA_STATUS); if (r < 0) { dev_err(&sd->client->dev, "error %d reading device status\n", r); } /* * If we get reset during initialization, unconfigured should be on */ if (r & (1 << 7)) { dev_warn(&sd->client->dev, "lost config during initialize\n"); sd->failed_inits++; syn_reset_device(sd); goto err_out; } sd->failed_inits = 0; return 0; err_out: return r; } static int syn_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct syn *sd; struct tm12xx_ts_platform_data *pdata; int r; int man_id; sd = kzalloc(sizeof(struct syn), GFP_KERNEL); if (sd == NULL) return -ENOMEM; INIT_WORK(&sd->isr_work, syn_isr_work); i2c_set_clientdata(client, sd); sd->client = client; mutex_init(&sd->lock); sd->t_work_min = ULONG_MAX; sd->t_wakeup_min = ULONG_MAX; sd->wq = create_singlethread_workqueue("tm12xx_wq"); if (!sd->wq) { r = -ENOMEM; goto err_free_dev; } pdata = sd->client->dev.platform_data; if (!pdata) { dev_err(&client->dev, "no platform data found\n"); r = -ENODEV; goto err_free_dev; } sd->gpio_intr = pdata->gpio_intr; if (pdata->suspend_state == SYNTM12XX_SLEEP_ON_SUSPEND) sd->suspend_mode = DEVICE_CONTROL_SLEEP_SENSOR; else sd->suspend_mode = DEVICE_CONTROL_SLEEP_NORMAL; r = syn_read_func_descs(sd); if (r < 0) { dev_err(&client->dev, "error reading func descs\n"); goto err_free_dev; } r = syn_write_u8(sd, sd->control->control + DEVICE_CONTROL_INTR_ENABLE, 0); if (r < 0) goto err_free_dev; r = syn_control_data_read(sd, DEVICE_CONTROL_DATA_INTR_STATUS); if (r < 0) goto err_free_dev; man_id = syn_control_query_read(sd, DEVICE_CONTROL_QUERY_MANID); if (man_id < 0) { dev_dbg(&client->dev, "unable to get manufacturer id\n"); r = -ENODEV; goto err_free_dev; } printk(KERN_INFO DRIVER_NAME ": " DRIVER_DESC " found man id %x (%d)\n", man_id, man_id); r = gpio_request(sd->gpio_intr, "Synaptic TM12XX Interrupt"); if (r < 0) { dev_dbg(&client->dev, "unable to get INT GPIO\n"); r = -ENODEV; goto err_free_dev; } gpio_direction_input(sd->gpio_intr); r = syn_register_intr_handler(sd, FUNC_DEVICE_CONTROL, syn_isr_device_control); if (r < 0) { dev_err(&sd->client->dev, "no device control, can't continue\n"); r = -ENODEV; goto err_free_int_gpio; } mutex_lock(&sd->lock); r = request_irq(gpio_to_irq(sd->gpio_intr), syn_isr, IRQF_DISABLED | IRQF_TRIGGER_LOW | IRQF_TRIGGER_FALLING, DRIVER_NAME, sd); if (r) { dev_dbg(&client->dev, "can't get IRQ %d (%d), err %d\n", gpio_to_irq(sd->gpio_intr), sd->gpio_intr, r); goto err_release_mutex; } syn_create_sysfs(sd); /* Initialize thru reset */ r = syn_reset_device(sd); if (r < 0) { dev_err(&client->dev, "error in reset device\n"); goto err_free_irq; } #ifdef CONFIG_HAS_EARLYSUSPEND sd->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1; sd->early_suspend.suspend = syn_ts_early_suspend; sd->early_suspend.resume = syn_ts_late_resume; register_early_suspend(&sd->early_suspend); #endif mutex_unlock(&sd->lock); return 0; err_free_irq: free_irq(gpio_to_irq(sd->gpio_intr), sd); err_release_mutex: mutex_unlock(&sd->lock); err_free_int_gpio: gpio_free(sd->gpio_intr); err_free_dev: kfree(sd); sd = NULL; return r; } static int __exit syn_remove(struct i2c_client *client) { struct syn *sd = i2c_get_clientdata(client); int i; mutex_lock(&sd->lock); if (sd->control) syn_write_u8(sd, sd->control->control + DEVICE_CONTROL_INTR_ENABLE, 0); free_irq(gpio_to_irq(sd->gpio_intr), sd); mutex_unlock(&sd->lock); destroy_workqueue(sd->wq); sd->wq = NULL; syn_remove_sysfs(sd); for (i = 0; i < MAX_TOUCH_POINTS; i++) { if (sd->tp[i].idev) { input_unregister_device(sd->tp[i].idev); input_free_device(sd->tp[i].idev); sd->tp[i].idev = NULL; } } gpio_free(sd->gpio_intr); kfree(sd); i2c_set_clientdata(client, NULL); return 0; } #ifdef CONFIG_PM static int syn_suspend(struct i2c_client *client, pm_message_t msg) { struct syn *sd = i2c_get_clientdata(client); int r; mutex_lock(&sd->lock); r = syn_read_u8(sd, sd->control->control + DEVICE_CONTROL_CTRL); /* If we fail to get previous finetuned power mode, we don't care */ if (r < 0) goto out; sd->device_control_ctrl = r & 0xff; r = syn_write_u8(sd, sd->control->control + DEVICE_CONTROL_CTRL, sd->suspend_mode); out: mutex_unlock(&sd->lock); return 0; } static int syn_resume(struct i2c_client *client) { struct syn *sd = i2c_get_clientdata(client); int r; mutex_lock(&sd->lock); r = syn_write_u8(sd, sd->control->control + DEVICE_CONTROL_CTRL, sd->device_control_ctrl); if (r < 0) dev_err(&sd->client->dev, "error %d restoring device state\n", r); mutex_unlock(&sd->lock); return 0; } #ifdef CONFIG_HAS_EARLYSUSPEND static void syn_ts_early_suspend(struct early_suspend *handler) { struct syn *sd; sd = container_of(handler, struct syn, early_suspend); syn_suspend(sd->client, PMSG_SUSPEND); } static void syn_ts_late_resume(struct early_suspend *handler) { struct syn *sd; sd = container_of(handler, struct syn, early_suspend); syn_resume(sd->client); } #endif #endif static const struct i2c_device_id syn_id[] = { { "tm12xx_ts_primary", 0 }, { "tm12xx_ts_secondary", 1}, { } }; static struct i2c_driver syn_i2c_driver = { .driver = { .name = DRIVER_NAME, }, .probe = syn_probe, .remove = __exit_p(syn_remove), .id_table = syn_id, #ifdef CONFIG_PM #ifdef CONFIG_HAS_EARLYSUSPEND .suspend = NULL, .resume = NULL, #else .suspend = syn_suspend, .resume = syn_resume, #endif #endif }; static int __init syn_init(void) { int r; r = i2c_add_driver(&syn_i2c_driver); if (r < 0) { printk(KERN_WARNING DRIVER_NAME " driver registration failed\n"); return r; } return 0; } static void __exit syn_exit(void) { i2c_del_driver(&syn_i2c_driver); } module_init(syn_init); module_exit(syn_exit); MODULE_AUTHOR("Mika Kuoppala "); MODULE_DESCRIPTION("Synaptic TM12xx Touch controller driver"); MODULE_LICENSE("GPL");