1*caab277bSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2b029ffafSHemanth V /*
3b029ffafSHemanth V * VTI CMA3000_D0x Accelerometer driver
4b029ffafSHemanth V *
5b029ffafSHemanth V * Copyright (C) 2010 Texas Instruments
6b029ffafSHemanth V * Author: Hemanth V <hemanthv@ti.com>
7b029ffafSHemanth V */
8b029ffafSHemanth V
9b029ffafSHemanth V #include <linux/types.h>
10b029ffafSHemanth V #include <linux/interrupt.h>
11b029ffafSHemanth V #include <linux/delay.h>
12b029ffafSHemanth V #include <linux/slab.h>
13b029ffafSHemanth V #include <linux/input.h>
14b029ffafSHemanth V #include <linux/input/cma3000.h>
15d2d8442dSPaul Gortmaker #include <linux/module.h>
16b029ffafSHemanth V
17b029ffafSHemanth V #include "cma3000_d0x.h"
18b029ffafSHemanth V
19b029ffafSHemanth V #define CMA3000_WHOAMI 0x00
20b029ffafSHemanth V #define CMA3000_REVID 0x01
21b029ffafSHemanth V #define CMA3000_CTRL 0x02
22b029ffafSHemanth V #define CMA3000_STATUS 0x03
23b029ffafSHemanth V #define CMA3000_RSTR 0x04
24b029ffafSHemanth V #define CMA3000_INTSTATUS 0x05
25b029ffafSHemanth V #define CMA3000_DOUTX 0x06
26b029ffafSHemanth V #define CMA3000_DOUTY 0x07
27b029ffafSHemanth V #define CMA3000_DOUTZ 0x08
28b029ffafSHemanth V #define CMA3000_MDTHR 0x09
29b029ffafSHemanth V #define CMA3000_MDFFTMR 0x0A
30b029ffafSHemanth V #define CMA3000_FFTHR 0x0B
31b029ffafSHemanth V
32b029ffafSHemanth V #define CMA3000_RANGE2G (1 << 7)
33b029ffafSHemanth V #define CMA3000_RANGE8G (0 << 7)
34b029ffafSHemanth V #define CMA3000_BUSI2C (0 << 4)
35b029ffafSHemanth V #define CMA3000_MODEMASK (7 << 1)
36b029ffafSHemanth V #define CMA3000_GRANGEMASK (1 << 7)
37b029ffafSHemanth V
38b029ffafSHemanth V #define CMA3000_STATUS_PERR 1
39b029ffafSHemanth V #define CMA3000_INTSTATUS_FFDET (1 << 2)
40b029ffafSHemanth V
41b029ffafSHemanth V /* Settling time delay in ms */
42b029ffafSHemanth V #define CMA3000_SETDELAY 30
43b029ffafSHemanth V
44b029ffafSHemanth V /* Delay for clearing interrupt in us */
45b029ffafSHemanth V #define CMA3000_INTDELAY 44
46b029ffafSHemanth V
47b029ffafSHemanth V
48b029ffafSHemanth V /*
49b029ffafSHemanth V * Bit weights in mg for bit 0, other bits need
5092a9f14bSRalf Baechle * multiply factor 2^n. Eight bit is the sign bit.
51b029ffafSHemanth V */
52b029ffafSHemanth V #define BIT_TO_2G 18
53b029ffafSHemanth V #define BIT_TO_8G 71
54b029ffafSHemanth V
55b029ffafSHemanth V struct cma3000_accl_data {
56b029ffafSHemanth V const struct cma3000_bus_ops *bus_ops;
57b029ffafSHemanth V const struct cma3000_platform_data *pdata;
58b029ffafSHemanth V
59b029ffafSHemanth V struct device *dev;
60b029ffafSHemanth V struct input_dev *input_dev;
61b029ffafSHemanth V
62b029ffafSHemanth V int bit_to_mg;
63b029ffafSHemanth V int irq;
64b029ffafSHemanth V
65b029ffafSHemanth V int g_range;
66b029ffafSHemanth V u8 mode;
67b029ffafSHemanth V
68b029ffafSHemanth V struct mutex mutex;
69b029ffafSHemanth V bool opened;
70b029ffafSHemanth V bool suspended;
71b029ffafSHemanth V };
72b029ffafSHemanth V
73b029ffafSHemanth V #define CMA3000_READ(data, reg, msg) \
74b029ffafSHemanth V (data->bus_ops->read(data->dev, reg, msg))
75b029ffafSHemanth V #define CMA3000_SET(data, reg, val, msg) \
76b029ffafSHemanth V ((data)->bus_ops->write(data->dev, reg, val, msg))
77b029ffafSHemanth V
78b029ffafSHemanth V /*
79b029ffafSHemanth V * Conversion for each of the eight modes to g, depending
80b029ffafSHemanth V * on G range i.e 2G or 8G. Some modes always operate in
81b029ffafSHemanth V * 8G.
82b029ffafSHemanth V */
83b029ffafSHemanth V
84b029ffafSHemanth V static int mode_to_mg[8][2] = {
85b029ffafSHemanth V { 0, 0 },
86b029ffafSHemanth V { BIT_TO_8G, BIT_TO_2G },
87b029ffafSHemanth V { BIT_TO_8G, BIT_TO_2G },
88b029ffafSHemanth V { BIT_TO_8G, BIT_TO_8G },
89b029ffafSHemanth V { BIT_TO_8G, BIT_TO_8G },
90b029ffafSHemanth V { BIT_TO_8G, BIT_TO_2G },
91b029ffafSHemanth V { BIT_TO_8G, BIT_TO_2G },
92b029ffafSHemanth V { 0, 0},
93b029ffafSHemanth V };
94b029ffafSHemanth V
decode_mg(struct cma3000_accl_data * data,int * datax,int * datay,int * dataz)95b029ffafSHemanth V static void decode_mg(struct cma3000_accl_data *data, int *datax,
96b029ffafSHemanth V int *datay, int *dataz)
97b029ffafSHemanth V {
98b029ffafSHemanth V /* Data in 2's complement, convert to mg */
99b029ffafSHemanth V *datax = ((s8)*datax) * data->bit_to_mg;
100b029ffafSHemanth V *datay = ((s8)*datay) * data->bit_to_mg;
101b029ffafSHemanth V *dataz = ((s8)*dataz) * data->bit_to_mg;
102b029ffafSHemanth V }
103b029ffafSHemanth V
cma3000_thread_irq(int irq,void * dev_id)104b029ffafSHemanth V static irqreturn_t cma3000_thread_irq(int irq, void *dev_id)
105b029ffafSHemanth V {
106b029ffafSHemanth V struct cma3000_accl_data *data = dev_id;
1073a7f8fb1SXi Wang int datax, datay, dataz, intr_status;
1083a7f8fb1SXi Wang u8 ctrl, mode, range;
109b029ffafSHemanth V
110b029ffafSHemanth V intr_status = CMA3000_READ(data, CMA3000_INTSTATUS, "interrupt status");
111b029ffafSHemanth V if (intr_status < 0)
112b029ffafSHemanth V return IRQ_NONE;
113b029ffafSHemanth V
114b029ffafSHemanth V /* Check if free fall is detected, report immediately */
115b029ffafSHemanth V if (intr_status & CMA3000_INTSTATUS_FFDET) {
116b029ffafSHemanth V input_report_abs(data->input_dev, ABS_MISC, 1);
117b029ffafSHemanth V input_sync(data->input_dev);
118b029ffafSHemanth V } else {
119b029ffafSHemanth V input_report_abs(data->input_dev, ABS_MISC, 0);
120b029ffafSHemanth V }
121b029ffafSHemanth V
122b029ffafSHemanth V datax = CMA3000_READ(data, CMA3000_DOUTX, "X");
123b029ffafSHemanth V datay = CMA3000_READ(data, CMA3000_DOUTY, "Y");
124b029ffafSHemanth V dataz = CMA3000_READ(data, CMA3000_DOUTZ, "Z");
125b029ffafSHemanth V
126b029ffafSHemanth V ctrl = CMA3000_READ(data, CMA3000_CTRL, "ctrl");
127b029ffafSHemanth V mode = (ctrl & CMA3000_MODEMASK) >> 1;
128b029ffafSHemanth V range = (ctrl & CMA3000_GRANGEMASK) >> 7;
129b029ffafSHemanth V
130b029ffafSHemanth V data->bit_to_mg = mode_to_mg[mode][range];
131b029ffafSHemanth V
132b029ffafSHemanth V /* Interrupt not for this device */
133b029ffafSHemanth V if (data->bit_to_mg == 0)
134b029ffafSHemanth V return IRQ_NONE;
135b029ffafSHemanth V
136b029ffafSHemanth V /* Decode register values to milli g */
137b029ffafSHemanth V decode_mg(data, &datax, &datay, &dataz);
138b029ffafSHemanth V
139b029ffafSHemanth V input_report_abs(data->input_dev, ABS_X, datax);
140b029ffafSHemanth V input_report_abs(data->input_dev, ABS_Y, datay);
141b029ffafSHemanth V input_report_abs(data->input_dev, ABS_Z, dataz);
142b029ffafSHemanth V input_sync(data->input_dev);
143b029ffafSHemanth V
144b029ffafSHemanth V return IRQ_HANDLED;
145b029ffafSHemanth V }
146b029ffafSHemanth V
cma3000_reset(struct cma3000_accl_data * data)147b029ffafSHemanth V static int cma3000_reset(struct cma3000_accl_data *data)
148b029ffafSHemanth V {
149b029ffafSHemanth V int val;
150b029ffafSHemanth V
151b029ffafSHemanth V /* Reset sequence */
152b029ffafSHemanth V CMA3000_SET(data, CMA3000_RSTR, 0x02, "Reset");
153b029ffafSHemanth V CMA3000_SET(data, CMA3000_RSTR, 0x0A, "Reset");
154b029ffafSHemanth V CMA3000_SET(data, CMA3000_RSTR, 0x04, "Reset");
155b029ffafSHemanth V
156b029ffafSHemanth V /* Settling time delay */
157b029ffafSHemanth V mdelay(10);
158b029ffafSHemanth V
159b029ffafSHemanth V val = CMA3000_READ(data, CMA3000_STATUS, "Status");
160b029ffafSHemanth V if (val < 0) {
161b029ffafSHemanth V dev_err(data->dev, "Reset failed\n");
162b029ffafSHemanth V return val;
163b029ffafSHemanth V }
164b029ffafSHemanth V
165b029ffafSHemanth V if (val & CMA3000_STATUS_PERR) {
166b029ffafSHemanth V dev_err(data->dev, "Parity Error\n");
167b029ffafSHemanth V return -EIO;
168b029ffafSHemanth V }
169b029ffafSHemanth V
170b029ffafSHemanth V return 0;
171b029ffafSHemanth V }
172b029ffafSHemanth V
cma3000_poweron(struct cma3000_accl_data * data)173b029ffafSHemanth V static int cma3000_poweron(struct cma3000_accl_data *data)
174b029ffafSHemanth V {
175b029ffafSHemanth V const struct cma3000_platform_data *pdata = data->pdata;
176b029ffafSHemanth V u8 ctrl = 0;
177b029ffafSHemanth V int ret;
178b029ffafSHemanth V
179b029ffafSHemanth V if (data->g_range == CMARANGE_2G) {
180b029ffafSHemanth V ctrl = (data->mode << 1) | CMA3000_RANGE2G;
181b029ffafSHemanth V } else if (data->g_range == CMARANGE_8G) {
182b029ffafSHemanth V ctrl = (data->mode << 1) | CMA3000_RANGE8G;
183b029ffafSHemanth V } else {
184b029ffafSHemanth V dev_info(data->dev,
185b029ffafSHemanth V "Invalid G range specified, assuming 8G\n");
186b029ffafSHemanth V ctrl = (data->mode << 1) | CMA3000_RANGE8G;
187b029ffafSHemanth V }
188b029ffafSHemanth V
189b029ffafSHemanth V ctrl |= data->bus_ops->ctrl_mod;
190b029ffafSHemanth V
191b029ffafSHemanth V CMA3000_SET(data, CMA3000_MDTHR, pdata->mdthr,
192b029ffafSHemanth V "Motion Detect Threshold");
193b029ffafSHemanth V CMA3000_SET(data, CMA3000_MDFFTMR, pdata->mdfftmr,
194b029ffafSHemanth V "Time register");
195b029ffafSHemanth V CMA3000_SET(data, CMA3000_FFTHR, pdata->ffthr,
196b029ffafSHemanth V "Free fall threshold");
197b029ffafSHemanth V ret = CMA3000_SET(data, CMA3000_CTRL, ctrl, "Mode setting");
198b029ffafSHemanth V if (ret < 0)
199b029ffafSHemanth V return -EIO;
200b029ffafSHemanth V
201b029ffafSHemanth V msleep(CMA3000_SETDELAY);
202b029ffafSHemanth V
203b029ffafSHemanth V return 0;
204b029ffafSHemanth V }
205b029ffafSHemanth V
cma3000_poweroff(struct cma3000_accl_data * data)206b029ffafSHemanth V static int cma3000_poweroff(struct cma3000_accl_data *data)
207b029ffafSHemanth V {
208b029ffafSHemanth V int ret;
209b029ffafSHemanth V
210b029ffafSHemanth V ret = CMA3000_SET(data, CMA3000_CTRL, CMAMODE_POFF, "Mode setting");
211b029ffafSHemanth V msleep(CMA3000_SETDELAY);
212b029ffafSHemanth V
213b029ffafSHemanth V return ret;
214b029ffafSHemanth V }
215b029ffafSHemanth V
cma3000_open(struct input_dev * input_dev)216b029ffafSHemanth V static int cma3000_open(struct input_dev *input_dev)
217b029ffafSHemanth V {
218b029ffafSHemanth V struct cma3000_accl_data *data = input_get_drvdata(input_dev);
219b029ffafSHemanth V
220b029ffafSHemanth V mutex_lock(&data->mutex);
221b029ffafSHemanth V
222b029ffafSHemanth V if (!data->suspended)
223b029ffafSHemanth V cma3000_poweron(data);
224b029ffafSHemanth V
225b029ffafSHemanth V data->opened = true;
226b029ffafSHemanth V
227b029ffafSHemanth V mutex_unlock(&data->mutex);
228b029ffafSHemanth V
229b029ffafSHemanth V return 0;
230b029ffafSHemanth V }
231b029ffafSHemanth V
cma3000_close(struct input_dev * input_dev)232b029ffafSHemanth V static void cma3000_close(struct input_dev *input_dev)
233b029ffafSHemanth V {
234b029ffafSHemanth V struct cma3000_accl_data *data = input_get_drvdata(input_dev);
235b029ffafSHemanth V
236b029ffafSHemanth V mutex_lock(&data->mutex);
237b029ffafSHemanth V
238b029ffafSHemanth V if (!data->suspended)
239b029ffafSHemanth V cma3000_poweroff(data);
240b029ffafSHemanth V
241b029ffafSHemanth V data->opened = false;
242b029ffafSHemanth V
243b029ffafSHemanth V mutex_unlock(&data->mutex);
244b029ffafSHemanth V }
245b029ffafSHemanth V
cma3000_suspend(struct cma3000_accl_data * data)246b029ffafSHemanth V void cma3000_suspend(struct cma3000_accl_data *data)
247b029ffafSHemanth V {
248b029ffafSHemanth V mutex_lock(&data->mutex);
249b029ffafSHemanth V
250b029ffafSHemanth V if (!data->suspended && data->opened)
251b029ffafSHemanth V cma3000_poweroff(data);
252b029ffafSHemanth V
253b029ffafSHemanth V data->suspended = true;
254b029ffafSHemanth V
255b029ffafSHemanth V mutex_unlock(&data->mutex);
256b029ffafSHemanth V }
257b029ffafSHemanth V EXPORT_SYMBOL(cma3000_suspend);
258b029ffafSHemanth V
259b029ffafSHemanth V
cma3000_resume(struct cma3000_accl_data * data)260b029ffafSHemanth V void cma3000_resume(struct cma3000_accl_data *data)
261b029ffafSHemanth V {
262b029ffafSHemanth V mutex_lock(&data->mutex);
263b029ffafSHemanth V
264b029ffafSHemanth V if (data->suspended && data->opened)
265b029ffafSHemanth V cma3000_poweron(data);
266b029ffafSHemanth V
267b029ffafSHemanth V data->suspended = false;
268b029ffafSHemanth V
269b029ffafSHemanth V mutex_unlock(&data->mutex);
270b029ffafSHemanth V }
271b029ffafSHemanth V EXPORT_SYMBOL(cma3000_resume);
272b029ffafSHemanth V
cma3000_init(struct device * dev,int irq,const struct cma3000_bus_ops * bops)273b029ffafSHemanth V struct cma3000_accl_data *cma3000_init(struct device *dev, int irq,
274b029ffafSHemanth V const struct cma3000_bus_ops *bops)
275b029ffafSHemanth V {
276c838cb3dSJingoo Han const struct cma3000_platform_data *pdata = dev_get_platdata(dev);
277b029ffafSHemanth V struct cma3000_accl_data *data;
278b029ffafSHemanth V struct input_dev *input_dev;
279b029ffafSHemanth V int rev;
280b029ffafSHemanth V int error;
281b029ffafSHemanth V
282b029ffafSHemanth V if (!pdata) {
283b029ffafSHemanth V dev_err(dev, "platform data not found\n");
284b029ffafSHemanth V error = -EINVAL;
285b029ffafSHemanth V goto err_out;
286b029ffafSHemanth V }
287b029ffafSHemanth V
288b029ffafSHemanth V
289b029ffafSHemanth V /* if no IRQ return error */
290b029ffafSHemanth V if (irq == 0) {
291b029ffafSHemanth V error = -EINVAL;
292b029ffafSHemanth V goto err_out;
293b029ffafSHemanth V }
294b029ffafSHemanth V
295b029ffafSHemanth V data = kzalloc(sizeof(struct cma3000_accl_data), GFP_KERNEL);
296b029ffafSHemanth V input_dev = input_allocate_device();
297b029ffafSHemanth V if (!data || !input_dev) {
298b029ffafSHemanth V error = -ENOMEM;
299b029ffafSHemanth V goto err_free_mem;
300b029ffafSHemanth V }
301b029ffafSHemanth V
302b029ffafSHemanth V data->dev = dev;
303b029ffafSHemanth V data->input_dev = input_dev;
304b029ffafSHemanth V data->bus_ops = bops;
305b029ffafSHemanth V data->pdata = pdata;
306b029ffafSHemanth V data->irq = irq;
307b029ffafSHemanth V mutex_init(&data->mutex);
308b029ffafSHemanth V
309b029ffafSHemanth V data->mode = pdata->mode;
310bcad87bdSDmitry Torokhov if (data->mode > CMAMODE_POFF) {
311b029ffafSHemanth V data->mode = CMAMODE_MOTDET;
312b029ffafSHemanth V dev_warn(dev,
313b029ffafSHemanth V "Invalid mode specified, assuming Motion Detect\n");
314b029ffafSHemanth V }
315b029ffafSHemanth V
316b029ffafSHemanth V data->g_range = pdata->g_range;
317b029ffafSHemanth V if (data->g_range != CMARANGE_2G && data->g_range != CMARANGE_8G) {
318b029ffafSHemanth V dev_info(dev,
319b029ffafSHemanth V "Invalid G range specified, assuming 8G\n");
320b029ffafSHemanth V data->g_range = CMARANGE_8G;
321b029ffafSHemanth V }
322b029ffafSHemanth V
323b029ffafSHemanth V input_dev->name = "cma3000-accelerometer";
324b029ffafSHemanth V input_dev->id.bustype = bops->bustype;
325b029ffafSHemanth V input_dev->open = cma3000_open;
326b029ffafSHemanth V input_dev->close = cma3000_close;
327b029ffafSHemanth V
328b029ffafSHemanth V input_set_abs_params(input_dev, ABS_X,
329b029ffafSHemanth V -data->g_range, data->g_range, pdata->fuzz_x, 0);
330b029ffafSHemanth V input_set_abs_params(input_dev, ABS_Y,
331b029ffafSHemanth V -data->g_range, data->g_range, pdata->fuzz_y, 0);
332b029ffafSHemanth V input_set_abs_params(input_dev, ABS_Z,
333b029ffafSHemanth V -data->g_range, data->g_range, pdata->fuzz_z, 0);
334b029ffafSHemanth V input_set_abs_params(input_dev, ABS_MISC, 0, 1, 0, 0);
335b029ffafSHemanth V
336b029ffafSHemanth V input_set_drvdata(input_dev, data);
337b029ffafSHemanth V
338b029ffafSHemanth V error = cma3000_reset(data);
339b029ffafSHemanth V if (error)
340b029ffafSHemanth V goto err_free_mem;
341b029ffafSHemanth V
342b029ffafSHemanth V rev = CMA3000_READ(data, CMA3000_REVID, "Revid");
343b029ffafSHemanth V if (rev < 0) {
344b029ffafSHemanth V error = rev;
345b029ffafSHemanth V goto err_free_mem;
346b029ffafSHemanth V }
347b029ffafSHemanth V
348b029ffafSHemanth V pr_info("CMA3000 Accelerometer: Revision %x\n", rev);
349b029ffafSHemanth V
350b029ffafSHemanth V error = request_threaded_irq(irq, NULL, cma3000_thread_irq,
351b029ffafSHemanth V pdata->irqflags | IRQF_ONESHOT,
352b029ffafSHemanth V "cma3000_d0x", data);
353b029ffafSHemanth V if (error) {
354b029ffafSHemanth V dev_err(dev, "request_threaded_irq failed\n");
355b029ffafSHemanth V goto err_free_mem;
356b029ffafSHemanth V }
357b029ffafSHemanth V
358b029ffafSHemanth V error = input_register_device(data->input_dev);
359b029ffafSHemanth V if (error) {
360b029ffafSHemanth V dev_err(dev, "Unable to register input device\n");
361b029ffafSHemanth V goto err_free_irq;
362b029ffafSHemanth V }
363b029ffafSHemanth V
364b029ffafSHemanth V return data;
365b029ffafSHemanth V
366b029ffafSHemanth V err_free_irq:
367b029ffafSHemanth V free_irq(irq, data);
368b029ffafSHemanth V err_free_mem:
369b029ffafSHemanth V input_free_device(input_dev);
370b029ffafSHemanth V kfree(data);
371b029ffafSHemanth V err_out:
372b029ffafSHemanth V return ERR_PTR(error);
373b029ffafSHemanth V }
374b029ffafSHemanth V EXPORT_SYMBOL(cma3000_init);
375b029ffafSHemanth V
cma3000_exit(struct cma3000_accl_data * data)376b029ffafSHemanth V void cma3000_exit(struct cma3000_accl_data *data)
377b029ffafSHemanth V {
378b029ffafSHemanth V free_irq(data->irq, data);
379b029ffafSHemanth V input_unregister_device(data->input_dev);
380b029ffafSHemanth V kfree(data);
381b029ffafSHemanth V }
382b029ffafSHemanth V EXPORT_SYMBOL(cma3000_exit);
383b029ffafSHemanth V
384b029ffafSHemanth V MODULE_DESCRIPTION("CMA3000-D0x Accelerometer Driver");
385b029ffafSHemanth V MODULE_LICENSE("GPL");
386b029ffafSHemanth V MODULE_AUTHOR("Hemanth V <hemanthv@ti.com>");
387