xref: /openbmc/linux/drivers/input/misc/bma150.c (revision ef3714fd)
1c17ca3f5SEric Andersson /*
2c17ca3f5SEric Andersson  * Copyright (c) 2011 Bosch Sensortec GmbH
3c17ca3f5SEric Andersson  * Copyright (c) 2011 Unixphere
4c17ca3f5SEric Andersson  *
5c17ca3f5SEric Andersson  * This driver adds support for Bosch Sensortec's digital acceleration
6c17ca3f5SEric Andersson  * sensors BMA150 and SMB380.
7c17ca3f5SEric Andersson  * The SMB380 is fully compatible with BMA150 and only differs in packaging.
8c17ca3f5SEric Andersson  *
9c17ca3f5SEric Andersson  * The datasheet for the BMA150 chip can be found here:
10c17ca3f5SEric Andersson  * http://www.bosch-sensortec.com/content/language1/downloads/BST-BMA150-DS000-07.pdf
11c17ca3f5SEric Andersson  *
12c17ca3f5SEric Andersson  * This program is free software; you can redistribute it and/or modify
13c17ca3f5SEric Andersson  * it under the terms of the GNU General Public License as published by
14c17ca3f5SEric Andersson  * the Free Software Foundation; either version 2 of the License, or
15c17ca3f5SEric Andersson  * (at your option) any later version.
16c17ca3f5SEric Andersson  *
17c17ca3f5SEric Andersson  * This program is distributed in the hope that it will be useful,
18c17ca3f5SEric Andersson  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19c17ca3f5SEric Andersson  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20c17ca3f5SEric Andersson  * GNU General Public License for more details.
21c17ca3f5SEric Andersson  *
22c17ca3f5SEric Andersson  * You should have received a copy of the GNU General Public License
23c17ca3f5SEric Andersson  * along with this program; if not, write to the Free Software
24c17ca3f5SEric Andersson  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25c17ca3f5SEric Andersson  */
26c17ca3f5SEric Andersson #include <linux/kernel.h>
27c17ca3f5SEric Andersson #include <linux/module.h>
28c17ca3f5SEric Andersson #include <linux/i2c.h>
29c17ca3f5SEric Andersson #include <linux/input.h>
30c17ca3f5SEric Andersson #include <linux/input-polldev.h>
31c17ca3f5SEric Andersson #include <linux/interrupt.h>
32c17ca3f5SEric Andersson #include <linux/delay.h>
33c17ca3f5SEric Andersson #include <linux/slab.h>
34c17ca3f5SEric Andersson #include <linux/pm.h>
35c17ca3f5SEric Andersson #include <linux/pm_runtime.h>
36c17ca3f5SEric Andersson #include <linux/bma150.h>
37c17ca3f5SEric Andersson 
38c17ca3f5SEric Andersson #define ABSMAX_ACC_VAL		0x01FF
39c17ca3f5SEric Andersson #define ABSMIN_ACC_VAL		-(ABSMAX_ACC_VAL)
40c17ca3f5SEric Andersson 
41c17ca3f5SEric Andersson /* Each axis is represented by a 2-byte data word */
42c17ca3f5SEric Andersson #define BMA150_XYZ_DATA_SIZE	6
43c17ca3f5SEric Andersson 
44c17ca3f5SEric Andersson /* Input poll interval in milliseconds */
45c17ca3f5SEric Andersson #define BMA150_POLL_INTERVAL	10
46c17ca3f5SEric Andersson #define BMA150_POLL_MAX		200
47c17ca3f5SEric Andersson #define BMA150_POLL_MIN		0
48c17ca3f5SEric Andersson 
49c17ca3f5SEric Andersson #define BMA150_MODE_NORMAL	0
50c17ca3f5SEric Andersson #define BMA150_MODE_SLEEP	2
51c17ca3f5SEric Andersson #define BMA150_MODE_WAKE_UP	3
52c17ca3f5SEric Andersson 
53c17ca3f5SEric Andersson /* Data register addresses */
54c17ca3f5SEric Andersson #define BMA150_DATA_0_REG	0x00
55c17ca3f5SEric Andersson #define BMA150_DATA_1_REG	0x01
56c17ca3f5SEric Andersson #define BMA150_DATA_2_REG	0x02
57c17ca3f5SEric Andersson 
58c17ca3f5SEric Andersson /* Control register addresses */
59c17ca3f5SEric Andersson #define BMA150_CTRL_0_REG	0x0A
60c17ca3f5SEric Andersson #define BMA150_CTRL_1_REG	0x0B
61c17ca3f5SEric Andersson #define BMA150_CTRL_2_REG	0x14
62c17ca3f5SEric Andersson #define BMA150_CTRL_3_REG	0x15
63c17ca3f5SEric Andersson 
64c17ca3f5SEric Andersson /* Configuration/Setting register addresses */
65c17ca3f5SEric Andersson #define BMA150_CFG_0_REG	0x0C
66c17ca3f5SEric Andersson #define BMA150_CFG_1_REG	0x0D
67c17ca3f5SEric Andersson #define BMA150_CFG_2_REG	0x0E
68c17ca3f5SEric Andersson #define BMA150_CFG_3_REG	0x0F
69c17ca3f5SEric Andersson #define BMA150_CFG_4_REG	0x10
70c17ca3f5SEric Andersson #define BMA150_CFG_5_REG	0x11
71c17ca3f5SEric Andersson 
72c17ca3f5SEric Andersson #define BMA150_CHIP_ID		2
73ef3714fdSDr. H. Nikolaus Schaller #define BMA180_CHIP_ID		3
74c17ca3f5SEric Andersson #define BMA150_CHIP_ID_REG	BMA150_DATA_0_REG
75c17ca3f5SEric Andersson 
76c17ca3f5SEric Andersson #define BMA150_ACC_X_LSB_REG	BMA150_DATA_2_REG
77c17ca3f5SEric Andersson 
78c17ca3f5SEric Andersson #define BMA150_SLEEP_POS	0
79c17ca3f5SEric Andersson #define BMA150_SLEEP_MSK	0x01
80c17ca3f5SEric Andersson #define BMA150_SLEEP_REG	BMA150_CTRL_0_REG
81c17ca3f5SEric Andersson 
82c17ca3f5SEric Andersson #define BMA150_BANDWIDTH_POS	0
83c17ca3f5SEric Andersson #define BMA150_BANDWIDTH_MSK	0x07
84c17ca3f5SEric Andersson #define BMA150_BANDWIDTH_REG	BMA150_CTRL_2_REG
85c17ca3f5SEric Andersson 
86c17ca3f5SEric Andersson #define BMA150_RANGE_POS	3
87c17ca3f5SEric Andersson #define BMA150_RANGE_MSK	0x18
88c17ca3f5SEric Andersson #define BMA150_RANGE_REG	BMA150_CTRL_2_REG
89c17ca3f5SEric Andersson 
90c17ca3f5SEric Andersson #define BMA150_WAKE_UP_POS	0
91c17ca3f5SEric Andersson #define BMA150_WAKE_UP_MSK	0x01
92c17ca3f5SEric Andersson #define BMA150_WAKE_UP_REG	BMA150_CTRL_3_REG
93c17ca3f5SEric Andersson 
94c17ca3f5SEric Andersson #define BMA150_SW_RES_POS	1
95c17ca3f5SEric Andersson #define BMA150_SW_RES_MSK	0x02
96c17ca3f5SEric Andersson #define BMA150_SW_RES_REG	BMA150_CTRL_0_REG
97c17ca3f5SEric Andersson 
98c17ca3f5SEric Andersson /* Any-motion interrupt register fields */
99c17ca3f5SEric Andersson #define BMA150_ANY_MOTION_EN_POS	6
100c17ca3f5SEric Andersson #define BMA150_ANY_MOTION_EN_MSK	0x40
101c17ca3f5SEric Andersson #define BMA150_ANY_MOTION_EN_REG	BMA150_CTRL_1_REG
102c17ca3f5SEric Andersson 
103c17ca3f5SEric Andersson #define BMA150_ANY_MOTION_DUR_POS	6
104c17ca3f5SEric Andersson #define BMA150_ANY_MOTION_DUR_MSK	0xC0
105c17ca3f5SEric Andersson #define BMA150_ANY_MOTION_DUR_REG	BMA150_CFG_5_REG
106c17ca3f5SEric Andersson 
107c17ca3f5SEric Andersson #define BMA150_ANY_MOTION_THRES_REG	BMA150_CFG_4_REG
108c17ca3f5SEric Andersson 
109c17ca3f5SEric Andersson /* Advanced interrupt register fields */
110c17ca3f5SEric Andersson #define BMA150_ADV_INT_EN_POS		6
111c17ca3f5SEric Andersson #define BMA150_ADV_INT_EN_MSK		0x40
112c17ca3f5SEric Andersson #define BMA150_ADV_INT_EN_REG		BMA150_CTRL_3_REG
113c17ca3f5SEric Andersson 
114c17ca3f5SEric Andersson /* High-G interrupt register fields */
115c17ca3f5SEric Andersson #define BMA150_HIGH_G_EN_POS		1
116c17ca3f5SEric Andersson #define BMA150_HIGH_G_EN_MSK		0x02
117c17ca3f5SEric Andersson #define BMA150_HIGH_G_EN_REG		BMA150_CTRL_1_REG
118c17ca3f5SEric Andersson 
119c17ca3f5SEric Andersson #define BMA150_HIGH_G_HYST_POS		3
120c17ca3f5SEric Andersson #define BMA150_HIGH_G_HYST_MSK		0x38
121c17ca3f5SEric Andersson #define BMA150_HIGH_G_HYST_REG		BMA150_CFG_5_REG
122c17ca3f5SEric Andersson 
123c17ca3f5SEric Andersson #define BMA150_HIGH_G_DUR_REG		BMA150_CFG_3_REG
124c17ca3f5SEric Andersson #define BMA150_HIGH_G_THRES_REG		BMA150_CFG_2_REG
125c17ca3f5SEric Andersson 
126c17ca3f5SEric Andersson /* Low-G interrupt register fields */
127c17ca3f5SEric Andersson #define BMA150_LOW_G_EN_POS		0
128c17ca3f5SEric Andersson #define BMA150_LOW_G_EN_MSK		0x01
129c17ca3f5SEric Andersson #define BMA150_LOW_G_EN_REG		BMA150_CTRL_1_REG
130c17ca3f5SEric Andersson 
131c17ca3f5SEric Andersson #define BMA150_LOW_G_HYST_POS		0
132c17ca3f5SEric Andersson #define BMA150_LOW_G_HYST_MSK		0x07
133c17ca3f5SEric Andersson #define BMA150_LOW_G_HYST_REG		BMA150_CFG_5_REG
134c17ca3f5SEric Andersson 
135c17ca3f5SEric Andersson #define BMA150_LOW_G_DUR_REG		BMA150_CFG_1_REG
136c17ca3f5SEric Andersson #define BMA150_LOW_G_THRES_REG		BMA150_CFG_0_REG
137c17ca3f5SEric Andersson 
138c17ca3f5SEric Andersson struct bma150_data {
139c17ca3f5SEric Andersson 	struct i2c_client *client;
140c17ca3f5SEric Andersson 	struct input_polled_dev *input_polled;
141c17ca3f5SEric Andersson 	struct input_dev *input;
142c17ca3f5SEric Andersson 	u8 mode;
143c17ca3f5SEric Andersson };
144c17ca3f5SEric Andersson 
145c17ca3f5SEric Andersson /*
146c17ca3f5SEric Andersson  * The settings for the given range, bandwidth and interrupt features
147c17ca3f5SEric Andersson  * are stated and verified by Bosch Sensortec where they are configured
148c17ca3f5SEric Andersson  * to provide a generic sensitivity performance.
149c17ca3f5SEric Andersson  */
150d6f6dfd9SBill Pemberton static struct bma150_cfg default_cfg = {
151c17ca3f5SEric Andersson 	.any_motion_int = 1,
152c17ca3f5SEric Andersson 	.hg_int = 1,
153c17ca3f5SEric Andersson 	.lg_int = 1,
154c17ca3f5SEric Andersson 	.any_motion_dur = 0,
155c17ca3f5SEric Andersson 	.any_motion_thres = 0,
156c17ca3f5SEric Andersson 	.hg_hyst = 0,
157c17ca3f5SEric Andersson 	.hg_dur = 150,
158c17ca3f5SEric Andersson 	.hg_thres = 160,
159c17ca3f5SEric Andersson 	.lg_hyst = 0,
160c17ca3f5SEric Andersson 	.lg_dur = 150,
161c17ca3f5SEric Andersson 	.lg_thres = 20,
162c17ca3f5SEric Andersson 	.range = BMA150_RANGE_2G,
163c17ca3f5SEric Andersson 	.bandwidth = BMA150_BW_50HZ
164c17ca3f5SEric Andersson };
165c17ca3f5SEric Andersson 
166c17ca3f5SEric Andersson static int bma150_write_byte(struct i2c_client *client, u8 reg, u8 val)
167c17ca3f5SEric Andersson {
168c17ca3f5SEric Andersson 	s32 ret;
169c17ca3f5SEric Andersson 
170c17ca3f5SEric Andersson 	/* As per specification, disable irq in between register writes */
171c17ca3f5SEric Andersson 	if (client->irq)
172c17ca3f5SEric Andersson 		disable_irq_nosync(client->irq);
173c17ca3f5SEric Andersson 
174c17ca3f5SEric Andersson 	ret = i2c_smbus_write_byte_data(client, reg, val);
175c17ca3f5SEric Andersson 
176c17ca3f5SEric Andersson 	if (client->irq)
177c17ca3f5SEric Andersson 		enable_irq(client->irq);
178c17ca3f5SEric Andersson 
179c17ca3f5SEric Andersson 	return ret;
180c17ca3f5SEric Andersson }
181c17ca3f5SEric Andersson 
182c17ca3f5SEric Andersson static int bma150_set_reg_bits(struct i2c_client *client,
183c17ca3f5SEric Andersson 					int val, int shift, u8 mask, u8 reg)
184c17ca3f5SEric Andersson {
185c17ca3f5SEric Andersson 	int data;
186c17ca3f5SEric Andersson 
187c17ca3f5SEric Andersson 	data = i2c_smbus_read_byte_data(client, reg);
188c17ca3f5SEric Andersson 	if (data < 0)
189c17ca3f5SEric Andersson 		return data;
190c17ca3f5SEric Andersson 
191c17ca3f5SEric Andersson 	data = (data & ~mask) | ((val << shift) & mask);
192c17ca3f5SEric Andersson 	return bma150_write_byte(client, reg, data);
193c17ca3f5SEric Andersson }
194c17ca3f5SEric Andersson 
195c17ca3f5SEric Andersson static int bma150_set_mode(struct bma150_data *bma150, u8 mode)
196c17ca3f5SEric Andersson {
197c17ca3f5SEric Andersson 	int error;
198c17ca3f5SEric Andersson 
199c17ca3f5SEric Andersson 	error = bma150_set_reg_bits(bma150->client, mode, BMA150_WAKE_UP_POS,
200c17ca3f5SEric Andersson 				BMA150_WAKE_UP_MSK, BMA150_WAKE_UP_REG);
201c17ca3f5SEric Andersson 	if (error)
202c17ca3f5SEric Andersson 		return error;
203c17ca3f5SEric Andersson 
204c17ca3f5SEric Andersson 	error = bma150_set_reg_bits(bma150->client, mode, BMA150_SLEEP_POS,
205c17ca3f5SEric Andersson 				BMA150_SLEEP_MSK, BMA150_SLEEP_REG);
206c17ca3f5SEric Andersson 	if (error)
207c17ca3f5SEric Andersson 		return error;
208c17ca3f5SEric Andersson 
209c17ca3f5SEric Andersson 	if (mode == BMA150_MODE_NORMAL)
210c17ca3f5SEric Andersson 		msleep(2);
211c17ca3f5SEric Andersson 
212c17ca3f5SEric Andersson 	bma150->mode = mode;
213c17ca3f5SEric Andersson 	return 0;
214c17ca3f5SEric Andersson }
215c17ca3f5SEric Andersson 
2165298cc4cSBill Pemberton static int bma150_soft_reset(struct bma150_data *bma150)
217c17ca3f5SEric Andersson {
218c17ca3f5SEric Andersson 	int error;
219c17ca3f5SEric Andersson 
220c17ca3f5SEric Andersson 	error = bma150_set_reg_bits(bma150->client, 1, BMA150_SW_RES_POS,
221c17ca3f5SEric Andersson 				BMA150_SW_RES_MSK, BMA150_SW_RES_REG);
222c17ca3f5SEric Andersson 	if (error)
223c17ca3f5SEric Andersson 		return error;
224c17ca3f5SEric Andersson 
225c17ca3f5SEric Andersson 	msleep(2);
226c17ca3f5SEric Andersson 	return 0;
227c17ca3f5SEric Andersson }
228c17ca3f5SEric Andersson 
2295298cc4cSBill Pemberton static int bma150_set_range(struct bma150_data *bma150, u8 range)
230c17ca3f5SEric Andersson {
231c17ca3f5SEric Andersson 	return bma150_set_reg_bits(bma150->client, range, BMA150_RANGE_POS,
232c17ca3f5SEric Andersson 				BMA150_RANGE_MSK, BMA150_RANGE_REG);
233c17ca3f5SEric Andersson }
234c17ca3f5SEric Andersson 
2355298cc4cSBill Pemberton static int bma150_set_bandwidth(struct bma150_data *bma150, u8 bw)
236c17ca3f5SEric Andersson {
237c17ca3f5SEric Andersson 	return bma150_set_reg_bits(bma150->client, bw, BMA150_BANDWIDTH_POS,
238c17ca3f5SEric Andersson 				BMA150_BANDWIDTH_MSK, BMA150_BANDWIDTH_REG);
239c17ca3f5SEric Andersson }
240c17ca3f5SEric Andersson 
2415298cc4cSBill Pemberton static int bma150_set_low_g_interrupt(struct bma150_data *bma150,
242c17ca3f5SEric Andersson 					u8 enable, u8 hyst, u8 dur, u8 thres)
243c17ca3f5SEric Andersson {
244c17ca3f5SEric Andersson 	int error;
245c17ca3f5SEric Andersson 
246c17ca3f5SEric Andersson 	error = bma150_set_reg_bits(bma150->client, hyst,
247c17ca3f5SEric Andersson 				BMA150_LOW_G_HYST_POS, BMA150_LOW_G_HYST_MSK,
248c17ca3f5SEric Andersson 				BMA150_LOW_G_HYST_REG);
249c17ca3f5SEric Andersson 	if (error)
250c17ca3f5SEric Andersson 		return error;
251c17ca3f5SEric Andersson 
252c17ca3f5SEric Andersson 	error = bma150_write_byte(bma150->client, BMA150_LOW_G_DUR_REG, dur);
253c17ca3f5SEric Andersson 	if (error)
254c17ca3f5SEric Andersson 		return error;
255c17ca3f5SEric Andersson 
256c17ca3f5SEric Andersson 	error = bma150_write_byte(bma150->client, BMA150_LOW_G_THRES_REG, thres);
257c17ca3f5SEric Andersson 	if (error)
258c17ca3f5SEric Andersson 		return error;
259c17ca3f5SEric Andersson 
260c17ca3f5SEric Andersson 	return bma150_set_reg_bits(bma150->client, !!enable,
261c17ca3f5SEric Andersson 				BMA150_LOW_G_EN_POS, BMA150_LOW_G_EN_MSK,
262c17ca3f5SEric Andersson 				BMA150_LOW_G_EN_REG);
263c17ca3f5SEric Andersson }
264c17ca3f5SEric Andersson 
2655298cc4cSBill Pemberton static int bma150_set_high_g_interrupt(struct bma150_data *bma150,
266c17ca3f5SEric Andersson 					u8 enable, u8 hyst, u8 dur, u8 thres)
267c17ca3f5SEric Andersson {
268c17ca3f5SEric Andersson 	int error;
269c17ca3f5SEric Andersson 
270c17ca3f5SEric Andersson 	error = bma150_set_reg_bits(bma150->client, hyst,
271c17ca3f5SEric Andersson 				BMA150_HIGH_G_HYST_POS, BMA150_HIGH_G_HYST_MSK,
272c17ca3f5SEric Andersson 				BMA150_HIGH_G_HYST_REG);
273c17ca3f5SEric Andersson 	if (error)
274c17ca3f5SEric Andersson 		return error;
275c17ca3f5SEric Andersson 
276c17ca3f5SEric Andersson 	error = bma150_write_byte(bma150->client,
277c17ca3f5SEric Andersson 				BMA150_HIGH_G_DUR_REG, dur);
278c17ca3f5SEric Andersson 	if (error)
279c17ca3f5SEric Andersson 		return error;
280c17ca3f5SEric Andersson 
281c17ca3f5SEric Andersson 	error = bma150_write_byte(bma150->client,
282c17ca3f5SEric Andersson 				BMA150_HIGH_G_THRES_REG, thres);
283c17ca3f5SEric Andersson 	if (error)
284c17ca3f5SEric Andersson 		return error;
285c17ca3f5SEric Andersson 
286c17ca3f5SEric Andersson 	return bma150_set_reg_bits(bma150->client, !!enable,
287c17ca3f5SEric Andersson 				BMA150_HIGH_G_EN_POS, BMA150_HIGH_G_EN_MSK,
288c17ca3f5SEric Andersson 				BMA150_HIGH_G_EN_REG);
289c17ca3f5SEric Andersson }
290c17ca3f5SEric Andersson 
291c17ca3f5SEric Andersson 
2925298cc4cSBill Pemberton static int bma150_set_any_motion_interrupt(struct bma150_data *bma150,
293c17ca3f5SEric Andersson 						u8 enable, u8 dur, u8 thres)
294c17ca3f5SEric Andersson {
295c17ca3f5SEric Andersson 	int error;
296c17ca3f5SEric Andersson 
297c17ca3f5SEric Andersson 	error = bma150_set_reg_bits(bma150->client, dur,
298c17ca3f5SEric Andersson 				BMA150_ANY_MOTION_DUR_POS,
299c17ca3f5SEric Andersson 				BMA150_ANY_MOTION_DUR_MSK,
300c17ca3f5SEric Andersson 				BMA150_ANY_MOTION_DUR_REG);
301c17ca3f5SEric Andersson 	if (error)
302c17ca3f5SEric Andersson 		return error;
303c17ca3f5SEric Andersson 
304c17ca3f5SEric Andersson 	error = bma150_write_byte(bma150->client,
305c17ca3f5SEric Andersson 				BMA150_ANY_MOTION_THRES_REG, thres);
306c17ca3f5SEric Andersson 	if (error)
307c17ca3f5SEric Andersson 		return error;
308c17ca3f5SEric Andersson 
309c17ca3f5SEric Andersson 	error = bma150_set_reg_bits(bma150->client, !!enable,
310c17ca3f5SEric Andersson 				BMA150_ADV_INT_EN_POS, BMA150_ADV_INT_EN_MSK,
311c17ca3f5SEric Andersson 				BMA150_ADV_INT_EN_REG);
312c17ca3f5SEric Andersson 	if (error)
313c17ca3f5SEric Andersson 		return error;
314c17ca3f5SEric Andersson 
315c17ca3f5SEric Andersson 	return bma150_set_reg_bits(bma150->client, !!enable,
316c17ca3f5SEric Andersson 				BMA150_ANY_MOTION_EN_POS,
317c17ca3f5SEric Andersson 				BMA150_ANY_MOTION_EN_MSK,
318c17ca3f5SEric Andersson 				BMA150_ANY_MOTION_EN_REG);
319c17ca3f5SEric Andersson }
320c17ca3f5SEric Andersson 
321c17ca3f5SEric Andersson static void bma150_report_xyz(struct bma150_data *bma150)
322c17ca3f5SEric Andersson {
323c17ca3f5SEric Andersson 	u8 data[BMA150_XYZ_DATA_SIZE];
324c17ca3f5SEric Andersson 	s16 x, y, z;
325c17ca3f5SEric Andersson 	s32 ret;
326c17ca3f5SEric Andersson 
327c17ca3f5SEric Andersson 	ret = i2c_smbus_read_i2c_block_data(bma150->client,
328c17ca3f5SEric Andersson 			BMA150_ACC_X_LSB_REG, BMA150_XYZ_DATA_SIZE, data);
329c17ca3f5SEric Andersson 	if (ret != BMA150_XYZ_DATA_SIZE)
330c17ca3f5SEric Andersson 		return;
331c17ca3f5SEric Andersson 
332c17ca3f5SEric Andersson 	x = ((0xc0 & data[0]) >> 6) | (data[1] << 2);
333c17ca3f5SEric Andersson 	y = ((0xc0 & data[2]) >> 6) | (data[3] << 2);
334c17ca3f5SEric Andersson 	z = ((0xc0 & data[4]) >> 6) | (data[5] << 2);
335c17ca3f5SEric Andersson 
336c17ca3f5SEric Andersson 	/* sign extension */
337c17ca3f5SEric Andersson 	x = (s16) (x << 6) >> 6;
338c17ca3f5SEric Andersson 	y = (s16) (y << 6) >> 6;
339c17ca3f5SEric Andersson 	z = (s16) (z << 6) >> 6;
340c17ca3f5SEric Andersson 
341c17ca3f5SEric Andersson 	input_report_abs(bma150->input, ABS_X, x);
342c17ca3f5SEric Andersson 	input_report_abs(bma150->input, ABS_Y, y);
343c17ca3f5SEric Andersson 	input_report_abs(bma150->input, ABS_Z, z);
344c17ca3f5SEric Andersson 	input_sync(bma150->input);
345c17ca3f5SEric Andersson }
346c17ca3f5SEric Andersson 
347c17ca3f5SEric Andersson static irqreturn_t bma150_irq_thread(int irq, void *dev)
348c17ca3f5SEric Andersson {
349c17ca3f5SEric Andersson 	bma150_report_xyz(dev);
350c17ca3f5SEric Andersson 
351c17ca3f5SEric Andersson 	return IRQ_HANDLED;
352c17ca3f5SEric Andersson }
353c17ca3f5SEric Andersson 
354c17ca3f5SEric Andersson static void bma150_poll(struct input_polled_dev *dev)
355c17ca3f5SEric Andersson {
356c17ca3f5SEric Andersson 	bma150_report_xyz(dev->private);
357c17ca3f5SEric Andersson }
358c17ca3f5SEric Andersson 
359c17ca3f5SEric Andersson static int bma150_open(struct bma150_data *bma150)
360c17ca3f5SEric Andersson {
361c17ca3f5SEric Andersson 	int error;
362c17ca3f5SEric Andersson 
363c17ca3f5SEric Andersson 	error = pm_runtime_get_sync(&bma150->client->dev);
36479f34d19SMichael Trimarchi 	if (error < 0 && error != -ENOSYS)
365c17ca3f5SEric Andersson 		return error;
366c17ca3f5SEric Andersson 
367c17ca3f5SEric Andersson 	/*
368c17ca3f5SEric Andersson 	 * See if runtime PM woke up the device. If runtime PM
369c17ca3f5SEric Andersson 	 * is disabled we need to do it ourselves.
370c17ca3f5SEric Andersson 	 */
371c17ca3f5SEric Andersson 	if (bma150->mode != BMA150_MODE_NORMAL) {
372c17ca3f5SEric Andersson 		error = bma150_set_mode(bma150, BMA150_MODE_NORMAL);
373c17ca3f5SEric Andersson 		if (error)
374c17ca3f5SEric Andersson 			return error;
375c17ca3f5SEric Andersson 	}
376c17ca3f5SEric Andersson 
377c17ca3f5SEric Andersson 	return 0;
378c17ca3f5SEric Andersson }
379c17ca3f5SEric Andersson 
380c17ca3f5SEric Andersson static void bma150_close(struct bma150_data *bma150)
381c17ca3f5SEric Andersson {
382c17ca3f5SEric Andersson 	pm_runtime_put_sync(&bma150->client->dev);
383c17ca3f5SEric Andersson 
384c17ca3f5SEric Andersson 	if (bma150->mode != BMA150_MODE_SLEEP)
385c17ca3f5SEric Andersson 		bma150_set_mode(bma150, BMA150_MODE_SLEEP);
386c17ca3f5SEric Andersson }
387c17ca3f5SEric Andersson 
388c17ca3f5SEric Andersson static int bma150_irq_open(struct input_dev *input)
389c17ca3f5SEric Andersson {
390c17ca3f5SEric Andersson 	struct bma150_data *bma150 = input_get_drvdata(input);
391c17ca3f5SEric Andersson 
392c17ca3f5SEric Andersson 	return bma150_open(bma150);
393c17ca3f5SEric Andersson }
394c17ca3f5SEric Andersson 
395c17ca3f5SEric Andersson static void bma150_irq_close(struct input_dev *input)
396c17ca3f5SEric Andersson {
397c17ca3f5SEric Andersson 	struct bma150_data *bma150 = input_get_drvdata(input);
398c17ca3f5SEric Andersson 
399c17ca3f5SEric Andersson 	bma150_close(bma150);
400c17ca3f5SEric Andersson }
401c17ca3f5SEric Andersson 
402c17ca3f5SEric Andersson static void bma150_poll_open(struct input_polled_dev *ipoll_dev)
403c17ca3f5SEric Andersson {
404c17ca3f5SEric Andersson 	struct bma150_data *bma150 = ipoll_dev->private;
405c17ca3f5SEric Andersson 
406c17ca3f5SEric Andersson 	bma150_open(bma150);
407c17ca3f5SEric Andersson }
408c17ca3f5SEric Andersson 
409c17ca3f5SEric Andersson static void bma150_poll_close(struct input_polled_dev *ipoll_dev)
410c17ca3f5SEric Andersson {
411c17ca3f5SEric Andersson 	struct bma150_data *bma150 = ipoll_dev->private;
412c17ca3f5SEric Andersson 
413c17ca3f5SEric Andersson 	bma150_close(bma150);
414c17ca3f5SEric Andersson }
415c17ca3f5SEric Andersson 
4165298cc4cSBill Pemberton static int bma150_initialize(struct bma150_data *bma150,
417c17ca3f5SEric Andersson 				       const struct bma150_cfg *cfg)
418c17ca3f5SEric Andersson {
419c17ca3f5SEric Andersson 	int error;
420c17ca3f5SEric Andersson 
421c17ca3f5SEric Andersson 	error = bma150_soft_reset(bma150);
422c17ca3f5SEric Andersson 	if (error)
423c17ca3f5SEric Andersson 		return error;
424c17ca3f5SEric Andersson 
425c17ca3f5SEric Andersson 	error = bma150_set_bandwidth(bma150, cfg->bandwidth);
426c17ca3f5SEric Andersson 	if (error)
427c17ca3f5SEric Andersson 		return error;
428c17ca3f5SEric Andersson 
429c17ca3f5SEric Andersson 	error = bma150_set_range(bma150, cfg->range);
430c17ca3f5SEric Andersson 	if (error)
431c17ca3f5SEric Andersson 		return error;
432c17ca3f5SEric Andersson 
433c17ca3f5SEric Andersson 	if (bma150->client->irq) {
434c17ca3f5SEric Andersson 		error = bma150_set_any_motion_interrupt(bma150,
435c17ca3f5SEric Andersson 					cfg->any_motion_int,
436c17ca3f5SEric Andersson 					cfg->any_motion_dur,
437c17ca3f5SEric Andersson 					cfg->any_motion_thres);
438c17ca3f5SEric Andersson 		if (error)
439c17ca3f5SEric Andersson 			return error;
440c17ca3f5SEric Andersson 
441c17ca3f5SEric Andersson 		error = bma150_set_high_g_interrupt(bma150,
442c17ca3f5SEric Andersson 					cfg->hg_int, cfg->hg_hyst,
443c17ca3f5SEric Andersson 					cfg->hg_dur, cfg->hg_thres);
444c17ca3f5SEric Andersson 		if (error)
445c17ca3f5SEric Andersson 			return error;
446c17ca3f5SEric Andersson 
447c17ca3f5SEric Andersson 		error = bma150_set_low_g_interrupt(bma150,
448c17ca3f5SEric Andersson 					cfg->lg_int, cfg->lg_hyst,
449c17ca3f5SEric Andersson 					cfg->lg_dur, cfg->lg_thres);
450c17ca3f5SEric Andersson 		if (error)
451c17ca3f5SEric Andersson 			return error;
452c17ca3f5SEric Andersson 	}
453c17ca3f5SEric Andersson 
454c17ca3f5SEric Andersson 	return bma150_set_mode(bma150, BMA150_MODE_SLEEP);
455c17ca3f5SEric Andersson }
456c17ca3f5SEric Andersson 
4575298cc4cSBill Pemberton static void bma150_init_input_device(struct bma150_data *bma150,
458c17ca3f5SEric Andersson 						struct input_dev *idev)
459c17ca3f5SEric Andersson {
460c17ca3f5SEric Andersson 	idev->name = BMA150_DRIVER;
461c17ca3f5SEric Andersson 	idev->phys = BMA150_DRIVER "/input0";
462c17ca3f5SEric Andersson 	idev->id.bustype = BUS_I2C;
463c17ca3f5SEric Andersson 	idev->dev.parent = &bma150->client->dev;
464c17ca3f5SEric Andersson 
465c17ca3f5SEric Andersson 	idev->evbit[0] = BIT_MASK(EV_ABS);
466c17ca3f5SEric Andersson 	input_set_abs_params(idev, ABS_X, ABSMIN_ACC_VAL, ABSMAX_ACC_VAL, 0, 0);
467c17ca3f5SEric Andersson 	input_set_abs_params(idev, ABS_Y, ABSMIN_ACC_VAL, ABSMAX_ACC_VAL, 0, 0);
468c17ca3f5SEric Andersson 	input_set_abs_params(idev, ABS_Z, ABSMIN_ACC_VAL, ABSMAX_ACC_VAL, 0, 0);
469c17ca3f5SEric Andersson }
470c17ca3f5SEric Andersson 
4715298cc4cSBill Pemberton static int bma150_register_input_device(struct bma150_data *bma150)
472c17ca3f5SEric Andersson {
473c17ca3f5SEric Andersson 	struct input_dev *idev;
474c17ca3f5SEric Andersson 	int error;
475c17ca3f5SEric Andersson 
476c17ca3f5SEric Andersson 	idev = input_allocate_device();
477c17ca3f5SEric Andersson 	if (!idev)
478c17ca3f5SEric Andersson 		return -ENOMEM;
479c17ca3f5SEric Andersson 
480c17ca3f5SEric Andersson 	bma150_init_input_device(bma150, idev);
481c17ca3f5SEric Andersson 
482c17ca3f5SEric Andersson 	idev->open = bma150_irq_open;
483c17ca3f5SEric Andersson 	idev->close = bma150_irq_close;
484c17ca3f5SEric Andersson 	input_set_drvdata(idev, bma150);
485c17ca3f5SEric Andersson 
486c17ca3f5SEric Andersson 	error = input_register_device(idev);
487c17ca3f5SEric Andersson 	if (error) {
488c17ca3f5SEric Andersson 		input_free_device(idev);
489c17ca3f5SEric Andersson 		return error;
490c17ca3f5SEric Andersson 	}
491c17ca3f5SEric Andersson 
492c17ca3f5SEric Andersson 	bma150->input = idev;
493c17ca3f5SEric Andersson 	return 0;
494c17ca3f5SEric Andersson }
495c17ca3f5SEric Andersson 
4965298cc4cSBill Pemberton static int bma150_register_polled_device(struct bma150_data *bma150)
497c17ca3f5SEric Andersson {
498c17ca3f5SEric Andersson 	struct input_polled_dev *ipoll_dev;
499c17ca3f5SEric Andersson 	int error;
500c17ca3f5SEric Andersson 
501c17ca3f5SEric Andersson 	ipoll_dev = input_allocate_polled_device();
502c17ca3f5SEric Andersson 	if (!ipoll_dev)
503c17ca3f5SEric Andersson 		return -ENOMEM;
504c17ca3f5SEric Andersson 
505c17ca3f5SEric Andersson 	ipoll_dev->private = bma150;
506c17ca3f5SEric Andersson 	ipoll_dev->open = bma150_poll_open;
507c17ca3f5SEric Andersson 	ipoll_dev->close = bma150_poll_close;
508c17ca3f5SEric Andersson 	ipoll_dev->poll = bma150_poll;
509c17ca3f5SEric Andersson 	ipoll_dev->poll_interval = BMA150_POLL_INTERVAL;
510c17ca3f5SEric Andersson 	ipoll_dev->poll_interval_min = BMA150_POLL_MIN;
511c17ca3f5SEric Andersson 	ipoll_dev->poll_interval_max = BMA150_POLL_MAX;
512c17ca3f5SEric Andersson 
513c17ca3f5SEric Andersson 	bma150_init_input_device(bma150, ipoll_dev->input);
514c17ca3f5SEric Andersson 
515c17ca3f5SEric Andersson 	error = input_register_polled_device(ipoll_dev);
516c17ca3f5SEric Andersson 	if (error) {
517c17ca3f5SEric Andersson 		input_free_polled_device(ipoll_dev);
518c17ca3f5SEric Andersson 		return error;
519c17ca3f5SEric Andersson 	}
520c17ca3f5SEric Andersson 
521c17ca3f5SEric Andersson 	bma150->input_polled = ipoll_dev;
522c17ca3f5SEric Andersson 	bma150->input = ipoll_dev->input;
523c17ca3f5SEric Andersson 
524c17ca3f5SEric Andersson 	return 0;
525c17ca3f5SEric Andersson }
526c17ca3f5SEric Andersson 
5275298cc4cSBill Pemberton static int bma150_probe(struct i2c_client *client,
528c17ca3f5SEric Andersson 				  const struct i2c_device_id *id)
529c17ca3f5SEric Andersson {
530c838cb3dSJingoo Han 	const struct bma150_platform_data *pdata =
531c838cb3dSJingoo Han 			dev_get_platdata(&client->dev);
532c17ca3f5SEric Andersson 	const struct bma150_cfg *cfg;
533c17ca3f5SEric Andersson 	struct bma150_data *bma150;
534c17ca3f5SEric Andersson 	int chip_id;
535c17ca3f5SEric Andersson 	int error;
536c17ca3f5SEric Andersson 
537c17ca3f5SEric Andersson 	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
538c17ca3f5SEric Andersson 		dev_err(&client->dev, "i2c_check_functionality error\n");
539c17ca3f5SEric Andersson 		return -EIO;
540c17ca3f5SEric Andersson 	}
541c17ca3f5SEric Andersson 
542c17ca3f5SEric Andersson 	chip_id = i2c_smbus_read_byte_data(client, BMA150_CHIP_ID_REG);
543ef3714fdSDr. H. Nikolaus Schaller 	if (chip_id != BMA150_CHIP_ID && chip_id != BMA180_CHIP_ID) {
544c17ca3f5SEric Andersson 		dev_err(&client->dev, "BMA150 chip id error: %d\n", chip_id);
545c17ca3f5SEric Andersson 		return -EINVAL;
546c17ca3f5SEric Andersson 	}
547c17ca3f5SEric Andersson 
548c17ca3f5SEric Andersson 	bma150 = kzalloc(sizeof(struct bma150_data), GFP_KERNEL);
549c17ca3f5SEric Andersson 	if (!bma150)
550c17ca3f5SEric Andersson 		return -ENOMEM;
551c17ca3f5SEric Andersson 
552c17ca3f5SEric Andersson 	bma150->client = client;
553c17ca3f5SEric Andersson 
554c17ca3f5SEric Andersson 	if (pdata) {
555c17ca3f5SEric Andersson 		if (pdata->irq_gpio_cfg) {
556c17ca3f5SEric Andersson 			error = pdata->irq_gpio_cfg();
557c17ca3f5SEric Andersson 			if (error) {
558c17ca3f5SEric Andersson 				dev_err(&client->dev,
559c17ca3f5SEric Andersson 					"IRQ GPIO conf. error %d, error %d\n",
560c17ca3f5SEric Andersson 					client->irq, error);
561c17ca3f5SEric Andersson 				goto err_free_mem;
562c17ca3f5SEric Andersson 			}
563c17ca3f5SEric Andersson 		}
564c17ca3f5SEric Andersson 		cfg = &pdata->cfg;
565c17ca3f5SEric Andersson 	} else {
566c17ca3f5SEric Andersson 		cfg = &default_cfg;
567c17ca3f5SEric Andersson 	}
568c17ca3f5SEric Andersson 
569c17ca3f5SEric Andersson 	error = bma150_initialize(bma150, cfg);
570c17ca3f5SEric Andersson 	if (error)
571c17ca3f5SEric Andersson 		goto err_free_mem;
572c17ca3f5SEric Andersson 
573c17ca3f5SEric Andersson 	if (client->irq > 0) {
574c17ca3f5SEric Andersson 		error = bma150_register_input_device(bma150);
575c17ca3f5SEric Andersson 		if (error)
576c17ca3f5SEric Andersson 			goto err_free_mem;
577c17ca3f5SEric Andersson 
578c17ca3f5SEric Andersson 		error = request_threaded_irq(client->irq,
579c17ca3f5SEric Andersson 					NULL, bma150_irq_thread,
580c17ca3f5SEric Andersson 					IRQF_TRIGGER_RISING | IRQF_ONESHOT,
581c17ca3f5SEric Andersson 					BMA150_DRIVER, bma150);
582c17ca3f5SEric Andersson 		if (error) {
583c17ca3f5SEric Andersson 			dev_err(&client->dev,
584c17ca3f5SEric Andersson 				"irq request failed %d, error %d\n",
585c17ca3f5SEric Andersson 				client->irq, error);
586c17ca3f5SEric Andersson 			input_unregister_device(bma150->input);
587c17ca3f5SEric Andersson 			goto err_free_mem;
588c17ca3f5SEric Andersson 		}
589c17ca3f5SEric Andersson 	} else {
590c17ca3f5SEric Andersson 		error = bma150_register_polled_device(bma150);
591c17ca3f5SEric Andersson 		if (error)
592c17ca3f5SEric Andersson 			goto err_free_mem;
593c17ca3f5SEric Andersson 	}
594c17ca3f5SEric Andersson 
595c17ca3f5SEric Andersson 	i2c_set_clientdata(client, bma150);
596c17ca3f5SEric Andersson 
597c17ca3f5SEric Andersson 	pm_runtime_enable(&client->dev);
598c17ca3f5SEric Andersson 
599c17ca3f5SEric Andersson 	return 0;
600c17ca3f5SEric Andersson 
601c17ca3f5SEric Andersson err_free_mem:
602c17ca3f5SEric Andersson 	kfree(bma150);
603c17ca3f5SEric Andersson 	return error;
604c17ca3f5SEric Andersson }
605c17ca3f5SEric Andersson 
606e2619cf7SBill Pemberton static int bma150_remove(struct i2c_client *client)
607c17ca3f5SEric Andersson {
608c17ca3f5SEric Andersson 	struct bma150_data *bma150 = i2c_get_clientdata(client);
609c17ca3f5SEric Andersson 
610c17ca3f5SEric Andersson 	pm_runtime_disable(&client->dev);
611c17ca3f5SEric Andersson 
612c17ca3f5SEric Andersson 	if (client->irq > 0) {
613c17ca3f5SEric Andersson 		free_irq(client->irq, bma150);
614c17ca3f5SEric Andersson 		input_unregister_device(bma150->input);
615c17ca3f5SEric Andersson 	} else {
616c17ca3f5SEric Andersson 		input_unregister_polled_device(bma150->input_polled);
617c17ca3f5SEric Andersson 		input_free_polled_device(bma150->input_polled);
618c17ca3f5SEric Andersson 	}
619c17ca3f5SEric Andersson 
620c17ca3f5SEric Andersson 	kfree(bma150);
621c17ca3f5SEric Andersson 
622c17ca3f5SEric Andersson 	return 0;
623c17ca3f5SEric Andersson }
624c17ca3f5SEric Andersson 
625c17ca3f5SEric Andersson #ifdef CONFIG_PM
626c17ca3f5SEric Andersson static int bma150_suspend(struct device *dev)
627c17ca3f5SEric Andersson {
628c17ca3f5SEric Andersson 	struct i2c_client *client = to_i2c_client(dev);
629c17ca3f5SEric Andersson 	struct bma150_data *bma150 = i2c_get_clientdata(client);
630c17ca3f5SEric Andersson 
631c17ca3f5SEric Andersson 	return bma150_set_mode(bma150, BMA150_MODE_SLEEP);
632c17ca3f5SEric Andersson }
633c17ca3f5SEric Andersson 
634c17ca3f5SEric Andersson static int bma150_resume(struct device *dev)
635c17ca3f5SEric Andersson {
636c17ca3f5SEric Andersson 	struct i2c_client *client = to_i2c_client(dev);
637c17ca3f5SEric Andersson 	struct bma150_data *bma150 = i2c_get_clientdata(client);
638c17ca3f5SEric Andersson 
639c17ca3f5SEric Andersson 	return bma150_set_mode(bma150, BMA150_MODE_NORMAL);
640c17ca3f5SEric Andersson }
641c17ca3f5SEric Andersson #endif
642c17ca3f5SEric Andersson 
643c17ca3f5SEric Andersson static UNIVERSAL_DEV_PM_OPS(bma150_pm, bma150_suspend, bma150_resume, NULL);
644c17ca3f5SEric Andersson 
645c17ca3f5SEric Andersson static const struct i2c_device_id bma150_id[] = {
646c17ca3f5SEric Andersson 	{ "bma150", 0 },
647ef3714fdSDr. H. Nikolaus Schaller 	{ "bma180", 0 },
648c17ca3f5SEric Andersson 	{ "smb380", 0 },
649c17ca3f5SEric Andersson 	{ "bma023", 0 },
650c17ca3f5SEric Andersson 	{ }
651c17ca3f5SEric Andersson };
652c17ca3f5SEric Andersson 
653c17ca3f5SEric Andersson MODULE_DEVICE_TABLE(i2c, bma150_id);
654c17ca3f5SEric Andersson 
655c17ca3f5SEric Andersson static struct i2c_driver bma150_driver = {
656c17ca3f5SEric Andersson 	.driver = {
657c17ca3f5SEric Andersson 		.owner	= THIS_MODULE,
658c17ca3f5SEric Andersson 		.name	= BMA150_DRIVER,
659c17ca3f5SEric Andersson 		.pm	= &bma150_pm,
660c17ca3f5SEric Andersson 	},
661c17ca3f5SEric Andersson 	.class		= I2C_CLASS_HWMON,
662c17ca3f5SEric Andersson 	.id_table	= bma150_id,
663c17ca3f5SEric Andersson 	.probe		= bma150_probe,
6641cb0aa88SBill Pemberton 	.remove		= bma150_remove,
665c17ca3f5SEric Andersson };
666c17ca3f5SEric Andersson 
6671b92c1cfSAxel Lin module_i2c_driver(bma150_driver);
668c17ca3f5SEric Andersson 
669c17ca3f5SEric Andersson MODULE_AUTHOR("Albert Zhang <xu.zhang@bosch-sensortec.com>");
670c17ca3f5SEric Andersson MODULE_DESCRIPTION("BMA150 driver");
671c17ca3f5SEric Andersson MODULE_LICENSE("GPL");
672