diff options
author | Naveen Kumar Gaddipati <naveen.gaddipati@stericsson.com> | 2010-10-05 01:32:48 -0400 |
---|---|---|
committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2010-10-13 10:49:27 -0400 |
commit | 4780c8df3856398020be2928d9e9fa8c457a09a4 (patch) | |
tree | 398c8111f0de21a74e871dcf8eb6c15ff88e8940 | |
parent | 9a34bc61160167319fcfa59842cc0373487d533b (diff) |
Input: add ROHM BU21013 touch panel controller support
Add the ROHM BU21013 capacitive touch panel controller support with
i2c interface.
Acked-by: Linus Walleij <linus.walleij@stericsson.com>
Signed-off-by: Naveen Kumar Gaddipati <naveen.gaddipati@stericsson.com>
Acked-by: Henrik Rydberg <rydberg@euromail.se>
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
-rw-r--r-- | drivers/input/touchscreen/Kconfig | 12 | ||||
-rw-r--r-- | drivers/input/touchscreen/Makefile | 1 | ||||
-rw-r--r-- | drivers/input/touchscreen/bu21013_ts.c | 648 | ||||
-rw-r--r-- | include/linux/input/bu21013.h | 44 |
4 files changed, 705 insertions, 0 deletions
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index d59feb7b90f6..0ea361f23fa7 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig | |||
@@ -98,6 +98,18 @@ config TOUCHSCREEN_BITSY | |||
98 | To compile this driver as a module, choose M here: the | 98 | To compile this driver as a module, choose M here: the |
99 | module will be called h3600_ts_input. | 99 | module will be called h3600_ts_input. |
100 | 100 | ||
101 | config TOUCHSCREEN_BU21013 | ||
102 | tristate "BU21013 based touch panel controllers" | ||
103 | depends on I2C | ||
104 | help | ||
105 | Say Y here if you have a bu21013 touchscreen connected to | ||
106 | your system. | ||
107 | |||
108 | If unsure, say N. | ||
109 | |||
110 | To compile this driver as a module, choose M here: the | ||
111 | module will be called bu21013_ts. | ||
112 | |||
101 | config TOUCHSCREEN_CY8CTMG110 | 113 | config TOUCHSCREEN_CY8CTMG110 |
102 | tristate "cy8ctmg110 touchscreen" | 114 | tristate "cy8ctmg110 touchscreen" |
103 | depends on I2C | 115 | depends on I2C |
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index f1bc8a416824..99b353c4e9ae 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile | |||
@@ -14,6 +14,7 @@ obj-$(CONFIG_TOUCHSCREEN_AD7879_SPI) += ad7879-spi.o | |||
14 | obj-$(CONFIG_TOUCHSCREEN_ADS7846) += ads7846.o | 14 | obj-$(CONFIG_TOUCHSCREEN_ADS7846) += ads7846.o |
15 | obj-$(CONFIG_TOUCHSCREEN_ATMEL_TSADCC) += atmel_tsadcc.o | 15 | obj-$(CONFIG_TOUCHSCREEN_ATMEL_TSADCC) += atmel_tsadcc.o |
16 | obj-$(CONFIG_TOUCHSCREEN_BITSY) += h3600_ts_input.o | 16 | obj-$(CONFIG_TOUCHSCREEN_BITSY) += h3600_ts_input.o |
17 | obj-$(CONFIG_TOUCHSCREEN_BU21013) += bu21013_ts.o | ||
17 | obj-$(CONFIG_TOUCHSCREEN_CY8CTMG110) += cy8ctmg110_ts.o | 18 | obj-$(CONFIG_TOUCHSCREEN_CY8CTMG110) += cy8ctmg110_ts.o |
18 | obj-$(CONFIG_TOUCHSCREEN_DA9034) += da9034-ts.o | 19 | obj-$(CONFIG_TOUCHSCREEN_DA9034) += da9034-ts.o |
19 | obj-$(CONFIG_TOUCHSCREEN_DYNAPRO) += dynapro.o | 20 | obj-$(CONFIG_TOUCHSCREEN_DYNAPRO) += dynapro.o |
diff --git a/drivers/input/touchscreen/bu21013_ts.c b/drivers/input/touchscreen/bu21013_ts.c new file mode 100644 index 000000000000..ccde58602563 --- /dev/null +++ b/drivers/input/touchscreen/bu21013_ts.c | |||
@@ -0,0 +1,648 @@ | |||
1 | /* | ||
2 | * Copyright (C) ST-Ericsson SA 2010 | ||
3 | * Author: Naveen Kumar G <naveen.gaddipati@stericsson.com> for ST-Ericsson | ||
4 | * License terms:GNU General Public License (GPL) version 2 | ||
5 | */ | ||
6 | |||
7 | #include <linux/kernel.h> | ||
8 | #include <linux/delay.h> | ||
9 | #include <linux/interrupt.h> | ||
10 | #include <linux/i2c.h> | ||
11 | #include <linux/workqueue.h> | ||
12 | #include <linux/input.h> | ||
13 | #include <linux/input/bu21013.h> | ||
14 | #include <linux/slab.h> | ||
15 | |||
16 | #define PEN_DOWN_INTR 0 | ||
17 | #define MAX_FINGERS 2 | ||
18 | #define RESET_DELAY 30 | ||
19 | #define PENUP_TIMEOUT (10) | ||
20 | #define DELTA_MIN 16 | ||
21 | #define MASK_BITS 0x03 | ||
22 | #define SHIFT_8 8 | ||
23 | #define SHIFT_2 2 | ||
24 | #define LENGTH_OF_BUFFER 11 | ||
25 | #define I2C_RETRY_COUNT 5 | ||
26 | |||
27 | #define BU21013_SENSORS_BTN_0_7_REG 0x70 | ||
28 | #define BU21013_SENSORS_BTN_8_15_REG 0x71 | ||
29 | #define BU21013_SENSORS_BTN_16_23_REG 0x72 | ||
30 | #define BU21013_X1_POS_MSB_REG 0x73 | ||
31 | #define BU21013_X1_POS_LSB_REG 0x74 | ||
32 | #define BU21013_Y1_POS_MSB_REG 0x75 | ||
33 | #define BU21013_Y1_POS_LSB_REG 0x76 | ||
34 | #define BU21013_X2_POS_MSB_REG 0x77 | ||
35 | #define BU21013_X2_POS_LSB_REG 0x78 | ||
36 | #define BU21013_Y2_POS_MSB_REG 0x79 | ||
37 | #define BU21013_Y2_POS_LSB_REG 0x7A | ||
38 | #define BU21013_INT_CLR_REG 0xE8 | ||
39 | #define BU21013_INT_MODE_REG 0xE9 | ||
40 | #define BU21013_GAIN_REG 0xEA | ||
41 | #define BU21013_OFFSET_MODE_REG 0xEB | ||
42 | #define BU21013_XY_EDGE_REG 0xEC | ||
43 | #define BU21013_RESET_REG 0xED | ||
44 | #define BU21013_CALIB_REG 0xEE | ||
45 | #define BU21013_DONE_REG 0xEF | ||
46 | #define BU21013_SENSOR_0_7_REG 0xF0 | ||
47 | #define BU21013_SENSOR_8_15_REG 0xF1 | ||
48 | #define BU21013_SENSOR_16_23_REG 0xF2 | ||
49 | #define BU21013_POS_MODE1_REG 0xF3 | ||
50 | #define BU21013_POS_MODE2_REG 0xF4 | ||
51 | #define BU21013_CLK_MODE_REG 0xF5 | ||
52 | #define BU21013_IDLE_REG 0xFA | ||
53 | #define BU21013_FILTER_REG 0xFB | ||
54 | #define BU21013_TH_ON_REG 0xFC | ||
55 | #define BU21013_TH_OFF_REG 0xFD | ||
56 | |||
57 | |||
58 | #define BU21013_RESET_ENABLE 0x01 | ||
59 | |||
60 | #define BU21013_SENSORS_EN_0_7 0x3F | ||
61 | #define BU21013_SENSORS_EN_8_15 0xFC | ||
62 | #define BU21013_SENSORS_EN_16_23 0x1F | ||
63 | |||
64 | #define BU21013_POS_MODE1_0 0x02 | ||
65 | #define BU21013_POS_MODE1_1 0x04 | ||
66 | #define BU21013_POS_MODE1_2 0x08 | ||
67 | |||
68 | #define BU21013_POS_MODE2_ZERO 0x01 | ||
69 | #define BU21013_POS_MODE2_AVG1 0x02 | ||
70 | #define BU21013_POS_MODE2_AVG2 0x04 | ||
71 | #define BU21013_POS_MODE2_EN_XY 0x08 | ||
72 | #define BU21013_POS_MODE2_EN_RAW 0x10 | ||
73 | #define BU21013_POS_MODE2_MULTI 0x80 | ||
74 | |||
75 | #define BU21013_CLK_MODE_DIV 0x01 | ||
76 | #define BU21013_CLK_MODE_EXT 0x02 | ||
77 | #define BU21013_CLK_MODE_CALIB 0x80 | ||
78 | |||
79 | #define BU21013_IDLET_0 0x01 | ||
80 | #define BU21013_IDLET_1 0x02 | ||
81 | #define BU21013_IDLET_2 0x04 | ||
82 | #define BU21013_IDLET_3 0x08 | ||
83 | #define BU21013_IDLE_INTERMIT_EN 0x10 | ||
84 | |||
85 | #define BU21013_DELTA_0_6 0x7F | ||
86 | #define BU21013_FILTER_EN 0x80 | ||
87 | |||
88 | #define BU21013_INT_MODE_LEVEL 0x00 | ||
89 | #define BU21013_INT_MODE_EDGE 0x01 | ||
90 | |||
91 | #define BU21013_GAIN_0 0x01 | ||
92 | #define BU21013_GAIN_1 0x02 | ||
93 | #define BU21013_GAIN_2 0x04 | ||
94 | |||
95 | #define BU21013_OFFSET_MODE_DEFAULT 0x00 | ||
96 | #define BU21013_OFFSET_MODE_MOVE 0x01 | ||
97 | #define BU21013_OFFSET_MODE_DISABLE 0x02 | ||
98 | |||
99 | #define BU21013_TH_ON_0 0x01 | ||
100 | #define BU21013_TH_ON_1 0x02 | ||
101 | #define BU21013_TH_ON_2 0x04 | ||
102 | #define BU21013_TH_ON_3 0x08 | ||
103 | #define BU21013_TH_ON_4 0x10 | ||
104 | #define BU21013_TH_ON_5 0x20 | ||
105 | #define BU21013_TH_ON_6 0x40 | ||
106 | #define BU21013_TH_ON_7 0x80 | ||
107 | #define BU21013_TH_ON_MAX 0xFF | ||
108 | |||
109 | #define BU21013_TH_OFF_0 0x01 | ||
110 | #define BU21013_TH_OFF_1 0x02 | ||
111 | #define BU21013_TH_OFF_2 0x04 | ||
112 | #define BU21013_TH_OFF_3 0x08 | ||
113 | #define BU21013_TH_OFF_4 0x10 | ||
114 | #define BU21013_TH_OFF_5 0x20 | ||
115 | #define BU21013_TH_OFF_6 0x40 | ||
116 | #define BU21013_TH_OFF_7 0x80 | ||
117 | #define BU21013_TH_OFF_MAX 0xFF | ||
118 | |||
119 | #define BU21013_X_EDGE_0 0x01 | ||
120 | #define BU21013_X_EDGE_1 0x02 | ||
121 | #define BU21013_X_EDGE_2 0x04 | ||
122 | #define BU21013_X_EDGE_3 0x08 | ||
123 | #define BU21013_Y_EDGE_0 0x10 | ||
124 | #define BU21013_Y_EDGE_1 0x20 | ||
125 | #define BU21013_Y_EDGE_2 0x40 | ||
126 | #define BU21013_Y_EDGE_3 0x80 | ||
127 | |||
128 | #define BU21013_DONE 0x01 | ||
129 | #define BU21013_NUMBER_OF_X_SENSORS (6) | ||
130 | #define BU21013_NUMBER_OF_Y_SENSORS (11) | ||
131 | |||
132 | #define DRIVER_TP "bu21013_tp" | ||
133 | |||
134 | /** | ||
135 | * struct bu21013_ts_data - touch panel data structure | ||
136 | * @client: pointer to the i2c client | ||
137 | * @wait: variable to wait_queue_head_t structure | ||
138 | * @touch_stopped: touch stop flag | ||
139 | * @chip: pointer to the touch panel controller | ||
140 | * @in_dev: pointer to the input device structure | ||
141 | * @intr_pin: interrupt pin value | ||
142 | * | ||
143 | * Touch panel device data structure | ||
144 | */ | ||
145 | struct bu21013_ts_data { | ||
146 | struct i2c_client *client; | ||
147 | wait_queue_head_t wait; | ||
148 | bool touch_stopped; | ||
149 | const struct bu21013_platform_device *chip; | ||
150 | struct input_dev *in_dev; | ||
151 | unsigned int intr_pin; | ||
152 | }; | ||
153 | |||
154 | /** | ||
155 | * bu21013_read_block_data(): read the touch co-ordinates | ||
156 | * @data: bu21013_ts_data structure pointer | ||
157 | * @buf: byte pointer | ||
158 | * | ||
159 | * Read the touch co-ordinates using i2c read block into buffer | ||
160 | * and returns integer. | ||
161 | */ | ||
162 | static int bu21013_read_block_data(struct bu21013_ts_data *data, u8 *buf) | ||
163 | { | ||
164 | int ret, i; | ||
165 | |||
166 | for (i = 0; i < I2C_RETRY_COUNT; i++) { | ||
167 | ret = i2c_smbus_read_i2c_block_data | ||
168 | (data->client, BU21013_SENSORS_BTN_0_7_REG, | ||
169 | LENGTH_OF_BUFFER, buf); | ||
170 | if (ret == LENGTH_OF_BUFFER) | ||
171 | return 0; | ||
172 | } | ||
173 | return -EINVAL; | ||
174 | } | ||
175 | |||
176 | /** | ||
177 | * bu21013_do_touch_report(): Get the touch co-ordinates | ||
178 | * @data: bu21013_ts_data structure pointer | ||
179 | * | ||
180 | * Get the touch co-ordinates from touch sensor registers and writes | ||
181 | * into device structure and returns integer. | ||
182 | */ | ||
183 | static int bu21013_do_touch_report(struct bu21013_ts_data *data) | ||
184 | { | ||
185 | u8 buf[LENGTH_OF_BUFFER]; | ||
186 | unsigned int pos_x[2], pos_y[2]; | ||
187 | bool has_x_sensors, has_y_sensors; | ||
188 | int finger_down_count = 0; | ||
189 | int i; | ||
190 | |||
191 | if (data == NULL) | ||
192 | return -EINVAL; | ||
193 | |||
194 | if (bu21013_read_block_data(data, buf) < 0) | ||
195 | return -EINVAL; | ||
196 | |||
197 | has_x_sensors = hweight32(buf[0] & BU21013_SENSORS_EN_0_7); | ||
198 | has_y_sensors = hweight32(((buf[1] & BU21013_SENSORS_EN_8_15) | | ||
199 | ((buf[2] & BU21013_SENSORS_EN_16_23) << SHIFT_8)) >> SHIFT_2); | ||
200 | if (!has_x_sensors || !has_y_sensors) | ||
201 | return 0; | ||
202 | |||
203 | for (i = 0; i < MAX_FINGERS; i++) { | ||
204 | const u8 *p = &buf[4 * i + 3]; | ||
205 | unsigned int x = p[0] << SHIFT_2 | (p[1] & MASK_BITS); | ||
206 | unsigned int y = p[2] << SHIFT_2 | (p[3] & MASK_BITS); | ||
207 | if (x == 0 || y == 0) | ||
208 | continue; | ||
209 | pos_x[finger_down_count] = x; | ||
210 | pos_y[finger_down_count] = y; | ||
211 | finger_down_count++; | ||
212 | } | ||
213 | |||
214 | if (finger_down_count) { | ||
215 | if (finger_down_count == 2 && | ||
216 | (abs(pos_x[0] - pos_x[1]) < DELTA_MIN || | ||
217 | abs(pos_y[0] - pos_y[1]) < DELTA_MIN)) { | ||
218 | return 0; | ||
219 | } | ||
220 | |||
221 | for (i = 0; i < finger_down_count; i++) { | ||
222 | if (data->chip->x_flip) | ||
223 | pos_x[i] = data->chip->touch_x_max - pos_x[i]; | ||
224 | if (data->chip->y_flip) | ||
225 | pos_y[i] = data->chip->touch_y_max - pos_y[i]; | ||
226 | |||
227 | input_report_abs(data->in_dev, | ||
228 | ABS_MT_POSITION_X, pos_x[i]); | ||
229 | input_report_abs(data->in_dev, | ||
230 | ABS_MT_POSITION_Y, pos_y[i]); | ||
231 | input_mt_sync(data->in_dev); | ||
232 | } | ||
233 | } else | ||
234 | input_mt_sync(data->in_dev); | ||
235 | |||
236 | input_sync(data->in_dev); | ||
237 | |||
238 | return 0; | ||
239 | } | ||
240 | /** | ||
241 | * bu21013_gpio_irq() - gpio thread function for touch interrupt | ||
242 | * @irq: irq value | ||
243 | * @device_data: void pointer | ||
244 | * | ||
245 | * This gpio thread function for touch interrupt | ||
246 | * and returns irqreturn_t. | ||
247 | */ | ||
248 | static irqreturn_t bu21013_gpio_irq(int irq, void *device_data) | ||
249 | { | ||
250 | struct bu21013_ts_data *data = device_data; | ||
251 | struct i2c_client *i2c = data->client; | ||
252 | int retval; | ||
253 | |||
254 | do { | ||
255 | retval = bu21013_do_touch_report(data); | ||
256 | if (retval < 0) { | ||
257 | dev_err(&i2c->dev, "bu21013_do_touch_report failed\n"); | ||
258 | return IRQ_NONE; | ||
259 | } | ||
260 | |||
261 | data->intr_pin = data->chip->irq_read_val(); | ||
262 | if (data->intr_pin == PEN_DOWN_INTR) | ||
263 | wait_event_timeout(data->wait, data->touch_stopped, | ||
264 | msecs_to_jiffies(2)); | ||
265 | } while (!data->intr_pin && !data->touch_stopped); | ||
266 | |||
267 | return IRQ_HANDLED; | ||
268 | } | ||
269 | |||
270 | /** | ||
271 | * bu21013_init_chip() - power on sequence for the bu21013 controller | ||
272 | * @data: device structure pointer | ||
273 | * | ||
274 | * This function is used to power on | ||
275 | * the bu21013 controller and returns integer. | ||
276 | */ | ||
277 | static int bu21013_init_chip(struct bu21013_ts_data *data) | ||
278 | { | ||
279 | int retval; | ||
280 | struct i2c_client *i2c = data->client; | ||
281 | |||
282 | retval = i2c_smbus_write_byte_data(i2c, BU21013_RESET_REG, | ||
283 | BU21013_RESET_ENABLE); | ||
284 | if (retval < 0) { | ||
285 | dev_err(&i2c->dev, "BU21013_RESET reg write failed\n"); | ||
286 | return retval; | ||
287 | } | ||
288 | msleep(RESET_DELAY); | ||
289 | |||
290 | retval = i2c_smbus_write_byte_data(i2c, BU21013_SENSOR_0_7_REG, | ||
291 | BU21013_SENSORS_EN_0_7); | ||
292 | if (retval < 0) { | ||
293 | dev_err(&i2c->dev, "BU21013_SENSOR_0_7 reg write failed\n"); | ||
294 | return retval; | ||
295 | } | ||
296 | |||
297 | retval = i2c_smbus_write_byte_data(i2c, BU21013_SENSOR_8_15_REG, | ||
298 | BU21013_SENSORS_EN_8_15); | ||
299 | if (retval < 0) { | ||
300 | dev_err(&i2c->dev, "BU21013_SENSOR_8_15 reg write failed\n"); | ||
301 | return retval; | ||
302 | } | ||
303 | |||
304 | retval = i2c_smbus_write_byte_data(i2c, BU21013_SENSOR_16_23_REG, | ||
305 | BU21013_SENSORS_EN_16_23); | ||
306 | if (retval < 0) { | ||
307 | dev_err(&i2c->dev, "BU21013_SENSOR_16_23 reg write failed\n"); | ||
308 | return retval; | ||
309 | } | ||
310 | |||
311 | retval = i2c_smbus_write_byte_data(i2c, BU21013_POS_MODE1_REG, | ||
312 | (BU21013_POS_MODE1_0 | BU21013_POS_MODE1_1)); | ||
313 | if (retval < 0) { | ||
314 | dev_err(&i2c->dev, "BU21013_POS_MODE1 reg write failed\n"); | ||
315 | return retval; | ||
316 | } | ||
317 | |||
318 | retval = i2c_smbus_write_byte_data(i2c, BU21013_POS_MODE2_REG, | ||
319 | (BU21013_POS_MODE2_ZERO | BU21013_POS_MODE2_AVG1 | | ||
320 | BU21013_POS_MODE2_AVG2 | BU21013_POS_MODE2_EN_RAW | | ||
321 | BU21013_POS_MODE2_MULTI)); | ||
322 | if (retval < 0) { | ||
323 | dev_err(&i2c->dev, "BU21013_POS_MODE2 reg write failed\n"); | ||
324 | return retval; | ||
325 | } | ||
326 | |||
327 | if (data->chip->ext_clk) | ||
328 | retval = i2c_smbus_write_byte_data(i2c, BU21013_CLK_MODE_REG, | ||
329 | (BU21013_CLK_MODE_EXT | BU21013_CLK_MODE_CALIB)); | ||
330 | else | ||
331 | retval = i2c_smbus_write_byte_data(i2c, BU21013_CLK_MODE_REG, | ||
332 | (BU21013_CLK_MODE_DIV | BU21013_CLK_MODE_CALIB)); | ||
333 | if (retval < 0) { | ||
334 | dev_err(&i2c->dev, "BU21013_CLK_MODE reg write failed\n"); | ||
335 | return retval; | ||
336 | } | ||
337 | |||
338 | retval = i2c_smbus_write_byte_data(i2c, BU21013_IDLE_REG, | ||
339 | (BU21013_IDLET_0 | BU21013_IDLE_INTERMIT_EN)); | ||
340 | if (retval < 0) { | ||
341 | dev_err(&i2c->dev, "BU21013_IDLE reg write failed\n"); | ||
342 | return retval; | ||
343 | } | ||
344 | |||
345 | retval = i2c_smbus_write_byte_data(i2c, BU21013_INT_MODE_REG, | ||
346 | BU21013_INT_MODE_LEVEL); | ||
347 | if (retval < 0) { | ||
348 | dev_err(&i2c->dev, "BU21013_INT_MODE reg write failed\n"); | ||
349 | return retval; | ||
350 | } | ||
351 | |||
352 | retval = i2c_smbus_write_byte_data(i2c, BU21013_FILTER_REG, | ||
353 | (BU21013_DELTA_0_6 | | ||
354 | BU21013_FILTER_EN)); | ||
355 | if (retval < 0) { | ||
356 | dev_err(&i2c->dev, "BU21013_FILTER reg write failed\n"); | ||
357 | return retval; | ||
358 | } | ||
359 | |||
360 | retval = i2c_smbus_write_byte_data(i2c, BU21013_TH_ON_REG, | ||
361 | BU21013_TH_ON_5); | ||
362 | if (retval < 0) { | ||
363 | dev_err(&i2c->dev, "BU21013_TH_ON reg write failed\n"); | ||
364 | return retval; | ||
365 | } | ||
366 | |||
367 | retval = i2c_smbus_write_byte_data(i2c, BU21013_TH_OFF_REG, | ||
368 | BU21013_TH_OFF_4 || BU21013_TH_OFF_3); | ||
369 | if (retval < 0) { | ||
370 | dev_err(&i2c->dev, "BU21013_TH_OFF reg write failed\n"); | ||
371 | return retval; | ||
372 | } | ||
373 | |||
374 | retval = i2c_smbus_write_byte_data(i2c, BU21013_GAIN_REG, | ||
375 | (BU21013_GAIN_0 | BU21013_GAIN_1)); | ||
376 | if (retval < 0) { | ||
377 | dev_err(&i2c->dev, "BU21013_GAIN reg write failed\n"); | ||
378 | return retval; | ||
379 | } | ||
380 | |||
381 | retval = i2c_smbus_write_byte_data(i2c, BU21013_OFFSET_MODE_REG, | ||
382 | BU21013_OFFSET_MODE_DEFAULT); | ||
383 | if (retval < 0) { | ||
384 | dev_err(&i2c->dev, "BU21013_OFFSET_MODE reg write failed\n"); | ||
385 | return retval; | ||
386 | } | ||
387 | |||
388 | retval = i2c_smbus_write_byte_data(i2c, BU21013_XY_EDGE_REG, | ||
389 | (BU21013_X_EDGE_0 | BU21013_X_EDGE_2 | | ||
390 | BU21013_Y_EDGE_1 | BU21013_Y_EDGE_3)); | ||
391 | if (retval < 0) { | ||
392 | dev_err(&i2c->dev, "BU21013_XY_EDGE reg write failed\n"); | ||
393 | return retval; | ||
394 | } | ||
395 | |||
396 | retval = i2c_smbus_write_byte_data(i2c, BU21013_DONE_REG, | ||
397 | BU21013_DONE); | ||
398 | if (retval < 0) { | ||
399 | dev_err(&i2c->dev, "BU21013_REG_DONE reg write failed\n"); | ||
400 | return retval; | ||
401 | } | ||
402 | |||
403 | return 0; | ||
404 | } | ||
405 | |||
406 | /** | ||
407 | * bu21013_free_irq() - frees IRQ registered for touchscreen | ||
408 | * @bu21013_data: device structure pointer | ||
409 | * | ||
410 | * This function signals interrupt thread to stop processing and | ||
411 | * frees interrupt. | ||
412 | */ | ||
413 | static void bu21013_free_irq(struct bu21013_ts_data *bu21013_data) | ||
414 | { | ||
415 | bu21013_data->touch_stopped = true; | ||
416 | wake_up(&bu21013_data->wait); | ||
417 | free_irq(bu21013_data->chip->irq, bu21013_data); | ||
418 | } | ||
419 | |||
420 | /** | ||
421 | * bu21013_probe() - initializes the i2c-client touchscreen driver | ||
422 | * @client: i2c client structure pointer | ||
423 | * @id: i2c device id pointer | ||
424 | * | ||
425 | * This function used to initializes the i2c-client touchscreen | ||
426 | * driver and returns integer. | ||
427 | */ | ||
428 | static int __devinit bu21013_probe(struct i2c_client *client, | ||
429 | const struct i2c_device_id *id) | ||
430 | { | ||
431 | struct bu21013_ts_data *bu21013_data; | ||
432 | struct input_dev *in_dev; | ||
433 | const struct bu21013_platform_device *pdata = | ||
434 | client->dev.platform_data; | ||
435 | int error; | ||
436 | |||
437 | if (!i2c_check_functionality(client->adapter, | ||
438 | I2C_FUNC_SMBUS_BYTE_DATA)) { | ||
439 | dev_err(&client->dev, "i2c smbus byte data not supported\n"); | ||
440 | return -EIO; | ||
441 | } | ||
442 | |||
443 | if (!pdata) { | ||
444 | dev_err(&client->dev, "platform data not defined\n"); | ||
445 | return -EINVAL; | ||
446 | } | ||
447 | |||
448 | bu21013_data = kzalloc(sizeof(struct bu21013_ts_data), GFP_KERNEL); | ||
449 | in_dev = input_allocate_device(); | ||
450 | if (!bu21013_data || !in_dev) { | ||
451 | dev_err(&client->dev, "device memory alloc failed\n"); | ||
452 | error = -ENOMEM; | ||
453 | goto err_free_mem; | ||
454 | } | ||
455 | |||
456 | bu21013_data->in_dev = in_dev; | ||
457 | bu21013_data->chip = pdata; | ||
458 | bu21013_data->client = client; | ||
459 | bu21013_data->touch_stopped = false; | ||
460 | init_waitqueue_head(&bu21013_data->wait); | ||
461 | |||
462 | /* configure the gpio pins */ | ||
463 | if (pdata->cs_en) { | ||
464 | error = pdata->cs_en(pdata->cs_pin); | ||
465 | if (error < 0) { | ||
466 | dev_err(&client->dev, "chip init failed\n"); | ||
467 | goto err_free_mem; | ||
468 | } | ||
469 | } | ||
470 | |||
471 | /* configure the touch panel controller */ | ||
472 | error = bu21013_init_chip(bu21013_data); | ||
473 | if (error) { | ||
474 | dev_err(&client->dev, "error in bu21013 config\n"); | ||
475 | goto err_cs_disable; | ||
476 | } | ||
477 | |||
478 | /* register the device to input subsystem */ | ||
479 | in_dev->name = DRIVER_TP; | ||
480 | in_dev->id.bustype = BUS_I2C; | ||
481 | in_dev->dev.parent = &client->dev; | ||
482 | |||
483 | __set_bit(EV_SYN, in_dev->evbit); | ||
484 | __set_bit(EV_KEY, in_dev->evbit); | ||
485 | __set_bit(EV_ABS, in_dev->evbit); | ||
486 | |||
487 | input_set_abs_params(in_dev, ABS_MT_POSITION_X, 0, | ||
488 | pdata->x_max_res, 0, 0); | ||
489 | input_set_abs_params(in_dev, ABS_MT_POSITION_Y, 0, | ||
490 | pdata->y_max_res, 0, 0); | ||
491 | input_set_drvdata(in_dev, bu21013_data); | ||
492 | |||
493 | error = request_threaded_irq(pdata->irq, NULL, bu21013_gpio_irq, | ||
494 | IRQF_TRIGGER_FALLING | IRQF_SHARED, | ||
495 | DRIVER_TP, bu21013_data); | ||
496 | if (error) { | ||
497 | dev_err(&client->dev, "request irq %d failed\n", pdata->irq); | ||
498 | goto err_cs_disable; | ||
499 | } | ||
500 | |||
501 | error = input_register_device(in_dev); | ||
502 | if (error) { | ||
503 | dev_err(&client->dev, "failed to register input device\n"); | ||
504 | goto err_free_irq; | ||
505 | } | ||
506 | |||
507 | device_init_wakeup(&client->dev, pdata->wakeup); | ||
508 | i2c_set_clientdata(client, bu21013_data); | ||
509 | |||
510 | return 0; | ||
511 | |||
512 | err_free_irq: | ||
513 | bu21013_free_irq(bu21013_data); | ||
514 | err_cs_disable: | ||
515 | pdata->cs_dis(pdata->cs_pin); | ||
516 | err_free_mem: | ||
517 | input_free_device(bu21013_data->in_dev); | ||
518 | kfree(bu21013_data); | ||
519 | |||
520 | return error; | ||
521 | } | ||
522 | /** | ||
523 | * bu21013_remove() - removes the i2c-client touchscreen driver | ||
524 | * @client: i2c client structure pointer | ||
525 | * | ||
526 | * This function uses to remove the i2c-client | ||
527 | * touchscreen driver and returns integer. | ||
528 | */ | ||
529 | static int __devexit bu21013_remove(struct i2c_client *client) | ||
530 | { | ||
531 | struct bu21013_ts_data *bu21013_data = i2c_get_clientdata(client); | ||
532 | |||
533 | bu21013_free_irq(bu21013_data); | ||
534 | |||
535 | bu21013_data->chip->cs_dis(bu21013_data->chip->cs_pin); | ||
536 | |||
537 | input_unregister_device(bu21013_data->in_dev); | ||
538 | kfree(bu21013_data); | ||
539 | |||
540 | device_init_wakeup(&client->dev, false); | ||
541 | |||
542 | return 0; | ||
543 | } | ||
544 | |||
545 | #ifdef CONFIG_PM | ||
546 | /** | ||
547 | * bu21013_suspend() - suspend the touch screen controller | ||
548 | * @dev: pointer to device structure | ||
549 | * | ||
550 | * This function is used to suspend the | ||
551 | * touch panel controller and returns integer | ||
552 | */ | ||
553 | static int bu21013_suspend(struct device *dev) | ||
554 | { | ||
555 | struct bu21013_ts_data *bu21013_data = dev_get_drvdata(dev); | ||
556 | struct i2c_client *client = bu21013_data->client; | ||
557 | |||
558 | bu21013_data->touch_stopped = true; | ||
559 | if (device_may_wakeup(&client->dev)) | ||
560 | enable_irq_wake(bu21013_data->chip->irq); | ||
561 | else | ||
562 | disable_irq(bu21013_data->chip->irq); | ||
563 | |||
564 | return 0; | ||
565 | } | ||
566 | |||
567 | /** | ||
568 | * bu21013_resume() - resume the touch screen controller | ||
569 | * @dev: pointer to device structure | ||
570 | * | ||
571 | * This function is used to resume the touch panel | ||
572 | * controller and returns integer. | ||
573 | */ | ||
574 | static int bu21013_resume(struct device *dev) | ||
575 | { | ||
576 | struct bu21013_ts_data *bu21013_data = dev_get_drvdata(dev); | ||
577 | struct i2c_client *client = bu21013_data->client; | ||
578 | int retval; | ||
579 | |||
580 | retval = bu21013_init_chip(bu21013_data); | ||
581 | if (retval < 0) { | ||
582 | dev_err(&client->dev, "bu21013 controller config failed\n"); | ||
583 | return retval; | ||
584 | } | ||
585 | |||
586 | bu21013_data->touch_stopped = false; | ||
587 | |||
588 | if (device_may_wakeup(&client->dev)) | ||
589 | disable_irq_wake(bu21013_data->chip->irq); | ||
590 | else | ||
591 | enable_irq(bu21013_data->chip->irq); | ||
592 | |||
593 | return 0; | ||
594 | } | ||
595 | |||
596 | static const struct dev_pm_ops bu21013_dev_pm_ops = { | ||
597 | .suspend = bu21013_suspend, | ||
598 | .resume = bu21013_resume, | ||
599 | }; | ||
600 | #endif | ||
601 | |||
602 | static const struct i2c_device_id bu21013_id[] = { | ||
603 | { DRIVER_TP, 0 }, | ||
604 | { } | ||
605 | }; | ||
606 | MODULE_DEVICE_TABLE(i2c, bu21013_id); | ||
607 | |||
608 | static struct i2c_driver bu21013_driver = { | ||
609 | .driver = { | ||
610 | .name = DRIVER_TP, | ||
611 | .owner = THIS_MODULE, | ||
612 | #ifdef CONFIG_PM | ||
613 | .pm = &bu21013_dev_pm_ops, | ||
614 | #endif | ||
615 | }, | ||
616 | .probe = bu21013_probe, | ||
617 | .remove = __devexit_p(bu21013_remove), | ||
618 | .id_table = bu21013_id, | ||
619 | }; | ||
620 | |||
621 | /** | ||
622 | * bu21013_init() - initializes the bu21013 touchscreen driver | ||
623 | * | ||
624 | * This function used to initializes the bu21013 | ||
625 | * touchscreen driver and returns integer. | ||
626 | */ | ||
627 | static int __init bu21013_init(void) | ||
628 | { | ||
629 | return i2c_add_driver(&bu21013_driver); | ||
630 | } | ||
631 | |||
632 | /** | ||
633 | * bu21013_exit() - de-initializes the bu21013 touchscreen driver | ||
634 | * | ||
635 | * This function uses to de-initializes the bu21013 | ||
636 | * touchscreen driver and returns none. | ||
637 | */ | ||
638 | static void __exit bu21013_exit(void) | ||
639 | { | ||
640 | i2c_del_driver(&bu21013_driver); | ||
641 | } | ||
642 | |||
643 | module_init(bu21013_init); | ||
644 | module_exit(bu21013_exit); | ||
645 | |||
646 | MODULE_LICENSE("GPL v2"); | ||
647 | MODULE_AUTHOR("Naveen Kumar G <naveen.gaddipati@stericsson.com>"); | ||
648 | MODULE_DESCRIPTION("bu21013 touch screen controller driver"); | ||
diff --git a/include/linux/input/bu21013.h b/include/linux/input/bu21013.h new file mode 100644 index 000000000000..e470d387dd49 --- /dev/null +++ b/include/linux/input/bu21013.h | |||
@@ -0,0 +1,44 @@ | |||
1 | /* | ||
2 | * Copyright (C) ST-Ericsson SA 2010 | ||
3 | * Author: Naveen Kumar G <naveen.gaddipati@stericsson.com> for ST-Ericsson | ||
4 | * License terms:GNU General Public License (GPL) version 2 | ||
5 | */ | ||
6 | |||
7 | #ifndef _BU21013_H | ||
8 | #define _BU21013_H | ||
9 | |||
10 | /** | ||
11 | * struct bu21013_platform_device - Handle the platform data | ||
12 | * @cs_en: pointer to the cs enable function | ||
13 | * @cs_dis: pointer to the cs disable function | ||
14 | * @irq_read_val: pointer to read the pen irq value function | ||
15 | * @x_max_res: xmax resolution | ||
16 | * @y_max_res: ymax resolution | ||
17 | * @touch_x_max: touch x max | ||
18 | * @touch_y_max: touch y max | ||
19 | * @cs_pin: chip select pin | ||
20 | * @irq: irq pin | ||
21 | * @ext_clk: external clock flag | ||
22 | * @x_flip: x flip flag | ||
23 | * @y_flip: y flip flag | ||
24 | * @wakeup: wakeup flag | ||
25 | * | ||
26 | * This is used to handle the platform data | ||
27 | */ | ||
28 | struct bu21013_platform_device { | ||
29 | int (*cs_en)(int reset_pin); | ||
30 | int (*cs_dis)(int reset_pin); | ||
31 | int (*irq_read_val)(void); | ||
32 | int x_max_res; | ||
33 | int y_max_res; | ||
34 | int touch_x_max; | ||
35 | int touch_y_max; | ||
36 | unsigned int cs_pin; | ||
37 | unsigned int irq; | ||
38 | bool ext_clk; | ||
39 | bool x_flip; | ||
40 | bool y_flip; | ||
41 | bool wakeup; | ||
42 | }; | ||
43 | |||
44 | #endif | ||