diff options
Diffstat (limited to 'drivers/input/touchscreen/pixcir_i2c_ts.c')
-rw-r--r-- | drivers/input/touchscreen/pixcir_i2c_ts.c | 182 |
1 files changed, 174 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 | ||
35 | static void pixcir_ts_poscheck(struct pixcir_i2c_ts_data *data) | 35 | static 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 | ||
103 | static 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 | */ | ||
137 | static 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 | */ | ||
171 | static 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 | |||
198 | static 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 | |||
224 | static 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 | |||
247 | static 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 | |||
254 | static 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 |
104 | static int pixcir_i2c_ts_suspend(struct device *dev) | 262 | static 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 | ||
189 | static int pixcir_i2c_ts_remove(struct i2c_client *client) | 360 | static 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 | ||