aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/misc/inv_mpu/pressure
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/misc/inv_mpu/pressure')
-rw-r--r--drivers/misc/inv_mpu/pressure/Kconfig20
-rw-r--r--drivers/misc/inv_mpu/pressure/Makefile8
-rw-r--r--drivers/misc/inv_mpu/pressure/bma085.c367
3 files changed, 395 insertions, 0 deletions
diff --git a/drivers/misc/inv_mpu/pressure/Kconfig b/drivers/misc/inv_mpu/pressure/Kconfig
new file mode 100644
index 00000000000..f1c021e8f12
--- /dev/null
+++ b/drivers/misc/inv_mpu/pressure/Kconfig
@@ -0,0 +1,20 @@
1menuconfig: INV_SENSORS_PRESSURE
2 bool "Pressure Sensor Slaves"
3 depends on INV_SENSORS
4 default y
5 help
6 Select y to see a list of supported pressure sensors that can be
7 integrated with the MPUxxxx set of motion processors.
8
9if INV_SENSORS_PRESSURE
10
11config MPU_SENSORS_BMA085
12 tristate "Bosch BMA085"
13 help
14 This enables support for the Bosch bma085 pressure sensor
15 This support is for integration with the MPU3050 or MPU6050 gyroscope
16 device driver. Only one accelerometer can be registered at a time.
17 Specifying more that one accelerometer in the board file will result
18 in runtime errors.
19
20endif
diff --git a/drivers/misc/inv_mpu/pressure/Makefile b/drivers/misc/inv_mpu/pressure/Makefile
new file mode 100644
index 00000000000..595923d809d
--- /dev/null
+++ b/drivers/misc/inv_mpu/pressure/Makefile
@@ -0,0 +1,8 @@
1#
2# Pressure Slaves to MPUxxxx
3#
4obj-$(CONFIG_MPU_SENSORS_BMA085) += inv_mpu_bma085.o
5inv_mpu_bma085-objs += bma085.o
6
7EXTRA_CFLAGS += -Idrivers/misc/inv_mpu
8EXTRA_CFLAGS += -D__C99_DESIGNATED_INITIALIZER
diff --git a/drivers/misc/inv_mpu/pressure/bma085.c b/drivers/misc/inv_mpu/pressure/bma085.c
new file mode 100644
index 00000000000..696d2b6e183
--- /dev/null
+++ b/drivers/misc/inv_mpu/pressure/bma085.c
@@ -0,0 +1,367 @@
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 * @defgroup ACCELDL (Motion Library - Pressure Driver Layer)
22 * @brief Provides the interface to setup and handle a pressure
23 * connected to the secondary I2C interface of the gyroscope.
24 *
25 * @{
26 * @file bma085.c
27 * @brief Pressure setup and handling methods.
28 */
29
30/* ------------------ */
31/* - Include Files. - */
32/* ------------------ */
33
34#include <linux/i2c.h>
35#include <linux/module.h>
36#include <linux/moduleparam.h>
37#include <linux/kernel.h>
38#include <linux/errno.h>
39#include <linux/slab.h>
40#include <linux/delay.h>
41#include "mpu-dev.h"
42
43#include <linux/mpu.h>
44#include "mlsl.h"
45#include "log.h"
46
47/*
48 * this structure holds all device specific calibration parameters
49 */
50struct bmp085_calibration_param_t {
51 short ac1;
52 short ac2;
53 short ac3;
54 unsigned short ac4;
55 unsigned short ac5;
56 unsigned short ac6;
57 short b1;
58 short b2;
59 short mb;
60 short mc;
61 short md;
62 long param_b5;
63};
64
65struct bmp085_calibration_param_t cal_param;
66
67#define PRESSURE_BMA085_PARAM_MG 3038 /* calibration parameter */
68#define PRESSURE_BMA085_PARAM_MH -7357 /* calibration parameter */
69#define PRESSURE_BMA085_PARAM_MI 3791 /* calibration parameter */
70
71/*********************************************
72 * Pressure Initialization Functions
73 *********************************************/
74
75static int bma085_suspend(void *mlsl_handle,
76 struct ext_slave_descr *slave,
77 struct ext_slave_platform_data *pdata)
78{
79 int result = INV_SUCCESS;
80 return result;
81}
82
83#define PRESSURE_BMA085_PROM_START_ADDR (0xAA)
84#define PRESSURE_BMA085_PROM_DATA_LEN (22)
85#define PRESSURE_BMP085_CTRL_MEAS_REG (0xF4)
86/* temperature measurent */
87#define PRESSURE_BMP085_T_MEAS (0x2E)
88/* pressure measurement; oversampling_setting */
89#define PRESSURE_BMP085_P_MEAS_OSS_0 (0x34)
90#define PRESSURE_BMP085_P_MEAS_OSS_1 (0x74)
91#define PRESSURE_BMP085_P_MEAS_OSS_2 (0xB4)
92#define PRESSURE_BMP085_P_MEAS_OSS_3 (0xF4)
93#define PRESSURE_BMP085_ADC_OUT_MSB_REG (0xF6)
94#define PRESSURE_BMP085_ADC_OUT_LSB_REG (0xF7)
95
96static int bma085_resume(void *mlsl_handle,
97 struct ext_slave_descr *slave,
98 struct ext_slave_platform_data *pdata)
99{
100 int result;
101 unsigned char data[PRESSURE_BMA085_PROM_DATA_LEN];
102
103 result =
104 inv_serial_read(mlsl_handle, pdata->address,
105 PRESSURE_BMA085_PROM_START_ADDR,
106 PRESSURE_BMA085_PROM_DATA_LEN, data);
107 if (result) {
108 LOG_RESULT_LOCATION(result);
109 return result;
110 }
111
112 /* parameters AC1-AC6 */
113 cal_param.ac1 = (data[0] << 8) | data[1];
114 cal_param.ac2 = (data[2] << 8) | data[3];
115 cal_param.ac3 = (data[4] << 8) | data[5];
116 cal_param.ac4 = (data[6] << 8) | data[7];
117 cal_param.ac5 = (data[8] << 8) | data[9];
118 cal_param.ac6 = (data[10] << 8) | data[11];
119
120 /* parameters B1,B2 */
121 cal_param.b1 = (data[12] << 8) | data[13];
122 cal_param.b2 = (data[14] << 8) | data[15];
123
124 /* parameters MB,MC,MD */
125 cal_param.mb = (data[16] << 8) | data[17];
126 cal_param.mc = (data[18] << 8) | data[19];
127 cal_param.md = (data[20] << 8) | data[21];
128
129 return result;
130}
131
132static int bma085_read(void *mlsl_handle,
133 struct ext_slave_descr *slave,
134 struct ext_slave_platform_data *pdata,
135 unsigned char *data)
136{
137 int result;
138 long pressure, x1, x2, x3, b3, b6;
139 unsigned long b4, b7;
140 unsigned long up;
141 unsigned short ut;
142 short oversampling_setting = 0;
143 short temperature;
144 long divisor;
145
146 /* get temprature */
147 result = inv_serial_single_write(mlsl_handle, pdata->address,
148 PRESSURE_BMP085_CTRL_MEAS_REG,
149 PRESSURE_BMP085_T_MEAS);
150 msleep(5);
151 result =
152 inv_serial_read(mlsl_handle, pdata->address,
153 PRESSURE_BMP085_ADC_OUT_MSB_REG, 2,
154 (unsigned char *)data);
155 if (result) {
156 LOG_RESULT_LOCATION(result);
157 return result;
158 }
159 ut = (data[0] << 8) | data[1];
160
161 x1 = (((long) ut - (long)cal_param.ac6) * (long)cal_param.ac5) >> 15;
162 divisor = x1 + cal_param.md;
163 if (!divisor)
164 return INV_ERROR_DIVIDE_BY_ZERO;
165
166 x2 = ((long)cal_param.mc << 11) / (x1 + cal_param.md);
167 cal_param.param_b5 = x1 + x2;
168 /* temperature in 0.1 degree C */
169 temperature = (short)((cal_param.param_b5 + 8) >> 4);
170
171 /* get pressure */
172 result = inv_serial_single_write(mlsl_handle, pdata->address,
173 PRESSURE_BMP085_CTRL_MEAS_REG,
174 PRESSURE_BMP085_P_MEAS_OSS_0);
175 msleep(5);
176 result =
177 inv_serial_read(mlsl_handle, pdata->address,
178 PRESSURE_BMP085_ADC_OUT_MSB_REG, 2,
179 (unsigned char *)data);
180 if (result) {
181 LOG_RESULT_LOCATION(result);
182 return result;
183 }
184 up = (((unsigned long) data[0] << 8) | ((unsigned long) data[1]));
185
186 b6 = cal_param.param_b5 - 4000;
187 /* calculate B3 */
188 x1 = (b6*b6) >> 12;
189 x1 *= cal_param.b2;
190 x1 >>= 11;
191
192 x2 = (cal_param.ac2*b6);
193 x2 >>= 11;
194
195 x3 = x1 + x2;
196
197 b3 = (((((long)cal_param.ac1) * 4 + x3)
198 << oversampling_setting) + 2) >> 2;
199
200 /* calculate B4 */
201 x1 = (cal_param.ac3 * b6) >> 13;
202 x2 = (cal_param.b1 * ((b6*b6) >> 12)) >> 16;
203 x3 = ((x1 + x2) + 2) >> 2;
204 b4 = (cal_param.ac4 * (unsigned long) (x3 + 32768)) >> 15;
205 if (!b4)
206 return INV_ERROR;
207
208 b7 = ((unsigned long)(up - b3) * (50000>>oversampling_setting));
209 if (b7 < 0x80000000)
210 pressure = (b7 << 1) / b4;
211 else
212 pressure = (b7 / b4) << 1;
213
214 x1 = pressure >> 8;
215 x1 *= x1;
216 x1 = (x1 * PRESSURE_BMA085_PARAM_MG) >> 16;
217 x2 = (pressure * PRESSURE_BMA085_PARAM_MH) >> 16;
218 /* pressure in Pa */
219 pressure += (x1 + x2 + PRESSURE_BMA085_PARAM_MI) >> 4;
220
221 data[0] = (unsigned char)(pressure >> 16);
222 data[1] = (unsigned char)(pressure >> 8);
223 data[2] = (unsigned char)(pressure & 0xFF);
224
225 return result;
226}
227
228static struct ext_slave_descr bma085_descr = {
229 .init = NULL,
230 .exit = NULL,
231 .suspend = bma085_suspend,
232 .resume = bma085_resume,
233 .read = bma085_read,
234 .config = NULL,
235 .get_config = NULL,
236 .name = "bma085",
237 .type = EXT_SLAVE_TYPE_PRESSURE,
238 .id = PRESSURE_ID_BMA085,
239 .read_reg = 0xF6,
240 .read_len = 3,
241 .endian = EXT_SLAVE_BIG_ENDIAN,
242 .range = {0, 0},
243};
244
245static
246struct ext_slave_descr *bma085_get_slave_descr(void)
247{
248 return &bma085_descr;
249}
250
251/* Platform data for the MPU */
252struct bma085_mod_private_data {
253 struct i2c_client *client;
254 struct ext_slave_platform_data *pdata;
255};
256
257static unsigned short normal_i2c[] = { I2C_CLIENT_END };
258
259static int bma085_mod_probe(struct i2c_client *client,
260 const struct i2c_device_id *devid)
261{
262 struct ext_slave_platform_data *pdata;
263 struct bma085_mod_private_data *private_data;
264 int result = 0;
265
266 dev_info(&client->adapter->dev, "%s: %s\n", __func__, devid->name);
267
268 if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
269 result = -ENODEV;
270 goto out_no_free;
271 }
272
273 pdata = client->dev.platform_data;
274 if (!pdata) {
275 dev_err(&client->adapter->dev,
276 "Missing platform data for slave %s\n", devid->name);
277 result = -EFAULT;
278 goto out_no_free;
279 }
280
281 private_data = kzalloc(sizeof(*private_data), GFP_KERNEL);
282 if (!private_data) {
283 result = -ENOMEM;
284 goto out_no_free;
285 }
286
287 i2c_set_clientdata(client, private_data);
288 private_data->client = client;
289 private_data->pdata = pdata;
290
291 result = inv_mpu_register_slave(THIS_MODULE, client, pdata,
292 bma085_get_slave_descr);
293 if (result) {
294 dev_err(&client->adapter->dev,
295 "Slave registration failed: %s, %d\n",
296 devid->name, result);
297 goto out_free_memory;
298 }
299
300 return result;
301
302out_free_memory:
303 kfree(private_data);
304out_no_free:
305 dev_err(&client->adapter->dev, "%s failed %d\n", __func__, result);
306 return result;
307
308}
309
310static int bma085_mod_remove(struct i2c_client *client)
311{
312 struct bma085_mod_private_data *private_data =
313 i2c_get_clientdata(client);
314
315 dev_dbg(&client->adapter->dev, "%s\n", __func__);
316
317 inv_mpu_unregister_slave(client, private_data->pdata,
318 bma085_get_slave_descr);
319
320 kfree(private_data);
321 return 0;
322}
323
324static const struct i2c_device_id bma085_mod_id[] = {
325 { "bma085", PRESSURE_ID_BMA085 },
326 {}
327};
328
329MODULE_DEVICE_TABLE(i2c, bma085_mod_id);
330
331static struct i2c_driver bma085_mod_driver = {
332 .class = I2C_CLASS_HWMON,
333 .probe = bma085_mod_probe,
334 .remove = bma085_mod_remove,
335 .id_table = bma085_mod_id,
336 .driver = {
337 .owner = THIS_MODULE,
338 .name = "bma085_mod",
339 },
340 .address_list = normal_i2c,
341};
342
343static int __init bma085_mod_init(void)
344{
345 int res = i2c_add_driver(&bma085_mod_driver);
346 pr_info("%s: Probe name %s\n", __func__, "bma085_mod");
347 if (res)
348 pr_err("%s failed\n", __func__);
349 return res;
350}
351
352static void __exit bma085_mod_exit(void)
353{
354 pr_info("%s\n", __func__);
355 i2c_del_driver(&bma085_mod_driver);
356}
357
358module_init(bma085_mod_init);
359module_exit(bma085_mod_exit);
360
361MODULE_AUTHOR("Invensense Corporation");
362MODULE_DESCRIPTION("Driver to integrate BMA085 sensor with the MPU");
363MODULE_LICENSE("GPL");
364MODULE_ALIAS("bma085_mod");
365/**
366 * @}
367**/