aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRoger Quadros <rogerq@ti.com>2014-05-19 01:44:35 -0400
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2014-05-19 02:25:56 -0400
commit3b36fbb01dc50f58e7803006f5a99683daf26c8c (patch)
treed523a06fd4a4ea9b5043e22c101fe853bb7075bb
parente9d4718dcd53281c191cb5fccb53ce0246e10104 (diff)
Input: pixcir_i2c_ts - initialize interrupt mode and power mode
Introduce helper functions to configure power and interrupt registers. Default to IDLE mode on probe as device supports auto wakeup to ACVIE mode on detecting finger touch. Configure interrupt mode and polarity on start up. Power down on device closure or module removal. Signed-off-by: Roger Quadros <rogerq@ti.com> Acked-by: Mugunthan V N <mugunthanvnm@ti.com> Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
-rw-r--r--drivers/input/touchscreen/pixcir_i2c_ts.c182
-rw-r--r--include/linux/input/pixcir_ts.h42
2 files changed, 216 insertions, 8 deletions
diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c
index 5d36243bdc79..6c6f6dacb858 100644
--- a/drivers/input/touchscreen/pixcir_i2c_ts.c
+++ b/drivers/input/touchscreen/pixcir_i2c_ts.c
@@ -29,7 +29,7 @@ struct pixcir_i2c_ts_data {
29 struct i2c_client *client; 29 struct i2c_client *client;
30 struct input_dev *input; 30 struct input_dev *input;
31 const struct pixcir_ts_platform_data *chip; 31 const struct pixcir_ts_platform_data *chip;
32 bool exiting; 32 bool running;
33}; 33};
34 34
35static void pixcir_ts_poscheck(struct pixcir_i2c_ts_data *data) 35static void pixcir_ts_poscheck(struct pixcir_i2c_ts_data *data)
@@ -88,7 +88,7 @@ static irqreturn_t pixcir_ts_isr(int irq, void *dev_id)
88{ 88{
89 struct pixcir_i2c_ts_data *tsdata = dev_id; 89 struct pixcir_i2c_ts_data *tsdata = dev_id;
90 90
91 while (!tsdata->exiting) { 91 while (tsdata->running) {
92 pixcir_ts_poscheck(tsdata); 92 pixcir_ts_poscheck(tsdata);
93 93
94 if (tsdata->chip->attb_read_val()) 94 if (tsdata->chip->attb_read_val())
@@ -100,6 +100,164 @@ static irqreturn_t pixcir_ts_isr(int irq, void *dev_id)
100 return IRQ_HANDLED; 100 return IRQ_HANDLED;
101} 101}
102 102
103static int pixcir_set_power_mode(struct pixcir_i2c_ts_data *ts,
104 enum pixcir_power_mode mode)
105{
106 struct device *dev = &ts->client->dev;
107 int ret;
108
109 ret = i2c_smbus_read_byte_data(ts->client, PIXCIR_REG_POWER_MODE);
110 if (ret < 0) {
111 dev_err(dev, "%s: can't read reg 0x%x : %d\n",
112 __func__, PIXCIR_REG_POWER_MODE, ret);
113 return ret;
114 }
115
116 ret &= ~PIXCIR_POWER_MODE_MASK;
117 ret |= mode;
118
119 /* Always AUTO_IDLE */
120 ret |= PIXCIR_POWER_ALLOW_IDLE;
121
122 ret = i2c_smbus_write_byte_data(ts->client, PIXCIR_REG_POWER_MODE, ret);
123 if (ret < 0) {
124 dev_err(dev, "%s: can't write reg 0x%x : %d\n",
125 __func__, PIXCIR_REG_POWER_MODE, ret);
126 return ret;
127 }
128
129 return 0;
130}
131
132/*
133 * Set the interrupt mode for the device i.e. ATTB line behaviour
134 *
135 * @polarity : 1 for active high, 0 for active low.
136 */
137static int pixcir_set_int_mode(struct pixcir_i2c_ts_data *ts,
138 enum pixcir_int_mode mode, bool polarity)
139{
140 struct device *dev = &ts->client->dev;
141 int ret;
142
143 ret = i2c_smbus_read_byte_data(ts->client, PIXCIR_REG_INT_MODE);
144 if (ret < 0) {
145 dev_err(dev, "%s: can't read reg 0x%x : %d\n",
146 __func__, PIXCIR_REG_INT_MODE, ret);
147 return ret;
148 }
149
150 ret &= ~PIXCIR_INT_MODE_MASK;
151 ret |= mode;
152
153 if (polarity)
154 ret |= PIXCIR_INT_POL_HIGH;
155 else
156 ret &= ~PIXCIR_INT_POL_HIGH;
157
158 ret = i2c_smbus_write_byte_data(ts->client, PIXCIR_REG_INT_MODE, ret);
159 if (ret < 0) {
160 dev_err(dev, "%s: can't write reg 0x%x : %d\n",
161 __func__, PIXCIR_REG_INT_MODE, ret);
162 return ret;
163 }
164
165 return 0;
166}
167
168/*
169 * Enable/disable interrupt generation
170 */
171static int pixcir_int_enable(struct pixcir_i2c_ts_data *ts, bool enable)
172{
173 struct device *dev = &ts->client->dev;
174 int ret;
175
176 ret = i2c_smbus_read_byte_data(ts->client, PIXCIR_REG_INT_MODE);
177 if (ret < 0) {
178 dev_err(dev, "%s: can't read reg 0x%x : %d\n",
179 __func__, PIXCIR_REG_INT_MODE, ret);
180 return ret;
181 }
182
183 if (enable)
184 ret |= PIXCIR_INT_ENABLE;
185 else
186 ret &= ~PIXCIR_INT_ENABLE;
187
188 ret = i2c_smbus_write_byte_data(ts->client, PIXCIR_REG_INT_MODE, ret);
189 if (ret < 0) {
190 dev_err(dev, "%s: can't write reg 0x%x : %d\n",
191 __func__, PIXCIR_REG_INT_MODE, ret);
192 return ret;
193 }
194
195 return 0;
196}
197
198static int pixcir_start(struct pixcir_i2c_ts_data *ts)
199{
200 struct device *dev = &ts->client->dev;
201 int error;
202
203 /* LEVEL_TOUCH interrupt with active low polarity */
204 error = pixcir_set_int_mode(ts, PIXCIR_INT_LEVEL_TOUCH, 0);
205 if (error) {
206 dev_err(dev, "Failed to set interrupt mode: %d\n", error);
207 return error;
208 }
209
210 ts->running = true;
211 mb(); /* Update status before IRQ can fire */
212
213 /* enable interrupt generation */
214 error = pixcir_int_enable(ts, true);
215 if (error) {
216 dev_err(dev, "Failed to enable interrupt generation: %d\n",
217 error);
218 return error;
219 }
220
221 return 0;
222}
223
224static int pixcir_stop(struct pixcir_i2c_ts_data *ts)
225{
226 int error;
227
228 /* Disable interrupt generation */
229 error = pixcir_int_enable(ts, false);
230 if (error) {
231 dev_err(&ts->client->dev,
232 "Failed to disable interrupt generation: %d\n",
233 error);
234 return error;
235 }
236
237 /* Exit ISR if running, no more report parsing */
238 ts->running = false;
239 mb(); /* update status before we synchronize irq */
240
241 /* Wait till running ISR is complete */
242 synchronize_irq(ts->client->irq);
243
244 return 0;
245}
246
247static int pixcir_input_open(struct input_dev *dev)
248{
249 struct pixcir_i2c_ts_data *ts = input_get_drvdata(dev);
250
251 return pixcir_start(ts);
252}
253
254static void pixcir_input_close(struct input_dev *dev)
255{
256 struct pixcir_i2c_ts_data *ts = input_get_drvdata(dev);
257
258 pixcir_stop(ts);
259}
260
103#ifdef CONFIG_PM_SLEEP 261#ifdef CONFIG_PM_SLEEP
104static int pixcir_i2c_ts_suspend(struct device *dev) 262static int pixcir_i2c_ts_suspend(struct device *dev)
105{ 263{
@@ -156,6 +314,8 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client,
156 314
157 input->name = client->name; 315 input->name = client->name;
158 input->id.bustype = BUS_I2C; 316 input->id.bustype = BUS_I2C;
317 input->open = pixcir_input_open;
318 input->close = pixcir_input_close;
159 input->dev.parent = &client->dev; 319 input->dev.parent = &client->dev;
160 320
161 __set_bit(EV_KEY, input->evbit); 321 __set_bit(EV_KEY, input->evbit);
@@ -176,11 +336,22 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client,
176 return error; 336 return error;
177 } 337 }
178 338
339 /* Always be in IDLE mode to save power, device supports auto wake */
340 error = pixcir_set_power_mode(tsdata, PIXCIR_POWER_IDLE);
341 if (error) {
342 dev_err(dev, "Failed to set IDLE mode\n");
343 return error;
344 }
345
346 /* Stop device till opened */
347 error = pixcir_stop(tsdata);
348 if (error)
349 return error;
350
179 error = input_register_device(input); 351 error = input_register_device(input);
180 if (error) 352 if (error)
181 return error; 353 return error;
182 354
183 i2c_set_clientdata(client, tsdata);
184 device_init_wakeup(&client->dev, 1); 355 device_init_wakeup(&client->dev, 1);
185 356
186 return 0; 357 return 0;
@@ -188,13 +359,8 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client,
188 359
189static int pixcir_i2c_ts_remove(struct i2c_client *client) 360static int pixcir_i2c_ts_remove(struct i2c_client *client)
190{ 361{
191 struct pixcir_i2c_ts_data *tsdata = i2c_get_clientdata(client);
192
193 device_init_wakeup(&client->dev, 0); 362 device_init_wakeup(&client->dev, 0);
194 363
195 tsdata->exiting = true;
196 mb();
197
198 return 0; 364 return 0;
199} 365}
200 366
diff --git a/include/linux/input/pixcir_ts.h b/include/linux/input/pixcir_ts.h
index 7163d91c0373..7942804464d3 100644
--- a/include/linux/input/pixcir_ts.h
+++ b/include/linux/input/pixcir_ts.h
@@ -1,6 +1,48 @@
1#ifndef _PIXCIR_I2C_TS_H 1#ifndef _PIXCIR_I2C_TS_H
2#define _PIXCIR_I2C_TS_H 2#define _PIXCIR_I2C_TS_H
3 3
4/*
5 * Register map
6 */
7#define PIXCIR_REG_POWER_MODE 51
8#define PIXCIR_REG_INT_MODE 52
9
10/*
11 * Power modes:
12 * active: max scan speed
13 * idle: lower scan speed with automatic transition to active on touch
14 * halt: datasheet says sleep but this is more like halt as the chip
15 * clocks are cut and it can only be brought out of this mode
16 * using the RESET pin.
17 */
18enum pixcir_power_mode {
19 PIXCIR_POWER_ACTIVE,
20 PIXCIR_POWER_IDLE,
21 PIXCIR_POWER_HALT,
22};
23
24#define PIXCIR_POWER_MODE_MASK 0x03
25#define PIXCIR_POWER_ALLOW_IDLE (1UL << 2)
26
27/*
28 * Interrupt modes:
29 * periodical: interrupt is asserted periodicaly
30 * diff coordinates: interrupt is asserted when coordinates change
31 * level on touch: interrupt level asserted during touch
32 * pulse on touch: interrupt pulse asserted druing touch
33 *
34 */
35enum pixcir_int_mode {
36 PIXCIR_INT_PERIODICAL,
37 PIXCIR_INT_DIFF_COORD,
38 PIXCIR_INT_LEVEL_TOUCH,
39 PIXCIR_INT_PULSE_TOUCH,
40};
41
42#define PIXCIR_INT_MODE_MASK 0x03
43#define PIXCIR_INT_ENABLE (1UL << 3)
44#define PIXCIR_INT_POL_HIGH (1UL << 2)
45
4struct pixcir_ts_platform_data { 46struct pixcir_ts_platform_data {
5 int (*attb_read_val)(void); 47 int (*attb_read_val)(void);
6 int x_max; 48 int x_max;