blob: 4c4429598adbb02c0c84154573212790bad34134 [file] [log] [blame]
Benson Leungd7e34d12013-01-09 16:25:11 -08001/*
2 * Cypress APA trackpad with I2C interface
3 *
4 * Author: Dudley Du <dudl@cypress.com>
5 * Further cleanup and restructuring by:
6 * Daniel Kurtz <djkurtz@chromium.org>
7 * Benson Leung <bleung@chromium.org>
8 *
Dudley Du94897612015-07-20 16:49:06 -07009 * Copyright (C) 2011-2015 Cypress Semiconductor, Inc.
Benson Leungd7e34d12013-01-09 16:25:11 -080010 * Copyright (C) 2011-2012 Google, Inc.
11 *
12 * This file is subject to the terms and conditions of the GNU General Public
13 * License. See the file COPYING in the main directory of this archive for
14 * more details.
15 */
16
17#include <linux/delay.h>
18#include <linux/i2c.h>
19#include <linux/input.h>
20#include <linux/input/mt.h>
21#include <linux/interrupt.h>
22#include <linux/module.h>
Dudley Du9f1cd852015-01-17 18:35:26 -080023#include <linux/mutex.h>
Benson Leungd7e34d12013-01-09 16:25:11 -080024#include <linux/slab.h>
Dudley Du9f1cd852015-01-17 18:35:26 -080025#include <linux/uaccess.h>
Dudley Du67286502015-01-17 18:57:42 -080026#include <linux/pm_runtime.h>
Dudley Du7b2171d2015-01-17 22:18:59 -080027#include <linux/acpi.h>
Dudley Du9f1cd852015-01-17 18:35:26 -080028#include "cyapa.h"
Benson Leungd7e34d12013-01-09 16:25:11 -080029
Benson Leungd7e34d12013-01-09 16:25:11 -080030
Benson Leung6ddaf742013-02-13 13:56:03 -080031#define CYAPA_ADAPTER_FUNC_NONE 0
32#define CYAPA_ADAPTER_FUNC_I2C 1
33#define CYAPA_ADAPTER_FUNC_SMBUS 2
34#define CYAPA_ADAPTER_FUNC_BOTH 3
35
Dudley Duc806b0b2015-01-17 22:07:12 -080036#define CYAPA_FW_NAME "cyapa.bin"
37
Dudley Du9f1cd852015-01-17 18:35:26 -080038const char product_id[] = "CYTRA";
Benson Leung6ddaf742013-02-13 13:56:03 -080039
Dudley Du9f1cd852015-01-17 18:35:26 -080040static int cyapa_reinitialize(struct cyapa *cyapa);
Benson Leung6ddaf742013-02-13 13:56:03 -080041
Dudley Du94897612015-07-20 16:49:06 -070042bool cyapa_is_pip_bl_mode(struct cyapa *cyapa)
Dudley Du9f1cd852015-01-17 18:35:26 -080043{
44 if (cyapa->gen == CYAPA_GEN5 && cyapa->state == CYAPA_STATE_GEN5_BL)
45 return true;
Benson Leung6ddaf742013-02-13 13:56:03 -080046
Dudley Du94897612015-07-20 16:49:06 -070047 return false;
48}
49
50bool cyapa_is_pip_app_mode(struct cyapa *cyapa)
51{
52 if (cyapa->gen == CYAPA_GEN5 && cyapa->state == CYAPA_STATE_GEN5_APP)
53 return true;
54
55 return false;
56}
57
58static bool cyapa_is_bootloader_mode(struct cyapa *cyapa)
59{
60 if (cyapa_is_pip_bl_mode(cyapa))
61 return true;
62
Dudley Du9f1cd852015-01-17 18:35:26 -080063 if (cyapa->gen == CYAPA_GEN3 &&
64 cyapa->state >= CYAPA_STATE_BL_BUSY &&
65 cyapa->state <= CYAPA_STATE_BL_ACTIVE)
66 return true;
Benson Leung6ddaf742013-02-13 13:56:03 -080067
Dudley Du9f1cd852015-01-17 18:35:26 -080068 return false;
69}
Benson Leung6ddaf742013-02-13 13:56:03 -080070
Dudley Du9f1cd852015-01-17 18:35:26 -080071static inline bool cyapa_is_operational_mode(struct cyapa *cyapa)
72{
Dudley Du94897612015-07-20 16:49:06 -070073 if (cyapa_is_pip_app_mode(cyapa))
Dudley Du9f1cd852015-01-17 18:35:26 -080074 return true;
Benson Leung6ddaf742013-02-13 13:56:03 -080075
Dudley Du9f1cd852015-01-17 18:35:26 -080076 if (cyapa->gen == CYAPA_GEN3 && cyapa->state == CYAPA_STATE_OP)
77 return true;
Benson Leungd7e34d12013-01-09 16:25:11 -080078
Dudley Du9f1cd852015-01-17 18:35:26 -080079 return false;
80}
Benson Leung6ddaf742013-02-13 13:56:03 -080081
Dudley Du9f1cd852015-01-17 18:35:26 -080082/* Returns 0 on success, else negative errno on failure. */
83static ssize_t cyapa_i2c_read(struct cyapa *cyapa, u8 reg, size_t len,
Benson Leungd7e34d12013-01-09 16:25:11 -080084 u8 *values)
85{
Benson Leung6ddaf742013-02-13 13:56:03 -080086 struct i2c_client *client = cyapa->client;
Dudley Du9f1cd852015-01-17 18:35:26 -080087 struct i2c_msg msgs[] = {
88 {
89 .addr = client->addr,
90 .flags = 0,
91 .len = 1,
92 .buf = &reg,
93 },
94 {
95 .addr = client->addr,
96 .flags = I2C_M_RD,
97 .len = len,
98 .buf = values,
99 },
100 };
101 int ret;
Benson Leung6ddaf742013-02-13 13:56:03 -0800102
Dudley Du9f1cd852015-01-17 18:35:26 -0800103 ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
Benson Leung6ddaf742013-02-13 13:56:03 -0800104
Dudley Du9f1cd852015-01-17 18:35:26 -0800105 if (ret != ARRAY_SIZE(msgs))
106 return ret < 0 ? ret : -EIO;
Benson Leung6ddaf742013-02-13 13:56:03 -0800107
Dudley Du9f1cd852015-01-17 18:35:26 -0800108 return 0;
Benson Leung6ddaf742013-02-13 13:56:03 -0800109}
110
Dudley Du9f1cd852015-01-17 18:35:26 -0800111/**
112 * cyapa_i2c_write - Execute i2c block data write operation
113 * @cyapa: Handle to this driver
114 * @ret: Offset of the data to written in the register map
115 * @len: number of bytes to write
116 * @values: Data to be written
117 *
118 * Return negative errno code on error; return zero when success.
119 */
120static int cyapa_i2c_write(struct cyapa *cyapa, u8 reg,
121 size_t len, const void *values)
Benson Leungd7e34d12013-01-09 16:25:11 -0800122{
Dudley Du9f1cd852015-01-17 18:35:26 -0800123 struct i2c_client *client = cyapa->client;
124 char buf[32];
125 int ret;
Benson Leungd7e34d12013-01-09 16:25:11 -0800126
Dudley Du9f1cd852015-01-17 18:35:26 -0800127 if (len > sizeof(buf) - 1)
128 return -ENOMEM;
129
130 buf[0] = reg;
131 memcpy(&buf[1], values, len);
132
133 ret = i2c_master_send(client, buf, len + 1);
134 if (ret != len + 1)
135 return ret < 0 ? ret : -EIO;
136
137 return 0;
Benson Leungd7e34d12013-01-09 16:25:11 -0800138}
139
Dudley Du9f1cd852015-01-17 18:35:26 -0800140static u8 cyapa_check_adapter_functionality(struct i2c_client *client)
Benson Leungd7e34d12013-01-09 16:25:11 -0800141{
Dudley Du9f1cd852015-01-17 18:35:26 -0800142 u8 ret = CYAPA_ADAPTER_FUNC_NONE;
Benson Leungd7e34d12013-01-09 16:25:11 -0800143
Dudley Du9f1cd852015-01-17 18:35:26 -0800144 if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
145 ret |= CYAPA_ADAPTER_FUNC_I2C;
146 if (i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA |
147 I2C_FUNC_SMBUS_BLOCK_DATA |
148 I2C_FUNC_SMBUS_I2C_BLOCK))
149 ret |= CYAPA_ADAPTER_FUNC_SMBUS;
150 return ret;
Benson Leungd7e34d12013-01-09 16:25:11 -0800151}
152
153/*
154 * Query device for its current operating state.
Benson Leungd7e34d12013-01-09 16:25:11 -0800155 */
156static int cyapa_get_state(struct cyapa *cyapa)
157{
Benson Leungd7e34d12013-01-09 16:25:11 -0800158 u8 status[BL_STATUS_SIZE];
Dudley Du9f1cd852015-01-17 18:35:26 -0800159 u8 cmd[32];
160 /* The i2c address of gen4 and gen5 trackpad device must be even. */
161 bool even_addr = ((cyapa->client->addr & 0x0001) == 0);
162 bool smbus = false;
163 int retries = 2;
Dudley Du823a11f2014-12-04 07:00:03 -0800164 int error;
Benson Leungd7e34d12013-01-09 16:25:11 -0800165
166 cyapa->state = CYAPA_STATE_NO_DEVICE;
167
168 /*
169 * Get trackpad status by reading 3 registers starting from 0.
170 * If the device is in the bootloader, this will be BL_HEAD.
171 * If the device is in operation mode, this will be the DATA regs.
172 *
173 */
Dudley Du823a11f2014-12-04 07:00:03 -0800174 error = cyapa_i2c_reg_read_block(cyapa, BL_HEAD_OFFSET, BL_STATUS_SIZE,
Dudley Du9f1cd852015-01-17 18:35:26 -0800175 status);
Benson Leung6ddaf742013-02-13 13:56:03 -0800176
177 /*
178 * On smbus systems in OP mode, the i2c_reg_read will fail with
179 * -ETIMEDOUT. In this case, try again using the smbus equivalent
180 * command. This should return a BL_HEAD indicating CYAPA_STATE_OP.
181 */
Dudley Du9f1cd852015-01-17 18:35:26 -0800182 if (cyapa->smbus && (error == -ETIMEDOUT || error == -ENXIO)) {
183 if (!even_addr)
184 error = cyapa_read_block(cyapa,
185 CYAPA_CMD_BL_STATUS, status);
186 smbus = true;
187 }
Benson Leung6ddaf742013-02-13 13:56:03 -0800188
Dudley Du823a11f2014-12-04 07:00:03 -0800189 if (error != BL_STATUS_SIZE)
Benson Leungd7e34d12013-01-09 16:25:11 -0800190 goto error;
191
Dudley Du9f1cd852015-01-17 18:35:26 -0800192 /*
193 * Detect trackpad protocol based on characteristic registers and bits.
194 */
195 do {
196 cyapa->status[REG_OP_STATUS] = status[REG_OP_STATUS];
197 cyapa->status[REG_BL_STATUS] = status[REG_BL_STATUS];
198 cyapa->status[REG_BL_ERROR] = status[REG_BL_ERROR];
Benson Leungd7e34d12013-01-09 16:25:11 -0800199
Dudley Du9f1cd852015-01-17 18:35:26 -0800200 if (cyapa->gen == CYAPA_GEN_UNKNOWN ||
201 cyapa->gen == CYAPA_GEN3) {
202 error = cyapa_gen3_ops.state_parse(cyapa,
203 status, BL_STATUS_SIZE);
204 if (!error)
205 goto out_detected;
206 }
Dudley Du6972a852015-01-17 18:49:37 -0800207 if ((cyapa->gen == CYAPA_GEN_UNKNOWN ||
208 cyapa->gen == CYAPA_GEN5) &&
209 !smbus && even_addr) {
210 error = cyapa_gen5_ops.state_parse(cyapa,
211 status, BL_STATUS_SIZE);
212 if (!error)
213 goto out_detected;
214 }
Dudley Du9f1cd852015-01-17 18:35:26 -0800215
216 /*
217 * Write 0x00 0x00 to trackpad device to force update its
218 * status, then redo the detection again.
219 */
220 if (!smbus) {
221 cmd[0] = 0x00;
222 cmd[1] = 0x00;
223 error = cyapa_i2c_write(cyapa, 0, 2, cmd);
224 if (error)
225 goto error;
226
227 msleep(50);
228
229 error = cyapa_i2c_read(cyapa, BL_HEAD_OFFSET,
230 BL_STATUS_SIZE, status);
231 if (error)
232 goto error;
233 }
234 } while (--retries > 0 && !smbus);
235
236 goto error;
237
238out_detected:
239 if (cyapa->state <= CYAPA_STATE_BL_BUSY)
240 return -EAGAIN;
Benson Leungd7e34d12013-01-09 16:25:11 -0800241 return 0;
Dudley Du9f1cd852015-01-17 18:35:26 -0800242
Benson Leungd7e34d12013-01-09 16:25:11 -0800243error:
Dudley Du823a11f2014-12-04 07:00:03 -0800244 return (error < 0) ? error : -EAGAIN;
Benson Leungd7e34d12013-01-09 16:25:11 -0800245}
246
247/*
248 * Poll device for its status in a loop, waiting up to timeout for a response.
249 *
250 * When the device switches state, it usually takes ~300 ms.
251 * However, when running a new firmware image, the device must calibrate its
252 * sensors, which can take as long as 2 seconds.
253 *
254 * Note: The timeout has granularity of the polling rate, which is 100 ms.
255 *
256 * Returns:
257 * 0 when the device eventually responds with a valid non-busy state.
258 * -ETIMEDOUT if device never responds (too many -EAGAIN)
Dudley Du9f1cd852015-01-17 18:35:26 -0800259 * -EAGAIN if bootload is busy, or unknown state.
260 * < 0 other errors
Benson Leungd7e34d12013-01-09 16:25:11 -0800261 */
Dudley Du9f1cd852015-01-17 18:35:26 -0800262int cyapa_poll_state(struct cyapa *cyapa, unsigned int timeout)
Benson Leungd7e34d12013-01-09 16:25:11 -0800263{
Dudley Du823a11f2014-12-04 07:00:03 -0800264 int error;
Benson Leungd7e34d12013-01-09 16:25:11 -0800265 int tries = timeout / 100;
266
Dudley Du9f1cd852015-01-17 18:35:26 -0800267 do {
Dudley Du823a11f2014-12-04 07:00:03 -0800268 error = cyapa_get_state(cyapa);
Dudley Du9f1cd852015-01-17 18:35:26 -0800269 if (!error && cyapa->state > CYAPA_STATE_BL_BUSY)
270 return 0;
271
272 msleep(100);
273 } while (tries--);
274
Dudley Du823a11f2014-12-04 07:00:03 -0800275 return (error == -EAGAIN || error == -ETIMEDOUT) ? -ETIMEDOUT : error;
Benson Leungd7e34d12013-01-09 16:25:11 -0800276}
277
Benson Leungd7e34d12013-01-09 16:25:11 -0800278/*
279 * Check if device is operational.
280 *
281 * An operational device is responding, has exited bootloader, and has
282 * firmware supported by this driver.
283 *
284 * Returns:
Dudley Du9f1cd852015-01-17 18:35:26 -0800285 * -ENODEV no device
Benson Leungd7e34d12013-01-09 16:25:11 -0800286 * -EBUSY no device or in bootloader
287 * -EIO failure while reading from device
Dudley Du9f1cd852015-01-17 18:35:26 -0800288 * -ETIMEDOUT timeout failure for bus idle or bus no response
Benson Leungd7e34d12013-01-09 16:25:11 -0800289 * -EAGAIN device is still in bootloader
290 * if ->state = CYAPA_STATE_BL_IDLE, device has invalid firmware
291 * -EINVAL device is in operational mode, but not supported by this driver
292 * 0 device is supported
293 */
294static int cyapa_check_is_operational(struct cyapa *cyapa)
295{
Dudley Du823a11f2014-12-04 07:00:03 -0800296 int error;
Benson Leungd7e34d12013-01-09 16:25:11 -0800297
Dudley Du9f1cd852015-01-17 18:35:26 -0800298 error = cyapa_poll_state(cyapa, 4000);
Dudley Du823a11f2014-12-04 07:00:03 -0800299 if (error)
300 return error;
Benson Leungd7e34d12013-01-09 16:25:11 -0800301
Dudley Du9f1cd852015-01-17 18:35:26 -0800302 switch (cyapa->gen) {
Dudley Du6972a852015-01-17 18:49:37 -0800303 case CYAPA_GEN5:
304 cyapa->ops = &cyapa_gen5_ops;
305 break;
Dudley Du9f1cd852015-01-17 18:35:26 -0800306 case CYAPA_GEN3:
307 cyapa->ops = &cyapa_gen3_ops;
308 break;
Benson Leungd7e34d12013-01-09 16:25:11 -0800309 default:
Dudley Du9f1cd852015-01-17 18:35:26 -0800310 return -ENODEV;
Benson Leungd7e34d12013-01-09 16:25:11 -0800311 }
Dudley Du9f1cd852015-01-17 18:35:26 -0800312
313 error = cyapa->ops->operational_check(cyapa);
314 if (!error && cyapa_is_operational_mode(cyapa))
315 cyapa->operational = true;
316 else
317 cyapa->operational = false;
318
319 return error;
Benson Leungd7e34d12013-01-09 16:25:11 -0800320}
321
Dudley Du9f1cd852015-01-17 18:35:26 -0800322
323/*
324 * Returns 0 on device detected, negative errno on no device detected.
Dudley Du94897612015-07-20 16:49:06 -0700325 * And when the device is detected and operational, it will be reset to
Dudley Du9f1cd852015-01-17 18:35:26 -0800326 * full power active mode automatically.
327 */
328static int cyapa_detect(struct cyapa *cyapa)
Benson Leungd7e34d12013-01-09 16:25:11 -0800329{
Benson Leungd7e34d12013-01-09 16:25:11 -0800330 struct device *dev = &cyapa->client->dev;
Dudley Du9f1cd852015-01-17 18:35:26 -0800331 int error;
Benson Leungd7e34d12013-01-09 16:25:11 -0800332
Dudley Du9f1cd852015-01-17 18:35:26 -0800333 error = cyapa_check_is_operational(cyapa);
334 if (error) {
335 if (error != -ETIMEDOUT && error != -ENODEV &&
336 cyapa_is_bootloader_mode(cyapa)) {
337 dev_warn(dev, "device detected but not operational\n");
338 return 0;
339 }
Benson Leungd7e34d12013-01-09 16:25:11 -0800340
Dudley Du9f1cd852015-01-17 18:35:26 -0800341 dev_err(dev, "no device detected: %d\n", error);
342 return error;
Benson Leungd7e34d12013-01-09 16:25:11 -0800343 }
344
Dudley Du9f1cd852015-01-17 18:35:26 -0800345 return 0;
Benson Leung6ddaf742013-02-13 13:56:03 -0800346}
347
Dudley Dub1cfa7b2014-11-09 12:36:34 -0800348static int cyapa_open(struct input_dev *input)
349{
350 struct cyapa *cyapa = input_get_drvdata(input);
351 struct i2c_client *client = cyapa->client;
352 int error;
353
Dudley Du9f1cd852015-01-17 18:35:26 -0800354 error = mutex_lock_interruptible(&cyapa->state_sync_lock);
355 if (error)
Dudley Dub1cfa7b2014-11-09 12:36:34 -0800356 return error;
Dudley Du9f1cd852015-01-17 18:35:26 -0800357
358 if (cyapa->operational) {
359 /*
360 * though failed to set active power mode,
361 * but still may be able to work in lower scan rate
362 * when in operational mode.
363 */
364 error = cyapa->ops->set_power_mode(cyapa,
365 PWR_MODE_FULL_ACTIVE, 0);
366 if (error) {
367 dev_warn(&client->dev,
368 "set active power failed: %d\n", error);
369 goto out;
370 }
371 } else {
372 error = cyapa_reinitialize(cyapa);
373 if (error || !cyapa->operational) {
374 error = error ? error : -EAGAIN;
375 goto out;
376 }
Dudley Dub1cfa7b2014-11-09 12:36:34 -0800377 }
378
379 enable_irq(client->irq);
Dudley Du67286502015-01-17 18:57:42 -0800380 if (!pm_runtime_enabled(&client->dev)) {
381 pm_runtime_set_active(&client->dev);
382 pm_runtime_enable(&client->dev);
383 }
Dudley Du9f1cd852015-01-17 18:35:26 -0800384out:
385 mutex_unlock(&cyapa->state_sync_lock);
386 return error;
Dudley Dub1cfa7b2014-11-09 12:36:34 -0800387}
388
389static void cyapa_close(struct input_dev *input)
390{
391 struct cyapa *cyapa = input_get_drvdata(input);
Dudley Du9f1cd852015-01-17 18:35:26 -0800392 struct i2c_client *client = cyapa->client;
Dudley Dub1cfa7b2014-11-09 12:36:34 -0800393
Dudley Du9f1cd852015-01-17 18:35:26 -0800394 mutex_lock(&cyapa->state_sync_lock);
395
396 disable_irq(client->irq);
Dudley Du67286502015-01-17 18:57:42 -0800397 if (pm_runtime_enabled(&client->dev))
398 pm_runtime_disable(&client->dev);
399 pm_runtime_set_suspended(&client->dev);
400
Dudley Du9f1cd852015-01-17 18:35:26 -0800401 if (cyapa->operational)
402 cyapa->ops->set_power_mode(cyapa, PWR_MODE_OFF, 0);
403
404 mutex_unlock(&cyapa->state_sync_lock);
Dudley Dub1cfa7b2014-11-09 12:36:34 -0800405}
406
Benson Leungd7e34d12013-01-09 16:25:11 -0800407static int cyapa_create_input_dev(struct cyapa *cyapa)
408{
409 struct device *dev = &cyapa->client->dev;
Benson Leungd7e34d12013-01-09 16:25:11 -0800410 struct input_dev *input;
Dudley Dub1cfa7b2014-11-09 12:36:34 -0800411 int error;
Benson Leungd7e34d12013-01-09 16:25:11 -0800412
413 if (!cyapa->physical_size_x || !cyapa->physical_size_y)
414 return -EINVAL;
415
Dudley Dub1cfa7b2014-11-09 12:36:34 -0800416 input = devm_input_allocate_device(dev);
Benson Leungd7e34d12013-01-09 16:25:11 -0800417 if (!input) {
Dudley Du823a11f2014-12-04 07:00:03 -0800418 dev_err(dev, "failed to allocate memory for input device.\n");
Benson Leungd7e34d12013-01-09 16:25:11 -0800419 return -ENOMEM;
420 }
421
422 input->name = CYAPA_NAME;
423 input->phys = cyapa->phys;
424 input->id.bustype = BUS_I2C;
425 input->id.version = 1;
Dudley Du823a11f2014-12-04 07:00:03 -0800426 input->id.product = 0; /* Means any product in eventcomm. */
Benson Leungd7e34d12013-01-09 16:25:11 -0800427 input->dev.parent = &cyapa->client->dev;
428
Dudley Dub1cfa7b2014-11-09 12:36:34 -0800429 input->open = cyapa_open;
430 input->close = cyapa_close;
431
Benson Leungd7e34d12013-01-09 16:25:11 -0800432 input_set_drvdata(input, cyapa);
433
434 __set_bit(EV_ABS, input->evbit);
435
Dudley Du823a11f2014-12-04 07:00:03 -0800436 /* Finger position */
Benson Leungd7e34d12013-01-09 16:25:11 -0800437 input_set_abs_params(input, ABS_MT_POSITION_X, 0, cyapa->max_abs_x, 0,
438 0);
439 input_set_abs_params(input, ABS_MT_POSITION_Y, 0, cyapa->max_abs_y, 0,
440 0);
Dudley Du9f1cd852015-01-17 18:35:26 -0800441 input_set_abs_params(input, ABS_MT_PRESSURE, 0, cyapa->max_z, 0, 0);
442 if (cyapa->gen > CYAPA_GEN3) {
443 input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0);
444 input_set_abs_params(input, ABS_MT_TOUCH_MINOR, 0, 255, 0, 0);
445 /*
446 * Orientation is the angle between the vertical axis and
447 * the major axis of the contact ellipse.
448 * The range is -127 to 127.
449 * the positive direction is clockwise form the vertical axis.
450 * If the ellipse of contact degenerates into a circle,
451 * orientation is reported as 0.
452 *
453 * Also, for Gen5 trackpad the accurate of this orientation
454 * value is value + (-30 ~ 30).
455 */
456 input_set_abs_params(input, ABS_MT_ORIENTATION,
457 -127, 127, 0, 0);
458 }
459 if (cyapa->gen >= CYAPA_GEN5) {
460 input_set_abs_params(input, ABS_MT_WIDTH_MAJOR, 0, 255, 0, 0);
461 input_set_abs_params(input, ABS_MT_WIDTH_MINOR, 0, 255, 0, 0);
462 }
Benson Leungd7e34d12013-01-09 16:25:11 -0800463
464 input_abs_set_res(input, ABS_MT_POSITION_X,
465 cyapa->max_abs_x / cyapa->physical_size_x);
466 input_abs_set_res(input, ABS_MT_POSITION_Y,
467 cyapa->max_abs_y / cyapa->physical_size_y);
468
469 if (cyapa->btn_capability & CAPABILITY_LEFT_BTN_MASK)
470 __set_bit(BTN_LEFT, input->keybit);
471 if (cyapa->btn_capability & CAPABILITY_MIDDLE_BTN_MASK)
472 __set_bit(BTN_MIDDLE, input->keybit);
473 if (cyapa->btn_capability & CAPABILITY_RIGHT_BTN_MASK)
474 __set_bit(BTN_RIGHT, input->keybit);
475
476 if (cyapa->btn_capability == CAPABILITY_LEFT_BTN_MASK)
477 __set_bit(INPUT_PROP_BUTTONPAD, input->propbit);
478
Dudley Du823a11f2014-12-04 07:00:03 -0800479 /* Handle pointer emulation and unused slots in core */
Dudley Dub1cfa7b2014-11-09 12:36:34 -0800480 error = input_mt_init_slots(input, CYAPA_MAX_MT_SLOTS,
481 INPUT_MT_POINTER | INPUT_MT_DROP_UNUSED);
482 if (error) {
483 dev_err(dev, "failed to initialize MT slots: %d\n", error);
484 return error;
Benson Leungd7e34d12013-01-09 16:25:11 -0800485 }
486
Dudley Du9f1cd852015-01-17 18:35:26 -0800487 /* Register the device in input subsystem */
488 error = input_register_device(input);
489 if (error) {
490 dev_err(dev, "failed to register input device: %d\n", error);
491 return error;
492 }
493
Dudley Dub1cfa7b2014-11-09 12:36:34 -0800494 cyapa->input = input;
Benson Leungd7e34d12013-01-09 16:25:11 -0800495 return 0;
Benson Leungd7e34d12013-01-09 16:25:11 -0800496}
497
Dudley Duc806b0b2015-01-17 22:07:12 -0800498static void cyapa_enable_irq_for_cmd(struct cyapa *cyapa)
499{
500 struct input_dev *input = cyapa->input;
501
502 if (!input || !input->users) {
503 /*
504 * When input is NULL, TP must be in deep sleep mode.
505 * In this mode, later non-power I2C command will always failed
506 * if not bring it out of deep sleep mode firstly,
507 * so must command TP to active mode here.
508 */
509 if (!input || cyapa->operational)
510 cyapa->ops->set_power_mode(cyapa,
511 PWR_MODE_FULL_ACTIVE, 0);
512 /* Gen3 always using polling mode for command. */
513 if (cyapa->gen >= CYAPA_GEN5)
514 enable_irq(cyapa->client->irq);
515 }
516}
517
518static void cyapa_disable_irq_for_cmd(struct cyapa *cyapa)
519{
520 struct input_dev *input = cyapa->input;
521
522 if (!input || !input->users) {
523 if (cyapa->gen >= CYAPA_GEN5)
524 disable_irq(cyapa->client->irq);
525 if (!input || cyapa->operational)
526 cyapa->ops->set_power_mode(cyapa, PWR_MODE_OFF, 0);
527 }
528}
529
Dudley Du9f1cd852015-01-17 18:35:26 -0800530/*
531 * cyapa_sleep_time_to_pwr_cmd and cyapa_pwr_cmd_to_sleep_time
532 *
533 * These are helper functions that convert to and from integer idle
534 * times and register settings to write to the PowerMode register.
535 * The trackpad supports between 20ms to 1000ms scan intervals.
536 * The time will be increased in increments of 10ms from 20ms to 100ms.
537 * From 100ms to 1000ms, time will be increased in increments of 20ms.
538 *
539 * When Idle_Time < 100, the format to convert Idle_Time to Idle_Command is:
540 * Idle_Command = Idle Time / 10;
541 * When Idle_Time >= 100, the format to convert Idle_Time to Idle_Command is:
542 * Idle_Command = Idle Time / 20 + 5;
543 */
544u8 cyapa_sleep_time_to_pwr_cmd(u16 sleep_time)
545{
546 u16 encoded_time;
547
548 sleep_time = clamp_val(sleep_time, 20, 1000);
549 encoded_time = sleep_time < 100 ? sleep_time / 10 : sleep_time / 20 + 5;
550 return (encoded_time << 2) & PWR_MODE_MASK;
551}
552
553u16 cyapa_pwr_cmd_to_sleep_time(u8 pwr_mode)
554{
555 u8 encoded_time = pwr_mode >> 2;
556
557 return (encoded_time < 10) ? encoded_time * 10
558 : (encoded_time - 5) * 20;
559}
560
561/* 0 on driver initialize and detected successfully, negative on failure. */
562static int cyapa_initialize(struct cyapa *cyapa)
563{
564 int error = 0;
565
566 cyapa->state = CYAPA_STATE_NO_DEVICE;
567 cyapa->gen = CYAPA_GEN_UNKNOWN;
568 mutex_init(&cyapa->state_sync_lock);
569
570 /*
571 * Set to hard code default, they will be updated with trackpad set
572 * default values after probe and initialized.
573 */
574 cyapa->suspend_power_mode = PWR_MODE_SLEEP;
575 cyapa->suspend_sleep_time =
576 cyapa_pwr_cmd_to_sleep_time(cyapa->suspend_power_mode);
577
578 /* ops.initialize() is aimed to prepare for module communications. */
579 error = cyapa_gen3_ops.initialize(cyapa);
Dudley Du6972a852015-01-17 18:49:37 -0800580 if (!error)
581 error = cyapa_gen5_ops.initialize(cyapa);
Dudley Du9f1cd852015-01-17 18:35:26 -0800582 if (error)
583 return error;
584
585 error = cyapa_detect(cyapa);
586 if (error)
587 return error;
588
589 /* Power down the device until we need it. */
590 if (cyapa->operational)
591 cyapa->ops->set_power_mode(cyapa, PWR_MODE_OFF, 0);
592
593 return 0;
594}
595
596static int cyapa_reinitialize(struct cyapa *cyapa)
597{
598 struct device *dev = &cyapa->client->dev;
599 struct input_dev *input = cyapa->input;
600 int error;
601
Dudley Du67286502015-01-17 18:57:42 -0800602 if (pm_runtime_enabled(dev))
603 pm_runtime_disable(dev);
604
Dudley Du9f1cd852015-01-17 18:35:26 -0800605 /* Avoid command failures when TP was in OFF state. */
606 if (cyapa->operational)
607 cyapa->ops->set_power_mode(cyapa, PWR_MODE_FULL_ACTIVE, 0);
608
609 error = cyapa_detect(cyapa);
610 if (error)
611 goto out;
612
613 if (!input && cyapa->operational) {
614 error = cyapa_create_input_dev(cyapa);
615 if (error) {
616 dev_err(dev, "create input_dev instance failed: %d\n",
617 error);
618 goto out;
619 }
620 }
621
622out:
623 if (!input || !input->users) {
624 /* Reset to power OFF state to save power when no user open. */
625 if (cyapa->operational)
626 cyapa->ops->set_power_mode(cyapa, PWR_MODE_OFF, 0);
Dudley Du67286502015-01-17 18:57:42 -0800627 } else if (!error && cyapa->operational) {
628 /*
629 * Make sure only enable runtime PM when device is
630 * in operational mode and input->users > 0.
631 */
632 pm_runtime_set_active(dev);
633 pm_runtime_enable(dev);
Dudley Du9f1cd852015-01-17 18:35:26 -0800634 }
635
636 return error;
637}
638
639static irqreturn_t cyapa_irq(int irq, void *dev_id)
640{
641 struct cyapa *cyapa = dev_id;
642 struct device *dev = &cyapa->client->dev;
643
Dudley Du67286502015-01-17 18:57:42 -0800644 pm_runtime_get_sync(dev);
Dudley Du9f1cd852015-01-17 18:35:26 -0800645 if (device_may_wakeup(dev))
646 pm_wakeup_event(dev, 0);
647
Dudley Du94897612015-07-20 16:49:06 -0700648 /* Interrupt event can be caused by host command to trackpad device. */
Dudley Du9f1cd852015-01-17 18:35:26 -0800649 if (cyapa->ops->irq_cmd_handler(cyapa)) {
650 /*
651 * Interrupt event maybe from trackpad device input reporting.
652 */
653 if (!cyapa->input) {
654 /*
Dudley Du94897612015-07-20 16:49:06 -0700655 * Still in probing or in firmware image
656 * updating or reading.
Dudley Du9f1cd852015-01-17 18:35:26 -0800657 */
658 cyapa->ops->sort_empty_output_data(cyapa,
659 NULL, NULL, NULL);
660 goto out;
661 }
662
663 if (!cyapa->operational || cyapa->ops->irq_handler(cyapa)) {
664 if (!mutex_trylock(&cyapa->state_sync_lock)) {
665 cyapa->ops->sort_empty_output_data(cyapa,
666 NULL, NULL, NULL);
667 goto out;
668 }
669 cyapa_reinitialize(cyapa);
670 mutex_unlock(&cyapa->state_sync_lock);
671 }
672 }
673
674out:
Dudley Du67286502015-01-17 18:57:42 -0800675 pm_runtime_mark_last_busy(dev);
676 pm_runtime_put_sync_autosuspend(dev);
Dudley Du9f1cd852015-01-17 18:35:26 -0800677 return IRQ_HANDLED;
678}
679
Dudley Du22e7db82015-01-17 18:56:18 -0800680/*
681 **************************************************************
682 * sysfs interface
683 **************************************************************
684*/
685#ifdef CONFIG_PM_SLEEP
686static ssize_t cyapa_show_suspend_scanrate(struct device *dev,
687 struct device_attribute *attr,
688 char *buf)
689{
690 struct cyapa *cyapa = dev_get_drvdata(dev);
691 u8 pwr_cmd = cyapa->suspend_power_mode;
692 u16 sleep_time;
693 int len;
694 int error;
695
696 error = mutex_lock_interruptible(&cyapa->state_sync_lock);
697 if (error)
698 return error;
699
700 pwr_cmd = cyapa->suspend_power_mode;
701 sleep_time = cyapa->suspend_sleep_time;
702
703 mutex_unlock(&cyapa->state_sync_lock);
704
705 switch (pwr_cmd) {
706 case PWR_MODE_BTN_ONLY:
707 len = scnprintf(buf, PAGE_SIZE, "%s\n", BTN_ONLY_MODE_NAME);
708 break;
709
710 case PWR_MODE_OFF:
711 len = scnprintf(buf, PAGE_SIZE, "%s\n", OFF_MODE_NAME);
712 break;
713
714 default:
715 len = scnprintf(buf, PAGE_SIZE, "%u\n",
716 cyapa->gen == CYAPA_GEN3 ?
717 cyapa_pwr_cmd_to_sleep_time(pwr_cmd) :
718 sleep_time);
719 break;
720 }
721
722 return len;
723}
724
725static ssize_t cyapa_update_suspend_scanrate(struct device *dev,
726 struct device_attribute *attr,
727 const char *buf, size_t count)
728{
729 struct cyapa *cyapa = dev_get_drvdata(dev);
730 u16 sleep_time;
731 int error;
732
733 error = mutex_lock_interruptible(&cyapa->state_sync_lock);
734 if (error)
735 return error;
736
737 if (sysfs_streq(buf, BTN_ONLY_MODE_NAME)) {
738 cyapa->suspend_power_mode = PWR_MODE_BTN_ONLY;
739 } else if (sysfs_streq(buf, OFF_MODE_NAME)) {
740 cyapa->suspend_power_mode = PWR_MODE_OFF;
741 } else if (!kstrtou16(buf, 10, &sleep_time)) {
Dudley Dua333a032015-04-20 10:00:05 -0700742 cyapa->suspend_sleep_time = min_t(u16, sleep_time, 1000);
Dudley Du22e7db82015-01-17 18:56:18 -0800743 cyapa->suspend_power_mode =
744 cyapa_sleep_time_to_pwr_cmd(cyapa->suspend_sleep_time);
745 } else {
746 count = -EINVAL;
747 }
748
749 mutex_unlock(&cyapa->state_sync_lock);
750
751 return count;
752}
753
754static DEVICE_ATTR(suspend_scanrate_ms, S_IRUGO|S_IWUSR,
755 cyapa_show_suspend_scanrate,
756 cyapa_update_suspend_scanrate);
757
758static struct attribute *cyapa_power_wakeup_entries[] = {
759 &dev_attr_suspend_scanrate_ms.attr,
760 NULL,
761};
762
763static const struct attribute_group cyapa_power_wakeup_group = {
764 .name = power_group_name,
765 .attrs = cyapa_power_wakeup_entries,
766};
767
768static void cyapa_remove_power_wakeup_group(void *data)
769{
770 struct cyapa *cyapa = data;
771
772 sysfs_unmerge_group(&cyapa->client->dev.kobj,
773 &cyapa_power_wakeup_group);
774}
775
776static int cyapa_prepare_wakeup_controls(struct cyapa *cyapa)
777{
778 struct i2c_client *client = cyapa->client;
779 struct device *dev = &client->dev;
780 int error;
781
782 if (device_can_wakeup(dev)) {
783 error = sysfs_merge_group(&client->dev.kobj,
784 &cyapa_power_wakeup_group);
785 if (error) {
786 dev_err(dev, "failed to add power wakeup group: %d\n",
787 error);
788 return error;
789 }
790
791 error = devm_add_action(dev,
792 cyapa_remove_power_wakeup_group, cyapa);
793 if (error) {
794 cyapa_remove_power_wakeup_group(cyapa);
795 dev_err(dev, "failed to add power cleanup action: %d\n",
796 error);
797 return error;
798 }
799 }
800
801 return 0;
802}
803#else
804static inline int cyapa_prepare_wakeup_controls(struct cyapa *cyapa)
805{
806 return 0;
807}
808#endif /* CONFIG_PM_SLEEP */
809
Dudley Du67286502015-01-17 18:57:42 -0800810#ifdef CONFIG_PM
811static ssize_t cyapa_show_rt_suspend_scanrate(struct device *dev,
812 struct device_attribute *attr,
813 char *buf)
814{
815 struct cyapa *cyapa = dev_get_drvdata(dev);
816 u8 pwr_cmd;
817 u16 sleep_time;
818 int error;
819
820 error = mutex_lock_interruptible(&cyapa->state_sync_lock);
821 if (error)
822 return error;
823
824 pwr_cmd = cyapa->runtime_suspend_power_mode;
825 sleep_time = cyapa->runtime_suspend_sleep_time;
826
827 mutex_unlock(&cyapa->state_sync_lock);
828
829 return scnprintf(buf, PAGE_SIZE, "%u\n",
830 cyapa->gen == CYAPA_GEN3 ?
831 cyapa_pwr_cmd_to_sleep_time(pwr_cmd) :
832 sleep_time);
833}
834
835static ssize_t cyapa_update_rt_suspend_scanrate(struct device *dev,
836 struct device_attribute *attr,
837 const char *buf, size_t count)
838{
839 struct cyapa *cyapa = dev_get_drvdata(dev);
840 u16 time;
841 int error;
842
843 if (buf == NULL || count == 0 || kstrtou16(buf, 10, &time)) {
844 dev_err(dev, "invalid runtime suspend scanrate ms parameter\n");
845 return -EINVAL;
846 }
847
848 /*
849 * When the suspend scanrate is changed, pm_runtime_get to resume
850 * a potentially suspended device, update to the new pwr_cmd
851 * and then pm_runtime_put to suspend into the new power mode.
852 */
853 pm_runtime_get_sync(dev);
854
855 error = mutex_lock_interruptible(&cyapa->state_sync_lock);
856 if (error)
857 return error;
858
Dudley Dua333a032015-04-20 10:00:05 -0700859 cyapa->runtime_suspend_sleep_time = min_t(u16, time, 1000);
Dudley Du67286502015-01-17 18:57:42 -0800860 cyapa->runtime_suspend_power_mode =
861 cyapa_sleep_time_to_pwr_cmd(cyapa->runtime_suspend_sleep_time);
862
863 mutex_unlock(&cyapa->state_sync_lock);
864
865 pm_runtime_put_sync_autosuspend(dev);
866
867 return count;
868}
869
870static DEVICE_ATTR(runtime_suspend_scanrate_ms, S_IRUGO|S_IWUSR,
871 cyapa_show_rt_suspend_scanrate,
872 cyapa_update_rt_suspend_scanrate);
873
874static struct attribute *cyapa_power_runtime_entries[] = {
875 &dev_attr_runtime_suspend_scanrate_ms.attr,
876 NULL,
877};
878
879static const struct attribute_group cyapa_power_runtime_group = {
880 .name = power_group_name,
881 .attrs = cyapa_power_runtime_entries,
882};
883
884static void cyapa_remove_power_runtime_group(void *data)
885{
886 struct cyapa *cyapa = data;
887
888 sysfs_unmerge_group(&cyapa->client->dev.kobj,
889 &cyapa_power_runtime_group);
890}
891
892static int cyapa_start_runtime(struct cyapa *cyapa)
893{
894 struct device *dev = &cyapa->client->dev;
895 int error;
896
897 cyapa->runtime_suspend_power_mode = PWR_MODE_IDLE;
898 cyapa->runtime_suspend_sleep_time =
899 cyapa_pwr_cmd_to_sleep_time(cyapa->runtime_suspend_power_mode);
900
901 error = sysfs_merge_group(&dev->kobj, &cyapa_power_runtime_group);
902 if (error) {
903 dev_err(dev,
904 "failed to create power runtime group: %d\n", error);
905 return error;
906 }
907
908 error = devm_add_action(dev, cyapa_remove_power_runtime_group, cyapa);
909 if (error) {
910 cyapa_remove_power_runtime_group(cyapa);
911 dev_err(dev,
912 "failed to add power runtime cleanup action: %d\n",
913 error);
914 return error;
915 }
916
917 /* runtime is enabled until device is operational and opened. */
918 pm_runtime_set_suspended(dev);
919 pm_runtime_use_autosuspend(dev);
920 pm_runtime_set_autosuspend_delay(dev, AUTOSUSPEND_DELAY);
921
922 return 0;
923}
924#else
925static inline int cyapa_start_runtime(struct cyapa *cyapa)
926{
927 return 0;
928}
929#endif /* CONFIG_PM */
930
Dudley Duc806b0b2015-01-17 22:07:12 -0800931static ssize_t cyapa_show_fm_ver(struct device *dev,
932 struct device_attribute *attr, char *buf)
933{
934 int error;
935 struct cyapa *cyapa = dev_get_drvdata(dev);
936
937 error = mutex_lock_interruptible(&cyapa->state_sync_lock);
938 if (error)
939 return error;
940 error = scnprintf(buf, PAGE_SIZE, "%d.%d\n", cyapa->fw_maj_ver,
941 cyapa->fw_min_ver);
942 mutex_unlock(&cyapa->state_sync_lock);
943 return error;
944}
945
946static ssize_t cyapa_show_product_id(struct device *dev,
947 struct device_attribute *attr, char *buf)
948{
949 struct cyapa *cyapa = dev_get_drvdata(dev);
950 int size;
951 int error;
952
953 error = mutex_lock_interruptible(&cyapa->state_sync_lock);
954 if (error)
955 return error;
956 size = scnprintf(buf, PAGE_SIZE, "%s\n", cyapa->product_id);
957 mutex_unlock(&cyapa->state_sync_lock);
958 return size;
959}
960
961static int cyapa_firmware(struct cyapa *cyapa, const char *fw_name)
962{
963 struct device *dev = &cyapa->client->dev;
964 const struct firmware *fw;
965 int error;
966
967 error = request_firmware(&fw, fw_name, dev);
968 if (error) {
969 dev_err(dev, "Could not load firmware from %s: %d\n",
970 fw_name, error);
971 return error;
972 }
973
974 error = cyapa->ops->check_fw(cyapa, fw);
975 if (error) {
976 dev_err(dev, "Invalid CYAPA firmware image: %s\n",
977 fw_name);
978 goto done;
979 }
980
981 /*
982 * Resume the potentially suspended device because doing FW
983 * update on a device not in the FULL mode has a chance to
984 * fail.
985 */
986 pm_runtime_get_sync(dev);
987
988 /* Require IRQ support for firmware update commands. */
989 cyapa_enable_irq_for_cmd(cyapa);
990
991 error = cyapa->ops->bl_enter(cyapa);
992 if (error) {
993 dev_err(dev, "bl_enter failed, %d\n", error);
994 goto err_detect;
995 }
996
997 error = cyapa->ops->bl_activate(cyapa);
998 if (error) {
999 dev_err(dev, "bl_activate failed, %d\n", error);
1000 goto err_detect;
1001 }
1002
1003 error = cyapa->ops->bl_initiate(cyapa, fw);
1004 if (error) {
1005 dev_err(dev, "bl_initiate failed, %d\n", error);
1006 goto err_detect;
1007 }
1008
1009 error = cyapa->ops->update_fw(cyapa, fw);
1010 if (error) {
1011 dev_err(dev, "update_fw failed, %d\n", error);
1012 goto err_detect;
1013 }
1014
1015err_detect:
1016 cyapa_disable_irq_for_cmd(cyapa);
1017 pm_runtime_put_noidle(dev);
1018
1019done:
1020 release_firmware(fw);
1021 return error;
1022}
1023
1024static ssize_t cyapa_update_fw_store(struct device *dev,
1025 struct device_attribute *attr,
1026 const char *buf, size_t count)
1027{
1028 struct cyapa *cyapa = dev_get_drvdata(dev);
1029 char fw_name[NAME_MAX];
1030 int ret, error;
1031
Dan Carpenterb4810772015-01-22 08:20:16 -08001032 if (count >= NAME_MAX) {
Dudley Duc806b0b2015-01-17 22:07:12 -08001033 dev_err(dev, "File name too long\n");
1034 return -EINVAL;
1035 }
1036
1037 memcpy(fw_name, buf, count);
1038 if (fw_name[count - 1] == '\n')
1039 fw_name[count - 1] = '\0';
1040 else
1041 fw_name[count] = '\0';
1042
1043 if (cyapa->input) {
1044 /*
1045 * Force the input device to be registered after the firmware
1046 * image is updated, so if the corresponding parameters updated
1047 * in the new firmware image can taken effect immediately.
1048 */
1049 input_unregister_device(cyapa->input);
1050 cyapa->input = NULL;
1051 }
1052
1053 error = mutex_lock_interruptible(&cyapa->state_sync_lock);
1054 if (error) {
1055 /*
1056 * Whatever, do reinitialize to try to recover TP state to
1057 * previous state just as it entered fw update entrance.
1058 */
1059 cyapa_reinitialize(cyapa);
1060 return error;
1061 }
1062
1063 error = cyapa_firmware(cyapa, fw_name);
1064 if (error)
1065 dev_err(dev, "firmware update failed: %d\n", error);
1066 else
1067 dev_dbg(dev, "firmware update successfully done.\n");
1068
1069 /*
Dudley Du94897612015-07-20 16:49:06 -07001070 * Re-detect trackpad device states because firmware update process
Dudley Duc806b0b2015-01-17 22:07:12 -08001071 * will reset trackpad device into bootloader mode.
1072 */
1073 ret = cyapa_reinitialize(cyapa);
1074 if (ret) {
Dudley Du94897612015-07-20 16:49:06 -07001075 dev_err(dev, "failed to re-detect after updated: %d\n", ret);
Dudley Duc806b0b2015-01-17 22:07:12 -08001076 error = error ? error : ret;
1077 }
1078
1079 mutex_unlock(&cyapa->state_sync_lock);
1080
1081 return error ? error : count;
1082}
1083
1084static ssize_t cyapa_calibrate_store(struct device *dev,
1085 struct device_attribute *attr,
1086 const char *buf, size_t count)
1087{
1088 struct cyapa *cyapa = dev_get_drvdata(dev);
1089 int error;
1090
1091 error = mutex_lock_interruptible(&cyapa->state_sync_lock);
1092 if (error)
1093 return error;
1094
1095 if (cyapa->operational) {
1096 cyapa_enable_irq_for_cmd(cyapa);
1097 error = cyapa->ops->calibrate_store(dev, attr, buf, count);
1098 cyapa_disable_irq_for_cmd(cyapa);
1099 } else {
1100 error = -EBUSY; /* Still running in bootloader mode. */
1101 }
1102
1103 mutex_unlock(&cyapa->state_sync_lock);
1104 return error < 0 ? error : count;
1105}
1106
1107static ssize_t cyapa_show_baseline(struct device *dev,
1108 struct device_attribute *attr, char *buf)
1109{
1110 struct cyapa *cyapa = dev_get_drvdata(dev);
1111 ssize_t error;
1112
1113 error = mutex_lock_interruptible(&cyapa->state_sync_lock);
1114 if (error)
1115 return error;
1116
1117 if (cyapa->operational) {
1118 cyapa_enable_irq_for_cmd(cyapa);
1119 error = cyapa->ops->show_baseline(dev, attr, buf);
1120 cyapa_disable_irq_for_cmd(cyapa);
1121 } else {
1122 error = -EBUSY; /* Still running in bootloader mode. */
1123 }
1124
1125 mutex_unlock(&cyapa->state_sync_lock);
1126 return error;
1127}
1128
1129static char *cyapa_state_to_string(struct cyapa *cyapa)
1130{
1131 switch (cyapa->state) {
1132 case CYAPA_STATE_BL_BUSY:
1133 return "bootloader busy";
1134 case CYAPA_STATE_BL_IDLE:
1135 return "bootloader idle";
1136 case CYAPA_STATE_BL_ACTIVE:
1137 return "bootloader active";
1138 case CYAPA_STATE_GEN5_BL:
1139 return "bootloader";
1140 case CYAPA_STATE_OP:
1141 case CYAPA_STATE_GEN5_APP:
1142 return "operational"; /* Normal valid state. */
1143 default:
1144 return "invalid mode";
1145 }
1146}
1147
1148static ssize_t cyapa_show_mode(struct device *dev,
1149 struct device_attribute *attr, char *buf)
1150{
1151 struct cyapa *cyapa = dev_get_drvdata(dev);
1152 int size;
1153 int error;
1154
1155 error = mutex_lock_interruptible(&cyapa->state_sync_lock);
1156 if (error)
1157 return error;
1158
1159 size = scnprintf(buf, PAGE_SIZE, "gen%d %s\n",
1160 cyapa->gen, cyapa_state_to_string(cyapa));
1161
1162 mutex_unlock(&cyapa->state_sync_lock);
1163 return size;
1164}
1165
1166static DEVICE_ATTR(firmware_version, S_IRUGO, cyapa_show_fm_ver, NULL);
1167static DEVICE_ATTR(product_id, S_IRUGO, cyapa_show_product_id, NULL);
1168static DEVICE_ATTR(update_fw, S_IWUSR, NULL, cyapa_update_fw_store);
1169static DEVICE_ATTR(baseline, S_IRUGO, cyapa_show_baseline, NULL);
1170static DEVICE_ATTR(calibrate, S_IWUSR, NULL, cyapa_calibrate_store);
1171static DEVICE_ATTR(mode, S_IRUGO, cyapa_show_mode, NULL);
1172
1173static struct attribute *cyapa_sysfs_entries[] = {
1174 &dev_attr_firmware_version.attr,
1175 &dev_attr_product_id.attr,
1176 &dev_attr_update_fw.attr,
1177 &dev_attr_baseline.attr,
1178 &dev_attr_calibrate.attr,
1179 &dev_attr_mode.attr,
1180 NULL,
1181};
1182
1183static const struct attribute_group cyapa_sysfs_group = {
1184 .attrs = cyapa_sysfs_entries,
1185};
1186
1187static void cyapa_remove_sysfs_group(void *data)
1188{
1189 struct cyapa *cyapa = data;
1190
1191 sysfs_remove_group(&cyapa->client->dev.kobj, &cyapa_sysfs_group);
1192}
1193
Benson Leungd7e34d12013-01-09 16:25:11 -08001194static int cyapa_probe(struct i2c_client *client,
1195 const struct i2c_device_id *dev_id)
1196{
Benson Leungd7e34d12013-01-09 16:25:11 -08001197 struct device *dev = &client->dev;
Dudley Dub1cfa7b2014-11-09 12:36:34 -08001198 struct cyapa *cyapa;
1199 u8 adapter_func;
Dudley Du9f1cd852015-01-17 18:35:26 -08001200 union i2c_smbus_data dummy;
Dudley Dub1cfa7b2014-11-09 12:36:34 -08001201 int error;
Benson Leungd7e34d12013-01-09 16:25:11 -08001202
Benson Leung6ddaf742013-02-13 13:56:03 -08001203 adapter_func = cyapa_check_adapter_functionality(client);
1204 if (adapter_func == CYAPA_ADAPTER_FUNC_NONE) {
1205 dev_err(dev, "not a supported I2C/SMBus adapter\n");
1206 return -EIO;
1207 }
1208
Dudley Du9f1cd852015-01-17 18:35:26 -08001209 /* Make sure there is something at this address */
1210 if (i2c_smbus_xfer(client->adapter, client->addr, 0,
1211 I2C_SMBUS_READ, 0, I2C_SMBUS_BYTE, &dummy) < 0)
1212 return -ENODEV;
1213
Dudley Dub1cfa7b2014-11-09 12:36:34 -08001214 cyapa = devm_kzalloc(dev, sizeof(struct cyapa), GFP_KERNEL);
1215 if (!cyapa)
Benson Leungd7e34d12013-01-09 16:25:11 -08001216 return -ENOMEM;
Benson Leungd7e34d12013-01-09 16:25:11 -08001217
Benson Leung6ddaf742013-02-13 13:56:03 -08001218 /* i2c isn't supported, use smbus */
1219 if (adapter_func == CYAPA_ADAPTER_FUNC_SMBUS)
1220 cyapa->smbus = true;
Dudley Dub1cfa7b2014-11-09 12:36:34 -08001221
Dudley Du9f1cd852015-01-17 18:35:26 -08001222 cyapa->client = client;
1223 i2c_set_clientdata(client, cyapa);
1224 sprintf(cyapa->phys, "i2c-%d-%04x/input0", client->adapter->nr,
1225 client->addr);
Dudley Dub1cfa7b2014-11-09 12:36:34 -08001226
Dudley Du9f1cd852015-01-17 18:35:26 -08001227 error = cyapa_initialize(cyapa);
Dudley Dub1cfa7b2014-11-09 12:36:34 -08001228 if (error) {
Dudley Du9f1cd852015-01-17 18:35:26 -08001229 dev_err(dev, "failed to detect and initialize tp device.\n");
Dudley Dub1cfa7b2014-11-09 12:36:34 -08001230 return error;
Benson Leungd7e34d12013-01-09 16:25:11 -08001231 }
1232
Dudley Duc806b0b2015-01-17 22:07:12 -08001233 error = sysfs_create_group(&client->dev.kobj, &cyapa_sysfs_group);
1234 if (error) {
1235 dev_err(dev, "failed to create sysfs entries: %d\n", error);
1236 return error;
1237 }
1238
1239 error = devm_add_action(dev, cyapa_remove_sysfs_group, cyapa);
1240 if (error) {
1241 cyapa_remove_sysfs_group(cyapa);
1242 dev_err(dev, "failed to add sysfs cleanup action: %d\n", error);
1243 return error;
1244 }
1245
Dudley Du22e7db82015-01-17 18:56:18 -08001246 error = cyapa_prepare_wakeup_controls(cyapa);
1247 if (error) {
1248 dev_err(dev, "failed to prepare wakeup controls: %d\n", error);
1249 return error;
1250 }
1251
Dudley Du67286502015-01-17 18:57:42 -08001252 error = cyapa_start_runtime(cyapa);
1253 if (error) {
1254 dev_err(dev, "failed to start pm_runtime: %d\n", error);
1255 return error;
1256 }
1257
Dudley Dub1cfa7b2014-11-09 12:36:34 -08001258 error = devm_request_threaded_irq(dev, client->irq,
1259 NULL, cyapa_irq,
1260 IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
1261 "cyapa", cyapa);
1262 if (error) {
Dudley Du823a11f2014-12-04 07:00:03 -08001263 dev_err(dev, "failed to request threaded irq: %d\n", error);
Dudley Dub1cfa7b2014-11-09 12:36:34 -08001264 return error;
Benson Leungd7e34d12013-01-09 16:25:11 -08001265 }
1266
Dudley Dub1cfa7b2014-11-09 12:36:34 -08001267 /* Disable IRQ until the device is opened */
1268 disable_irq(client->irq);
1269
Dudley Du9f1cd852015-01-17 18:35:26 -08001270 /*
1271 * Register the device in the input subsystem when it's operational.
1272 * Otherwise, keep in this driver, so it can be be recovered or updated
1273 * through the sysfs mode and update_fw interfaces by user or apps.
1274 */
1275 if (cyapa->operational) {
1276 error = cyapa_create_input_dev(cyapa);
1277 if (error) {
1278 dev_err(dev, "create input_dev instance failed: %d\n",
1279 error);
1280 return error;
1281 }
Benson Leungd7e34d12013-01-09 16:25:11 -08001282 }
1283
1284 return 0;
Benson Leungd7e34d12013-01-09 16:25:11 -08001285}
1286
Jingoo Han572081a2014-11-02 00:03:37 -07001287static int __maybe_unused cyapa_suspend(struct device *dev)
Benson Leungd7e34d12013-01-09 16:25:11 -08001288{
Dudley Dub1cfa7b2014-11-09 12:36:34 -08001289 struct i2c_client *client = to_i2c_client(dev);
1290 struct cyapa *cyapa = i2c_get_clientdata(client);
Benson Leungd7e34d12013-01-09 16:25:11 -08001291 u8 power_mode;
Dudley Dub1cfa7b2014-11-09 12:36:34 -08001292 int error;
Benson Leungd7e34d12013-01-09 16:25:11 -08001293
Dudley Du9f1cd852015-01-17 18:35:26 -08001294 error = mutex_lock_interruptible(&cyapa->state_sync_lock);
Dudley Dub1cfa7b2014-11-09 12:36:34 -08001295 if (error)
1296 return error;
1297
Dudley Du67286502015-01-17 18:57:42 -08001298 /*
1299 * Runtime PM is enable only when device is in operational mode and
1300 * users in use, so need check it before disable it to
1301 * avoid unbalance warning.
1302 */
1303 if (pm_runtime_enabled(dev))
1304 pm_runtime_disable(dev);
Dudley Dub1cfa7b2014-11-09 12:36:34 -08001305 disable_irq(client->irq);
Benson Leungd7e34d12013-01-09 16:25:11 -08001306
1307 /*
1308 * Set trackpad device to idle mode if wakeup is allowed,
1309 * otherwise turn off.
1310 */
Dudley Du9f1cd852015-01-17 18:35:26 -08001311 if (cyapa->operational) {
1312 power_mode = device_may_wakeup(dev) ? cyapa->suspend_power_mode
1313 : PWR_MODE_OFF;
1314 error = cyapa->ops->set_power_mode(cyapa, power_mode,
1315 cyapa->suspend_sleep_time);
1316 if (error)
1317 dev_err(dev, "suspend set power mode failed: %d\n",
1318 error);
1319 }
Benson Leungd7e34d12013-01-09 16:25:11 -08001320
1321 if (device_may_wakeup(dev))
Dudley Duf68a95c2014-12-03 15:29:34 -08001322 cyapa->irq_wake = (enable_irq_wake(client->irq) == 0);
Dudley Dub1cfa7b2014-11-09 12:36:34 -08001323
Dudley Du9f1cd852015-01-17 18:35:26 -08001324 mutex_unlock(&cyapa->state_sync_lock);
Benson Leungd7e34d12013-01-09 16:25:11 -08001325 return 0;
1326}
1327
Jingoo Han572081a2014-11-02 00:03:37 -07001328static int __maybe_unused cyapa_resume(struct device *dev)
Benson Leungd7e34d12013-01-09 16:25:11 -08001329{
Dudley Dub1cfa7b2014-11-09 12:36:34 -08001330 struct i2c_client *client = to_i2c_client(dev);
1331 struct cyapa *cyapa = i2c_get_clientdata(client);
Dudley Dub1cfa7b2014-11-09 12:36:34 -08001332 int error;
1333
Dudley Du9f1cd852015-01-17 18:35:26 -08001334 mutex_lock(&cyapa->state_sync_lock);
Benson Leungd7e34d12013-01-09 16:25:11 -08001335
Dudley Du9f1cd852015-01-17 18:35:26 -08001336 if (device_may_wakeup(dev) && cyapa->irq_wake) {
Dudley Duf68a95c2014-12-03 15:29:34 -08001337 disable_irq_wake(client->irq);
Dudley Du9f1cd852015-01-17 18:35:26 -08001338 cyapa->irq_wake = false;
1339 }
Benson Leungd7e34d12013-01-09 16:25:11 -08001340
Dudley Du67286502015-01-17 18:57:42 -08001341 /* Update device states and runtime PM states. */
Dudley Du9f1cd852015-01-17 18:35:26 -08001342 error = cyapa_reinitialize(cyapa);
Dudley Dub1cfa7b2014-11-09 12:36:34 -08001343 if (error)
Dudley Du9f1cd852015-01-17 18:35:26 -08001344 dev_warn(dev, "failed to reinitialize TP device: %d\n", error);
Benson Leungd7e34d12013-01-09 16:25:11 -08001345
Dudley Duf68a95c2014-12-03 15:29:34 -08001346 enable_irq(client->irq);
Dudley Dub1cfa7b2014-11-09 12:36:34 -08001347
Dudley Du9f1cd852015-01-17 18:35:26 -08001348 mutex_unlock(&cyapa->state_sync_lock);
Benson Leungd7e34d12013-01-09 16:25:11 -08001349 return 0;
1350}
Benson Leungd7e34d12013-01-09 16:25:11 -08001351
Dudley Du67286502015-01-17 18:57:42 -08001352static int __maybe_unused cyapa_runtime_suspend(struct device *dev)
1353{
1354 struct cyapa *cyapa = dev_get_drvdata(dev);
1355 int error;
1356
1357 error = cyapa->ops->set_power_mode(cyapa,
1358 cyapa->runtime_suspend_power_mode,
1359 cyapa->runtime_suspend_sleep_time);
1360 if (error)
1361 dev_warn(dev, "runtime suspend failed: %d\n", error);
1362
1363 return 0;
1364}
1365
1366static int __maybe_unused cyapa_runtime_resume(struct device *dev)
1367{
1368 struct cyapa *cyapa = dev_get_drvdata(dev);
1369 int error;
1370
1371 error = cyapa->ops->set_power_mode(cyapa, PWR_MODE_FULL_ACTIVE, 0);
1372 if (error)
1373 dev_warn(dev, "runtime resume failed: %d\n", error);
1374
1375 return 0;
1376}
1377
1378static const struct dev_pm_ops cyapa_pm_ops = {
1379 SET_SYSTEM_SLEEP_PM_OPS(cyapa_suspend, cyapa_resume)
1380 SET_RUNTIME_PM_OPS(cyapa_runtime_suspend, cyapa_runtime_resume, NULL)
1381};
Benson Leungd7e34d12013-01-09 16:25:11 -08001382
1383static const struct i2c_device_id cyapa_id_table[] = {
1384 { "cyapa", 0 },
1385 { },
1386};
1387MODULE_DEVICE_TABLE(i2c, cyapa_id_table);
1388
Dudley Du7b2171d2015-01-17 22:18:59 -08001389#ifdef CONFIG_ACPI
1390static const struct acpi_device_id cyapa_acpi_id[] = {
1391 { "CYAP0000", 0 }, /* Gen3 trackpad with 0x67 I2C address. */
1392 { "CYAP0001", 0 }, /* Gen5 trackpad with 0x24 I2C address. */
1393 { }
1394};
1395MODULE_DEVICE_TABLE(acpi, cyapa_acpi_id);
1396#endif
1397
Benson Leungd7e34d12013-01-09 16:25:11 -08001398static struct i2c_driver cyapa_driver = {
1399 .driver = {
1400 .name = "cyapa",
Benson Leungd7e34d12013-01-09 16:25:11 -08001401 .pm = &cyapa_pm_ops,
Dudley Du7b2171d2015-01-17 22:18:59 -08001402 .acpi_match_table = ACPI_PTR(cyapa_acpi_id),
Benson Leungd7e34d12013-01-09 16:25:11 -08001403 },
1404
1405 .probe = cyapa_probe,
Benson Leungd7e34d12013-01-09 16:25:11 -08001406 .id_table = cyapa_id_table,
1407};
1408
1409module_i2c_driver(cyapa_driver);
1410
1411MODULE_DESCRIPTION("Cypress APA I2C Trackpad Driver");
1412MODULE_AUTHOR("Dudley Du <dudl@cypress.com>");
1413MODULE_LICENSE("GPL");