blob: 32fd583c82e4ae3a20ee3d3c51971229b63fef58 [file] [log] [blame]
/*
* syntm12xx.c
* Synaptic TM12XX touchscreen driver
*
* Copyright (C) 2009 Nokia Corporation
* Author: Mika Kuoppala <mika.kuoppala@nokia.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include <linux/module.h>
#include <linux/input.h>
#include <linux/platform_device.h>
#include <linux/i2c.h>
#include <linux/gpio.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/firmware.h>
#include <linux/slab.h>
#ifdef CONFIG_HAS_EARLYSUSPEND
#include <linux/earlysuspend.h>
#endif
#include <plat/syntm12xx.h>
#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 = 0;
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 <addr> <value>\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 <mika.kuoppala@nokia.com>");
MODULE_DESCRIPTION("Synaptic TM12xx Touch controller driver");
MODULE_LICENSE("GPL");