aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPeter Meerwald <pmeerw@pmeerw.net>2014-02-05 11:58:00 -0500
committerJonathan Cameron <jic23@kernel.org>2014-05-03 06:31:36 -0400
commit3017d90e8931fbd5dbde06b4e793aebb141e4977 (patch)
tree6b2ace8b7963b135cd467c5f51099f5230c18418
parent0828eddc56d38b70f9a9e5cf7a0050328a90e7a1 (diff)
iio: Add Freescale MPL115A2 pressure / temperature sensor driver
I2C-controlled sensor with 10-bit pressure and temperature measurement datasheet: http://cache.freescale.com/files/sensors/doc/data_sheet/MPL3115A2.pdf v2: * use devm_iio_device_register() Signed-off-by: Peter Meerwald <pmeerw@pmeerw.net> Signed-off-by: Jonathan Cameron <jic23@kernel.org>
-rw-r--r--drivers/iio/pressure/Kconfig10
-rw-r--r--drivers/iio/pressure/Makefile1
-rw-r--r--drivers/iio/pressure/mpl115.c211
3 files changed, 222 insertions, 0 deletions
diff --git a/drivers/iio/pressure/Kconfig b/drivers/iio/pressure/Kconfig
index d88ff17fedb2..ffac8ac1efca 100644
--- a/drivers/iio/pressure/Kconfig
+++ b/drivers/iio/pressure/Kconfig
@@ -19,6 +19,16 @@ config HID_SENSOR_PRESS
19 To compile this driver as a module, choose M here: the module 19 To compile this driver as a module, choose M here: the module
20 will be called hid-sensor-press. 20 will be called hid-sensor-press.
21 21
22config MPL115
23 tristate "Freescale MPL115A2 pressure sensor driver"
24 depends on I2C
25 help
26 Say yes here to build support for the Freescale MPL115A2
27 pressure sensor connected via I2C.
28
29 To compile this driver as a module, choose M here: the module
30 will be called mpl115.
31
22config MPL3115 32config MPL3115
23 tristate "Freescale MPL3115A2 pressure sensor driver" 33 tristate "Freescale MPL3115A2 pressure sensor driver"
24 depends on I2C 34 depends on I2C
diff --git a/drivers/iio/pressure/Makefile b/drivers/iio/pressure/Makefile
index 4a57bf65b04b..c53d2500737a 100644
--- a/drivers/iio/pressure/Makefile
+++ b/drivers/iio/pressure/Makefile
@@ -4,6 +4,7 @@
4 4
5# When adding new entries keep the list in alphabetical order 5# When adding new entries keep the list in alphabetical order
6obj-$(CONFIG_HID_SENSOR_PRESS) += hid-sensor-press.o 6obj-$(CONFIG_HID_SENSOR_PRESS) += hid-sensor-press.o
7obj-$(CONFIG_MPL115) += mpl115.o
7obj-$(CONFIG_MPL3115) += mpl3115.o 8obj-$(CONFIG_MPL3115) += mpl3115.o
8obj-$(CONFIG_IIO_ST_PRESS) += st_pressure.o 9obj-$(CONFIG_IIO_ST_PRESS) += st_pressure.o
9st_pressure-y := st_pressure_core.o 10st_pressure-y := st_pressure_core.o
diff --git a/drivers/iio/pressure/mpl115.c b/drivers/iio/pressure/mpl115.c
new file mode 100644
index 000000000000..f5ecd6e19f5d
--- /dev/null
+++ b/drivers/iio/pressure/mpl115.c
@@ -0,0 +1,211 @@
1/*
2 * mpl115.c - Support for Freescale MPL115A2 pressure/temperature sensor
3 *
4 * Copyright (c) 2014 Peter Meerwald <pmeerw@pmeerw.net>
5 *
6 * This file is subject to the terms and conditions of version 2 of
7 * the GNU General Public License. See the file COPYING in the main
8 * directory of this archive for more details.
9 *
10 * (7-bit I2C slave address 0x60)
11 *
12 * TODO: shutdown pin
13 *
14 */
15
16#include <linux/module.h>
17#include <linux/i2c.h>
18#include <linux/iio/iio.h>
19#include <linux/delay.h>
20
21#define MPL115_PADC 0x00 /* pressure ADC output value, MSB first, 10 bit */
22#define MPL115_TADC 0x02 /* temperature ADC output value, MSB first, 10 bit */
23#define MPL115_A0 0x04 /* 12 bit integer, 3 bit fraction */
24#define MPL115_B1 0x06 /* 2 bit integer, 13 bit fraction */
25#define MPL115_B2 0x08 /* 1 bit integer, 14 bit fraction */
26#define MPL115_C12 0x0a /* 0 bit integer, 13 bit fraction */
27#define MPL115_CONVERT 0x12 /* convert temperature and pressure */
28
29struct mpl115_data {
30 struct i2c_client *client;
31 struct mutex lock;
32 s16 a0;
33 s16 b1, b2;
34 s16 c12;
35};
36
37static int mpl115_request(struct mpl115_data *data)
38{
39 int ret = i2c_smbus_write_byte_data(data->client, MPL115_CONVERT, 0);
40 if (ret < 0)
41 return ret;
42
43 usleep_range(3000, 4000);
44
45 return 0;
46}
47
48static int mpl115_comp_pressure(struct mpl115_data *data, int *val, int *val2)
49{
50 int ret;
51 u16 padc, tadc;
52 int a1, y1, pcomp;
53 unsigned kpa;
54
55 mutex_lock(&data->lock);
56 ret = mpl115_request(data);
57 if (ret < 0)
58 goto done;
59
60 ret = i2c_smbus_read_word_swapped(data->client, MPL115_PADC);
61 if (ret < 0)
62 goto done;
63 padc = ret >> 6;
64
65 ret = i2c_smbus_read_word_swapped(data->client, MPL115_TADC);
66 if (ret < 0)
67 goto done;
68 tadc = ret >> 6;
69
70 /* see Freescale AN3785 */
71 a1 = data->b1 + ((data->c12 * tadc) >> 11);
72 y1 = (data->a0 << 10) + a1 * padc;
73
74 /* compensated pressure with 4 fractional bits */
75 pcomp = (y1 + ((data->b2 * (int) tadc) >> 1)) >> 9;
76
77 kpa = pcomp * (115 - 50) / 1023 + (50 << 4);
78 *val = kpa >> 4;
79 *val2 = (kpa & 15) * (1000000 >> 4);
80done:
81 mutex_unlock(&data->lock);
82 return ret;
83}
84
85static int mpl115_read_temp(struct mpl115_data *data)
86{
87 int ret;
88
89 mutex_lock(&data->lock);
90 ret = mpl115_request(data);
91 if (ret < 0)
92 goto done;
93 ret = i2c_smbus_read_word_swapped(data->client, MPL115_TADC);
94done:
95 mutex_unlock(&data->lock);
96 return ret;
97}
98
99static int mpl115_read_raw(struct iio_dev *indio_dev,
100 struct iio_chan_spec const *chan,
101 int *val, int *val2, long mask)
102{
103 struct mpl115_data *data = iio_priv(indio_dev);
104 int ret;
105
106 switch (mask) {
107 case IIO_CHAN_INFO_PROCESSED:
108 ret = mpl115_comp_pressure(data, val, val2);
109 if (ret < 0)
110 return ret;
111 return IIO_VAL_INT_PLUS_MICRO;
112 case IIO_CHAN_INFO_RAW:
113 /* temperature -5.35 C / LSB, 472 LSB is 25 C */
114 ret = mpl115_read_temp(data);
115 if (ret < 0)
116 return ret;
117 *val = ret >> 6;
118 return IIO_VAL_INT;
119 case IIO_CHAN_INFO_OFFSET:
120 *val = 605;
121 *val2 = 750000;
122 return IIO_VAL_INT_PLUS_MICRO;
123 case IIO_CHAN_INFO_SCALE:
124 *val = -186;
125 *val2 = 915888;
126 return IIO_VAL_INT_PLUS_MICRO;
127 }
128 return -EINVAL;
129}
130
131static const struct iio_chan_spec mpl115_channels[] = {
132 {
133 .type = IIO_PRESSURE,
134 .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
135 },
136 {
137 .type = IIO_TEMP,
138 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
139 BIT(IIO_CHAN_INFO_OFFSET) | BIT(IIO_CHAN_INFO_SCALE),
140 },
141};
142
143static const struct iio_info mpl115_info = {
144 .read_raw = &mpl115_read_raw,
145 .driver_module = THIS_MODULE,
146};
147
148static int mpl115_probe(struct i2c_client *client,
149 const struct i2c_device_id *id)
150{
151 struct mpl115_data *data;
152 struct iio_dev *indio_dev;
153 int ret;
154
155 if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA))
156 return -ENODEV;
157
158 indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
159 if (!indio_dev)
160 return -ENOMEM;
161
162 data = iio_priv(indio_dev);
163 data->client = client;
164 mutex_init(&data->lock);
165
166 i2c_set_clientdata(client, indio_dev);
167 indio_dev->info = &mpl115_info;
168 indio_dev->name = id->name;
169 indio_dev->dev.parent = &client->dev;
170 indio_dev->modes = INDIO_DIRECT_MODE;
171 indio_dev->channels = mpl115_channels;
172 indio_dev->num_channels = ARRAY_SIZE(mpl115_channels);
173
174 ret = i2c_smbus_read_word_swapped(data->client, MPL115_A0);
175 if (ret < 0)
176 return ret;
177 data->a0 = ret;
178 ret = i2c_smbus_read_word_swapped(data->client, MPL115_B1);
179 if (ret < 0)
180 return ret;
181 data->b1 = ret;
182 ret = i2c_smbus_read_word_swapped(data->client, MPL115_B2);
183 if (ret < 0)
184 return ret;
185 data->b2 = ret;
186 ret = i2c_smbus_read_word_swapped(data->client, MPL115_C12);
187 if (ret < 0)
188 return ret;
189 data->c12 = ret;
190
191 return devm_iio_device_register(&client->dev, indio_dev);
192}
193
194static const struct i2c_device_id mpl115_id[] = {
195 { "mpl115", 0 },
196 { }
197};
198MODULE_DEVICE_TABLE(i2c, mpl115_id);
199
200static struct i2c_driver mpl115_driver = {
201 .driver = {
202 .name = "mpl115",
203 },
204 .probe = mpl115_probe,
205 .id_table = mpl115_id,
206};
207module_i2c_driver(mpl115_driver);
208
209MODULE_AUTHOR("Peter Meerwald <pmeerw@pmeerw.net>");
210MODULE_DESCRIPTION("Freescale MPL115 pressure/temperature driver");
211MODULE_LICENSE("GPL");