add new mpu3050 driver support from manufacturing company
[firefly-linux-kernel-4.4.55.git] / drivers / misc / inv_mpu / compass / hscdtd002b.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 COMPASSDL
22  *
23  *  @{
24  *      @file   hscdtd002b.c
25  *      @brief  Magnetometer setup and handling methods for Alps HSCDTD002B
26  *              compass.
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-compass"
46
47 /* -------------------------------------------------------------------------- */
48 #define COMPASS_HSCDTD002B_STAT          (0x18)
49 #define COMPASS_HSCDTD002B_CTRL1         (0x1B)
50 #define COMPASS_HSCDTD002B_CTRL2         (0x1C)
51 #define COMPASS_HSCDTD002B_CTRL3         (0x1D)
52 #define COMPASS_HSCDTD002B_DATAX         (0x10)
53
54 /* -------------------------------------------------------------------------- */
55 static int hscdtd002b_suspend(void *mlsl_handle,
56                               struct ext_slave_descr *slave,
57                               struct ext_slave_platform_data *pdata)
58 {
59         int result = INV_SUCCESS;
60
61         /* Power mode: stand-by */
62         result =
63             inv_serial_single_write(mlsl_handle, pdata->address,
64                                     COMPASS_HSCDTD002B_CTRL1, 0x00);
65         if (result) {
66                 LOG_RESULT_LOCATION(result);
67                 return result;
68         }
69         msleep(1);              /* turn-off time */
70
71         return result;
72 }
73
74 static int hscdtd002b_resume(void *mlsl_handle,
75                              struct ext_slave_descr *slave,
76                              struct ext_slave_platform_data *pdata)
77 {
78         int result = INV_SUCCESS;
79
80         /* Soft reset */
81         result =
82             inv_serial_single_write(mlsl_handle, pdata->address,
83                                     COMPASS_HSCDTD002B_CTRL3, 0x80);
84         if (result) {
85                 LOG_RESULT_LOCATION(result);
86                 return result;
87         }
88         /* Force state; Power mode: active */
89         result =
90             inv_serial_single_write(mlsl_handle, pdata->address,
91                                     COMPASS_HSCDTD002B_CTRL1, 0x82);
92         if (result) {
93                 LOG_RESULT_LOCATION(result);
94                 return result;
95         }
96         /* Data ready enable */
97         result =
98             inv_serial_single_write(mlsl_handle, pdata->address,
99                                     COMPASS_HSCDTD002B_CTRL2, 0x08);
100         if (result) {
101                 LOG_RESULT_LOCATION(result);
102                 return result;
103         }
104         msleep(1);              /* turn-on time */
105
106         return result;
107 }
108
109 static int hscdtd002b_read(void *mlsl_handle,
110                            struct ext_slave_descr *slave,
111                            struct ext_slave_platform_data *pdata,
112                            unsigned char *data)
113 {
114         unsigned char stat;
115         int result = INV_SUCCESS;
116         int status = INV_SUCCESS;
117
118         /* Read status reg. to check if data is ready */
119         result =
120             inv_serial_read(mlsl_handle, pdata->address,
121                             COMPASS_HSCDTD002B_STAT, 1, &stat);
122         if (result) {
123                 LOG_RESULT_LOCATION(result);
124                 return result;
125         }
126         if (stat & 0x40) {
127                 result =
128                     inv_serial_read(mlsl_handle, pdata->address,
129                                     COMPASS_HSCDTD002B_DATAX, 6,
130                                     (unsigned char *)data);
131                 if (result) {
132                         LOG_RESULT_LOCATION(result);
133                         return result;
134                 }
135                 status = INV_SUCCESS;
136         } else if (stat & 0x20) {
137                 status = INV_ERROR_COMPASS_DATA_OVERFLOW;
138         } else {
139                 status = INV_ERROR_COMPASS_DATA_NOT_READY;
140         }
141         /* trigger next measurement read */
142         result =
143             inv_serial_single_write(mlsl_handle, pdata->address,
144                                     COMPASS_HSCDTD002B_CTRL3, 0x40);
145         if (result) {
146                 LOG_RESULT_LOCATION(result);
147                 return result;
148         }
149
150         return status;
151 }
152
153 static struct ext_slave_descr hscdtd002b_descr = {
154         .init             = NULL,
155         .exit             = NULL,
156         .suspend          = hscdtd002b_suspend,
157         .resume           = hscdtd002b_resume,
158         .read             = hscdtd002b_read,
159         .config           = NULL,
160         .get_config       = NULL,
161         .name             = "hscdtd002b",
162         .type             = EXT_SLAVE_TYPE_COMPASS,
163         .id               = COMPASS_ID_HSCDTD002B,
164         .read_reg         = 0x10,
165         .read_len         = 6,
166         .endian           = EXT_SLAVE_LITTLE_ENDIAN,
167         .range            = {9830, 4000},
168         .trigger          = NULL,
169 };
170
171 static
172 struct ext_slave_descr *hscdtd002b_get_slave_descr(void)
173 {
174         return &hscdtd002b_descr;
175 }
176
177 /* -------------------------------------------------------------------------- */
178 struct hscdtd002b_mod_private_data {
179         struct i2c_client *client;
180         struct ext_slave_platform_data *pdata;
181 };
182
183 static unsigned short normal_i2c[] = { I2C_CLIENT_END };
184
185 static int hscdtd002b_mod_probe(struct i2c_client *client,
186                            const struct i2c_device_id *devid)
187 {
188         struct ext_slave_platform_data *pdata;
189         struct hscdtd002b_mod_private_data *private_data;
190         int result = 0;
191
192         dev_info(&client->adapter->dev, "%s: %s\n", __func__, devid->name);
193
194         if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
195                 result = -ENODEV;
196                 goto out_no_free;
197         }
198
199         pdata = client->dev.platform_data;
200         if (!pdata) {
201                 dev_err(&client->adapter->dev,
202                         "Missing platform data for slave %s\n", devid->name);
203                 result = -EFAULT;
204                 goto out_no_free;
205         }
206
207         private_data = kzalloc(sizeof(*private_data), GFP_KERNEL);
208         if (!private_data) {
209                 result = -ENOMEM;
210                 goto out_no_free;
211         }
212
213         i2c_set_clientdata(client, private_data);
214         private_data->client = client;
215         private_data->pdata = pdata;
216
217         result = inv_mpu_register_slave(THIS_MODULE, client, pdata,
218                                         hscdtd002b_get_slave_descr);
219         if (result) {
220                 dev_err(&client->adapter->dev,
221                         "Slave registration failed: %s, %d\n",
222                         devid->name, result);
223                 goto out_free_memory;
224         }
225
226         return result;
227
228 out_free_memory:
229         kfree(private_data);
230 out_no_free:
231         dev_err(&client->adapter->dev, "%s failed %d\n", __func__, result);
232         return result;
233
234 }
235
236 static int hscdtd002b_mod_remove(struct i2c_client *client)
237 {
238         struct hscdtd002b_mod_private_data *private_data =
239                 i2c_get_clientdata(client);
240
241         dev_dbg(&client->adapter->dev, "%s\n", __func__);
242
243         inv_mpu_unregister_slave(client, private_data->pdata,
244                                 hscdtd002b_get_slave_descr);
245
246         kfree(private_data);
247         return 0;
248 }
249
250 static const struct i2c_device_id hscdtd002b_mod_id[] = {
251         { "hscdtd002b", COMPASS_ID_HSCDTD002B },
252         {}
253 };
254
255 MODULE_DEVICE_TABLE(i2c, hscdtd002b_mod_id);
256
257 static struct i2c_driver hscdtd002b_mod_driver = {
258         .class = I2C_CLASS_HWMON,
259         .probe = hscdtd002b_mod_probe,
260         .remove = hscdtd002b_mod_remove,
261         .id_table = hscdtd002b_mod_id,
262         .driver = {
263                    .owner = THIS_MODULE,
264                    .name = "hscdtd002b_mod",
265                    },
266         .address_list = normal_i2c,
267 };
268
269 static int __init hscdtd002b_mod_init(void)
270 {
271         int res = i2c_add_driver(&hscdtd002b_mod_driver);
272         pr_info("%s: Probe name %s\n", __func__, "hscdtd002b_mod");
273         if (res)
274                 pr_err("%s failed\n", __func__);
275         return res;
276 }
277
278 static void __exit hscdtd002b_mod_exit(void)
279 {
280         pr_info("%s\n", __func__);
281         i2c_del_driver(&hscdtd002b_mod_driver);
282 }
283
284 module_init(hscdtd002b_mod_init);
285 module_exit(hscdtd002b_mod_exit);
286
287 MODULE_AUTHOR("Invensense Corporation");
288 MODULE_DESCRIPTION("Driver to integrate HSCDTD002B sensor with the MPU");
289 MODULE_LICENSE("GPL");
290 MODULE_ALIAS("hscdtd002b_mod");
291
292 /**
293  *  @}
294  */