diff options
| author | Evan Wilson <evan@oliodevices.com> | 2015-07-25 14:25:11 -0700 |
|---|---|---|
| committer | Evan Wilson <evan@oliodevices.com> | 2015-07-25 14:25:11 -0700 |
| commit | bb39f055aa4ca296019f355633060974c85928d9 (patch) | |
| tree | c77f8be215f4affb95aadb27d3f6b2721f7c2e49 | |
| parent | a6eec3c603b23f28e62e0a12adb61b7b290731d4 (diff) | |
| parent | c497cf80cda116bc2c2f478b96f21a917e5ca464 (diff) | |
| download | olio-linux-3.10-bb39f055aa4ca296019f355633060974c85928d9.tar.xz olio-linux-3.10-bb39f055aa4ca296019f355633060974c85928d9.zip | |
Merge tag 'maxtouch-v3.10-20150501' into android-3.10-bringup
atmel_mxt_ts driver for Linux kernel v3.10
| -rw-r--r-- | Documentation/devicetree/bindings/input/atmel,maxtouch.txt | 27 | ||||
| -rw-r--r-- | drivers/input/touchscreen/atmel_mxt_ts.c | 770 | ||||
| -rw-r--r-- | include/dt-bindings/input/atmel_mxt_ts.h | 22 | ||||
| -rw-r--r-- | include/linux/platform_data/atmel_mxt_ts.h (renamed from include/linux/i2c/atmel_mxt_ts.h) | 8 |
4 files changed, 543 insertions, 284 deletions
diff --git a/Documentation/devicetree/bindings/input/atmel,maxtouch.txt b/Documentation/devicetree/bindings/input/atmel,maxtouch.txt index 6319f07bfbc..e879f6d1d2c 100644 --- a/Documentation/devicetree/bindings/input/atmel,maxtouch.txt +++ b/Documentation/devicetree/bindings/input/atmel,maxtouch.txt @@ -6,15 +6,34 @@ Required properties: - reg: The I2C address of the device -- interrupts: The sink for the touch controller CHG/IRQ output +- interrupts: The sink for the touchpad's IRQ output See ../interrupt-controller/interrupts.txt -Optional properties for maXTouch device: +Optional properties for main touchpad device: -- linux,gpio-keymap: An array of up to 4 entries indicating the Linux - keycode generated by each GPIO. Linux keycodes are defined in +- linux,gpio-keymap: When enabled, the SPT_GPIOPWN_T19 object sends messages + on GPIO bit changes. An array of up to 8 entries can be provided + indicating the Linux keycode mapped to each bit of the status byte, + starting at the LSB. Linux keycodes are defined in <dt-bindings/input/input.h>. + Note: the numbering of the GPIOs and the bit they start at varies between + maXTouch devices. You must either refer to the documentation, or + experiment to determine which bit corresponds to which input. Use + KEY_RESERVED for unused padding values. + +- atmel,suspend-mode: Select method used to suspend: + MXT_SUSPEND_DEEP_SLEEP - use T7 to suspend the device into deep sleep + MXT_SUSPEND_TOUCH_CTRL - use T9.CTRL to turn off touch processing + Definitions are in <dt-bindings/input/atmel_mxt_ts.h>. + +- atmel,reset-gpio: Configure RESET GPIO. Required for regulator support. + +- atmel,cfg_name: Provide name of configuration file in OBP_RAW format. This + will be downloaded from the firmware loader on probe to the device. + +- atmel,input_name: Override name of input device from the default. + Example: touch@4b { diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index c4249f8b5ba..7298926a75c 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -20,7 +20,7 @@ #include <linux/delay.h> #include <linux/firmware.h> #include <linux/i2c.h> -#include <linux/i2c/atmel_mxt_ts.h> +#include <linux/platform_data/atmel_mxt_ts.h> #include <linux/input/mt.h> #include <linux/interrupt.h> #include <linux/irq.h> @@ -28,6 +28,7 @@ #include <linux/slab.h> #include <linux/regulator/consumer.h> #include <linux/gpio.h> +#include <linux/workqueue.h> #ifdef CONFIG_OF #include <linux/of_gpio.h> @@ -71,7 +72,9 @@ #define MXT_SPT_MESSAGECOUNT_T44 44 #define MXT_SPT_CTECONFIG_T46 46 #define MXT_PROCI_ACTIVE_STYLUS_T63 63 +#define MXT_SPT_DYNAMICCONFIGURATIONCONTAINER_T71 71 #define MXT_TOUCH_MULTITOUCHSCREEN_T100 100 +#define MXT_PROCI_ACTIVESTYLUS_T107 107 /* MXT_GEN_MESSAGE_T5 object */ #define MXT_RPTID_NOMSG 0xff @@ -101,6 +104,7 @@ struct t7_config { #define MXT_POWER_CFG_DEEPSLEEP 1 /* MXT_TOUCH_MULTI_T9 field */ +#define MXT_TOUCH_CTRL 0 #define MXT_T9_ORIENT 9 #define MXT_T9_RANGE 18 @@ -135,9 +139,6 @@ struct t9_range { /* Define for MXT_PROCI_TOUCHSUPPRESSION_T42 */ #define MXT_T42_MSG_TCHSUP (1 << 0) -/* T47 Stylus */ -#define MXT_TOUCH_MAJOR_T47_STYLUS 1 - /* T63 Stylus */ #define MXT_T63_STYLUS_PRESS (1 << 0) #define MXT_T63_STYLUS_RELEASE (1 << 1) @@ -166,7 +167,28 @@ struct t9_range { #define MXT_T100_DETECT (1 << 7) #define MXT_T100_TYPE_MASK 0x70 -#define MXT_T100_TYPE_STYLUS 0x20 + +enum t100_type { + MXT_T100_TYPE_FINGER = 1, + MXT_T100_TYPE_PASSIVE_STYLUS = 2, + MXT_T100_TYPE_ACTIVE_STYLUS = 3, + MXT_T100_TYPE_HOVERING_FINGER = 4, + MXT_T100_TYPE_GLOVE = 5, + MXT_T100_TYPE_LARGE_TOUCH = 6, +}; + +/* Gen2 Active Stylus */ +#define MXT_T107_STYLUS_STYAUX 42 +#define MXT_T107_STYLUS_STYAUX_PRESSURE (1 << 0) +#define MXT_T107_STYLUS_STYAUX_PEAK (1 << 4) + +#define MXT_T107_STYLUS_HOVER (1 << 0) +#define MXT_T107_STYLUS_TIPSWITCH (1 << 1) +#define MXT_T107_STYLUS_BUTTON0 (1 << 2) +#define MXT_T107_STYLUS_BUTTON1 (1 << 3) + +#define MXT_TOUCH_MAJOR_DEFAULT 1 +#define MXT_PRESSURE_DEFAULT 1 /* Delay times */ #define MXT_BACKUP_TIME 50 /* msec */ @@ -179,6 +201,7 @@ struct t9_range { #define MXT_REGULATOR_DELAY 150 /* msec */ #define MXT_CHG_DELAY 100 /* msec */ #define MXT_POWERON_DELAY 150 /* msec */ +#define MXT_BOOTLOADER_WAIT 36E5 /* 1 minute */ /* Command to unlock bootloader */ #define MXT_UNLOCK_CMD_MSB 0xaa @@ -220,6 +243,26 @@ struct mxt_object { u8 num_report_ids; } __packed; +/* Firmware frame structure */ +struct mxt_fw_frame { + __be16 size; + u8 data[]; +}; + +/* Firmware update context */ +struct mxt_flash { + struct mxt_data *data; + const struct firmware *fw; + struct mxt_fw_frame *frame; + loff_t pos; + size_t frame_size; + unsigned int count; + unsigned int retry; + u8 previous; + struct completion flash_completion; + struct delayed_work work; +}; + /* Each client has this additional data */ struct mxt_data { struct i2c_client *client; @@ -256,12 +299,14 @@ struct mxt_data { struct t7_config t7_cfg; u8 num_stylusids; unsigned long t15_keystatus; + u8 stylus_aux_pressure; + u8 stylus_aux_peak; bool use_retrigen_workaround; - bool use_regulator; struct regulator *reg_vdd; struct regulator *reg_avdd; char *fw_name; char *cfg_name; + struct mxt_flash *flash; /* Cached parameters from object table */ u16 T5_address; @@ -269,6 +314,7 @@ struct mxt_data { u8 T6_reportid; u16 T6_address; u16 T7_address; + u16 T71_address; u8 T9_reportid_min; u8 T9_reportid_max; u8 T15_reportid_min; @@ -283,9 +329,7 @@ struct mxt_data { u8 T63_reportid_max; u8 T100_reportid_min; u8 T100_reportid_max; - - /* for fw update in bootloader */ - struct completion bl_completion; + u16 T107_address; /* for reset handling */ struct completion reset_completion; @@ -293,6 +337,9 @@ struct mxt_data { /* for config update handling */ struct completion crc_completion; + /* for power up handling */ + struct completion chg_completion; + /* Indicates whether device is in suspend */ bool suspended; @@ -337,6 +384,7 @@ static bool mxt_object_readable(unsigned int type) case MXT_SPT_USERDATA_T38: case MXT_SPT_DIGITIZER_T43: case MXT_SPT_CTECONFIG_T46: + case MXT_SPT_DYNAMICCONFIGURATIONCONTAINER_T71: return true; default: return false; @@ -582,111 +630,142 @@ static int mxt_probe_bootloader(struct mxt_data *data, bool alt_address) { struct device *dev = &data->client->dev; int error; - u8 val; - bool crc_failure; + u8 buf[3]; + bool crc_failure, extended_id; error = mxt_lookup_bootloader_address(data, alt_address); if (error) return error; - error = mxt_bootloader_read(data, &val, 1); + /* Check bootloader status and version information */ + error = mxt_bootloader_read(data, buf, sizeof(buf)); if (error) return error; - /* Check app crc fail mode */ - crc_failure = (val & ~MXT_BOOT_STATUS_MASK) == MXT_APP_CRC_FAIL; + crc_failure = (buf[0] & ~MXT_BOOT_STATUS_MASK) == MXT_APP_CRC_FAIL; + extended_id = buf[0] & MXT_BOOT_EXTENDED_ID; - dev_err(dev, "Detected bootloader, status:%02X%s\n", - val, crc_failure ? ", APP_CRC_FAIL" : ""); + dev_info(dev, "Found bootloader addr:%02x ID:%u%s%u%s\n", + data->bootloader_addr, + extended_id ? (buf[1] & MXT_BOOT_ID_MASK) : buf[0], + extended_id ? " version:" : "", + extended_id ? buf[2] : 0, + crc_failure ? ", APP_CRC_FAIL" : ""); return 0; } -static u8 mxt_get_bootloader_version(struct mxt_data *data, u8 val) -{ - struct device *dev = &data->client->dev; - u8 buf[3]; +static int mxt_send_bootloader_cmd(struct mxt_data *data, bool unlock); - if (val & MXT_BOOT_EXTENDED_ID) { - if (mxt_bootloader_read(data, &buf[0], 3) != 0) { - dev_err(dev, "%s: i2c failure\n", __func__); - return val; - } - - dev_dbg(dev, "Bootloader ID:%d Version:%d\n", buf[1], buf[2]); +static int mxt_write_firmware_frame(struct mxt_data *data, struct mxt_flash *f) +{ + f->frame = (struct mxt_fw_frame*)(f->fw->data + f->pos); - return buf[0]; - } else { - dev_dbg(dev, "Bootloader ID:%d\n", val & MXT_BOOT_ID_MASK); + /* Take account of CRC bytes */ + f->frame_size = __be16_to_cpu(f->frame->size) + 2U; - return val; - } + /* Write one frame to device */ + return mxt_bootloader_write(data, f->fw->data + f->pos, + f->frame_size); } -static int mxt_check_bootloader(struct mxt_data *data, unsigned int state, - bool wait) +static int mxt_check_bootloader(struct mxt_data *data) { struct device *dev = &data->client->dev; - u8 val; + struct mxt_flash *f = data->flash; + u8 state; int ret; -recheck: - if (wait) { - /* - * In application update mode, the interrupt - * line signals state transitions. We must wait for the - * CHG assertion before reading the status byte. - * Once the status byte has been read, the line is deasserted. - */ - ret = mxt_wait_for_completion(data, &data->bl_completion, - MXT_FW_CHG_TIMEOUT); - if (ret) { - /* - * TODO: handle -ERESTARTSYS better by terminating - * fw update process before returning to userspace - * by writing length 0x000 to device (iff we are in - * WAITING_FRAME_DATA state). - */ - dev_err(dev, "Update wait error %d\n", ret); - return ret; - } + /* Handle interrupt after download/flash process */ + if (f->pos >= f->fw->size) { + complete(&f->flash_completion); + return 0; } - ret = mxt_bootloader_read(data, &val, 1); + ret = mxt_bootloader_read(data, &state, 1); if (ret) return ret; - if (state == MXT_WAITING_BOOTLOAD_CMD) - val = mxt_get_bootloader_version(data, val); + /* Remove don't care bits */ + if (state & ~MXT_BOOT_STATUS_MASK) + state &= ~MXT_BOOT_STATUS_MASK; switch (state) { case MXT_WAITING_BOOTLOAD_CMD: + dev_info(dev, "Unlocking bootloader\n"); + ret = mxt_send_bootloader_cmd(data, true); + if (ret) + return ret; + + break; + case MXT_WAITING_FRAME_DATA: - case MXT_APP_CRC_FAIL: - val &= ~MXT_BOOT_STATUS_MASK; + if ((f->previous != MXT_WAITING_BOOTLOAD_CMD) + && (f->previous != MXT_FRAME_CRC_PASS) + && (f->previous != MXT_FRAME_CRC_FAIL)) + goto unexpected; + + ret = mxt_write_firmware_frame(data, f); + if (ret) + return ret; + break; + + case MXT_FRAME_CRC_CHECK: + if (f->previous != MXT_WAITING_FRAME_DATA) + goto unexpected; + break; + case MXT_FRAME_CRC_PASS: - if (val == MXT_FRAME_CRC_CHECK) { - goto recheck; - } else if (val == MXT_FRAME_CRC_FAIL) { - dev_err(dev, "Bootloader CRC fail\n"); - return -EINVAL; + if (f->previous != MXT_FRAME_CRC_CHECK) + goto unexpected; + + /* Next frame */ + f->retry = 0; + f->pos += f->frame_size; + f->count++; + + if (f->pos >= f->fw->size) + dev_info(dev, "Sent %u frames, %zu bytes\n", + f->count, f->fw->size); + else if (f->count % 50 == 0) + dev_dbg(dev, "Sent %u frames, %lld/%zu bytes\n", + f->count, f->pos, f->fw->size); + + break; + + case MXT_FRAME_CRC_FAIL: + f->retry++; + + if (f->retry > 20) { + dev_err(dev, "Retry count exceeded\n"); + return -EIO; + } else { + dev_dbg(dev, "Bootloader frame CRC failure\n"); } + + /* Back off by 20ms per retry */ + msleep(f->retry * 20); + break; + default: return -EINVAL; } - if (val != state) { - dev_err(dev, "Invalid bootloader state %02X != %02X\n", - val, state); - return -EINVAL; - } + f->previous = state; + + /* Poll after 0.1s if no interrupt received */ + schedule_delayed_work(&f->work, HZ / 10); return 0; + +unexpected: + dev_err(dev, "Unexpected state transition\n"); + return -EINVAL; } -static int mxt_send_bootloader_cmd(struct mxt_data *data, bool unlock) +int mxt_send_bootloader_cmd(struct mxt_data *data, bool unlock) { int ret; u8 buf[2]; @@ -839,6 +918,20 @@ static void mxt_proc_t6_messages(struct mxt_data *data, u8 *msg) data->t6_status = status; } +static int mxt_write_object(struct mxt_data *data, + u8 type, u8 offset, u8 val) +{ + struct mxt_object *object; + u16 reg; + + object = mxt_get_object(data, type); + if (!object || offset >= mxt_obj_size(object)) + return -EINVAL; + + reg = object->start_address; + return mxt_write_reg(data->client, reg + offset, val); +} + static void mxt_input_button(struct mxt_data *data, u8 *message) { struct input_dev *input = data->input_dev; @@ -922,7 +1015,7 @@ static void mxt_proc_t9_message(struct mxt_data *data, u8 *message) /* A size of zero indicates touch is from a linked T47 Stylus */ if (area == 0) { - area = MXT_TOUCH_MAJOR_T47_STYLUS; + area = MXT_TOUCH_MAJOR_DEFAULT; tool = MT_TOOL_PEN; } else { tool = MT_TOOL_FINGER; @@ -949,9 +1042,17 @@ static void mxt_proc_t100_message(struct mxt_data *data, u8 *message) struct input_dev *input_dev = data->input_dev; int id; u8 status; + u8 type; int x; int y; int tool; + u8 major = 0; + u8 pressure = 0; + u8 orientation = 0; + bool active = false; + bool hover = false; + bool eraser = false; + bool barrel = false; id = message[0] - data->T100_reportid_min - 2; @@ -963,53 +1064,108 @@ static void mxt_proc_t100_message(struct mxt_data *data, u8 *message) x = (message[3] << 8) | message[2]; y = (message[5] << 8) | message[4]; - dev_dbg(dev, - "[%u] status:%02X x:%u y:%u area:%02X amp:%02X vec:%02X\n", - id, - status, - x, y, - data->t100_aux_area ? message[data->t100_aux_area] : 0, - data->t100_aux_ampl ? message[data->t100_aux_ampl] : 0, - data->t100_aux_vect ? message[data->t100_aux_vect] : 0); + if (status & MXT_T100_DETECT) { + type = (status & MXT_T100_TYPE_MASK) >> 4; - input_mt_slot(input_dev, id); + switch (type) { + case MXT_T100_TYPE_HOVERING_FINGER: + hover = true; + /* fall through */ + case MXT_T100_TYPE_FINGER: + case MXT_T100_TYPE_GLOVE: + active = true; + tool = MT_TOOL_FINGER; - if (status & MXT_T100_DETECT) { - if ((status & MXT_T100_TYPE_MASK) == MXT_T100_TYPE_STYLUS) + if (data->t100_aux_area) + major = message[data->t100_aux_area]; + if (data->t100_aux_ampl) + pressure = message[data->t100_aux_ampl]; + if (data->t100_aux_vect) + orientation = message[data->t100_aux_vect]; + + break; + + case MXT_T100_TYPE_PASSIVE_STYLUS: + active = true; tool = MT_TOOL_PEN; - else - tool = MT_TOOL_FINGER; - /* Touch active */ - input_mt_report_slot_state(input_dev, tool, 1); - input_report_abs(input_dev, ABS_MT_POSITION_X, x); - input_report_abs(input_dev, ABS_MT_POSITION_Y, y); + /* Passive stylus is reported with size zero so + * hardcode */ + major = MXT_TOUCH_MAJOR_DEFAULT; - if (data->t100_aux_ampl) - input_report_abs(input_dev, ABS_MT_PRESSURE, - message[data->t100_aux_ampl]); + if (data->t100_aux_ampl) + pressure = message[data->t100_aux_ampl]; - if (data->t100_aux_area) { - if (tool == MT_TOOL_PEN) - input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR, - MXT_TOUCH_MAJOR_T47_STYLUS); - else - input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR, - message[data->t100_aux_area]); + break; + + case MXT_T100_TYPE_ACTIVE_STYLUS: + /* stylus in range, but position unavailable */ + if (!(message[6] & MXT_T107_STYLUS_HOVER)) + break; + + active = true; + tool = MT_TOOL_PEN; + major = MXT_TOUCH_MAJOR_DEFAULT; + eraser = message[6] & MXT_T107_STYLUS_BUTTON0; + barrel = message[6] & MXT_T107_STYLUS_BUTTON1; + + if (!(message[6] & MXT_T107_STYLUS_TIPSWITCH)) + hover = true; + else if (data->stylus_aux_pressure) + pressure = message[data->stylus_aux_pressure]; + + break; + + case MXT_T100_TYPE_LARGE_TOUCH: + /* Ignore suppressed touch */ + break; + + default: + dev_dbg(dev, "Unexpected T100 type\n"); + return; } + } + + if (hover) { + pressure = 0; + major = 0; + } else if (active) { + /* + * Values reported should be non-zero if tool is touching the + * device + */ + if (pressure == 0) + pressure = MXT_PRESSURE_DEFAULT; + + if (major == 0) + major = MXT_TOUCH_MAJOR_DEFAULT; + } + + input_mt_slot(input_dev, id); - if (data->t100_aux_vect) - input_report_abs(input_dev, ABS_MT_ORIENTATION, - message[data->t100_aux_vect]); + if (active) { + dev_dbg(dev, "[%u] type:%u x:%u y:%u a:%02X p:%02X v:%02X\n", + id, type, x, y, major, pressure, orientation); + + input_mt_report_slot_state(input_dev, tool, 1); + input_report_abs(input_dev, ABS_MT_POSITION_X, x); + input_report_abs(input_dev, ABS_MT_POSITION_Y, y); + input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR, major); + input_report_abs(input_dev, ABS_MT_PRESSURE, pressure); + input_report_abs(input_dev, ABS_MT_ORIENTATION, orientation); + + input_report_key(input_dev, BTN_STYLUS, eraser); + input_report_key(input_dev, BTN_STYLUS2, barrel); } else { - /* Touch no longer active, close out slot */ - input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, 0); + dev_dbg(dev, "[%u] release\n", id); + + /* close out slot */ + input_mt_report_slot_state(input_dev, 0, 0); } data->update_input = true; } - static void mxt_proc_t15_messages(struct mxt_data *data, u8 *msg) { struct input_dev *input_dev = data->input_dev; @@ -1327,10 +1483,13 @@ static irqreturn_t mxt_interrupt(int irq, void *dev_id) { struct mxt_data *data = dev_id; + complete(&data->chg_completion); + if (data->in_bootloader) { - /* bootloader state transition completion */ - complete(&data->bl_completion); - return IRQ_HANDLED; + if (data->flash && &data->flash->work) + cancel_delayed_work_sync(&data->flash->work); + + return IRQ_RETVAL(mxt_check_bootloader(data)); } if (!data->object_table) @@ -1380,7 +1539,9 @@ static int mxt_soft_reset(struct mxt_data *data) struct device *dev = &data->client->dev; int ret = 0; - dev_info(dev, "Resetting chip\n"); + dev_info(dev, "Resetting device\n"); + + disable_irq(data->irq); INIT_COMPLETION(data->reset_completion); @@ -1388,6 +1549,11 @@ static int mxt_soft_reset(struct mxt_data *data) if (ret) return ret; + /* Ignore CHG line for 100ms after reset */ + msleep(100); + + enable_irq(data->irq); + ret = mxt_wait_for_completion(data, &data->reset_completion, MXT_RESET_TIMEOUT); if (ret) @@ -1644,6 +1810,7 @@ static int mxt_update_cfg(struct mxt_data *data, const struct firmware *cfg) u32 info_crc, config_crc, calculated_crc; u8 *config_mem; size_t config_mem_size; + u16 crc_start = 0; mxt_update_crc(data, MXT_COMMAND_REPORTALL, 1); @@ -1721,10 +1888,8 @@ static int mxt_update_cfg(struct mxt_data *data, const struct firmware *cfg) MXT_INFO_CHECKSUM_SIZE; config_mem_size = data->mem_size - cfg_start_ofs; config_mem = kzalloc(config_mem_size, GFP_KERNEL); - if (!config_mem) { - dev_err(dev, "Failed to allocate memory\n"); + if (!config_mem) return -ENOMEM; - } ret = mxt_prepare_cfg_mem(data, cfg, data_pos, cfg_start_ofs, config_mem, config_mem_size); @@ -1732,20 +1897,22 @@ static int mxt_update_cfg(struct mxt_data *data, const struct firmware *cfg) goto release_mem; /* Calculate crc of the received configs (not the raw config file) */ - if (data->T7_address < cfg_start_ofs) { - dev_err(dev, "Bad T7 address, T7addr = %x, config offset %x\n", - data->T7_address, cfg_start_ofs); - ret = 0; - goto release_mem; - } + if (data->T71_address) + crc_start = data->T71_address; + else if (data->T7_address) + crc_start = data->T7_address; + else + dev_warn(dev, "Could not find CRC start\n"); - calculated_crc = mxt_calculate_crc(config_mem, - data->T7_address - cfg_start_ofs, - config_mem_size); + if (crc_start > cfg_start_ofs) { + calculated_crc = mxt_calculate_crc(config_mem, + crc_start - cfg_start_ofs, + config_mem_size); - if (config_crc > 0 && config_crc != calculated_crc) - dev_warn(dev, "Config CRC error, calculated=%06X, file=%06X\n", - calculated_crc, config_crc); + if (config_crc > 0 && config_crc != calculated_crc) + dev_warn(dev, "Config CRC in file inconsistent, calculated=%06X, file=%06X\n", + calculated_crc, config_crc); + } ret = mxt_upload_cfg_mem(data, cfg_start_ofs, config_mem, config_mem_size); @@ -1776,9 +1943,23 @@ static int mxt_acquire_irq(struct mxt_data *data) { int error; - enable_irq(data->irq); + if (!data->irq) { + error = request_threaded_irq(data->client->irq, NULL, + mxt_interrupt, + data->pdata->irqflags | IRQF_ONESHOT, + data->client->name, data); + if (error) { + dev_err(&data->client->dev, "Error requesting irq\n"); + return error; + } + + /* Presence of data->irq means IRQ initialised */ + data->irq = data->client->irq; + } else { + enable_irq(data->irq); + } - if (data->use_retrigen_workaround) { + if (data->object_table && data->use_retrigen_workaround) { error = mxt_process_messages_until_invalid(data); if (error) return error; @@ -1805,11 +1986,11 @@ static void mxt_free_object_table(struct mxt_data *data) data->raw_info_block = NULL; kfree(data->msg_buf); data->msg_buf = NULL; - data->T5_address = 0; data->T5_msg_size = 0; data->T6_reportid = 0; data->T7_address = 0; + data->T71_address = 0; data->T9_reportid_min = 0; data->T9_reportid_max = 0; data->T15_reportid_min = 0; @@ -1883,6 +2064,9 @@ static int mxt_parse_object_table(struct mxt_data *data, case MXT_GEN_POWER_T7: data->T7_address = object->start_address; break; + case MXT_SPT_DYNAMICCONFIGURATIONCONTAINER_T71: + data->T71_address = object->start_address; + break; case MXT_TOUCH_MULTI_T9: /* Only handle messages from first T9 instance */ data->T9_reportid_min = min_id; @@ -1922,6 +2106,9 @@ static int mxt_parse_object_table(struct mxt_data *data, /* first two report IDs reserved */ data->num_touchids = object->num_report_ids - 2; break; + case MXT_PROCI_ACTIVESTYLUS_T107: + data->T107_address = object->start_address; + break; } end_address = object->start_address @@ -1942,10 +2129,8 @@ static int mxt_parse_object_table(struct mxt_data *data, data->msg_buf = kcalloc(data->max_reportid, data->T5_msg_size, GFP_KERNEL); - if (!data->msg_buf) { - dev_err(&client->dev, "Failed to allocate message buffer\n"); + if (!data->msg_buf) return -ENOMEM; - } return 0; } @@ -1967,10 +2152,8 @@ static int mxt_read_info_block(struct mxt_data *data) /* Read 7-byte ID information block starting at address 0 */ size = sizeof(struct mxt_info); id_buf = kzalloc(size, GFP_KERNEL); - if (!id_buf) { - dev_err(&client->dev, "Failed to allocate memory\n"); + if (!id_buf) return -ENOMEM; - } error = __mxt_read_reg(client, 0, size, id_buf); if (error) { @@ -1985,7 +2168,6 @@ static int mxt_read_info_block(struct mxt_data *data) buf = krealloc(id_buf, size, GFP_KERNEL); if (!buf) { - dev_err(&client->dev, "Failed to allocate memory\n"); error = -ENOMEM; goto err_free_mem; } @@ -2056,14 +2238,19 @@ static void mxt_regulator_enable(struct mxt_data *data) if (error) return; + /* + * According to maXTouch power sequencing specification, RESET line + * must be kept low until some time after regulators come up to + * voltage + */ msleep(MXT_REGULATOR_DELAY); gpio_set_value(data->pdata->gpio_reset, 1); msleep(MXT_CHG_DELAY); retry_wait: - INIT_COMPLETION(data->bl_completion); + INIT_COMPLETION(data->chg_completion); data->in_bootloader = true; - error = mxt_wait_for_completion(data, &data->bl_completion, + error = mxt_wait_for_completion(data, &data->chg_completion, MXT_POWERON_DELAY); if (error == -EINTR) goto retry_wait; @@ -2077,18 +2264,14 @@ static void mxt_regulator_disable(struct mxt_data *data) regulator_disable(data->reg_avdd); } -static void mxt_probe_regulators(struct mxt_data *data) +static int mxt_probe_regulators(struct mxt_data *data) { struct device *dev = &data->client->dev; int error; - /* - * According to maXTouch power sequencing specification, RESET line - * must be kept low until some time after regulators come up to - * voltage - */ if (!gpio_is_valid(data->pdata->gpio_reset)) { dev_dbg(dev, "Must have reset GPIO to use regulator support\n"); + error = -EINVAL; goto fail; } @@ -2106,18 +2289,17 @@ static void mxt_probe_regulators(struct mxt_data *data) goto fail_release; } - data->use_regulator = true; mxt_regulator_enable(data); dev_dbg(dev, "Initialised regulators\n"); - return; + return 0; fail_release: regulator_put(data->reg_vdd); fail: data->reg_vdd = NULL; data->reg_avdd = NULL; - data->use_regulator = false; + return error; } static int mxt_read_t9_resolution(struct mxt_data *data) @@ -2168,8 +2350,6 @@ static int mxt_read_t9_resolution(struct mxt_data *data) return 0; } -static void mxt_start(struct mxt_data *data); -static void mxt_stop(struct mxt_data *data); static int mxt_input_open(struct input_dev *dev); static void mxt_input_close(struct input_dev *dev); @@ -2188,10 +2368,8 @@ static int mxt_initialize_t9_input_device(struct mxt_data *data) dev_warn(dev, "Failed to initialize T9 resolution\n"); input_dev = input_allocate_device(); - if (!input_dev) { - dev_err(dev, "Failed to allocate memory\n"); + if (!input_dev) return -ENOMEM; - } input_dev->name = "Atmel maXTouch Touchscreen"; input_dev->phys = data->phys; @@ -2287,6 +2465,40 @@ err_free_mem: return error; } +static int mxt_read_t107_stylus_config(struct mxt_data *data) +{ + struct i2c_client *client = data->client; + int error; + struct mxt_object *object; + u8 styaux; + int aux; + + object = mxt_get_object(data, MXT_PROCI_ACTIVESTYLUS_T107); + if (!object) + return 0; + + error = __mxt_read_reg(client, + object->start_address + MXT_T107_STYLUS_STYAUX, + 1, &styaux); + if (error) + return error; + + /* map aux bits */ + aux = 7; + + if (styaux & MXT_T107_STYLUS_STYAUX_PRESSURE) + data->stylus_aux_pressure = aux++; + + if (styaux & MXT_T107_STYLUS_STYAUX_PEAK) + data->stylus_aux_peak = aux++; + + dev_dbg(&client->dev, + "Enabling T107 active stylus, aux map pressure:%u peak:%u\n", + data->stylus_aux_pressure, data->stylus_aux_peak); + + return 0; +} + static int mxt_read_t100_config(struct mxt_data *data) { struct i2c_client *client = data->client; @@ -2332,10 +2544,6 @@ static int mxt_read_t100_config(struct mxt_data *data) if (range_x == 0) range_x = 1023; - /* Handle default values */ - if (range_x == 0) - range_x = 1023; - if (range_y == 0) range_y = 1023; @@ -2359,6 +2567,10 @@ static int mxt_read_t100_config(struct mxt_data *data) if (tchaux & MXT_T100_TCHAUX_AREA) data->t100_aux_area = aux++; + dev_dbg(&client->dev, + "T100 aux mappings vect:%u ampl:%u area:%u\n", + data->t100_aux_vect, data->t100_aux_ampl, data->t100_aux_area); + dev_info(&client->dev, "T100 Touchscreen size X%uY%u\n", data->max_x, data->max_y); @@ -2372,14 +2584,16 @@ static int mxt_initialize_t100_input_device(struct mxt_data *data) int error; error = mxt_read_t100_config(data); - if (error) - dev_warn(dev, "Failed to initialize T9 resolution\n"); + if (error) { + dev_err(dev, "Failed to read T100 config\n"); + return error; + } + + mxt_read_t107_stylus_config(data); input_dev = input_allocate_device(); - if (!data || !input_dev) { - dev_err(dev, "Failed to allocate memory\n"); + if (!data || !input_dev) return -ENOMEM; - } if (data->pdata->input_name) input_dev->name = data->pdata->input_name; @@ -2419,11 +2633,16 @@ static int mxt_initialize_t100_input_device(struct mxt_data *data) input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 0, data->max_y, 0, 0); + if (data->T107_address) { + input_set_capability(input_dev, EV_KEY, BTN_STYLUS); + input_set_capability(input_dev, EV_KEY, BTN_STYLUS2); + } + if (data->t100_aux_area) input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, MXT_MAX_AREA, 0, 0); - if (data->t100_aux_ampl) + if (data->t100_aux_ampl | data->stylus_aux_pressure) input_set_abs_params(input_dev, ABS_MT_PRESSURE, 0, 255, 0, 0); @@ -2743,132 +2962,98 @@ static int mxt_check_firmware_format(struct device *dev, return -EINVAL; } -static int mxt_load_fw(struct device *dev) +static int mxt_enter_bootloader(struct mxt_data *data) { - struct mxt_data *data = dev_get_drvdata(dev); - const struct firmware *fw = NULL; - unsigned int frame_size; - unsigned int pos = 0; - unsigned int retry = 0; - unsigned int frame = 0; int ret; - ret = request_firmware(&fw, data->fw_name, dev); - if (ret) { - dev_err(dev, "Unable to open firmware %s\n", data->fw_name); - return ret; - } - - /* Check for incorrect enc file */ - ret = mxt_check_firmware_format(dev, fw); - if (ret) - goto release_firmware; - if (data->suspended) { - if (data->use_regulator) + if (data->pdata->suspend_mode == MXT_SUSPEND_REGULATOR) mxt_regulator_enable(data); - enable_irq(data->irq); data->suspended = false; } if (!data->in_bootloader) { /* Change to the bootloader mode */ - data->in_bootloader = true; - ret = mxt_t6_command(data, MXT_COMMAND_RESET, MXT_BOOT_VALUE, false); if (ret) - goto release_firmware; + return ret; msleep(MXT_RESET_TIME); /* Do not need to scan since we know family ID */ - ret = mxt_lookup_bootloader_address(data, 0); + ret = mxt_probe_bootloader(data, 0); if (ret) - goto release_firmware; + return ret; + data->in_bootloader = true; mxt_free_input_device(data); mxt_free_object_table(data); - } else { - enable_irq(data->irq); } - INIT_COMPLETION(data->bl_completion); + dev_dbg(&data->client->dev, "Entered bootloader\n"); - ret = mxt_check_bootloader(data, MXT_WAITING_BOOTLOAD_CMD, false); - if (ret) { - /* Bootloader may still be unlocked from previous attempt */ - ret = mxt_check_bootloader(data, MXT_WAITING_FRAME_DATA, false); - if (ret) - goto disable_irq; - } else { - dev_info(dev, "Unlocking bootloader\n"); + return 0; +} - /* Unlock bootloader */ - ret = mxt_send_bootloader_cmd(data, true); - if (ret) - goto disable_irq; - } +static void mxt_fw_work(struct work_struct *work) +{ + struct mxt_flash *f = + container_of(work, struct mxt_flash, work.work); - while (pos < fw->size) { - ret = mxt_check_bootloader(data, MXT_WAITING_FRAME_DATA, true); - if (ret) - goto disable_irq; + mxt_check_bootloader(f->data); +} - frame_size = ((*(fw->data + pos) << 8) | *(fw->data + pos + 1)); +static int mxt_load_fw(struct device *dev) +{ + struct mxt_data *data = dev_get_drvdata(dev); + int ret; - /* Take account of CRC bytes */ - frame_size += 2; + data->flash = devm_kzalloc(dev, sizeof(struct mxt_flash), GFP_KERNEL); + if (!data->flash) + return -ENOMEM; - /* Write one frame to device */ - ret = mxt_bootloader_write(data, fw->data + pos, frame_size); - if (ret) - goto disable_irq; + data->flash->data = data; - ret = mxt_check_bootloader(data, MXT_FRAME_CRC_PASS, true); - if (ret) { - retry++; + ret = request_firmware(&data->flash->fw, data->fw_name, dev); + if (ret) { + dev_err(dev, "Unable to open firmware %s\n", data->fw_name); + goto free; + } - /* Back off by 20ms per retry */ - msleep(retry * 20); + /* Check for incorrect enc file */ + ret = mxt_check_firmware_format(dev, data->flash->fw); + if (ret) + goto release_firmware; - if (retry > 20) { - dev_err(dev, "Retry count exceeded\n"); - goto disable_irq; - } - } else { - retry = 0; - pos += frame_size; - frame++; - } + init_completion(&data->flash->flash_completion); + INIT_DELAYED_WORK(&data->flash->work, mxt_fw_work); - if (frame % 50 == 0) - dev_dbg(dev, "Sent %d frames, %d/%zd bytes\n", - frame, pos, fw->size); + if (!data->in_bootloader) { + ret = mxt_enter_bootloader(data); + if (ret) + goto release_firmware; } - /* Wait for flash. */ - ret = mxt_wait_for_completion(data, &data->bl_completion, - MXT_FW_RESET_TIME); + ret = mxt_acquire_irq(data); if (ret) - goto disable_irq; + goto release_firmware; - dev_dbg(dev, "Sent %d frames, %d bytes\n", frame, pos); + /* Poll after 0.1s if no interrupt received */ + schedule_delayed_work(&data->flash->work, HZ / 10); - /* - * Wait for device to reset. Some bootloader versions do not assert - * the CHG line after bootloading has finished, so ignore potential - * errors. - */ - mxt_wait_for_completion(data, &data->bl_completion, MXT_FW_RESET_TIME); - - data->in_bootloader = false; + /* Wait for flash. */ + ret = mxt_wait_for_completion(data, &data->flash->flash_completion, + MXT_BOOTLOADER_WAIT); -disable_irq: disable_irq(data->irq); + cancel_delayed_work_sync(&data->flash->work); + data->in_bootloader = false; release_firmware: - release_firmware(fw); + release_firmware(data->flash->fw); +free: + devm_kfree(dev, data->flash); return ret; } @@ -2884,10 +3069,8 @@ static int mxt_update_file_name(struct device *dev, char **file_name, } file_name_tmp = krealloc(*file_name, count + 1, GFP_KERNEL); - if (!file_name_tmp) { - dev_warn(dev, "no memory\n"); + if (!file_name_tmp) return -ENOMEM; - } *file_name = file_name_tmp; memcpy(*file_name, buf, count); @@ -2934,6 +3117,7 @@ static ssize_t mxt_update_cfg_store(struct device *dev, const char *buf, size_t count) { struct mxt_data *data = dev_get_drvdata(dev); + const struct mxt_platform_data *pdata = data->pdata; const struct firmware *cfg; int ret; @@ -2959,10 +3143,10 @@ static ssize_t mxt_update_cfg_store(struct device *dev, mxt_free_input_device(data); if (data->suspended) { - if (data->use_regulator) { + if (pdata->suspend_mode == MXT_SUSPEND_REGULATOR) { enable_irq(data->irq); mxt_regulator_enable(data); - } else { + } else if (pdata->suspend_mode == MXT_SUSPEND_DEEP_SLEEP) { mxt_set_t7_power_cfg(data, MXT_POWER_CFG_RUN); mxt_acquire_irq(data); } @@ -3044,6 +3228,9 @@ static ssize_t mxt_debug_enable_store(struct device *dev, static int mxt_check_mem_access_params(struct mxt_data *data, loff_t off, size_t *count) { + if (data->in_bootloader) + return -EINVAL; + if (off >= data->mem_size) return -EIO; @@ -3144,13 +3331,24 @@ static void mxt_start(struct mxt_data *data) if (!data->suspended || data->in_bootloader) return; - if (data->use_regulator) { - enable_irq(data->irq); + switch (data->pdata->suspend_mode) { + case MXT_SUSPEND_TOUCH_CTRL: + mxt_soft_reset(data); + + /* Touch enable */ + mxt_write_object(data, + MXT_TOUCH_MULTI_T9, MXT_TOUCH_CTRL, 0x83); + break; + case MXT_SUSPEND_REGULATOR: + enable_irq(data->irq); mxt_regulator_enable(data); - } else { + break; + + case MXT_SUSPEND_DEEP_SLEEP: + default: /* - * Discard any messages still in message buffer + * Discard any touch messages still in message buffer * from before chip went to sleep */ mxt_process_messages_until_invalid(data); @@ -3161,6 +3359,7 @@ static void mxt_start(struct mxt_data *data) mxt_t6_command(data, MXT_COMMAND_CALIBRATE, 1, false); mxt_acquire_irq(data); + break; } data->suspended = false; @@ -3171,14 +3370,29 @@ static void mxt_stop(struct mxt_data *data) if (data->suspended || data->in_bootloader || data->updating_config) return; - disable_irq(data->irq); + switch (data->pdata->suspend_mode) { + case MXT_SUSPEND_TOUCH_CTRL: + /* Touch disable */ + mxt_write_object(data, + MXT_TOUCH_MULTI_T9, MXT_TOUCH_CTRL, 0); + break; - if (data->use_regulator) + case MXT_SUSPEND_REGULATOR: + disable_irq(data->irq); mxt_regulator_disable(data); - else + mxt_reset_slots(data); + break; + + case MXT_SUSPEND_DEEP_SLEEP: + default: + disable_irq(data->irq); + mxt_set_t7_power_cfg(data, MXT_POWER_CFG_DEEPSLEEP); - mxt_reset_slots(data); + mxt_reset_slots(data); + break; + } + data->suspended = true; } @@ -3244,6 +3458,9 @@ static struct mxt_platform_data *mxt_parse_dt(struct i2c_client *client) pdata->t19_keymap = keymap; } + of_property_read_u32(client->dev.of_node, "atmel,suspend-mode", + &pdata->suspend_mode); + return pdata; } #else @@ -3276,17 +3493,14 @@ static int mxt_probe(struct i2c_client *client, const struct i2c_device_id *id) } data = kzalloc(sizeof(struct mxt_data), GFP_KERNEL); - if (!data) { - dev_err(&client->dev, "Failed to allocate memory\n"); + if (!data) return -ENOMEM; - } snprintf(data->phys, sizeof(data->phys), "i2c-%u-%04x/input0", client->adapter->nr, client->addr); data->client = client; data->pdata = pdata; - data->irq = client->irq; i2c_set_clientdata(client, data); if (data->pdata->cfg_name) @@ -3295,22 +3509,22 @@ static int mxt_probe(struct i2c_client *client, const struct i2c_device_id *id) data->pdata->cfg_name, strlen(data->pdata->cfg_name)); - init_completion(&data->bl_completion); init_completion(&data->reset_completion); init_completion(&data->crc_completion); + init_completion(&data->chg_completion); mutex_init(&data->debug_msg_lock); - error = request_threaded_irq(client->irq, NULL, mxt_interrupt, - pdata->irqflags | IRQF_ONESHOT, - client->name, data); - if (error) { - dev_err(&client->dev, "Failed to register interrupt\n"); - goto err_free_mem; - } + if (pdata->suspend_mode == MXT_SUSPEND_REGULATOR) { + error = mxt_acquire_irq(data); + if (error) + goto err_free_mem; - mxt_probe_regulators(data); + error = mxt_probe_regulators(data); + if (error) + goto err_free_irq; - disable_irq(data->irq); + disable_irq(data->irq); + } error = sysfs_create_group(&client->dev.kobj, &mxt_attr_group); if (error) { @@ -3345,7 +3559,8 @@ err_remove_mem_access: err_remove_sysfs_group: sysfs_remove_group(&client->dev.kobj, &mxt_attr_group); err_free_irq: - free_irq(client->irq, data); + if (data->irq) + free_irq(data->irq, data); err_free_mem: kfree(data); return error; @@ -3360,7 +3575,10 @@ static int mxt_remove(struct i2c_client *client) &data->mem_access_attr); sysfs_remove_group(&client->dev.kobj, &mxt_attr_group); - free_irq(data->irq, data); + + if (data->irq) + free_irq(data->irq, data); + regulator_put(data->reg_avdd); regulator_put(data->reg_vdd); mxt_free_input_device(data); @@ -3370,8 +3588,7 @@ static int mxt_remove(struct i2c_client *client) return 0; } -#ifdef CONFIG_PM_SLEEP -static int mxt_suspend(struct device *dev) +static int __maybe_unused mxt_suspend(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); struct mxt_data *data = i2c_get_clientdata(client); @@ -3387,7 +3604,7 @@ static int mxt_suspend(struct device *dev) return 0; } -static int mxt_resume(struct device *dev) +static int __maybe_unused mxt_resume(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); struct mxt_data *data = i2c_get_clientdata(client); @@ -3402,7 +3619,6 @@ static int mxt_resume(struct device *dev) return 0; } -#endif static SIMPLE_DEV_PM_OPS(mxt_pm_ops, mxt_suspend, mxt_resume); diff --git a/include/dt-bindings/input/atmel_mxt_ts.h b/include/dt-bindings/input/atmel_mxt_ts.h new file mode 100644 index 00000000000..c7637925da5 --- /dev/null +++ b/include/dt-bindings/input/atmel_mxt_ts.h @@ -0,0 +1,22 @@ +/* + * Atmel maXTouch Touchscreen driver + * + * Copyright (C) 2015 Atmel Corporation + * Author: Nick Dyer <nick.dyer@itdev.co.uk> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#ifndef __DT_BINDINGS_ATMEL_MXT_TS_H +#define __DT_BINDINGS_ATMEL_MXT_TS_H + +enum mxt_suspend_mode { + MXT_SUSPEND_DEEP_SLEEP = 0, + MXT_SUSPEND_TOUCH_CTRL = 1, + MXT_SUSPEND_REGULATOR = 2, +}; + +#endif /* __DT_BINDINGS_ATMEL_MXT_TS_H */ diff --git a/include/linux/i2c/atmel_mxt_ts.h b/include/linux/platform_data/atmel_mxt_ts.h index bc74c3f4c86..be6fa95a661 100644 --- a/include/linux/i2c/atmel_mxt_ts.h +++ b/include/linux/platform_data/atmel_mxt_ts.h @@ -10,16 +10,18 @@ * option) any later version. */ -#ifndef __LINUX_ATMEL_MXT_TS_H -#define __LINUX_ATMEL_MXT_TS_H +#ifndef __LINUX_PLATFORM_DATA_ATMEL_MXT_TS_H +#define __LINUX_PLATFORM_DATA_ATMEL_MXT_TS_H #include <linux/types.h> +#include <dt-bindings/input/atmel_mxt_ts.h> /* The platform data for the Atmel maXTouch touchscreen driver */ struct mxt_platform_data { unsigned long irqflags; u8 t19_num_keys; const unsigned int *t19_keymap; + enum mxt_suspend_mode suspend_mode; int t15_num_keys; const unsigned int *t15_keymap; unsigned long gpio_reset; @@ -27,4 +29,4 @@ struct mxt_platform_data { const char *input_name; }; -#endif /* __LINUX_ATMEL_MXT_TS_H */ +#endif /* __LINUX_PLATFORM_DATA_ATMEL_MXT_TS_H */ |