diff options
author | Hemanth V <hemanthv@ti.com> | 2010-12-01 02:03:54 -0500 |
---|---|---|
committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2010-12-01 02:05:21 -0500 |
commit | b029ffafe89cf4b97cf39e0225a5205cbbf9e02f (patch) | |
tree | 3f5b9074c4b9b4cf35d930f057ed6a73559e1e0c /drivers/input | |
parent | 33e808c383477e821163f133c2e3e671879c28b6 (diff) |
Input: add CMA3000 accelerometer driver
Add support for CMA3000 Tri-axis accelerometer, which supports Motion
detect, Measurement and Free fall modes. CMA3000 supports both I2C/SPI
bus for communication, currently the driver supports I2C based
communication.
Signed-off-by: Hemanth V <hemanthv@ti.com>
Reviewed-by: Jonathan Cameron <jic23@cam.ac.uk>
Reviewed-by: Sergio Aguirre <saaguirre@ti.com>
Reviewed-by: Shubhrajyoti <Shubhrajyoti@ti.com>
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
Diffstat (limited to 'drivers/input')
-rw-r--r-- | drivers/input/misc/Kconfig | 24 | ||||
-rw-r--r-- | drivers/input/misc/Makefile | 2 | ||||
-rw-r--r-- | drivers/input/misc/cma3000_d0x.c | 398 | ||||
-rw-r--r-- | drivers/input/misc/cma3000_d0x.h | 42 | ||||
-rw-r--r-- | drivers/input/misc/cma3000_d0x_i2c.c | 141 |
5 files changed, 607 insertions, 0 deletions
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index b99b8cbde02f..f0d90172a65f 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig | |||
@@ -448,4 +448,28 @@ config INPUT_ADXL34X_SPI | |||
448 | To compile this driver as a module, choose M here: the | 448 | To compile this driver as a module, choose M here: the |
449 | module will be called adxl34x-spi. | 449 | module will be called adxl34x-spi. |
450 | 450 | ||
451 | config INPUT_CMA3000 | ||
452 | tristate "VTI CMA3000 Tri-axis accelerometer" | ||
453 | help | ||
454 | Say Y here if you want to use VTI CMA3000_D0x Accelerometer | ||
455 | driver | ||
456 | |||
457 | This driver currently only supports I2C interface to the | ||
458 | controller. Also select the I2C method. | ||
459 | |||
460 | If unsure, say N | ||
461 | |||
462 | To compile this driver as a module, choose M here: the | ||
463 | module will be called cma3000_d0x. | ||
464 | |||
465 | config INPUT_CMA3000_I2C | ||
466 | tristate "Support I2C bus connection" | ||
467 | depends on INPUT_CMA3000 && I2C | ||
468 | help | ||
469 | Say Y here if you want to use VTI CMA3000_D0x Accelerometer | ||
470 | through I2C interface. | ||
471 | |||
472 | To compile this driver as a module, choose M here: the | ||
473 | module will be called cma3000_d0x_i2c. | ||
474 | |||
451 | endif | 475 | endif |
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index 1fe1f6c8b737..35bcfe46555e 100644 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile | |||
@@ -18,6 +18,8 @@ obj-$(CONFIG_INPUT_ATI_REMOTE2) += ati_remote2.o | |||
18 | obj-$(CONFIG_INPUT_ATLAS_BTNS) += atlas_btns.o | 18 | obj-$(CONFIG_INPUT_ATLAS_BTNS) += atlas_btns.o |
19 | obj-$(CONFIG_INPUT_BFIN_ROTARY) += bfin_rotary.o | 19 | obj-$(CONFIG_INPUT_BFIN_ROTARY) += bfin_rotary.o |
20 | obj-$(CONFIG_INPUT_CM109) += cm109.o | 20 | obj-$(CONFIG_INPUT_CM109) += cm109.o |
21 | obj-$(CONFIG_INPUT_CMA3000) += cma3000_d0x.o | ||
22 | obj-$(CONFIG_INPUT_CMA3000_I2C) += cma3000_d0x_i2c.o | ||
21 | obj-$(CONFIG_INPUT_COBALT_BTNS) += cobalt_btns.o | 23 | obj-$(CONFIG_INPUT_COBALT_BTNS) += cobalt_btns.o |
22 | obj-$(CONFIG_INPUT_DM355EVM) += dm355evm_keys.o | 24 | obj-$(CONFIG_INPUT_DM355EVM) += dm355evm_keys.o |
23 | obj-$(CONFIG_HP_SDC_RTC) += hp_sdc_rtc.o | 25 | obj-$(CONFIG_HP_SDC_RTC) += hp_sdc_rtc.o |
diff --git a/drivers/input/misc/cma3000_d0x.c b/drivers/input/misc/cma3000_d0x.c new file mode 100644 index 000000000000..1633b6342267 --- /dev/null +++ b/drivers/input/misc/cma3000_d0x.c | |||
@@ -0,0 +1,398 @@ | |||
1 | /* | ||
2 | * VTI CMA3000_D0x Accelerometer driver | ||
3 | * | ||
4 | * Copyright (C) 2010 Texas Instruments | ||
5 | * Author: Hemanth V <hemanthv@ti.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License version 2 as published by | ||
9 | * the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
14 | * more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License along with | ||
17 | * this program. If not, see <http://www.gnu.org/licenses/>. | ||
18 | */ | ||
19 | |||
20 | #include <linux/types.h> | ||
21 | #include <linux/interrupt.h> | ||
22 | #include <linux/delay.h> | ||
23 | #include <linux/slab.h> | ||
24 | #include <linux/input.h> | ||
25 | #include <linux/input/cma3000.h> | ||
26 | |||
27 | #include "cma3000_d0x.h" | ||
28 | |||
29 | #define CMA3000_WHOAMI 0x00 | ||
30 | #define CMA3000_REVID 0x01 | ||
31 | #define CMA3000_CTRL 0x02 | ||
32 | #define CMA3000_STATUS 0x03 | ||
33 | #define CMA3000_RSTR 0x04 | ||
34 | #define CMA3000_INTSTATUS 0x05 | ||
35 | #define CMA3000_DOUTX 0x06 | ||
36 | #define CMA3000_DOUTY 0x07 | ||
37 | #define CMA3000_DOUTZ 0x08 | ||
38 | #define CMA3000_MDTHR 0x09 | ||
39 | #define CMA3000_MDFFTMR 0x0A | ||
40 | #define CMA3000_FFTHR 0x0B | ||
41 | |||
42 | #define CMA3000_RANGE2G (1 << 7) | ||
43 | #define CMA3000_RANGE8G (0 << 7) | ||
44 | #define CMA3000_BUSI2C (0 << 4) | ||
45 | #define CMA3000_MODEMASK (7 << 1) | ||
46 | #define CMA3000_GRANGEMASK (1 << 7) | ||
47 | |||
48 | #define CMA3000_STATUS_PERR 1 | ||
49 | #define CMA3000_INTSTATUS_FFDET (1 << 2) | ||
50 | |||
51 | /* Settling time delay in ms */ | ||
52 | #define CMA3000_SETDELAY 30 | ||
53 | |||
54 | /* Delay for clearing interrupt in us */ | ||
55 | #define CMA3000_INTDELAY 44 | ||
56 | |||
57 | |||
58 | /* | ||
59 | * Bit weights in mg for bit 0, other bits need | ||
60 | * multipy factor 2^n. Eight bit is the sign bit. | ||
61 | */ | ||
62 | #define BIT_TO_2G 18 | ||
63 | #define BIT_TO_8G 71 | ||
64 | |||
65 | struct cma3000_accl_data { | ||
66 | const struct cma3000_bus_ops *bus_ops; | ||
67 | const struct cma3000_platform_data *pdata; | ||
68 | |||
69 | struct device *dev; | ||
70 | struct input_dev *input_dev; | ||
71 | |||
72 | int bit_to_mg; | ||
73 | int irq; | ||
74 | |||
75 | int g_range; | ||
76 | u8 mode; | ||
77 | |||
78 | struct mutex mutex; | ||
79 | bool opened; | ||
80 | bool suspended; | ||
81 | }; | ||
82 | |||
83 | #define CMA3000_READ(data, reg, msg) \ | ||
84 | (data->bus_ops->read(data->dev, reg, msg)) | ||
85 | #define CMA3000_SET(data, reg, val, msg) \ | ||
86 | ((data)->bus_ops->write(data->dev, reg, val, msg)) | ||
87 | |||
88 | /* | ||
89 | * Conversion for each of the eight modes to g, depending | ||
90 | * on G range i.e 2G or 8G. Some modes always operate in | ||
91 | * 8G. | ||
92 | */ | ||
93 | |||
94 | static int mode_to_mg[8][2] = { | ||
95 | { 0, 0 }, | ||
96 | { BIT_TO_8G, BIT_TO_2G }, | ||
97 | { BIT_TO_8G, BIT_TO_2G }, | ||
98 | { BIT_TO_8G, BIT_TO_8G }, | ||
99 | { BIT_TO_8G, BIT_TO_8G }, | ||
100 | { BIT_TO_8G, BIT_TO_2G }, | ||
101 | { BIT_TO_8G, BIT_TO_2G }, | ||
102 | { 0, 0}, | ||
103 | }; | ||
104 | |||
105 | static void decode_mg(struct cma3000_accl_data *data, int *datax, | ||
106 | int *datay, int *dataz) | ||
107 | { | ||
108 | /* Data in 2's complement, convert to mg */ | ||
109 | *datax = ((s8)*datax) * data->bit_to_mg; | ||
110 | *datay = ((s8)*datay) * data->bit_to_mg; | ||
111 | *dataz = ((s8)*dataz) * data->bit_to_mg; | ||
112 | } | ||
113 | |||
114 | static irqreturn_t cma3000_thread_irq(int irq, void *dev_id) | ||
115 | { | ||
116 | struct cma3000_accl_data *data = dev_id; | ||
117 | int datax, datay, dataz; | ||
118 | u8 ctrl, mode, range, intr_status; | ||
119 | |||
120 | intr_status = CMA3000_READ(data, CMA3000_INTSTATUS, "interrupt status"); | ||
121 | if (intr_status < 0) | ||
122 | return IRQ_NONE; | ||
123 | |||
124 | /* Check if free fall is detected, report immediately */ | ||
125 | if (intr_status & CMA3000_INTSTATUS_FFDET) { | ||
126 | input_report_abs(data->input_dev, ABS_MISC, 1); | ||
127 | input_sync(data->input_dev); | ||
128 | } else { | ||
129 | input_report_abs(data->input_dev, ABS_MISC, 0); | ||
130 | } | ||
131 | |||
132 | datax = CMA3000_READ(data, CMA3000_DOUTX, "X"); | ||
133 | datay = CMA3000_READ(data, CMA3000_DOUTY, "Y"); | ||
134 | dataz = CMA3000_READ(data, CMA3000_DOUTZ, "Z"); | ||
135 | |||
136 | ctrl = CMA3000_READ(data, CMA3000_CTRL, "ctrl"); | ||
137 | mode = (ctrl & CMA3000_MODEMASK) >> 1; | ||
138 | range = (ctrl & CMA3000_GRANGEMASK) >> 7; | ||
139 | |||
140 | data->bit_to_mg = mode_to_mg[mode][range]; | ||
141 | |||
142 | /* Interrupt not for this device */ | ||
143 | if (data->bit_to_mg == 0) | ||
144 | return IRQ_NONE; | ||
145 | |||
146 | /* Decode register values to milli g */ | ||
147 | decode_mg(data, &datax, &datay, &dataz); | ||
148 | |||
149 | input_report_abs(data->input_dev, ABS_X, datax); | ||
150 | input_report_abs(data->input_dev, ABS_Y, datay); | ||
151 | input_report_abs(data->input_dev, ABS_Z, dataz); | ||
152 | input_sync(data->input_dev); | ||
153 | |||
154 | return IRQ_HANDLED; | ||
155 | } | ||
156 | |||
157 | static int cma3000_reset(struct cma3000_accl_data *data) | ||
158 | { | ||
159 | int val; | ||
160 | |||
161 | /* Reset sequence */ | ||
162 | CMA3000_SET(data, CMA3000_RSTR, 0x02, "Reset"); | ||
163 | CMA3000_SET(data, CMA3000_RSTR, 0x0A, "Reset"); | ||
164 | CMA3000_SET(data, CMA3000_RSTR, 0x04, "Reset"); | ||
165 | |||
166 | /* Settling time delay */ | ||
167 | mdelay(10); | ||
168 | |||
169 | val = CMA3000_READ(data, CMA3000_STATUS, "Status"); | ||
170 | if (val < 0) { | ||
171 | dev_err(data->dev, "Reset failed\n"); | ||
172 | return val; | ||
173 | } | ||
174 | |||
175 | if (val & CMA3000_STATUS_PERR) { | ||
176 | dev_err(data->dev, "Parity Error\n"); | ||
177 | return -EIO; | ||
178 | } | ||
179 | |||
180 | return 0; | ||
181 | } | ||
182 | |||
183 | static int cma3000_poweron(struct cma3000_accl_data *data) | ||
184 | { | ||
185 | const struct cma3000_platform_data *pdata = data->pdata; | ||
186 | u8 ctrl = 0; | ||
187 | int ret; | ||
188 | |||
189 | if (data->g_range == CMARANGE_2G) { | ||
190 | ctrl = (data->mode << 1) | CMA3000_RANGE2G; | ||
191 | } else if (data->g_range == CMARANGE_8G) { | ||
192 | ctrl = (data->mode << 1) | CMA3000_RANGE8G; | ||
193 | } else { | ||
194 | dev_info(data->dev, | ||
195 | "Invalid G range specified, assuming 8G\n"); | ||
196 | ctrl = (data->mode << 1) | CMA3000_RANGE8G; | ||
197 | } | ||
198 | |||
199 | ctrl |= data->bus_ops->ctrl_mod; | ||
200 | |||
201 | CMA3000_SET(data, CMA3000_MDTHR, pdata->mdthr, | ||
202 | "Motion Detect Threshold"); | ||
203 | CMA3000_SET(data, CMA3000_MDFFTMR, pdata->mdfftmr, | ||
204 | "Time register"); | ||
205 | CMA3000_SET(data, CMA3000_FFTHR, pdata->ffthr, | ||
206 | "Free fall threshold"); | ||
207 | ret = CMA3000_SET(data, CMA3000_CTRL, ctrl, "Mode setting"); | ||
208 | if (ret < 0) | ||
209 | return -EIO; | ||
210 | |||
211 | msleep(CMA3000_SETDELAY); | ||
212 | |||
213 | return 0; | ||
214 | } | ||
215 | |||
216 | static int cma3000_poweroff(struct cma3000_accl_data *data) | ||
217 | { | ||
218 | int ret; | ||
219 | |||
220 | ret = CMA3000_SET(data, CMA3000_CTRL, CMAMODE_POFF, "Mode setting"); | ||
221 | msleep(CMA3000_SETDELAY); | ||
222 | |||
223 | return ret; | ||
224 | } | ||
225 | |||
226 | static int cma3000_open(struct input_dev *input_dev) | ||
227 | { | ||
228 | struct cma3000_accl_data *data = input_get_drvdata(input_dev); | ||
229 | |||
230 | mutex_lock(&data->mutex); | ||
231 | |||
232 | if (!data->suspended) | ||
233 | cma3000_poweron(data); | ||
234 | |||
235 | data->opened = true; | ||
236 | |||
237 | mutex_unlock(&data->mutex); | ||
238 | |||
239 | return 0; | ||
240 | } | ||
241 | |||
242 | static void cma3000_close(struct input_dev *input_dev) | ||
243 | { | ||
244 | struct cma3000_accl_data *data = input_get_drvdata(input_dev); | ||
245 | |||
246 | mutex_lock(&data->mutex); | ||
247 | |||
248 | if (!data->suspended) | ||
249 | cma3000_poweroff(data); | ||
250 | |||
251 | data->opened = false; | ||
252 | |||
253 | mutex_unlock(&data->mutex); | ||
254 | } | ||
255 | |||
256 | void cma3000_suspend(struct cma3000_accl_data *data) | ||
257 | { | ||
258 | mutex_lock(&data->mutex); | ||
259 | |||
260 | if (!data->suspended && data->opened) | ||
261 | cma3000_poweroff(data); | ||
262 | |||
263 | data->suspended = true; | ||
264 | |||
265 | mutex_unlock(&data->mutex); | ||
266 | } | ||
267 | EXPORT_SYMBOL(cma3000_suspend); | ||
268 | |||
269 | |||
270 | void cma3000_resume(struct cma3000_accl_data *data) | ||
271 | { | ||
272 | mutex_lock(&data->mutex); | ||
273 | |||
274 | if (data->suspended && data->opened) | ||
275 | cma3000_poweron(data); | ||
276 | |||
277 | data->suspended = false; | ||
278 | |||
279 | mutex_unlock(&data->mutex); | ||
280 | } | ||
281 | EXPORT_SYMBOL(cma3000_resume); | ||
282 | |||
283 | struct cma3000_accl_data *cma3000_init(struct device *dev, int irq, | ||
284 | const struct cma3000_bus_ops *bops) | ||
285 | { | ||
286 | const struct cma3000_platform_data *pdata = dev->platform_data; | ||
287 | struct cma3000_accl_data *data; | ||
288 | struct input_dev *input_dev; | ||
289 | int rev; | ||
290 | int error; | ||
291 | |||
292 | if (!pdata) { | ||
293 | dev_err(dev, "platform data not found\n"); | ||
294 | error = -EINVAL; | ||
295 | goto err_out; | ||
296 | } | ||
297 | |||
298 | |||
299 | /* if no IRQ return error */ | ||
300 | if (irq == 0) { | ||
301 | error = -EINVAL; | ||
302 | goto err_out; | ||
303 | } | ||
304 | |||
305 | data = kzalloc(sizeof(struct cma3000_accl_data), GFP_KERNEL); | ||
306 | input_dev = input_allocate_device(); | ||
307 | if (!data || !input_dev) { | ||
308 | error = -ENOMEM; | ||
309 | goto err_free_mem; | ||
310 | } | ||
311 | |||
312 | data->dev = dev; | ||
313 | data->input_dev = input_dev; | ||
314 | data->bus_ops = bops; | ||
315 | data->pdata = pdata; | ||
316 | data->irq = irq; | ||
317 | mutex_init(&data->mutex); | ||
318 | |||
319 | data->mode = pdata->mode; | ||
320 | if (data->mode < CMAMODE_DEFAULT || data->mode > CMAMODE_POFF) { | ||
321 | data->mode = CMAMODE_MOTDET; | ||
322 | dev_warn(dev, | ||
323 | "Invalid mode specified, assuming Motion Detect\n"); | ||
324 | } | ||
325 | |||
326 | data->g_range = pdata->g_range; | ||
327 | if (data->g_range != CMARANGE_2G && data->g_range != CMARANGE_8G) { | ||
328 | dev_info(dev, | ||
329 | "Invalid G range specified, assuming 8G\n"); | ||
330 | data->g_range = CMARANGE_8G; | ||
331 | } | ||
332 | |||
333 | input_dev->name = "cma3000-accelerometer"; | ||
334 | input_dev->id.bustype = bops->bustype; | ||
335 | input_dev->open = cma3000_open; | ||
336 | input_dev->close = cma3000_close; | ||
337 | |||
338 | __set_bit(EV_ABS, input_dev->evbit); | ||
339 | |||
340 | input_set_abs_params(input_dev, ABS_X, | ||
341 | -data->g_range, data->g_range, pdata->fuzz_x, 0); | ||
342 | input_set_abs_params(input_dev, ABS_Y, | ||
343 | -data->g_range, data->g_range, pdata->fuzz_y, 0); | ||
344 | input_set_abs_params(input_dev, ABS_Z, | ||
345 | -data->g_range, data->g_range, pdata->fuzz_z, 0); | ||
346 | input_set_abs_params(input_dev, ABS_MISC, 0, 1, 0, 0); | ||
347 | |||
348 | input_set_drvdata(input_dev, data); | ||
349 | |||
350 | error = cma3000_reset(data); | ||
351 | if (error) | ||
352 | goto err_free_mem; | ||
353 | |||
354 | rev = CMA3000_READ(data, CMA3000_REVID, "Revid"); | ||
355 | if (rev < 0) { | ||
356 | error = rev; | ||
357 | goto err_free_mem; | ||
358 | } | ||
359 | |||
360 | pr_info("CMA3000 Accelerometer: Revision %x\n", rev); | ||
361 | |||
362 | error = request_threaded_irq(irq, NULL, cma3000_thread_irq, | ||
363 | pdata->irqflags | IRQF_ONESHOT, | ||
364 | "cma3000_d0x", data); | ||
365 | if (error) { | ||
366 | dev_err(dev, "request_threaded_irq failed\n"); | ||
367 | goto err_free_mem; | ||
368 | } | ||
369 | |||
370 | error = input_register_device(data->input_dev); | ||
371 | if (error) { | ||
372 | dev_err(dev, "Unable to register input device\n"); | ||
373 | goto err_free_irq; | ||
374 | } | ||
375 | |||
376 | return data; | ||
377 | |||
378 | err_free_irq: | ||
379 | free_irq(irq, data); | ||
380 | err_free_mem: | ||
381 | input_free_device(input_dev); | ||
382 | kfree(data); | ||
383 | err_out: | ||
384 | return ERR_PTR(error); | ||
385 | } | ||
386 | EXPORT_SYMBOL(cma3000_init); | ||
387 | |||
388 | void cma3000_exit(struct cma3000_accl_data *data) | ||
389 | { | ||
390 | free_irq(data->irq, data); | ||
391 | input_unregister_device(data->input_dev); | ||
392 | kfree(data); | ||
393 | } | ||
394 | EXPORT_SYMBOL(cma3000_exit); | ||
395 | |||
396 | MODULE_DESCRIPTION("CMA3000-D0x Accelerometer Driver"); | ||
397 | MODULE_LICENSE("GPL"); | ||
398 | MODULE_AUTHOR("Hemanth V <hemanthv@ti.com>"); | ||
diff --git a/drivers/input/misc/cma3000_d0x.h b/drivers/input/misc/cma3000_d0x.h new file mode 100644 index 000000000000..2304ce306e1c --- /dev/null +++ b/drivers/input/misc/cma3000_d0x.h | |||
@@ -0,0 +1,42 @@ | |||
1 | /* | ||
2 | * VTI CMA3000_D0x Accelerometer driver | ||
3 | * | ||
4 | * Copyright (C) 2010 Texas Instruments | ||
5 | * Author: Hemanth V <hemanthv@ti.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License version 2 as published by | ||
9 | * the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
14 | * more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License along with | ||
17 | * this program. If not, see <http://www.gnu.org/licenses/>. | ||
18 | */ | ||
19 | |||
20 | #ifndef _INPUT_CMA3000_H | ||
21 | #define _INPUT_CMA3000_H | ||
22 | |||
23 | #include <linux/types.h> | ||
24 | #include <linux/input.h> | ||
25 | |||
26 | struct device; | ||
27 | struct cma3000_accl_data; | ||
28 | |||
29 | struct cma3000_bus_ops { | ||
30 | u16 bustype; | ||
31 | u8 ctrl_mod; | ||
32 | int (*read)(struct device *, u8, char *); | ||
33 | int (*write)(struct device *, u8, u8, char *); | ||
34 | }; | ||
35 | |||
36 | struct cma3000_accl_data *cma3000_init(struct device *dev, int irq, | ||
37 | const struct cma3000_bus_ops *bops); | ||
38 | void cma3000_exit(struct cma3000_accl_data *); | ||
39 | void cma3000_suspend(struct cma3000_accl_data *); | ||
40 | void cma3000_resume(struct cma3000_accl_data *); | ||
41 | |||
42 | #endif | ||
diff --git a/drivers/input/misc/cma3000_d0x_i2c.c b/drivers/input/misc/cma3000_d0x_i2c.c new file mode 100644 index 000000000000..c52d278a7942 --- /dev/null +++ b/drivers/input/misc/cma3000_d0x_i2c.c | |||
@@ -0,0 +1,141 @@ | |||
1 | /* | ||
2 | * Implements I2C interface for VTI CMA300_D0x Accelerometer driver | ||
3 | * | ||
4 | * Copyright (C) 2010 Texas Instruments | ||
5 | * Author: Hemanth V <hemanthv@ti.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License version 2 as published by | ||
9 | * the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
14 | * more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License along with | ||
17 | * this program. If not, see <http://www.gnu.org/licenses/>. | ||
18 | */ | ||
19 | |||
20 | #include <linux/module.h> | ||
21 | #include <linux/i2c.h> | ||
22 | #include <linux/input/cma3000.h> | ||
23 | #include "cma3000_d0x.h" | ||
24 | |||
25 | static int cma3000_i2c_set(struct device *dev, | ||
26 | u8 reg, u8 val, char *msg) | ||
27 | { | ||
28 | struct i2c_client *client = to_i2c_client(dev); | ||
29 | int ret; | ||
30 | |||
31 | ret = i2c_smbus_write_byte_data(client, reg, val); | ||
32 | if (ret < 0) | ||
33 | dev_err(&client->dev, | ||
34 | "%s failed (%s, %d)\n", __func__, msg, ret); | ||
35 | return ret; | ||
36 | } | ||
37 | |||
38 | static int cma3000_i2c_read(struct device *dev, u8 reg, char *msg) | ||
39 | { | ||
40 | struct i2c_client *client = to_i2c_client(dev); | ||
41 | int ret; | ||
42 | |||
43 | ret = i2c_smbus_read_byte_data(client, reg); | ||
44 | if (ret < 0) | ||
45 | dev_err(&client->dev, | ||
46 | "%s failed (%s, %d)\n", __func__, msg, ret); | ||
47 | return ret; | ||
48 | } | ||
49 | |||
50 | static const struct cma3000_bus_ops cma3000_i2c_bops = { | ||
51 | .bustype = BUS_I2C, | ||
52 | #define CMA3000_BUSI2C (0 << 4) | ||
53 | .ctrl_mod = CMA3000_BUSI2C, | ||
54 | .read = cma3000_i2c_read, | ||
55 | .write = cma3000_i2c_set, | ||
56 | }; | ||
57 | |||
58 | static int __devinit cma3000_i2c_probe(struct i2c_client *client, | ||
59 | const struct i2c_device_id *id) | ||
60 | { | ||
61 | struct cma3000_accl_data *data; | ||
62 | |||
63 | data = cma3000_init(&client->dev, client->irq, &cma3000_i2c_bops); | ||
64 | if (IS_ERR(data)) | ||
65 | return PTR_ERR(data); | ||
66 | |||
67 | i2c_set_clientdata(client, data); | ||
68 | |||
69 | return 0; | ||
70 | } | ||
71 | |||
72 | static int __devexit cma3000_i2c_remove(struct i2c_client *client) | ||
73 | { | ||
74 | struct cma3000_accl_data *data = i2c_get_clientdata(client); | ||
75 | |||
76 | cma3000_exit(data); | ||
77 | |||
78 | return 0; | ||
79 | } | ||
80 | |||
81 | #ifdef CONFIG_PM | ||
82 | static int cma3000_i2c_suspend(struct device *dev) | ||
83 | { | ||
84 | struct i2c_client *client = to_i2c_client(dev); | ||
85 | struct cma3000_accl_data *data = i2c_get_clientdata(client); | ||
86 | |||
87 | cma3000_suspend(data); | ||
88 | |||
89 | return 0; | ||
90 | } | ||
91 | |||
92 | static int cma3000_i2c_resume(struct device *dev) | ||
93 | { | ||
94 | struct i2c_client *client = to_i2c_client(dev); | ||
95 | struct cma3000_accl_data *data = i2c_get_clientdata(client); | ||
96 | |||
97 | cma3000_resume(data); | ||
98 | |||
99 | return 0; | ||
100 | } | ||
101 | |||
102 | static const struct dev_pm_ops cma3000_i2c_pm_ops = { | ||
103 | .suspend = cma3000_i2c_suspend, | ||
104 | .resume = cma3000_i2c_resume, | ||
105 | }; | ||
106 | #endif | ||
107 | |||
108 | static const struct i2c_device_id cma3000_i2c_id[] = { | ||
109 | { "cma3000_d01", 0 }, | ||
110 | { }, | ||
111 | }; | ||
112 | |||
113 | static struct i2c_driver cma3000_i2c_driver = { | ||
114 | .probe = cma3000_i2c_probe, | ||
115 | .remove = __devexit_p(cma3000_i2c_remove), | ||
116 | .id_table = cma3000_i2c_id, | ||
117 | .driver = { | ||
118 | .name = "cma3000_i2c_accl", | ||
119 | .owner = THIS_MODULE, | ||
120 | #ifdef CONFIG_PM | ||
121 | .pm = &cma3000_i2c_pm_ops, | ||
122 | #endif | ||
123 | }, | ||
124 | }; | ||
125 | |||
126 | static int __init cma3000_i2c_init(void) | ||
127 | { | ||
128 | return i2c_add_driver(&cma3000_i2c_driver); | ||
129 | } | ||
130 | |||
131 | static void __exit cma3000_i2c_exit(void) | ||
132 | { | ||
133 | i2c_del_driver(&cma3000_i2c_driver); | ||
134 | } | ||
135 | |||
136 | module_init(cma3000_i2c_init); | ||
137 | module_exit(cma3000_i2c_exit); | ||
138 | |||
139 | MODULE_DESCRIPTION("CMA3000-D0x Accelerometer I2C Driver"); | ||
140 | MODULE_LICENSE("GPL"); | ||
141 | MODULE_AUTHOR("Hemanth V <hemanthv@ti.com>"); | ||