ARM: tegra12: loki: Fix regulator warnings
[linux-3.10.git] / drivers / misc / inv_mpu / accel / bma222.c
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
64 struct bma222_config {
65         unsigned int odr;               /** < output data rate in mHz */
66         unsigned int fsr;               /** < full scale range mg */
67 };
68
69 struct 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  */
94 static 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  */
158 static 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  */
209 static 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  */
278 static 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  */
301 static 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  */
352 static 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  */
404 static 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  */
449 static 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  */
496 static 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
512 static 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
530 static
531 struct ext_slave_descr *bma222_get_slave_descr(void)
532 {
533         return &bma222_descr;
534 }
535
536 /* -------------------------------------------------------------------------- */
537
538 struct bma222_mod_private_data {
539         struct i2c_client *client;
540         struct ext_slave_platform_data *pdata;
541 };
542
543 static unsigned short normal_i2c[] = { I2C_CLIENT_END };
544
545 static 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
588 out_free_memory:
589         kfree(private_data);
590 out_no_free:
591         dev_err(&client->adapter->dev, "%s failed %d\n", __func__, result);
592         return result;
593
594 }
595
596 static 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
610 static const struct i2c_device_id bma222_mod_id[] = {
611         { "bma222", ACCEL_ID_BMA222 },
612         {}
613 };
614
615 MODULE_DEVICE_TABLE(i2c, bma222_mod_id);
616
617 static 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
629 static 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
638 static void __exit bma222_mod_exit(void)
639 {
640         pr_info("%s\n", __func__);
641         i2c_del_driver(&bma222_mod_driver);
642 }
643
644 module_init(bma222_mod_init);
645 module_exit(bma222_mod_exit);
646
647 MODULE_AUTHOR("Invensense Corporation");
648 MODULE_DESCRIPTION("Driver to integrate BMA222 sensor with the MPU");
649 MODULE_LICENSE("GPL");
650 MODULE_ALIAS("bma222_mod");
651
652 /**
653  *  @}
654  */