ARM: tegra12: loki: Fix regulator warnings
[linux-3.10.git] / drivers / misc / mpu3050 / compass / ak8975.c
1 /*
2  $License:
3     Copyright (C) 2010 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  *  @defgroup   COMPASSDL (Motion Library - Accelerometer Driver Layer)
22  *  @brief      Provides the interface to setup and handle an accelerometers
23  *              connected to the secondary I2C interface of the gyroscope.
24  *
25  *  @{
26  *      @file   AK8975.c
27  *      @brief  Magnetometer setup and handling methods for AKM 8975 compass.
28  */
29
30 /* ------------------ */
31 /* - Include Files. - */
32 /* ------------------ */
33
34 #include <string.h>
35
36 #ifdef __KERNEL__
37 #include <linux/module.h>
38 #endif
39
40 #include "mpu.h"
41 #include "mlsl.h"
42 #include "mlos.h"
43
44 #include <log.h>
45 #undef MPL_LOG_TAG
46 #define MPL_LOG_TAG "MPL-compass"
47
48
49 #define AK8975_REG_ST1  (0x02)
50 #define AK8975_REG_HXL  (0x03)
51 #define AK8975_REG_ST2  (0x09)
52
53 #define AK8975_REG_CNTL (0x0A)
54
55 #define AK8975_CNTL_MODE_POWER_DOWN         (0x00)
56 #define AK8975_CNTL_MODE_SINGLE_MEASUREMENT (0x01)
57
58 int ak8975_suspend(void *mlsl_handle,
59                    struct ext_slave_descr *slave,
60                    struct ext_slave_platform_data *pdata)
61 {
62         int result = ML_SUCCESS;
63         result =
64             MLSLSerialWriteSingle(mlsl_handle, pdata->address,
65                                   AK8975_REG_CNTL,
66                                   AK8975_CNTL_MODE_POWER_DOWN);
67         MLOSSleep(1);           /* wait at least 100us */
68         ERROR_CHECK(result);
69         return result;
70 }
71
72 int ak8975_resume(void *mlsl_handle,
73                   struct ext_slave_descr *slave,
74                   struct ext_slave_platform_data *pdata)
75 {
76         int result = ML_SUCCESS;
77         result =
78             MLSLSerialWriteSingle(mlsl_handle, pdata->address,
79                                   AK8975_REG_CNTL,
80                                   AK8975_CNTL_MODE_SINGLE_MEASUREMENT);
81         ERROR_CHECK(result);
82         return result;
83 }
84
85 int ak8975_read(void *mlsl_handle,
86                 struct ext_slave_descr *slave,
87                 struct ext_slave_platform_data *pdata, unsigned char *data)
88 {
89         unsigned char regs[8];
90         unsigned char *stat = &regs[0];
91         unsigned char *stat2 = &regs[7];
92         int result = ML_SUCCESS;
93         int status = ML_SUCCESS;
94
95         result =
96             MLSLSerialRead(mlsl_handle, pdata->address, AK8975_REG_ST1,
97                            8, regs);
98         ERROR_CHECK(result);
99
100         /*
101          * ST : data ready -
102          * Measurement has been completed and data is ready to be read.
103          */
104         if (*stat & 0x01) {
105                 memcpy(data, &regs[1], 6);
106                 status = ML_SUCCESS;
107         }
108
109         /*
110          * ST2 : data error -
111          * occurs when data read is started outside of a readable period;
112          * data read would not be correct.
113          * Valid in continuous measurement mode only.
114          * In single measurement mode this error should not occour but we
115          * stil account for it and return an error, since the data would be
116          * corrupted.
117          * DERR bit is self-clearing when ST2 register is read.
118          */
119         if (*stat2 & 0x04)
120                 status = ML_ERROR_COMPASS_DATA_ERROR;
121         /*
122          * ST2 : overflow -
123          * the sum of the absolute values of all axis |X|+|Y|+|Z| < 2400uT.
124          * This is likely to happen in presence of an external magnetic
125          * disturbance; it indicates, the sensor data is incorrect and should
126          * be ignored.
127          * An error is returned.
128          * HOFL bit clears when a new measurement starts.
129          */
130         if (*stat2 & 0x08)
131                 status = ML_ERROR_COMPASS_DATA_OVERFLOW;
132         /*
133          * ST : overrun -
134          * the previous sample was not fetched and lost.
135          * Valid in continuous measurement mode only.
136          * In single measurement mode this error should not occour and we
137          * don't consider this condition an error.
138          * DOR bit is self-clearing when ST2 or any meas. data register is
139          * read.
140          */
141         if (*stat & 0x02) {
142                 /* status = ML_ERROR_COMPASS_DATA_UNDERFLOW; */
143                 status = ML_SUCCESS;
144         }
145
146         /*
147          * trigger next measurement if:
148          *    - stat is non zero;
149          *    - if stat is zero and stat2 is non zero.
150          * Won't trigger if data is not ready and there was no error.
151          */
152         if (*stat != 0x00 || *stat2 != 0x00) {
153                 result =
154                     MLSLSerialWriteSingle(mlsl_handle, pdata->address,
155                                           AK8975_REG_CNTL,
156                                           AK8975_CNTL_MODE_SINGLE_MEASUREMENT);
157                 ERROR_CHECK(result);
158         }
159
160         return status;
161 }
162
163 static int ak8975_config(void *mlsl_handle,
164                         struct ext_slave_descr *slave,
165                         struct ext_slave_platform_data *pdata,
166                         struct ext_slave_config *data)
167 {
168         int result;
169         if (!data->data)
170                 return ML_ERROR_INVALID_PARAMETER;
171
172         switch (data->key) {
173         case MPU_SLAVE_WRITE_REGISTERS:
174                 result = MLSLSerialWrite(mlsl_handle, pdata->address,
175                                         data->len,
176                                         (unsigned char *)data->data);
177                 ERROR_CHECK(result);
178                 break;
179         case MPU_SLAVE_CONFIG_ODR_SUSPEND:
180         case MPU_SLAVE_CONFIG_ODR_RESUME:
181         case MPU_SLAVE_CONFIG_FSR_SUSPEND:
182         case MPU_SLAVE_CONFIG_FSR_RESUME:
183         case MPU_SLAVE_CONFIG_MOT_THS:
184         case MPU_SLAVE_CONFIG_NMOT_THS:
185         case MPU_SLAVE_CONFIG_MOT_DUR:
186         case MPU_SLAVE_CONFIG_NMOT_DUR:
187         case MPU_SLAVE_CONFIG_IRQ_SUSPEND:
188         case MPU_SLAVE_CONFIG_IRQ_RESUME:
189         default:
190                 return ML_ERROR_FEATURE_NOT_IMPLEMENTED;
191         };
192
193         return ML_SUCCESS;
194 }
195
196 static int ak8975_get_config(void *mlsl_handle,
197                                 struct ext_slave_descr *slave,
198                                 struct ext_slave_platform_data *pdata,
199                                 struct ext_slave_config *data)
200 {
201         int result;
202         if (!data->data)
203                 return ML_ERROR_INVALID_PARAMETER;
204
205         switch (data->key) {
206         case MPU_SLAVE_READ_REGISTERS:
207         {
208                 unsigned char *serial_data = (unsigned char *)data->data;
209                 result = MLSLSerialRead(mlsl_handle, pdata->address,
210                                         serial_data[0],
211                                         data->len - 1,
212                                         &serial_data[1]);
213                 ERROR_CHECK(result);
214                 break;
215         }
216         case MPU_SLAVE_CONFIG_ODR_SUSPEND:
217         case MPU_SLAVE_CONFIG_ODR_RESUME:
218         case MPU_SLAVE_CONFIG_FSR_SUSPEND:
219         case MPU_SLAVE_CONFIG_FSR_RESUME:
220         case MPU_SLAVE_CONFIG_MOT_THS:
221         case MPU_SLAVE_CONFIG_NMOT_THS:
222         case MPU_SLAVE_CONFIG_MOT_DUR:
223         case MPU_SLAVE_CONFIG_NMOT_DUR:
224         case MPU_SLAVE_CONFIG_IRQ_SUSPEND:
225         case MPU_SLAVE_CONFIG_IRQ_RESUME:
226         default:
227                 return ML_ERROR_FEATURE_NOT_IMPLEMENTED;
228         };
229
230         return ML_SUCCESS;
231 }
232
233 struct ext_slave_descr ak8975_descr = {
234         /*.init             = */ NULL,
235         /*.exit             = */ NULL,
236         /*.suspend          = */ ak8975_suspend,
237         /*.resume           = */ ak8975_resume,
238         /*.read             = */ ak8975_read,
239         /*.config           = */ ak8975_config,
240         /*.get_config       = */ ak8975_get_config,
241         /*.name             = */ "ak8975",
242         /*.type             = */ EXT_SLAVE_TYPE_COMPASS,
243         /*.id               = */ COMPASS_ID_AKM,
244         /*.reg              = */ 0x01,
245         /*.len              = */ 9,
246         /*.endian           = */ EXT_SLAVE_LITTLE_ENDIAN,
247         /*.range            = */ {9830, 4000}
248 };
249
250 struct ext_slave_descr *ak8975_get_slave_descr(void)
251 {
252         return &ak8975_descr;
253 }
254 EXPORT_SYMBOL(ak8975_get_slave_descr);
255
256 /**
257  *  @}
258  */