aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/misc/inv_mpu/compass/hscdtd004a.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/compass/hscdtd004a.c
parent8dea78da5cee153b8af9c07a2745f6c55057fe12 (diff)
Added missing tegra files.HEADmaster
Diffstat (limited to 'drivers/misc/inv_mpu/compass/hscdtd004a.c')
-rw-r--r--drivers/misc/inv_mpu/compass/hscdtd004a.c318
1 files changed, 318 insertions, 0 deletions
diff --git a/drivers/misc/inv_mpu/compass/hscdtd004a.c b/drivers/misc/inv_mpu/compass/hscdtd004a.c
new file mode 100644
index 00000000000..f0915599bd2
--- /dev/null
+++ b/drivers/misc/inv_mpu/compass/hscdtd004a.c
@@ -0,0 +1,318 @@
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 hscdtd004a.c
25 * @brief Magnetometer setup and handling methods for Alps HSCDTD004A
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_HSCDTD004A_STAT (0x18)
49#define COMPASS_HSCDTD004A_CTRL1 (0x1B)
50#define COMPASS_HSCDTD004A_CTRL2 (0x1C)
51#define COMPASS_HSCDTD004A_CTRL3 (0x1D)
52#define COMPASS_HSCDTD004A_DATAX (0x10)
53
54/* -------------------------------------------------------------------------- */
55
56static int hscdtd004a_suspend(void *mlsl_handle,
57 struct ext_slave_descr *slave,
58 struct ext_slave_platform_data *pdata)
59{
60 int result = INV_SUCCESS;
61
62 /* Power mode: stand-by */
63 result =
64 inv_serial_single_write(mlsl_handle, pdata->address,
65 COMPASS_HSCDTD004A_CTRL1, 0x00);
66 if (result) {
67 LOG_RESULT_LOCATION(result);
68 return result;
69 }
70 msleep(1); /* turn-off time */
71
72 return result;
73}
74
75static int hscdtd004a_init(void *mlsl_handle,
76 struct ext_slave_descr *slave,
77 struct ext_slave_platform_data *pdata)
78{
79 int result;
80 unsigned char data1, data2[2];
81
82 result = inv_serial_read(mlsl_handle, pdata->address, 0xf, 1, &data1);
83 if (result) {
84 LOG_RESULT_LOCATION(result);
85 return result;
86 }
87 result = inv_serial_read(mlsl_handle, pdata->address, 0xd, 2, data2);
88 if (result) {
89 LOG_RESULT_LOCATION(result);
90 return result;
91 }
92 if (data1 != 0x49 || data2[0] != 0x45 || data2[1] != 0x54) {
93 LOG_RESULT_LOCATION(INV_ERROR_SERIAL_DEVICE_NOT_RECOGNIZED);
94 return INV_ERROR_SERIAL_DEVICE_NOT_RECOGNIZED;
95 }
96 return result;
97}
98
99static int hscdtd004a_resume(void *mlsl_handle,
100 struct ext_slave_descr *slave,
101 struct ext_slave_platform_data *pdata)
102{
103 int result = INV_SUCCESS;
104
105 /* Soft reset */
106 result =
107 inv_serial_single_write(mlsl_handle, pdata->address,
108 COMPASS_HSCDTD004A_CTRL3, 0x80);
109 if (result) {
110 LOG_RESULT_LOCATION(result);
111 return result;
112 }
113 /* Normal state; Power mode: active */
114 result =
115 inv_serial_single_write(mlsl_handle, pdata->address,
116 COMPASS_HSCDTD004A_CTRL1, 0x82);
117 if (result) {
118 LOG_RESULT_LOCATION(result);
119 return result;
120 }
121 /* Data ready enable */
122 result =
123 inv_serial_single_write(mlsl_handle, pdata->address,
124 COMPASS_HSCDTD004A_CTRL2, 0x7C);
125 if (result) {
126 LOG_RESULT_LOCATION(result);
127 return result;
128 }
129 msleep(1); /* turn-on time */
130 return result;
131}
132
133static int hscdtd004a_read(void *mlsl_handle,
134 struct ext_slave_descr *slave,
135 struct ext_slave_platform_data *pdata,
136 unsigned char *data)
137{
138 unsigned char stat;
139 int result = INV_SUCCESS;
140 int status = INV_SUCCESS;
141
142 /* Read status reg. to check if data is ready */
143 result =
144 inv_serial_read(mlsl_handle, pdata->address,
145 COMPASS_HSCDTD004A_STAT, 1, &stat);
146 if (result) {
147 LOG_RESULT_LOCATION(result);
148 return result;
149 }
150 if (stat & 0x48) {
151 result =
152 inv_serial_read(mlsl_handle, pdata->address,
153 COMPASS_HSCDTD004A_DATAX, 6,
154 (unsigned char *)data);
155 if (result) {
156 LOG_RESULT_LOCATION(result);
157 return result;
158 }
159 status = INV_SUCCESS;
160 } else if (stat & 0x68) {
161 status = INV_ERROR_COMPASS_DATA_OVERFLOW;
162 } else {
163 status = INV_ERROR_COMPASS_DATA_NOT_READY;
164 }
165 /* trigger next measurement read */
166 result =
167 inv_serial_single_write(mlsl_handle, pdata->address,
168 COMPASS_HSCDTD004A_CTRL3, 0x40);
169 if (result) {
170 LOG_RESULT_LOCATION(result);
171 return result;
172 }
173 return status;
174
175}
176
177static struct ext_slave_descr hscdtd004a_descr = {
178 .init = hscdtd004a_init,
179 .exit = NULL,
180 .suspend = hscdtd004a_suspend,
181 .resume = hscdtd004a_resume,
182 .read = hscdtd004a_read,
183 .config = NULL,
184 .get_config = NULL,
185 .name = "hscdtd004a",
186 .type = EXT_SLAVE_TYPE_COMPASS,
187 .id = COMPASS_ID_HSCDTD004A,
188 .read_reg = 0x10,
189 .read_len = 6,
190 .endian = EXT_SLAVE_LITTLE_ENDIAN,
191 .range = {9830, 4000},
192 .trigger = NULL,
193};
194
195static
196struct ext_slave_descr *hscdtd004a_get_slave_descr(void)
197{
198 return &hscdtd004a_descr;
199}
200
201/* -------------------------------------------------------------------------- */
202struct hscdtd004a_mod_private_data {
203 struct i2c_client *client;
204 struct ext_slave_platform_data *pdata;
205};
206
207static unsigned short normal_i2c[] = { I2C_CLIENT_END };
208
209static int hscdtd004a_mod_probe(struct i2c_client *client,
210 const struct i2c_device_id *devid)
211{
212 struct ext_slave_platform_data *pdata;
213 struct hscdtd004a_mod_private_data *private_data;
214 int result = 0;
215
216 dev_info(&client->adapter->dev, "%s: %s\n", __func__, devid->name);
217
218 if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
219 result = -ENODEV;
220 goto out_no_free;
221 }
222
223 pdata = client->dev.platform_data;
224 if (!pdata) {
225 dev_err(&client->adapter->dev,
226 "Missing platform data for slave %s\n", devid->name);
227 result = -EFAULT;
228 goto out_no_free;
229 }
230
231 private_data = kzalloc(sizeof(*private_data), GFP_KERNEL);
232 if (!private_data) {
233 result = -ENOMEM;
234 goto out_no_free;
235 }
236
237 i2c_set_clientdata(client, private_data);
238 private_data->client = client;
239 private_data->pdata = pdata;
240
241 result = inv_mpu_register_slave(THIS_MODULE, client, pdata,
242 hscdtd004a_get_slave_descr);
243 if (result) {
244 dev_err(&client->adapter->dev,
245 "Slave registration failed: %s, %d\n",
246 devid->name, result);
247 goto out_free_memory;
248 }
249
250 return result;
251
252out_free_memory:
253 kfree(private_data);
254out_no_free:
255 dev_err(&client->adapter->dev, "%s failed %d\n", __func__, result);
256 return result;
257
258}
259
260static int hscdtd004a_mod_remove(struct i2c_client *client)
261{
262 struct hscdtd004a_mod_private_data *private_data =
263 i2c_get_clientdata(client);
264
265 dev_dbg(&client->adapter->dev, "%s\n", __func__);
266
267 inv_mpu_unregister_slave(client, private_data->pdata,
268 hscdtd004a_get_slave_descr);
269
270 kfree(private_data);
271 return 0;
272}
273
274static const struct i2c_device_id hscdtd004a_mod_id[] = {
275 { "hscdtd004a", COMPASS_ID_HSCDTD004A },
276 {}
277};
278
279MODULE_DEVICE_TABLE(i2c, hscdtd004a_mod_id);
280
281static struct i2c_driver hscdtd004a_mod_driver = {
282 .class = I2C_CLASS_HWMON,
283 .probe = hscdtd004a_mod_probe,
284 .remove = hscdtd004a_mod_remove,
285 .id_table = hscdtd004a_mod_id,
286 .driver = {
287 .owner = THIS_MODULE,
288 .name = "hscdtd004a_mod",
289 },
290 .address_list = normal_i2c,
291};
292
293static int __init hscdtd004a_mod_init(void)
294{
295 int res = i2c_add_driver(&hscdtd004a_mod_driver);
296 pr_info("%s: Probe name %s\n", __func__, "hscdtd004a_mod");
297 if (res)
298 pr_err("%s failed\n", __func__);
299 return res;
300}
301
302static void __exit hscdtd004a_mod_exit(void)
303{
304 pr_info("%s\n", __func__);
305 i2c_del_driver(&hscdtd004a_mod_driver);
306}
307
308module_init(hscdtd004a_mod_init);
309module_exit(hscdtd004a_mod_exit);
310
311MODULE_AUTHOR("Invensense Corporation");
312MODULE_DESCRIPTION("Driver to integrate HSCDTD004A sensor with the MPU");
313MODULE_LICENSE("GPL");
314MODULE_ALIAS("hscdtd004a_mod");
315
316/**
317 * @}
318 */