xref: /openbmc/linux/drivers/input/misc/bma150.c (revision d8bde56d)
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