174ba9207SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2c17ca3f5SEric Andersson /*
3c17ca3f5SEric Andersson * Copyright (c) 2011 Bosch Sensortec GmbH
4c17ca3f5SEric Andersson * Copyright (c) 2011 Unixphere
5c17ca3f5SEric Andersson *
6c17ca3f5SEric Andersson * This driver adds support for Bosch Sensortec's digital acceleration
7c17ca3f5SEric Andersson * sensors BMA150 and SMB380.
8c17ca3f5SEric Andersson * The SMB380 is fully compatible with BMA150 and only differs in packaging.
9c17ca3f5SEric Andersson *
10c17ca3f5SEric Andersson * The datasheet for the BMA150 chip can be found here:
11c17ca3f5SEric Andersson * http://www.bosch-sensortec.com/content/language1/downloads/BST-BMA150-DS000-07.pdf
12c17ca3f5SEric Andersson */
13c17ca3f5SEric Andersson #include <linux/kernel.h>
14c17ca3f5SEric Andersson #include <linux/module.h>
15c17ca3f5SEric Andersson #include <linux/i2c.h>
16c17ca3f5SEric Andersson #include <linux/input.h>
17c17ca3f5SEric Andersson #include <linux/interrupt.h>
18c17ca3f5SEric Andersson #include <linux/delay.h>
19c17ca3f5SEric Andersson #include <linux/slab.h>
20c17ca3f5SEric Andersson #include <linux/pm.h>
21c17ca3f5SEric Andersson #include <linux/pm_runtime.h>
22c17ca3f5SEric Andersson #include <linux/bma150.h>
23c17ca3f5SEric Andersson
24c17ca3f5SEric Andersson #define ABSMAX_ACC_VAL 0x01FF
25c17ca3f5SEric Andersson #define ABSMIN_ACC_VAL -(ABSMAX_ACC_VAL)
26c17ca3f5SEric Andersson
27c17ca3f5SEric Andersson /* Each axis is represented by a 2-byte data word */
28c17ca3f5SEric Andersson #define BMA150_XYZ_DATA_SIZE 6
29c17ca3f5SEric Andersson
30c17ca3f5SEric Andersson /* Input poll interval in milliseconds */
31c17ca3f5SEric Andersson #define BMA150_POLL_INTERVAL 10
32c17ca3f5SEric Andersson #define BMA150_POLL_MAX 200
33c17ca3f5SEric Andersson #define BMA150_POLL_MIN 0
34c17ca3f5SEric Andersson
35c17ca3f5SEric Andersson #define BMA150_MODE_NORMAL 0
36c17ca3f5SEric Andersson #define BMA150_MODE_SLEEP 2
37c17ca3f5SEric Andersson #define BMA150_MODE_WAKE_UP 3
38c17ca3f5SEric Andersson
39c17ca3f5SEric Andersson /* Data register addresses */
40c17ca3f5SEric Andersson #define BMA150_DATA_0_REG 0x00
41c17ca3f5SEric Andersson #define BMA150_DATA_1_REG 0x01
42c17ca3f5SEric Andersson #define BMA150_DATA_2_REG 0x02
43c17ca3f5SEric Andersson
44c17ca3f5SEric Andersson /* Control register addresses */
45c17ca3f5SEric Andersson #define BMA150_CTRL_0_REG 0x0A
46c17ca3f5SEric Andersson #define BMA150_CTRL_1_REG 0x0B
47c17ca3f5SEric Andersson #define BMA150_CTRL_2_REG 0x14
48c17ca3f5SEric Andersson #define BMA150_CTRL_3_REG 0x15
49c17ca3f5SEric Andersson
50c17ca3f5SEric Andersson /* Configuration/Setting register addresses */
51c17ca3f5SEric Andersson #define BMA150_CFG_0_REG 0x0C
52c17ca3f5SEric Andersson #define BMA150_CFG_1_REG 0x0D
53c17ca3f5SEric Andersson #define BMA150_CFG_2_REG 0x0E
54c17ca3f5SEric Andersson #define BMA150_CFG_3_REG 0x0F
55c17ca3f5SEric Andersson #define BMA150_CFG_4_REG 0x10
56c17ca3f5SEric Andersson #define BMA150_CFG_5_REG 0x11
57c17ca3f5SEric Andersson
58c17ca3f5SEric Andersson #define BMA150_CHIP_ID 2
59c17ca3f5SEric Andersson #define BMA150_CHIP_ID_REG BMA150_DATA_0_REG
60c17ca3f5SEric Andersson
61c17ca3f5SEric Andersson #define BMA150_ACC_X_LSB_REG BMA150_DATA_2_REG
62c17ca3f5SEric Andersson
63c17ca3f5SEric Andersson #define BMA150_SLEEP_POS 0
64c17ca3f5SEric Andersson #define BMA150_SLEEP_MSK 0x01
65c17ca3f5SEric Andersson #define BMA150_SLEEP_REG BMA150_CTRL_0_REG
66c17ca3f5SEric Andersson
67c17ca3f5SEric Andersson #define BMA150_BANDWIDTH_POS 0
68c17ca3f5SEric Andersson #define BMA150_BANDWIDTH_MSK 0x07
69c17ca3f5SEric Andersson #define BMA150_BANDWIDTH_REG BMA150_CTRL_2_REG
70c17ca3f5SEric Andersson
71c17ca3f5SEric Andersson #define BMA150_RANGE_POS 3
72c17ca3f5SEric Andersson #define BMA150_RANGE_MSK 0x18
73c17ca3f5SEric Andersson #define BMA150_RANGE_REG BMA150_CTRL_2_REG
74c17ca3f5SEric Andersson
75c17ca3f5SEric Andersson #define BMA150_WAKE_UP_POS 0
76c17ca3f5SEric Andersson #define BMA150_WAKE_UP_MSK 0x01
77c17ca3f5SEric Andersson #define BMA150_WAKE_UP_REG BMA150_CTRL_3_REG
78c17ca3f5SEric Andersson
79c17ca3f5SEric Andersson #define BMA150_SW_RES_POS 1
80c17ca3f5SEric Andersson #define BMA150_SW_RES_MSK 0x02
81c17ca3f5SEric Andersson #define BMA150_SW_RES_REG BMA150_CTRL_0_REG
82c17ca3f5SEric Andersson
83c17ca3f5SEric Andersson /* Any-motion interrupt register fields */
84c17ca3f5SEric Andersson #define BMA150_ANY_MOTION_EN_POS 6
85c17ca3f5SEric Andersson #define BMA150_ANY_MOTION_EN_MSK 0x40
86c17ca3f5SEric Andersson #define BMA150_ANY_MOTION_EN_REG BMA150_CTRL_1_REG
87c17ca3f5SEric Andersson
88c17ca3f5SEric Andersson #define BMA150_ANY_MOTION_DUR_POS 6
89c17ca3f5SEric Andersson #define BMA150_ANY_MOTION_DUR_MSK 0xC0
90c17ca3f5SEric Andersson #define BMA150_ANY_MOTION_DUR_REG BMA150_CFG_5_REG
91c17ca3f5SEric Andersson
92c17ca3f5SEric Andersson #define BMA150_ANY_MOTION_THRES_REG BMA150_CFG_4_REG
93c17ca3f5SEric Andersson
94c17ca3f5SEric Andersson /* Advanced interrupt register fields */
95c17ca3f5SEric Andersson #define BMA150_ADV_INT_EN_POS 6
96c17ca3f5SEric Andersson #define BMA150_ADV_INT_EN_MSK 0x40
97c17ca3f5SEric Andersson #define BMA150_ADV_INT_EN_REG BMA150_CTRL_3_REG
98c17ca3f5SEric Andersson
99c17ca3f5SEric Andersson /* High-G interrupt register fields */
100c17ca3f5SEric Andersson #define BMA150_HIGH_G_EN_POS 1
101c17ca3f5SEric Andersson #define BMA150_HIGH_G_EN_MSK 0x02
102c17ca3f5SEric Andersson #define BMA150_HIGH_G_EN_REG BMA150_CTRL_1_REG
103c17ca3f5SEric Andersson
104c17ca3f5SEric Andersson #define BMA150_HIGH_G_HYST_POS 3
105c17ca3f5SEric Andersson #define BMA150_HIGH_G_HYST_MSK 0x38
106c17ca3f5SEric Andersson #define BMA150_HIGH_G_HYST_REG BMA150_CFG_5_REG
107c17ca3f5SEric Andersson
108c17ca3f5SEric Andersson #define BMA150_HIGH_G_DUR_REG BMA150_CFG_3_REG
109c17ca3f5SEric Andersson #define BMA150_HIGH_G_THRES_REG BMA150_CFG_2_REG
110c17ca3f5SEric Andersson
111c17ca3f5SEric Andersson /* Low-G interrupt register fields */
112c17ca3f5SEric Andersson #define BMA150_LOW_G_EN_POS 0
113c17ca3f5SEric Andersson #define BMA150_LOW_G_EN_MSK 0x01
114c17ca3f5SEric Andersson #define BMA150_LOW_G_EN_REG BMA150_CTRL_1_REG
115c17ca3f5SEric Andersson
116c17ca3f5SEric Andersson #define BMA150_LOW_G_HYST_POS 0
117c17ca3f5SEric Andersson #define BMA150_LOW_G_HYST_MSK 0x07
118c17ca3f5SEric Andersson #define BMA150_LOW_G_HYST_REG BMA150_CFG_5_REG
119c17ca3f5SEric Andersson
120c17ca3f5SEric Andersson #define BMA150_LOW_G_DUR_REG BMA150_CFG_1_REG
121c17ca3f5SEric Andersson #define BMA150_LOW_G_THRES_REG BMA150_CFG_0_REG
122c17ca3f5SEric Andersson
123c17ca3f5SEric Andersson struct bma150_data {
124c17ca3f5SEric Andersson struct i2c_client *client;
125c17ca3f5SEric Andersson struct input_dev *input;
126c17ca3f5SEric Andersson u8 mode;
127c17ca3f5SEric Andersson };
128c17ca3f5SEric Andersson
129c17ca3f5SEric Andersson /*
130c17ca3f5SEric Andersson * The settings for the given range, bandwidth and interrupt features
131c17ca3f5SEric Andersson * are stated and verified by Bosch Sensortec where they are configured
132c17ca3f5SEric Andersson * to provide a generic sensitivity performance.
133c17ca3f5SEric Andersson */
1347ed5ff82SJulia Lawall static const struct bma150_cfg default_cfg = {
135c17ca3f5SEric Andersson .any_motion_int = 1,
136c17ca3f5SEric Andersson .hg_int = 1,
137c17ca3f5SEric Andersson .lg_int = 1,
138c17ca3f5SEric Andersson .any_motion_dur = 0,
139c17ca3f5SEric Andersson .any_motion_thres = 0,
140c17ca3f5SEric Andersson .hg_hyst = 0,
141c17ca3f5SEric Andersson .hg_dur = 150,
142c17ca3f5SEric Andersson .hg_thres = 160,
143c17ca3f5SEric Andersson .lg_hyst = 0,
144c17ca3f5SEric Andersson .lg_dur = 150,
145c17ca3f5SEric Andersson .lg_thres = 20,
146c17ca3f5SEric Andersson .range = BMA150_RANGE_2G,
147c17ca3f5SEric Andersson .bandwidth = BMA150_BW_50HZ
148c17ca3f5SEric Andersson };
149c17ca3f5SEric Andersson
bma150_write_byte(struct i2c_client * client,u8 reg,u8 val)150c17ca3f5SEric Andersson static int bma150_write_byte(struct i2c_client *client, u8 reg, u8 val)
151c17ca3f5SEric Andersson {
152c17ca3f5SEric Andersson s32 ret;
153c17ca3f5SEric Andersson
154c17ca3f5SEric Andersson /* As per specification, disable irq in between register writes */
155c17ca3f5SEric Andersson if (client->irq)
156c17ca3f5SEric Andersson disable_irq_nosync(client->irq);
157c17ca3f5SEric Andersson
158c17ca3f5SEric Andersson ret = i2c_smbus_write_byte_data(client, reg, val);
159c17ca3f5SEric Andersson
160c17ca3f5SEric Andersson if (client->irq)
161c17ca3f5SEric Andersson enable_irq(client->irq);
162c17ca3f5SEric Andersson
163c17ca3f5SEric Andersson return ret;
164c17ca3f5SEric Andersson }
165c17ca3f5SEric Andersson
bma150_set_reg_bits(struct i2c_client * client,int val,int shift,u8 mask,u8 reg)166c17ca3f5SEric Andersson static int bma150_set_reg_bits(struct i2c_client *client,
167c17ca3f5SEric Andersson int val, int shift, u8 mask, u8 reg)
168c17ca3f5SEric Andersson {
169c17ca3f5SEric Andersson int data;
170c17ca3f5SEric Andersson
171c17ca3f5SEric Andersson data = i2c_smbus_read_byte_data(client, reg);
172c17ca3f5SEric Andersson if (data < 0)
173c17ca3f5SEric Andersson return data;
174c17ca3f5SEric Andersson
175c17ca3f5SEric Andersson data = (data & ~mask) | ((val << shift) & mask);
176c17ca3f5SEric Andersson return bma150_write_byte(client, reg, data);
177c17ca3f5SEric Andersson }
178c17ca3f5SEric Andersson
bma150_set_mode(struct bma150_data * bma150,u8 mode)179c17ca3f5SEric Andersson static int bma150_set_mode(struct bma150_data *bma150, u8 mode)
180c17ca3f5SEric Andersson {
181c17ca3f5SEric Andersson int error;
182c17ca3f5SEric Andersson
183c17ca3f5SEric Andersson error = bma150_set_reg_bits(bma150->client, mode, BMA150_WAKE_UP_POS,
184c17ca3f5SEric Andersson BMA150_WAKE_UP_MSK, BMA150_WAKE_UP_REG);
185c17ca3f5SEric Andersson if (error)
186c17ca3f5SEric Andersson return error;
187c17ca3f5SEric Andersson
188c17ca3f5SEric Andersson error = bma150_set_reg_bits(bma150->client, mode, BMA150_SLEEP_POS,
189c17ca3f5SEric Andersson BMA150_SLEEP_MSK, BMA150_SLEEP_REG);
190c17ca3f5SEric Andersson if (error)
191c17ca3f5SEric Andersson return error;
192c17ca3f5SEric Andersson
193c17ca3f5SEric Andersson if (mode == BMA150_MODE_NORMAL)
194f63bb4f4SAniroop Mathur usleep_range(2000, 2100);
195c17ca3f5SEric Andersson
196c17ca3f5SEric Andersson bma150->mode = mode;
197c17ca3f5SEric Andersson return 0;
198c17ca3f5SEric Andersson }
199c17ca3f5SEric Andersson
bma150_soft_reset(struct bma150_data * bma150)2005298cc4cSBill Pemberton static int bma150_soft_reset(struct bma150_data *bma150)
201c17ca3f5SEric Andersson {
202c17ca3f5SEric Andersson int error;
203c17ca3f5SEric Andersson
204c17ca3f5SEric Andersson error = bma150_set_reg_bits(bma150->client, 1, BMA150_SW_RES_POS,
205c17ca3f5SEric Andersson BMA150_SW_RES_MSK, BMA150_SW_RES_REG);
206c17ca3f5SEric Andersson if (error)
207c17ca3f5SEric Andersson return error;
208c17ca3f5SEric Andersson
209f63bb4f4SAniroop Mathur usleep_range(2000, 2100);
210c17ca3f5SEric Andersson return 0;
211c17ca3f5SEric Andersson }
212c17ca3f5SEric Andersson
bma150_set_range(struct bma150_data * bma150,u8 range)2135298cc4cSBill Pemberton static int bma150_set_range(struct bma150_data *bma150, u8 range)
214c17ca3f5SEric Andersson {
215c17ca3f5SEric Andersson return bma150_set_reg_bits(bma150->client, range, BMA150_RANGE_POS,
216c17ca3f5SEric Andersson BMA150_RANGE_MSK, BMA150_RANGE_REG);
217c17ca3f5SEric Andersson }
218c17ca3f5SEric Andersson
bma150_set_bandwidth(struct bma150_data * bma150,u8 bw)2195298cc4cSBill Pemberton static int bma150_set_bandwidth(struct bma150_data *bma150, u8 bw)
220c17ca3f5SEric Andersson {
221c17ca3f5SEric Andersson return bma150_set_reg_bits(bma150->client, bw, BMA150_BANDWIDTH_POS,
222c17ca3f5SEric Andersson BMA150_BANDWIDTH_MSK, BMA150_BANDWIDTH_REG);
223c17ca3f5SEric Andersson }
224c17ca3f5SEric Andersson
bma150_set_low_g_interrupt(struct bma150_data * bma150,u8 enable,u8 hyst,u8 dur,u8 thres)2255298cc4cSBill Pemberton static int bma150_set_low_g_interrupt(struct bma150_data *bma150,
226c17ca3f5SEric Andersson u8 enable, u8 hyst, u8 dur, u8 thres)
227c17ca3f5SEric Andersson {
228c17ca3f5SEric Andersson int error;
229c17ca3f5SEric Andersson
230c17ca3f5SEric Andersson error = bma150_set_reg_bits(bma150->client, hyst,
231c17ca3f5SEric Andersson BMA150_LOW_G_HYST_POS, BMA150_LOW_G_HYST_MSK,
232c17ca3f5SEric Andersson BMA150_LOW_G_HYST_REG);
233c17ca3f5SEric Andersson if (error)
234c17ca3f5SEric Andersson return error;
235c17ca3f5SEric Andersson
236c17ca3f5SEric Andersson error = bma150_write_byte(bma150->client, BMA150_LOW_G_DUR_REG, dur);
237c17ca3f5SEric Andersson if (error)
238c17ca3f5SEric Andersson return error;
239c17ca3f5SEric Andersson
240c17ca3f5SEric Andersson error = bma150_write_byte(bma150->client, BMA150_LOW_G_THRES_REG, thres);
241c17ca3f5SEric Andersson if (error)
242c17ca3f5SEric Andersson return error;
243c17ca3f5SEric Andersson
244c17ca3f5SEric Andersson return bma150_set_reg_bits(bma150->client, !!enable,
245c17ca3f5SEric Andersson BMA150_LOW_G_EN_POS, BMA150_LOW_G_EN_MSK,
246c17ca3f5SEric Andersson BMA150_LOW_G_EN_REG);
247c17ca3f5SEric Andersson }
248c17ca3f5SEric Andersson
bma150_set_high_g_interrupt(struct bma150_data * bma150,u8 enable,u8 hyst,u8 dur,u8 thres)2495298cc4cSBill Pemberton static int bma150_set_high_g_interrupt(struct bma150_data *bma150,
250c17ca3f5SEric Andersson u8 enable, u8 hyst, u8 dur, u8 thres)
251c17ca3f5SEric Andersson {
252c17ca3f5SEric Andersson int error;
253c17ca3f5SEric Andersson
254c17ca3f5SEric Andersson error = bma150_set_reg_bits(bma150->client, hyst,
255c17ca3f5SEric Andersson BMA150_HIGH_G_HYST_POS, BMA150_HIGH_G_HYST_MSK,
256c17ca3f5SEric Andersson BMA150_HIGH_G_HYST_REG);
257c17ca3f5SEric Andersson if (error)
258c17ca3f5SEric Andersson return error;
259c17ca3f5SEric Andersson
260c17ca3f5SEric Andersson error = bma150_write_byte(bma150->client,
261c17ca3f5SEric Andersson BMA150_HIGH_G_DUR_REG, dur);
262c17ca3f5SEric Andersson if (error)
263c17ca3f5SEric Andersson return error;
264c17ca3f5SEric Andersson
265c17ca3f5SEric Andersson error = bma150_write_byte(bma150->client,
266c17ca3f5SEric Andersson BMA150_HIGH_G_THRES_REG, thres);
267c17ca3f5SEric Andersson if (error)
268c17ca3f5SEric Andersson return error;
269c17ca3f5SEric Andersson
270c17ca3f5SEric Andersson return bma150_set_reg_bits(bma150->client, !!enable,
271c17ca3f5SEric Andersson BMA150_HIGH_G_EN_POS, BMA150_HIGH_G_EN_MSK,
272c17ca3f5SEric Andersson BMA150_HIGH_G_EN_REG);
273c17ca3f5SEric Andersson }
274c17ca3f5SEric Andersson
275c17ca3f5SEric Andersson
bma150_set_any_motion_interrupt(struct bma150_data * bma150,u8 enable,u8 dur,u8 thres)2765298cc4cSBill Pemberton static int bma150_set_any_motion_interrupt(struct bma150_data *bma150,
277c17ca3f5SEric Andersson u8 enable, u8 dur, u8 thres)
278c17ca3f5SEric Andersson {
279c17ca3f5SEric Andersson int error;
280c17ca3f5SEric Andersson
281c17ca3f5SEric Andersson error = bma150_set_reg_bits(bma150->client, dur,
282c17ca3f5SEric Andersson BMA150_ANY_MOTION_DUR_POS,
283c17ca3f5SEric Andersson BMA150_ANY_MOTION_DUR_MSK,
284c17ca3f5SEric Andersson BMA150_ANY_MOTION_DUR_REG);
285c17ca3f5SEric Andersson if (error)
286c17ca3f5SEric Andersson return error;
287c17ca3f5SEric Andersson
288c17ca3f5SEric Andersson error = bma150_write_byte(bma150->client,
289c17ca3f5SEric Andersson BMA150_ANY_MOTION_THRES_REG, thres);
290c17ca3f5SEric Andersson if (error)
291c17ca3f5SEric Andersson return error;
292c17ca3f5SEric Andersson
293c17ca3f5SEric Andersson error = bma150_set_reg_bits(bma150->client, !!enable,
294c17ca3f5SEric Andersson BMA150_ADV_INT_EN_POS, BMA150_ADV_INT_EN_MSK,
295c17ca3f5SEric Andersson BMA150_ADV_INT_EN_REG);
296c17ca3f5SEric Andersson if (error)
297c17ca3f5SEric Andersson return error;
298c17ca3f5SEric Andersson
299c17ca3f5SEric Andersson return bma150_set_reg_bits(bma150->client, !!enable,
300c17ca3f5SEric Andersson BMA150_ANY_MOTION_EN_POS,
301c17ca3f5SEric Andersson BMA150_ANY_MOTION_EN_MSK,
302c17ca3f5SEric Andersson BMA150_ANY_MOTION_EN_REG);
303c17ca3f5SEric Andersson }
304c17ca3f5SEric Andersson
bma150_report_xyz(struct bma150_data * bma150)305c17ca3f5SEric Andersson static void bma150_report_xyz(struct bma150_data *bma150)
306c17ca3f5SEric Andersson {
307c17ca3f5SEric Andersson u8 data[BMA150_XYZ_DATA_SIZE];
308c17ca3f5SEric Andersson s16 x, y, z;
309c17ca3f5SEric Andersson s32 ret;
310c17ca3f5SEric Andersson
311c17ca3f5SEric Andersson ret = i2c_smbus_read_i2c_block_data(bma150->client,
312c17ca3f5SEric Andersson BMA150_ACC_X_LSB_REG, BMA150_XYZ_DATA_SIZE, data);
313c17ca3f5SEric Andersson if (ret != BMA150_XYZ_DATA_SIZE)
314c17ca3f5SEric Andersson return;
315c17ca3f5SEric Andersson
316c17ca3f5SEric Andersson x = ((0xc0 & data[0]) >> 6) | (data[1] << 2);
317c17ca3f5SEric Andersson y = ((0xc0 & data[2]) >> 6) | (data[3] << 2);
318c17ca3f5SEric Andersson z = ((0xc0 & data[4]) >> 6) | (data[5] << 2);
319c17ca3f5SEric Andersson
320b7e79329SMartin Kepplinger x = sign_extend32(x, 9);
321b7e79329SMartin Kepplinger y = sign_extend32(y, 9);
322b7e79329SMartin Kepplinger z = sign_extend32(z, 9);
323c17ca3f5SEric Andersson
324c17ca3f5SEric Andersson input_report_abs(bma150->input, ABS_X, x);
325c17ca3f5SEric Andersson input_report_abs(bma150->input, ABS_Y, y);
326c17ca3f5SEric Andersson input_report_abs(bma150->input, ABS_Z, z);
327c17ca3f5SEric Andersson input_sync(bma150->input);
328c17ca3f5SEric Andersson }
329c17ca3f5SEric Andersson
bma150_irq_thread(int irq,void * dev)330c17ca3f5SEric Andersson static irqreturn_t bma150_irq_thread(int irq, void *dev)
331c17ca3f5SEric Andersson {
332c17ca3f5SEric Andersson bma150_report_xyz(dev);
333c17ca3f5SEric Andersson
334c17ca3f5SEric Andersson return IRQ_HANDLED;
335c17ca3f5SEric Andersson }
336c17ca3f5SEric Andersson
bma150_poll(struct input_dev * input)337b873f73cSDmitry Torokhov static void bma150_poll(struct input_dev *input)
338c17ca3f5SEric Andersson {
339b873f73cSDmitry Torokhov struct bma150_data *bma150 = input_get_drvdata(input);
340b873f73cSDmitry Torokhov
341b873f73cSDmitry Torokhov bma150_report_xyz(bma150);
342c17ca3f5SEric Andersson }
343c17ca3f5SEric Andersson
bma150_open(struct input_dev * input)344b873f73cSDmitry Torokhov static int bma150_open(struct input_dev *input)
345c17ca3f5SEric Andersson {
346b873f73cSDmitry Torokhov struct bma150_data *bma150 = input_get_drvdata(input);
347c17ca3f5SEric Andersson int error;
348c17ca3f5SEric Andersson
349c17ca3f5SEric Andersson error = pm_runtime_get_sync(&bma150->client->dev);
35079f34d19SMichael Trimarchi if (error < 0 && error != -ENOSYS)
351c17ca3f5SEric Andersson return error;
352c17ca3f5SEric Andersson
353c17ca3f5SEric Andersson /*
354c17ca3f5SEric Andersson * See if runtime PM woke up the device. If runtime PM
355c17ca3f5SEric Andersson * is disabled we need to do it ourselves.
356c17ca3f5SEric Andersson */
357c17ca3f5SEric Andersson if (bma150->mode != BMA150_MODE_NORMAL) {
358c17ca3f5SEric Andersson error = bma150_set_mode(bma150, BMA150_MODE_NORMAL);
359c17ca3f5SEric Andersson if (error)
360c17ca3f5SEric Andersson return error;
361c17ca3f5SEric Andersson }
362c17ca3f5SEric Andersson
363c17ca3f5SEric Andersson return 0;
364c17ca3f5SEric Andersson }
365c17ca3f5SEric Andersson
bma150_close(struct input_dev * input)366b873f73cSDmitry Torokhov static void bma150_close(struct input_dev *input)
367c17ca3f5SEric Andersson {
368b873f73cSDmitry Torokhov struct bma150_data *bma150 = input_get_drvdata(input);
369b873f73cSDmitry Torokhov
370c17ca3f5SEric Andersson pm_runtime_put_sync(&bma150->client->dev);
371c17ca3f5SEric Andersson
372c17ca3f5SEric Andersson if (bma150->mode != BMA150_MODE_SLEEP)
373c17ca3f5SEric Andersson bma150_set_mode(bma150, BMA150_MODE_SLEEP);
374c17ca3f5SEric Andersson }
375c17ca3f5SEric Andersson
bma150_initialize(struct bma150_data * bma150,const struct bma150_cfg * cfg)3765298cc4cSBill Pemberton static int bma150_initialize(struct bma150_data *bma150,
377c17ca3f5SEric Andersson const struct bma150_cfg *cfg)
378c17ca3f5SEric Andersson {
379c17ca3f5SEric Andersson int error;
380c17ca3f5SEric Andersson
381c17ca3f5SEric Andersson error = bma150_soft_reset(bma150);
382c17ca3f5SEric Andersson if (error)
383c17ca3f5SEric Andersson return error;
384c17ca3f5SEric Andersson
385c17ca3f5SEric Andersson error = bma150_set_bandwidth(bma150, cfg->bandwidth);
386c17ca3f5SEric Andersson if (error)
387c17ca3f5SEric Andersson return error;
388c17ca3f5SEric Andersson
389c17ca3f5SEric Andersson error = bma150_set_range(bma150, cfg->range);
390c17ca3f5SEric Andersson if (error)
391c17ca3f5SEric Andersson return error;
392c17ca3f5SEric Andersson
393c17ca3f5SEric Andersson if (bma150->client->irq) {
394c17ca3f5SEric Andersson error = bma150_set_any_motion_interrupt(bma150,
395c17ca3f5SEric Andersson cfg->any_motion_int,
396c17ca3f5SEric Andersson cfg->any_motion_dur,
397c17ca3f5SEric Andersson cfg->any_motion_thres);
398c17ca3f5SEric Andersson if (error)
399c17ca3f5SEric Andersson return error;
400c17ca3f5SEric Andersson
401c17ca3f5SEric Andersson error = bma150_set_high_g_interrupt(bma150,
402c17ca3f5SEric Andersson cfg->hg_int, cfg->hg_hyst,
403c17ca3f5SEric Andersson cfg->hg_dur, cfg->hg_thres);
404c17ca3f5SEric Andersson if (error)
405c17ca3f5SEric Andersson return error;
406c17ca3f5SEric Andersson
407c17ca3f5SEric Andersson error = bma150_set_low_g_interrupt(bma150,
408c17ca3f5SEric Andersson cfg->lg_int, cfg->lg_hyst,
409c17ca3f5SEric Andersson cfg->lg_dur, cfg->lg_thres);
410c17ca3f5SEric Andersson if (error)
411c17ca3f5SEric Andersson return error;
412c17ca3f5SEric Andersson }
413c17ca3f5SEric Andersson
414c17ca3f5SEric Andersson return bma150_set_mode(bma150, BMA150_MODE_SLEEP);
415c17ca3f5SEric Andersson }
416c17ca3f5SEric Andersson
bma150_probe(struct i2c_client * client)4178140acffSUwe Kleine-König static int bma150_probe(struct i2c_client *client)
418c17ca3f5SEric Andersson {
419c838cb3dSJingoo Han const struct bma150_platform_data *pdata =
420c838cb3dSJingoo Han dev_get_platdata(&client->dev);
421c17ca3f5SEric Andersson const struct bma150_cfg *cfg;
422c17ca3f5SEric Andersson struct bma150_data *bma150;
423b873f73cSDmitry Torokhov struct input_dev *idev;
424c17ca3f5SEric Andersson int chip_id;
425c17ca3f5SEric Andersson int error;
426c17ca3f5SEric Andersson
427c17ca3f5SEric Andersson if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
428c17ca3f5SEric Andersson dev_err(&client->dev, "i2c_check_functionality error\n");
429c17ca3f5SEric Andersson return -EIO;
430c17ca3f5SEric Andersson }
431c17ca3f5SEric Andersson
432c17ca3f5SEric Andersson chip_id = i2c_smbus_read_byte_data(client, BMA150_CHIP_ID_REG);
433f069b5a0SH. Nikolaus Schaller if (chip_id != BMA150_CHIP_ID) {
434c17ca3f5SEric Andersson dev_err(&client->dev, "BMA150 chip id error: %d\n", chip_id);
435c17ca3f5SEric Andersson return -EINVAL;
436c17ca3f5SEric Andersson }
437c17ca3f5SEric Andersson
438493a6ebdSJonathan Bakker bma150 = devm_kzalloc(&client->dev, sizeof(*bma150), GFP_KERNEL);
439c17ca3f5SEric Andersson if (!bma150)
440c17ca3f5SEric Andersson return -ENOMEM;
441c17ca3f5SEric Andersson
442c17ca3f5SEric Andersson bma150->client = client;
443c17ca3f5SEric Andersson
444c17ca3f5SEric Andersson if (pdata) {
445c17ca3f5SEric Andersson if (pdata->irq_gpio_cfg) {
446c17ca3f5SEric Andersson error = pdata->irq_gpio_cfg();
447c17ca3f5SEric Andersson if (error) {
448c17ca3f5SEric Andersson dev_err(&client->dev,
449c17ca3f5SEric Andersson "IRQ GPIO conf. error %d, error %d\n",
450c17ca3f5SEric Andersson client->irq, error);
451493a6ebdSJonathan Bakker return error;
452c17ca3f5SEric Andersson }
453c17ca3f5SEric Andersson }
454c17ca3f5SEric Andersson cfg = &pdata->cfg;
455c17ca3f5SEric Andersson } else {
456c17ca3f5SEric Andersson cfg = &default_cfg;
457c17ca3f5SEric Andersson }
458c17ca3f5SEric Andersson
459c17ca3f5SEric Andersson error = bma150_initialize(bma150, cfg);
460c17ca3f5SEric Andersson if (error)
461493a6ebdSJonathan Bakker return error;
462c17ca3f5SEric Andersson
463b873f73cSDmitry Torokhov idev = devm_input_allocate_device(&bma150->client->dev);
464b873f73cSDmitry Torokhov if (!idev)
465b873f73cSDmitry Torokhov return -ENOMEM;
466b873f73cSDmitry Torokhov
467b873f73cSDmitry Torokhov input_set_drvdata(idev, bma150);
468b873f73cSDmitry Torokhov bma150->input = idev;
469b873f73cSDmitry Torokhov
470b873f73cSDmitry Torokhov idev->name = BMA150_DRIVER;
471b873f73cSDmitry Torokhov idev->phys = BMA150_DRIVER "/input0";
472b873f73cSDmitry Torokhov idev->id.bustype = BUS_I2C;
473b873f73cSDmitry Torokhov
474b873f73cSDmitry Torokhov idev->open = bma150_open;
475b873f73cSDmitry Torokhov idev->close = bma150_close;
476b873f73cSDmitry Torokhov
477b873f73cSDmitry Torokhov input_set_abs_params(idev, ABS_X, ABSMIN_ACC_VAL, ABSMAX_ACC_VAL, 0, 0);
478b873f73cSDmitry Torokhov input_set_abs_params(idev, ABS_Y, ABSMIN_ACC_VAL, ABSMAX_ACC_VAL, 0, 0);
479b873f73cSDmitry Torokhov input_set_abs_params(idev, ABS_Z, ABSMIN_ACC_VAL, ABSMAX_ACC_VAL, 0, 0);
480b873f73cSDmitry Torokhov
481b873f73cSDmitry Torokhov if (client->irq <= 0) {
482b873f73cSDmitry Torokhov error = input_setup_polling(idev, bma150_poll);
483c17ca3f5SEric Andersson if (error)
484493a6ebdSJonathan Bakker return error;
485c17ca3f5SEric Andersson
486b873f73cSDmitry Torokhov input_set_poll_interval(idev, BMA150_POLL_INTERVAL);
487b873f73cSDmitry Torokhov input_set_min_poll_interval(idev, BMA150_POLL_MIN);
488b873f73cSDmitry Torokhov input_set_max_poll_interval(idev, BMA150_POLL_MAX);
489b873f73cSDmitry Torokhov }
490b873f73cSDmitry Torokhov
491b873f73cSDmitry Torokhov error = input_register_device(idev);
492b873f73cSDmitry Torokhov if (error)
493b873f73cSDmitry Torokhov return error;
494b873f73cSDmitry Torokhov
495b873f73cSDmitry Torokhov if (client->irq > 0) {
496493a6ebdSJonathan Bakker error = devm_request_threaded_irq(&client->dev, client->irq,
497c17ca3f5SEric Andersson NULL, bma150_irq_thread,
498c17ca3f5SEric Andersson IRQF_TRIGGER_RISING | IRQF_ONESHOT,
499c17ca3f5SEric Andersson BMA150_DRIVER, bma150);
500c17ca3f5SEric Andersson if (error) {
501c17ca3f5SEric Andersson dev_err(&client->dev,
502c17ca3f5SEric Andersson "irq request failed %d, error %d\n",
503c17ca3f5SEric Andersson client->irq, error);
504493a6ebdSJonathan Bakker return error;
505c17ca3f5SEric Andersson }
506c17ca3f5SEric Andersson }
507c17ca3f5SEric Andersson
508c17ca3f5SEric Andersson i2c_set_clientdata(client, bma150);
509c17ca3f5SEric Andersson
510c17ca3f5SEric Andersson pm_runtime_enable(&client->dev);
511c17ca3f5SEric Andersson
512c17ca3f5SEric Andersson return 0;
513c17ca3f5SEric Andersson }
514c17ca3f5SEric Andersson
bma150_remove(struct i2c_client * client)515ed5c2f5fSUwe Kleine-König static void bma150_remove(struct i2c_client *client)
516c17ca3f5SEric Andersson {
517c17ca3f5SEric Andersson pm_runtime_disable(&client->dev);
518c17ca3f5SEric Andersson }
519c17ca3f5SEric Andersson
bma150_suspend(struct device * dev)520b873f73cSDmitry Torokhov static int __maybe_unused bma150_suspend(struct device *dev)
521c17ca3f5SEric Andersson {
522c17ca3f5SEric Andersson struct i2c_client *client = to_i2c_client(dev);
523c17ca3f5SEric Andersson struct bma150_data *bma150 = i2c_get_clientdata(client);
524c17ca3f5SEric Andersson
525c17ca3f5SEric Andersson return bma150_set_mode(bma150, BMA150_MODE_SLEEP);
526c17ca3f5SEric Andersson }
527c17ca3f5SEric Andersson
bma150_resume(struct device * dev)528b873f73cSDmitry Torokhov static int __maybe_unused bma150_resume(struct device *dev)
529c17ca3f5SEric Andersson {
530c17ca3f5SEric Andersson struct i2c_client *client = to_i2c_client(dev);
531c17ca3f5SEric Andersson struct bma150_data *bma150 = i2c_get_clientdata(client);
532c17ca3f5SEric Andersson
533c17ca3f5SEric Andersson return bma150_set_mode(bma150, BMA150_MODE_NORMAL);
534c17ca3f5SEric Andersson }
535c17ca3f5SEric Andersson
536c17ca3f5SEric Andersson static UNIVERSAL_DEV_PM_OPS(bma150_pm, bma150_suspend, bma150_resume, NULL);
537c17ca3f5SEric Andersson
538c17ca3f5SEric Andersson static const struct i2c_device_id bma150_id[] = {
539c17ca3f5SEric Andersson { "bma150", 0 },
540c17ca3f5SEric Andersson { "smb380", 0 },
541c17ca3f5SEric Andersson { "bma023", 0 },
542c17ca3f5SEric Andersson { }
543c17ca3f5SEric Andersson };
544c17ca3f5SEric Andersson
545c17ca3f5SEric Andersson MODULE_DEVICE_TABLE(i2c, bma150_id);
546c17ca3f5SEric Andersson
547c17ca3f5SEric Andersson static struct i2c_driver bma150_driver = {
548c17ca3f5SEric Andersson .driver = {
549c17ca3f5SEric Andersson .name = BMA150_DRIVER,
550c17ca3f5SEric Andersson .pm = &bma150_pm,
551c17ca3f5SEric Andersson },
552c17ca3f5SEric Andersson .class = I2C_CLASS_HWMON,
553c17ca3f5SEric Andersson .id_table = bma150_id,
554*d8bde56dSUwe Kleine-König .probe = bma150_probe,
5551cb0aa88SBill Pemberton .remove = bma150_remove,
556c17ca3f5SEric Andersson };
557c17ca3f5SEric Andersson
5581b92c1cfSAxel Lin module_i2c_driver(bma150_driver);
559c17ca3f5SEric Andersson
560c17ca3f5SEric Andersson MODULE_AUTHOR("Albert Zhang <xu.zhang@bosch-sensortec.com>");
561c17ca3f5SEric Andersson MODULE_DESCRIPTION("BMA150 driver");
562c17ca3f5SEric Andersson MODULE_LICENSE("GPL");
563