aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/misc/inv_mpu/accel/kxsd9.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/kxsd9.c
parent8dea78da5cee153b8af9c07a2745f6c55057fe12 (diff)
Added missing tegra files.HEADmaster
Diffstat (limited to 'drivers/misc/inv_mpu/accel/kxsd9.c')
-rw-r--r--drivers/misc/inv_mpu/accel/kxsd9.c264
1 files changed, 264 insertions, 0 deletions
diff --git a/drivers/misc/inv_mpu/accel/kxsd9.c b/drivers/misc/inv_mpu/accel/kxsd9.c
new file mode 100644
index 00000000000..5cb4eaf6b4a
--- /dev/null
+++ b/drivers/misc/inv_mpu/accel/kxsd9.c
@@ -0,0 +1,264 @@
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 Accelerometer setup and handling methods for Kionix KXSD9.
23 *
24 * @{
25 * @file kxsd9.c
26 * @brief Accelerometer setup and handling methods for Kionix KXSD9.
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-acc"
46
47/* -------------------------------------------------------------------------- */
48
49static int kxsd9_suspend(void *mlsl_handle,
50 struct ext_slave_descr *slave,
51 struct ext_slave_platform_data *pdata)
52{
53 int result;
54 /* CTRL_REGB: low-power standby mode */
55 result =
56 inv_serial_single_write(mlsl_handle, pdata->address, 0x0d, 0x0);
57 if (result) {
58 LOG_RESULT_LOCATION(result);
59 return result;
60 }
61 return result;
62}
63
64/* full scale setting - register and mask */
65#define ACCEL_KIONIX_CTRL_REG (0x0C)
66#define ACCEL_KIONIX_CTRL_MASK (0x3)
67
68static int kxsd9_resume(void *mlsl_handle,
69 struct ext_slave_descr *slave,
70 struct ext_slave_platform_data *pdata)
71{
72 int result = INV_SUCCESS;
73 unsigned char reg;
74
75 /* Full Scale */
76 reg = 0x0;
77 reg &= ~ACCEL_KIONIX_CTRL_MASK;
78 reg |= 0x00;
79 if (slave->range.mantissa == 4) { /* 4g scale = 4.9951 */
80 reg |= 0x2;
81 slave->range.fraction = 9951;
82 } else if (slave->range.mantissa == 7) { /* 6g scale = 7.5018 */
83 reg |= 0x1;
84 slave->range.fraction = 5018;
85 } else if (slave->range.mantissa == 9) { /* 8g scale = 9.9902 */
86 reg |= 0x0;
87 slave->range.fraction = 9902;
88 } else {
89 slave->range.mantissa = 2; /* 2g scale = 2.5006 */
90 slave->range.fraction = 5006;
91 reg |= 0x3;
92 }
93 reg |= 0xC0; /* 100Hz LPF */
94 result =
95 inv_serial_single_write(mlsl_handle, pdata->address,
96 ACCEL_KIONIX_CTRL_REG, reg);
97 if (result) {
98 LOG_RESULT_LOCATION(result);
99 return result;
100 }
101 /* normal operation */
102 result =
103 inv_serial_single_write(mlsl_handle, pdata->address, 0x0d, 0x40);
104 if (result) {
105 LOG_RESULT_LOCATION(result);
106 return result;
107 }
108
109 return INV_SUCCESS;
110}
111
112static int kxsd9_read(void *mlsl_handle,
113 struct ext_slave_descr *slave,
114 struct ext_slave_platform_data *pdata,
115 unsigned char *data)
116{
117 int result;
118 result = inv_serial_read(mlsl_handle, pdata->address,
119 slave->read_reg, slave->read_len, data);
120 return result;
121}
122
123static struct ext_slave_descr kxsd9_descr = {
124 .init = NULL,
125 .exit = NULL,
126 .suspend = kxsd9_suspend,
127 .resume = kxsd9_resume,
128 .read = kxsd9_read,
129 .config = NULL,
130 .get_config = NULL,
131 .name = "kxsd9",
132 .type = EXT_SLAVE_TYPE_ACCEL,
133 .id = ACCEL_ID_KXSD9,
134 .read_reg = 0x00,
135 .read_len = 6,
136 .endian = EXT_SLAVE_BIG_ENDIAN,
137 .range = {2, 5006},
138 .trigger = NULL,
139};
140
141static
142struct ext_slave_descr *kxsd9_get_slave_descr(void)
143{
144 return &kxsd9_descr;
145}
146
147/* -------------------------------------------------------------------------- */
148struct kxsd9_mod_private_data {
149 struct i2c_client *client;
150 struct ext_slave_platform_data *pdata;
151};
152
153static unsigned short normal_i2c[] = { I2C_CLIENT_END };
154
155static int kxsd9_mod_probe(struct i2c_client *client,
156 const struct i2c_device_id *devid)
157{
158 struct ext_slave_platform_data *pdata;
159 struct kxsd9_mod_private_data *private_data;
160 int result = 0;
161
162 dev_info(&client->adapter->dev, "%s: %s\n", __func__, devid->name);
163
164 if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
165 result = -ENODEV;
166 goto out_no_free;
167 }
168
169 pdata = client->dev.platform_data;
170 if (!pdata) {
171 dev_err(&client->adapter->dev,
172 "Missing platform data for slave %s\n", devid->name);
173 result = -EFAULT;
174 goto out_no_free;
175 }
176
177 private_data = kzalloc(sizeof(*private_data), GFP_KERNEL);
178 if (!private_data) {
179 result = -ENOMEM;
180 goto out_no_free;
181 }
182
183 i2c_set_clientdata(client, private_data);
184 private_data->client = client;
185 private_data->pdata = pdata;
186
187 result = inv_mpu_register_slave(THIS_MODULE, client, pdata,
188 kxsd9_get_slave_descr);
189 if (result) {
190 dev_err(&client->adapter->dev,
191 "Slave registration failed: %s, %d\n",
192 devid->name, result);
193 goto out_free_memory;
194 }
195
196 return result;
197
198out_free_memory:
199 kfree(private_data);
200out_no_free:
201 dev_err(&client->adapter->dev, "%s failed %d\n", __func__, result);
202 return result;
203
204}
205
206static int kxsd9_mod_remove(struct i2c_client *client)
207{
208 struct kxsd9_mod_private_data *private_data =
209 i2c_get_clientdata(client);
210
211 dev_dbg(&client->adapter->dev, "%s\n", __func__);
212
213 inv_mpu_unregister_slave(client, private_data->pdata,
214 kxsd9_get_slave_descr);
215
216 kfree(private_data);
217 return 0;
218}
219
220static const struct i2c_device_id kxsd9_mod_id[] = {
221 { "kxsd9", ACCEL_ID_KXSD9 },
222 {}
223};
224
225MODULE_DEVICE_TABLE(i2c, kxsd9_mod_id);
226
227static struct i2c_driver kxsd9_mod_driver = {
228 .class = I2C_CLASS_HWMON,
229 .probe = kxsd9_mod_probe,
230 .remove = kxsd9_mod_remove,
231 .id_table = kxsd9_mod_id,
232 .driver = {
233 .owner = THIS_MODULE,
234 .name = "kxsd9_mod",
235 },
236 .address_list = normal_i2c,
237};
238
239static int __init kxsd9_mod_init(void)
240{
241 int res = i2c_add_driver(&kxsd9_mod_driver);
242 pr_info("%s: Probe name %s\n", __func__, "kxsd9_mod");
243 if (res)
244 pr_err("%s failed\n", __func__);
245 return res;
246}
247
248static void __exit kxsd9_mod_exit(void)
249{
250 pr_info("%s\n", __func__);
251 i2c_del_driver(&kxsd9_mod_driver);
252}
253
254module_init(kxsd9_mod_init);
255module_exit(kxsd9_mod_exit);
256
257MODULE_AUTHOR("Invensense Corporation");
258MODULE_DESCRIPTION("Driver to integrate KXSD9 sensor with the MPU");
259MODULE_LICENSE("GPL");
260MODULE_ALIAS("kxsd9_mod");
261
262/**
263 * @}
264 */