aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/misc/inv_mpu/accel
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/misc/inv_mpu/accel')
-rw-r--r--drivers/misc/inv_mpu/accel/Kconfig133
-rw-r--r--drivers/misc/inv_mpu/accel/Makefile38
-rw-r--r--drivers/misc/inv_mpu/accel/adxl34x.c728
-rw-r--r--drivers/misc/inv_mpu/accel/bma150.c777
-rw-r--r--drivers/misc/inv_mpu/accel/bma222.c654
-rw-r--r--drivers/misc/inv_mpu/accel/bma250.c787
-rw-r--r--drivers/misc/inv_mpu/accel/cma3000.c222
-rw-r--r--drivers/misc/inv_mpu/accel/kxsd9.c264
-rw-r--r--drivers/misc/inv_mpu/accel/kxtf9.c841
-rw-r--r--drivers/misc/inv_mpu/accel/lis331.c745
-rw-r--r--drivers/misc/inv_mpu/accel/lis3dh.c728
-rw-r--r--drivers/misc/inv_mpu/accel/lsm303dlx_a.c881
-rw-r--r--drivers/misc/inv_mpu/accel/mma8450.c804
-rw-r--r--drivers/misc/inv_mpu/accel/mma845x.c713
-rw-r--r--drivers/misc/inv_mpu/accel/mpu6050.c695
-rw-r--r--drivers/misc/inv_mpu/accel/mpu6050.h28
16 files changed, 9038 insertions, 0 deletions
diff --git a/drivers/misc/inv_mpu/accel/Kconfig b/drivers/misc/inv_mpu/accel/Kconfig
new file mode 100644
index 00000000000..4e280bd876b
--- /dev/null
+++ b/drivers/misc/inv_mpu/accel/Kconfig
@@ -0,0 +1,133 @@
1menuconfig INV_SENSORS_ACCELEROMETERS
2 bool "Accelerometer Slave Sensors"
3 default y
4 ---help---
5 Say Y here to get to see options for device drivers for various
6 accelerometrs for integration with the MPU3050 or MPU6050 driver.
7 This option alone does not add any kernel code.
8
9 If you say N, all options in this submenu will be skipped and disabled.
10
11if INV_SENSORS_ACCELEROMETERS
12
13config MPU_SENSORS_ADXL34X
14 tristate "ADI adxl34x"
15 depends on MPU_SENSORS_MPU3050 || MPU_SENSORS_MPU6050B1 || MPU_SENSORS_MPU6050A2
16 help
17 This enables support for the ADI adxl345 or adxl346 accelerometers.
18 This support is for integration with the MPU3050 gyroscope device
19 driver. Only one accelerometer can be registered at a time.
20 Specifying more that one accelerometer in the board file will result
21 in runtime errors.
22
23config MPU_SENSORS_BMA222
24 tristate "Bosch BMA222"
25 depends on MPU_SENSORS_MPU3050 || MPU_SENSORS_MPU6050B1 || MPU_SENSORS_MPU6050A2
26 help
27 This enables support for the Bosch BMA222 accelerometer
28 This support is for integration with the MPU3050 gyroscope device
29 driver. Only one accelerometer can be registered at a time.
30 Specifying more that one accelerometer in the board file will result
31 in runtime errors.
32
33config MPU_SENSORS_BMA150
34 tristate "Bosch BMA150"
35 depends on MPU_SENSORS_MPU3050 || MPU_SENSORS_MPU6050B1 || MPU_SENSORS_MPU6050A2
36 help
37 This enables support for the Bosch BMA150 accelerometer
38 This support is for integration with the MPU3050 gyroscope device
39 driver. Only one accelerometer can be registered at a time.
40 Specifying more that one accelerometer in the board file will result
41 in runtime errors.
42
43config MPU_SENSORS_BMA250
44 tristate "Bosch BMA250"
45 depends on MPU_SENSORS_MPU3050 || MPU_SENSORS_MPU6050B1 || MPU_SENSORS_MPU6050A2
46 help
47 This enables support for the Bosch BMA250 accelerometer
48 This support is for integration with the MPU3050 gyroscope device
49 driver. Only one accelerometer can be registered at a time.
50 Specifying more that one accelerometer in the board file will result
51 in runtime errors.
52
53config MPU_SENSORS_KXSD9
54 tristate "Kionix KXSD9"
55 depends on MPU_SENSORS_MPU3050 || MPU_SENSORS_MPU6050B1 || MPU_SENSORS_MPU6050A2
56 help
57 This enables support for the Kionix KXSD9 accelerometer
58 This support is for integration with the MPU3050 gyroscope device
59 driver. Only one accelerometer can be registered at a time.
60 Specifying more that one accelerometer in the board file will result
61 in runtime errors.
62
63config MPU_SENSORS_KXTF9
64 tristate "Kionix KXTF9"
65 depends on MPU_SENSORS_MPU3050 || MPU_SENSORS_MPU6050B1 || MPU_SENSORS_MPU6050A2
66 help
67 This enables support for the Kionix KXFT9 accelerometer
68 This support is for integration with the MPU3050 gyroscope device
69 driver. Only one accelerometer can be registered at a time.
70 Specifying more that one accelerometer in the board file will result
71 in runtime errors.
72
73config MPU_SENSORS_LIS331DLH
74 tristate "ST lis331dlh"
75 depends on MPU_SENSORS_MPU3050 || MPU_SENSORS_MPU6050B1 || MPU_SENSORS_MPU6050A2
76 help
77 This enables support for the ST lis331dlh accelerometer
78 This support is for integration with the MPU3050 gyroscope device
79 driver. Only one accelerometer can be registered at a time.
80 Specifying more that one accelerometer in the board file will result
81 in runtime errors.
82
83config MPU_SENSORS_LIS3DH
84 tristate "ST lis3dh"
85 depends on MPU_SENSORS_MPU3050 || MPU_SENSORS_MPU6050B1 || MPU_SENSORS_MPU6050A2
86 help
87 This enables support for the ST lis3dh accelerometer
88 This support is for integration with the MPU3050 gyroscope device
89 driver. Only one accelerometer can be registered at a time.
90 Specifying more that one accelerometer in the board file will result
91 in runtime errors.
92
93config MPU_SENSORS_LSM303DLX_A
94 tristate "ST lsm303dlx"
95 depends on MPU_SENSORS_MPU3050 || MPU_SENSORS_MPU6050B1 || MPU_SENSORS_MPU6050A2
96 help
97 This enables support for the ST lsm303dlh and lsm303dlm accelerometers
98 This support is for integration with the MPU3050 gyroscope device
99 driver. Only one accelerometer can be registered at a time.
100 Specifying more that one accelerometer in the board file will result
101 in runtime errors.
102
103config MPU_SENSORS_MMA8450
104 tristate "Freescale mma8450"
105 depends on MPU_SENSORS_MPU3050 || MPU_SENSORS_MPU6050B1 || MPU_SENSORS_MPU6050A2
106 help
107 This enables support for the Freescale mma8450 accelerometer
108 This support is for integration with the MPU3050 gyroscope device
109 driver. Only one accelerometer can be registered at a time.
110 Specifying more that one accelerometer in the board file will result
111 in runtime errors.
112
113config MPU_SENSORS_MMA845X
114 tristate "Freescale mma8451/8452/8453"
115 depends on MPU_SENSORS_MPU3050 || MPU_SENSORS_MPU6050B1 || MPU_SENSORS_MPU6050A2
116 help
117 This enables support for the Freescale mma8451/8452/8453 accelerometer
118 This support is for integration with the MPU3050 gyroscope device
119 driver. Only one accelerometer can be registered at a time.
120 Specifying more that one accelerometer in the board file will result
121 in runtime errors.
122
123config MPU_SENSORS_MPU6050_ACCEL
124 tristate "MPU6050 built in accelerometer"
125 depends on MPU_SENSORS_MPU6050B1 || MPU_SENSORS_MPU6050A2
126 help
127 This enables support for the MPU6050 built in accelerometer.
128 This the built in support for integration with the MPU6050 gyroscope
129 device driver. This is the only accelerometer supported with the
130 MPU6050. Specifying another accelerometer in the board file will
131 result in runtime errors.
132
133endif
diff --git a/drivers/misc/inv_mpu/accel/Makefile b/drivers/misc/inv_mpu/accel/Makefile
new file mode 100644
index 00000000000..1f0f5bec677
--- /dev/null
+++ b/drivers/misc/inv_mpu/accel/Makefile
@@ -0,0 +1,38 @@
1#
2# Accel Slaves to MPUxxxx
3#
4obj-$(CONFIG_MPU_SENSORS_ADXL34X) += inv_mpu_adxl34x.o
5inv_mpu_adxl34x-objs += adxl34x.o
6
7obj-$(CONFIG_MPU_SENSORS_BMA150) += inv_mpu_bma150.o
8inv_mpu_bma150-objs += bma150.o
9
10obj-$(CONFIG_MPU_SENSORS_KXTF9) += inv_mpu_kxtf9.o
11inv_mpu_kxtf9-objs += kxtf9.o
12
13obj-$(CONFIG_MPU_SENSORS_BMA222) += inv_mpu_bma222.o
14inv_mpu_bma222-objs += bma222.o
15
16obj-$(CONFIG_MPU_SENSORS_BMA250) += inv_mpu_bma250.o
17inv_mpu_bma250-objs += bma250.o
18
19obj-$(CONFIG_MPU_SENSORS_KXSD9) += inv_mpu_kxsd9.o
20inv_mpu_kxsd9-objs += kxsd9.o
21
22obj-$(CONFIG_MPU_SENSORS_LIS331DLH) += inv_mpu_lis331.o
23inv_mpu_lis331-objs += lis331.o
24
25obj-$(CONFIG_MPU_SENSORS_LIS3DH) += inv_mpu_lis3dh.o
26inv_mpu_lis3dh-objs += lis3dh.o
27
28obj-$(CONFIG_MPU_SENSORS_LSM303DLX_A) += inv_mpu_lsm303dlx_a.o
29inv_mpu_lsm303dlx_a-objs += lsm303dlx_a.o
30
31obj-$(CONFIG_MPU_SENSORS_MMA8450) += inv_mpu_mma8450.o
32inv_mpu_mma8450-objs += mma8450.o
33
34obj-$(CONFIG_MPU_SENSORS_MMA845X) += inv_mpu_mma845x.o
35inv_mpu_mma845x-objs += mma845x.o
36
37EXTRA_CFLAGS += -Idrivers/misc/inv_mpu
38EXTRA_CFLAGS += -D__C99_DESIGNATED_INITIALIZER
diff --git a/drivers/misc/inv_mpu/accel/adxl34x.c b/drivers/misc/inv_mpu/accel/adxl34x.c
new file mode 100644
index 00000000000..f2bff8a7592
--- /dev/null
+++ b/drivers/misc/inv_mpu/accel/adxl34x.c
@@ -0,0 +1,728 @@
1/*
2 $License:
3 Copyright (C) 2011 InvenSense Corporation, All Rights Reserved.
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, see <http://www.gnu.org/licenses/>.
17 $
18 */
19
20/**
21 * @addtogroup ACCELDL
22 * @brief Provides the interface to setup and handle an accelerometer.
23 *
24 * @{
25 * @file adxl34x.c
26 * @brief Accelerometer setup and handling methods for AD adxl345 and
27 * adxl346.
28 */
29
30/* -------------------------------------------------------------------------- */
31
32#include <linux/i2c.h>
33#include <linux/module.h>
34#include <linux/moduleparam.h>
35#include <linux/kernel.h>
36#include <linux/errno.h>
37#include <linux/slab.h>
38#include <linux/delay.h>
39#include "mpu-dev.h"
40
41#include <log.h>
42
43#include <linux/mpu.h>
44#include "mlsl.h"
45#include "mldl_cfg.h"
46
47#undef MPL_LOG_TAG
48#define MPL_LOG_TAG "MPL-acc"
49
50/* -------------------------------------------------------------------------- */
51
52/* registers */
53#define ADXL34X_ODR_REG (0x2C)
54#define ADXL34X_PWR_REG (0x2D)
55#define ADXL34X_DATAFORMAT_REG (0x31)
56
57/* masks */
58#define ADXL34X_ODR_MASK (0x0F)
59#define ADXL34X_PWR_SLEEP_MASK (0x04)
60#define ADXL34X_PWR_MEAS_MASK (0x08)
61#define ADXL34X_DATAFORMAT_JUSTIFY_MASK (0x04)
62#define ADXL34X_DATAFORMAT_FSR_MASK (0x03)
63
64/* -------------------------------------------------------------------------- */
65
66struct adxl34x_config {
67 unsigned int odr; /** < output data rate in mHz */
68 unsigned int fsr; /** < full scale range mg */
69 unsigned int fsr_reg_mask; /** < register setting for fsr */
70};
71
72struct adxl34x_private_data {
73 struct adxl34x_config suspend; /** < suspend configuration */
74 struct adxl34x_config resume; /** < resume configuration */
75};
76
77/**
78 * @brief Set the output data rate for the particular configuration.
79 *
80 * @param mlsl_handle
81 * the handle to the serial channel the device is connected to.
82 * @param pdata
83 * a pointer to the slave platform data.
84 * @param config
85 * Config to modify with new ODR.
86 * @param apply
87 * whether to apply immediately or save the settings to be applied
88 * at the next resume.
89 * @param odr
90 * Output data rate in units of 1/1000Hz (mHz).
91 *
92 * @return INV_SUCCESS if successful or a non-zero error code.
93 */
94static int adxl34x_set_odr(void *mlsl_handle,
95 struct ext_slave_platform_data *pdata,
96 struct adxl34x_config *config,
97 int apply,
98 long odr)
99{
100 int result = INV_SUCCESS;
101 unsigned char new_odr_mask;
102
103 /* ADXL346 (Rev. A) pages 13, 24 */
104 if (odr >= 3200000) {
105 new_odr_mask = 0x0F;
106 config->odr = 3200000;
107 } else if (odr >= 1600000) {
108 new_odr_mask = 0x0E;
109 config->odr = 1600000;
110 } else if (odr >= 800000) {
111 new_odr_mask = 0x0D;
112 config->odr = 800000;
113 } else if (odr >= 400000) {
114 new_odr_mask = 0x0C;
115 config->odr = 400000;
116 } else if (odr >= 200000) {
117 new_odr_mask = 0x0B;
118 config->odr = 200000;
119 } else if (odr >= 100000) {
120 new_odr_mask = 0x0A;
121 config->odr = 100000;
122 } else if (odr >= 50000) {
123 new_odr_mask = 0x09;
124 config->odr = 50000;
125 } else if (odr >= 25000) {
126 new_odr_mask = 0x08;
127 config->odr = 25000;
128 } else if (odr >= 12500) {
129 new_odr_mask = 0x07;
130 config->odr = 12500;
131 } else if (odr >= 6250) {
132 new_odr_mask = 0x06;
133 config->odr = 6250;
134 } else if (odr >= 3130) {
135 new_odr_mask = 0x05;
136 config->odr = 3130;
137 } else if (odr >= 1560) {
138 new_odr_mask = 0x04;
139 config->odr = 1560;
140 } else if (odr >= 780) {
141 new_odr_mask = 0x03;
142 config->odr = 780;
143 } else if (odr >= 390) {
144 new_odr_mask = 0x02;
145 config->odr = 390;
146 } else if (odr >= 200) {
147 new_odr_mask = 0x01;
148 config->odr = 200;
149 } else {
150 new_odr_mask = 0x00;
151 config->odr = 100;
152 }
153
154 if (apply) {
155 unsigned char reg_odr;
156 result = inv_serial_read(mlsl_handle, pdata->address,
157 ADXL34X_ODR_REG, 1, &reg_odr);
158 if (result) {
159 LOG_RESULT_LOCATION(result);
160 return result;
161 }
162 reg_odr &= ~ADXL34X_ODR_MASK;
163 reg_odr |= new_odr_mask;
164 result = inv_serial_single_write(mlsl_handle, pdata->address,
165 ADXL34X_ODR_REG, reg_odr);
166 if (result) {
167 LOG_RESULT_LOCATION(result);
168 return result;
169 }
170 MPL_LOGV("ODR: %d mHz\n", config->odr);
171 }
172 return result;
173}
174
175/**
176 * @brief Set the full scale range of the accels
177 *
178 * @param mlsl_handle
179 * the handle to the serial channel the device is connected to.
180 * @param pdata
181 * a pointer to the slave platform data.
182 * @param config
183 * pointer to configuration.
184 * @param apply
185 * whether to apply immediately or save the settings to be applied
186 * at the next resume.
187 * @param fsr
188 * requested full scale range in milli gees (mg).
189 *
190 * @return INV_SUCCESS if successful or a non-zero error code.
191 */
192static int adxl34x_set_fsr(void *mlsl_handle,
193 struct ext_slave_platform_data *pdata,
194 struct adxl34x_config *config,
195 int apply,
196 long fsr)
197{
198 int result = INV_SUCCESS;
199
200 if (fsr <= 2000) {
201 config->fsr_reg_mask = 0x00;
202 config->fsr = 2000;
203 } else if (fsr <= 4000) {
204 config->fsr_reg_mask = 0x01;
205 config->fsr = 4000;
206 } else if (fsr <= 8000) {
207 config->fsr_reg_mask = 0x02;
208 config->fsr = 8000;
209 } else { /* 8001 -> oo */
210 config->fsr_reg_mask = 0x03;
211 config->fsr = 16000;
212 }
213
214 if (apply) {
215 unsigned char reg_df;
216 result = inv_serial_read(mlsl_handle, pdata->address,
217 ADXL34X_DATAFORMAT_REG, 1, &reg_df);
218 reg_df &= ~ADXL34X_DATAFORMAT_FSR_MASK;
219 result = inv_serial_single_write(mlsl_handle, pdata->address,
220 ADXL34X_DATAFORMAT_REG,
221 reg_df | config->fsr_reg_mask);
222 if (result) {
223 LOG_RESULT_LOCATION(result);
224 return result;
225 }
226 MPL_LOGV("FSR: %d mg\n", config->fsr);
227 }
228 return result;
229}
230
231/**
232 * @brief facility to retrieve the device configuration.
233 *
234 * @param mlsl_handle
235 * the handle to the serial channel the device is connected to.
236 * @param slave
237 * a pointer to the slave descriptor data structure.
238 * @param pdata
239 * a pointer to the slave platform data.
240 * @param data
241 * a pointer to store the returned configuration data structure.
242 *
243 * @return INV_SUCCESS if successful or a non-zero error code.
244 */
245static int adxl34x_get_config(void *mlsl_handle,
246 struct ext_slave_descr *slave,
247 struct ext_slave_platform_data *pdata,
248 struct ext_slave_config *data)
249{
250 struct adxl34x_private_data *private_data =
251 (struct adxl34x_private_data *)(pdata->private_data);
252
253 if (!data->data)
254 return INV_ERROR_INVALID_PARAMETER;
255
256 switch (data->key) {
257 case MPU_SLAVE_CONFIG_ODR_SUSPEND:
258 (*(unsigned long *)data->data) =
259 (unsigned long) private_data->suspend.odr;
260 break;
261 case MPU_SLAVE_CONFIG_ODR_RESUME:
262 (*(unsigned long *)data->data) =
263 (unsigned long) private_data->resume.odr;
264 break;
265 case MPU_SLAVE_CONFIG_FSR_SUSPEND:
266 (*(unsigned long *)data->data) =
267 (unsigned long) private_data->suspend.fsr;
268 break;
269 case MPU_SLAVE_CONFIG_FSR_RESUME:
270 (*(unsigned long *)data->data) =
271 (unsigned long) private_data->resume.fsr;
272 break;
273 case MPU_SLAVE_CONFIG_IRQ_SUSPEND:
274 case MPU_SLAVE_CONFIG_IRQ_RESUME:
275 default:
276 return INV_ERROR_FEATURE_NOT_IMPLEMENTED;
277 };
278
279 return INV_SUCCESS;
280}
281
282/**
283 * @brief device configuration facility.
284 *
285 * @param mlsl_handle
286 * the handle to the serial channel the device is connected to.
287 * @param slave
288 * a pointer to the slave descriptor data structure.
289 * @param pdata
290 * a pointer to the slave platform data.
291 * @param data
292 * a pointer to the configuration data structure.
293 *
294 * @return INV_SUCCESS if successful or a non-zero error code.
295 */
296static int adxl34x_config(void *mlsl_handle,
297 struct ext_slave_descr *slave,
298 struct ext_slave_platform_data *pdata,
299 struct ext_slave_config *data)
300{
301 struct adxl34x_private_data *private_data =
302 (struct adxl34x_private_data *)(pdata->private_data);
303
304 if (!data->data)
305 return INV_ERROR_INVALID_PARAMETER;
306
307 switch (data->key) {
308 case MPU_SLAVE_CONFIG_ODR_SUSPEND:
309 return adxl34x_set_odr(mlsl_handle, pdata,
310 &private_data->suspend,
311 data->apply,
312 *((long *)data->data));
313 case MPU_SLAVE_CONFIG_ODR_RESUME:
314 return adxl34x_set_odr(mlsl_handle, pdata,
315 &private_data->resume,
316 data->apply,
317 *((long *)data->data));
318 case MPU_SLAVE_CONFIG_FSR_SUSPEND:
319 return adxl34x_set_fsr(mlsl_handle, pdata,
320 &private_data->suspend,
321 data->apply,
322 *((long *)data->data));
323 case MPU_SLAVE_CONFIG_FSR_RESUME:
324 return adxl34x_set_fsr(mlsl_handle, pdata,
325 &private_data->resume,
326 data->apply,
327 *((long *)data->data));
328 case MPU_SLAVE_CONFIG_IRQ_SUSPEND:
329 case MPU_SLAVE_CONFIG_IRQ_RESUME:
330 default:
331 return INV_ERROR_FEATURE_NOT_IMPLEMENTED;
332 };
333 return INV_SUCCESS;
334}
335
336/**
337 * @brief suspends the device to put it in its lowest power mode.
338 *
339 * @param mlsl_handle
340 * the handle to the serial channel the device is connected to.
341 * @param slave
342 * a pointer to the slave descriptor data structure.
343 * @param pdata
344 * a pointer to the slave platform data.
345 *
346 * @return INV_SUCCESS if successful or a non-zero error code.
347 */
348static int adxl34x_suspend(void *mlsl_handle,
349 struct ext_slave_descr *slave,
350 struct ext_slave_platform_data *pdata)
351{
352 int result;
353
354 /*
355 struct adxl34x_config *suspend_config =
356 &((struct adxl34x_private_data *)pdata->private_data)->suspend;
357
358 result = adxl34x_set_odr(mlsl_handle, pdata, suspend_config,
359 true, suspend_config->odr);
360 if (result) {
361 LOG_RESULT_LOCATION(result);
362 return result;
363}
364 result = adxl34x_set_fsr(mlsl_handle, pdata, suspend_config,
365 true, suspend_config->fsr);
366 if (result) {
367 LOG_RESULT_LOCATION(result);
368 return result;
369}
370 */
371
372 /*
373 Page 25
374 When clearing the sleep bit, it is recommended that the part
375 be placed into standby mode and then set back to measurement mode
376 with a subsequent write.
377 This is done to ensure that the device is properly biased if sleep
378 mode is manually disabled; otherwise, the first few samples of data
379 after the sleep bit is cleared may have additional noise,
380 especially if the device was asleep when the bit was cleared. */
381
382 /* go in standy-by mode (suspends measurements) */
383 result = inv_serial_single_write(mlsl_handle, pdata->address,
384 ADXL34X_PWR_REG, ADXL34X_PWR_MEAS_MASK);
385 if (result) {
386 LOG_RESULT_LOCATION(result);
387 return result;
388 }
389 /* and then in sleep */
390 result = inv_serial_single_write(mlsl_handle, pdata->address,
391 ADXL34X_PWR_REG,
392 ADXL34X_PWR_MEAS_MASK | ADXL34X_PWR_SLEEP_MASK);
393 if (result) {
394 LOG_RESULT_LOCATION(result);
395 return result;
396 }
397 return result;
398}
399
400/**
401 * @brief resume the device in the proper power state given the configuration
402 * chosen.
403 *
404 * @param mlsl_handle
405 * the handle to the serial channel the device is connected to.
406 * @param slave
407 * a pointer to the slave descriptor data structure.
408 * @param pdata
409 * a pointer to the slave platform data.
410 *
411 * @return INV_SUCCESS if successful or a non-zero error code.
412 */
413static int adxl34x_resume(void *mlsl_handle,
414 struct ext_slave_descr *slave,
415 struct ext_slave_platform_data *pdata)
416{
417 int result = INV_SUCCESS;
418 struct adxl34x_config *resume_config =
419 &((struct adxl34x_private_data *)pdata->private_data)->resume;
420 unsigned char reg;
421
422 /*
423 Page 25
424 When clearing the sleep bit, it is recommended that the part
425 be placed into standby mode and then set back to measurement mode
426 with a subsequent write.
427 This is done to ensure that the device is properly biased if sleep
428 mode is manually disabled; otherwise, the first few samples of data
429 after the sleep bit is cleared may have additional noise,
430 especially if the device was asleep when the bit was cleared. */
431
432 /* remove sleep, but leave in stand-by */
433 result = inv_serial_single_write(mlsl_handle, pdata->address,
434 ADXL34X_PWR_REG, ADXL34X_PWR_MEAS_MASK);
435 if (result) {
436 LOG_RESULT_LOCATION(result);
437 return result;
438 }
439
440 result = adxl34x_set_odr(mlsl_handle, pdata, resume_config,
441 true, resume_config->odr);
442 if (result) {
443 LOG_RESULT_LOCATION(result);
444 return result;
445 }
446
447 /*
448 -> FSR
449 -> Justiy bit for Big endianess
450 -> resulution to 10 bits
451 */
452 reg = ADXL34X_DATAFORMAT_JUSTIFY_MASK;
453 reg |= resume_config->fsr_reg_mask;
454 result = inv_serial_single_write(mlsl_handle, pdata->address,
455 ADXL34X_DATAFORMAT_REG, reg);
456 if (result) {
457 LOG_RESULT_LOCATION(result);
458 return result;
459 }
460
461 /* go in measurement mode */
462 result = inv_serial_single_write(mlsl_handle, pdata->address,
463 ADXL34X_PWR_REG, 0x00);
464 if (result) {
465 LOG_RESULT_LOCATION(result);
466 return result;
467 }
468
469 /* DATA_FORMAT: full resolution of +/-2g; data is left justified */
470 result = inv_serial_single_write(mlsl_handle, pdata->address,
471 0x31, reg);
472
473 return result;
474}
475
476/**
477 * @brief one-time device driver initialization function.
478 * If the driver is built as a kernel module, this function will be
479 * called when the module is loaded in the kernel.
480 * If the driver is built-in in the kernel, this function will be
481 * called at boot time.
482 *
483 * @param mlsl_handle
484 * the handle to the serial channel the device is connected to.
485 * @param slave
486 * a pointer to the slave descriptor data structure.
487 * @param pdata
488 * a pointer to the slave platform data.
489 *
490 * @return INV_SUCCESS if successful or a non-zero error code.
491 */
492static int adxl34x_init(void *mlsl_handle,
493 struct ext_slave_descr *slave,
494 struct ext_slave_platform_data *pdata)
495{
496 int result;
497 long range;
498
499 struct adxl34x_private_data *private_data;
500 private_data = (struct adxl34x_private_data *)
501 kzalloc(sizeof(struct adxl34x_private_data), GFP_KERNEL);
502
503 if (!private_data)
504 return INV_ERROR_MEMORY_EXAUSTED;
505
506 pdata->private_data = private_data;
507
508 result = adxl34x_set_odr(mlsl_handle, pdata, &private_data->suspend,
509 false, 0);
510 if (result) {
511 LOG_RESULT_LOCATION(result);
512 return result;
513 }
514 result = adxl34x_set_odr(mlsl_handle, pdata, &private_data->resume,
515 false, 200000);
516 if (result) {
517 LOG_RESULT_LOCATION(result);
518 return result;
519 }
520
521 range = range_fixedpoint_to_long_mg(slave->range);
522 result = adxl34x_set_fsr(mlsl_handle, pdata, &private_data->suspend,
523 false, range);
524 result = adxl34x_set_fsr(mlsl_handle, pdata, &private_data->resume,
525 false, range);
526 if (result) {
527 LOG_RESULT_LOCATION(result);
528 return result;
529 }
530
531 result = adxl34x_suspend(mlsl_handle, slave, pdata);
532 if (result) {
533 LOG_RESULT_LOCATION(result);
534 return result;
535 }
536
537 return result;
538}
539
540/**
541 * @brief one-time device driver exit function.
542 * If the driver is built as a kernel module, this function will be
543 * called when the module is removed from the kernel.
544 *
545 * @param mlsl_handle
546 * the handle to the serial channel the device is connected to.
547 * @param slave
548 * a pointer to the slave descriptor data structure.
549 * @param pdata
550 * a pointer to the slave platform data.
551 *
552 * @return INV_SUCCESS if successful or a non-zero error code.
553 */
554static int adxl34x_exit(void *mlsl_handle,
555 struct ext_slave_descr *slave,
556 struct ext_slave_platform_data *pdata)
557{
558 kfree(pdata->private_data);
559 return INV_SUCCESS;
560}
561
562/**
563 * @brief read the sensor data from the device.
564 *
565 * @param mlsl_handle
566 * the handle to the serial channel the device is connected to.
567 * @param slave
568 * a pointer to the slave descriptor data structure.
569 * @param pdata
570 * a pointer to the slave platform data.
571 * @param data
572 * a buffer to store the data read.
573 *
574 * @return INV_SUCCESS if successful or a non-zero error code.
575 */
576static int adxl34x_read(void *mlsl_handle,
577 struct ext_slave_descr *slave,
578 struct ext_slave_platform_data *pdata,
579 unsigned char *data)
580{
581 int result;
582 result = inv_serial_read(mlsl_handle, pdata->address,
583 slave->read_reg, slave->read_len, data);
584 return result;
585}
586
587static struct ext_slave_descr adxl34x_descr = {
588 .init = adxl34x_init,
589 .exit = adxl34x_exit,
590 .suspend = adxl34x_suspend,
591 .resume = adxl34x_resume,
592 .read = adxl34x_read,
593 .config = adxl34x_config,
594 .get_config = adxl34x_get_config,
595 .name = "adxl34x", /* 5 or 6 */
596 .type = EXT_SLAVE_TYPE_ACCEL,
597 .id = ACCEL_ID_ADXL34X,
598 .read_reg = 0x32,
599 .read_len = 6,
600 .endian = EXT_SLAVE_LITTLE_ENDIAN,
601 .range = {2, 0},
602 .trigger = NULL,
603};
604
605static
606struct ext_slave_descr *adxl34x_get_slave_descr(void)
607{
608 return &adxl34x_descr;
609}
610
611/* -------------------------------------------------------------------------- */
612struct adxl34x_mod_private_data {
613 struct i2c_client *client;
614 struct ext_slave_platform_data *pdata;
615};
616
617static unsigned short normal_i2c[] = { I2C_CLIENT_END };
618
619static int adxl34x_mod_probe(struct i2c_client *client,
620 const struct i2c_device_id *devid)
621{
622 struct ext_slave_platform_data *pdata;
623 struct adxl34x_mod_private_data *private_data;
624 int result = 0;
625
626 dev_info(&client->adapter->dev, "%s: %s\n", __func__, devid->name);
627
628 if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
629 result = -ENODEV;
630 goto out_no_free;
631 }
632
633 pdata = client->dev.platform_data;
634 if (!pdata) {
635 dev_err(&client->adapter->dev,
636 "Missing platform data for slave %s\n", devid->name);
637 result = -EFAULT;
638 goto out_no_free;
639 }
640
641 private_data = kzalloc(sizeof(*private_data), GFP_KERNEL);
642 if (!private_data) {
643 result = -ENOMEM;
644 goto out_no_free;
645 }
646
647 i2c_set_clientdata(client, private_data);
648 private_data->client = client;
649 private_data->pdata = pdata;
650
651 result = inv_mpu_register_slave(THIS_MODULE, client, pdata,
652 adxl34x_get_slave_descr);
653 if (result) {
654 dev_err(&client->adapter->dev,
655 "Slave registration failed: %s, %d\n",
656 devid->name, result);
657 goto out_free_memory;
658 }
659
660 return result;
661
662out_free_memory:
663 kfree(private_data);
664out_no_free:
665 dev_err(&client->adapter->dev, "%s failed %d\n", __func__, result);
666 return result;
667
668}
669
670static int adxl34x_mod_remove(struct i2c_client *client)
671{
672 struct adxl34x_mod_private_data *private_data =
673 i2c_get_clientdata(client);
674
675 dev_dbg(&client->adapter->dev, "%s\n", __func__);
676
677 inv_mpu_unregister_slave(client, private_data->pdata,
678 adxl34x_get_slave_descr);
679
680 kfree(private_data);
681 return 0;
682}
683
684static const struct i2c_device_id adxl34x_mod_id[] = {
685 { "adxl34x", ACCEL_ID_ADXL34X },
686 {}
687};
688
689MODULE_DEVICE_TABLE(i2c, adxl34x_mod_id);
690
691static struct i2c_driver adxl34x_mod_driver = {
692 .class = I2C_CLASS_HWMON,
693 .probe = adxl34x_mod_probe,
694 .remove = adxl34x_mod_remove,
695 .id_table = adxl34x_mod_id,
696 .driver = {
697 .owner = THIS_MODULE,
698 .name = "adxl34x_mod",
699 },
700 .address_list = normal_i2c,
701};
702
703static int __init adxl34x_mod_init(void)
704{
705 int res = i2c_add_driver(&adxl34x_mod_driver);
706 pr_info("%s: Probe name %s\n", __func__, "adxl34x_mod");
707 if (res)
708 pr_err("%s failed\n", __func__);
709 return res;
710}
711
712static void __exit adxl34x_mod_exit(void)
713{
714 pr_info("%s\n", __func__);
715 i2c_del_driver(&adxl34x_mod_driver);
716}
717
718module_init(adxl34x_mod_init);
719module_exit(adxl34x_mod_exit);
720
721MODULE_AUTHOR("Invensense Corporation");
722MODULE_DESCRIPTION("Driver to integrate ADXL34X sensor with the MPU");
723MODULE_LICENSE("GPL");
724MODULE_ALIAS("adxl34x_mod");
725
726/**
727 * @}
728 */
diff --git a/drivers/misc/inv_mpu/accel/bma150.c b/drivers/misc/inv_mpu/accel/bma150.c
new file mode 100644
index 00000000000..745d90a6744
--- /dev/null
+++ b/drivers/misc/inv_mpu/accel/bma150.c
@@ -0,0 +1,777 @@
1/*
2 $License:
3 Copyright (C) 2011 InvenSense Corporation, All Rights Reserved.
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, see <http://www.gnu.org/licenses/>.
17 $
18 */
19
20/**
21 * @addtogroup ACCELDL
22 * @brief Provides the interface to setup and handle an accelerometer.
23 *
24 * @{
25 * @file bma150.c
26 * @brief Accelerometer setup and handling methods for Bosch BMA150.
27 */
28
29/* -------------------------------------------------------------------------- */
30#include <linux/i2c.h>
31#include <linux/module.h>
32#include <linux/moduleparam.h>
33#include <linux/kernel.h>
34#include <linux/errno.h>
35#include <linux/slab.h>
36#include <linux/delay.h>
37#include "mpu-dev.h"
38
39#include <linux/mpu.h>
40#include "mlsl.h"
41#include "mldl_cfg.h"
42
43/* -------------------------------------------------------------------------- */
44/* registers */
45#define BMA150_CTRL_REG (0x14)
46#define BMA150_INT_REG (0x15)
47#define BMA150_PWR_REG (0x0A)
48
49/* masks */
50#define BMA150_CTRL_MASK (0x18)
51#define BMA150_CTRL_MASK_ODR (0xF8)
52#define BMA150_CTRL_MASK_FSR (0xE7)
53#define BMA150_INT_MASK_WUP (0xF8)
54#define BMA150_INT_MASK_IRQ (0xDF)
55#define BMA150_PWR_MASK_SLEEP (0x01)
56#define BMA150_PWR_MASK_SOFT_RESET (0x02)
57
58/* -------------------------------------------------------------------------- */
59struct bma150_config {
60 unsigned int odr; /** < output data rate mHz */
61 unsigned int fsr; /** < full scale range mgees */
62 unsigned int irq_type; /** < type of IRQ, see bma150_set_irq */
63 unsigned char ctrl_reg; /** < control register value */
64 unsigned char int_reg; /** < interrupt control register value */
65};
66
67struct bma150_private_data {
68 struct bma150_config suspend; /** < suspend configuration */
69 struct bma150_config resume; /** < resume configuration */
70};
71
72/**
73 * @brief Simply disables the IRQ since it is not usable on BMA150 devices.
74 *
75 * @param mlsl_handle
76 * the handle to the serial channel the device is connected to.
77 * @param pdata
78 * a pointer to the slave platform data.
79 * @param config
80 * configuration to apply to, suspend or resume
81 * @param apply
82 * whether to apply immediately or save the settings to be applied
83 * at the next resume.
84 * @param irq_type
85 * the type of IRQ. Valid values are
86 * - MPU_SLAVE_IRQ_TYPE_NONE
87 * - MPU_SLAVE_IRQ_TYPE_MOTION
88 * - MPU_SLAVE_IRQ_TYPE_DATA_READY
89 * The only supported IRQ type is MPU_SLAVE_IRQ_TYPE_NONE which
90 * corresponds to disabling the IRQ completely.
91 *
92 * @return INV_SUCCESS if successful or a non-zero error code.
93 */
94static int bma150_set_irq(void *mlsl_handle,
95 struct ext_slave_platform_data *pdata,
96 struct bma150_config *config,
97 int apply,
98 long irq_type)
99{
100 int result = INV_SUCCESS;
101
102 if (irq_type != MPU_SLAVE_IRQ_TYPE_NONE)
103 return INV_ERROR_FEATURE_NOT_IMPLEMENTED;
104
105 config->irq_type = MPU_SLAVE_IRQ_TYPE_NONE;
106 config->int_reg = 0x00;
107
108 if (apply) {
109 result = inv_serial_single_write(mlsl_handle, pdata->address,
110 BMA150_CTRL_REG, config->ctrl_reg);
111 if (result) {
112 LOG_RESULT_LOCATION(result);
113 return result;
114 }
115 result = inv_serial_single_write(mlsl_handle, pdata->address,
116 BMA150_INT_REG, config->int_reg);
117 if (result) {
118 LOG_RESULT_LOCATION(result);
119 return result;
120 }
121 }
122 return result;
123}
124
125/**
126 * @brief Set the output data rate for the particular configuration.
127 *
128 * @param mlsl_handle
129 * the handle to the serial channel the device is connected to.
130 * @param pdata
131 * a pointer to the slave platform data.
132 * @param config
133 * Config to modify with new ODR.
134 * @param apply
135 * whether to apply immediately or save the settings to be applied
136 * at the next resume.
137 * @param odr
138 * Output data rate in units of 1/1000Hz (mHz).
139 *
140 * @return INV_SUCCESS if successful or a non-zero error code.
141 */
142static int bma150_set_odr(void *mlsl_handle,
143 struct ext_slave_platform_data *pdata,
144 struct bma150_config *config,
145 int apply,
146 long odr)
147{
148 unsigned char odr_bits = 0;
149 unsigned char wup_bits = 0;
150 int result = INV_SUCCESS;
151
152 if (odr > 100000) {
153 config->odr = 190000;
154 odr_bits = 0x03;
155 } else if (odr > 50000) {
156 config->odr = 100000;
157 odr_bits = 0x02;
158 } else if (odr > 25000) {
159 config->odr = 50000;
160 odr_bits = 0x01;
161 } else if (odr > 0) {
162 config->odr = 25000;
163 odr_bits = 0x00;
164 } else {
165 config->odr = 0;
166 wup_bits = 0x00;
167 }
168
169 config->int_reg &= BMA150_INT_MASK_WUP;
170 config->ctrl_reg &= BMA150_CTRL_MASK_ODR;
171 config->ctrl_reg |= odr_bits;
172
173 MPL_LOGV("ODR: %d\n", config->odr);
174 if (apply) {
175 result = inv_serial_single_write(mlsl_handle, pdata->address,
176 BMA150_CTRL_REG, config->ctrl_reg);
177 if (result) {
178 LOG_RESULT_LOCATION(result);
179 return result;
180 }
181 result = inv_serial_single_write(mlsl_handle, pdata->address,
182 BMA150_INT_REG, config->int_reg);
183 if (result) {
184 LOG_RESULT_LOCATION(result);
185 return result;
186 }
187 }
188
189 return result;
190}
191
192/**
193 * @brief Set the full scale range of the accels
194 *
195 * @param mlsl_handle
196 * the handle to the serial channel the device is connected to.
197 * @param pdata
198 * a pointer to the slave platform data.
199 * @param config
200 * pointer to configuration.
201 * @param apply
202 * whether to apply immediately or save the settings to be applied
203 * at the next resume.
204 * @param fsr
205 * requested full scale range.
206 *
207 * @return INV_SUCCESS if successful or a non-zero error code.
208 */
209static int bma150_set_fsr(void *mlsl_handle,
210 struct ext_slave_platform_data *pdata,
211 struct bma150_config *config,
212 int apply,
213 long fsr)
214{
215 unsigned char fsr_bits;
216 int result = INV_SUCCESS;
217
218 if (fsr <= 2048) {
219 fsr_bits = 0x00;
220 config->fsr = 2048;
221 } else if (fsr <= 4096) {
222 fsr_bits = 0x08;
223 config->fsr = 4096;
224 } else {
225 fsr_bits = 0x10;
226 config->fsr = 8192;
227 }
228
229 config->ctrl_reg &= BMA150_CTRL_MASK_FSR;
230 config->ctrl_reg |= fsr_bits;
231
232 MPL_LOGV("FSR: %d\n", config->fsr);
233 if (apply) {
234 result = inv_serial_single_write(mlsl_handle, pdata->address,
235 BMA150_CTRL_REG, config->ctrl_reg);
236 if (result) {
237 LOG_RESULT_LOCATION(result);
238 return result;
239 }
240 result = inv_serial_single_write(mlsl_handle, pdata->address,
241 BMA150_CTRL_REG, config->ctrl_reg);
242 if (result) {
243 LOG_RESULT_LOCATION(result);
244 return result;
245 }
246 }
247 return result;
248}
249
250/**
251 * @brief one-time device driver initialization function.
252 * If the driver is built as a kernel module, this function will be
253 * called when the module is loaded in the kernel.
254 * If the driver is built-in in the kernel, this function will be
255 * called at boot time.
256 *
257 * @param mlsl_handle
258 * the handle to the serial channel the device is connected to.
259 * @param slave
260 * a pointer to the slave descriptor data structure.
261 * @param pdata
262 * a pointer to the slave platform data.
263 *
264 * @return INV_SUCCESS if successful or a non-zero error code.
265 */
266static int bma150_init(void *mlsl_handle,
267 struct ext_slave_descr *slave,
268 struct ext_slave_platform_data *pdata)
269{
270 int result;
271 unsigned char reg;
272 long range;
273
274 struct bma150_private_data *private_data;
275 private_data = (struct bma150_private_data *)
276 kzalloc(sizeof(struct bma150_private_data), GFP_KERNEL);
277
278 if (!private_data)
279 return INV_ERROR_MEMORY_EXAUSTED;
280
281 pdata->private_data = private_data;
282
283 result = inv_serial_single_write(mlsl_handle, pdata->address,
284 BMA150_PWR_REG, BMA150_PWR_MASK_SOFT_RESET);
285 if (result) {
286 LOG_RESULT_LOCATION(result);
287 return result;
288 }
289 msleep(1);
290
291 result = inv_serial_read(mlsl_handle, pdata->address,
292 BMA150_CTRL_REG, 1, &reg);
293 if (result) {
294 LOG_RESULT_LOCATION(result);
295 return result;
296 }
297 private_data->resume.ctrl_reg = reg;
298 private_data->suspend.ctrl_reg = reg;
299
300 result = inv_serial_read(mlsl_handle, pdata->address,
301 BMA150_INT_REG, 1, &reg);
302 if (result) {
303 LOG_RESULT_LOCATION(result);
304 return result;
305 }
306 private_data->resume.int_reg = reg;
307 private_data->suspend.int_reg = reg;
308
309 result = bma150_set_odr(mlsl_handle, pdata, &private_data->suspend,
310 false, 0);
311 if (result) {
312 LOG_RESULT_LOCATION(result);
313 return result;
314 }
315 result = bma150_set_odr(mlsl_handle, pdata, &private_data->resume,
316 false, 200000);
317 if (result) {
318 LOG_RESULT_LOCATION(result);
319 return result;
320 }
321
322 range = range_fixedpoint_to_long_mg(slave->range);
323 result = bma150_set_fsr(mlsl_handle, pdata, &private_data->suspend,
324 false, range);
325 result = bma150_set_fsr(mlsl_handle, pdata, &private_data->resume,
326 false, range);
327 if (result) {
328 LOG_RESULT_LOCATION(result);
329 return result;
330 }
331
332 result = bma150_set_irq(mlsl_handle, pdata, &private_data->suspend,
333 false, MPU_SLAVE_IRQ_TYPE_NONE);
334 if (result) {
335 LOG_RESULT_LOCATION(result);
336 return result;
337 }
338 result = bma150_set_irq(mlsl_handle, pdata, &private_data->resume,
339 false, MPU_SLAVE_IRQ_TYPE_NONE);
340 if (result) {
341 LOG_RESULT_LOCATION(result);
342 return result;
343 }
344
345 result = inv_serial_single_write(mlsl_handle, pdata->address,
346 BMA150_PWR_REG, BMA150_PWR_MASK_SLEEP);
347 if (result) {
348 LOG_RESULT_LOCATION(result);
349 return result;
350 }
351
352 return result;
353}
354
355/**
356 * @brief one-time device driver exit function.
357 * If the driver is built as a kernel module, this function will be
358 * called when the module is removed from the kernel.
359 *
360 * @param mlsl_handle
361 * the handle to the serial channel the device is connected to.
362 * @param slave
363 * a pointer to the slave descriptor data structure.
364 * @param pdata
365 * a pointer to the slave platform data.
366 *
367 * @return INV_SUCCESS if successful or a non-zero error code.
368 */
369static int bma150_exit(void *mlsl_handle,
370 struct ext_slave_descr *slave,
371 struct ext_slave_platform_data *pdata)
372{
373 kfree(pdata->private_data);
374 return INV_SUCCESS;
375}
376
377/**
378 * @brief device configuration facility.
379 *
380 * @param mlsl_handle
381 * the handle to the serial channel the device is connected to.
382 * @param slave
383 * a pointer to the slave descriptor data structure.
384 * @param pdata
385 * a pointer to the slave platform data.
386 * @param data
387 * a pointer to the configuration data structure.
388 *
389 * @return INV_SUCCESS if successful or a non-zero error code.
390 */
391static int bma150_config(void *mlsl_handle,
392 struct ext_slave_descr *slave,
393 struct ext_slave_platform_data *pdata,
394 struct ext_slave_config *data)
395{
396 struct bma150_private_data *private_data =
397 (struct bma150_private_data *)(pdata->private_data);
398
399 if (!data->data)
400 return INV_ERROR_INVALID_PARAMETER;
401
402 switch (data->key) {
403 case MPU_SLAVE_CONFIG_ODR_SUSPEND:
404 return bma150_set_odr(mlsl_handle, pdata,
405 &private_data->suspend,
406 data->apply,
407 *((long *)data->data));
408 case MPU_SLAVE_CONFIG_ODR_RESUME:
409 return bma150_set_odr(mlsl_handle, pdata,
410 &private_data->resume,
411 data->apply,
412 *((long *)data->data));
413 case MPU_SLAVE_CONFIG_FSR_SUSPEND:
414 return bma150_set_fsr(mlsl_handle, pdata,
415 &private_data->suspend,
416 data->apply,
417 *((long *)data->data));
418 case MPU_SLAVE_CONFIG_FSR_RESUME:
419 return bma150_set_fsr(mlsl_handle, pdata,
420 &private_data->resume,
421 data->apply,
422 *((long *)data->data));
423 case MPU_SLAVE_CONFIG_IRQ_SUSPEND:
424 return bma150_set_irq(mlsl_handle, pdata,
425 &private_data->suspend,
426 data->apply,
427 *((long *)data->data));
428 case MPU_SLAVE_CONFIG_IRQ_RESUME:
429 return bma150_set_irq(mlsl_handle, pdata,
430 &private_data->resume,
431 data->apply,
432 *((long *)data->data));
433 default:
434 return INV_ERROR_FEATURE_NOT_IMPLEMENTED;
435 };
436 return INV_SUCCESS;
437}
438
439/**
440 * @brief facility to retrieve the device configuration.
441 *
442 * @param mlsl_handle
443 * the handle to the serial channel the device is connected to.
444 * @param slave
445 * a pointer to the slave descriptor data structure.
446 * @param pdata
447 * a pointer to the slave platform data.
448 * @param data
449 * a pointer to store the returned configuration data structure.
450 *
451 * @return INV_SUCCESS if successful or a non-zero error code.
452 */
453static int bma150_get_config(void *mlsl_handle,
454 struct ext_slave_descr *slave,
455 struct ext_slave_platform_data *pdata,
456 struct ext_slave_config *data)
457{
458 struct bma150_private_data *private_data =
459 (struct bma150_private_data *)(pdata->private_data);
460
461 if (!data->data)
462 return INV_ERROR_INVALID_PARAMETER;
463
464 switch (data->key) {
465 case MPU_SLAVE_CONFIG_ODR_SUSPEND:
466 (*(unsigned long *)data->data) =
467 (unsigned long) private_data->suspend.odr;
468 break;
469 case MPU_SLAVE_CONFIG_ODR_RESUME:
470 (*(unsigned long *)data->data) =
471 (unsigned long) private_data->resume.odr;
472 break;
473 case MPU_SLAVE_CONFIG_FSR_SUSPEND:
474 (*(unsigned long *)data->data) =
475 (unsigned long) private_data->suspend.fsr;
476 break;
477 case MPU_SLAVE_CONFIG_FSR_RESUME:
478 (*(unsigned long *)data->data) =
479 (unsigned long) private_data->resume.fsr;
480 break;
481 case MPU_SLAVE_CONFIG_IRQ_SUSPEND:
482 (*(unsigned long *)data->data) =
483 (unsigned long) private_data->suspend.irq_type;
484 break;
485 case MPU_SLAVE_CONFIG_IRQ_RESUME:
486 (*(unsigned long *)data->data) =
487 (unsigned long) private_data->resume.irq_type;
488 break;
489 default:
490 return INV_ERROR_FEATURE_NOT_IMPLEMENTED;
491 };
492
493 return INV_SUCCESS;
494}
495
496/**
497 * @brief suspends the device to put it in its lowest power mode.
498 *
499 * @param mlsl_handle
500 * the handle to the serial channel the device is connected to.
501 * @param slave
502 * a pointer to the slave descriptor data structure.
503 * @param pdata
504 * a pointer to the slave platform data.
505 *
506 * @return INV_SUCCESS if successful or a non-zero error code.
507 */
508static int bma150_suspend(void *mlsl_handle,
509 struct ext_slave_descr *slave,
510 struct ext_slave_platform_data *pdata)
511{
512 int result;
513 unsigned char ctrl_reg;
514 unsigned char int_reg;
515
516 struct bma150_private_data *private_data =
517 (struct bma150_private_data *)(pdata->private_data);
518
519 ctrl_reg = private_data->suspend.ctrl_reg;
520 int_reg = private_data->suspend.int_reg;
521
522 result = inv_serial_single_write(mlsl_handle, pdata->address,
523 BMA150_PWR_REG, BMA150_PWR_MASK_SOFT_RESET);
524 if (result) {
525 LOG_RESULT_LOCATION(result);
526 return result;
527 }
528 msleep(1);
529
530 result = inv_serial_single_write(mlsl_handle, pdata->address,
531 BMA150_CTRL_REG, ctrl_reg);
532 if (result) {
533 LOG_RESULT_LOCATION(result);
534 return result;
535 }
536 result = inv_serial_single_write(mlsl_handle, pdata->address,
537 BMA150_INT_REG, int_reg);
538 if (result) {
539 LOG_RESULT_LOCATION(result);
540 return result;
541 }
542 result = inv_serial_single_write(mlsl_handle, pdata->address,
543 BMA150_PWR_REG, BMA150_PWR_MASK_SLEEP);
544 if (result) {
545 LOG_RESULT_LOCATION(result);
546 return result;
547 }
548
549 return result;
550}
551
552/**
553 * @brief resume the device in the proper power state given the configuration
554 * chosen.
555 *
556 * @param mlsl_handle
557 * the handle to the serial channel the device is connected to.
558 * @param slave
559 * a pointer to the slave descriptor data structure.
560 * @param pdata
561 * a pointer to the slave platform data.
562 *
563 * @return INV_SUCCESS if successful or a non-zero error code.
564 */
565static int bma150_resume(void *mlsl_handle,
566 struct ext_slave_descr *slave,
567 struct ext_slave_platform_data *pdata)
568{
569 int result;
570 unsigned char ctrl_reg;
571 unsigned char int_reg;
572
573 struct bma150_private_data *private_data =
574 (struct bma150_private_data *)(pdata->private_data);
575
576 ctrl_reg = private_data->resume.ctrl_reg;
577 int_reg = private_data->resume.int_reg;
578
579 result = inv_serial_single_write(mlsl_handle, pdata->address,
580 BMA150_PWR_REG, BMA150_PWR_MASK_SOFT_RESET);
581 if (result) {
582 LOG_RESULT_LOCATION(result);
583 return result;
584 }
585 msleep(1);
586
587 result = inv_serial_single_write(mlsl_handle, pdata->address,
588 BMA150_CTRL_REG, ctrl_reg);
589 if (result) {
590 LOG_RESULT_LOCATION(result);
591 return result;
592 }
593 result = inv_serial_single_write(mlsl_handle, pdata->address,
594 BMA150_INT_REG, int_reg);
595 if (result) {
596 LOG_RESULT_LOCATION(result);
597 return result;
598 }
599
600 result = inv_serial_single_write(mlsl_handle, pdata->address,
601 BMA150_PWR_REG, 0x00);
602 if (result) {
603 LOG_RESULT_LOCATION(result);
604 return result;
605 }
606
607 return result;
608}
609
610/**
611 * @brief read the sensor data from the device.
612 *
613 * @param mlsl_handle
614 * the handle to the serial channel the device is connected to.
615 * @param slave
616 * a pointer to the slave descriptor data structure.
617 * @param pdata
618 * a pointer to the slave platform data.
619 * @param data
620 * a buffer to store the data read.
621 *
622 * @return INV_SUCCESS if successful or a non-zero error code.
623 */
624static int bma150_read(void *mlsl_handle,
625 struct ext_slave_descr *slave,
626 struct ext_slave_platform_data *pdata,
627 unsigned char *data)
628{
629 return inv_serial_read(mlsl_handle, pdata->address,
630 slave->read_reg, slave->read_len, data);
631}
632
633static struct ext_slave_descr bma150_descr = {
634 .init = bma150_init,
635 .exit = bma150_exit,
636 .suspend = bma150_suspend,
637 .resume = bma150_resume,
638 .read = bma150_read,
639 .config = bma150_config,
640 .get_config = bma150_get_config,
641 .name = "bma150",
642 .type = EXT_SLAVE_TYPE_ACCEL,
643 .id = ACCEL_ID_BMA150,
644 .read_reg = 0x02,
645 .read_len = 6,
646 .endian = EXT_SLAVE_LITTLE_ENDIAN,
647 .range = {2, 0},
648 .trigger = NULL,
649};
650
651static
652struct ext_slave_descr *bma150_get_slave_descr(void)
653{
654 return &bma150_descr;
655}
656
657/* -------------------------------------------------------------------------- */
658
659/* Platform data for the MPU */
660struct bma150_mod_private_data {
661 struct i2c_client *client;
662 struct ext_slave_platform_data *pdata;
663};
664
665static unsigned short normal_i2c[] = { I2C_CLIENT_END };
666
667static int bma150_mod_probe(struct i2c_client *client,
668 const struct i2c_device_id *devid)
669{
670 struct ext_slave_platform_data *pdata;
671 struct bma150_mod_private_data *private_data;
672 int result = 0;
673
674 dev_info(&client->adapter->dev, "%s: %s\n", __func__, devid->name);
675
676 if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
677 result = -ENODEV;
678 goto out_no_free;
679 }
680
681 pdata = client->dev.platform_data;
682 if (!pdata) {
683 dev_err(&client->adapter->dev,
684 "Missing platform data for slave %s\n", devid->name);
685 result = -EFAULT;
686 goto out_no_free;
687 }
688
689 private_data = kzalloc(sizeof(*private_data), GFP_KERNEL);
690 if (!private_data) {
691 result = -ENOMEM;
692 goto out_no_free;
693 }
694
695 i2c_set_clientdata(client, private_data);
696 private_data->client = client;
697 private_data->pdata = pdata;
698
699 result = inv_mpu_register_slave(THIS_MODULE, client, pdata,
700 bma150_get_slave_descr);
701 if (result) {
702 dev_err(&client->adapter->dev,
703 "Slave registration failed: %s, %d\n",
704 devid->name, result);
705 goto out_free_memory;
706 }
707
708 return result;
709
710out_free_memory:
711 kfree(private_data);
712out_no_free:
713 dev_err(&client->adapter->dev, "%s failed %d\n", __func__, result);
714 return result;
715
716}
717
718static int bma150_mod_remove(struct i2c_client *client)
719{
720 struct bma150_mod_private_data *private_data =
721 i2c_get_clientdata(client);
722
723 dev_dbg(&client->adapter->dev, "%s\n", __func__);
724
725 inv_mpu_unregister_slave(client, private_data->pdata,
726 bma150_get_slave_descr);
727
728 kfree(private_data);
729 return 0;
730}
731
732static const struct i2c_device_id bma150_mod_id[] = {
733 { "bma150", ACCEL_ID_BMA150 },
734 {}
735};
736
737MODULE_DEVICE_TABLE(i2c, bma150_mod_id);
738
739static struct i2c_driver bma150_mod_driver = {
740 .class = I2C_CLASS_HWMON,
741 .probe = bma150_mod_probe,
742 .remove = bma150_mod_remove,
743 .id_table = bma150_mod_id,
744 .driver = {
745 .owner = THIS_MODULE,
746 .name = "bma150_mod",
747 },
748 .address_list = normal_i2c,
749};
750
751static int __init bma150_mod_init(void)
752{
753 int res = i2c_add_driver(&bma150_mod_driver);
754 pr_info("%s: Probe name %s\n", __func__, "bma150_mod");
755 if (res)
756 pr_err("%s failed\n", __func__);
757 return res;
758}
759
760static void __exit bma150_mod_exit(void)
761{
762 pr_info("%s\n", __func__);
763 i2c_del_driver(&bma150_mod_driver);
764}
765
766module_init(bma150_mod_init);
767module_exit(bma150_mod_exit);
768
769MODULE_AUTHOR("Invensense Corporation");
770MODULE_DESCRIPTION("Driver to integrate BMA150 sensor with the MPU");
771MODULE_LICENSE("GPL");
772MODULE_ALIAS("bma150_mod");
773
774/**
775 * @}
776 */
777
diff --git a/drivers/misc/inv_mpu/accel/bma222.c b/drivers/misc/inv_mpu/accel/bma222.c
new file mode 100644
index 00000000000..e9fc99b1a62
--- /dev/null
+++ b/drivers/misc/inv_mpu/accel/bma222.c
@@ -0,0 +1,654 @@
1/*
2 $License:
3 Copyright (C) 2011 InvenSense Corporation, All Rights Reserved.
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, see <http://www.gnu.org/licenses/>.
17 $
18 */
19
20/*
21 * @addtogroup ACCELDL
22 * @brief Provides the interface to setup and handle an accelerometer.
23 *
24 * @{
25 * @file bma222.c
26 * @brief Accelerometer setup and handling methods for Bosch BMA222.
27 */
28
29/* ------------------ */
30/* - Include Files. - */
31/* ------------------ */
32
33#include <linux/i2c.h>
34#include <linux/module.h>
35#include <linux/moduleparam.h>
36#include <linux/kernel.h>
37#include <linux/errno.h>
38#include <linux/slab.h>
39#include <linux/delay.h>
40#include "mpu-dev.h"
41
42#include <linux/mpu.h>
43#include "mlsl.h"
44#include "mldl_cfg.h"
45
46/* -------------------------------------------------------------------------- */
47
48#define BMA222_STATUS_REG (0x0A)
49#define BMA222_FSR_REG (0x0F)
50#define ADXL34X_ODR_REG (0x10)
51#define BMA222_PWR_REG (0x11)
52#define BMA222_SOFTRESET_REG (0x14)
53
54#define BMA222_STATUS_RDY_MASK (0x80)
55#define BMA222_FSR_MASK (0x0F)
56#define BMA222_ODR_MASK (0x1F)
57#define BMA222_PWR_SLEEP_MASK (0x80)
58#define BMA222_PWR_AWAKE_MASK (0x00)
59#define BMA222_SOFTRESET_MASK (0xB6)
60#define BMA222_SOFTRESET_MASK (0xB6)
61
62/* -------------------------------------------------------------------------- */
63
64struct bma222_config {
65 unsigned int odr; /** < output data rate in mHz */
66 unsigned int fsr; /** < full scale range mg */
67};
68
69struct bma222_private_data {
70 struct bma222_config suspend; /** < suspend configuration */
71 struct bma222_config resume; /** < resume configuration */
72};
73
74
75/* -------------------------------------------------------------------------- */
76
77/**
78 * @brief Set the output data rate for the particular configuration.
79 *
80 * @param mlsl_handle
81 * the handle to the serial channel the device is connected to.
82 * @param pdata
83 * a pointer to the slave platform data.
84 * @param config
85 * Config to modify with new ODR.
86 * @param apply
87 * whether to apply immediately or save the settings to be applied
88 * at the next resume.
89 * @param odr
90 * Output data rate in units of 1/1000Hz (mHz).
91 *
92 * @return INV_SUCCESS if successful or a non-zero error code.
93 */
94static int bma222_set_odr(void *mlsl_handle,
95 struct ext_slave_platform_data *pdata,
96 struct bma222_config *config,
97 int apply,
98 long odr)
99{
100 int result = INV_SUCCESS;
101 unsigned char reg_odr;
102
103 if (odr >= 1000000) {
104 reg_odr = 0x0F;
105 config->odr = 1000000;
106 } else if (odr >= 500000) {
107 reg_odr = 0x0E;
108 config->odr = 500000;
109 } else if (odr >= 250000) {
110 reg_odr = 0x0D;
111 config->odr = 250000;
112 } else if (odr >= 125000) {
113 reg_odr = 0x0C;
114 config->odr = 125000;
115 } else if (odr >= 62500) {
116 reg_odr = 0x0B;
117 config->odr = 62500;
118 } else if (odr >= 32000) {
119 reg_odr = 0x0A;
120 config->odr = 32000;
121 } else if (odr >= 16000) {
122 reg_odr = 0x09;
123 config->odr = 16000;
124 } else {
125 reg_odr = 0x08;
126 config->odr = 8000;
127 }
128
129 if (apply) {
130 MPL_LOGV("ODR: %d\n", config->odr);
131 result = inv_serial_single_write(mlsl_handle, pdata->address,
132 ADXL34X_ODR_REG, reg_odr);
133 if (result) {
134 LOG_RESULT_LOCATION(result);
135 return result;
136 }
137 }
138 return result;
139}
140
141/**
142 * @brief Set the full scale range of the accels
143 *
144 * @param mlsl_handle
145 * the handle to the serial channel the device is connected to.
146 * @param pdata
147 * a pointer to the slave platform data.
148 * @param config
149 * pointer to configuration.
150 * @param apply
151 * whether to apply immediately or save the settings to be applied
152 * at the next resume.
153 * @param fsr
154 * requested full scale range.
155 *
156 * @return INV_SUCCESS if successful or a non-zero error code.
157 */
158static int bma222_set_fsr(void *mlsl_handle,
159 struct ext_slave_platform_data *pdata,
160 struct bma222_config *config,
161 int apply,
162 long fsr)
163{
164 int result = INV_SUCCESS;
165 unsigned char reg_fsr_mask;
166
167 if (fsr <= 2000) {
168 reg_fsr_mask = 0x03;
169 config->fsr = 2000;
170 } else if (fsr <= 4000) {
171 reg_fsr_mask = 0x05;
172 config->fsr = 4000;
173 } else if (fsr <= 8000) {
174 reg_fsr_mask = 0x08;
175 config->fsr = 8000;
176 } else { /* 8001 -> oo */
177 reg_fsr_mask = 0x0C;
178 config->fsr = 16000;
179 }
180
181 if (apply) {
182 MPL_LOGV("FSR: %d\n", config->fsr);
183 result = inv_serial_single_write(mlsl_handle, pdata->address,
184 BMA222_FSR_REG, reg_fsr_mask);
185 if (result) {
186 LOG_RESULT_LOCATION(result);
187 return result;
188 }
189 }
190 return result;
191}
192
193/**
194 * @brief one-time device driver initialization function.
195 * If the driver is built as a kernel module, this function will be
196 * called when the module is loaded in the kernel.
197 * If the driver is built-in in the kernel, this function will be
198 * called at boot time.
199 *
200 * @param mlsl_handle
201 * the handle to the serial channel the device is connected to.
202 * @param slave
203 * a pointer to the slave descriptor data structure.
204 * @param pdata
205 * a pointer to the slave platform data.
206 *
207 * @return INV_SUCCESS if successful or a non-zero error code.
208 */
209static int bma222_init(void *mlsl_handle,
210 struct ext_slave_descr *slave,
211 struct ext_slave_platform_data *pdata)
212{
213 int result;
214
215 struct bma222_private_data *private_data;
216 private_data = (struct bma222_private_data *)
217 kzalloc(sizeof(struct bma222_private_data), GFP_KERNEL);
218
219 if (!private_data)
220 return INV_ERROR_MEMORY_EXAUSTED;
221
222 pdata->private_data = private_data;
223
224 result = inv_serial_single_write(mlsl_handle, pdata->address,
225 BMA222_SOFTRESET_REG, BMA222_SOFTRESET_MASK);
226 if (result) {
227 LOG_RESULT_LOCATION(result);
228 return result;
229 }
230 msleep(1);
231
232 result = bma222_set_odr(mlsl_handle, pdata, &private_data->suspend,
233 false, 0);
234 if (result) {
235 LOG_RESULT_LOCATION(result);
236 return result;
237 }
238 result = bma222_set_odr(mlsl_handle, pdata, &private_data->resume,
239 false, 200000);
240 if (result) {
241 LOG_RESULT_LOCATION(result);
242 return result;
243 }
244
245 result = bma222_set_fsr(mlsl_handle, pdata, &private_data->suspend,
246 false, 2000);
247 result = bma222_set_fsr(mlsl_handle, pdata, &private_data->resume,
248 false, 2000);
249 if (result) {
250 LOG_RESULT_LOCATION(result);
251 return result;
252 }
253
254 result = inv_serial_single_write(mlsl_handle, pdata->address,
255 BMA222_PWR_REG, BMA222_PWR_SLEEP_MASK);
256 if (result) {
257 LOG_RESULT_LOCATION(result);
258 return result;
259 }
260
261 return result;
262}
263
264/**
265 * @brief one-time device driver exit function.
266 * If the driver is built as a kernel module, this function will be
267 * called when the module is removed from the kernel.
268 *
269 * @param mlsl_handle
270 * the handle to the serial channel the device is connected to.
271 * @param slave
272 * a pointer to the slave descriptor data structure.
273 * @param pdata
274 * a pointer to the slave platform data.
275 *
276 * @return INV_SUCCESS if successful or a non-zero error code.
277 */
278static int bma222_exit(void *mlsl_handle,
279 struct ext_slave_descr *slave,
280 struct ext_slave_platform_data *pdata)
281{
282 kfree(pdata->private_data);
283 return INV_SUCCESS;
284}
285
286
287/**
288 * @brief facility to retrieve the device configuration.
289 *
290 * @param mlsl_handle
291 * the handle to the serial channel the device is connected to.
292 * @param slave
293 * a pointer to the slave descriptor data structure.
294 * @param pdata
295 * a pointer to the slave platform data.
296 * @param data
297 * a pointer to store the returned configuration data structure.
298 *
299 * @return INV_SUCCESS if successful or a non-zero error code.
300 */
301static int bma222_get_config(void *mlsl_handle,
302 struct ext_slave_descr *slave,
303 struct ext_slave_platform_data *pdata,
304 struct ext_slave_config *data)
305{
306 struct bma222_private_data *private_data =
307 (struct bma222_private_data *)(pdata->private_data);
308
309 if (!data->data)
310 return INV_ERROR_INVALID_PARAMETER;
311
312 switch (data->key) {
313 case MPU_SLAVE_CONFIG_ODR_SUSPEND:
314 (*(unsigned long *)data->data) =
315 (unsigned long) private_data->suspend.odr;
316 break;
317 case MPU_SLAVE_CONFIG_ODR_RESUME:
318 (*(unsigned long *)data->data) =
319 (unsigned long) private_data->resume.odr;
320 break;
321 case MPU_SLAVE_CONFIG_FSR_SUSPEND:
322 (*(unsigned long *)data->data) =
323 (unsigned long) private_data->suspend.fsr;
324 break;
325 case MPU_SLAVE_CONFIG_FSR_RESUME:
326 (*(unsigned long *)data->data) =
327 (unsigned long) private_data->resume.fsr;
328 break;
329 case MPU_SLAVE_CONFIG_IRQ_SUSPEND:
330 case MPU_SLAVE_CONFIG_IRQ_RESUME:
331 default:
332 return INV_ERROR_FEATURE_NOT_IMPLEMENTED;
333 };
334
335 return INV_SUCCESS;
336}
337
338/**
339 * @brief device configuration facility.
340 *
341 * @param mlsl_handle
342 * the handle to the serial channel the device is connected to.
343 * @param slave
344 * a pointer to the slave descriptor data structure.
345 * @param pdata
346 * a pointer to the slave platform data.
347 * @param data
348 * a pointer to the configuration data structure.
349 *
350 * @return INV_SUCCESS if successful or a non-zero error code.
351 */
352static int bma222_config(void *mlsl_handle,
353 struct ext_slave_descr *slave,
354 struct ext_slave_platform_data *pdata,
355 struct ext_slave_config *data)
356{
357 struct bma222_private_data *private_data =
358 (struct bma222_private_data *)(pdata->private_data);
359
360 if (!data->data)
361 return INV_ERROR_INVALID_PARAMETER;
362
363 switch (data->key) {
364 case MPU_SLAVE_CONFIG_ODR_SUSPEND:
365 return bma222_set_odr(mlsl_handle, pdata,
366 &private_data->suspend,
367 data->apply,
368 *((long *)data->data));
369 case MPU_SLAVE_CONFIG_ODR_RESUME:
370 return bma222_set_odr(mlsl_handle, pdata,
371 &private_data->resume,
372 data->apply,
373 *((long *)data->data));
374 case MPU_SLAVE_CONFIG_FSR_SUSPEND:
375 return bma222_set_fsr(mlsl_handle, pdata,
376 &private_data->suspend,
377 data->apply,
378 *((long *)data->data));
379 case MPU_SLAVE_CONFIG_FSR_RESUME:
380 return bma222_set_fsr(mlsl_handle, pdata,
381 &private_data->resume,
382 data->apply,
383 *((long *)data->data));
384 case MPU_SLAVE_CONFIG_IRQ_SUSPEND:
385 case MPU_SLAVE_CONFIG_IRQ_RESUME:
386 default:
387 return INV_ERROR_FEATURE_NOT_IMPLEMENTED;
388 };
389 return INV_SUCCESS;
390}
391
392/**
393 * @brief suspends the device to put it in its lowest power mode.
394 *
395 * @param mlsl_handle
396 * the handle to the serial channel the device is connected to.
397 * @param slave
398 * a pointer to the slave descriptor data structure.
399 * @param pdata
400 * a pointer to the slave platform data.
401 *
402 * @return INV_SUCCESS if successful or a non-zero error code.
403 */
404static int bma222_suspend(void *mlsl_handle,
405 struct ext_slave_descr *slave,
406 struct ext_slave_platform_data *pdata)
407{
408 int result;
409 struct bma222_config *suspend_config =
410 &((struct bma222_private_data *)pdata->private_data)->suspend;
411
412 result = bma222_set_odr(mlsl_handle, pdata, suspend_config,
413 true, suspend_config->odr);
414 if (result) {
415 LOG_RESULT_LOCATION(result);
416 return result;
417 }
418 result = bma222_set_fsr(mlsl_handle, pdata, suspend_config,
419 true, suspend_config->fsr);
420 if (result) {
421 LOG_RESULT_LOCATION(result);
422 return result;
423 }
424
425 result = inv_serial_single_write(mlsl_handle, pdata->address,
426 BMA222_PWR_REG, BMA222_PWR_SLEEP_MASK);
427 if (result) {
428 LOG_RESULT_LOCATION(result);
429 return result;
430 }
431
432 msleep(3); /* 3 ms powerup time maximum */
433 return result;
434}
435
436/**
437 * @brief resume the device in the proper power state given the configuration
438 * chosen.
439 *
440 * @param mlsl_handle
441 * the handle to the serial channel the device is connected to.
442 * @param slave
443 * a pointer to the slave descriptor data structure.
444 * @param pdata
445 * a pointer to the slave platform data.
446 *
447 * @return INV_SUCCESS if successful or a non-zero error code.
448 */
449static int bma222_resume(void *mlsl_handle,
450 struct ext_slave_descr *slave,
451 struct ext_slave_platform_data *pdata)
452{
453 int result;
454 struct bma222_config *resume_config =
455 &((struct bma222_private_data *)pdata->private_data)->resume;
456
457 /* Soft reset */
458 result = inv_serial_single_write(mlsl_handle, pdata->address,
459 BMA222_SOFTRESET_REG, BMA222_SOFTRESET_MASK);
460 if (result) {
461 LOG_RESULT_LOCATION(result);
462 return result;
463 }
464 msleep(10);
465
466 result = bma222_set_odr(mlsl_handle, pdata, resume_config,
467 true, resume_config->odr);
468 if (result) {
469 LOG_RESULT_LOCATION(result);
470 return result;
471 }
472 result = bma222_set_fsr(mlsl_handle, pdata, resume_config,
473 true, resume_config->fsr);
474 if (result) {
475 LOG_RESULT_LOCATION(result);
476 return result;
477 }
478
479 return result;
480}
481
482/**
483 * @brief read the sensor data from the device.
484 *
485 * @param mlsl_handle
486 * the handle to the serial channel the device is connected to.
487 * @param slave
488 * a pointer to the slave descriptor data structure.
489 * @param pdata
490 * a pointer to the slave platform data.
491 * @param data
492 * a buffer to store the data read.
493 *
494 * @return INV_SUCCESS if successful or a non-zero error code.
495 */
496static int bma222_read(void *mlsl_handle,
497 struct ext_slave_descr *slave,
498 struct ext_slave_platform_data *pdata,
499 unsigned char *data)
500{
501 int result = INV_SUCCESS;
502 result = inv_serial_read(mlsl_handle, pdata->address,
503 BMA222_STATUS_REG, 1, data);
504 if (data[0] & BMA222_STATUS_RDY_MASK) {
505 result = inv_serial_read(mlsl_handle, pdata->address,
506 slave->read_reg, slave->read_len, data);
507 return result;
508 } else
509 return INV_ERROR_ACCEL_DATA_NOT_READY;
510}
511
512static struct ext_slave_descr bma222_descr = {
513 .init = bma222_init,
514 .exit = bma222_exit,
515 .suspend = bma222_suspend,
516 .resume = bma222_resume,
517 .read = bma222_read,
518 .config = bma222_config,
519 .get_config = bma222_get_config,
520 .name = "bma222",
521 .type = EXT_SLAVE_TYPE_ACCEL,
522 .id = ACCEL_ID_BMA222,
523 .read_reg = 0x02,
524 .read_len = 6,
525 .endian = EXT_SLAVE_LITTLE_ENDIAN,
526 .range = {2, 0},
527 .trigger = NULL,
528};
529
530static
531struct ext_slave_descr *bma222_get_slave_descr(void)
532{
533 return &bma222_descr;
534}
535
536/* -------------------------------------------------------------------------- */
537
538struct bma222_mod_private_data {
539 struct i2c_client *client;
540 struct ext_slave_platform_data *pdata;
541};
542
543static unsigned short normal_i2c[] = { I2C_CLIENT_END };
544
545static int bma222_mod_probe(struct i2c_client *client,
546 const struct i2c_device_id *devid)
547{
548 struct ext_slave_platform_data *pdata;
549 struct bma222_mod_private_data *private_data;
550 int result = 0;
551
552 dev_info(&client->adapter->dev, "%s: %s\n", __func__, devid->name);
553
554 if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
555 result = -ENODEV;
556 goto out_no_free;
557 }
558
559 pdata = client->dev.platform_data;
560 if (!pdata) {
561 dev_err(&client->adapter->dev,
562 "Missing platform data for slave %s\n", devid->name);
563 result = -EFAULT;
564 goto out_no_free;
565 }
566
567 private_data = kzalloc(sizeof(*private_data), GFP_KERNEL);
568 if (!private_data) {
569 result = -ENOMEM;
570 goto out_no_free;
571 }
572
573 i2c_set_clientdata(client, private_data);
574 private_data->client = client;
575 private_data->pdata = pdata;
576
577 result = inv_mpu_register_slave(THIS_MODULE, client, pdata,
578 bma222_get_slave_descr);
579 if (result) {
580 dev_err(&client->adapter->dev,
581 "Slave registration failed: %s, %d\n",
582 devid->name, result);
583 goto out_free_memory;
584 }
585
586 return result;
587
588out_free_memory:
589 kfree(private_data);
590out_no_free:
591 dev_err(&client->adapter->dev, "%s failed %d\n", __func__, result);
592 return result;
593
594}
595
596static int bma222_mod_remove(struct i2c_client *client)
597{
598 struct bma222_mod_private_data *private_data =
599 i2c_get_clientdata(client);
600
601 dev_dbg(&client->adapter->dev, "%s\n", __func__);
602
603 inv_mpu_unregister_slave(client, private_data->pdata,
604 bma222_get_slave_descr);
605
606 kfree(private_data);
607 return 0;
608}
609
610static const struct i2c_device_id bma222_mod_id[] = {
611 { "bma222", ACCEL_ID_BMA222 },
612 {}
613};
614
615MODULE_DEVICE_TABLE(i2c, bma222_mod_id);
616
617static struct i2c_driver bma222_mod_driver = {
618 .class = I2C_CLASS_HWMON,
619 .probe = bma222_mod_probe,
620 .remove = bma222_mod_remove,
621 .id_table = bma222_mod_id,
622 .driver = {
623 .owner = THIS_MODULE,
624 .name = "bma222_mod",
625 },
626 .address_list = normal_i2c,
627};
628
629static int __init bma222_mod_init(void)
630{
631 int res = i2c_add_driver(&bma222_mod_driver);
632 pr_info("%s: Probe name %s\n", __func__, "bma222_mod");
633 if (res)
634 pr_err("%s failed\n", __func__);
635 return res;
636}
637
638static void __exit bma222_mod_exit(void)
639{
640 pr_info("%s\n", __func__);
641 i2c_del_driver(&bma222_mod_driver);
642}
643
644module_init(bma222_mod_init);
645module_exit(bma222_mod_exit);
646
647MODULE_AUTHOR("Invensense Corporation");
648MODULE_DESCRIPTION("Driver to integrate BMA222 sensor with the MPU");
649MODULE_LICENSE("GPL");
650MODULE_ALIAS("bma222_mod");
651
652/**
653 * @}
654 */
diff --git a/drivers/misc/inv_mpu/accel/bma250.c b/drivers/misc/inv_mpu/accel/bma250.c
new file mode 100644
index 00000000000..6a245f4566a
--- /dev/null
+++ b/drivers/misc/inv_mpu/accel/bma250.c
@@ -0,0 +1,787 @@
1/*
2 $License:
3 Copyright (C) 2011 InvenSense Corporation, All Rights Reserved.
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, see <http://www.gnu.org/licenses/>.
17 $
18 */
19
20/**
21 * @addtogroup ACCELDL
22 * @brief Provides the interface to setup and handle an accelerometer.
23 *
24 * @{
25 * @file bma250.c
26 * @brief Accelerometer setup and handling methods for Bosch BMA250.
27 */
28
29/* -------------------------------------------------------------------------- */
30
31#include <linux/i2c.h>
32#include <linux/module.h>
33#include <linux/moduleparam.h>
34#include <linux/kernel.h>
35#include <linux/errno.h>
36#include <linux/slab.h>
37#include <linux/delay.h>
38#include "mpu-dev.h"
39
40#include <linux/mpu.h>
41#include "mlsl.h"
42#include "mldl_cfg.h"
43
44/* -------------------------------------------------------------------------- */
45
46/* registers */
47#define BMA250_STATUS_REG (0x0A)
48#define BMA250_FSR_REG (0x0F)
49#define BMA250_ODR_REG (0x10)
50#define BMA250_PWR_REG (0x11)
51#define BMA250_SOFTRESET_REG (0x14)
52#define BMA250_INT_TYPE_REG (0x17)
53#define BMA250_INT_DST_REG (0x1A)
54#define BMA250_INT_SRC_REG (0x1E)
55
56/* masks */
57#define BMA250_STATUS_RDY_MASK (0x80)
58#define BMA250_FSR_MASK (0x0F)
59#define BMA250_ODR_MASK (0x1F)
60#define BMA250_PWR_SLEEP_MASK (0x80)
61#define BMA250_PWR_AWAKE_MASK (0x00)
62#define BMA250_SOFTRESET_MASK (0xB6)
63#define BMA250_INT_TYPE_MASK (0x10)
64#define BMA250_INT_DST_1_MASK (0x01)
65#define BMA250_INT_DST_2_MASK (0x80)
66#define BMA250_INT_SRC_MASK (0x00)
67
68/* -------------------------------------------------------------------------- */
69
70struct bma250_config {
71 unsigned int odr; /** < output data rate in mHz */
72 unsigned int fsr; /** < full scale range mg */
73 unsigned char irq_type;
74};
75
76struct bma250_private_data {
77 struct bma250_config suspend; /** < suspend configuration */
78 struct bma250_config resume; /** < resume configuration */
79};
80
81/* -------------------------------------------------------------------------- */
82/**
83 * @brief Sets the IRQ to fire when one of the IRQ events occur.
84 * Threshold and duration will not be used unless the type is MOT or
85 * NMOT.
86 *
87 * @param mlsl_handle
88 * the handle to the serial channel the device is connected to.
89 * @param pdata
90 * a pointer to the slave platform data.
91 * @param config
92 * configuration to apply to, suspend or resume
93 * @param apply
94 * whether to apply immediately or save the settings to be applied
95 * at the next resume.
96 * @param irq_type
97 * the type of IRQ. Valid values are
98 * - MPU_SLAVE_IRQ_TYPE_NONE
99 * - MPU_SLAVE_IRQ_TYPE_MOTION
100 * - MPU_SLAVE_IRQ_TYPE_DATA_READY
101 *
102 * @return INV_SUCCESS if successful or a non-zero error code.
103 */
104static int bma250_set_irq(void *mlsl_handle,
105 struct ext_slave_platform_data *pdata,
106 struct bma250_config *config,
107 int apply, long irq_type)
108{
109 int result = INV_SUCCESS;
110 unsigned char irqtype_reg;
111 unsigned char irqdst_reg;
112 unsigned char irqsrc_reg;
113
114 switch (irq_type) {
115 case MPU_SLAVE_IRQ_TYPE_DATA_READY:
116 /* data ready int. */
117 irqtype_reg = BMA250_INT_TYPE_MASK;
118 /* routed to interrupt pin 1 */
119 irqdst_reg = BMA250_INT_DST_1_MASK;
120 /* from filtered data */
121 irqsrc_reg = BMA250_INT_SRC_MASK;
122 break;
123 /* unfinished
124 case MPU_SLAVE_IRQ_TYPE_MOTION:
125 reg1 = 0x00;
126 reg2 = config->mot_int1_cfg;
127 reg3 = ;
128 break;
129 */
130 case MPU_SLAVE_IRQ_TYPE_NONE:
131 irqtype_reg = 0x00;
132 irqdst_reg = 0x00;
133 irqsrc_reg = 0x00;
134 break;
135 default:
136 return INV_ERROR_INVALID_PARAMETER;
137 break;
138 }
139
140 config->irq_type = (unsigned char)irq_type;
141
142 if (apply) {
143 /* select the type of interrupt to use */
144 result = inv_serial_single_write(mlsl_handle, pdata->address,
145 BMA250_INT_TYPE_REG, irqtype_reg);
146 if (result) {
147 LOG_RESULT_LOCATION(result);
148 return result;
149 }
150 /* select to which interrupt pin to route it to */
151 result = inv_serial_single_write(mlsl_handle, pdata->address,
152 BMA250_INT_DST_REG, irqdst_reg);
153 if (result) {
154 LOG_RESULT_LOCATION(result);
155 return result;
156 }
157 /* select whether the interrupt works off filtered or
158 unfiltered data */
159 result = inv_serial_single_write(mlsl_handle, pdata->address,
160 BMA250_INT_SRC_REG, irqsrc_reg);
161 if (result) {
162 LOG_RESULT_LOCATION(result);
163 return result;
164 }
165 }
166 return result;
167}
168
169/**
170 * @brief Set the output data rate for the particular configuration.
171 *
172 * @param mlsl_handle
173 * the handle to the serial channel the device is connected to.
174 * @param pdata
175 * a pointer to the slave platform data.
176 * @param config
177 * Config to modify with new ODR.
178 * @param apply
179 * whether to apply immediately or save the settings to be applied
180 * at the next resume.
181 * @param odr
182 * Output data rate in units of 1/1000Hz (mHz).
183 *
184 * @return INV_SUCCESS if successful or a non-zero error code.
185 */
186static int bma250_set_odr(void *mlsl_handle,
187 struct ext_slave_platform_data *pdata,
188 struct bma250_config *config,
189 int apply,
190 long odr)
191{
192 int result = INV_SUCCESS;
193 unsigned char reg_odr;
194
195 /* Table uses bandwidth which is half the sample rate */
196 odr = odr >> 1;
197 if (odr >= 1000000) {
198 reg_odr = 0x0F;
199 config->odr = 2000000;
200 } else if (odr >= 500000) {
201 reg_odr = 0x0E;
202 config->odr = 1000000;
203 } else if (odr >= 250000) {
204 reg_odr = 0x0D;
205 config->odr = 500000;
206 } else if (odr >= 125000) {
207 reg_odr = 0x0C;
208 config->odr = 250000;
209 } else if (odr >= 62500) {
210 reg_odr = 0x0B;
211 config->odr = 125000;
212 } else if (odr >= 31250) {
213 reg_odr = 0x0A;
214 config->odr = 62500;
215 } else if (odr >= 15630) {
216 reg_odr = 0x09;
217 config->odr = 31250;
218 } else {
219 reg_odr = 0x08;
220 config->odr = 15630;
221 }
222
223 if (apply) {
224 MPL_LOGV("ODR: %d\n", config->odr);
225 result = inv_serial_single_write(mlsl_handle, pdata->address,
226 BMA250_ODR_REG, reg_odr);
227 if (result) {
228 LOG_RESULT_LOCATION(result);
229 return result;
230 }
231 }
232
233 return result;
234}
235
236/**
237 * @brief Set the full scale range of the accels
238 *
239 * @param mlsl_handle
240 * the handle to the serial channel the device is connected to.
241 * @param pdata
242 * a pointer to the slave platform data.
243 * @param config
244 * pointer to configuration.
245 * @param apply
246 * whether to apply immediately or save the settings to be applied
247 * at the next resume.
248 * @param fsr
249 * requested full scale range.
250 *
251 * @return INV_SUCCESS if successful or a non-zero error code.
252 */
253static int bma250_set_fsr(void *mlsl_handle,
254 struct ext_slave_platform_data *pdata,
255 struct bma250_config *config,
256 int apply,
257 long fsr)
258{
259 int result = INV_SUCCESS;
260 unsigned char reg_fsr_mask;
261
262 if (fsr <= 2000) {
263 reg_fsr_mask = 0x03;
264 config->fsr = 2000;
265 } else if (fsr <= 4000) {
266 reg_fsr_mask = 0x05;
267 config->fsr = 4000;
268 } else if (fsr <= 8000) {
269 reg_fsr_mask = 0x08;
270 config->fsr = 8000;
271 } else { /* 8001 -> oo */
272 reg_fsr_mask = 0x0C;
273 config->fsr = 16000;
274 }
275
276 if (apply) {
277 MPL_LOGV("FSR: %d\n", config->fsr);
278 result = inv_serial_single_write(mlsl_handle, pdata->address,
279 BMA250_FSR_REG, reg_fsr_mask);
280 if (result) {
281 LOG_RESULT_LOCATION(result);
282 return result;
283 }
284 }
285 return result;
286}
287
288/**
289 * @brief one-time device driver initialization function.
290 * If the driver is built as a kernel module, this function will be
291 * called when the module is loaded in the kernel.
292 * If the driver is built-in in the kernel, this function will be
293 * called at boot time.
294 *
295 * @param mlsl_handle
296 * the handle to the serial channel the device is connected to.
297 * @param slave
298 * a pointer to the slave descriptor data structure.
299 * @param pdata
300 * a pointer to the slave platform data.
301 *
302 * @return INV_SUCCESS if successful or a non-zero error code.
303 */
304static int bma250_init(void *mlsl_handle,
305 struct ext_slave_descr *slave,
306 struct ext_slave_platform_data *pdata)
307{
308 int result;
309 long range;
310
311 struct bma250_private_data *private_data;
312 private_data = kzalloc(sizeof(struct bma250_private_data), GFP_KERNEL);
313
314 if (!private_data)
315 return INV_ERROR_MEMORY_EXAUSTED;
316
317 pdata->private_data = private_data;
318
319 result = inv_serial_single_write(mlsl_handle, pdata->address,
320 BMA250_SOFTRESET_REG, BMA250_SOFTRESET_MASK);
321 if (result) {
322 LOG_RESULT_LOCATION(result);
323 return result;
324 }
325 msleep(1);
326
327 result = bma250_set_odr(mlsl_handle, pdata, &private_data->suspend,
328 false, 0);
329 if (result) {
330 LOG_RESULT_LOCATION(result);
331 return result;
332 }
333 result = bma250_set_odr(mlsl_handle, pdata, &private_data->resume,
334 false, 200000);
335 if (result) {
336 LOG_RESULT_LOCATION(result);
337 return result;
338 }
339
340 range = range_fixedpoint_to_long_mg(slave->range);
341 result = bma250_set_fsr(mlsl_handle, pdata, &private_data->suspend,
342 false, range);
343 result = bma250_set_fsr(mlsl_handle, pdata, &private_data->resume,
344 false, range);
345 if (result) {
346 LOG_RESULT_LOCATION(result);
347 return result;
348 }
349
350 result = bma250_set_irq(mlsl_handle, pdata, &private_data->suspend,
351 false, MPU_SLAVE_IRQ_TYPE_NONE);
352 if (result) {
353 LOG_RESULT_LOCATION(result);
354 return result;
355 }
356 result = bma250_set_irq(mlsl_handle, pdata, &private_data->resume,
357 false, MPU_SLAVE_IRQ_TYPE_NONE);
358 if (result) {
359 LOG_RESULT_LOCATION(result);
360 return result;
361 }
362
363 result = inv_serial_single_write(mlsl_handle, pdata->address,
364 BMA250_PWR_REG, BMA250_PWR_SLEEP_MASK);
365 if (result) {
366 LOG_RESULT_LOCATION(result);
367 return result;
368 }
369
370 return result;
371}
372
373/**
374 * @brief one-time device driver exit function.
375 * If the driver is built as a kernel module, this function will be
376 * called when the module is removed from the kernel.
377 *
378 * @param mlsl_handle
379 * the handle to the serial channel the device is connected to.
380 * @param slave
381 * a pointer to the slave descriptor data structure.
382 * @param pdata
383 * a pointer to the slave platform data.
384 *
385 * @return INV_SUCCESS if successful or a non-zero error code.
386 */
387static int bma250_exit(void *mlsl_handle,
388 struct ext_slave_descr *slave,
389 struct ext_slave_platform_data *pdata)
390{
391 kfree(pdata->private_data);
392 return INV_SUCCESS;
393}
394
395/**
396 * @brief device configuration facility.
397 *
398 * @param mlsl_handle
399 * the handle to the serial channel the device is connected to.
400 * @param slave
401 * a pointer to the slave descriptor data structure.
402 * @param pdata
403 * a pointer to the slave platform data.
404 * @param data
405 * a pointer to the configuration data structure.
406 *
407 * @return INV_SUCCESS if successful or a non-zero error code.
408 */
409static int bma250_config(void *mlsl_handle,
410 struct ext_slave_descr *slave,
411 struct ext_slave_platform_data *pdata,
412 struct ext_slave_config *data)
413{
414 struct bma250_private_data *private_data =
415 (struct bma250_private_data *)(pdata->private_data);
416
417 if (!data->data)
418 return INV_ERROR_INVALID_PARAMETER;
419
420 switch (data->key) {
421 case MPU_SLAVE_CONFIG_ODR_SUSPEND:
422 return bma250_set_odr(mlsl_handle, pdata,
423 &private_data->suspend,
424 data->apply,
425 *((long *)data->data));
426 case MPU_SLAVE_CONFIG_ODR_RESUME:
427 return bma250_set_odr(mlsl_handle, pdata,
428 &private_data->resume,
429 data->apply,
430 *((long *)data->data));
431 case MPU_SLAVE_CONFIG_FSR_SUSPEND:
432 return bma250_set_fsr(mlsl_handle, pdata,
433 &private_data->suspend,
434 data->apply,
435 *((long *)data->data));
436 case MPU_SLAVE_CONFIG_FSR_RESUME:
437 return bma250_set_fsr(mlsl_handle, pdata,
438 &private_data->resume,
439 data->apply,
440 *((long *)data->data));
441 case MPU_SLAVE_CONFIG_IRQ_SUSPEND:
442 return bma250_set_irq(mlsl_handle, pdata,
443 &private_data->suspend,
444 data->apply,
445 *((long *)data->data));
446 case MPU_SLAVE_CONFIG_IRQ_RESUME:
447 return bma250_set_irq(mlsl_handle, pdata,
448 &private_data->resume,
449 data->apply,
450 *((long *)data->data));
451 default:
452 return INV_ERROR_FEATURE_NOT_IMPLEMENTED;
453 };
454 return INV_SUCCESS;
455}
456
457/**
458 * @brief facility to retrieve the device configuration.
459 *
460 * @param mlsl_handle
461 * the handle to the serial channel the device is connected to.
462 * @param slave
463 * a pointer to the slave descriptor data structure.
464 * @param pdata
465 * a pointer to the slave platform data.
466 * @param data
467 * a pointer to store the returned configuration data structure.
468 *
469 * @return INV_SUCCESS if successful or a non-zero error code.
470 */
471static int bma250_get_config(void *mlsl_handle,
472 struct ext_slave_descr *slave,
473 struct ext_slave_platform_data *pdata,
474 struct ext_slave_config *data)
475{
476 struct bma250_private_data *private_data =
477 (struct bma250_private_data *)(pdata->private_data);
478
479 if (!data->data)
480 return INV_ERROR_INVALID_PARAMETER;
481
482 switch (data->key) {
483 case MPU_SLAVE_CONFIG_ODR_SUSPEND:
484 (*(unsigned long *)data->data) =
485 (unsigned long) private_data->suspend.odr;
486 break;
487 case MPU_SLAVE_CONFIG_ODR_RESUME:
488 (*(unsigned long *)data->data) =
489 (unsigned long) private_data->resume.odr;
490 break;
491 case MPU_SLAVE_CONFIG_FSR_SUSPEND:
492 (*(unsigned long *)data->data) =
493 (unsigned long) private_data->suspend.fsr;
494 break;
495 case MPU_SLAVE_CONFIG_FSR_RESUME:
496 (*(unsigned long *)data->data) =
497 (unsigned long) private_data->resume.fsr;
498 break;
499 case MPU_SLAVE_CONFIG_IRQ_SUSPEND:
500 (*(unsigned long *)data->data) =
501 (unsigned long) private_data->suspend.irq_type;
502 break;
503 case MPU_SLAVE_CONFIG_IRQ_RESUME:
504 (*(unsigned long *)data->data) =
505 (unsigned long) private_data->resume.irq_type;
506 break;
507 default:
508 return INV_ERROR_FEATURE_NOT_IMPLEMENTED;
509 };
510
511 return INV_SUCCESS;
512}
513
514/**
515 * @brief suspends the device to put it in its lowest power mode.
516 *
517 * @param mlsl_handle
518 * the handle to the serial channel the device is connected to.
519 * @param slave
520 * a pointer to the slave descriptor data structure.
521 * @param pdata
522 * a pointer to the slave platform data.
523 *
524 * @return INV_SUCCESS if successful or a non-zero error code.
525 */
526static int bma250_suspend(void *mlsl_handle,
527 struct ext_slave_descr *slave,
528 struct ext_slave_platform_data *pdata)
529{
530 int result;
531 struct bma250_config *suspend_config =
532 &((struct bma250_private_data *)pdata->private_data)->suspend;
533
534 result = bma250_set_odr(mlsl_handle, pdata, suspend_config,
535 true, suspend_config->odr);
536 if (result) {
537 LOG_RESULT_LOCATION(result);
538 return result;
539 }
540 result = bma250_set_fsr(mlsl_handle, pdata, suspend_config,
541 true, suspend_config->fsr);
542 if (result) {
543 LOG_RESULT_LOCATION(result);
544 return result;
545 }
546 result = bma250_set_irq(mlsl_handle, pdata, suspend_config,
547 true, suspend_config->irq_type);
548 if (result) {
549 LOG_RESULT_LOCATION(result);
550 return result;
551 }
552
553 result = inv_serial_single_write(mlsl_handle, pdata->address,
554 BMA250_PWR_REG, BMA250_PWR_SLEEP_MASK);
555 if (result) {
556 LOG_RESULT_LOCATION(result);
557 return result;
558 }
559
560 msleep(3); /* 3 ms powerup time maximum */
561 return result;
562}
563
564/**
565 * @brief resume the device in the proper power state given the configuration
566 * chosen.
567 *
568 * @param mlsl_handle
569 * the handle to the serial channel the device is connected to.
570 * @param slave
571 * a pointer to the slave descriptor data structure.
572 * @param pdata
573 * a pointer to the slave platform data.
574 *
575 * @return INV_SUCCESS if successful or a non-zero error code.
576 */
577static int bma250_resume(void *mlsl_handle,
578 struct ext_slave_descr *slave,
579 struct ext_slave_platform_data *pdata)
580{
581 int result;
582 struct bma250_config *resume_config =
583 &((struct bma250_private_data *)pdata->private_data)->resume;
584
585 result = bma250_set_odr(mlsl_handle, pdata, resume_config,
586 true, resume_config->odr);
587 if (result) {
588 LOG_RESULT_LOCATION(result);
589 return result;
590 }
591 result = bma250_set_fsr(mlsl_handle, pdata, resume_config,
592 true, resume_config->fsr);
593 if (result) {
594 LOG_RESULT_LOCATION(result);
595 return result;
596 }
597 result = bma250_set_irq(mlsl_handle, pdata, resume_config,
598 true, resume_config->irq_type);
599 if (result) {
600 LOG_RESULT_LOCATION(result);
601 return result;
602 }
603
604 result = inv_serial_single_write(mlsl_handle, pdata->address,
605 BMA250_PWR_REG, BMA250_PWR_AWAKE_MASK);
606 if (result) {
607 LOG_RESULT_LOCATION(result);
608 return result;
609 }
610
611 return result;
612}
613
614/**
615 * @brief read the sensor data from the device.
616 *
617 * @param mlsl_handle
618 * the handle to the serial channel the device is connected to.
619 * @param slave
620 * a pointer to the slave descriptor data structure.
621 * @param pdata
622 * a pointer to the slave platform data.
623 * @param data
624 * a buffer to store the data read.
625 *
626 * @return INV_SUCCESS if successful or a non-zero error code.
627 */
628static int bma250_read(void *mlsl_handle,
629 struct ext_slave_descr *slave,
630 struct ext_slave_platform_data *pdata,
631 unsigned char *data)
632{
633 int result = INV_SUCCESS;
634 result = inv_serial_read(mlsl_handle, pdata->address,
635 BMA250_STATUS_REG, 1, data);
636 if (1) { /* KLP - workaroud for small data ready window */
637 result = inv_serial_read(mlsl_handle, pdata->address,
638 slave->read_reg, slave->read_len, data);
639 return result;
640 } else
641 return INV_ERROR_ACCEL_DATA_NOT_READY;
642}
643
644static struct ext_slave_descr bma250_descr = {
645 .init = bma250_init,
646 .exit = bma250_exit,
647 .suspend = bma250_suspend,
648 .resume = bma250_resume,
649 .read = bma250_read,
650 .config = bma250_config,
651 .get_config = bma250_get_config,
652 .name = "bma250",
653 .type = EXT_SLAVE_TYPE_ACCEL,
654 .id = ACCEL_ID_BMA250,
655 .read_reg = 0x02,
656 .read_len = 6,
657 .endian = EXT_SLAVE_LITTLE_ENDIAN,
658 .range = {2, 0},
659 .trigger = NULL,
660};
661
662static
663struct ext_slave_descr *bma250_get_slave_descr(void)
664{
665 return &bma250_descr;
666}
667
668/* -------------------------------------------------------------------------- */
669
670/* Platform data for the MPU */
671struct bma250_mod_private_data {
672 struct i2c_client *client;
673 struct ext_slave_platform_data *pdata;
674};
675
676static unsigned short normal_i2c[] = { I2C_CLIENT_END };
677
678static int bma250_mod_probe(struct i2c_client *client,
679 const struct i2c_device_id *devid)
680{
681 struct ext_slave_platform_data *pdata;
682 struct bma250_mod_private_data *private_data;
683 int result = 0;
684
685 dev_info(&client->adapter->dev, "%s: %s\n", __func__, devid->name);
686
687 if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
688 result = -ENODEV;
689 goto out_no_free;
690 }
691
692 pdata = client->dev.platform_data;
693 if (!pdata) {
694 dev_err(&client->adapter->dev,
695 "Missing platform data for slave %s\n", devid->name);
696 result = -EFAULT;
697 goto out_no_free;
698 }
699
700 private_data = kzalloc(sizeof(*private_data), GFP_KERNEL);
701 if (!private_data) {
702 result = -ENOMEM;
703 goto out_no_free;
704 }
705
706 i2c_set_clientdata(client, private_data);
707 private_data->client = client;
708 private_data->pdata = pdata;
709
710 result = inv_mpu_register_slave(THIS_MODULE, client, pdata,
711 bma250_get_slave_descr);
712 if (result) {
713 dev_err(&client->adapter->dev,
714 "Slave registration failed: %s, %d\n",
715 devid->name, result);
716 goto out_free_memory;
717 }
718
719 return result;
720
721out_free_memory:
722 kfree(private_data);
723out_no_free:
724 dev_err(&client->adapter->dev, "%s failed %d\n", __func__, result);
725 return result;
726
727}
728
729static int bma250_mod_remove(struct i2c_client *client)
730{
731 struct bma250_mod_private_data *private_data =
732 i2c_get_clientdata(client);
733
734 dev_dbg(&client->adapter->dev, "%s\n", __func__);
735
736 inv_mpu_unregister_slave(client, private_data->pdata,
737 bma250_get_slave_descr);
738
739 kfree(private_data);
740 return 0;
741}
742
743static const struct i2c_device_id bma250_mod_id[] = {
744 { "bma250", ACCEL_ID_BMA250 },
745 {}
746};
747
748MODULE_DEVICE_TABLE(i2c, bma250_mod_id);
749
750static struct i2c_driver bma250_mod_driver = {
751 .class = I2C_CLASS_HWMON,
752 .probe = bma250_mod_probe,
753 .remove = bma250_mod_remove,
754 .id_table = bma250_mod_id,
755 .driver = {
756 .owner = THIS_MODULE,
757 .name = "bma250_mod",
758 },
759 .address_list = normal_i2c,
760};
761
762static int __init bma250_mod_init(void)
763{
764 int res = i2c_add_driver(&bma250_mod_driver);
765 pr_info("%s: Probe name %s\n", __func__, "bma250_mod");
766 if (res)
767 pr_err("%s failed\n", __func__);
768 return res;
769}
770
771static void __exit bma250_mod_exit(void)
772{
773 pr_info("%s\n", __func__);
774 i2c_del_driver(&bma250_mod_driver);
775}
776
777module_init(bma250_mod_init);
778module_exit(bma250_mod_exit);
779
780MODULE_AUTHOR("Invensense Corporation");
781MODULE_DESCRIPTION("Driver to integrate BMA250 sensor with the MPU");
782MODULE_LICENSE("GPL");
783MODULE_ALIAS("bma250_mod");
784
785/**
786 * @}
787 */
diff --git a/drivers/misc/inv_mpu/accel/cma3000.c b/drivers/misc/inv_mpu/accel/cma3000.c
new file mode 100644
index 00000000000..496d1f29bdc
--- /dev/null
+++ b/drivers/misc/inv_mpu/accel/cma3000.c
@@ -0,0 +1,222 @@
1/*
2 $License:
3 Copyright (C) 2011 InvenSense Corporation, All Rights Reserved.
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, see <http://www.gnu.org/licenses/>.
17 $
18 */
19
20/*
21 * @addtogroup ACCELDL
22 * @brief Accelerometer setup and handling methods for VTI CMA3000.
23 *
24 * @{
25 * @file cma3000.c
26 * @brief Accelerometer setup and handling methods for VTI CMA3000
27 */
28
29/* -------------------------------------------------------------------------- */
30
31#include <linux/i2c.h>
32#include <linux/module.h>
33#include <linux/moduleparam.h>
34#include <linux/kernel.h>
35#include <linux/errno.h>
36#include <linux/slab.h>
37#include <linux/delay.h>
38#include "mpu-dev.h"
39
40#include <log.h>
41#include <linux/mpu.h>
42#include "mlsl.h"
43#include "mldl_cfg.h"
44#undef MPL_LOG_TAG
45#define MPL_LOG_TAG "MPL-acc"
46
47/* -------------------------------------------------------------------------- */
48
49static int cma3000_suspend(void *mlsl_handle,
50 struct ext_slave_descr *slave,
51 struct ext_slave_platform_data *pdata)
52{
53 int result;
54 /* RAM reset */
55 result =
56 inv_serial_single_write(mlsl_handle, pdata->address, 0x1d, 0xcd);
57 return result;
58}
59
60static int cma3000_resume(void *mlsl_handle,
61 struct ext_slave_descr *slave,
62 struct ext_slave_platform_data *pdata)
63{
64
65 return INV_SUCCESS;
66}
67
68static int cma3000_read(void *mlsl_handle,
69 struct ext_slave_descr *slave,
70 struct ext_slave_platform_data *pdata,
71 unsigned char *data)
72{
73 int result;
74 result = inv_serial_read(mlsl_handle, pdata->address,
75 slave->reg, slave->len, data);
76 return result;
77}
78
79static struct ext_slave_descr cma3000_descr = {
80 .init = NULL,
81 .exit = NULL,
82 .suspend = cma3000_suspend,
83 .resume = cma3000_resume,
84 .read = cma3000_read,
85 .config = NULL,
86 .get_config = NULL,
87 .name = "cma3000",
88 .type = EXT_SLAVE_TYPE_ACCEL,
89 .id = ID_INVALID,
90 .read_reg = 0x06,
91 .read_len = 6,
92 .endian = EXT_SLAVE_LITTLE_ENDIAN,
93 .range = {2, 0},
94 .trigger = NULL,
95
96};
97
98static
99struct ext_slave_descr *cma3000_get_slave_descr(void)
100{
101 return &cma3000_descr;
102}
103
104/* -------------------------------------------------------------------------- */
105
106struct cma3000_mod_private_data {
107 struct i2c_client *client;
108 struct ext_slave_platform_data *pdata;
109};
110
111static unsigned short normal_i2c[] = { I2C_CLIENT_END };
112
113static int cma3000_mod_probe(struct i2c_client *client,
114 const struct i2c_device_id *devid)
115{
116 struct ext_slave_platform_data *pdata;
117 struct cma3000_mod_private_data *private_data;
118 int result = 0;
119
120 dev_info(&client->adapter->dev, "%s: %s\n", __func__, devid->name);
121
122 if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
123 result = -ENODEV;
124 goto out_no_free;
125 }
126
127 pdata = client->dev.platform_data;
128 if (!pdata) {
129 dev_err(&client->adapter->dev,
130 "Missing platform data for slave %s\n", devid->name);
131 result = -EFAULT;
132 goto out_no_free;
133 }
134
135 private_data = kzalloc(sizeof(*private_data), GFP_KERNEL);
136 if (!private_data) {
137 result = -ENOMEM;
138 goto out_no_free;
139 }
140
141 i2c_set_clientdata(client, private_data);
142 private_data->client = client;
143 private_data->pdata = pdata;
144
145 result = inv_mpu_register_slave(THIS_MODULE, client, pdata,
146 cma3000_get_slave_descr);
147 if (result) {
148 dev_err(&client->adapter->dev,
149 "Slave registration failed: %s, %d\n",
150 devid->name, result);
151 goto out_free_memory;
152 }
153
154 return result;
155
156out_free_memory:
157 kfree(private_data);
158out_no_free:
159 dev_err(&client->adapter->dev, "%s failed %d\n", __func__, result);
160 return result;
161
162}
163
164static int cma3000_mod_remove(struct i2c_client *client)
165{
166 struct cma3000_mod_private_data *private_data =
167 i2c_get_clientdata(client);
168
169 dev_dbg(&client->adapter->dev, "%s\n", __func__);
170
171 inv_mpu_unregister_slave(client, private_data->pdata,
172 cma3000_get_slave_descr);
173
174 kfree(private_data);
175 return 0;
176}
177
178static const struct i2c_device_id cma3000_mod_id[] = {
179 { "cma3000", ACCEL_ID_CMA3000 },
180 {}
181};
182
183MODULE_DEVICE_TABLE(i2c, cma3000_mod_id);
184
185static struct i2c_driver cma3000_mod_driver = {
186 .class = I2C_CLASS_HWMON,
187 .probe = cma3000_mod_probe,
188 .remove = cma3000_mod_remove,
189 .id_table = cma3000_mod_id,
190 .driver = {
191 .owner = THIS_MODULE,
192 .name = "cma3000_mod",
193 },
194 .address_list = normal_i2c,
195};
196
197static int __init cma3000_mod_init(void)
198{
199 int res = i2c_add_driver(&cma3000_mod_driver);
200 pr_info("%s: Probe name %s\n", __func__, "cma3000_mod");
201 if (res)
202 pr_err("%s failed\n", __func__);
203 return res;
204}
205
206static void __exit cma3000_mod_exit(void)
207{
208 pr_info("%s\n", __func__);
209 i2c_del_driver(&cma3000_mod_driver);
210}
211
212module_init(cma3000_mod_init);
213module_exit(cma3000_mod_exit);
214
215MODULE_AUTHOR("Invensense Corporation");
216MODULE_DESCRIPTION("Driver to integrate CMA3000 sensor with the MPU");
217MODULE_LICENSE("GPL");
218MODULE_ALIAS("cma3000_mod");
219
220/**
221 * @}
222 */
diff --git a/drivers/misc/inv_mpu/accel/kxsd9.c b/drivers/misc/inv_mpu/accel/kxsd9.c
new file mode 100644
index 00000000000..5cb4eaf6b4a
--- /dev/null
+++ b/drivers/misc/inv_mpu/accel/kxsd9.c
@@ -0,0 +1,264 @@
1/*
2 $License:
3 Copyright (C) 2011 InvenSense Corporation, All Rights Reserved.
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, see <http://www.gnu.org/licenses/>.
17 $
18 */
19
20/**
21 * @addtogroup ACCELDL
22 * @brief Accelerometer setup and handling methods for Kionix KXSD9.
23 *
24 * @{
25 * @file kxsd9.c
26 * @brief Accelerometer setup and handling methods for Kionix KXSD9.
27 */
28
29/* -------------------------------------------------------------------------- */
30
31#include <linux/i2c.h>
32#include <linux/module.h>
33#include <linux/moduleparam.h>
34#include <linux/kernel.h>
35#include <linux/errno.h>
36#include <linux/slab.h>
37#include <linux/delay.h>
38#include "mpu-dev.h"
39
40#include <log.h>
41#include <linux/mpu.h>
42#include "mlsl.h"
43#include "mldl_cfg.h"
44#undef MPL_LOG_TAG
45#define MPL_LOG_TAG "MPL-acc"
46
47/* -------------------------------------------------------------------------- */
48
49static int kxsd9_suspend(void *mlsl_handle,
50 struct ext_slave_descr *slave,
51 struct ext_slave_platform_data *pdata)
52{
53 int result;
54 /* CTRL_REGB: low-power standby mode */
55 result =
56 inv_serial_single_write(mlsl_handle, pdata->address, 0x0d, 0x0);
57 if (result) {
58 LOG_RESULT_LOCATION(result);
59 return result;
60 }
61 return result;
62}
63
64/* full scale setting - register and mask */
65#define ACCEL_KIONIX_CTRL_REG (0x0C)
66#define ACCEL_KIONIX_CTRL_MASK (0x3)
67
68static int kxsd9_resume(void *mlsl_handle,
69 struct ext_slave_descr *slave,
70 struct ext_slave_platform_data *pdata)
71{
72 int result = INV_SUCCESS;
73 unsigned char reg;
74
75 /* Full Scale */
76 reg = 0x0;
77 reg &= ~ACCEL_KIONIX_CTRL_MASK;
78 reg |= 0x00;
79 if (slave->range.mantissa == 4) { /* 4g scale = 4.9951 */
80 reg |= 0x2;
81 slave->range.fraction = 9951;
82 } else if (slave->range.mantissa == 7) { /* 6g scale = 7.5018 */
83 reg |= 0x1;
84 slave->range.fraction = 5018;
85 } else if (slave->range.mantissa == 9) { /* 8g scale = 9.9902 */
86 reg |= 0x0;
87 slave->range.fraction = 9902;
88 } else {
89 slave->range.mantissa = 2; /* 2g scale = 2.5006 */
90 slave->range.fraction = 5006;
91 reg |= 0x3;
92 }
93 reg |= 0xC0; /* 100Hz LPF */
94 result =
95 inv_serial_single_write(mlsl_handle, pdata->address,
96 ACCEL_KIONIX_CTRL_REG, reg);
97 if (result) {
98 LOG_RESULT_LOCATION(result);
99 return result;
100 }
101 /* normal operation */
102 result =
103 inv_serial_single_write(mlsl_handle, pdata->address, 0x0d, 0x40);
104 if (result) {
105 LOG_RESULT_LOCATION(result);
106 return result;
107 }
108
109 return INV_SUCCESS;
110}
111
112static int kxsd9_read(void *mlsl_handle,
113 struct ext_slave_descr *slave,
114 struct ext_slave_platform_data *pdata,
115 unsigned char *data)
116{
117 int result;
118 result = inv_serial_read(mlsl_handle, pdata->address,
119 slave->read_reg, slave->read_len, data);
120 return result;
121}
122
123static struct ext_slave_descr kxsd9_descr = {
124 .init = NULL,
125 .exit = NULL,
126 .suspend = kxsd9_suspend,
127 .resume = kxsd9_resume,
128 .read = kxsd9_read,
129 .config = NULL,
130 .get_config = NULL,
131 .name = "kxsd9",
132 .type = EXT_SLAVE_TYPE_ACCEL,
133 .id = ACCEL_ID_KXSD9,
134 .read_reg = 0x00,
135 .read_len = 6,
136 .endian = EXT_SLAVE_BIG_ENDIAN,
137 .range = {2, 5006},
138 .trigger = NULL,
139};
140
141static
142struct ext_slave_descr *kxsd9_get_slave_descr(void)
143{
144 return &kxsd9_descr;
145}
146
147/* -------------------------------------------------------------------------- */
148struct kxsd9_mod_private_data {
149 struct i2c_client *client;
150 struct ext_slave_platform_data *pdata;
151};
152
153static unsigned short normal_i2c[] = { I2C_CLIENT_END };
154
155static int kxsd9_mod_probe(struct i2c_client *client,
156 const struct i2c_device_id *devid)
157{
158 struct ext_slave_platform_data *pdata;
159 struct kxsd9_mod_private_data *private_data;
160 int result = 0;
161
162 dev_info(&client->adapter->dev, "%s: %s\n", __func__, devid->name);
163
164 if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
165 result = -ENODEV;
166 goto out_no_free;
167 }
168
169 pdata = client->dev.platform_data;
170 if (!pdata) {
171 dev_err(&client->adapter->dev,
172 "Missing platform data for slave %s\n", devid->name);
173 result = -EFAULT;
174 goto out_no_free;
175 }
176
177 private_data = kzalloc(sizeof(*private_data), GFP_KERNEL);
178 if (!private_data) {
179 result = -ENOMEM;
180 goto out_no_free;
181 }
182
183 i2c_set_clientdata(client, private_data);
184 private_data->client = client;
185 private_data->pdata = pdata;
186
187 result = inv_mpu_register_slave(THIS_MODULE, client, pdata,
188 kxsd9_get_slave_descr);
189 if (result) {
190 dev_err(&client->adapter->dev,
191 "Slave registration failed: %s, %d\n",
192 devid->name, result);
193 goto out_free_memory;
194 }
195
196 return result;
197
198out_free_memory:
199 kfree(private_data);
200out_no_free:
201 dev_err(&client->adapter->dev, "%s failed %d\n", __func__, result);
202 return result;
203
204}
205
206static int kxsd9_mod_remove(struct i2c_client *client)
207{
208 struct kxsd9_mod_private_data *private_data =
209 i2c_get_clientdata(client);
210
211 dev_dbg(&client->adapter->dev, "%s\n", __func__);
212
213 inv_mpu_unregister_slave(client, private_data->pdata,
214 kxsd9_get_slave_descr);
215
216 kfree(private_data);
217 return 0;
218}
219
220static const struct i2c_device_id kxsd9_mod_id[] = {
221 { "kxsd9", ACCEL_ID_KXSD9 },
222 {}
223};
224
225MODULE_DEVICE_TABLE(i2c, kxsd9_mod_id);
226
227static struct i2c_driver kxsd9_mod_driver = {
228 .class = I2C_CLASS_HWMON,
229 .probe = kxsd9_mod_probe,
230 .remove = kxsd9_mod_remove,
231 .id_table = kxsd9_mod_id,
232 .driver = {
233 .owner = THIS_MODULE,
234 .name = "kxsd9_mod",
235 },
236 .address_list = normal_i2c,
237};
238
239static int __init kxsd9_mod_init(void)
240{
241 int res = i2c_add_driver(&kxsd9_mod_driver);
242 pr_info("%s: Probe name %s\n", __func__, "kxsd9_mod");
243 if (res)
244 pr_err("%s failed\n", __func__);
245 return res;
246}
247
248static void __exit kxsd9_mod_exit(void)
249{
250 pr_info("%s\n", __func__);
251 i2c_del_driver(&kxsd9_mod_driver);
252}
253
254module_init(kxsd9_mod_init);
255module_exit(kxsd9_mod_exit);
256
257MODULE_AUTHOR("Invensense Corporation");
258MODULE_DESCRIPTION("Driver to integrate KXSD9 sensor with the MPU");
259MODULE_LICENSE("GPL");
260MODULE_ALIAS("kxsd9_mod");
261
262/**
263 * @}
264 */
diff --git a/drivers/misc/inv_mpu/accel/kxtf9.c b/drivers/misc/inv_mpu/accel/kxtf9.c
new file mode 100644
index 00000000000..80776f249c6
--- /dev/null
+++ b/drivers/misc/inv_mpu/accel/kxtf9.c
@@ -0,0 +1,841 @@
1/*
2 $License:
3 Copyright (C) 2011 InvenSense Corporation, All Rights Reserved.
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, see <http://www.gnu.org/licenses/>.
17 $
18 */
19
20/**
21 * @addtogroup ACCELDL
22 * @brief Accelerometer setup and handling methods for Kionix KXTF9.
23 *
24 * @{
25 * @file kxtf9.c
26 * @brief Accelerometer setup and handling methods for Kionix KXTF9.
27*/
28
29/* -------------------------------------------------------------------------- */
30
31#undef MPL_LOG_NDEBUG
32#define MPL_LOG_NDEBUG 1
33
34#include <linux/i2c.h>
35#include <linux/module.h>
36#include <linux/moduleparam.h>
37#include <linux/kernel.h>
38#include <linux/errno.h>
39#include <linux/slab.h>
40#include <linux/delay.h>
41#include "mpu-dev.h"
42
43#include <log.h>
44#include <linux/mpu.h>
45#include "mlsl.h"
46#include "mldl_cfg.h"
47#undef MPL_LOG_TAG
48#define MPL_LOG_TAG "MPL-acc"
49
50#define KXTF9_XOUT_HPF_L (0x00) /* 0000 0000 */
51#define KXTF9_XOUT_HPF_H (0x01) /* 0000 0001 */
52#define KXTF9_YOUT_HPF_L (0x02) /* 0000 0010 */
53#define KXTF9_YOUT_HPF_H (0x03) /* 0000 0011 */
54#define KXTF9_ZOUT_HPF_L (0x04) /* 0001 0100 */
55#define KXTF9_ZOUT_HPF_H (0x05) /* 0001 0101 */
56#define KXTF9_XOUT_L (0x06) /* 0000 0110 */
57#define KXTF9_XOUT_H (0x07) /* 0000 0111 */
58#define KXTF9_YOUT_L (0x08) /* 0000 1000 */
59#define KXTF9_YOUT_H (0x09) /* 0000 1001 */
60#define KXTF9_ZOUT_L (0x0A) /* 0001 1010 */
61#define KXTF9_ZOUT_H (0x0B) /* 0001 1011 */
62#define KXTF9_ST_RESP (0x0C) /* 0000 1100 */
63#define KXTF9_WHO_AM_I (0x0F) /* 0000 1111 */
64#define KXTF9_TILT_POS_CUR (0x10) /* 0001 0000 */
65#define KXTF9_TILT_POS_PRE (0x11) /* 0001 0001 */
66#define KXTF9_INT_SRC_REG1 (0x15) /* 0001 0101 */
67#define KXTF9_INT_SRC_REG2 (0x16) /* 0001 0110 */
68#define KXTF9_STATUS_REG (0x18) /* 0001 1000 */
69#define KXTF9_INT_REL (0x1A) /* 0001 1010 */
70#define KXTF9_CTRL_REG1 (0x1B) /* 0001 1011 */
71#define KXTF9_CTRL_REG2 (0x1C) /* 0001 1100 */
72#define KXTF9_CTRL_REG3 (0x1D) /* 0001 1101 */
73#define KXTF9_INT_CTRL_REG1 (0x1E) /* 0001 1110 */
74#define KXTF9_INT_CTRL_REG2 (0x1F) /* 0001 1111 */
75#define KXTF9_INT_CTRL_REG3 (0x20) /* 0010 0000 */
76#define KXTF9_DATA_CTRL_REG (0x21) /* 0010 0001 */
77#define KXTF9_TILT_TIMER (0x28) /* 0010 1000 */
78#define KXTF9_WUF_TIMER (0x29) /* 0010 1001 */
79#define KXTF9_TDT_TIMER (0x2B) /* 0010 1011 */
80#define KXTF9_TDT_H_THRESH (0x2C) /* 0010 1100 */
81#define KXTF9_TDT_L_THRESH (0x2D) /* 0010 1101 */
82#define KXTF9_TDT_TAP_TIMER (0x2E) /* 0010 1110 */
83#define KXTF9_TDT_TOTAL_TIMER (0x2F) /* 0010 1111 */
84#define KXTF9_TDT_LATENCY_TIMER (0x30) /* 0011 0000 */
85#define KXTF9_TDT_WINDOW_TIMER (0x31) /* 0011 0001 */
86#define KXTF9_WUF_THRESH (0x5A) /* 0101 1010 */
87#define KXTF9_TILT_ANGLE (0x5C) /* 0101 1100 */
88#define KXTF9_HYST_SET (0x5F) /* 0101 1111 */
89
90#define KXTF9_MAX_DUR (0xFF)
91#define KXTF9_MAX_THS (0xFF)
92#define KXTF9_THS_COUNTS_P_G (32)
93
94/* -------------------------------------------------------------------------- */
95
96struct kxtf9_config {
97 unsigned long odr; /* Output data rate mHz */
98 unsigned int fsr; /* full scale range mg */
99 unsigned int ths; /* Motion no-motion thseshold mg */
100 unsigned int dur; /* Motion no-motion duration ms */
101 unsigned int irq_type;
102 unsigned char reg_ths;
103 unsigned char reg_dur;
104 unsigned char reg_odr;
105 unsigned char reg_int_cfg1;
106 unsigned char reg_int_cfg2;
107 unsigned char ctrl_reg1;
108};
109
110struct kxtf9_private_data {
111 struct kxtf9_config suspend;
112 struct kxtf9_config resume;
113};
114
115static int kxtf9_set_ths(void *mlsl_handle,
116 struct ext_slave_platform_data *pdata,
117 struct kxtf9_config *config, int apply, long ths)
118{
119 int result = INV_SUCCESS;
120 if ((ths * KXTF9_THS_COUNTS_P_G / 1000) > KXTF9_MAX_THS)
121 ths = (long)(KXTF9_MAX_THS * 1000) / KXTF9_THS_COUNTS_P_G;
122
123 if (ths < 0)
124 ths = 0;
125
126 config->ths = ths;
127 config->reg_ths = (unsigned char)
128 ((long)(ths * KXTF9_THS_COUNTS_P_G) / 1000);
129 MPL_LOGV("THS: %d, 0x%02x\n", config->ths, (int)config->reg_ths);
130 if (apply)
131 result = inv_serial_single_write(mlsl_handle, pdata->address,
132 KXTF9_WUF_THRESH,
133 config->reg_ths);
134 return result;
135}
136
137static int kxtf9_set_dur(void *mlsl_handle,
138 struct ext_slave_platform_data *pdata,
139 struct kxtf9_config *config, int apply, long dur)
140{
141 int result = INV_SUCCESS;
142 long reg_dur = (dur * config->odr) / 1000000L;
143 config->dur = dur;
144
145 if (reg_dur > KXTF9_MAX_DUR)
146 reg_dur = KXTF9_MAX_DUR;
147
148 config->reg_dur = (unsigned char)reg_dur;
149 MPL_LOGV("DUR: %d, 0x%02x\n", config->dur, (int)config->reg_dur);
150 if (apply)
151 result = inv_serial_single_write(mlsl_handle, pdata->address,
152 KXTF9_WUF_TIMER,
153 (unsigned char)reg_dur);
154 return result;
155}
156
157/**
158 * Sets the IRQ to fire when one of the IRQ events occur. Threshold and
159 * duration will not be used uless the type is MOT or NMOT.
160 *
161 * @param config configuration to apply to, suspend or resume
162 * @param irq_type The type of IRQ. Valid values are
163 * - MPU_SLAVE_IRQ_TYPE_NONE
164 * - MPU_SLAVE_IRQ_TYPE_MOTION
165 * - MPU_SLAVE_IRQ_TYPE_DATA_READY
166 */
167static int kxtf9_set_irq(void *mlsl_handle,
168 struct ext_slave_platform_data *pdata,
169 struct kxtf9_config *config, int apply, long irq_type)
170{
171 int result = INV_SUCCESS;
172 struct kxtf9_private_data *private_data = pdata->private_data;
173
174 config->irq_type = (unsigned char)irq_type;
175 config->ctrl_reg1 &= ~0x22;
176 if (irq_type == MPU_SLAVE_IRQ_TYPE_DATA_READY) {
177 config->ctrl_reg1 |= 0x20;
178 config->reg_int_cfg1 = 0x38;
179 config->reg_int_cfg2 = 0x00;
180 } else if (irq_type == MPU_SLAVE_IRQ_TYPE_MOTION) {
181 config->ctrl_reg1 |= 0x02;
182 if ((unsigned long)config ==
183 (unsigned long)&private_data->suspend)
184 config->reg_int_cfg1 = 0x34;
185 else
186 config->reg_int_cfg1 = 0x24;
187 config->reg_int_cfg2 = 0xE0;
188 } else {
189 config->reg_int_cfg1 = 0x00;
190 config->reg_int_cfg2 = 0x00;
191 }
192
193 if (apply) {
194 /* Must clear bit 7 before writing new configuration */
195 result = inv_serial_single_write(mlsl_handle, pdata->address,
196 KXTF9_CTRL_REG1, 0x40);
197 result = inv_serial_single_write(mlsl_handle, pdata->address,
198 KXTF9_INT_CTRL_REG1,
199 config->reg_int_cfg1);
200 result = inv_serial_single_write(mlsl_handle, pdata->address,
201 KXTF9_INT_CTRL_REG2,
202 config->reg_int_cfg2);
203 result = inv_serial_single_write(mlsl_handle, pdata->address,
204 KXTF9_CTRL_REG1,
205 config->ctrl_reg1);
206 }
207 MPL_LOGV("CTRL_REG1: %lx, INT_CFG1: %lx, INT_CFG2: %lx\n",
208 (unsigned long)config->ctrl_reg1,
209 (unsigned long)config->reg_int_cfg1,
210 (unsigned long)config->reg_int_cfg2);
211
212 return result;
213}
214
215/**
216 * Set the Output data rate for the particular configuration
217 *
218 * @param config Config to modify with new ODR
219 * @param odr Output data rate in units of 1/1000Hz
220 */
221static int kxtf9_set_odr(void *mlsl_handle,
222 struct ext_slave_platform_data *pdata,
223 struct kxtf9_config *config, int apply, long odr)
224{
225 unsigned char bits;
226 int result = INV_SUCCESS;
227
228 /* Data sheet says there is 12.5 hz, but that seems to produce a single
229 * correct data value, thus we remove it from the table */
230 if (odr > 400000L) {
231 config->odr = 800000L;
232 bits = 0x06;
233 } else if (odr > 200000L) {
234 config->odr = 400000L;
235 bits = 0x05;
236 } else if (odr > 100000L) {
237 config->odr = 200000L;
238 bits = 0x04;
239 } else if (odr > 50000) {
240 config->odr = 100000L;
241 bits = 0x03;
242 } else if (odr > 25000) {
243 config->odr = 50000;
244 bits = 0x02;
245 } else if (odr != 0) {
246 config->odr = 25000;
247 bits = 0x01;
248 } else {
249 config->odr = 0;
250 bits = 0;
251 }
252
253 if (odr != 0)
254 config->ctrl_reg1 |= 0x80;
255 else
256 config->ctrl_reg1 &= ~0x80;
257
258 config->reg_odr = bits;
259 kxtf9_set_dur(mlsl_handle, pdata, config, apply, config->dur);
260 MPL_LOGV("ODR: %ld, 0x%02x\n", config->odr, (int)config->ctrl_reg1);
261 if (apply) {
262 result = inv_serial_single_write(mlsl_handle, pdata->address,
263 KXTF9_DATA_CTRL_REG,
264 config->reg_odr);
265 result = inv_serial_single_write(mlsl_handle, pdata->address,
266 KXTF9_CTRL_REG1, 0x40);
267 result = inv_serial_single_write(mlsl_handle, pdata->address,
268 KXTF9_CTRL_REG1,
269 config->ctrl_reg1);
270 }
271 return result;
272}
273
274/**
275 * Set the full scale range of the accels
276 *
277 * @param config pointer to configuration
278 * @param fsr requested full scale range
279 */
280static int kxtf9_set_fsr(void *mlsl_handle,
281 struct ext_slave_platform_data *pdata,
282 struct kxtf9_config *config, int apply, long fsr)
283{
284 int result = INV_SUCCESS;
285
286 config->ctrl_reg1 = (config->ctrl_reg1 & 0xE7);
287 if (fsr <= 2000) {
288 config->fsr = 2000;
289 config->ctrl_reg1 |= 0x00;
290 } else if (fsr <= 4000) {
291 config->fsr = 4000;
292 config->ctrl_reg1 |= 0x08;
293 } else {
294 config->fsr = 8000;
295 config->ctrl_reg1 |= 0x10;
296 }
297
298 MPL_LOGV("FSR: %d\n", config->fsr);
299 if (apply) {
300 /* Must clear bit 7 before writing new configuration */
301 result = inv_serial_single_write(mlsl_handle, pdata->address,
302 KXTF9_CTRL_REG1, 0x40);
303 result = inv_serial_single_write(mlsl_handle, pdata->address,
304 KXTF9_CTRL_REG1,
305 config->ctrl_reg1);
306 }
307 return result;
308}
309
310static int kxtf9_suspend(void *mlsl_handle,
311 struct ext_slave_descr *slave,
312 struct ext_slave_platform_data *pdata)
313{
314 int result;
315 unsigned char data;
316 struct kxtf9_private_data *private_data = pdata->private_data;
317
318 /* Wake up */
319 result = inv_serial_single_write(mlsl_handle, pdata->address,
320 KXTF9_CTRL_REG1, 0x40);
321 if (result) {
322 LOG_RESULT_LOCATION(result);
323 return result;
324 }
325 /* INT_CTRL_REG1: */
326 result = inv_serial_single_write(mlsl_handle, pdata->address,
327 KXTF9_INT_CTRL_REG1,
328 private_data->suspend.reg_int_cfg1);
329 if (result) {
330 LOG_RESULT_LOCATION(result);
331 return result;
332 }
333 /* WUF_THRESH: */
334 result = inv_serial_single_write(mlsl_handle, pdata->address,
335 KXTF9_WUF_THRESH,
336 private_data->suspend.reg_ths);
337 if (result) {
338 LOG_RESULT_LOCATION(result);
339 return result;
340 }
341 /* DATA_CTRL_REG */
342 result = inv_serial_single_write(mlsl_handle, pdata->address,
343 KXTF9_DATA_CTRL_REG,
344 private_data->suspend.reg_odr);
345 if (result) {
346 LOG_RESULT_LOCATION(result);
347 return result;
348 }
349 /* WUF_TIMER */
350 result = inv_serial_single_write(mlsl_handle, pdata->address,
351 KXTF9_WUF_TIMER,
352 private_data->suspend.reg_dur);
353 if (result) {
354 LOG_RESULT_LOCATION(result);
355 return result;
356 }
357
358 /* Normal operation */
359 result = inv_serial_single_write(mlsl_handle, pdata->address,
360 KXTF9_CTRL_REG1,
361 private_data->suspend.ctrl_reg1);
362 if (result) {
363 LOG_RESULT_LOCATION(result);
364 return result;
365 }
366 result = inv_serial_read(mlsl_handle, pdata->address,
367 KXTF9_INT_REL, 1, &data);
368 if (result) {
369 LOG_RESULT_LOCATION(result);
370 return result;
371 }
372
373 return result;
374}
375
376/* full scale setting - register and mask */
377#define ACCEL_KIONIX_CTRL_REG (0x1b)
378#define ACCEL_KIONIX_CTRL_MASK (0x18)
379
380static int kxtf9_resume(void *mlsl_handle,
381 struct ext_slave_descr *slave,
382 struct ext_slave_platform_data *pdata)
383{
384 int result = INV_SUCCESS;
385 unsigned char data;
386 struct kxtf9_private_data *private_data = pdata->private_data;
387
388 /* Wake up */
389 result = inv_serial_single_write(mlsl_handle, pdata->address,
390 KXTF9_CTRL_REG1, 0x40);
391 if (result) {
392 LOG_RESULT_LOCATION(result);
393 return result;
394 }
395 /* INT_CTRL_REG1: */
396 result = inv_serial_single_write(mlsl_handle, pdata->address,
397 KXTF9_INT_CTRL_REG1,
398 private_data->resume.reg_int_cfg1);
399 if (result) {
400 LOG_RESULT_LOCATION(result);
401 return result;
402 }
403 /* WUF_THRESH: */
404 result = inv_serial_single_write(mlsl_handle, pdata->address,
405 KXTF9_WUF_THRESH,
406 private_data->resume.reg_ths);
407 if (result) {
408 LOG_RESULT_LOCATION(result);
409 return result;
410 }
411 /* DATA_CTRL_REG */
412 result = inv_serial_single_write(mlsl_handle, pdata->address,
413 KXTF9_DATA_CTRL_REG,
414 private_data->resume.reg_odr);
415 if (result) {
416 LOG_RESULT_LOCATION(result);
417 return result;
418 }
419 /* WUF_TIMER */
420 result = inv_serial_single_write(mlsl_handle, pdata->address,
421 KXTF9_WUF_TIMER,
422 private_data->resume.reg_dur);
423 if (result) {
424 LOG_RESULT_LOCATION(result);
425 return result;
426 }
427
428 /* Normal operation */
429 result = inv_serial_single_write(mlsl_handle, pdata->address,
430 KXTF9_CTRL_REG1,
431 private_data->resume.ctrl_reg1);
432 if (result) {
433 LOG_RESULT_LOCATION(result);
434 return result;
435 }
436 result = inv_serial_read(mlsl_handle, pdata->address,
437 KXTF9_INT_REL, 1, &data);
438 if (result) {
439 LOG_RESULT_LOCATION(result);
440 return result;
441 }
442
443 return INV_SUCCESS;
444}
445
446static int kxtf9_init(void *mlsl_handle,
447 struct ext_slave_descr *slave,
448 struct ext_slave_platform_data *pdata)
449{
450
451 struct kxtf9_private_data *private_data;
452 int result = INV_SUCCESS;
453
454 private_data = (struct kxtf9_private_data *)
455 kzalloc(sizeof(struct kxtf9_private_data), GFP_KERNEL);
456
457 if (!private_data)
458 return INV_ERROR_MEMORY_EXAUSTED;
459
460 /* RAM reset */
461 /* Fastest Reset */
462 result = inv_serial_single_write(mlsl_handle, pdata->address,
463 KXTF9_CTRL_REG1, 0x40);
464 if (result) {
465 LOG_RESULT_LOCATION(result);
466 return result;
467 }
468 /* Fastest Reset */
469 result = inv_serial_single_write(mlsl_handle, pdata->address,
470 KXTF9_DATA_CTRL_REG, 0x36);
471 if (result) {
472 LOG_RESULT_LOCATION(result);
473 return result;
474 }
475 /* Reset */
476 result = inv_serial_single_write(mlsl_handle, pdata->address,
477 KXTF9_CTRL_REG3, 0xcd);
478 if (result) {
479 LOG_RESULT_LOCATION(result);
480 return result;
481 }
482 msleep(2);
483
484 pdata->private_data = private_data;
485
486 private_data->resume.ctrl_reg1 = 0xC0;
487 private_data->suspend.ctrl_reg1 = 0x40;
488
489 result = kxtf9_set_dur(mlsl_handle, pdata, &private_data->suspend,
490 false, 1000);
491 if (result) {
492 LOG_RESULT_LOCATION(result);
493 return result;
494 }
495 result = kxtf9_set_dur(mlsl_handle, pdata, &private_data->resume,
496 false, 2540);
497 if (result) {
498 LOG_RESULT_LOCATION(result);
499 return result;
500 }
501
502 result = kxtf9_set_odr(mlsl_handle, pdata, &private_data->suspend,
503 false, 50000);
504 if (result) {
505 LOG_RESULT_LOCATION(result);
506 return result;
507 }
508 result = kxtf9_set_odr(mlsl_handle, pdata, &private_data->resume,
509 false, 200000L);
510
511 result = kxtf9_set_fsr(mlsl_handle, pdata, &private_data->suspend,
512 false, 2000);
513 if (result) {
514 LOG_RESULT_LOCATION(result);
515 return result;
516 }
517 result = kxtf9_set_fsr(mlsl_handle, pdata, &private_data->resume,
518 false, 2000);
519 if (result) {
520 LOG_RESULT_LOCATION(result);
521 return result;
522 }
523
524 result = kxtf9_set_ths(mlsl_handle, pdata, &private_data->suspend,
525 false, 80);
526 if (result) {
527 LOG_RESULT_LOCATION(result);
528 return result;
529 }
530 result = kxtf9_set_ths(mlsl_handle, pdata, &private_data->resume,
531 false, 40);
532 if (result) {
533 LOG_RESULT_LOCATION(result);
534 return result;
535 }
536
537 result = kxtf9_set_irq(mlsl_handle, pdata, &private_data->suspend,
538 false, MPU_SLAVE_IRQ_TYPE_NONE);
539 if (result) {
540 LOG_RESULT_LOCATION(result);
541 return result;
542 }
543 result = kxtf9_set_irq(mlsl_handle, pdata, &private_data->resume,
544 false, MPU_SLAVE_IRQ_TYPE_NONE);
545 if (result) {
546 LOG_RESULT_LOCATION(result);
547 return result;
548 }
549 return result;
550}
551
552static int kxtf9_exit(void *mlsl_handle,
553 struct ext_slave_descr *slave,
554 struct ext_slave_platform_data *pdata)
555{
556 kfree(pdata->private_data);
557 return INV_SUCCESS;
558}
559
560static int kxtf9_config(void *mlsl_handle,
561 struct ext_slave_descr *slave,
562 struct ext_slave_platform_data *pdata,
563 struct ext_slave_config *data)
564{
565 struct kxtf9_private_data *private_data = pdata->private_data;
566 if (!data->data)
567 return INV_ERROR_INVALID_PARAMETER;
568
569 switch (data->key) {
570 case MPU_SLAVE_CONFIG_ODR_SUSPEND:
571 return kxtf9_set_odr(mlsl_handle, pdata,
572 &private_data->suspend,
573 data->apply, *((long *)data->data));
574 case MPU_SLAVE_CONFIG_ODR_RESUME:
575 return kxtf9_set_odr(mlsl_handle, pdata,
576 &private_data->resume,
577 data->apply, *((long *)data->data));
578 case MPU_SLAVE_CONFIG_FSR_SUSPEND:
579 return kxtf9_set_fsr(mlsl_handle, pdata,
580 &private_data->suspend,
581 data->apply, *((long *)data->data));
582 case MPU_SLAVE_CONFIG_FSR_RESUME:
583 return kxtf9_set_fsr(mlsl_handle, pdata,
584 &private_data->resume,
585 data->apply, *((long *)data->data));
586 case MPU_SLAVE_CONFIG_MOT_THS:
587 return kxtf9_set_ths(mlsl_handle, pdata,
588 &private_data->suspend,
589 data->apply, *((long *)data->data));
590 case MPU_SLAVE_CONFIG_NMOT_THS:
591 return kxtf9_set_ths(mlsl_handle, pdata,
592 &private_data->resume,
593 data->apply, *((long *)data->data));
594 case MPU_SLAVE_CONFIG_MOT_DUR:
595 return kxtf9_set_dur(mlsl_handle, pdata,
596 &private_data->suspend,
597 data->apply, *((long *)data->data));
598 case MPU_SLAVE_CONFIG_NMOT_DUR:
599 return kxtf9_set_dur(mlsl_handle, pdata,
600 &private_data->resume,
601 data->apply, *((long *)data->data));
602 case MPU_SLAVE_CONFIG_IRQ_SUSPEND:
603 return kxtf9_set_irq(mlsl_handle, pdata,
604 &private_data->suspend,
605 data->apply, *((long *)data->data));
606 case MPU_SLAVE_CONFIG_IRQ_RESUME:
607 return kxtf9_set_irq(mlsl_handle, pdata,
608 &private_data->resume,
609 data->apply, *((long *)data->data));
610 default:
611 return INV_ERROR_FEATURE_NOT_IMPLEMENTED;
612 };
613
614 return INV_SUCCESS;
615}
616
617static int kxtf9_get_config(void *mlsl_handle,
618 struct ext_slave_descr *slave,
619 struct ext_slave_platform_data *pdata,
620 struct ext_slave_config *data)
621{
622 struct kxtf9_private_data *private_data = pdata->private_data;
623 if (!data->data)
624 return INV_ERROR_INVALID_PARAMETER;
625
626 switch (data->key) {
627 case MPU_SLAVE_CONFIG_ODR_SUSPEND:
628 (*(unsigned long *)data->data) =
629 (unsigned long)private_data->suspend.odr;
630 break;
631 case MPU_SLAVE_CONFIG_ODR_RESUME:
632 (*(unsigned long *)data->data) =
633 (unsigned long)private_data->resume.odr;
634 break;
635 case MPU_SLAVE_CONFIG_FSR_SUSPEND:
636 (*(unsigned long *)data->data) =
637 (unsigned long)private_data->suspend.fsr;
638 break;
639 case MPU_SLAVE_CONFIG_FSR_RESUME:
640 (*(unsigned long *)data->data) =
641 (unsigned long)private_data->resume.fsr;
642 break;
643 case MPU_SLAVE_CONFIG_MOT_THS:
644 (*(unsigned long *)data->data) =
645 (unsigned long)private_data->suspend.ths;
646 break;
647 case MPU_SLAVE_CONFIG_NMOT_THS:
648 (*(unsigned long *)data->data) =
649 (unsigned long)private_data->resume.ths;
650 break;
651 case MPU_SLAVE_CONFIG_MOT_DUR:
652 (*(unsigned long *)data->data) =
653 (unsigned long)private_data->suspend.dur;
654 break;
655 case MPU_SLAVE_CONFIG_NMOT_DUR:
656 (*(unsigned long *)data->data) =
657 (unsigned long)private_data->resume.dur;
658 break;
659 case MPU_SLAVE_CONFIG_IRQ_SUSPEND:
660 (*(unsigned long *)data->data) =
661 (unsigned long)private_data->suspend.irq_type;
662 break;
663 case MPU_SLAVE_CONFIG_IRQ_RESUME:
664 (*(unsigned long *)data->data) =
665 (unsigned long)private_data->resume.irq_type;
666 break;
667 default:
668 return INV_ERROR_FEATURE_NOT_IMPLEMENTED;
669 };
670
671 return INV_SUCCESS;
672}
673
674static int kxtf9_read(void *mlsl_handle,
675 struct ext_slave_descr *slave,
676 struct ext_slave_platform_data *pdata,
677 unsigned char *data)
678{
679 int result;
680 unsigned char reg;
681 result = inv_serial_read(mlsl_handle, pdata->address,
682 KXTF9_INT_SRC_REG2, 1, &reg);
683 if (result) {
684 LOG_RESULT_LOCATION(result);
685 return result;
686 }
687
688 if (!(reg & 0x10))
689 return INV_ERROR_ACCEL_DATA_NOT_READY;
690
691 result = inv_serial_read(mlsl_handle, pdata->address,
692 slave->read_reg, slave->read_len, data);
693 if (result) {
694 LOG_RESULT_LOCATION(result);
695 return result;
696 }
697 return result;
698}
699
700static struct ext_slave_descr kxtf9_descr = {
701 .init = kxtf9_init,
702 .exit = kxtf9_exit,
703 .suspend = kxtf9_suspend,
704 .resume = kxtf9_resume,
705 .read = kxtf9_read,
706 .config = kxtf9_config,
707 .get_config = kxtf9_get_config,
708 .name = "kxtf9",
709 .type = EXT_SLAVE_TYPE_ACCEL,
710 .id = ACCEL_ID_KXTF9,
711 .read_reg = 0x06,
712 .read_len = 6,
713 .endian = EXT_SLAVE_LITTLE_ENDIAN,
714 .range = {2, 0},
715 .trigger = NULL,
716};
717
718static
719struct ext_slave_descr *kxtf9_get_slave_descr(void)
720{
721 return &kxtf9_descr;
722}
723
724/* -------------------------------------------------------------------------- */
725struct kxtf9_mod_private_data {
726 struct i2c_client *client;
727 struct ext_slave_platform_data *pdata;
728};
729
730static unsigned short normal_i2c[] = { I2C_CLIENT_END };
731
732static int kxtf9_mod_probe(struct i2c_client *client,
733 const struct i2c_device_id *devid)
734{
735 struct ext_slave_platform_data *pdata;
736 struct kxtf9_mod_private_data *private_data;
737 int result = 0;
738
739 dev_info(&client->adapter->dev, "%s: %s\n", __func__, devid->name);
740
741 if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
742 result = -ENODEV;
743 goto out_no_free;
744 }
745
746 pdata = client->dev.platform_data;
747 if (!pdata) {
748 dev_err(&client->adapter->dev,
749 "Missing platform data for slave %s\n", devid->name);
750 result = -EFAULT;
751 goto out_no_free;
752 }
753
754 private_data = kzalloc(sizeof(*private_data), GFP_KERNEL);
755 if (!private_data) {
756 result = -ENOMEM;
757 goto out_no_free;
758 }
759
760 i2c_set_clientdata(client, private_data);
761 private_data->client = client;
762 private_data->pdata = pdata;
763
764 result = inv_mpu_register_slave(THIS_MODULE, client, pdata,
765 kxtf9_get_slave_descr);
766 if (result) {
767 dev_err(&client->adapter->dev,
768 "Slave registration failed: %s, %d\n",
769 devid->name, result);
770 goto out_free_memory;
771 }
772
773 return result;
774
775out_free_memory:
776 kfree(private_data);
777out_no_free:
778 dev_err(&client->adapter->dev, "%s failed %d\n", __func__, result);
779 return result;
780
781}
782
783static int kxtf9_mod_remove(struct i2c_client *client)
784{
785 struct kxtf9_mod_private_data *private_data =
786 i2c_get_clientdata(client);
787
788 dev_dbg(&client->adapter->dev, "%s\n", __func__);
789
790 inv_mpu_unregister_slave(client, private_data->pdata,
791 kxtf9_get_slave_descr);
792
793 kfree(private_data);
794 return 0;
795}
796
797static const struct i2c_device_id kxtf9_mod_id[] = {
798 { "kxtf9", ACCEL_ID_KXTF9 },
799 {}
800};
801
802MODULE_DEVICE_TABLE(i2c, kxtf9_mod_id);
803
804static struct i2c_driver kxtf9_mod_driver = {
805 .class = I2C_CLASS_HWMON,
806 .probe = kxtf9_mod_probe,
807 .remove = kxtf9_mod_remove,
808 .id_table = kxtf9_mod_id,
809 .driver = {
810 .owner = THIS_MODULE,
811 .name = "kxtf9_mod",
812 },
813 .address_list = normal_i2c,
814};
815
816static int __init kxtf9_mod_init(void)
817{
818 int res = i2c_add_driver(&kxtf9_mod_driver);
819 pr_info("%s: Probe name %s\n", __func__, "kxtf9_mod");
820 if (res)
821 pr_err("%s failed\n", __func__);
822 return res;
823}
824
825static void __exit kxtf9_mod_exit(void)
826{
827 pr_info("%s\n", __func__);
828 i2c_del_driver(&kxtf9_mod_driver);
829}
830
831module_init(kxtf9_mod_init);
832module_exit(kxtf9_mod_exit);
833
834MODULE_AUTHOR("Invensense Corporation");
835MODULE_DESCRIPTION("Driver to integrate KXTF9 sensor with the MPU");
836MODULE_LICENSE("GPL");
837MODULE_ALIAS("kxtf9_mod");
838
839/**
840 * @}
841 */
diff --git a/drivers/misc/inv_mpu/accel/lis331.c b/drivers/misc/inv_mpu/accel/lis331.c
new file mode 100644
index 00000000000..bcbec252af9
--- /dev/null
+++ b/drivers/misc/inv_mpu/accel/lis331.c
@@ -0,0 +1,745 @@
1/*
2 $License:
3 Copyright (C) 2011 InvenSense Corporation, All Rights Reserved.
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, see <http://www.gnu.org/licenses/>.
17 $
18 */
19
20/**
21 * @addtogroup ACCELDL
22 * @brief Provides the interface to setup and handle an accelerometer.
23 *
24 * @{
25 * @file lis331.c
26 * @brief Accelerometer setup and handling methods for ST LIS331DLH.
27 */
28
29/* -------------------------------------------------------------------------- */
30
31#undef MPL_LOG_NDEBUG
32#define MPL_LOG_NDEBUG 1
33
34#include <linux/i2c.h>
35#include <linux/module.h>
36#include <linux/moduleparam.h>
37#include <linux/kernel.h>
38#include <linux/errno.h>
39#include <linux/slab.h>
40#include <linux/delay.h>
41#include "mpu-dev.h"
42
43#include <log.h>
44#include <linux/mpu.h>
45#include "mlsl.h"
46#include "mldl_cfg.h"
47#undef MPL_LOG_TAG
48#define MPL_LOG_TAG "MPL-acc"
49
50/* full scale setting - register & mask */
51#define LIS331DLH_CTRL_REG1 (0x20)
52#define LIS331DLH_CTRL_REG2 (0x21)
53#define LIS331DLH_CTRL_REG3 (0x22)
54#define LIS331DLH_CTRL_REG4 (0x23)
55#define LIS331DLH_CTRL_REG5 (0x24)
56#define LIS331DLH_HP_FILTER_RESET (0x25)
57#define LIS331DLH_REFERENCE (0x26)
58#define LIS331DLH_STATUS_REG (0x27)
59#define LIS331DLH_OUT_X_L (0x28)
60#define LIS331DLH_OUT_X_H (0x29)
61#define LIS331DLH_OUT_Y_L (0x2a)
62#define LIS331DLH_OUT_Y_H (0x2b)
63#define LIS331DLH_OUT_Z_L (0x2b)
64#define LIS331DLH_OUT_Z_H (0x2d)
65
66#define LIS331DLH_INT1_CFG (0x30)
67#define LIS331DLH_INT1_SRC (0x31)
68#define LIS331DLH_INT1_THS (0x32)
69#define LIS331DLH_INT1_DURATION (0x33)
70
71#define LIS331DLH_INT2_CFG (0x34)
72#define LIS331DLH_INT2_SRC (0x35)
73#define LIS331DLH_INT2_THS (0x36)
74#define LIS331DLH_INT2_DURATION (0x37)
75
76/* CTRL_REG1 */
77#define LIS331DLH_CTRL_MASK (0x30)
78#define LIS331DLH_SLEEP_MASK (0x20)
79#define LIS331DLH_PWR_MODE_NORMAL (0x20)
80
81#define LIS331DLH_MAX_DUR (0x7F)
82
83
84/* -------------------------------------------------------------------------- */
85
86struct lis331dlh_config {
87 unsigned int odr;
88 unsigned int fsr; /* full scale range mg */
89 unsigned int ths; /* Motion no-motion thseshold mg */
90 unsigned int dur; /* Motion no-motion duration ms */
91 unsigned char reg_ths;
92 unsigned char reg_dur;
93 unsigned char ctrl_reg1;
94 unsigned char irq_type;
95 unsigned char mot_int1_cfg;
96};
97
98struct lis331dlh_private_data {
99 struct lis331dlh_config suspend;
100 struct lis331dlh_config resume;
101};
102
103/* -------------------------------------------------------------------------- */
104static int lis331dlh_set_ths(void *mlsl_handle,
105 struct ext_slave_platform_data *pdata,
106 struct lis331dlh_config *config,
107 int apply, long ths)
108{
109 int result = INV_SUCCESS;
110 if ((unsigned int)ths >= config->fsr)
111 ths = (long)config->fsr - 1;
112
113 if (ths < 0)
114 ths = 0;
115
116 config->ths = ths;
117 config->reg_ths = (unsigned char)(long)((ths * 128L) / (config->fsr));
118 MPL_LOGV("THS: %d, 0x%02x\n", config->ths, (int)config->reg_ths);
119 if (apply)
120 result = inv_serial_single_write(mlsl_handle, pdata->address,
121 LIS331DLH_INT1_THS,
122 config->reg_ths);
123 return result;
124}
125
126static int lis331dlh_set_dur(void *mlsl_handle,
127 struct ext_slave_platform_data *pdata,
128 struct lis331dlh_config *config,
129 int apply, long dur)
130{
131 int result = INV_SUCCESS;
132 long reg_dur = (dur * config->odr) / 1000000L;
133 config->dur = dur;
134
135 if (reg_dur > LIS331DLH_MAX_DUR)
136 reg_dur = LIS331DLH_MAX_DUR;
137
138 config->reg_dur = (unsigned char)reg_dur;
139 MPL_LOGV("DUR: %d, 0x%02x\n", config->dur, (int)config->reg_dur);
140 if (apply)
141 result = inv_serial_single_write(mlsl_handle, pdata->address,
142 LIS331DLH_INT1_DURATION,
143 (unsigned char)reg_dur);
144 return result;
145}
146
147/**
148 * Sets the IRQ to fire when one of the IRQ events occur. Threshold and
149 * duration will not be used uless the type is MOT or NMOT.
150 *
151 * @param config configuration to apply to, suspend or resume
152 * @param irq_type The type of IRQ. Valid values are
153 * - MPU_SLAVE_IRQ_TYPE_NONE
154 * - MPU_SLAVE_IRQ_TYPE_MOTION
155 * - MPU_SLAVE_IRQ_TYPE_DATA_READY
156 */
157static int lis331dlh_set_irq(void *mlsl_handle,
158 struct ext_slave_platform_data *pdata,
159 struct lis331dlh_config *config,
160 int apply, long irq_type)
161{
162 int result = INV_SUCCESS;
163 unsigned char reg1;
164 unsigned char reg2;
165
166 config->irq_type = (unsigned char)irq_type;
167 if (irq_type == MPU_SLAVE_IRQ_TYPE_DATA_READY) {
168 reg1 = 0x02;
169 reg2 = 0x00;
170 } else if (irq_type == MPU_SLAVE_IRQ_TYPE_MOTION) {
171 reg1 = 0x00;
172 reg2 = config->mot_int1_cfg;
173 } else {
174 reg1 = 0x00;
175 reg2 = 0x00;
176 }
177
178 if (apply) {
179 result = inv_serial_single_write(mlsl_handle, pdata->address,
180 LIS331DLH_CTRL_REG3, reg1);
181 result = inv_serial_single_write(mlsl_handle, pdata->address,
182 LIS331DLH_INT1_CFG, reg2);
183 }
184
185 return result;
186}
187
188/**
189 * Set the Output data rate for the particular configuration
190 *
191 * @param config Config to modify with new ODR
192 * @param odr Output data rate in units of 1/1000Hz
193 */
194static int lis331dlh_set_odr(void *mlsl_handle,
195 struct ext_slave_platform_data *pdata,
196 struct lis331dlh_config *config,
197 int apply, long odr)
198{
199 unsigned char bits;
200 int result = INV_SUCCESS;
201
202 /* normal power modes */
203 if (odr > 400000) {
204 config->odr = 1000000;
205 bits = LIS331DLH_PWR_MODE_NORMAL | 0x18;
206 } else if (odr > 100000) {
207 config->odr = 400000;
208 bits = LIS331DLH_PWR_MODE_NORMAL | 0x10;
209 } else if (odr > 50000) {
210 config->odr = 100000;
211 bits = LIS331DLH_PWR_MODE_NORMAL | 0x08;
212 } else if (odr > 10000) {
213 config->odr = 50000;
214 bits = LIS331DLH_PWR_MODE_NORMAL | 0x00;
215 /* low power modes */
216 } else if (odr > 5000) {
217 config->odr = 10000;
218 bits = 0xC0;
219 } else if (odr > 2000) {
220 config->odr = 5000;
221 bits = 0xA0;
222 } else if (odr > 1000) {
223 config->odr = 2000;
224 bits = 0x80;
225 } else if (odr > 500) {
226 config->odr = 1000;
227 bits = 0x60;
228 } else if (odr > 0) {
229 config->odr = 500;
230 bits = 0x40;
231 } else {
232 config->odr = 0;
233 bits = 0;
234 }
235
236 config->ctrl_reg1 = bits | (config->ctrl_reg1 & 0x7);
237 lis331dlh_set_dur(mlsl_handle, pdata, config, apply, config->dur);
238 MPL_LOGV("ODR: %d, 0x%02x\n", config->odr, (int)config->ctrl_reg1);
239 if (apply)
240 result = inv_serial_single_write(mlsl_handle, pdata->address,
241 LIS331DLH_CTRL_REG1,
242 config->ctrl_reg1);
243 return result;
244}
245
246/**
247 * Set the full scale range of the accels
248 *
249 * @param config pointer to configuration
250 * @param fsr requested full scale range
251 */
252static int lis331dlh_set_fsr(void *mlsl_handle,
253 struct ext_slave_platform_data *pdata,
254 struct lis331dlh_config *config,
255 int apply, long fsr)
256{
257 unsigned char reg1 = 0x40;
258 int result = INV_SUCCESS;
259
260 if (fsr <= 2048) {
261 config->fsr = 2048;
262 } else if (fsr <= 4096) {
263 reg1 |= 0x30;
264 config->fsr = 4096;
265 } else {
266 reg1 |= 0x10;
267 config->fsr = 8192;
268 }
269
270 lis331dlh_set_ths(mlsl_handle, pdata, config, apply, config->ths);
271 MPL_LOGV("FSR: %d\n", config->fsr);
272 if (apply)
273 result = inv_serial_single_write(mlsl_handle, pdata->address,
274 LIS331DLH_CTRL_REG4, reg1);
275
276 return result;
277}
278
279static int lis331dlh_suspend(void *mlsl_handle,
280 struct ext_slave_descr *slave,
281 struct ext_slave_platform_data *pdata)
282{
283 int result = INV_SUCCESS;
284 unsigned char reg1;
285 unsigned char reg2;
286 struct lis331dlh_private_data *private_data =
287 (struct lis331dlh_private_data *)(pdata->private_data);
288
289 result = inv_serial_single_write(mlsl_handle, pdata->address,
290 LIS331DLH_CTRL_REG1,
291 private_data->suspend.ctrl_reg1);
292
293 result = inv_serial_single_write(mlsl_handle, pdata->address,
294 LIS331DLH_CTRL_REG2, 0x0f);
295 reg1 = 0x40;
296 if (private_data->suspend.fsr == 8192)
297 reg1 |= 0x30;
298 else if (private_data->suspend.fsr == 4096)
299 reg1 |= 0x10;
300 /* else bits [4..5] are already zero */
301
302 result = inv_serial_single_write(mlsl_handle, pdata->address,
303 LIS331DLH_CTRL_REG4, reg1);
304 result = inv_serial_single_write(mlsl_handle, pdata->address,
305 LIS331DLH_INT1_THS,
306 private_data->suspend.reg_ths);
307 result = inv_serial_single_write(mlsl_handle, pdata->address,
308 LIS331DLH_INT1_DURATION,
309 private_data->suspend.reg_dur);
310
311 if (private_data->suspend.irq_type == MPU_SLAVE_IRQ_TYPE_DATA_READY) {
312 reg1 = 0x02;
313 reg2 = 0x00;
314 } else if (private_data->suspend.irq_type ==
315 MPU_SLAVE_IRQ_TYPE_MOTION) {
316 reg1 = 0x00;
317 reg2 = private_data->suspend.mot_int1_cfg;
318 } else {
319 reg1 = 0x00;
320 reg2 = 0x00;
321 }
322 result = inv_serial_single_write(mlsl_handle, pdata->address,
323 LIS331DLH_CTRL_REG3, reg1);
324 result = inv_serial_single_write(mlsl_handle, pdata->address,
325 LIS331DLH_INT1_CFG, reg2);
326 result = inv_serial_read(mlsl_handle, pdata->address,
327 LIS331DLH_HP_FILTER_RESET, 1, &reg1);
328 return result;
329}
330
331static int lis331dlh_resume(void *mlsl_handle,
332 struct ext_slave_descr *slave,
333 struct ext_slave_platform_data *pdata)
334{
335 int result = INV_SUCCESS;
336 unsigned char reg1;
337 unsigned char reg2;
338 struct lis331dlh_private_data *private_data =
339 (struct lis331dlh_private_data *)(pdata->private_data);
340
341 result = inv_serial_single_write(mlsl_handle, pdata->address,
342 LIS331DLH_CTRL_REG1,
343 private_data->resume.ctrl_reg1);
344 if (result) {
345 LOG_RESULT_LOCATION(result);
346 return result;
347 }
348 msleep(6);
349
350 /* Full Scale */
351 reg1 = 0x40;
352 if (private_data->resume.fsr == 8192)
353 reg1 |= 0x30;
354 else if (private_data->resume.fsr == 4096)
355 reg1 |= 0x10;
356
357 result = inv_serial_single_write(mlsl_handle, pdata->address,
358 LIS331DLH_CTRL_REG4, reg1);
359 if (result) {
360 LOG_RESULT_LOCATION(result);
361 return result;
362 }
363
364 /* Configure high pass filter */
365 result = inv_serial_single_write(mlsl_handle, pdata->address,
366 LIS331DLH_CTRL_REG2, 0x0F);
367 if (result) {
368 LOG_RESULT_LOCATION(result);
369 return result;
370 }
371
372 if (private_data->resume.irq_type == MPU_SLAVE_IRQ_TYPE_DATA_READY) {
373 reg1 = 0x02;
374 reg2 = 0x00;
375 } else if (private_data->resume.irq_type == MPU_SLAVE_IRQ_TYPE_MOTION) {
376 reg1 = 0x00;
377 reg2 = private_data->resume.mot_int1_cfg;
378 } else {
379 reg1 = 0x00;
380 reg2 = 0x00;
381 }
382 result = inv_serial_single_write(mlsl_handle, pdata->address,
383 LIS331DLH_CTRL_REG3, reg1);
384 if (result) {
385 LOG_RESULT_LOCATION(result);
386 return result;
387 }
388 result = inv_serial_single_write(mlsl_handle, pdata->address,
389 LIS331DLH_INT1_THS,
390 private_data->resume.reg_ths);
391 if (result) {
392 LOG_RESULT_LOCATION(result);
393 return result;
394 }
395 result = inv_serial_single_write(mlsl_handle, pdata->address,
396 LIS331DLH_INT1_DURATION,
397 private_data->resume.reg_dur);
398 if (result) {
399 LOG_RESULT_LOCATION(result);
400 return result;
401 }
402 result = inv_serial_single_write(mlsl_handle, pdata->address,
403 LIS331DLH_INT1_CFG, reg2);
404 if (result) {
405 LOG_RESULT_LOCATION(result);
406 return result;
407 }
408 result = inv_serial_read(mlsl_handle, pdata->address,
409 LIS331DLH_HP_FILTER_RESET, 1, &reg1);
410 if (result) {
411 LOG_RESULT_LOCATION(result);
412 return result;
413 }
414 return result;
415}
416
417static int lis331dlh_read(void *mlsl_handle,
418 struct ext_slave_descr *slave,
419 struct ext_slave_platform_data *pdata,
420 unsigned char *data)
421{
422 int result = INV_SUCCESS;
423 result = inv_serial_read(mlsl_handle, pdata->address,
424 LIS331DLH_STATUS_REG, 1, data);
425 if (data[0] & 0x0F) {
426 result = inv_serial_read(mlsl_handle, pdata->address,
427 slave->read_reg, slave->read_len,
428 data);
429 return result;
430 } else
431 return INV_ERROR_ACCEL_DATA_NOT_READY;
432}
433
434static int lis331dlh_init(void *mlsl_handle,
435 struct ext_slave_descr *slave,
436 struct ext_slave_platform_data *pdata)
437{
438 struct lis331dlh_private_data *private_data;
439 long range;
440 private_data = (struct lis331dlh_private_data *)
441 kzalloc(sizeof(struct lis331dlh_private_data), GFP_KERNEL);
442
443 if (!private_data)
444 return INV_ERROR_MEMORY_EXAUSTED;
445
446 pdata->private_data = private_data;
447
448 private_data->resume.ctrl_reg1 = 0x37;
449 private_data->suspend.ctrl_reg1 = 0x47;
450 private_data->resume.mot_int1_cfg = 0x95;
451 private_data->suspend.mot_int1_cfg = 0x2a;
452
453 lis331dlh_set_odr(mlsl_handle, pdata, &private_data->suspend, false, 0);
454 lis331dlh_set_odr(mlsl_handle, pdata, &private_data->resume,
455 false, 200000);
456
457 range = range_fixedpoint_to_long_mg(slave->range);
458 lis331dlh_set_fsr(mlsl_handle, pdata, &private_data->suspend,
459 false, range);
460 lis331dlh_set_fsr(mlsl_handle, pdata, &private_data->resume,
461 false, range);
462
463 lis331dlh_set_ths(mlsl_handle, pdata, &private_data->suspend,
464 false, 80);
465 lis331dlh_set_ths(mlsl_handle, pdata, &private_data->resume, false, 40);
466
467
468 lis331dlh_set_dur(mlsl_handle, pdata, &private_data->suspend,
469 false, 1000);
470 lis331dlh_set_dur(mlsl_handle, pdata, &private_data->resume,
471 false, 2540);
472
473 lis331dlh_set_irq(mlsl_handle, pdata, &private_data->suspend,
474 false, MPU_SLAVE_IRQ_TYPE_NONE);
475 lis331dlh_set_irq(mlsl_handle, pdata, &private_data->resume,
476 false, MPU_SLAVE_IRQ_TYPE_NONE);
477 return INV_SUCCESS;
478}
479
480static int lis331dlh_exit(void *mlsl_handle,
481 struct ext_slave_descr *slave,
482 struct ext_slave_platform_data *pdata)
483{
484 kfree(pdata->private_data);
485 return INV_SUCCESS;
486}
487
488static int lis331dlh_config(void *mlsl_handle,
489 struct ext_slave_descr *slave,
490 struct ext_slave_platform_data *pdata,
491 struct ext_slave_config *data)
492{
493 struct lis331dlh_private_data *private_data = pdata->private_data;
494 if (!data->data)
495 return INV_ERROR_INVALID_PARAMETER;
496
497 switch (data->key) {
498 case MPU_SLAVE_CONFIG_ODR_SUSPEND:
499 return lis331dlh_set_odr(mlsl_handle, pdata,
500 &private_data->suspend,
501 data->apply, *((long *)data->data));
502 case MPU_SLAVE_CONFIG_ODR_RESUME:
503 return lis331dlh_set_odr(mlsl_handle, pdata,
504 &private_data->resume,
505 data->apply, *((long *)data->data));
506 case MPU_SLAVE_CONFIG_FSR_SUSPEND:
507 return lis331dlh_set_fsr(mlsl_handle, pdata,
508 &private_data->suspend,
509 data->apply, *((long *)data->data));
510 case MPU_SLAVE_CONFIG_FSR_RESUME:
511 return lis331dlh_set_fsr(mlsl_handle, pdata,
512 &private_data->resume,
513 data->apply, *((long *)data->data));
514 case MPU_SLAVE_CONFIG_MOT_THS:
515 return lis331dlh_set_ths(mlsl_handle, pdata,
516 &private_data->suspend,
517 data->apply, *((long *)data->data));
518 case MPU_SLAVE_CONFIG_NMOT_THS:
519 return lis331dlh_set_ths(mlsl_handle, pdata,
520 &private_data->resume,
521 data->apply, *((long *)data->data));
522 case MPU_SLAVE_CONFIG_MOT_DUR:
523 return lis331dlh_set_dur(mlsl_handle, pdata,
524 &private_data->suspend,
525 data->apply, *((long *)data->data));
526 case MPU_SLAVE_CONFIG_NMOT_DUR:
527 return lis331dlh_set_dur(mlsl_handle, pdata,
528 &private_data->resume,
529 data->apply, *((long *)data->data));
530 case MPU_SLAVE_CONFIG_IRQ_SUSPEND:
531 return lis331dlh_set_irq(mlsl_handle, pdata,
532 &private_data->suspend,
533 data->apply, *((long *)data->data));
534 case MPU_SLAVE_CONFIG_IRQ_RESUME:
535 return lis331dlh_set_irq(mlsl_handle, pdata,
536 &private_data->resume,
537 data->apply, *((long *)data->data));
538 default:
539 LOG_RESULT_LOCATION(INV_ERROR_FEATURE_NOT_IMPLEMENTED);
540 return INV_ERROR_FEATURE_NOT_IMPLEMENTED;
541 };
542
543 return INV_SUCCESS;
544}
545
546static int lis331dlh_get_config(void *mlsl_handle,
547 struct ext_slave_descr *slave,
548 struct ext_slave_platform_data *pdata,
549 struct ext_slave_config *data)
550{
551 struct lis331dlh_private_data *private_data = pdata->private_data;
552 if (!data->data)
553 return INV_ERROR_INVALID_PARAMETER;
554
555 switch (data->key) {
556 case MPU_SLAVE_CONFIG_ODR_SUSPEND:
557 (*(unsigned long *)data->data) =
558 (unsigned long)private_data->suspend.odr;
559 break;
560 case MPU_SLAVE_CONFIG_ODR_RESUME:
561 (*(unsigned long *)data->data) =
562 (unsigned long)private_data->resume.odr;
563 break;
564 case MPU_SLAVE_CONFIG_FSR_SUSPEND:
565 (*(unsigned long *)data->data) =
566 (unsigned long)private_data->suspend.fsr;
567 break;
568 case MPU_SLAVE_CONFIG_FSR_RESUME:
569 (*(unsigned long *)data->data) =
570 (unsigned long)private_data->resume.fsr;
571 break;
572 case MPU_SLAVE_CONFIG_MOT_THS:
573 (*(unsigned long *)data->data) =
574 (unsigned long)private_data->suspend.ths;
575 break;
576 case MPU_SLAVE_CONFIG_NMOT_THS:
577 (*(unsigned long *)data->data) =
578 (unsigned long)private_data->resume.ths;
579 break;
580 case MPU_SLAVE_CONFIG_MOT_DUR:
581 (*(unsigned long *)data->data) =
582 (unsigned long)private_data->suspend.dur;
583 break;
584 case MPU_SLAVE_CONFIG_NMOT_DUR:
585 (*(unsigned long *)data->data) =
586 (unsigned long)private_data->resume.dur;
587 break;
588 case MPU_SLAVE_CONFIG_IRQ_SUSPEND:
589 (*(unsigned long *)data->data) =
590 (unsigned long)private_data->suspend.irq_type;
591 break;
592 case MPU_SLAVE_CONFIG_IRQ_RESUME:
593 (*(unsigned long *)data->data) =
594 (unsigned long)private_data->resume.irq_type;
595 break;
596 default:
597 LOG_RESULT_LOCATION(INV_ERROR_FEATURE_NOT_IMPLEMENTED);
598 return INV_ERROR_FEATURE_NOT_IMPLEMENTED;
599 };
600
601 return INV_SUCCESS;
602}
603
604static struct ext_slave_descr lis331dlh_descr = {
605 .init = lis331dlh_init,
606 .exit = lis331dlh_exit,
607 .suspend = lis331dlh_suspend,
608 .resume = lis331dlh_resume,
609 .read = lis331dlh_read,
610 .config = lis331dlh_config,
611 .get_config = lis331dlh_get_config,
612 .name = "lis331dlh",
613 .type = EXT_SLAVE_TYPE_ACCEL,
614 .id = ACCEL_ID_LIS331,
615 .read_reg = (0x28 | 0x80), /* 0x80 for burst reads */
616 .read_len = 6,
617 .endian = EXT_SLAVE_BIG_ENDIAN,
618 .range = {2, 480},
619 .trigger = NULL,
620};
621
622static
623struct ext_slave_descr *lis331_get_slave_descr(void)
624{
625 return &lis331dlh_descr;
626}
627
628/* -------------------------------------------------------------------------- */
629struct lis331_mod_private_data {
630 struct i2c_client *client;
631 struct ext_slave_platform_data *pdata;
632};
633
634static unsigned short normal_i2c[] = { I2C_CLIENT_END };
635
636static int lis331_mod_probe(struct i2c_client *client,
637 const struct i2c_device_id *devid)
638{
639 struct ext_slave_platform_data *pdata;
640 struct lis331_mod_private_data *private_data;
641 int result = 0;
642
643 dev_info(&client->adapter->dev, "%s: %s\n", __func__, devid->name);
644
645 if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
646 result = -ENODEV;
647 goto out_no_free;
648 }
649
650 pdata = client->dev.platform_data;
651 if (!pdata) {
652 dev_err(&client->adapter->dev,
653 "Missing platform data for slave %s\n", devid->name);
654 result = -EFAULT;
655 goto out_no_free;
656 }
657
658 private_data = kzalloc(sizeof(*private_data), GFP_KERNEL);
659 if (!private_data) {
660 result = -ENOMEM;
661 goto out_no_free;
662 }
663
664 i2c_set_clientdata(client, private_data);
665 private_data->client = client;
666 private_data->pdata = pdata;
667
668 result = inv_mpu_register_slave(THIS_MODULE, client, pdata,
669 lis331_get_slave_descr);
670 if (result) {
671 dev_err(&client->adapter->dev,
672 "Slave registration failed: %s, %d\n",
673 devid->name, result);
674 goto out_free_memory;
675 }
676
677 return result;
678
679out_free_memory:
680 kfree(private_data);
681out_no_free:
682 dev_err(&client->adapter->dev, "%s failed %d\n", __func__, result);
683 return result;
684
685}
686
687static int lis331_mod_remove(struct i2c_client *client)
688{
689 struct lis331_mod_private_data *private_data =
690 i2c_get_clientdata(client);
691
692 dev_dbg(&client->adapter->dev, "%s\n", __func__);
693
694 inv_mpu_unregister_slave(client, private_data->pdata,
695 lis331_get_slave_descr);
696
697 kfree(private_data);
698 return 0;
699}
700
701static const struct i2c_device_id lis331_mod_id[] = {
702 { "lis331", ACCEL_ID_LIS331 },
703 {}
704};
705
706MODULE_DEVICE_TABLE(i2c, lis331_mod_id);
707
708static struct i2c_driver lis331_mod_driver = {
709 .class = I2C_CLASS_HWMON,
710 .probe = lis331_mod_probe,
711 .remove = lis331_mod_remove,
712 .id_table = lis331_mod_id,
713 .driver = {
714 .owner = THIS_MODULE,
715 .name = "lis331_mod",
716 },
717 .address_list = normal_i2c,
718};
719
720static int __init lis331_mod_init(void)
721{
722 int res = i2c_add_driver(&lis331_mod_driver);
723 pr_info("%s: Probe name %s\n", __func__, "lis331_mod");
724 if (res)
725 pr_err("%s failed\n", __func__);
726 return res;
727}
728
729static void __exit lis331_mod_exit(void)
730{
731 pr_info("%s\n", __func__);
732 i2c_del_driver(&lis331_mod_driver);
733}
734
735module_init(lis331_mod_init);
736module_exit(lis331_mod_exit);
737
738MODULE_AUTHOR("Invensense Corporation");
739MODULE_DESCRIPTION("Driver to integrate LIS331 sensor with the MPU");
740MODULE_LICENSE("GPL");
741MODULE_ALIAS("lis331_mod");
742
743/**
744 * @}
745 */
diff --git a/drivers/misc/inv_mpu/accel/lis3dh.c b/drivers/misc/inv_mpu/accel/lis3dh.c
new file mode 100644
index 00000000000..27206e4b847
--- /dev/null
+++ b/drivers/misc/inv_mpu/accel/lis3dh.c
@@ -0,0 +1,728 @@
1/*
2 $License:
3 Copyright (C) 2011 InvenSense Corporation, All Rights Reserved.
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, see <http://www.gnu.org/licenses/>.
17 $
18 */
19
20/**
21 * @addtogroup ACCELDL
22 * @brief Provides the interface to setup and handle an accelerometer.
23 *
24 * @{
25 * @file lis3dh.c
26 * @brief Accelerometer setup and handling methods for ST LIS3DH.
27 */
28
29/* -------------------------------------------------------------------------- */
30
31#undef MPL_LOG_NDEBUG
32#define MPL_LOG_NDEBUG 0
33
34#include <linux/i2c.h>
35#include <linux/module.h>
36#include <linux/moduleparam.h>
37#include <linux/kernel.h>
38#include <linux/errno.h>
39#include <linux/slab.h>
40#include <linux/delay.h>
41#include "mpu-dev.h"
42
43#include <log.h>
44#include <linux/mpu.h>
45#include "mlsl.h"
46#include "mldl_cfg.h"
47#undef MPL_LOG_TAG
48#define MPL_LOG_TAG "MPL-acc"
49
50/* full scale setting - register & mask */
51#define LIS3DH_CTRL_REG1 (0x20)
52#define LIS3DH_CTRL_REG2 (0x21)
53#define LIS3DH_CTRL_REG3 (0x22)
54#define LIS3DH_CTRL_REG4 (0x23)
55#define LIS3DH_CTRL_REG5 (0x24)
56#define LIS3DH_CTRL_REG6 (0x25)
57#define LIS3DH_REFERENCE (0x26)
58#define LIS3DH_STATUS_REG (0x27)
59#define LIS3DH_OUT_X_L (0x28)
60#define LIS3DH_OUT_X_H (0x29)
61#define LIS3DH_OUT_Y_L (0x2a)
62#define LIS3DH_OUT_Y_H (0x2b)
63#define LIS3DH_OUT_Z_L (0x2c)
64#define LIS3DH_OUT_Z_H (0x2d)
65
66#define LIS3DH_INT1_CFG (0x30)
67#define LIS3DH_INT1_SRC (0x31)
68#define LIS3DH_INT1_THS (0x32)
69#define LIS3DH_INT1_DURATION (0x33)
70
71#define LIS3DH_MAX_DUR (0x7F)
72
73/* -------------------------------------------------------------------------- */
74
75struct lis3dh_config {
76 unsigned long odr;
77 unsigned int fsr; /* full scale range mg */
78 unsigned int ths; /* Motion no-motion thseshold mg */
79 unsigned int dur; /* Motion no-motion duration ms */
80 unsigned char reg_ths;
81 unsigned char reg_dur;
82 unsigned char ctrl_reg1;
83 unsigned char irq_type;
84 unsigned char mot_int1_cfg;
85};
86
87struct lis3dh_private_data {
88 struct lis3dh_config suspend;
89 struct lis3dh_config resume;
90};
91
92/* -------------------------------------------------------------------------- */
93
94static int lis3dh_set_ths(void *mlsl_handle,
95 struct ext_slave_platform_data *pdata,
96 struct lis3dh_config *config, int apply, long ths)
97{
98 int result = INV_SUCCESS;
99 if ((unsigned int)ths > 1000 * config->fsr)
100 ths = (long)1000 * config->fsr;
101
102 if (ths < 0)
103 ths = 0;
104
105 config->ths = ths;
106 config->reg_ths = (unsigned char)(long)((ths * 128L) / (config->fsr));
107 MPL_LOGV("THS: %d, 0x%02x\n", config->ths, (int)config->reg_ths);
108 if (apply)
109 result = inv_serial_single_write(mlsl_handle, pdata->address,
110 LIS3DH_INT1_THS,
111 config->reg_ths);
112 return result;
113}
114
115static int lis3dh_set_dur(void *mlsl_handle,
116 struct ext_slave_platform_data *pdata,
117 struct lis3dh_config *config, int apply, long dur)
118{
119 int result = INV_SUCCESS;
120 long reg_dur = (dur * config->odr) / 1000000L;
121 config->dur = dur;
122
123 if (reg_dur > LIS3DH_MAX_DUR)
124 reg_dur = LIS3DH_MAX_DUR;
125
126 config->reg_dur = (unsigned char)reg_dur;
127 MPL_LOGV("DUR: %d, 0x%02x\n", config->dur, (int)config->reg_dur);
128 if (apply)
129 result = inv_serial_single_write(mlsl_handle, pdata->address,
130 LIS3DH_INT1_DURATION,
131 (unsigned char)reg_dur);
132 return result;
133}
134
135/**
136 * Sets the IRQ to fire when one of the IRQ events occur. Threshold and
137 * duration will not be used uless the type is MOT or NMOT.
138 *
139 * @param config configuration to apply to, suspend or resume
140 * @param irq_type The type of IRQ. Valid values are
141 * - MPU_SLAVE_IRQ_TYPE_NONE
142 * - MPU_SLAVE_IRQ_TYPE_MOTION
143 * - MPU_SLAVE_IRQ_TYPE_DATA_READY
144 */
145static int lis3dh_set_irq(void *mlsl_handle,
146 struct ext_slave_platform_data *pdata,
147 struct lis3dh_config *config,
148 int apply, long irq_type)
149{
150 int result = INV_SUCCESS;
151 unsigned char reg1;
152 unsigned char reg2;
153
154 config->irq_type = (unsigned char)irq_type;
155 if (irq_type == MPU_SLAVE_IRQ_TYPE_DATA_READY) {
156 reg1 = 0x10;
157 reg2 = 0x00;
158 } else if (irq_type == MPU_SLAVE_IRQ_TYPE_MOTION) {
159 reg1 = 0x40;
160 reg2 = config->mot_int1_cfg;
161 } else {
162 reg1 = 0x00;
163 reg2 = 0x00;
164 }
165
166 if (apply) {
167 result = inv_serial_single_write(mlsl_handle, pdata->address,
168 LIS3DH_CTRL_REG3, reg1);
169 result = inv_serial_single_write(mlsl_handle, pdata->address,
170 LIS3DH_INT1_CFG, reg2);
171 }
172
173 return result;
174}
175
176/**
177 * Set the Output data rate for the particular configuration
178 *
179 * @param config Config to modify with new ODR
180 * @param odr Output data rate in units of 1/1000Hz
181 */
182static int lis3dh_set_odr(void *mlsl_handle,
183 struct ext_slave_platform_data *pdata,
184 struct lis3dh_config *config, int apply, long odr)
185{
186 unsigned char bits;
187 int result = INV_SUCCESS;
188
189 if (odr > 400000L) {
190 config->odr = 1250000L;
191 bits = 0x90;
192 } else if (odr > 200000L) {
193 config->odr = 400000L;
194 bits = 0x70;
195 } else if (odr > 100000L) {
196 config->odr = 200000L;
197 bits = 0x60;
198 } else if (odr > 50000) {
199 config->odr = 100000L;
200 bits = 0x50;
201 } else if (odr > 25000) {
202 config->odr = 50000;
203 bits = 0x40;
204 } else if (odr > 10000) {
205 config->odr = 25000;
206 bits = 0x30;
207 } else if (odr > 1000) {
208 config->odr = 10000;
209 bits = 0x20;
210 } else if (odr > 500) {
211 config->odr = 1000;
212 bits = 0x10;
213 } else {
214 config->odr = 0;
215 bits = 0;
216 }
217
218 config->ctrl_reg1 = bits | (config->ctrl_reg1 & 0xf);
219 lis3dh_set_dur(mlsl_handle, pdata, config, apply, config->dur);
220 MPL_LOGV("ODR: %ld, 0x%02x\n", config->odr, (int)config->ctrl_reg1);
221 if (apply)
222 result = inv_serial_single_write(mlsl_handle, pdata->address,
223 LIS3DH_CTRL_REG1,
224 config->ctrl_reg1);
225 return result;
226}
227
228/**
229 * Set the full scale range of the accels
230 *
231 * @param config pointer to configuration
232 * @param fsr requested full scale range
233 */
234static int lis3dh_set_fsr(void *mlsl_handle,
235 struct ext_slave_platform_data *pdata,
236 struct lis3dh_config *config, int apply, long fsr)
237{
238 int result = INV_SUCCESS;
239 unsigned char reg1 = 0x48;
240
241 if (fsr <= 2048) {
242 config->fsr = 2048;
243 } else if (fsr <= 4096) {
244 reg1 |= 0x10;
245 config->fsr = 4096;
246 } else if (fsr <= 8192) {
247 reg1 |= 0x20;
248 config->fsr = 8192;
249 } else {
250 reg1 |= 0x30;
251 config->fsr = 16348;
252 }
253
254 lis3dh_set_ths(mlsl_handle, pdata, config, apply, config->ths);
255 MPL_LOGV("FSR: %d\n", config->fsr);
256 if (apply)
257 result = inv_serial_single_write(mlsl_handle, pdata->address,
258 LIS3DH_CTRL_REG4, reg1);
259
260 return result;
261}
262
263static int lis3dh_suspend(void *mlsl_handle,
264 struct ext_slave_descr *slave,
265 struct ext_slave_platform_data *pdata)
266{
267 int result = INV_SUCCESS;
268 unsigned char reg1;
269 unsigned char reg2;
270 struct lis3dh_private_data *private_data = pdata->private_data;
271
272 result = inv_serial_single_write(mlsl_handle, pdata->address,
273 LIS3DH_CTRL_REG1,
274 private_data->suspend.ctrl_reg1);
275
276 reg1 = 0x48;
277 if (private_data->suspend.fsr == 16384)
278 reg1 |= 0x30;
279 else if (private_data->suspend.fsr == 8192)
280 reg1 |= 0x20;
281 else if (private_data->suspend.fsr == 4096)
282 reg1 |= 0x10;
283 else if (private_data->suspend.fsr == 2048)
284 reg1 |= 0x00;
285
286 result = inv_serial_single_write(mlsl_handle, pdata->address,
287 LIS3DH_CTRL_REG4, reg1);
288 result = inv_serial_single_write(mlsl_handle, pdata->address,
289 LIS3DH_INT1_THS,
290 private_data->suspend.reg_ths);
291 result = inv_serial_single_write(mlsl_handle, pdata->address,
292 LIS3DH_INT1_DURATION,
293 private_data->suspend.reg_dur);
294
295 if (private_data->suspend.irq_type == MPU_SLAVE_IRQ_TYPE_DATA_READY) {
296 reg1 = 0x10;
297 reg2 = 0x00;
298 } else if (private_data->suspend.irq_type ==
299 MPU_SLAVE_IRQ_TYPE_MOTION) {
300 reg1 = 0x40;
301 reg2 = private_data->suspend.mot_int1_cfg;
302 } else {
303 reg1 = 0x00;
304 reg2 = 0x00;
305 }
306 result = inv_serial_single_write(mlsl_handle, pdata->address,
307 LIS3DH_CTRL_REG3, reg1);
308 result = inv_serial_single_write(mlsl_handle, pdata->address,
309 LIS3DH_INT1_CFG, reg2);
310 result = inv_serial_read(mlsl_handle, pdata->address,
311 LIS3DH_CTRL_REG6, 1, &reg1);
312
313 return result;
314}
315
316static int lis3dh_resume(void *mlsl_handle,
317 struct ext_slave_descr *slave,
318 struct ext_slave_platform_data *pdata)
319{
320 int result;
321 unsigned char reg1;
322 unsigned char reg2;
323 struct lis3dh_private_data *private_data = pdata->private_data;
324
325 result = inv_serial_single_write(mlsl_handle, pdata->address,
326 LIS3DH_CTRL_REG1,
327 private_data->resume.ctrl_reg1);
328 if (result) {
329 LOG_RESULT_LOCATION(result);
330 return result;
331 }
332 msleep(6);
333
334 /* Full Scale */
335 reg1 = 0x48;
336 if (private_data->suspend.fsr == 16384)
337 reg1 |= 0x30;
338 else if (private_data->suspend.fsr == 8192)
339 reg1 |= 0x20;
340 else if (private_data->suspend.fsr == 4096)
341 reg1 |= 0x10;
342 else if (private_data->suspend.fsr == 2048)
343 reg1 |= 0x00;
344
345 result = inv_serial_single_write(mlsl_handle, pdata->address,
346 LIS3DH_CTRL_REG4, reg1);
347 if (result) {
348 LOG_RESULT_LOCATION(result);
349 return result;
350 }
351
352 if (private_data->resume.irq_type == MPU_SLAVE_IRQ_TYPE_DATA_READY) {
353 reg1 = 0x10;
354 reg2 = 0x00;
355 } else if (private_data->resume.irq_type == MPU_SLAVE_IRQ_TYPE_MOTION) {
356 reg1 = 0x40;
357 reg2 = private_data->resume.mot_int1_cfg;
358 } else {
359 reg1 = 0x00;
360 reg2 = 0x00;
361 }
362 result = inv_serial_single_write(mlsl_handle, pdata->address,
363 LIS3DH_CTRL_REG3, reg1);
364 if (result) {
365 LOG_RESULT_LOCATION(result);
366 return result;
367 }
368 result = inv_serial_single_write(mlsl_handle, pdata->address,
369 LIS3DH_INT1_THS,
370 private_data->resume.reg_ths);
371 if (result) {
372 LOG_RESULT_LOCATION(result);
373 return result;
374 }
375 result = inv_serial_single_write(mlsl_handle, pdata->address,
376 LIS3DH_INT1_DURATION,
377 private_data->resume.reg_dur);
378 if (result) {
379 LOG_RESULT_LOCATION(result);
380 return result;
381 }
382 result = inv_serial_single_write(mlsl_handle, pdata->address,
383 LIS3DH_INT1_CFG, reg2);
384 if (result) {
385 LOG_RESULT_LOCATION(result);
386 return result;
387 }
388 result = inv_serial_read(mlsl_handle, pdata->address,
389 LIS3DH_CTRL_REG6, 1, &reg1);
390 if (result) {
391 LOG_RESULT_LOCATION(result);
392 return result;
393 }
394 return result;
395}
396
397static int lis3dh_read(void *mlsl_handle,
398 struct ext_slave_descr *slave,
399 struct ext_slave_platform_data *pdata,
400 unsigned char *data)
401{
402 int result = INV_SUCCESS;
403 result = inv_serial_read(mlsl_handle, pdata->address,
404 LIS3DH_STATUS_REG, 1, data);
405 if (data[0] & 0x0F) {
406 result = inv_serial_read(mlsl_handle, pdata->address,
407 slave->read_reg, slave->read_len,
408 data);
409 return result;
410 } else
411 return INV_ERROR_ACCEL_DATA_NOT_READY;
412}
413
414static int lis3dh_init(void *mlsl_handle,
415 struct ext_slave_descr *slave,
416 struct ext_slave_platform_data *pdata)
417{
418 int result;
419 long range;
420 struct lis3dh_private_data *private_data;
421 private_data = (struct lis3dh_private_data *)
422 kzalloc(sizeof(struct lis3dh_private_data), GFP_KERNEL);
423
424 if (!private_data)
425 return INV_ERROR_MEMORY_EXAUSTED;
426
427 pdata->private_data = private_data;
428
429 private_data->resume.ctrl_reg1 = 0x67;
430 private_data->suspend.ctrl_reg1 = 0x18;
431 private_data->resume.mot_int1_cfg = 0x95;
432 private_data->suspend.mot_int1_cfg = 0x2a;
433
434 lis3dh_set_odr(mlsl_handle, pdata, &private_data->suspend, false, 0);
435 lis3dh_set_odr(mlsl_handle, pdata, &private_data->resume,
436 false, 200000L);
437
438 range = range_fixedpoint_to_long_mg(slave->range);
439 lis3dh_set_fsr(mlsl_handle, pdata, &private_data->suspend,
440 false, range);
441 lis3dh_set_fsr(mlsl_handle, pdata, &private_data->resume,
442 false, range);
443
444 lis3dh_set_ths(mlsl_handle, pdata, &private_data->suspend,
445 false, 80);
446 lis3dh_set_ths(mlsl_handle, pdata, &private_data->resume,
447 false, 40);
448
449 lis3dh_set_dur(mlsl_handle, pdata, &private_data->suspend,
450 false, 1000);
451 lis3dh_set_dur(mlsl_handle, pdata, &private_data->resume,
452 false, 2540);
453
454 lis3dh_set_irq(mlsl_handle, pdata, &private_data->suspend,
455 false, MPU_SLAVE_IRQ_TYPE_NONE);
456 lis3dh_set_irq(mlsl_handle, pdata, &private_data->resume,
457 false, MPU_SLAVE_IRQ_TYPE_NONE);
458
459 result = inv_serial_single_write(mlsl_handle, pdata->address,
460 LIS3DH_CTRL_REG1, 0x07);
461 msleep(6);
462
463 return INV_SUCCESS;
464}
465
466static int lis3dh_exit(void *mlsl_handle,
467 struct ext_slave_descr *slave,
468 struct ext_slave_platform_data *pdata)
469{
470 kfree(pdata->private_data);
471 return INV_SUCCESS;
472}
473
474static int lis3dh_config(void *mlsl_handle,
475 struct ext_slave_descr *slave,
476 struct ext_slave_platform_data *pdata,
477 struct ext_slave_config *data)
478{
479 struct lis3dh_private_data *private_data = pdata->private_data;
480 if (!data->data)
481 return INV_ERROR_INVALID_PARAMETER;
482
483 switch (data->key) {
484 case MPU_SLAVE_CONFIG_ODR_SUSPEND:
485 return lis3dh_set_odr(mlsl_handle, pdata,
486 &private_data->suspend,
487 data->apply, *((long *)data->data));
488 case MPU_SLAVE_CONFIG_ODR_RESUME:
489 return lis3dh_set_odr(mlsl_handle, pdata,
490 &private_data->resume,
491 data->apply, *((long *)data->data));
492 case MPU_SLAVE_CONFIG_FSR_SUSPEND:
493 return lis3dh_set_fsr(mlsl_handle, pdata,
494 &private_data->suspend,
495 data->apply, *((long *)data->data));
496 case MPU_SLAVE_CONFIG_FSR_RESUME:
497 return lis3dh_set_fsr(mlsl_handle, pdata,
498 &private_data->resume,
499 data->apply, *((long *)data->data));
500 case MPU_SLAVE_CONFIG_MOT_THS:
501 return lis3dh_set_ths(mlsl_handle, pdata,
502 &private_data->suspend,
503 data->apply, *((long *)data->data));
504 case MPU_SLAVE_CONFIG_NMOT_THS:
505 return lis3dh_set_ths(mlsl_handle, pdata,
506 &private_data->resume,
507 data->apply, *((long *)data->data));
508 case MPU_SLAVE_CONFIG_MOT_DUR:
509 return lis3dh_set_dur(mlsl_handle, pdata,
510 &private_data->suspend,
511 data->apply, *((long *)data->data));
512 case MPU_SLAVE_CONFIG_NMOT_DUR:
513 return lis3dh_set_dur(mlsl_handle, pdata,
514 &private_data->resume,
515 data->apply, *((long *)data->data));
516 case MPU_SLAVE_CONFIG_IRQ_SUSPEND:
517 return lis3dh_set_irq(mlsl_handle, pdata,
518 &private_data->suspend,
519 data->apply, *((long *)data->data));
520 case MPU_SLAVE_CONFIG_IRQ_RESUME:
521 return lis3dh_set_irq(mlsl_handle, pdata,
522 &private_data->resume,
523 data->apply, *((long *)data->data));
524 default:
525 return INV_ERROR_FEATURE_NOT_IMPLEMENTED;
526 };
527 return INV_SUCCESS;
528}
529
530static int lis3dh_get_config(void *mlsl_handle,
531 struct ext_slave_descr *slave,
532 struct ext_slave_platform_data *pdata,
533 struct ext_slave_config *data)
534{
535 struct lis3dh_private_data *private_data = pdata->private_data;
536 if (!data->data)
537 return INV_ERROR_INVALID_PARAMETER;
538
539 switch (data->key) {
540 case MPU_SLAVE_CONFIG_ODR_SUSPEND:
541 (*(unsigned long *)data->data) =
542 (unsigned long)private_data->suspend.odr;
543 break;
544 case MPU_SLAVE_CONFIG_ODR_RESUME:
545 (*(unsigned long *)data->data) =
546 (unsigned long)private_data->resume.odr;
547 break;
548 case MPU_SLAVE_CONFIG_FSR_SUSPEND:
549 (*(unsigned long *)data->data) =
550 (unsigned long)private_data->suspend.fsr;
551 break;
552 case MPU_SLAVE_CONFIG_FSR_RESUME:
553 (*(unsigned long *)data->data) =
554 (unsigned long)private_data->resume.fsr;
555 break;
556 case MPU_SLAVE_CONFIG_MOT_THS:
557 (*(unsigned long *)data->data) =
558 (unsigned long)private_data->suspend.ths;
559 break;
560 case MPU_SLAVE_CONFIG_NMOT_THS:
561 (*(unsigned long *)data->data) =
562 (unsigned long)private_data->resume.ths;
563 break;
564 case MPU_SLAVE_CONFIG_MOT_DUR:
565 (*(unsigned long *)data->data) =
566 (unsigned long)private_data->suspend.dur;
567 break;
568 case MPU_SLAVE_CONFIG_NMOT_DUR:
569 (*(unsigned long *)data->data) =
570 (unsigned long)private_data->resume.dur;
571 break;
572 case MPU_SLAVE_CONFIG_IRQ_SUSPEND:
573 (*(unsigned long *)data->data) =
574 (unsigned long)private_data->suspend.irq_type;
575 break;
576 case MPU_SLAVE_CONFIG_IRQ_RESUME:
577 (*(unsigned long *)data->data) =
578 (unsigned long)private_data->resume.irq_type;
579 break;
580 default:
581 return INV_ERROR_FEATURE_NOT_IMPLEMENTED;
582 };
583
584 return INV_SUCCESS;
585}
586
587static struct ext_slave_descr lis3dh_descr = {
588 .init = lis3dh_init,
589 .exit = lis3dh_exit,
590 .suspend = lis3dh_suspend,
591 .resume = lis3dh_resume,
592 .read = lis3dh_read,
593 .config = lis3dh_config,
594 .get_config = lis3dh_get_config,
595 .name = "lis3dh",
596 .type = EXT_SLAVE_TYPE_ACCEL,
597 .id = ACCEL_ID_LIS3DH,
598 .read_reg = 0x28 | 0x80, /* 0x80 for burst reads */
599 .read_len = 6,
600 .endian = EXT_SLAVE_BIG_ENDIAN,
601 .range = {2, 480},
602 .trigger = NULL,
603};
604
605static
606struct ext_slave_descr *lis3dh_get_slave_descr(void)
607{
608 return &lis3dh_descr;
609}
610
611/* -------------------------------------------------------------------------- */
612struct lis3dh_mod_private_data {
613 struct i2c_client *client;
614 struct ext_slave_platform_data *pdata;
615};
616
617static unsigned short normal_i2c[] = { I2C_CLIENT_END };
618
619static int lis3dh_mod_probe(struct i2c_client *client,
620 const struct i2c_device_id *devid)
621{
622 struct ext_slave_platform_data *pdata;
623 struct lis3dh_mod_private_data *private_data;
624 int result = 0;
625
626 dev_info(&client->adapter->dev, "%s: %s\n", __func__, devid->name);
627
628 if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
629 result = -ENODEV;
630 goto out_no_free;
631 }
632
633 pdata = client->dev.platform_data;
634 if (!pdata) {
635 dev_err(&client->adapter->dev,
636 "Missing platform data for slave %s\n", devid->name);
637 result = -EFAULT;
638 goto out_no_free;
639 }
640
641 private_data = kzalloc(sizeof(*private_data), GFP_KERNEL);
642 if (!private_data) {
643 result = -ENOMEM;
644 goto out_no_free;
645 }
646
647 i2c_set_clientdata(client, private_data);
648 private_data->client = client;
649 private_data->pdata = pdata;
650
651 result = inv_mpu_register_slave(THIS_MODULE, client, pdata,
652 lis3dh_get_slave_descr);
653 if (result) {
654 dev_err(&client->adapter->dev,
655 "Slave registration failed: %s, %d\n",
656 devid->name, result);
657 goto out_free_memory;
658 }
659
660 return result;
661
662out_free_memory:
663 kfree(private_data);
664out_no_free:
665 dev_err(&client->adapter->dev, "%s failed %d\n", __func__, result);
666 return result;
667
668}
669
670static int lis3dh_mod_remove(struct i2c_client *client)
671{
672 struct lis3dh_mod_private_data *private_data =
673 i2c_get_clientdata(client);
674
675 dev_dbg(&client->adapter->dev, "%s\n", __func__);
676
677 inv_mpu_unregister_slave(client, private_data->pdata,
678 lis3dh_get_slave_descr);
679
680 kfree(private_data);
681 return 0;
682}
683
684static const struct i2c_device_id lis3dh_mod_id[] = {
685 { "lis3dh", ACCEL_ID_LIS3DH },
686 {}
687};
688
689MODULE_DEVICE_TABLE(i2c, lis3dh_mod_id);
690
691static struct i2c_driver lis3dh_mod_driver = {
692 .class = I2C_CLASS_HWMON,
693 .probe = lis3dh_mod_probe,
694 .remove = lis3dh_mod_remove,
695 .id_table = lis3dh_mod_id,
696 .driver = {
697 .owner = THIS_MODULE,
698 .name = "lis3dh_mod",
699 },
700 .address_list = normal_i2c,
701};
702
703static int __init lis3dh_mod_init(void)
704{
705 int res = i2c_add_driver(&lis3dh_mod_driver);
706 pr_info("%s: Probe name %s\n", __func__, "lis3dh_mod");
707 if (res)
708 pr_err("%s failed\n", __func__);
709 return res;
710}
711
712static void __exit lis3dh_mod_exit(void)
713{
714 pr_info("%s\n", __func__);
715 i2c_del_driver(&lis3dh_mod_driver);
716}
717
718module_init(lis3dh_mod_init);
719module_exit(lis3dh_mod_exit);
720
721MODULE_AUTHOR("Invensense Corporation");
722MODULE_DESCRIPTION("Driver to integrate LIS3DH sensor with the MPU");
723MODULE_LICENSE("GPL");
724MODULE_ALIAS("lis3dh_mod");
725
726/*
727 * @}
728 */
diff --git a/drivers/misc/inv_mpu/accel/lsm303dlx_a.c b/drivers/misc/inv_mpu/accel/lsm303dlx_a.c
new file mode 100644
index 00000000000..576282a0fb1
--- /dev/null
+++ b/drivers/misc/inv_mpu/accel/lsm303dlx_a.c
@@ -0,0 +1,881 @@
1/*
2 $License:
3 Copyright (C) 2011 InvenSense Corporation, All Rights Reserved.
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, see <http://www.gnu.org/licenses/>.
17 $
18 */
19
20/**
21 * @addtogroup ACCELDL
22 * @brief Provides the interface to setup and handle an accelerometer.
23 *
24 * @{
25 * @file lsm303dlx_a.c
26 * @brief Accelerometer setup and handling methods for ST LSM303DLH
27 * or LSM303DLM accel.
28 */
29
30/* -------------------------------------------------------------------------- */
31
32#include <linux/i2c.h>
33#include <linux/module.h>
34#include <linux/moduleparam.h>
35#include <linux/kernel.h>
36#include <linux/errno.h>
37#include <linux/slab.h>
38#include <linux/delay.h>
39#include "mpu-dev.h"
40
41#include <log.h>
42#include <linux/mpu.h>
43#include "mlsl.h"
44#include "mldl_cfg.h"
45#undef MPL_LOG_TAG
46#define MPL_LOG_TAG "MPL-acc"
47
48/* -------------------------------------------------------------------------- */
49
50/* full scale setting - register & mask */
51#define LSM303DLx_CTRL_REG1 (0x20)
52#define LSM303DLx_CTRL_REG2 (0x21)
53#define LSM303DLx_CTRL_REG3 (0x22)
54#define LSM303DLx_CTRL_REG4 (0x23)
55#define LSM303DLx_CTRL_REG5 (0x24)
56#define LSM303DLx_HP_FILTER_RESET (0x25)
57#define LSM303DLx_REFERENCE (0x26)
58#define LSM303DLx_STATUS_REG (0x27)
59#define LSM303DLx_OUT_X_L (0x28)
60#define LSM303DLx_OUT_X_H (0x29)
61#define LSM303DLx_OUT_Y_L (0x2a)
62#define LSM303DLx_OUT_Y_H (0x2b)
63#define LSM303DLx_OUT_Z_L (0x2b)
64#define LSM303DLx_OUT_Z_H (0x2d)
65
66#define LSM303DLx_INT1_CFG (0x30)
67#define LSM303DLx_INT1_SRC (0x31)
68#define LSM303DLx_INT1_THS (0x32)
69#define LSM303DLx_INT1_DURATION (0x33)
70
71#define LSM303DLx_INT2_CFG (0x34)
72#define LSM303DLx_INT2_SRC (0x35)
73#define LSM303DLx_INT2_THS (0x36)
74#define LSM303DLx_INT2_DURATION (0x37)
75
76#define LSM303DLx_CTRL_MASK (0x30)
77#define LSM303DLx_SLEEP_MASK (0x20)
78#define LSM303DLx_PWR_MODE_NORMAL (0x20)
79
80#define LSM303DLx_MAX_DUR (0x7F)
81
82/* -------------------------------------------------------------------------- */
83
84struct lsm303dlx_a_config {
85 unsigned int odr;
86 unsigned int fsr; /** < full scale range mg */
87 unsigned int ths; /** < Motion no-motion thseshold mg */
88 unsigned int dur; /** < Motion no-motion duration ms */
89 unsigned char reg_ths;
90 unsigned char reg_dur;
91 unsigned char ctrl_reg1;
92 unsigned char irq_type;
93 unsigned char mot_int1_cfg;
94};
95
96struct lsm303dlx_a_private_data {
97 struct lsm303dlx_a_config suspend;
98 struct lsm303dlx_a_config resume;
99};
100
101/* -------------------------------------------------------------------------- */
102
103static int lsm303dlx_a_set_ths(void *mlsl_handle,
104 struct ext_slave_platform_data *pdata,
105 struct lsm303dlx_a_config *config,
106 int apply,
107 long ths)
108{
109 int result = INV_SUCCESS;
110 if ((unsigned int) ths >= config->fsr)
111 ths = (long) config->fsr - 1;
112
113 if (ths < 0)
114 ths = 0;
115
116 config->ths = ths;
117 config->reg_ths = (unsigned char)(long)((ths * 128L) / (config->fsr));
118 MPL_LOGV("THS: %d, 0x%02x\n", config->ths, (int)config->reg_ths);
119 if (apply)
120 result = inv_serial_single_write(mlsl_handle, pdata->address,
121 LSM303DLx_INT1_THS,
122 config->reg_ths);
123 return result;
124}
125
126static int lsm303dlx_a_set_dur(void *mlsl_handle,
127 struct ext_slave_platform_data *pdata,
128 struct lsm303dlx_a_config *config,
129 int apply,
130 long dur)
131{
132 int result = INV_SUCCESS;
133 long reg_dur = (dur * config->odr) / 1000000L;
134 config->dur = dur;
135
136 if (reg_dur > LSM303DLx_MAX_DUR)
137 reg_dur = LSM303DLx_MAX_DUR;
138
139 config->reg_dur = (unsigned char) reg_dur;
140 MPL_LOGV("DUR: %d, 0x%02x\n", config->dur, (int)config->reg_dur);
141 if (apply)
142 result = inv_serial_single_write(mlsl_handle, pdata->address,
143 LSM303DLx_INT1_DURATION,
144 (unsigned char)reg_dur);
145 return result;
146}
147
148/**
149 * Sets the IRQ to fire when one of the IRQ events occur. Threshold and
150 * duration will not be used uless the type is MOT or NMOT.
151 *
152 * @param config configuration to apply to, suspend or resume
153 * @param irq_type The type of IRQ. Valid values are
154 * - MPU_SLAVE_IRQ_TYPE_NONE
155 * - MPU_SLAVE_IRQ_TYPE_MOTION
156 * - MPU_SLAVE_IRQ_TYPE_DATA_READY
157 */
158static int lsm303dlx_a_set_irq(void *mlsl_handle,
159 struct ext_slave_platform_data *pdata,
160 struct lsm303dlx_a_config *config,
161 int apply,
162 long irq_type)
163{
164 int result = INV_SUCCESS;
165 unsigned char reg1;
166 unsigned char reg2;
167
168 config->irq_type = (unsigned char)irq_type;
169 if (irq_type == MPU_SLAVE_IRQ_TYPE_DATA_READY) {
170 reg1 = 0x02;
171 reg2 = 0x00;
172 } else if (irq_type == MPU_SLAVE_IRQ_TYPE_MOTION) {
173 reg1 = 0x00;
174 reg2 = config->mot_int1_cfg;
175 } else {
176 reg1 = 0x00;
177 reg2 = 0x00;
178 }
179
180 if (apply) {
181 result = inv_serial_single_write(mlsl_handle, pdata->address,
182 LSM303DLx_CTRL_REG3, reg1);
183 result = inv_serial_single_write(mlsl_handle, pdata->address,
184 LSM303DLx_INT1_CFG, reg2);
185 }
186
187 return result;
188}
189
190/**
191 * @brief Set the output data rate for the particular configuration.
192 *
193 * @param mlsl_handle
194 * the handle to the serial channel the device is connected to.
195 * @param pdata
196 * a pointer to the slave platform data.
197 * @param config
198 * Config to modify with new ODR.
199 * @param apply
200 * whether to apply immediately or save the settings to be applied
201 * at the next resume.
202 * @param odr
203 * Output data rate in units of 1/1000Hz (mHz).
204 *
205 * @return INV_SUCCESS if successful or a non-zero error code.
206 */
207static int lsm303dlx_a_set_odr(void *mlsl_handle,
208 struct ext_slave_platform_data *pdata,
209 struct lsm303dlx_a_config *config,
210 int apply,
211 long odr)
212{
213 unsigned char bits;
214 int result = INV_SUCCESS;
215
216 /* normal power modes */
217 if (odr > 400000) {
218 config->odr = 1000000;
219 bits = LSM303DLx_PWR_MODE_NORMAL | 0x18;
220 } else if (odr > 100000) {
221 config->odr = 400000;
222 bits = LSM303DLx_PWR_MODE_NORMAL | 0x10;
223 } else if (odr > 50000) {
224 config->odr = 100000;
225 bits = LSM303DLx_PWR_MODE_NORMAL | 0x08;
226 } else if (odr > 10000) {
227 config->odr = 50000;
228 bits = LSM303DLx_PWR_MODE_NORMAL | 0x00;
229 /* low power modes */
230 } else if (odr > 5000) {
231 config->odr = 10000;
232 bits = 0xC0;
233 } else if (odr > 2000) {
234 config->odr = 5000;
235 bits = 0xA0;
236 } else if (odr > 1000) {
237 config->odr = 2000;
238 bits = 0x80;
239 } else if (odr > 500) {
240 config->odr = 1000;
241 bits = 0x60;
242 } else if (odr > 0) {
243 config->odr = 500;
244 bits = 0x40;
245 } else {
246 config->odr = 0;
247 bits = 0;
248 }
249
250 config->ctrl_reg1 = bits | (config->ctrl_reg1 & 0x7);
251 lsm303dlx_a_set_dur(mlsl_handle, pdata, config, apply, config->dur);
252 MPL_LOGV("ODR: %d, 0x%02x\n", config->odr, (int)config->ctrl_reg1);
253 if (apply)
254 result = inv_serial_single_write(mlsl_handle, pdata->address,
255 LSM303DLx_CTRL_REG1,
256 config->ctrl_reg1);
257 return result;
258}
259
260/**
261 * @brief Set the full scale range of the accels
262 *
263 * @param mlsl_handle
264 * the handle to the serial channel the device is connected to.
265 * @param pdata
266 * a pointer to the slave platform data.
267 * @param config
268 * pointer to configuration.
269 * @param apply
270 * whether to apply immediately or save the settings to be applied
271 * at the next resume.
272 * @param fsr
273 * requested full scale range.
274 *
275 * @return INV_SUCCESS if successful or a non-zero error code.
276 */
277static int lsm303dlx_a_set_fsr(void *mlsl_handle,
278 struct ext_slave_platform_data *pdata,
279 struct lsm303dlx_a_config *config,
280 int apply,
281 long fsr)
282{
283 unsigned char reg1 = 0x40;
284 int result = INV_SUCCESS;
285
286 if (fsr <= 2048) {
287 config->fsr = 2048;
288 } else if (fsr <= 4096) {
289 reg1 |= 0x30;
290 config->fsr = 4096;
291 } else {
292 reg1 |= 0x10;
293 config->fsr = 8192;
294 }
295
296 lsm303dlx_a_set_ths(mlsl_handle, pdata,
297 config, apply, config->ths);
298 MPL_LOGV("FSR: %d\n", config->fsr);
299 if (apply)
300 result = inv_serial_single_write(mlsl_handle, pdata->address,
301 LSM303DLx_CTRL_REG4, reg1);
302
303 return result;
304}
305
306/**
307 * @brief suspends the device to put it in its lowest power mode.
308 *
309 * @param mlsl_handle
310 * the handle to the serial channel the device is connected to.
311 * @param slave
312 * a pointer to the slave descriptor data structure.
313 * @param pdata
314 * a pointer to the slave platform data.
315 *
316 * @return INV_SUCCESS if successful or a non-zero error code.
317 */
318static int lsm303dlx_a_suspend(void *mlsl_handle,
319 struct ext_slave_descr *slave,
320 struct ext_slave_platform_data *pdata)
321{
322 int result = INV_SUCCESS;
323 unsigned char reg1;
324 unsigned char reg2;
325 struct lsm303dlx_a_private_data *private_data =
326 (struct lsm303dlx_a_private_data *)(pdata->private_data);
327
328 result = inv_serial_single_write(mlsl_handle, pdata->address,
329 LSM303DLx_CTRL_REG1,
330 private_data->suspend.ctrl_reg1);
331
332 result = inv_serial_single_write(mlsl_handle, pdata->address,
333 LSM303DLx_CTRL_REG2, 0x0f);
334 reg1 = 0x40;
335 if (private_data->suspend.fsr == 8192)
336 reg1 |= 0x30;
337 else if (private_data->suspend.fsr == 4096)
338 reg1 |= 0x10;
339 /* else bits [4..5] are already zero */
340
341 result = inv_serial_single_write(mlsl_handle, pdata->address,
342 LSM303DLx_CTRL_REG4, reg1);
343 result = inv_serial_single_write(mlsl_handle, pdata->address,
344 LSM303DLx_INT1_THS,
345 private_data->suspend.reg_ths);
346 result = inv_serial_single_write(mlsl_handle, pdata->address,
347 LSM303DLx_INT1_DURATION,
348 private_data->suspend.reg_dur);
349
350 if (private_data->suspend.irq_type == MPU_SLAVE_IRQ_TYPE_DATA_READY) {
351 reg1 = 0x02;
352 reg2 = 0x00;
353 } else if (private_data->suspend.irq_type ==
354 MPU_SLAVE_IRQ_TYPE_MOTION) {
355 reg1 = 0x00;
356 reg2 = private_data->suspend.mot_int1_cfg;
357 } else {
358 reg1 = 0x00;
359 reg2 = 0x00;
360 }
361 result = inv_serial_single_write(mlsl_handle, pdata->address,
362 LSM303DLx_CTRL_REG3, reg1);
363 result = inv_serial_single_write(mlsl_handle, pdata->address,
364 LSM303DLx_INT1_CFG, reg2);
365 result = inv_serial_read(mlsl_handle, pdata->address,
366 LSM303DLx_HP_FILTER_RESET, 1, &reg1);
367 return result;
368}
369
370/**
371 * @brief resume the device in the proper power state given the configuration
372 * chosen.
373 *
374 * @param mlsl_handle
375 * the handle to the serial channel the device is connected to.
376 * @param slave
377 * a pointer to the slave descriptor data structure.
378 * @param pdata
379 * a pointer to the slave platform data.
380 *
381 * @return INV_SUCCESS if successful or a non-zero error code.
382 */
383static int lsm303dlx_a_resume(void *mlsl_handle,
384 struct ext_slave_descr *slave,
385 struct ext_slave_platform_data *pdata)
386{
387 int result = INV_SUCCESS;
388 unsigned char reg1;
389 unsigned char reg2;
390 struct lsm303dlx_a_private_data *private_data =
391 (struct lsm303dlx_a_private_data *)(pdata->private_data);
392
393
394 result = inv_serial_single_write(mlsl_handle, pdata->address,
395 LSM303DLx_CTRL_REG1,
396 private_data->resume.ctrl_reg1);
397 if (result) {
398 LOG_RESULT_LOCATION(result);
399 return result;
400 }
401 msleep(6);
402
403 /* Full Scale */
404 reg1 = 0x40;
405 if (private_data->resume.fsr == 8192)
406 reg1 |= 0x30;
407 else if (private_data->resume.fsr == 4096)
408 reg1 |= 0x10;
409
410 result = inv_serial_single_write(mlsl_handle, pdata->address,
411 LSM303DLx_CTRL_REG4, reg1);
412 if (result) {
413 LOG_RESULT_LOCATION(result);
414 return result;
415 }
416
417 /* Configure high pass filter */
418 result = inv_serial_single_write(mlsl_handle, pdata->address,
419 LSM303DLx_CTRL_REG2, 0x0F);
420 if (result) {
421 LOG_RESULT_LOCATION(result);
422 return result;
423 }
424
425 if (private_data->resume.irq_type == MPU_SLAVE_IRQ_TYPE_DATA_READY) {
426 reg1 = 0x02;
427 reg2 = 0x00;
428 } else if (private_data->resume.irq_type ==
429 MPU_SLAVE_IRQ_TYPE_MOTION) {
430 reg1 = 0x00;
431 reg2 = private_data->resume.mot_int1_cfg;
432 } else {
433 reg1 = 0x00;
434 reg2 = 0x00;
435 }
436 result = inv_serial_single_write(mlsl_handle, pdata->address,
437 LSM303DLx_CTRL_REG3, reg1);
438 if (result) {
439 LOG_RESULT_LOCATION(result);
440 return result;
441 }
442 result = inv_serial_single_write(mlsl_handle, pdata->address,
443 LSM303DLx_INT1_THS,
444 private_data->resume.reg_ths);
445 if (result) {
446 LOG_RESULT_LOCATION(result);
447 return result;
448 }
449 result = inv_serial_single_write(mlsl_handle, pdata->address,
450 LSM303DLx_INT1_DURATION,
451 private_data->resume.reg_dur);
452 if (result) {
453 LOG_RESULT_LOCATION(result);
454 return result;
455 }
456 result = inv_serial_single_write(mlsl_handle, pdata->address,
457 LSM303DLx_INT1_CFG, reg2);
458 if (result) {
459 LOG_RESULT_LOCATION(result);
460 return result;
461 }
462 result = inv_serial_read(mlsl_handle, pdata->address,
463 LSM303DLx_HP_FILTER_RESET, 1, &reg1);
464 if (result) {
465 LOG_RESULT_LOCATION(result);
466 return result;
467 }
468 return result;
469}
470
471/**
472 * @brief read the sensor data from the device.
473 *
474 * @param mlsl_handle
475 * the handle to the serial channel the device is connected to.
476 * @param slave
477 * a pointer to the slave descriptor data structure.
478 * @param pdata
479 * a pointer to the slave platform data.
480 * @param data
481 * a buffer to store the data read.
482 *
483 * @return INV_SUCCESS if successful or a non-zero error code.
484 */
485static int lsm303dlx_a_read(void *mlsl_handle,
486 struct ext_slave_descr *slave,
487 struct ext_slave_platform_data *pdata,
488 unsigned char *data)
489{
490 int result = INV_SUCCESS;
491 result = inv_serial_read(mlsl_handle, pdata->address,
492 LSM303DLx_STATUS_REG, 1, data);
493 if (data[0] & 0x0F) {
494 result = inv_serial_read(mlsl_handle, pdata->address,
495 slave->read_reg, slave->read_len, data);
496 return result;
497 } else
498 return INV_ERROR_ACCEL_DATA_NOT_READY;
499}
500
501/**
502 * @brief one-time device driver initialization function.
503 * If the driver is built as a kernel module, this function will be
504 * called when the module is loaded in the kernel.
505 * If the driver is built-in in the kernel, this function will be
506 * called at boot time.
507 *
508 * @param mlsl_handle
509 * the handle to the serial channel the device is connected to.
510 * @param slave
511 * a pointer to the slave descriptor data structure.
512 * @param pdata
513 * a pointer to the slave platform data.
514 *
515 * @return INV_SUCCESS if successful or a non-zero error code.
516 */
517static int lsm303dlx_a_init(void *mlsl_handle,
518 struct ext_slave_descr *slave,
519 struct ext_slave_platform_data *pdata)
520{
521 long range;
522 struct lsm303dlx_a_private_data *private_data;
523 private_data = (struct lsm303dlx_a_private_data *)
524 kzalloc(sizeof(struct lsm303dlx_a_private_data), GFP_KERNEL);
525
526 if (!private_data)
527 return INV_ERROR_MEMORY_EXAUSTED;
528
529 pdata->private_data = private_data;
530
531 private_data->resume.ctrl_reg1 = 0x37;
532 private_data->suspend.ctrl_reg1 = 0x47;
533 private_data->resume.mot_int1_cfg = 0x95;
534 private_data->suspend.mot_int1_cfg = 0x2a;
535
536 lsm303dlx_a_set_odr(mlsl_handle, pdata, &private_data->suspend,
537 false, 0);
538 lsm303dlx_a_set_odr(mlsl_handle, pdata, &private_data->resume,
539 false, 200000);
540
541 range = range_fixedpoint_to_long_mg(slave->range);
542 lsm303dlx_a_set_fsr(mlsl_handle, pdata, &private_data->suspend,
543 false, range);
544 lsm303dlx_a_set_fsr(mlsl_handle, pdata, &private_data->resume,
545 false, range);
546
547 lsm303dlx_a_set_ths(mlsl_handle, pdata, &private_data->suspend,
548 false, 80);
549 lsm303dlx_a_set_ths(mlsl_handle, pdata, &private_data->resume,
550 false, 40);
551
552 lsm303dlx_a_set_dur(mlsl_handle, pdata, &private_data->suspend,
553 false, 1000);
554 lsm303dlx_a_set_dur(mlsl_handle, pdata, &private_data->resume,
555 false, 2540);
556
557 lsm303dlx_a_set_irq(mlsl_handle, pdata, &private_data->suspend,
558 false, MPU_SLAVE_IRQ_TYPE_NONE);
559 lsm303dlx_a_set_irq(mlsl_handle, pdata, &private_data->resume,
560 false, MPU_SLAVE_IRQ_TYPE_NONE);
561 return INV_SUCCESS;
562}
563
564/**
565 * @brief one-time device driver exit function.
566 * If the driver is built as a kernel module, this function will be
567 * called when the module is removed from the kernel.
568 *
569 * @param mlsl_handle
570 * the handle to the serial channel the device is connected to.
571 * @param slave
572 * a pointer to the slave descriptor data structure.
573 * @param pdata
574 * a pointer to the slave platform data.
575 *
576 * @return INV_SUCCESS if successful or a non-zero error code.
577 */
578static int lsm303dlx_a_exit(void *mlsl_handle,
579 struct ext_slave_descr *slave,
580 struct ext_slave_platform_data *pdata)
581{
582 kfree(pdata->private_data);
583 return INV_SUCCESS;
584}
585
586/**
587 * @brief device configuration facility.
588 *
589 * @param mlsl_handle
590 * the handle to the serial channel the device is connected to.
591 * @param slave
592 * a pointer to the slave descriptor data structure.
593 * @param pdata
594 * a pointer to the slave platform data.
595 * @param data
596 * a pointer to the configuration data structure.
597 *
598 * @return INV_SUCCESS if successful or a non-zero error code.
599 */
600static int lsm303dlx_a_config(void *mlsl_handle,
601 struct ext_slave_descr *slave,
602 struct ext_slave_platform_data *pdata,
603 struct ext_slave_config *data)
604{
605 struct lsm303dlx_a_private_data *private_data = pdata->private_data;
606 if (!data->data)
607 return INV_ERROR_INVALID_PARAMETER;
608
609 switch (data->key) {
610 case MPU_SLAVE_CONFIG_ODR_SUSPEND:
611 return lsm303dlx_a_set_odr(mlsl_handle, pdata,
612 &private_data->suspend,
613 data->apply,
614 *((long *)data->data));
615 case MPU_SLAVE_CONFIG_ODR_RESUME:
616 return lsm303dlx_a_set_odr(mlsl_handle, pdata,
617 &private_data->resume,
618 data->apply,
619 *((long *)data->data));
620 case MPU_SLAVE_CONFIG_FSR_SUSPEND:
621 return lsm303dlx_a_set_fsr(mlsl_handle, pdata,
622 &private_data->suspend,
623 data->apply,
624 *((long *)data->data));
625 case MPU_SLAVE_CONFIG_FSR_RESUME:
626 return lsm303dlx_a_set_fsr(mlsl_handle, pdata,
627 &private_data->resume,
628 data->apply,
629 *((long *)data->data));
630 case MPU_SLAVE_CONFIG_MOT_THS:
631 return lsm303dlx_a_set_ths(mlsl_handle, pdata,
632 &private_data->suspend,
633 data->apply,
634 *((long *)data->data));
635 case MPU_SLAVE_CONFIG_NMOT_THS:
636 return lsm303dlx_a_set_ths(mlsl_handle, pdata,
637 &private_data->resume,
638 data->apply,
639 *((long *)data->data));
640 case MPU_SLAVE_CONFIG_MOT_DUR:
641 return lsm303dlx_a_set_dur(mlsl_handle, pdata,
642 &private_data->suspend,
643 data->apply,
644 *((long *)data->data));
645 case MPU_SLAVE_CONFIG_NMOT_DUR:
646 return lsm303dlx_a_set_dur(mlsl_handle, pdata,
647 &private_data->resume,
648 data->apply,
649 *((long *)data->data));
650 case MPU_SLAVE_CONFIG_IRQ_SUSPEND:
651 return lsm303dlx_a_set_irq(mlsl_handle, pdata,
652 &private_data->suspend,
653 data->apply,
654 *((long *)data->data));
655 case MPU_SLAVE_CONFIG_IRQ_RESUME:
656 return lsm303dlx_a_set_irq(mlsl_handle, pdata,
657 &private_data->resume,
658 data->apply,
659 *((long *)data->data));
660 default:
661 LOG_RESULT_LOCATION(INV_ERROR_FEATURE_NOT_IMPLEMENTED);
662 return INV_ERROR_FEATURE_NOT_IMPLEMENTED;
663 };
664
665 return INV_SUCCESS;
666}
667
668/**
669 * @brief facility to retrieve the device configuration.
670 *
671 * @param mlsl_handle
672 * the handle to the serial channel the device is connected to.
673 * @param slave
674 * a pointer to the slave descriptor data structure.
675 * @param pdata
676 * a pointer to the slave platform data.
677 * @param data
678 * a pointer to store the returned configuration data structure.
679 *
680 * @return INV_SUCCESS if successful or a non-zero error code.
681 */
682static int lsm303dlx_a_get_config(void *mlsl_handle,
683 struct ext_slave_descr *slave,
684 struct ext_slave_platform_data *pdata,
685 struct ext_slave_config *data)
686{
687 struct lsm303dlx_a_private_data *private_data = pdata->private_data;
688 if (!data->data)
689 return INV_ERROR_INVALID_PARAMETER;
690
691 switch (data->key) {
692 case MPU_SLAVE_CONFIG_ODR_SUSPEND:
693 (*(unsigned long *)data->data) =
694 (unsigned long) private_data->suspend.odr;
695 break;
696 case MPU_SLAVE_CONFIG_ODR_RESUME:
697 (*(unsigned long *)data->data) =
698 (unsigned long) private_data->resume.odr;
699 break;
700 case MPU_SLAVE_CONFIG_FSR_SUSPEND:
701 (*(unsigned long *)data->data) =
702 (unsigned long) private_data->suspend.fsr;
703 break;
704 case MPU_SLAVE_CONFIG_FSR_RESUME:
705 (*(unsigned long *)data->data) =
706 (unsigned long) private_data->resume.fsr;
707 break;
708 case MPU_SLAVE_CONFIG_MOT_THS:
709 (*(unsigned long *)data->data) =
710 (unsigned long) private_data->suspend.ths;
711 break;
712 case MPU_SLAVE_CONFIG_NMOT_THS:
713 (*(unsigned long *)data->data) =
714 (unsigned long) private_data->resume.ths;
715 break;
716 case MPU_SLAVE_CONFIG_MOT_DUR:
717 (*(unsigned long *)data->data) =
718 (unsigned long) private_data->suspend.dur;
719 break;
720 case MPU_SLAVE_CONFIG_NMOT_DUR:
721 (*(unsigned long *)data->data) =
722 (unsigned long) private_data->resume.dur;
723 break;
724 case MPU_SLAVE_CONFIG_IRQ_SUSPEND:
725 (*(unsigned long *)data->data) =
726 (unsigned long) private_data->suspend.irq_type;
727 break;
728 case MPU_SLAVE_CONFIG_IRQ_RESUME:
729 (*(unsigned long *)data->data) =
730 (unsigned long) private_data->resume.irq_type;
731 break;
732 default:
733 LOG_RESULT_LOCATION(INV_ERROR_FEATURE_NOT_IMPLEMENTED);
734 return INV_ERROR_FEATURE_NOT_IMPLEMENTED;
735 };
736
737 return INV_SUCCESS;
738}
739
740static struct ext_slave_descr lsm303dlx_a_descr = {
741 .init = lsm303dlx_a_init,
742 .exit = lsm303dlx_a_exit,
743 .suspend = lsm303dlx_a_suspend,
744 .resume = lsm303dlx_a_resume,
745 .read = lsm303dlx_a_read,
746 .config = lsm303dlx_a_config,
747 .get_config = lsm303dlx_a_get_config,
748 .name = "lsm303dlx_a",
749 .type = EXT_SLAVE_TYPE_ACCEL,
750 .id = ACCEL_ID_LSM303DLX,
751 .read_reg = (0x28 | 0x80), /* 0x80 for burst reads */
752 .read_len = 6,
753 .endian = EXT_SLAVE_BIG_ENDIAN,
754 .range = {2, 480},
755 .trigger = NULL,
756};
757
758static
759struct ext_slave_descr *lsm303dlx_a_get_slave_descr(void)
760{
761 return &lsm303dlx_a_descr;
762}
763
764/* -------------------------------------------------------------------------- */
765struct lsm303dlx_a_mod_private_data {
766 struct i2c_client *client;
767 struct ext_slave_platform_data *pdata;
768};
769
770static unsigned short normal_i2c[] = { I2C_CLIENT_END };
771
772static int lsm303dlx_a_mod_probe(struct i2c_client *client,
773 const struct i2c_device_id *devid)
774{
775 struct ext_slave_platform_data *pdata;
776 struct lsm303dlx_a_mod_private_data *private_data;
777 int result = 0;
778
779 dev_info(&client->adapter->dev, "%s: %s\n", __func__, devid->name);
780
781 if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
782 result = -ENODEV;
783 goto out_no_free;
784 }
785
786 pdata = client->dev.platform_data;
787 if (!pdata) {
788 dev_err(&client->adapter->dev,
789 "Missing platform data for slave %s\n", devid->name);
790 result = -EFAULT;
791 goto out_no_free;
792 }
793
794 private_data = kzalloc(sizeof(*private_data), GFP_KERNEL);
795 if (!private_data) {
796 result = -ENOMEM;
797 goto out_no_free;
798 }
799
800 i2c_set_clientdata(client, private_data);
801 private_data->client = client;
802 private_data->pdata = pdata;
803
804 result = inv_mpu_register_slave(THIS_MODULE, client, pdata,
805 lsm303dlx_a_get_slave_descr);
806 if (result) {
807 dev_err(&client->adapter->dev,
808 "Slave registration failed: %s, %d\n",
809 devid->name, result);
810 goto out_free_memory;
811 }
812
813 return result;
814
815out_free_memory:
816 kfree(private_data);
817out_no_free:
818 dev_err(&client->adapter->dev, "%s failed %d\n", __func__, result);
819 return result;
820
821}
822
823static int lsm303dlx_a_mod_remove(struct i2c_client *client)
824{
825 struct lsm303dlx_a_mod_private_data *private_data =
826 i2c_get_clientdata(client);
827
828 dev_dbg(&client->adapter->dev, "%s\n", __func__);
829
830 inv_mpu_unregister_slave(client, private_data->pdata,
831 lsm303dlx_a_get_slave_descr);
832
833 kfree(private_data);
834 return 0;
835}
836
837static const struct i2c_device_id lsm303dlx_a_mod_id[] = {
838 { "lsm303dlx", ACCEL_ID_LSM303DLX },
839 {}
840};
841
842MODULE_DEVICE_TABLE(i2c, lsm303dlx_a_mod_id);
843
844static struct i2c_driver lsm303dlx_a_mod_driver = {
845 .class = I2C_CLASS_HWMON,
846 .probe = lsm303dlx_a_mod_probe,
847 .remove = lsm303dlx_a_mod_remove,
848 .id_table = lsm303dlx_a_mod_id,
849 .driver = {
850 .owner = THIS_MODULE,
851 .name = "lsm303dlx_a_mod",
852 },
853 .address_list = normal_i2c,
854};
855
856static int __init lsm303dlx_a_mod_init(void)
857{
858 int res = i2c_add_driver(&lsm303dlx_a_mod_driver);
859 pr_info("%s: Probe name %s\n", __func__, "lsm303dlx_a_mod");
860 if (res)
861 pr_err("%s failed\n", __func__);
862 return res;
863}
864
865static void __exit lsm303dlx_a_mod_exit(void)
866{
867 pr_info("%s\n", __func__);
868 i2c_del_driver(&lsm303dlx_a_mod_driver);
869}
870
871module_init(lsm303dlx_a_mod_init);
872module_exit(lsm303dlx_a_mod_exit);
873
874MODULE_AUTHOR("Invensense Corporation");
875MODULE_DESCRIPTION("Driver to integrate LSM303DLX_A sensor with the MPU");
876MODULE_LICENSE("GPL");
877MODULE_ALIAS("lsm303dlx_a_mod");
878
879/**
880 * @}
881 */
diff --git a/drivers/misc/inv_mpu/accel/mma8450.c b/drivers/misc/inv_mpu/accel/mma8450.c
new file mode 100644
index 00000000000..f698ee98bf5
--- /dev/null
+++ b/drivers/misc/inv_mpu/accel/mma8450.c
@@ -0,0 +1,804 @@
1/*
2 $License:
3 Copyright (C) 2011 InvenSense Corporation, All Rights Reserved.
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, see <http://www.gnu.org/licenses/>.
17 $
18 */
19
20/**
21 * @addtogroup ACCELDL
22 * @brief Provides the interface to setup and handle an accelerometer.
23 *
24 * @{
25 * @file mma8450.c
26 * @brief Accelerometer setup and handling methods for Freescale MMA8450.
27 */
28
29/* -------------------------------------------------------------------------- */
30
31#include <linux/i2c.h>
32#include <linux/module.h>
33#include <linux/moduleparam.h>
34#include <linux/kernel.h>
35#include <linux/errno.h>
36#include <linux/slab.h>
37#include <linux/delay.h>
38#include "mpu-dev.h"
39
40#include <log.h>
41#include <linux/mpu.h>
42#include "mlsl.h"
43#include "mldl_cfg.h"
44#undef MPL_LOG_TAG
45#define MPL_LOG_TAG "MPL-acc"
46
47/* full scale setting - register & mask */
48#define ACCEL_MMA8450_XYZ_DATA_CFG (0x16)
49
50#define ACCEL_MMA8450_CTRL_REG1 (0x38)
51#define ACCEL_MMA8450_CTRL_REG2 (0x39)
52#define ACCEL_MMA8450_CTRL_REG4 (0x3B)
53#define ACCEL_MMA8450_CTRL_REG5 (0x3C)
54
55#define ACCEL_MMA8450_CTRL_REG (0x38)
56#define ACCEL_MMA8450_CTRL_MASK (0x03)
57
58#define ACCEL_MMA8450_SLEEP_MASK (0x03)
59
60/* -------------------------------------------------------------------------- */
61
62struct mma8450_config {
63 unsigned int odr;
64 unsigned int fsr; /** < full scale range mg */
65 unsigned int ths; /** < Motion no-motion thseshold mg */
66 unsigned int dur; /** < Motion no-motion duration ms */
67 unsigned char reg_ths;
68 unsigned char reg_dur;
69 unsigned char ctrl_reg1;
70 unsigned char irq_type;
71 unsigned char mot_int1_cfg;
72};
73
74struct mma8450_private_data {
75 struct mma8450_config suspend;
76 struct mma8450_config resume;
77};
78
79
80/* -------------------------------------------------------------------------- */
81
82static int mma8450_set_ths(void *mlsl_handle,
83 struct ext_slave_platform_data *pdata,
84 struct mma8450_config *config,
85 int apply,
86 long ths)
87{
88 return INV_ERROR_FEATURE_NOT_IMPLEMENTED;
89}
90
91static int mma8450_set_dur(void *mlsl_handle,
92 struct ext_slave_platform_data *pdata,
93 struct mma8450_config *config,
94 int apply,
95 long dur)
96{
97 return INV_ERROR_FEATURE_NOT_IMPLEMENTED;
98}
99
100/**
101 * @brief Sets the IRQ to fire when one of the IRQ events occur.
102 * Threshold and duration will not be used unless the type is MOT or
103 * NMOT.
104 *
105 * @param mlsl_handle
106 * the handle to the serial channel the device is connected to.
107 * @param pdata
108 * a pointer to the slave platform data.
109 * @param config
110 * configuration to apply to, suspend or resume
111 * @param apply
112 * whether to apply immediately or save the settings to be applied
113 * at the next resume.
114 * @param irq_type
115 * the type of IRQ. Valid values are
116 * - MPU_SLAVE_IRQ_TYPE_NONE
117 * - MPU_SLAVE_IRQ_TYPE_MOTION
118 * - MPU_SLAVE_IRQ_TYPE_DATA_READY
119 *
120 * @return INV_SUCCESS if successful or a non-zero error code.
121 */
122static int mma8450_set_irq(void *mlsl_handle,
123 struct ext_slave_platform_data *pdata,
124 struct mma8450_config *config,
125 int apply,
126 long irq_type)
127{
128 int result = INV_SUCCESS;
129 unsigned char reg1;
130 unsigned char reg2;
131 unsigned char reg3;
132
133 config->irq_type = (unsigned char)irq_type;
134 if (irq_type == MPU_SLAVE_IRQ_TYPE_DATA_READY) {
135 reg1 = 0x01;
136 reg2 = 0x01;
137 reg3 = 0x07;
138 } else if (irq_type == MPU_SLAVE_IRQ_TYPE_NONE) {
139 reg1 = 0x00;
140 reg2 = 0x00;
141 reg3 = 0x00;
142 } else {
143 return INV_ERROR_FEATURE_NOT_IMPLEMENTED;
144 }
145
146 if (apply) {
147 /* XYZ_DATA_CFG: event flag enabled on Z axis */
148 result = inv_serial_single_write(mlsl_handle, pdata->address,
149 ACCEL_MMA8450_XYZ_DATA_CFG, reg3);
150 if (result) {
151 LOG_RESULT_LOCATION(result);
152 return result;
153 }
154 result = inv_serial_single_write(mlsl_handle, pdata->address,
155 ACCEL_MMA8450_CTRL_REG4, reg1);
156 if (result) {
157 LOG_RESULT_LOCATION(result);
158 return result;
159 }
160 result = inv_serial_single_write(mlsl_handle, pdata->address,
161 ACCEL_MMA8450_CTRL_REG5, reg2);
162 if (result) {
163 LOG_RESULT_LOCATION(result);
164 return result;
165 }
166 }
167
168 return result;
169}
170
171/**
172 * @brief Set the output data rate for the particular configuration.
173 *
174 * @param mlsl_handle
175 * the handle to the serial channel the device is connected to.
176 * @param pdata
177 * a pointer to the slave platform data.
178 * @param config
179 * Config to modify with new ODR.
180 * @param apply
181 * whether to apply immediately or save the settings to be applied
182 * at the next resume.
183 * @param odr
184 * Output data rate in units of 1/1000Hz (mHz).
185 *
186 * @return INV_SUCCESS if successful or a non-zero error code.
187 */
188static int mma8450_set_odr(void *mlsl_handle,
189 struct ext_slave_platform_data *pdata,
190 struct mma8450_config *config,
191 int apply,
192 long odr)
193{
194 unsigned char bits;
195 int result = INV_SUCCESS;
196
197 if (odr > 200000) {
198 config->odr = 400000;
199 bits = 0x00;
200 } else if (odr > 100000) {
201 config->odr = 200000;
202 bits = 0x04;
203 } else if (odr > 50000) {
204 config->odr = 100000;
205 bits = 0x08;
206 } else if (odr > 25000) {
207 config->odr = 50000;
208 bits = 0x0C;
209 } else if (odr > 12500) {
210 config->odr = 25000;
211 bits = 0x40; /* Sleep -> Auto wake mode */
212 } else if (odr > 1563) {
213 config->odr = 12500;
214 bits = 0x10;
215 } else if (odr > 0) {
216 config->odr = 1563;
217 bits = 0x14;
218 } else {
219 config->ctrl_reg1 = 0; /* Set FS1.FS2 to Standby */
220 config->odr = 0;
221 bits = 0;
222 }
223
224 config->ctrl_reg1 = bits | (config->ctrl_reg1 & 0x3);
225 if (apply) {
226 result = inv_serial_single_write(mlsl_handle, pdata->address,
227 ACCEL_MMA8450_CTRL_REG1, 0);
228 if (result) {
229 LOG_RESULT_LOCATION(result);
230 return result;
231 }
232 result = inv_serial_single_write(mlsl_handle, pdata->address,
233 ACCEL_MMA8450_CTRL_REG1, config->ctrl_reg1);
234 if (result) {
235 LOG_RESULT_LOCATION(result);
236 return result;
237 }
238 MPL_LOGV("ODR: %d mHz, 0x%02x\n",
239 config->odr, (int)config->ctrl_reg1);
240 }
241 return result;
242}
243
244/**
245 * @brief Set the full scale range of the accels
246 *
247 * @param mlsl_handle
248 * the handle to the serial channel the device is connected to.
249 * @param pdata
250 * a pointer to the slave platform data.
251 * @param config
252 * pointer to configuration.
253 * @param apply
254 * whether to apply immediately or save the settings to be applied
255 * at the next resume.
256 * @param fsr
257 * requested full scale range.
258 *
259 * @return INV_SUCCESS if successful or a non-zero error code.
260 */
261static int mma8450_set_fsr(void *mlsl_handle,
262 struct ext_slave_platform_data *pdata,
263 struct mma8450_config *config,
264 int apply,
265 long fsr)
266{
267 unsigned char bits;
268 int result = INV_SUCCESS;
269
270 if (fsr <= 2000) {
271 bits = 0x01;
272 config->fsr = 2000;
273 } else if (fsr <= 4000) {
274 bits = 0x02;
275 config->fsr = 4000;
276 } else {
277 bits = 0x03;
278 config->fsr = 8000;
279 }
280
281 config->ctrl_reg1 = bits | (config->ctrl_reg1 & 0xFC);
282 if (apply) {
283 result = inv_serial_single_write(mlsl_handle, pdata->address,
284 ACCEL_MMA8450_CTRL_REG1, config->ctrl_reg1);
285 if (result) {
286 LOG_RESULT_LOCATION(result);
287 return result;
288 }
289 MPL_LOGV("FSR: %d mg\n", config->fsr);
290 }
291 return result;
292}
293
294/**
295 * @brief suspends the device to put it in its lowest power mode.
296 *
297 * @param mlsl_handle
298 * the handle to the serial channel the device is connected to.
299 * @param slave
300 * a pointer to the slave descriptor data structure.
301 * @param pdata
302 * a pointer to the slave platform data.
303 *
304 * @return INV_SUCCESS if successful or a non-zero error code.
305 */
306static int mma8450_suspend(void *mlsl_handle,
307 struct ext_slave_descr *slave,
308 struct ext_slave_platform_data *pdata)
309{
310 int result;
311 struct mma8450_private_data *private_data = pdata->private_data;
312
313 if (private_data->suspend.fsr == 4000)
314 slave->range.mantissa = 4;
315 else if (private_data->suspend.fsr == 8000)
316 slave->range.mantissa = 8;
317 else
318 slave->range.mantissa = 2;
319 slave->range.fraction = 0;
320
321 result = inv_serial_single_write(mlsl_handle, pdata->address,
322 ACCEL_MMA8450_CTRL_REG1, 0);
323 if (result) {
324 LOG_RESULT_LOCATION(result);
325 return result;
326 }
327 if (private_data->suspend.ctrl_reg1) {
328 result = inv_serial_single_write(mlsl_handle, pdata->address,
329 ACCEL_MMA8450_CTRL_REG1,
330 private_data->suspend.ctrl_reg1);
331 if (result) {
332 LOG_RESULT_LOCATION(result);
333 return result;
334 }
335 }
336
337 result = mma8450_set_irq(mlsl_handle, pdata,
338 &private_data->suspend,
339 true, private_data->suspend.irq_type);
340 if (result) {
341 LOG_RESULT_LOCATION(result);
342 return result;
343 }
344 return result;
345}
346
347/**
348 * @brief resume the device in the proper power state given the configuration
349 * chosen.
350 *
351 * @param mlsl_handle
352 * the handle to the serial channel the device is connected to.
353 * @param slave
354 * a pointer to the slave descriptor data structure.
355 * @param pdata
356 * a pointer to the slave platform data.
357 *
358 * @return INV_SUCCESS if successful or a non-zero error code.
359 */
360static int mma8450_resume(void *mlsl_handle,
361 struct ext_slave_descr *slave,
362 struct ext_slave_platform_data *pdata)
363{
364 int result = INV_SUCCESS;
365 struct mma8450_private_data *private_data = pdata->private_data;
366
367 /* Full Scale */
368 if (private_data->resume.fsr == 4000)
369 slave->range.mantissa = 4;
370 else if (private_data->resume.fsr == 8000)
371 slave->range.mantissa = 8;
372 else
373 slave->range.mantissa = 2;
374 slave->range.fraction = 0;
375
376 if (result) {
377 LOG_RESULT_LOCATION(result);
378 return result;
379 }
380 result = inv_serial_single_write(mlsl_handle, pdata->address,
381 ACCEL_MMA8450_CTRL_REG1, 0);
382 if (result) {
383 LOG_RESULT_LOCATION(result);
384 return result;
385 }
386 if (private_data->resume.ctrl_reg1) {
387 result = inv_serial_single_write(mlsl_handle, pdata->address,
388 ACCEL_MMA8450_CTRL_REG1,
389 private_data->resume.ctrl_reg1);
390 if (result) {
391 LOG_RESULT_LOCATION(result);
392 return result;
393 }
394 }
395 result = mma8450_set_irq(mlsl_handle, pdata,
396 &private_data->resume,
397 true, private_data->resume.irq_type);
398 if (result) {
399 LOG_RESULT_LOCATION(result);
400 return result;
401 }
402
403 return result;
404}
405
406/**
407 * @brief read the sensor data from the device.
408 *
409 * @param mlsl_handle
410 * the handle to the serial channel the device is connected to.
411 * @param slave
412 * a pointer to the slave descriptor data structure.
413 * @param pdata
414 * a pointer to the slave platform data.
415 * @param data
416 * a buffer to store the data read.
417 *
418 * @return INV_SUCCESS if successful or a non-zero error code.
419 */
420static int mma8450_read(void *mlsl_handle,
421 struct ext_slave_descr *slave,
422 struct ext_slave_platform_data *pdata, unsigned char *data)
423{
424 int result;
425 unsigned char local_data[4]; /* Status register + 3 bytes data */
426 result = inv_serial_read(mlsl_handle, pdata->address,
427 0x00, sizeof(local_data), local_data);
428 if (result) {
429 LOG_RESULT_LOCATION(result);
430 return result;
431 }
432 memcpy(data, &local_data[1], (slave->read_len) - 1);
433
434 MPL_LOGV("Data Not Ready: %02x %02x %02x %02x\n",
435 local_data[0], local_data[1],
436 local_data[2], local_data[3]);
437
438 return result;
439}
440
441/**
442 * @brief one-time device driver initialization function.
443 * If the driver is built as a kernel module, this function will be
444 * called when the module is loaded in the kernel.
445 * If the driver is built-in in the kernel, this function will be
446 * called at boot time.
447 *
448 * @param mlsl_handle
449 * the handle to the serial channel the device is connected to.
450 * @param slave
451 * a pointer to the slave descriptor data structure.
452 * @param pdata
453 * a pointer to the slave platform data.
454 *
455 * @return INV_SUCCESS if successful or a non-zero error code.
456 */
457static int mma8450_init(void *mlsl_handle,
458 struct ext_slave_descr *slave,
459 struct ext_slave_platform_data *pdata)
460{
461 struct mma8450_private_data *private_data;
462 private_data = (struct mma8450_private_data *)
463 kzalloc(sizeof(struct mma8450_private_data), GFP_KERNEL);
464
465 if (!private_data)
466 return INV_ERROR_MEMORY_EXAUSTED;
467
468 pdata->private_data = private_data;
469
470 mma8450_set_odr(mlsl_handle, pdata, &private_data->suspend,
471 false, 0);
472 mma8450_set_odr(mlsl_handle, pdata, &private_data->resume,
473 false, 200000);
474 mma8450_set_fsr(mlsl_handle, pdata, &private_data->suspend,
475 false, 2000);
476 mma8450_set_fsr(mlsl_handle, pdata, &private_data->resume,
477 false, 2000);
478 mma8450_set_irq(mlsl_handle, pdata, &private_data->suspend,
479 false,
480 MPU_SLAVE_IRQ_TYPE_NONE);
481 mma8450_set_irq(mlsl_handle, pdata, &private_data->resume,
482 false,
483 MPU_SLAVE_IRQ_TYPE_NONE);
484 return INV_SUCCESS;
485}
486
487/**
488 * @brief one-time device driver exit function.
489 * If the driver is built as a kernel module, this function will be
490 * called when the module is removed from the kernel.
491 *
492 * @param mlsl_handle
493 * the handle to the serial channel the device is connected to.
494 * @param slave
495 * a pointer to the slave descriptor data structure.
496 * @param pdata
497 * a pointer to the slave platform data.
498 *
499 * @return INV_SUCCESS if successful or a non-zero error code.
500 */
501static int mma8450_exit(void *mlsl_handle,
502 struct ext_slave_descr *slave,
503 struct ext_slave_platform_data *pdata)
504{
505 kfree(pdata->private_data);
506 return INV_SUCCESS;
507}
508
509/**
510 * @brief device configuration facility.
511 *
512 * @param mlsl_handle
513 * the handle to the serial channel the device is connected to.
514 * @param slave
515 * a pointer to the slave descriptor data structure.
516 * @param pdata
517 * a pointer to the slave platform data.
518 * @param data
519 * a pointer to the configuration data structure.
520 *
521 * @return INV_SUCCESS if successful or a non-zero error code.
522 */
523static int mma8450_config(void *mlsl_handle,
524 struct ext_slave_descr *slave,
525 struct ext_slave_platform_data *pdata,
526 struct ext_slave_config *data)
527{
528 struct mma8450_private_data *private_data = pdata->private_data;
529 if (!data->data)
530 return INV_ERROR_INVALID_PARAMETER;
531
532 switch (data->key) {
533 case MPU_SLAVE_CONFIG_ODR_SUSPEND:
534 return mma8450_set_odr(mlsl_handle, pdata,
535 &private_data->suspend,
536 data->apply,
537 *((long *)data->data));
538 case MPU_SLAVE_CONFIG_ODR_RESUME:
539 return mma8450_set_odr(mlsl_handle, pdata,
540 &private_data->resume,
541 data->apply,
542 *((long *)data->data));
543 case MPU_SLAVE_CONFIG_FSR_SUSPEND:
544 return mma8450_set_fsr(mlsl_handle, pdata,
545 &private_data->suspend,
546 data->apply,
547 *((long *)data->data));
548 case MPU_SLAVE_CONFIG_FSR_RESUME:
549 return mma8450_set_fsr(mlsl_handle, pdata,
550 &private_data->resume,
551 data->apply,
552 *((long *)data->data));
553 case MPU_SLAVE_CONFIG_MOT_THS:
554 return mma8450_set_ths(mlsl_handle, pdata,
555 &private_data->suspend,
556 data->apply,
557 *((long *)data->data));
558 case MPU_SLAVE_CONFIG_NMOT_THS:
559 return mma8450_set_ths(mlsl_handle, pdata,
560 &private_data->resume,
561 data->apply,
562 *((long *)data->data));
563 case MPU_SLAVE_CONFIG_MOT_DUR:
564 return mma8450_set_dur(mlsl_handle, pdata,
565 &private_data->suspend,
566 data->apply,
567 *((long *)data->data));
568 case MPU_SLAVE_CONFIG_NMOT_DUR:
569 return mma8450_set_dur(mlsl_handle, pdata,
570 &private_data->resume,
571 data->apply,
572 *((long *)data->data));
573 case MPU_SLAVE_CONFIG_IRQ_SUSPEND:
574 return mma8450_set_irq(mlsl_handle, pdata,
575 &private_data->suspend,
576 data->apply,
577 *((long *)data->data));
578 case MPU_SLAVE_CONFIG_IRQ_RESUME:
579 return mma8450_set_irq(mlsl_handle, pdata,
580 &private_data->resume,
581 data->apply,
582 *((long *)data->data));
583 default:
584 LOG_RESULT_LOCATION(INV_ERROR_FEATURE_NOT_IMPLEMENTED);
585 return INV_ERROR_FEATURE_NOT_IMPLEMENTED;
586 };
587
588 return INV_SUCCESS;
589}
590
591/**
592 * @brief facility to retrieve the device configuration.
593 *
594 * @param mlsl_handle
595 * the handle to the serial channel the device is connected to.
596 * @param slave
597 * a pointer to the slave descriptor data structure.
598 * @param pdata
599 * a pointer to the slave platform data.
600 * @param data
601 * a pointer to store the returned configuration data structure.
602 *
603 * @return INV_SUCCESS if successful or a non-zero error code.
604 */
605static int mma8450_get_config(void *mlsl_handle,
606 struct ext_slave_descr *slave,
607 struct ext_slave_platform_data *pdata,
608 struct ext_slave_config *data)
609{
610 struct mma8450_private_data *private_data = pdata->private_data;
611 if (!data->data)
612 return INV_ERROR_INVALID_PARAMETER;
613
614 switch (data->key) {
615 case MPU_SLAVE_CONFIG_ODR_SUSPEND:
616 (*(unsigned long *)data->data) =
617 (unsigned long) private_data->suspend.odr;
618 break;
619 case MPU_SLAVE_CONFIG_ODR_RESUME:
620 (*(unsigned long *)data->data) =
621 (unsigned long) private_data->resume.odr;
622 break;
623 case MPU_SLAVE_CONFIG_FSR_SUSPEND:
624 (*(unsigned long *)data->data) =
625 (unsigned long) private_data->suspend.fsr;
626 break;
627 case MPU_SLAVE_CONFIG_FSR_RESUME:
628 (*(unsigned long *)data->data) =
629 (unsigned long) private_data->resume.fsr;
630 break;
631 case MPU_SLAVE_CONFIG_MOT_THS:
632 (*(unsigned long *)data->data) =
633 (unsigned long) private_data->suspend.ths;
634 break;
635 case MPU_SLAVE_CONFIG_NMOT_THS:
636 (*(unsigned long *)data->data) =
637 (unsigned long) private_data->resume.ths;
638 break;
639 case MPU_SLAVE_CONFIG_MOT_DUR:
640 (*(unsigned long *)data->data) =
641 (unsigned long) private_data->suspend.dur;
642 break;
643 case MPU_SLAVE_CONFIG_NMOT_DUR:
644 (*(unsigned long *)data->data) =
645 (unsigned long) private_data->resume.dur;
646 break;
647 case MPU_SLAVE_CONFIG_IRQ_SUSPEND:
648 (*(unsigned long *)data->data) =
649 (unsigned long) private_data->suspend.irq_type;
650 break;
651 case MPU_SLAVE_CONFIG_IRQ_RESUME:
652 (*(unsigned long *)data->data) =
653 (unsigned long) private_data->resume.irq_type;
654 break;
655 default:
656 LOG_RESULT_LOCATION(INV_ERROR_FEATURE_NOT_IMPLEMENTED);
657 return INV_ERROR_FEATURE_NOT_IMPLEMENTED;
658 };
659
660 return INV_SUCCESS;
661}
662
663static struct ext_slave_descr mma8450_descr = {
664 .init = mma8450_init,
665 .exit = mma8450_exit,
666 .suspend = mma8450_suspend,
667 .resume = mma8450_resume,
668 .read = mma8450_read,
669 .config = mma8450_config,
670 .get_config = mma8450_get_config,
671 .name = "mma8450",
672 .type = EXT_SLAVE_TYPE_ACCEL,
673 .id = ACCEL_ID_MMA8450,
674 .read_reg = 0x00,
675 .read_len = 4,
676 .endian = EXT_SLAVE_FS8_BIG_ENDIAN,
677 .range = {2, 0},
678 .trigger = NULL,
679};
680
681static
682struct ext_slave_descr *mma8450_get_slave_descr(void)
683{
684 return &mma8450_descr;
685}
686
687/* -------------------------------------------------------------------------- */
688struct mma8450_mod_private_data {
689 struct i2c_client *client;
690 struct ext_slave_platform_data *pdata;
691};
692
693static unsigned short normal_i2c[] = { I2C_CLIENT_END };
694
695static int mma8450_mod_probe(struct i2c_client *client,
696 const struct i2c_device_id *devid)
697{
698 struct ext_slave_platform_data *pdata;
699 struct mma8450_mod_private_data *private_data;
700 int result = 0;
701
702 dev_info(&client->adapter->dev, "%s: %s\n", __func__, devid->name);
703
704 if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
705 result = -ENODEV;
706 goto out_no_free;
707 }
708
709 pdata = client->dev.platform_data;
710 if (!pdata) {
711 dev_err(&client->adapter->dev,
712 "Missing platform data for slave %s\n", devid->name);
713 result = -EFAULT;
714 goto out_no_free;
715 }
716
717 private_data = kzalloc(sizeof(*private_data), GFP_KERNEL);
718 if (!private_data) {
719 result = -ENOMEM;
720 goto out_no_free;
721 }
722
723 i2c_set_clientdata(client, private_data);
724 private_data->client = client;
725 private_data->pdata = pdata;
726
727 result = inv_mpu_register_slave(THIS_MODULE, client, pdata,
728 mma8450_get_slave_descr);
729 if (result) {
730 dev_err(&client->adapter->dev,
731 "Slave registration failed: %s, %d\n",
732 devid->name, result);
733 goto out_free_memory;
734 }
735
736 return result;
737
738out_free_memory:
739 kfree(private_data);
740out_no_free:
741 dev_err(&client->adapter->dev, "%s failed %d\n", __func__, result);
742 return result;
743
744}
745
746static int mma8450_mod_remove(struct i2c_client *client)
747{
748 struct mma8450_mod_private_data *private_data =
749 i2c_get_clientdata(client);
750
751 dev_dbg(&client->adapter->dev, "%s\n", __func__);
752
753 inv_mpu_unregister_slave(client, private_data->pdata,
754 mma8450_get_slave_descr);
755
756 kfree(private_data);
757 return 0;
758}
759
760static const struct i2c_device_id mma8450_mod_id[] = {
761 { "mma8450", ACCEL_ID_MMA8450 },
762 {}
763};
764
765MODULE_DEVICE_TABLE(i2c, mma8450_mod_id);
766
767static struct i2c_driver mma8450_mod_driver = {
768 .class = I2C_CLASS_HWMON,
769 .probe = mma8450_mod_probe,
770 .remove = mma8450_mod_remove,
771 .id_table = mma8450_mod_id,
772 .driver = {
773 .owner = THIS_MODULE,
774 .name = "mma8450_mod",
775 },
776 .address_list = normal_i2c,
777};
778
779static int __init mma8450_mod_init(void)
780{
781 int res = i2c_add_driver(&mma8450_mod_driver);
782 pr_info("%s: Probe name %s\n", __func__, "mma8450_mod");
783 if (res)
784 pr_err("%s failed\n", __func__);
785 return res;
786}
787
788static void __exit mma8450_mod_exit(void)
789{
790 pr_info("%s\n", __func__);
791 i2c_del_driver(&mma8450_mod_driver);
792}
793
794module_init(mma8450_mod_init);
795module_exit(mma8450_mod_exit);
796
797MODULE_AUTHOR("Invensense Corporation");
798MODULE_DESCRIPTION("Driver to integrate MMA8450 sensor with the MPU");
799MODULE_LICENSE("GPL");
800MODULE_ALIAS("mma8450_mod");
801
802/**
803 * @}
804 */
diff --git a/drivers/misc/inv_mpu/accel/mma845x.c b/drivers/misc/inv_mpu/accel/mma845x.c
new file mode 100644
index 00000000000..5f62b22388b
--- /dev/null
+++ b/drivers/misc/inv_mpu/accel/mma845x.c
@@ -0,0 +1,713 @@
1/*
2 $License:
3 Copyright (C) 2011 InvenSense Corporation, All Rights Reserved.
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, see <http://www.gnu.org/licenses/>.
17 $
18 */
19
20/**
21 * @addtogroup ACCELDL
22 * @brief Provides the interface to setup and handle an accelerometer.
23 *
24 * @{
25 * @file mma845x.c
26 * @brief Accelerometer setup and handling methods for Freescale MMA845X
27 */
28
29/* -------------------------------------------------------------------------- */
30
31#include <linux/i2c.h>
32#include <linux/module.h>
33#include <linux/moduleparam.h>
34#include <linux/kernel.h>
35#include <linux/errno.h>
36#include <linux/slab.h>
37#include <linux/delay.h>
38#include "mpu-dev.h"
39
40#include <log.h>
41#include <linux/mpu.h>
42#include "mlsl.h"
43#include "mldl_cfg.h"
44#undef MPL_LOG_TAG
45#define MPL_LOG_TAG "MPL-acc"
46
47#define ACCEL_MMA845X_XYZ_DATA_CFG (0x0E)
48#define ACCEL_MMA845X_CTRL_REG1 (0x2A)
49#define ACCEL_MMA845X_CTRL_REG4 (0x2D)
50#define ACCEL_MMA845X_CTRL_REG5 (0x2E)
51
52#define ACCEL_MMA845X_SLEEP_MASK (0x01)
53
54/* full scale setting - register & mask */
55#define ACCEL_MMA845X_CFG_REG (0x0E)
56#define ACCEL_MMA845X_CTRL_MASK (0x03)
57
58/* -------------------------------------------------------------------------- */
59
60struct mma845x_config {
61 unsigned int odr;
62 unsigned int fsr; /** < full scale range mg */
63 unsigned int ths; /** < Motion no-motion thseshold mg */
64 unsigned int dur; /** < Motion no-motion duration ms */
65 unsigned char reg_ths;
66 unsigned char reg_dur;
67 unsigned char ctrl_reg1;
68 unsigned char irq_type;
69 unsigned char mot_int1_cfg;
70};
71
72struct mma845x_private_data {
73 struct mma845x_config suspend;
74 struct mma845x_config resume;
75};
76
77/* -------------------------------------------------------------------------- */
78
79static int mma845x_set_ths(void *mlsl_handle,
80 struct ext_slave_platform_data *pdata,
81 struct mma845x_config *config,
82 int apply,
83 long ths)
84{
85 return INV_ERROR_FEATURE_NOT_IMPLEMENTED;
86}
87
88static int mma845x_set_dur(void *mlsl_handle,
89 struct ext_slave_platform_data *pdata,
90 struct mma845x_config *config,
91 int apply,
92 long dur)
93{
94 return INV_ERROR_FEATURE_NOT_IMPLEMENTED;
95}
96
97/**
98 * @brief Sets the IRQ to fire when one of the IRQ events occur.
99 * Threshold and duration will not be used unless the type is MOT or
100 * NMOT.
101 *
102 * @param mlsl_handle
103 * the handle to the serial channel the device is connected to.
104 * @param pdata
105 * a pointer to the slave platform data.
106 * @param config
107 * configuration to apply to, suspend or resume
108 * @param apply
109 * whether to apply immediately or save the settings to be applied
110 * at the next resume.
111 * @param irq_type
112 * the type of IRQ. Valid values are
113 * - MPU_SLAVE_IRQ_TYPE_NONE
114 * - MPU_SLAVE_IRQ_TYPE_MOTION
115 * - MPU_SLAVE_IRQ_TYPE_DATA_READY
116 *
117 * @return INV_SUCCESS if successful or a non-zero error code.
118 */
119static int mma845x_set_irq(void *mlsl_handle,
120 struct ext_slave_platform_data *pdata,
121 struct mma845x_config *config,
122 int apply,
123 long irq_type)
124{
125 int result = INV_SUCCESS;
126 unsigned char reg1;
127 unsigned char reg2;
128
129 config->irq_type = (unsigned char)irq_type;
130 if (irq_type == MPU_SLAVE_IRQ_TYPE_DATA_READY) {
131 reg1 = 0x01;
132 reg2 = 0x01;
133 } else if (irq_type == MPU_SLAVE_IRQ_TYPE_NONE) {
134 reg1 = 0x00;
135 reg2 = 0x00;
136 } else {
137 return INV_ERROR_FEATURE_NOT_IMPLEMENTED;
138 }
139
140 if (apply) {
141 result = inv_serial_single_write(mlsl_handle, pdata->address,
142 ACCEL_MMA845X_CTRL_REG4, reg1);
143 if (result) {
144 LOG_RESULT_LOCATION(result);
145 return result;
146 }
147 result = inv_serial_single_write(mlsl_handle, pdata->address,
148 ACCEL_MMA845X_CTRL_REG5, reg2);
149 if (result) {
150 LOG_RESULT_LOCATION(result);
151 return result;
152 }
153 }
154
155 return result;
156}
157
158/**
159 * @brief Set the output data rate for the particular configuration.
160 *
161 * @param mlsl_handle
162 * the handle to the serial channel the device is connected to.
163 * @param pdata
164 * a pointer to the slave platform data.
165 * @param config
166 * Config to modify with new ODR.
167 * @param apply
168 * whether to apply immediately or save the settings to be applied
169 * at the next resume.
170 * @param odr
171 * Output data rate in units of 1/1000Hz (mHz).
172 *
173 * @return INV_SUCCESS if successful or a non-zero error code.
174 */
175static int mma845x_set_odr(void *mlsl_handle,
176 struct ext_slave_platform_data *pdata,
177 struct mma845x_config *config,
178 int apply,
179 long odr)
180{
181 unsigned char bits;
182 int result = INV_SUCCESS;
183
184 if (odr > 400000) {
185 config->odr = 800000;
186 bits = 0x01;
187 } else if (odr > 200000) {
188 config->odr = 400000;
189 bits = 0x09;
190 } else if (odr > 100000) {
191 config->odr = 200000;
192 bits = 0x11;
193 } else if (odr > 50000) {
194 config->odr = 100000;
195 bits = 0x19;
196 } else if (odr > 12500) {
197 config->odr = 50000;
198 bits = 0x21;
199 } else if (odr > 6250) {
200 config->odr = 12500;
201 bits = 0x29;
202 } else if (odr > 1560) {
203 config->odr = 6250;
204 bits = 0x31;
205 } else if (odr > 0) {
206 config->odr = 1560;
207 bits = 0x39;
208 } else {
209 config->ctrl_reg1 = 0; /* Set FS1.FS2 to Standby */
210 config->odr = 0;
211 bits = 0;
212 }
213
214 config->ctrl_reg1 = bits;
215 if (apply) {
216 result = inv_serial_single_write(mlsl_handle, pdata->address,
217 ACCEL_MMA845X_CTRL_REG1,
218 config->ctrl_reg1);
219 if (result) {
220 LOG_RESULT_LOCATION(result);
221 return result;
222 }
223 MPL_LOGV("ODR: %d mHz, 0x%02x\n", config->odr,
224 (int)config->ctrl_reg1);
225 }
226 return result;
227}
228
229/**
230 * @brief Set the full scale range of the accels
231 *
232 * @param mlsl_handle
233 * the handle to the serial channel the device is connected to.
234 * @param pdata
235 * a pointer to the slave platform data.
236 * @param config
237 * pointer to configuration.
238 * @param apply
239 * whether to apply immediately or save the settings to be applied
240 * at the next resume.
241 * @param fsr
242 * requested full scale range.
243 *
244 * @return INV_SUCCESS if successful or a non-zero error code.
245 */
246static int mma845x_set_fsr(void *mlsl_handle,
247 struct ext_slave_platform_data *pdata,
248 struct mma845x_config *config,
249 int apply,
250 long fsr)
251{
252 unsigned char bits;
253 int result = INV_SUCCESS;
254
255 if (fsr <= 2000) {
256 bits = 0x00;
257 config->fsr = 2000;
258 } else if (fsr <= 4000) {
259 bits = 0x01;
260 config->fsr = 4000;
261 } else {
262 bits = 0x02;
263 config->fsr = 8000;
264 }
265
266 if (apply) {
267 result = inv_serial_single_write(mlsl_handle, pdata->address,
268 ACCEL_MMA845X_XYZ_DATA_CFG,
269 bits);
270 if (result) {
271 LOG_RESULT_LOCATION(result);
272 return result;
273 }
274 MPL_LOGV("FSR: %d mg\n", config->fsr);
275 }
276 return result;
277}
278
279/**
280 * @brief suspends the device to put it in its lowest power mode.
281 *
282 * @param mlsl_handle
283 * the handle to the serial channel the device is connected to.
284 * @param slave
285 * a pointer to the slave descriptor data structure.
286 * @param pdata
287 * a pointer to the slave platform data.
288 *
289 * @return INV_SUCCESS if successful or a non-zero error code.
290 */
291static int mma845x_suspend(void *mlsl_handle,
292 struct ext_slave_descr *slave,
293 struct ext_slave_platform_data *pdata)
294{
295 int result;
296 struct mma845x_private_data *private_data = pdata->private_data;
297
298 /* Full Scale */
299 if (private_data->suspend.fsr == 4000)
300 slave->range.mantissa = 4;
301 else if (private_data->suspend.fsr == 8000)
302 slave->range.mantissa = 8;
303 else
304 slave->range.mantissa = 2;
305
306 slave->range.fraction = 0;
307
308 result = mma845x_set_fsr(mlsl_handle, pdata,
309 &private_data->suspend,
310 true, private_data->suspend.fsr);
311 if (result) {
312 LOG_RESULT_LOCATION(result);
313 return result;
314 }
315 result = inv_serial_single_write(mlsl_handle, pdata->address,
316 ACCEL_MMA845X_CTRL_REG1,
317 private_data->suspend.ctrl_reg1);
318 if (result) {
319 LOG_RESULT_LOCATION(result);
320 return result;
321 }
322
323 return result;
324}
325
326/**
327 * @brief resume the device in the proper power state given the configuration
328 * chosen.
329 *
330 * @param mlsl_handle
331 * the handle to the serial channel the device is connected to.
332 * @param slave
333 * a pointer to the slave descriptor data structure.
334 * @param pdata
335 * a pointer to the slave platform data.
336 *
337 * @return INV_SUCCESS if successful or a non-zero error code.
338 */
339static int mma845x_resume(void *mlsl_handle,
340 struct ext_slave_descr *slave,
341 struct ext_slave_platform_data *pdata)
342{
343 int result = INV_SUCCESS;
344 struct mma845x_private_data *private_data = pdata->private_data;
345
346 /* Full Scale */
347 if (private_data->resume.fsr == 4000)
348 slave->range.mantissa = 4;
349 else if (private_data->resume.fsr == 8000)
350 slave->range.mantissa = 8;
351 else
352 slave->range.mantissa = 2;
353
354 slave->range.fraction = 0;
355
356 result = mma845x_set_fsr(mlsl_handle, pdata,
357 &private_data->resume,
358 true, private_data->resume.fsr);
359 if (result) {
360 LOG_RESULT_LOCATION(result);
361 return result;
362 }
363 result = inv_serial_single_write(mlsl_handle, pdata->address,
364 ACCEL_MMA845X_CTRL_REG1,
365 private_data->resume.ctrl_reg1);
366 if (result) {
367 LOG_RESULT_LOCATION(result);
368 return result;
369 }
370
371 return result;
372}
373
374/**
375 * @brief read the sensor data from the device.
376 *
377 * @param mlsl_handle
378 * the handle to the serial channel the device is connected to.
379 * @param slave
380 * a pointer to the slave descriptor data structure.
381 * @param pdata
382 * a pointer to the slave platform data.
383 * @param data
384 * a buffer to store the data read.
385 *
386 * @return INV_SUCCESS if successful or a non-zero error code.
387 */
388static int mma845x_read(void *mlsl_handle,
389 struct ext_slave_descr *slave,
390 struct ext_slave_platform_data *pdata, unsigned char *data)
391{
392 int result;
393 unsigned char local_data[7]; /* Status register + 6 bytes data */
394 result = inv_serial_read(mlsl_handle, pdata->address,
395 slave->read_reg, sizeof(local_data),
396 local_data);
397 if (result) {
398 LOG_RESULT_LOCATION(result);
399 return result;
400 }
401 memcpy(data, &local_data[1], slave->read_len);
402 return result;
403}
404
405static int mma845x_init(void *mlsl_handle,
406 struct ext_slave_descr *slave,
407 struct ext_slave_platform_data *pdata)
408{
409 long range;
410 struct mma845x_private_data *private_data;
411 private_data = (struct mma845x_private_data *)
412 kzalloc(sizeof(struct mma845x_private_data), GFP_KERNEL);
413
414 if (!private_data)
415 return INV_ERROR_MEMORY_EXAUSTED;
416
417 pdata->private_data = private_data;
418
419 mma845x_set_odr(mlsl_handle, pdata, &private_data->suspend,
420 false, 0);
421 mma845x_set_odr(mlsl_handle, pdata, &private_data->resume,
422 false, 200000);
423
424 range = range_fixedpoint_to_long_mg(slave->range);
425 mma845x_set_fsr(mlsl_handle, pdata, &private_data->suspend,
426 false, range);
427 mma845x_set_fsr(mlsl_handle, pdata, &private_data->resume,
428 false, range);
429
430 mma845x_set_irq(mlsl_handle, pdata, &private_data->suspend,
431 false, MPU_SLAVE_IRQ_TYPE_NONE);
432 mma845x_set_irq(mlsl_handle, pdata, &private_data->resume,
433 false, MPU_SLAVE_IRQ_TYPE_NONE);
434 return INV_SUCCESS;
435}
436
437static int mma845x_exit(void *mlsl_handle,
438 struct ext_slave_descr *slave,
439 struct ext_slave_platform_data *pdata)
440{
441 kfree(pdata->private_data);
442 return INV_SUCCESS;
443}
444
445static int mma845x_config(void *mlsl_handle,
446 struct ext_slave_descr *slave,
447 struct ext_slave_platform_data *pdata,
448 struct ext_slave_config *data)
449{
450 struct mma845x_private_data *private_data = pdata->private_data;
451 if (!data->data)
452 return INV_ERROR_INVALID_PARAMETER;
453
454 switch (data->key) {
455 case MPU_SLAVE_CONFIG_ODR_SUSPEND:
456 return mma845x_set_odr(mlsl_handle, pdata,
457 &private_data->suspend,
458 data->apply,
459 *((long *)data->data));
460 case MPU_SLAVE_CONFIG_ODR_RESUME:
461 return mma845x_set_odr(mlsl_handle, pdata,
462 &private_data->resume,
463 data->apply,
464 *((long *)data->data));
465 case MPU_SLAVE_CONFIG_FSR_SUSPEND:
466 return mma845x_set_fsr(mlsl_handle, pdata,
467 &private_data->suspend,
468 data->apply,
469 *((long *)data->data));
470 case MPU_SLAVE_CONFIG_FSR_RESUME:
471 return mma845x_set_fsr(mlsl_handle, pdata,
472 &private_data->resume,
473 data->apply,
474 *((long *)data->data));
475 case MPU_SLAVE_CONFIG_MOT_THS:
476 return mma845x_set_ths(mlsl_handle, pdata,
477 &private_data->suspend,
478 data->apply,
479 *((long *)data->data));
480 case MPU_SLAVE_CONFIG_NMOT_THS:
481 return mma845x_set_ths(mlsl_handle, pdata,
482 &private_data->resume,
483 data->apply,
484 *((long *)data->data));
485 case MPU_SLAVE_CONFIG_MOT_DUR:
486 return mma845x_set_dur(mlsl_handle, pdata,
487 &private_data->suspend,
488 data->apply,
489 *((long *)data->data));
490 case MPU_SLAVE_CONFIG_NMOT_DUR:
491 return mma845x_set_dur(mlsl_handle, pdata,
492 &private_data->resume,
493 data->apply,
494 *((long *)data->data));
495 case MPU_SLAVE_CONFIG_IRQ_SUSPEND:
496 return mma845x_set_irq(mlsl_handle, pdata,
497 &private_data->suspend,
498 data->apply,
499 *((long *)data->data));
500 case MPU_SLAVE_CONFIG_IRQ_RESUME:
501 return mma845x_set_irq(mlsl_handle, pdata,
502 &private_data->resume,
503 data->apply,
504 *((long *)data->data));
505 default:
506 LOG_RESULT_LOCATION(INV_ERROR_FEATURE_NOT_IMPLEMENTED);
507 return INV_ERROR_FEATURE_NOT_IMPLEMENTED;
508 };
509
510 return INV_SUCCESS;
511}
512
513static int mma845x_get_config(void *mlsl_handle,
514 struct ext_slave_descr *slave,
515 struct ext_slave_platform_data *pdata,
516 struct ext_slave_config *data)
517{
518 struct mma845x_private_data *private_data = pdata->private_data;
519 if (!data->data)
520 return INV_ERROR_INVALID_PARAMETER;
521
522 switch (data->key) {
523 case MPU_SLAVE_CONFIG_ODR_SUSPEND:
524 (*(unsigned long *)data->data) =
525 (unsigned long) private_data->suspend.odr;
526 break;
527 case MPU_SLAVE_CONFIG_ODR_RESUME:
528 (*(unsigned long *)data->data) =
529 (unsigned long) private_data->resume.odr;
530 break;
531 case MPU_SLAVE_CONFIG_FSR_SUSPEND:
532 (*(unsigned long *)data->data) =
533 (unsigned long) private_data->suspend.fsr;
534 break;
535 case MPU_SLAVE_CONFIG_FSR_RESUME:
536 (*(unsigned long *)data->data) =
537 (unsigned long) private_data->resume.fsr;
538 break;
539 case MPU_SLAVE_CONFIG_MOT_THS:
540 (*(unsigned long *)data->data) =
541 (unsigned long) private_data->suspend.ths;
542 break;
543 case MPU_SLAVE_CONFIG_NMOT_THS:
544 (*(unsigned long *)data->data) =
545 (unsigned long) private_data->resume.ths;
546 break;
547 case MPU_SLAVE_CONFIG_MOT_DUR:
548 (*(unsigned long *)data->data) =
549 (unsigned long) private_data->suspend.dur;
550 break;
551 case MPU_SLAVE_CONFIG_NMOT_DUR:
552 (*(unsigned long *)data->data) =
553 (unsigned long) private_data->resume.dur;
554 break;
555 case MPU_SLAVE_CONFIG_IRQ_SUSPEND:
556 (*(unsigned long *)data->data) =
557 (unsigned long) private_data->suspend.irq_type;
558 break;
559 case MPU_SLAVE_CONFIG_IRQ_RESUME:
560 (*(unsigned long *)data->data) =
561 (unsigned long) private_data->resume.irq_type;
562 break;
563 default:
564 LOG_RESULT_LOCATION(INV_ERROR_FEATURE_NOT_IMPLEMENTED);
565 return INV_ERROR_FEATURE_NOT_IMPLEMENTED;
566 };
567
568 return INV_SUCCESS;
569}
570
571static struct ext_slave_descr mma845x_descr = {
572 .init = mma845x_init,
573 .exit = mma845x_exit,
574 .suspend = mma845x_suspend,
575 .resume = mma845x_resume,
576 .read = mma845x_read,
577 .config = mma845x_config,
578 .get_config = mma845x_get_config,
579 .name = "mma845x",
580 .type = EXT_SLAVE_TYPE_ACCEL,
581 .id = ACCEL_ID_MMA845X,
582 .read_reg = 0x00,
583 .read_len = 6,
584 .endian = EXT_SLAVE_FS16_BIG_ENDIAN,
585 .range = {2, 0},
586 .trigger = NULL,
587};
588
589static
590struct ext_slave_descr *mma845x_get_slave_descr(void)
591{
592 return &mma845x_descr;
593}
594
595/* -------------------------------------------------------------------------- */
596struct mma845x_mod_private_data {
597 struct i2c_client *client;
598 struct ext_slave_platform_data *pdata;
599};
600
601static unsigned short normal_i2c[] = { I2C_CLIENT_END };
602
603static int mma845x_mod_probe(struct i2c_client *client,
604 const struct i2c_device_id *devid)
605{
606 struct ext_slave_platform_data *pdata;
607 struct mma845x_mod_private_data *private_data;
608 int result = 0;
609
610 dev_info(&client->adapter->dev, "%s: %s\n", __func__, devid->name);
611
612 if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
613 result = -ENODEV;
614 goto out_no_free;
615 }
616
617 pdata = client->dev.platform_data;
618 if (!pdata) {
619 dev_err(&client->adapter->dev,
620 "Missing platform data for slave %s\n", devid->name);
621 result = -EFAULT;
622 goto out_no_free;
623 }
624
625 private_data = kzalloc(sizeof(*private_data), GFP_KERNEL);
626 if (!private_data) {
627 result = -ENOMEM;
628 goto out_no_free;
629 }
630
631 i2c_set_clientdata(client, private_data);
632 private_data->client = client;
633 private_data->pdata = pdata;
634
635 result = inv_mpu_register_slave(THIS_MODULE, client, pdata,
636 mma845x_get_slave_descr);
637 if (result) {
638 dev_err(&client->adapter->dev,
639 "Slave registration failed: %s, %d\n",
640 devid->name, result);
641 goto out_free_memory;
642 }
643
644 return result;
645
646out_free_memory:
647 kfree(private_data);
648out_no_free:
649 dev_err(&client->adapter->dev, "%s failed %d\n", __func__, result);
650 return result;
651
652}
653
654static int mma845x_mod_remove(struct i2c_client *client)
655{
656 struct mma845x_mod_private_data *private_data =
657 i2c_get_clientdata(client);
658
659 dev_dbg(&client->adapter->dev, "%s\n", __func__);
660
661 inv_mpu_unregister_slave(client, private_data->pdata,
662 mma845x_get_slave_descr);
663
664 kfree(private_data);
665 return 0;
666}
667
668static const struct i2c_device_id mma845x_mod_id[] = {
669 { "mma845x", ACCEL_ID_MMA845X },
670 {}
671};
672
673MODULE_DEVICE_TABLE(i2c, mma845x_mod_id);
674
675static struct i2c_driver mma845x_mod_driver = {
676 .class = I2C_CLASS_HWMON,
677 .probe = mma845x_mod_probe,
678 .remove = mma845x_mod_remove,
679 .id_table = mma845x_mod_id,
680 .driver = {
681 .owner = THIS_MODULE,
682 .name = "mma845x_mod",
683 },
684 .address_list = normal_i2c,
685};
686
687static int __init mma845x_mod_init(void)
688{
689 int res = i2c_add_driver(&mma845x_mod_driver);
690 pr_info("%s: Probe name %s\n", __func__, "mma845x_mod");
691 if (res)
692 pr_err("%s failed\n", __func__);
693 return res;
694}
695
696static void __exit mma845x_mod_exit(void)
697{
698 pr_info("%s\n", __func__);
699 i2c_del_driver(&mma845x_mod_driver);
700}
701
702module_init(mma845x_mod_init);
703module_exit(mma845x_mod_exit);
704
705MODULE_AUTHOR("Invensense Corporation");
706MODULE_DESCRIPTION("Driver to integrate MMA845X sensor with the MPU");
707MODULE_LICENSE("GPL");
708MODULE_ALIAS("mma845x_mod");
709
710
711/**
712 * @}
713 */
diff --git a/drivers/misc/inv_mpu/accel/mpu6050.c b/drivers/misc/inv_mpu/accel/mpu6050.c
new file mode 100644
index 00000000000..c5bb6784a41
--- /dev/null
+++ b/drivers/misc/inv_mpu/accel/mpu6050.c
@@ -0,0 +1,695 @@
1/*
2 $License:
3 Copyright (C) 2011 InvenSense Corporation, All Rights Reserved.
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, see <http://www.gnu.org/licenses/>.
17 $
18 */
19
20/**
21 * @addtogroup ACCELDL
22 * @brief Provides the interface to setup and handle an accelerometer.
23 *
24 * @{
25 * @file mpu6050.c
26 * @brief Accelerometer setup and handling methods for Invensense MPU6050
27 */
28
29/* -------------------------------------------------------------------------- */
30
31#include <linux/i2c.h>
32#include <linux/module.h>
33#include <linux/moduleparam.h>
34#include <linux/kernel.h>
35#include <linux/errno.h>
36#include <linux/delay.h>
37#include <linux/slab.h>
38#include "mpu-dev.h"
39
40#include <log.h>
41#include <linux/mpu.h>
42#include "mpu6050b1.h"
43#include "mlsl.h"
44#include "mldl_cfg.h"
45#undef MPL_LOG_TAG
46#define MPL_LOG_TAG "MPL-acc"
47
48/* -------------------------------------------------------------------------- */
49
50struct mpu6050_config {
51 unsigned int odr; /**< output data rate 1/1000 Hz */
52 unsigned int fsr; /**< full scale range mg */
53 unsigned int ths; /**< mot/no-mot thseshold mg */
54 unsigned int dur; /**< mot/no-mot duration ms */
55 unsigned int irq_type; /**< irq type */
56};
57
58struct mpu6050_private_data {
59 struct mpu6050_config suspend;
60 struct mpu6050_config resume;
61 struct mldl_cfg *mldl_cfg_ref;
62};
63
64/* -------------------------------------------------------------------------- */
65
66static int mpu6050_set_mldl_cfg_ref(void *mlsl_handle,
67 struct ext_slave_platform_data *pdata,
68 struct mldl_cfg *mldl_cfg_ref)
69{
70 struct mpu6050_private_data *private_data =
71 (struct mpu6050_private_data *)pdata->private_data;
72 private_data->mldl_cfg_ref = mldl_cfg_ref;
73 return 0;
74}
75static int mpu6050_set_lp_mode(void *mlsl_handle,
76 struct ext_slave_platform_data *pdata,
77 unsigned char lpa_freq)
78{
79 unsigned char b = 0;
80 /* Reducing the duration setting for lp mode */
81 b = 1;
82 inv_serial_single_write(mlsl_handle, pdata->address,
83 MPUREG_ACCEL_MOT_DUR, b);
84 /* Setting the cycle bit and LPA wake up freq */
85 inv_serial_read(mlsl_handle, pdata->address, MPUREG_PWR_MGMT_1, 1,
86 &b);
87 b |= BIT_CYCLE | BIT_PD_PTAT;
88 inv_serial_single_write(mlsl_handle, pdata->address,
89 MPUREG_PWR_MGMT_1,
90 b);
91 inv_serial_read(mlsl_handle, pdata->address,
92 MPUREG_PWR_MGMT_2, 1, &b);
93 b |= lpa_freq & BITS_LPA_WAKE_CTRL;
94 inv_serial_single_write(mlsl_handle, pdata->address,
95 MPUREG_PWR_MGMT_2, b);
96
97 return INV_SUCCESS;
98}
99
100static int mpu6050_set_fp_mode(void *mlsl_handle,
101 struct ext_slave_platform_data *pdata)
102{
103 unsigned char b;
104 struct mpu6050_private_data *private_data =
105 (struct mpu6050_private_data *)pdata->private_data;
106 /* Resetting the cycle bit and LPA wake up freq */
107 inv_serial_read(mlsl_handle, pdata->address,
108 MPUREG_PWR_MGMT_1, 1, &b);
109 b &= ~BIT_CYCLE & ~BIT_PD_PTAT;
110 inv_serial_single_write(mlsl_handle, pdata->address,
111 MPUREG_PWR_MGMT_1, b);
112 inv_serial_read(mlsl_handle, pdata->address,
113 MPUREG_PWR_MGMT_2, 1, &b);
114 b &= ~BITS_LPA_WAKE_CTRL;
115 inv_serial_single_write(mlsl_handle, pdata->address,
116 MPUREG_PWR_MGMT_2, b);
117 /* Resetting the duration setting for fp mode */
118 b = (unsigned char)private_data->suspend.ths / ACCEL_MOT_DUR_LSB;
119 inv_serial_single_write(mlsl_handle, pdata->address,
120 MPUREG_ACCEL_MOT_DUR, b);
121
122 return INV_SUCCESS;
123}
124/**
125 * Record the odr for use in computing duration values.
126 *
127 * @param config Config to set, suspend or resume structure
128 * @param odr output data rate in 1/1000 hz
129 */
130static int mpu6050_set_odr(void *mlsl_handle,
131 struct ext_slave_platform_data *pdata,
132 struct mpu6050_config *config, long apply, long odr)
133{
134 int result;
135 unsigned char b;
136 unsigned char lpa_freq = 1; /* Default value */
137 long base;
138 int total_divider;
139 struct mpu6050_private_data *private_data =
140 (struct mpu6050_private_data *)pdata->private_data;
141 struct mldl_cfg *mldl_cfg_ref =
142 (struct mldl_cfg *)private_data->mldl_cfg_ref;
143
144 if (mldl_cfg_ref) {
145 base = 1000 *
146 inv_mpu_get_sampling_rate_hz(mldl_cfg_ref->mpu_gyro_cfg)
147 * (mldl_cfg_ref->mpu_gyro_cfg->divider + 1);
148 } else {
149 /* have no reference to mldl_cfg => assume base rate is 1000 */
150 base = 1000000L;
151 }
152
153 if (odr != 0) {
154 total_divider = (base / odr) - 1;
155 /* final odr MAY be different from requested odr due to
156 integer truncation */
157 config->odr = base / (total_divider + 1);
158 } else {
159 config->odr = 0;
160 return 0;
161 }
162
163 /* if the DMP and/or gyros are on, don't set the ODR =>
164 the DMP/gyro mldl_cfg->divider setting will handle it */
165 if (apply
166 && (mldl_cfg_ref &&
167 !(mldl_cfg_ref->inv_mpu_cfg->requested_sensors &
168 INV_DMP_PROCESSOR))) {
169 result = inv_serial_single_write(mlsl_handle, pdata->address,
170 MPUREG_SMPLRT_DIV,
171 (unsigned char)total_divider);
172 if (result) {
173 LOG_RESULT_LOCATION(result);
174 return result;
175 }
176 MPL_LOGI("ODR : %d mHz\n", config->odr);
177 }
178 /* Decide whether to put accel in LP mode or pull out of LP mode
179 based on the odr. */
180 switch (odr) {
181 case 1000:
182 lpa_freq = BITS_LPA_WAKE_1HZ;
183 break;
184 case 2000:
185 lpa_freq = BITS_LPA_WAKE_2HZ;
186 break;
187 case 10000:
188 lpa_freq = BITS_LPA_WAKE_10HZ;
189 break;
190 case 40000:
191 lpa_freq = BITS_LPA_WAKE_40HZ;
192 break;
193 default:
194 inv_serial_read(mlsl_handle, pdata->address,
195 MPUREG_PWR_MGMT_1, 1, &b);
196 b &= BIT_CYCLE;
197 if (b == BIT_CYCLE) {
198 MPL_LOGI(" Accel LP - > FP mode. \n ");
199 mpu6050_set_fp_mode(mlsl_handle, pdata);
200 }
201 }
202 /* If lpa_freq default value was changed, set into LP mode */
203 if (lpa_freq != 1) {
204 MPL_LOGI(" Accel FP - > LP mode. \n ");
205 mpu6050_set_lp_mode(mlsl_handle, pdata, lpa_freq);
206 }
207 return 0;
208}
209
210static int mpu6050_set_fsr(void *mlsl_handle,
211 struct ext_slave_platform_data *pdata,
212 struct mpu6050_config *config, long apply, long fsr)
213{
214 unsigned char fsr_mask;
215 int result;
216
217 if (fsr <= 2000) {
218 config->fsr = 2000;
219 fsr_mask = 0x00;
220 } else if (fsr <= 4000) {
221 config->fsr = 4000;
222 fsr_mask = 0x08;
223 } else if (fsr <= 8000) {
224 config->fsr = 8000;
225 fsr_mask = 0x10;
226 } else { /* fsr = [8001, oo) */
227 config->fsr = 16000;
228 fsr_mask = 0x18;
229 }
230
231 if (apply) {
232 unsigned char reg;
233 result = inv_serial_read(mlsl_handle, pdata->address,
234 MPUREG_ACCEL_CONFIG, 1, &reg);
235 if (result) {
236 LOG_RESULT_LOCATION(result);
237 return result;
238 }
239 result = inv_serial_single_write(mlsl_handle, pdata->address,
240 MPUREG_ACCEL_CONFIG,
241 reg | fsr_mask);
242 if (result) {
243 LOG_RESULT_LOCATION(result);
244 return result;
245 }
246 MPL_LOGV("FSR: %d\n", config->fsr);
247 }
248 return 0;
249}
250
251static int mpu6050_set_irq(void *mlsl_handle,
252 struct ext_slave_platform_data *pdata,
253 struct mpu6050_config *config, long apply,
254 long irq_type)
255{
256 int result;
257 unsigned char reg_int_cfg;
258
259 switch (irq_type) {
260 case MPU_SLAVE_IRQ_TYPE_DATA_READY:
261 config->irq_type = irq_type;
262 reg_int_cfg = BIT_RAW_RDY_EN;
263 break;
264 /* todo: add MOTION, NO_MOTION, and FREEFALL */
265 case MPU_SLAVE_IRQ_TYPE_NONE:
266 /* Do nothing, not even set the interrupt because it is
267 shared with the gyro */
268 config->irq_type = irq_type;
269 return 0;
270 default:
271 return INV_ERROR_INVALID_PARAMETER;
272 }
273
274 if (apply) {
275 result = inv_serial_single_write(mlsl_handle, pdata->address,
276 MPUREG_INT_ENABLE,
277 reg_int_cfg);
278 if (result) {
279 LOG_RESULT_LOCATION(result);
280 return result;
281 }
282 MPL_LOGV("irq_type: %d\n", config->irq_type);
283 }
284
285 return 0;
286}
287
288static int mpu6050_set_ths(void *mlsl_handle,
289 struct ext_slave_platform_data *slave,
290 struct mpu6050_config *config, long apply, long ths)
291{
292 if (ths < 0)
293 ths = 0;
294
295 config->ths = ths;
296 MPL_LOGV("THS: %d\n", config->ths);
297 return 0;
298}
299
300static int mpu6050_set_dur(void *mlsl_handle,
301 struct ext_slave_platform_data *slave,
302 struct mpu6050_config *config, long apply, long dur)
303{
304 if (dur < 0)
305 dur = 0;
306
307 config->dur = dur;
308 MPL_LOGV("DUR: %d\n", config->dur);
309 return 0;
310}
311
312
313static int mpu6050_init(void *mlsl_handle,
314 struct ext_slave_descr *slave,
315 struct ext_slave_platform_data *pdata)
316{
317 int result;
318 struct mpu6050_private_data *private_data;
319
320
321 private_data = kzalloc(sizeof(*private_data), GFP_KERNEL);
322
323 if (!private_data)
324 return INV_ERROR_MEMORY_EXAUSTED;
325
326 pdata->private_data = private_data;
327
328 result = mpu6050_set_odr(mlsl_handle, pdata, &private_data->suspend,
329 false, 0);
330 if (result) {
331 LOG_RESULT_LOCATION(result);
332 return result;
333 }
334 result = mpu6050_set_odr(mlsl_handle, pdata, &private_data->resume,
335 false, 200000);
336 if (result) {
337 LOG_RESULT_LOCATION(result);
338 return result;
339 }
340 result = mpu6050_set_fsr(mlsl_handle, pdata, &private_data->suspend,
341 false, 2000);
342 if (result) {
343 LOG_RESULT_LOCATION(result);
344 return result;
345 }
346 result = mpu6050_set_fsr(mlsl_handle, pdata, &private_data->resume,
347 false, 2000);
348 if (result) {
349 LOG_RESULT_LOCATION(result);
350 return result;
351 }
352
353 result = mpu6050_set_irq(mlsl_handle, pdata, &private_data->suspend,
354 false, MPU_SLAVE_IRQ_TYPE_NONE);
355 if (result) {
356 LOG_RESULT_LOCATION(result);
357 return result;
358 }
359 result = mpu6050_set_irq(mlsl_handle, pdata, &private_data->resume,
360 false, MPU_SLAVE_IRQ_TYPE_NONE);
361 if (result) {
362 LOG_RESULT_LOCATION(result);
363 return result;
364 }
365
366 result = mpu6050_set_ths(mlsl_handle, pdata, &private_data->suspend,
367 false, 80);
368 if (result) {
369 LOG_RESULT_LOCATION(result);
370 return result;
371 }
372 result = mpu6050_set_ths(mlsl_handle, pdata, &private_data->resume,
373 false, 40);
374 if (result) {
375 LOG_RESULT_LOCATION(result);
376 return result;
377 }
378 result = mpu6050_set_dur(mlsl_handle, pdata, &private_data->suspend,
379 false, 1000);
380 if (result) {
381 LOG_RESULT_LOCATION(result);
382 return result;
383 }
384 result = mpu6050_set_dur(mlsl_handle, pdata, &private_data->resume,
385 false, 2540);
386 if (result) {
387 LOG_RESULT_LOCATION(result);
388 return result;
389 }
390
391 return 0;
392}
393
394static int mpu6050_exit(void *mlsl_handle,
395 struct ext_slave_descr *slave,
396 struct ext_slave_platform_data *pdata)
397{
398 kfree(pdata->private_data);
399 pdata->private_data = NULL;
400 return 0;
401}
402
403static int mpu6050_suspend(void *mlsl_handle,
404 struct ext_slave_descr *slave,
405 struct ext_slave_platform_data *pdata)
406{
407 unsigned char reg;
408 int result;
409 struct mpu6050_private_data *private_data =
410 (struct mpu6050_private_data *)pdata->private_data;
411
412 result = mpu6050_set_odr(mlsl_handle, pdata, &private_data->suspend,
413 true, private_data->suspend.odr);
414 if (result) {
415 LOG_RESULT_LOCATION(result);
416 return result;
417 }
418
419 result = mpu6050_set_irq(mlsl_handle, pdata, &private_data->suspend,
420 true, private_data->suspend.irq_type);
421 if (result) {
422 LOG_RESULT_LOCATION(result);
423 return result;
424 }
425
426 result = inv_serial_read(mlsl_handle, pdata->address,
427 MPUREG_PWR_MGMT_2, 1, &reg);
428 if (result) {
429 LOG_RESULT_LOCATION(result);
430 return result;
431 }
432 reg |= (BIT_STBY_XA | BIT_STBY_YA | BIT_STBY_ZA);
433
434 result = inv_serial_single_write(mlsl_handle, pdata->address,
435 MPUREG_PWR_MGMT_2, reg);
436 if (result) {
437 LOG_RESULT_LOCATION(result);
438 return result;
439 }
440
441 return 0;
442}
443
444static int mpu6050_resume(void *mlsl_handle,
445 struct ext_slave_descr *slave,
446 struct ext_slave_platform_data *pdata)
447{
448 int result;
449 unsigned char reg;
450 struct mpu6050_private_data *private_data =
451 (struct mpu6050_private_data *)pdata->private_data;
452
453 result = inv_serial_read(mlsl_handle, pdata->address,
454 MPUREG_PWR_MGMT_1, 1, &reg);
455 if (result) {
456 LOG_RESULT_LOCATION(result);
457 return result;
458 }
459
460 if (reg & BIT_SLEEP) {
461 result = inv_serial_single_write(mlsl_handle, pdata->address,
462 MPUREG_PWR_MGMT_1, reg & ~BIT_SLEEP);
463 if (result) {
464 LOG_RESULT_LOCATION(result);
465 return result;
466 }
467 }
468 msleep(2);
469
470 result = inv_serial_read(mlsl_handle, pdata->address,
471 MPUREG_PWR_MGMT_2, 1, &reg);
472 if (result) {
473 LOG_RESULT_LOCATION(result);
474 return result;
475 }
476 reg &= ~(BIT_STBY_XA | BIT_STBY_YA | BIT_STBY_ZA);
477 result = inv_serial_single_write(mlsl_handle, pdata->address,
478 MPUREG_PWR_MGMT_2, reg);
479 if (result) {
480 LOG_RESULT_LOCATION(result);
481 return result;
482 }
483
484 /* settings */
485
486 result = mpu6050_set_fsr(mlsl_handle, pdata, &private_data->resume,
487 true, private_data->resume.fsr);
488 if (result) {
489 LOG_RESULT_LOCATION(result);
490 return result;
491 }
492 result = mpu6050_set_odr(mlsl_handle, pdata, &private_data->resume,
493 true, private_data->resume.odr);
494 if (result) {
495 LOG_RESULT_LOCATION(result);
496 return result;
497 }
498 result = mpu6050_set_irq(mlsl_handle, pdata, &private_data->resume,
499 true, private_data->resume.irq_type);
500
501 /* motion, no_motion */
502 /* TODO : port these in their respective _set_thrs and _set_dur
503 functions and use the APPLY paremeter to apply just like
504 _set_odr, _set_irq, and _set_fsr. */
505 reg = (unsigned char)private_data->suspend.ths / ACCEL_MOT_THR_LSB;
506 result = inv_serial_single_write(mlsl_handle, pdata->address,
507 MPUREG_ACCEL_MOT_THR, reg);
508 if (result) {
509 LOG_RESULT_LOCATION(result);
510 return result;
511 }
512 reg = (unsigned char)
513 ACCEL_ZRMOT_THR_LSB_CONVERSION(private_data->resume.ths);
514 result = inv_serial_single_write(mlsl_handle, pdata->address,
515 MPUREG_ACCEL_ZRMOT_THR, reg);
516 if (result) {
517 LOG_RESULT_LOCATION(result);
518 return result;
519 }
520 reg = (unsigned char)private_data->suspend.ths / ACCEL_MOT_DUR_LSB;
521 result = inv_serial_single_write(mlsl_handle, pdata->address,
522 MPUREG_ACCEL_MOT_DUR, reg);
523 if (result) {
524 LOG_RESULT_LOCATION(result);
525 return result;
526 }
527 reg = (unsigned char)private_data->resume.ths / ACCEL_ZRMOT_DUR_LSB;
528 result = inv_serial_single_write(mlsl_handle, pdata->address,
529 MPUREG_ACCEL_ZRMOT_DUR, reg);
530 if (result) {
531 LOG_RESULT_LOCATION(result);
532 return result;
533 }
534 return 0;
535}
536
537static int mpu6050_read(void *mlsl_handle,
538 struct ext_slave_descr *slave,
539 struct ext_slave_platform_data *pdata,
540 unsigned char *data)
541{
542 int result;
543 result = inv_serial_read(mlsl_handle, pdata->address,
544 slave->read_reg, slave->read_len, data);
545 return result;
546}
547
548static int mpu6050_config(void *mlsl_handle,
549 struct ext_slave_descr *slave,
550 struct ext_slave_platform_data *pdata,
551 struct ext_slave_config *data)
552{
553 struct mpu6050_private_data *private_data =
554 (struct mpu6050_private_data *)pdata->private_data;
555 if (!data->data)
556 return INV_ERROR_INVALID_PARAMETER;
557
558 switch (data->key) {
559 case MPU_SLAVE_CONFIG_ODR_SUSPEND:
560 return mpu6050_set_odr(mlsl_handle, pdata,
561 &private_data->suspend,
562 data->apply, *((long *)data->data));
563 case MPU_SLAVE_CONFIG_ODR_RESUME:
564 return mpu6050_set_odr(mlsl_handle, pdata,
565 &private_data->resume,
566 data->apply, *((long *)data->data));
567 case MPU_SLAVE_CONFIG_FSR_SUSPEND:
568 return mpu6050_set_fsr(mlsl_handle, pdata,
569 &private_data->suspend,
570 data->apply, *((long *)data->data));
571 case MPU_SLAVE_CONFIG_FSR_RESUME:
572 return mpu6050_set_fsr(mlsl_handle, pdata,
573 &private_data->resume,
574 data->apply, *((long *)data->data));
575 case MPU_SLAVE_CONFIG_MOT_THS:
576 return mpu6050_set_ths(mlsl_handle, pdata,
577 &private_data->suspend,
578 data->apply, *((long *)data->data));
579 case MPU_SLAVE_CONFIG_NMOT_THS:
580 return mpu6050_set_ths(mlsl_handle, pdata,
581 &private_data->resume,
582 data->apply, *((long *)data->data));
583 case MPU_SLAVE_CONFIG_MOT_DUR:
584 return mpu6050_set_dur(mlsl_handle, pdata,
585 &private_data->suspend,
586 data->apply, *((long *)data->data));
587 case MPU_SLAVE_CONFIG_NMOT_DUR:
588 return mpu6050_set_dur(mlsl_handle, pdata,
589 &private_data->resume,
590 data->apply, *((long *)data->data));
591 case MPU_SLAVE_CONFIG_IRQ_SUSPEND:
592 return mpu6050_set_irq(mlsl_handle, pdata,
593 &private_data->suspend,
594 data->apply, *((long *)data->data));
595 break;
596 case MPU_SLAVE_CONFIG_IRQ_RESUME:
597 return mpu6050_set_irq(mlsl_handle, pdata,
598 &private_data->resume,
599 data->apply, *((long *)data->data));
600 case MPU_SLAVE_CONFIG_INTERNAL_REFERENCE:
601 return mpu6050_set_mldl_cfg_ref(mlsl_handle, pdata,
602 (struct mldl_cfg *)data->data);
603 break;
604
605 default:
606 return INV_ERROR_FEATURE_NOT_IMPLEMENTED;
607 };
608
609 return 0;
610}
611
612static int mpu6050_get_config(void *mlsl_handle,
613 struct ext_slave_descr *slave,
614 struct ext_slave_platform_data *pdata,
615 struct ext_slave_config *data)
616{
617 struct mpu6050_private_data *private_data =
618 (struct mpu6050_private_data *)pdata->private_data;
619 if (!data->data)
620 return INV_ERROR_INVALID_PARAMETER;
621
622 switch (data->key) {
623 case MPU_SLAVE_CONFIG_ODR_SUSPEND:
624 (*(unsigned long *)data->data) =
625 (unsigned long)private_data->suspend.odr;
626 break;
627 case MPU_SLAVE_CONFIG_ODR_RESUME:
628 (*(unsigned long *)data->data) =
629 (unsigned long)private_data->resume.odr;
630 break;
631 case MPU_SLAVE_CONFIG_FSR_SUSPEND:
632 (*(unsigned long *)data->data) =
633 (unsigned long)private_data->suspend.fsr;
634 break;
635 case MPU_SLAVE_CONFIG_FSR_RESUME:
636 (*(unsigned long *)data->data) =
637 (unsigned long)private_data->resume.fsr;
638 break;
639 case MPU_SLAVE_CONFIG_MOT_THS:
640 (*(unsigned long *)data->data) =
641 (unsigned long)private_data->suspend.ths;
642 break;
643 case MPU_SLAVE_CONFIG_NMOT_THS:
644 (*(unsigned long *)data->data) =
645 (unsigned long)private_data->resume.ths;
646 break;
647 case MPU_SLAVE_CONFIG_MOT_DUR:
648 (*(unsigned long *)data->data) =
649 (unsigned long)private_data->suspend.dur;
650 break;
651 case MPU_SLAVE_CONFIG_NMOT_DUR:
652 (*(unsigned long *)data->data) =
653 (unsigned long)private_data->resume.dur;
654 break;
655 case MPU_SLAVE_CONFIG_IRQ_SUSPEND:
656 (*(unsigned long *)data->data) =
657 (unsigned long)private_data->suspend.irq_type;
658 break;
659 case MPU_SLAVE_CONFIG_IRQ_RESUME:
660 (*(unsigned long *)data->data) =
661 (unsigned long)private_data->resume.irq_type;
662 break;
663 default:
664 return INV_ERROR_FEATURE_NOT_IMPLEMENTED;
665 };
666
667 return 0;
668}
669
670static struct ext_slave_descr mpu6050_descr = {
671 .init = mpu6050_init,
672 .exit = mpu6050_exit,
673 .suspend = mpu6050_suspend,
674 .resume = mpu6050_resume,
675 .read = mpu6050_read,
676 .config = mpu6050_config,
677 .get_config = mpu6050_get_config,
678 .name = "mpu6050",
679 .type = EXT_SLAVE_TYPE_ACCEL,
680 .id = ACCEL_ID_MPU6050,
681 .read_reg = 0x3B,
682 .read_len = 6,
683 .endian = EXT_SLAVE_BIG_ENDIAN,
684 .range = {2, 0},
685 .trigger = NULL,
686};
687
688struct ext_slave_descr *mpu6050_get_slave_descr(void)
689{
690 return &mpu6050_descr;
691}
692
693/**
694 * @}
695 */
diff --git a/drivers/misc/inv_mpu/accel/mpu6050.h b/drivers/misc/inv_mpu/accel/mpu6050.h
new file mode 100644
index 00000000000..c347bcb4d77
--- /dev/null
+++ b/drivers/misc/inv_mpu/accel/mpu6050.h
@@ -0,0 +1,28 @@
1/*
2 $License:
3 Copyright (C) 2011 InvenSense Corporation, All Rights Reserved.
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, see <http://www.gnu.org/licenses/>.
17 $
18 */
19
20
21#ifndef __MPU6050_H__
22#define __MPU6050_H__
23
24#include <linux/mpu.h>
25
26struct ext_slave_descr *mpu6050_get_slave_descr(void);
27
28#endif