aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/misc/inv_mpu/accel/bma222.c
diff options
context:
space:
mode:
authorJonathan Herman <hermanjl@cs.unc.edu>2013-01-22 10:38:37 -0500
committerJonathan Herman <hermanjl@cs.unc.edu>2013-01-22 10:38:37 -0500
commitfcc9d2e5a6c89d22b8b773a64fb4ad21ac318446 (patch)
treea57612d1888735a2ec7972891b68c1ac5ec8faea /drivers/misc/inv_mpu/accel/bma222.c
parent8dea78da5cee153b8af9c07a2745f6c55057fe12 (diff)
Added missing tegra files.HEADmaster
Diffstat (limited to 'drivers/misc/inv_mpu/accel/bma222.c')
-rw-r--r--drivers/misc/inv_mpu/accel/bma222.c654
1 files changed, 654 insertions, 0 deletions
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 */