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