diff options
author | Denis Ciocca <denis.ciocca@gmail.com> | 2013-01-25 18:44:00 -0500 |
---|---|---|
committer | Jonathan Cameron <jic23@kernel.org> | 2013-01-31 12:56:43 -0500 |
commit | 23491b513bcd3dfe4ddb94547d73d9deb94eda44 (patch) | |
tree | 2f7628041f42e3df88716253e8ca820b2ec884a1 | |
parent | 085494ac2039433a5df9fdd6fb653579e18b8c71 (diff) |
iio:common: Add STMicroelectronics common library
This patch add a generic library for STMicroelectronics 3-axis sensors.
Signed-off-by: Denis Ciocca <denis.ciocca@st.com>
Reviewed-by: Lars-Peter Clausen <lars@metafoo.de>
Signed-off-by: Jonathan Cameron <jic23@kernel.org>
-rw-r--r-- | drivers/iio/common/Kconfig | 1 | ||||
-rw-r--r-- | drivers/iio/common/Makefile | 1 | ||||
-rw-r--r-- | drivers/iio/common/st_sensors/Kconfig | 14 | ||||
-rw-r--r-- | drivers/iio/common/st_sensors/Makefile | 10 | ||||
-rw-r--r-- | drivers/iio/common/st_sensors/st_sensors_buffer.c | 116 | ||||
-rw-r--r-- | drivers/iio/common/st_sensors/st_sensors_core.c | 460 | ||||
-rw-r--r-- | drivers/iio/common/st_sensors/st_sensors_i2c.c | 81 | ||||
-rw-r--r-- | drivers/iio/common/st_sensors/st_sensors_spi.c | 128 | ||||
-rw-r--r-- | drivers/iio/common/st_sensors/st_sensors_trigger.c | 77 | ||||
-rw-r--r-- | include/linux/iio/common/st_sensors.h | 274 | ||||
-rw-r--r-- | include/linux/iio/common/st_sensors_i2c.h | 20 | ||||
-rw-r--r-- | include/linux/iio/common/st_sensors_spi.h | 20 |
12 files changed, 1202 insertions, 0 deletions
diff --git a/drivers/iio/common/Kconfig b/drivers/iio/common/Kconfig index ed45ee54500c..0b6e97d18fa0 100644 --- a/drivers/iio/common/Kconfig +++ b/drivers/iio/common/Kconfig | |||
@@ -3,3 +3,4 @@ | |||
3 | # | 3 | # |
4 | 4 | ||
5 | source "drivers/iio/common/hid-sensors/Kconfig" | 5 | source "drivers/iio/common/hid-sensors/Kconfig" |
6 | source "drivers/iio/common/st_sensors/Kconfig" | ||
diff --git a/drivers/iio/common/Makefile b/drivers/iio/common/Makefile index 81584009b21b..c2352beb5d97 100644 --- a/drivers/iio/common/Makefile +++ b/drivers/iio/common/Makefile | |||
@@ -7,3 +7,4 @@ | |||
7 | # | 7 | # |
8 | 8 | ||
9 | obj-y += hid-sensors/ | 9 | obj-y += hid-sensors/ |
10 | obj-y += st_sensors/ | ||
diff --git a/drivers/iio/common/st_sensors/Kconfig b/drivers/iio/common/st_sensors/Kconfig new file mode 100644 index 000000000000..865f1ca33eb9 --- /dev/null +++ b/drivers/iio/common/st_sensors/Kconfig | |||
@@ -0,0 +1,14 @@ | |||
1 | # | ||
2 | # STMicroelectronics sensors common library | ||
3 | # | ||
4 | |||
5 | config IIO_ST_SENSORS_I2C | ||
6 | tristate | ||
7 | |||
8 | config IIO_ST_SENSORS_SPI | ||
9 | tristate | ||
10 | |||
11 | config IIO_ST_SENSORS_CORE | ||
12 | tristate | ||
13 | select IIO_ST_SENSORS_I2C if I2C | ||
14 | select IIO_ST_SENSORS_SPI if SPI_MASTER | ||
diff --git a/drivers/iio/common/st_sensors/Makefile b/drivers/iio/common/st_sensors/Makefile new file mode 100644 index 000000000000..9f3e24f3024b --- /dev/null +++ b/drivers/iio/common/st_sensors/Makefile | |||
@@ -0,0 +1,10 @@ | |||
1 | # | ||
2 | # Makefile for the STMicroelectronics sensor common modules. | ||
3 | # | ||
4 | |||
5 | obj-$(CONFIG_IIO_ST_SENSORS_I2C) += st_sensors_i2c.o | ||
6 | obj-$(CONFIG_IIO_ST_SENSORS_SPI) += st_sensors_spi.o | ||
7 | obj-$(CONFIG_IIO_ST_SENSORS_CORE) += st_sensors.o | ||
8 | st_sensors-y := st_sensors_core.o | ||
9 | st_sensors-$(CONFIG_IIO_BUFFER) += st_sensors_buffer.o | ||
10 | st_sensors-$(CONFIG_IIO_TRIGGER) += st_sensors_trigger.o | ||
diff --git a/drivers/iio/common/st_sensors/st_sensors_buffer.c b/drivers/iio/common/st_sensors/st_sensors_buffer.c new file mode 100644 index 000000000000..09b236d6ee89 --- /dev/null +++ b/drivers/iio/common/st_sensors/st_sensors_buffer.c | |||
@@ -0,0 +1,116 @@ | |||
1 | /* | ||
2 | * STMicroelectronics sensors buffer library driver | ||
3 | * | ||
4 | * Copyright 2012-2013 STMicroelectronics Inc. | ||
5 | * | ||
6 | * Denis Ciocca <denis.ciocca@st.com> | ||
7 | * | ||
8 | * Licensed under the GPL-2. | ||
9 | */ | ||
10 | |||
11 | #include <linux/kernel.h> | ||
12 | #include <linux/module.h> | ||
13 | #include <linux/slab.h> | ||
14 | #include <linux/iio/iio.h> | ||
15 | #include <linux/iio/trigger.h> | ||
16 | #include <linux/interrupt.h> | ||
17 | #include <linux/iio/buffer.h> | ||
18 | #include <linux/iio/trigger_consumer.h> | ||
19 | #include <linux/iio/triggered_buffer.h> | ||
20 | #include <linux/irqreturn.h> | ||
21 | |||
22 | #include <linux/iio/common/st_sensors.h> | ||
23 | |||
24 | |||
25 | int st_sensors_get_buffer_element(struct iio_dev *indio_dev, u8 *buf) | ||
26 | { | ||
27 | int i, n = 0, len; | ||
28 | u8 addr[ST_SENSORS_NUMBER_DATA_CHANNELS]; | ||
29 | struct st_sensor_data *sdata = iio_priv(indio_dev); | ||
30 | |||
31 | for (i = 0; i < ST_SENSORS_NUMBER_DATA_CHANNELS; i++) { | ||
32 | if (test_bit(i, indio_dev->active_scan_mask)) { | ||
33 | addr[n] = indio_dev->channels[i].address; | ||
34 | n++; | ||
35 | } | ||
36 | } | ||
37 | switch (n) { | ||
38 | case 1: | ||
39 | len = sdata->tf->read_multiple_byte(&sdata->tb, sdata->dev, | ||
40 | addr[0], ST_SENSORS_BYTE_FOR_CHANNEL, buf, | ||
41 | sdata->multiread_bit); | ||
42 | break; | ||
43 | case 2: | ||
44 | if ((addr[1] - addr[0]) == ST_SENSORS_BYTE_FOR_CHANNEL) { | ||
45 | len = sdata->tf->read_multiple_byte(&sdata->tb, | ||
46 | sdata->dev, addr[0], | ||
47 | ST_SENSORS_BYTE_FOR_CHANNEL*n, | ||
48 | buf, sdata->multiread_bit); | ||
49 | } else { | ||
50 | u8 rx_array[ST_SENSORS_BYTE_FOR_CHANNEL* | ||
51 | ST_SENSORS_NUMBER_DATA_CHANNELS]; | ||
52 | len = sdata->tf->read_multiple_byte(&sdata->tb, | ||
53 | sdata->dev, addr[0], | ||
54 | ST_SENSORS_BYTE_FOR_CHANNEL* | ||
55 | ST_SENSORS_NUMBER_DATA_CHANNELS, | ||
56 | rx_array, sdata->multiread_bit); | ||
57 | if (len < 0) | ||
58 | goto read_data_channels_error; | ||
59 | |||
60 | for (i = 0; i < n * ST_SENSORS_NUMBER_DATA_CHANNELS; | ||
61 | i++) { | ||
62 | if (i < n) | ||
63 | buf[i] = rx_array[i]; | ||
64 | else | ||
65 | buf[i] = rx_array[n + i]; | ||
66 | } | ||
67 | len = ST_SENSORS_BYTE_FOR_CHANNEL*n; | ||
68 | } | ||
69 | break; | ||
70 | case 3: | ||
71 | len = sdata->tf->read_multiple_byte(&sdata->tb, sdata->dev, | ||
72 | addr[0], ST_SENSORS_BYTE_FOR_CHANNEL* | ||
73 | ST_SENSORS_NUMBER_DATA_CHANNELS, | ||
74 | buf, sdata->multiread_bit); | ||
75 | break; | ||
76 | default: | ||
77 | len = -EINVAL; | ||
78 | goto read_data_channels_error; | ||
79 | } | ||
80 | if (len != ST_SENSORS_BYTE_FOR_CHANNEL*n) { | ||
81 | len = -EIO; | ||
82 | goto read_data_channels_error; | ||
83 | } | ||
84 | |||
85 | read_data_channels_error: | ||
86 | return len; | ||
87 | } | ||
88 | EXPORT_SYMBOL(st_sensors_get_buffer_element); | ||
89 | |||
90 | irqreturn_t st_sensors_trigger_handler(int irq, void *p) | ||
91 | { | ||
92 | int len; | ||
93 | struct iio_poll_func *pf = p; | ||
94 | struct iio_dev *indio_dev = pf->indio_dev; | ||
95 | struct st_sensor_data *sdata = iio_priv(indio_dev); | ||
96 | |||
97 | len = st_sensors_get_buffer_element(indio_dev, sdata->buffer_data); | ||
98 | if (len < 0) | ||
99 | goto st_sensors_get_buffer_element_error; | ||
100 | |||
101 | if (indio_dev->scan_timestamp) | ||
102 | *(s64 *)((u8 *)sdata->buffer_data + | ||
103 | ALIGN(len, sizeof(s64))) = pf->timestamp; | ||
104 | |||
105 | iio_push_to_buffers(indio_dev, sdata->buffer_data); | ||
106 | |||
107 | st_sensors_get_buffer_element_error: | ||
108 | iio_trigger_notify_done(indio_dev->trig); | ||
109 | |||
110 | return IRQ_HANDLED; | ||
111 | } | ||
112 | EXPORT_SYMBOL(st_sensors_trigger_handler); | ||
113 | |||
114 | MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>"); | ||
115 | MODULE_DESCRIPTION("STMicroelectronics ST-sensors buffer"); | ||
116 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/iio/common/st_sensors/st_sensors_core.c b/drivers/iio/common/st_sensors/st_sensors_core.c new file mode 100644 index 000000000000..fba6d6847b6d --- /dev/null +++ b/drivers/iio/common/st_sensors/st_sensors_core.c | |||
@@ -0,0 +1,460 @@ | |||
1 | /* | ||
2 | * STMicroelectronics sensors core library driver | ||
3 | * | ||
4 | * Copyright 2012-2013 STMicroelectronics Inc. | ||
5 | * | ||
6 | * Denis Ciocca <denis.ciocca@st.com> | ||
7 | * | ||
8 | * Licensed under the GPL-2. | ||
9 | */ | ||
10 | |||
11 | #include <linux/kernel.h> | ||
12 | #include <linux/module.h> | ||
13 | #include <linux/slab.h> | ||
14 | #include <linux/delay.h> | ||
15 | #include <linux/iio/iio.h> | ||
16 | #include <asm/unaligned.h> | ||
17 | |||
18 | #include <linux/iio/common/st_sensors.h> | ||
19 | |||
20 | |||
21 | #define ST_SENSORS_WAI_ADDRESS 0x0f | ||
22 | |||
23 | static int st_sensors_write_data_with_mask(struct iio_dev *indio_dev, | ||
24 | u8 reg_addr, u8 mask, u8 data) | ||
25 | { | ||
26 | int err; | ||
27 | u8 new_data; | ||
28 | struct st_sensor_data *sdata = iio_priv(indio_dev); | ||
29 | |||
30 | err = sdata->tf->read_byte(&sdata->tb, sdata->dev, reg_addr, &new_data); | ||
31 | if (err < 0) | ||
32 | goto st_sensors_write_data_with_mask_error; | ||
33 | |||
34 | new_data = ((new_data & (~mask)) | ((data << __ffs(mask)) & mask)); | ||
35 | err = sdata->tf->write_byte(&sdata->tb, sdata->dev, reg_addr, new_data); | ||
36 | |||
37 | st_sensors_write_data_with_mask_error: | ||
38 | return err; | ||
39 | } | ||
40 | |||
41 | int st_sensors_get_sampling_frequency_avl(struct iio_dev *indio_dev, char *buf) | ||
42 | { | ||
43 | int i, len = 0; | ||
44 | struct st_sensor_data *sdata = iio_priv(indio_dev); | ||
45 | |||
46 | mutex_lock(&indio_dev->mlock); | ||
47 | for (i = 0; i < ST_SENSORS_ODR_LIST_MAX; i++) { | ||
48 | if (sdata->sensor->odr.odr_avl[i].hz == 0) | ||
49 | break; | ||
50 | |||
51 | len += scnprintf(buf + len, PAGE_SIZE - len, "%d ", | ||
52 | sdata->sensor->odr.odr_avl[i].hz); | ||
53 | } | ||
54 | mutex_unlock(&indio_dev->mlock); | ||
55 | buf[len - 1] = '\n'; | ||
56 | |||
57 | return len; | ||
58 | } | ||
59 | EXPORT_SYMBOL(st_sensors_get_sampling_frequency_avl); | ||
60 | |||
61 | int st_sensors_get_scale_avl(struct iio_dev *indio_dev, char *buf) | ||
62 | { | ||
63 | int i, len = 0; | ||
64 | struct st_sensor_data *sdata = iio_priv(indio_dev); | ||
65 | |||
66 | mutex_lock(&indio_dev->mlock); | ||
67 | for (i = 0; i < ST_SENSORS_FULLSCALE_AVL_MAX; i++) { | ||
68 | if (sdata->sensor->fs.fs_avl[i].num == 0) | ||
69 | break; | ||
70 | |||
71 | len += scnprintf(buf + len, PAGE_SIZE - len, "0.%06u ", | ||
72 | sdata->sensor->fs.fs_avl[i].gain); | ||
73 | } | ||
74 | mutex_unlock(&indio_dev->mlock); | ||
75 | buf[len - 1] = '\n'; | ||
76 | |||
77 | return len; | ||
78 | } | ||
79 | EXPORT_SYMBOL(st_sensors_get_scale_avl); | ||
80 | |||
81 | static int st_sensors_match_odr(struct st_sensors *sensor, | ||
82 | unsigned int odr, struct st_sensor_odr_avl *odr_out) | ||
83 | { | ||
84 | int i, ret = -EINVAL; | ||
85 | |||
86 | for (i = 0; i < ST_SENSORS_ODR_LIST_MAX; i++) { | ||
87 | if (sensor->odr.odr_avl[i].hz == 0) | ||
88 | goto st_sensors_match_odr_error; | ||
89 | |||
90 | if (sensor->odr.odr_avl[i].hz == odr) { | ||
91 | odr_out->hz = sensor->odr.odr_avl[i].hz; | ||
92 | odr_out->value = sensor->odr.odr_avl[i].value; | ||
93 | ret = 0; | ||
94 | break; | ||
95 | } | ||
96 | } | ||
97 | |||
98 | st_sensors_match_odr_error: | ||
99 | return ret; | ||
100 | } | ||
101 | |||
102 | int st_sensors_set_odr(struct iio_dev *indio_dev, unsigned int odr) | ||
103 | { | ||
104 | int err; | ||
105 | struct st_sensor_odr_avl odr_out; | ||
106 | struct st_sensor_data *sdata = iio_priv(indio_dev); | ||
107 | |||
108 | err = st_sensors_match_odr(sdata->sensor, odr, &odr_out); | ||
109 | if (err < 0) | ||
110 | goto st_sensors_match_odr_error; | ||
111 | |||
112 | if ((sdata->sensor->odr.addr == sdata->sensor->pw.addr) && | ||
113 | (sdata->sensor->odr.mask == sdata->sensor->pw.mask)) { | ||
114 | if (sdata->enabled == true) { | ||
115 | err = st_sensors_write_data_with_mask(indio_dev, | ||
116 | sdata->sensor->odr.addr, | ||
117 | sdata->sensor->odr.mask, | ||
118 | odr_out.value); | ||
119 | } else { | ||
120 | err = 0; | ||
121 | } | ||
122 | } else { | ||
123 | err = st_sensors_write_data_with_mask(indio_dev, | ||
124 | sdata->sensor->odr.addr, sdata->sensor->odr.mask, | ||
125 | odr_out.value); | ||
126 | } | ||
127 | if (err >= 0) | ||
128 | sdata->odr = odr_out.hz; | ||
129 | |||
130 | st_sensors_match_odr_error: | ||
131 | return err; | ||
132 | } | ||
133 | EXPORT_SYMBOL(st_sensors_set_odr); | ||
134 | |||
135 | static int st_sensors_match_fs(struct st_sensors *sensor, | ||
136 | unsigned int fs, int *index_fs_avl) | ||
137 | { | ||
138 | int i, ret = -EINVAL; | ||
139 | |||
140 | for (i = 0; i < ST_SENSORS_FULLSCALE_AVL_MAX; i++) { | ||
141 | if (sensor->fs.fs_avl[i].num == 0) | ||
142 | goto st_sensors_match_odr_error; | ||
143 | |||
144 | if (sensor->fs.fs_avl[i].num == fs) { | ||
145 | *index_fs_avl = i; | ||
146 | ret = 0; | ||
147 | break; | ||
148 | } | ||
149 | } | ||
150 | |||
151 | st_sensors_match_odr_error: | ||
152 | return ret; | ||
153 | } | ||
154 | |||
155 | static int st_sensors_set_fullscale(struct iio_dev *indio_dev, unsigned int fs) | ||
156 | { | ||
157 | int err, i; | ||
158 | struct st_sensor_data *sdata = iio_priv(indio_dev); | ||
159 | |||
160 | err = st_sensors_match_fs(sdata->sensor, fs, &i); | ||
161 | if (err < 0) | ||
162 | goto st_accel_set_fullscale_error; | ||
163 | |||
164 | err = st_sensors_write_data_with_mask(indio_dev, | ||
165 | sdata->sensor->fs.addr, | ||
166 | sdata->sensor->fs.mask, | ||
167 | sdata->sensor->fs.fs_avl[i].value); | ||
168 | if (err < 0) | ||
169 | goto st_accel_set_fullscale_error; | ||
170 | |||
171 | sdata->current_fullscale = (struct st_sensor_fullscale_avl *) | ||
172 | &sdata->sensor->fs.fs_avl[i]; | ||
173 | return err; | ||
174 | |||
175 | st_accel_set_fullscale_error: | ||
176 | dev_err(&indio_dev->dev, "failed to set new fullscale.\n"); | ||
177 | return err; | ||
178 | } | ||
179 | |||
180 | int st_sensors_set_enable(struct iio_dev *indio_dev, bool enable) | ||
181 | { | ||
182 | bool found; | ||
183 | u8 tmp_value; | ||
184 | int err = -EINVAL; | ||
185 | struct st_sensor_odr_avl odr_out; | ||
186 | struct st_sensor_data *sdata = iio_priv(indio_dev); | ||
187 | |||
188 | if (enable) { | ||
189 | found = false; | ||
190 | tmp_value = sdata->sensor->pw.value_on; | ||
191 | if ((sdata->sensor->odr.addr == sdata->sensor->pw.addr) && | ||
192 | (sdata->sensor->odr.mask == sdata->sensor->pw.mask)) { | ||
193 | err = st_sensors_match_odr(sdata->sensor, | ||
194 | sdata->odr, &odr_out); | ||
195 | if (err < 0) | ||
196 | goto set_enable_error; | ||
197 | tmp_value = odr_out.value; | ||
198 | found = true; | ||
199 | } | ||
200 | err = st_sensors_write_data_with_mask(indio_dev, | ||
201 | sdata->sensor->pw.addr, | ||
202 | sdata->sensor->pw.mask, tmp_value); | ||
203 | if (err < 0) | ||
204 | goto set_enable_error; | ||
205 | |||
206 | sdata->enabled = true; | ||
207 | |||
208 | if (found) | ||
209 | sdata->odr = odr_out.hz; | ||
210 | } else { | ||
211 | err = st_sensors_write_data_with_mask(indio_dev, | ||
212 | sdata->sensor->pw.addr, | ||
213 | sdata->sensor->pw.mask, | ||
214 | sdata->sensor->pw.value_off); | ||
215 | if (err < 0) | ||
216 | goto set_enable_error; | ||
217 | |||
218 | sdata->enabled = false; | ||
219 | } | ||
220 | |||
221 | set_enable_error: | ||
222 | return err; | ||
223 | } | ||
224 | EXPORT_SYMBOL(st_sensors_set_enable); | ||
225 | |||
226 | int st_sensors_set_axis_enable(struct iio_dev *indio_dev, u8 axis_enable) | ||
227 | { | ||
228 | struct st_sensor_data *sdata = iio_priv(indio_dev); | ||
229 | |||
230 | return st_sensors_write_data_with_mask(indio_dev, | ||
231 | sdata->sensor->enable_axis.addr, | ||
232 | sdata->sensor->enable_axis.mask, axis_enable); | ||
233 | } | ||
234 | EXPORT_SYMBOL(st_sensors_set_axis_enable); | ||
235 | |||
236 | int st_sensors_init_sensor(struct iio_dev *indio_dev) | ||
237 | { | ||
238 | int err; | ||
239 | struct st_sensor_data *sdata = iio_priv(indio_dev); | ||
240 | |||
241 | mutex_init(&sdata->tb.buf_lock); | ||
242 | |||
243 | err = st_sensors_set_enable(indio_dev, false); | ||
244 | if (err < 0) | ||
245 | goto init_error; | ||
246 | |||
247 | err = st_sensors_set_fullscale(indio_dev, | ||
248 | sdata->current_fullscale->num); | ||
249 | if (err < 0) | ||
250 | goto init_error; | ||
251 | |||
252 | err = st_sensors_set_odr(indio_dev, sdata->odr); | ||
253 | if (err < 0) | ||
254 | goto init_error; | ||
255 | |||
256 | /* set BDU */ | ||
257 | err = st_sensors_write_data_with_mask(indio_dev, | ||
258 | sdata->sensor->bdu.addr, sdata->sensor->bdu.mask, true); | ||
259 | if (err < 0) | ||
260 | goto init_error; | ||
261 | |||
262 | err = st_sensors_set_axis_enable(indio_dev, ST_SENSORS_ENABLE_ALL_AXIS); | ||
263 | |||
264 | init_error: | ||
265 | return err; | ||
266 | } | ||
267 | EXPORT_SYMBOL(st_sensors_init_sensor); | ||
268 | |||
269 | int st_sensors_set_dataready_irq(struct iio_dev *indio_dev, bool enable) | ||
270 | { | ||
271 | int err; | ||
272 | struct st_sensor_data *sdata = iio_priv(indio_dev); | ||
273 | |||
274 | /* Enable/Disable the interrupt generator 1. */ | ||
275 | if (sdata->sensor->drdy_irq.ig1.en_addr > 0) { | ||
276 | err = st_sensors_write_data_with_mask(indio_dev, | ||
277 | sdata->sensor->drdy_irq.ig1.en_addr, | ||
278 | sdata->sensor->drdy_irq.ig1.en_mask, (int)enable); | ||
279 | if (err < 0) | ||
280 | goto st_accel_set_dataready_irq_error; | ||
281 | } | ||
282 | |||
283 | /* Enable/Disable the interrupt generator for data ready. */ | ||
284 | err = st_sensors_write_data_with_mask(indio_dev, | ||
285 | sdata->sensor->drdy_irq.addr, | ||
286 | sdata->sensor->drdy_irq.mask, (int)enable); | ||
287 | |||
288 | st_accel_set_dataready_irq_error: | ||
289 | return err; | ||
290 | } | ||
291 | EXPORT_SYMBOL(st_sensors_set_dataready_irq); | ||
292 | |||
293 | int st_sensors_set_fullscale_by_gain(struct iio_dev *indio_dev, int scale) | ||
294 | { | ||
295 | int err = -EINVAL, i; | ||
296 | struct st_sensor_data *sdata = iio_priv(indio_dev); | ||
297 | |||
298 | for (i = 0; i < ST_SENSORS_FULLSCALE_AVL_MAX; i++) { | ||
299 | if ((sdata->sensor->fs.fs_avl[i].gain == scale) && | ||
300 | (sdata->sensor->fs.fs_avl[i].gain != 0)) { | ||
301 | err = 0; | ||
302 | break; | ||
303 | } | ||
304 | } | ||
305 | if (err < 0) | ||
306 | goto st_sensors_match_scale_error; | ||
307 | |||
308 | err = st_sensors_set_fullscale(indio_dev, | ||
309 | sdata->sensor->fs.fs_avl[i].num); | ||
310 | |||
311 | st_sensors_match_scale_error: | ||
312 | return err; | ||
313 | } | ||
314 | EXPORT_SYMBOL(st_sensors_set_fullscale_by_gain); | ||
315 | |||
316 | static int st_sensors_read_axis_data(struct iio_dev *indio_dev, | ||
317 | u8 ch_addr, int *data) | ||
318 | { | ||
319 | int err; | ||
320 | u8 outdata[ST_SENSORS_BYTE_FOR_CHANNEL]; | ||
321 | struct st_sensor_data *sdata = iio_priv(indio_dev); | ||
322 | |||
323 | err = sdata->tf->read_multiple_byte(&sdata->tb, sdata->dev, | ||
324 | ch_addr, ST_SENSORS_BYTE_FOR_CHANNEL, | ||
325 | outdata, sdata->multiread_bit); | ||
326 | if (err < 0) | ||
327 | goto read_error; | ||
328 | |||
329 | *data = (s16)get_unaligned_le16(outdata); | ||
330 | |||
331 | read_error: | ||
332 | return err; | ||
333 | } | ||
334 | |||
335 | int st_sensors_read_info_raw(struct iio_dev *indio_dev, | ||
336 | struct iio_chan_spec const *ch, int *val) | ||
337 | { | ||
338 | int err; | ||
339 | struct st_sensor_data *sdata = iio_priv(indio_dev); | ||
340 | |||
341 | mutex_lock(&indio_dev->mlock); | ||
342 | if (indio_dev->currentmode == INDIO_BUFFER_TRIGGERED) { | ||
343 | err = -EBUSY; | ||
344 | goto read_error; | ||
345 | } else { | ||
346 | err = st_sensors_set_enable(indio_dev, true); | ||
347 | if (err < 0) | ||
348 | goto read_error; | ||
349 | |||
350 | msleep((sdata->sensor->bootime * 1000) / sdata->odr); | ||
351 | err = st_sensors_read_axis_data(indio_dev, ch->address, val); | ||
352 | if (err < 0) | ||
353 | goto read_error; | ||
354 | |||
355 | *val = *val >> ch->scan_type.shift; | ||
356 | } | ||
357 | mutex_unlock(&indio_dev->mlock); | ||
358 | |||
359 | return err; | ||
360 | |||
361 | read_error: | ||
362 | mutex_unlock(&indio_dev->mlock); | ||
363 | return err; | ||
364 | } | ||
365 | EXPORT_SYMBOL(st_sensors_read_info_raw); | ||
366 | |||
367 | int st_sensors_check_device_support(struct iio_dev *indio_dev, | ||
368 | int num_sensors_list, const struct st_sensors *sensors) | ||
369 | { | ||
370 | u8 wai; | ||
371 | int i, n, err; | ||
372 | struct st_sensor_data *sdata = iio_priv(indio_dev); | ||
373 | |||
374 | err = sdata->tf->read_byte(&sdata->tb, sdata->dev, | ||
375 | ST_SENSORS_DEFAULT_WAI_ADDRESS, &wai); | ||
376 | if (err < 0) { | ||
377 | dev_err(&indio_dev->dev, "failed to read Who-Am-I register.\n"); | ||
378 | goto read_wai_error; | ||
379 | } | ||
380 | |||
381 | for (i = 0; i < num_sensors_list; i++) { | ||
382 | if (sensors[i].wai == wai) | ||
383 | break; | ||
384 | } | ||
385 | if (i == num_sensors_list) | ||
386 | goto device_not_supported; | ||
387 | |||
388 | for (n = 0; n < ARRAY_SIZE(sensors[i].sensors_supported); n++) { | ||
389 | if (strcmp(indio_dev->name, | ||
390 | &sensors[i].sensors_supported[n][0]) == 0) | ||
391 | break; | ||
392 | } | ||
393 | if (n == ARRAY_SIZE(sensors[i].sensors_supported)) { | ||
394 | dev_err(&indio_dev->dev, "device name and WhoAmI mismatch.\n"); | ||
395 | goto sensor_name_mismatch; | ||
396 | } | ||
397 | |||
398 | sdata->sensor = (struct st_sensors *)&sensors[i]; | ||
399 | |||
400 | return i; | ||
401 | |||
402 | device_not_supported: | ||
403 | dev_err(&indio_dev->dev, "device not supported: WhoAmI (0x%x).\n", wai); | ||
404 | sensor_name_mismatch: | ||
405 | err = -ENODEV; | ||
406 | read_wai_error: | ||
407 | return err; | ||
408 | } | ||
409 | EXPORT_SYMBOL(st_sensors_check_device_support); | ||
410 | |||
411 | ssize_t st_sensors_sysfs_get_sampling_frequency(struct device *dev, | ||
412 | struct device_attribute *attr, char *buf) | ||
413 | { | ||
414 | struct st_sensor_data *adata = iio_priv(dev_get_drvdata(dev)); | ||
415 | |||
416 | return sprintf(buf, "%d\n", adata->odr); | ||
417 | } | ||
418 | EXPORT_SYMBOL(st_sensors_sysfs_get_sampling_frequency); | ||
419 | |||
420 | ssize_t st_sensors_sysfs_set_sampling_frequency(struct device *dev, | ||
421 | struct device_attribute *attr, const char *buf, size_t size) | ||
422 | { | ||
423 | int err; | ||
424 | unsigned int odr; | ||
425 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
426 | |||
427 | err = kstrtoint(buf, 10, &odr); | ||
428 | if (err < 0) | ||
429 | goto conversion_error; | ||
430 | |||
431 | mutex_lock(&indio_dev->mlock); | ||
432 | err = st_sensors_set_odr(indio_dev, odr); | ||
433 | mutex_unlock(&indio_dev->mlock); | ||
434 | |||
435 | conversion_error: | ||
436 | return err < 0 ? err : size; | ||
437 | } | ||
438 | EXPORT_SYMBOL(st_sensors_sysfs_set_sampling_frequency); | ||
439 | |||
440 | ssize_t st_sensors_sysfs_sampling_frequency_avail(struct device *dev, | ||
441 | struct device_attribute *attr, char *buf) | ||
442 | { | ||
443 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
444 | |||
445 | return st_sensors_get_sampling_frequency_avl(indio_dev, buf); | ||
446 | } | ||
447 | EXPORT_SYMBOL(st_sensors_sysfs_sampling_frequency_avail); | ||
448 | |||
449 | ssize_t st_sensors_sysfs_scale_avail(struct device *dev, | ||
450 | struct device_attribute *attr, char *buf) | ||
451 | { | ||
452 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
453 | |||
454 | return st_sensors_get_scale_avl(indio_dev, buf); | ||
455 | } | ||
456 | EXPORT_SYMBOL(st_sensors_sysfs_scale_avail); | ||
457 | |||
458 | MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>"); | ||
459 | MODULE_DESCRIPTION("STMicroelectronics ST-sensors core"); | ||
460 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/iio/common/st_sensors/st_sensors_i2c.c b/drivers/iio/common/st_sensors/st_sensors_i2c.c new file mode 100644 index 000000000000..38af9440c103 --- /dev/null +++ b/drivers/iio/common/st_sensors/st_sensors_i2c.c | |||
@@ -0,0 +1,81 @@ | |||
1 | /* | ||
2 | * STMicroelectronics sensors i2c library driver | ||
3 | * | ||
4 | * Copyright 2012-2013 STMicroelectronics Inc. | ||
5 | * | ||
6 | * Denis Ciocca <denis.ciocca@st.com> | ||
7 | * | ||
8 | * Licensed under the GPL-2. | ||
9 | */ | ||
10 | |||
11 | #include <linux/kernel.h> | ||
12 | #include <linux/module.h> | ||
13 | #include <linux/slab.h> | ||
14 | #include <linux/iio/iio.h> | ||
15 | |||
16 | #include <linux/iio/common/st_sensors_i2c.h> | ||
17 | |||
18 | |||
19 | #define ST_SENSORS_I2C_MULTIREAD 0x80 | ||
20 | |||
21 | static unsigned int st_sensors_i2c_get_irq(struct iio_dev *indio_dev) | ||
22 | { | ||
23 | struct st_sensor_data *sdata = iio_priv(indio_dev); | ||
24 | |||
25 | return to_i2c_client(sdata->dev)->irq; | ||
26 | } | ||
27 | |||
28 | static int st_sensors_i2c_read_byte(struct st_sensor_transfer_buffer *tb, | ||
29 | struct device *dev, u8 reg_addr, u8 *res_byte) | ||
30 | { | ||
31 | int err; | ||
32 | |||
33 | err = i2c_smbus_read_byte_data(to_i2c_client(dev), reg_addr); | ||
34 | if (err < 0) | ||
35 | goto st_accel_i2c_read_byte_error; | ||
36 | |||
37 | *res_byte = err & 0xff; | ||
38 | |||
39 | st_accel_i2c_read_byte_error: | ||
40 | return err < 0 ? err : 0; | ||
41 | } | ||
42 | |||
43 | static int st_sensors_i2c_read_multiple_byte( | ||
44 | struct st_sensor_transfer_buffer *tb, struct device *dev, | ||
45 | u8 reg_addr, int len, u8 *data, bool multiread_bit) | ||
46 | { | ||
47 | if (multiread_bit) | ||
48 | reg_addr |= ST_SENSORS_I2C_MULTIREAD; | ||
49 | |||
50 | return i2c_smbus_read_i2c_block_data(to_i2c_client(dev), | ||
51 | reg_addr, len, data); | ||
52 | } | ||
53 | |||
54 | static int st_sensors_i2c_write_byte(struct st_sensor_transfer_buffer *tb, | ||
55 | struct device *dev, u8 reg_addr, u8 data) | ||
56 | { | ||
57 | return i2c_smbus_write_byte_data(to_i2c_client(dev), reg_addr, data); | ||
58 | } | ||
59 | |||
60 | static const struct st_sensor_transfer_function st_sensors_tf_i2c = { | ||
61 | .read_byte = st_sensors_i2c_read_byte, | ||
62 | .write_byte = st_sensors_i2c_write_byte, | ||
63 | .read_multiple_byte = st_sensors_i2c_read_multiple_byte, | ||
64 | }; | ||
65 | |||
66 | void st_sensors_i2c_configure(struct iio_dev *indio_dev, | ||
67 | struct i2c_client *client, struct st_sensor_data *sdata) | ||
68 | { | ||
69 | i2c_set_clientdata(client, indio_dev); | ||
70 | |||
71 | indio_dev->dev.parent = &client->dev; | ||
72 | indio_dev->name = client->name; | ||
73 | |||
74 | sdata->tf = &st_sensors_tf_i2c; | ||
75 | sdata->get_irq_data_ready = st_sensors_i2c_get_irq; | ||
76 | } | ||
77 | EXPORT_SYMBOL(st_sensors_i2c_configure); | ||
78 | |||
79 | MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>"); | ||
80 | MODULE_DESCRIPTION("STMicroelectronics ST-sensors i2c driver"); | ||
81 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/iio/common/st_sensors/st_sensors_spi.c b/drivers/iio/common/st_sensors/st_sensors_spi.c new file mode 100644 index 000000000000..f0aa2f105222 --- /dev/null +++ b/drivers/iio/common/st_sensors/st_sensors_spi.c | |||
@@ -0,0 +1,128 @@ | |||
1 | /* | ||
2 | * STMicroelectronics sensors spi library driver | ||
3 | * | ||
4 | * Copyright 2012-2013 STMicroelectronics Inc. | ||
5 | * | ||
6 | * Denis Ciocca <denis.ciocca@st.com> | ||
7 | * | ||
8 | * Licensed under the GPL-2. | ||
9 | */ | ||
10 | |||
11 | #include <linux/kernel.h> | ||
12 | #include <linux/module.h> | ||
13 | #include <linux/slab.h> | ||
14 | #include <linux/iio/iio.h> | ||
15 | |||
16 | #include <linux/iio/common/st_sensors_spi.h> | ||
17 | |||
18 | |||
19 | #define ST_SENSORS_SPI_MULTIREAD 0xc0 | ||
20 | #define ST_SENSORS_SPI_READ 0x80 | ||
21 | |||
22 | static unsigned int st_sensors_spi_get_irq(struct iio_dev *indio_dev) | ||
23 | { | ||
24 | struct st_sensor_data *sdata = iio_priv(indio_dev); | ||
25 | |||
26 | return to_spi_device(sdata->dev)->irq; | ||
27 | } | ||
28 | |||
29 | static int st_sensors_spi_read(struct st_sensor_transfer_buffer *tb, | ||
30 | struct device *dev, u8 reg_addr, int len, u8 *data, bool multiread_bit) | ||
31 | { | ||
32 | struct spi_message msg; | ||
33 | int err; | ||
34 | |||
35 | struct spi_transfer xfers[] = { | ||
36 | { | ||
37 | .tx_buf = tb->tx_buf, | ||
38 | .bits_per_word = 8, | ||
39 | .len = 1, | ||
40 | }, | ||
41 | { | ||
42 | .rx_buf = tb->rx_buf, | ||
43 | .bits_per_word = 8, | ||
44 | .len = len, | ||
45 | } | ||
46 | }; | ||
47 | |||
48 | mutex_lock(&tb->buf_lock); | ||
49 | if ((multiread_bit) && (len > 1)) | ||
50 | tb->tx_buf[0] = reg_addr | ST_SENSORS_SPI_MULTIREAD; | ||
51 | else | ||
52 | tb->tx_buf[0] = reg_addr | ST_SENSORS_SPI_READ; | ||
53 | |||
54 | spi_message_init(&msg); | ||
55 | spi_message_add_tail(&xfers[0], &msg); | ||
56 | spi_message_add_tail(&xfers[1], &msg); | ||
57 | err = spi_sync(to_spi_device(dev), &msg); | ||
58 | if (err) | ||
59 | goto acc_spi_read_error; | ||
60 | |||
61 | memcpy(data, tb->rx_buf, len*sizeof(u8)); | ||
62 | mutex_unlock(&tb->buf_lock); | ||
63 | return len; | ||
64 | |||
65 | acc_spi_read_error: | ||
66 | mutex_unlock(&tb->buf_lock); | ||
67 | return err; | ||
68 | } | ||
69 | |||
70 | static int st_sensors_spi_read_byte(struct st_sensor_transfer_buffer *tb, | ||
71 | struct device *dev, u8 reg_addr, u8 *res_byte) | ||
72 | { | ||
73 | return st_sensors_spi_read(tb, dev, reg_addr, 1, res_byte, false); | ||
74 | } | ||
75 | |||
76 | static int st_sensors_spi_read_multiple_byte( | ||
77 | struct st_sensor_transfer_buffer *tb, struct device *dev, | ||
78 | u8 reg_addr, int len, u8 *data, bool multiread_bit) | ||
79 | { | ||
80 | return st_sensors_spi_read(tb, dev, reg_addr, len, data, multiread_bit); | ||
81 | } | ||
82 | |||
83 | static int st_sensors_spi_write_byte(struct st_sensor_transfer_buffer *tb, | ||
84 | struct device *dev, u8 reg_addr, u8 data) | ||
85 | { | ||
86 | struct spi_message msg; | ||
87 | int err; | ||
88 | |||
89 | struct spi_transfer xfers = { | ||
90 | .tx_buf = tb->tx_buf, | ||
91 | .bits_per_word = 8, | ||
92 | .len = 2, | ||
93 | }; | ||
94 | |||
95 | mutex_lock(&tb->buf_lock); | ||
96 | tb->tx_buf[0] = reg_addr; | ||
97 | tb->tx_buf[1] = data; | ||
98 | |||
99 | spi_message_init(&msg); | ||
100 | spi_message_add_tail(&xfers, &msg); | ||
101 | err = spi_sync(to_spi_device(dev), &msg); | ||
102 | mutex_unlock(&tb->buf_lock); | ||
103 | |||
104 | return err; | ||
105 | } | ||
106 | |||
107 | static const struct st_sensor_transfer_function st_sensors_tf_spi = { | ||
108 | .read_byte = st_sensors_spi_read_byte, | ||
109 | .write_byte = st_sensors_spi_write_byte, | ||
110 | .read_multiple_byte = st_sensors_spi_read_multiple_byte, | ||
111 | }; | ||
112 | |||
113 | void st_sensors_spi_configure(struct iio_dev *indio_dev, | ||
114 | struct spi_device *spi, struct st_sensor_data *sdata) | ||
115 | { | ||
116 | spi_set_drvdata(spi, indio_dev); | ||
117 | |||
118 | indio_dev->dev.parent = &spi->dev; | ||
119 | indio_dev->name = spi->modalias; | ||
120 | |||
121 | sdata->tf = &st_sensors_tf_spi; | ||
122 | sdata->get_irq_data_ready = st_sensors_spi_get_irq; | ||
123 | } | ||
124 | EXPORT_SYMBOL(st_sensors_spi_configure); | ||
125 | |||
126 | MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>"); | ||
127 | MODULE_DESCRIPTION("STMicroelectronics ST-sensors spi driver"); | ||
128 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/iio/common/st_sensors/st_sensors_trigger.c b/drivers/iio/common/st_sensors/st_sensors_trigger.c new file mode 100644 index 000000000000..139ed030abb0 --- /dev/null +++ b/drivers/iio/common/st_sensors/st_sensors_trigger.c | |||
@@ -0,0 +1,77 @@ | |||
1 | /* | ||
2 | * STMicroelectronics sensors trigger library driver | ||
3 | * | ||
4 | * Copyright 2012-2013 STMicroelectronics Inc. | ||
5 | * | ||
6 | * Denis Ciocca <denis.ciocca@st.com> | ||
7 | * | ||
8 | * Licensed under the GPL-2. | ||
9 | */ | ||
10 | |||
11 | #include <linux/kernel.h> | ||
12 | #include <linux/module.h> | ||
13 | #include <linux/slab.h> | ||
14 | #include <linux/iio/iio.h> | ||
15 | #include <linux/iio/trigger.h> | ||
16 | #include <linux/interrupt.h> | ||
17 | |||
18 | #include <linux/iio/common/st_sensors.h> | ||
19 | |||
20 | |||
21 | int st_sensors_allocate_trigger(struct iio_dev *indio_dev, | ||
22 | const struct iio_trigger_ops *trigger_ops) | ||
23 | { | ||
24 | int err; | ||
25 | struct st_sensor_data *sdata = iio_priv(indio_dev); | ||
26 | |||
27 | sdata->trig = iio_trigger_alloc("%s-trigger", indio_dev->name); | ||
28 | if (sdata->trig == NULL) { | ||
29 | err = -ENOMEM; | ||
30 | dev_err(&indio_dev->dev, "failed to allocate iio trigger.\n"); | ||
31 | goto iio_trigger_alloc_error; | ||
32 | } | ||
33 | |||
34 | err = request_threaded_irq(sdata->get_irq_data_ready(indio_dev), | ||
35 | iio_trigger_generic_data_rdy_poll, | ||
36 | NULL, | ||
37 | IRQF_TRIGGER_RISING, | ||
38 | sdata->trig->name, | ||
39 | sdata->trig); | ||
40 | if (err) | ||
41 | goto request_irq_error; | ||
42 | |||
43 | sdata->trig->private_data = indio_dev; | ||
44 | sdata->trig->ops = trigger_ops; | ||
45 | sdata->trig->dev.parent = sdata->dev; | ||
46 | |||
47 | err = iio_trigger_register(sdata->trig); | ||
48 | if (err < 0) { | ||
49 | dev_err(&indio_dev->dev, "failed to register iio trigger.\n"); | ||
50 | goto iio_trigger_register_error; | ||
51 | } | ||
52 | indio_dev->trig = sdata->trig; | ||
53 | |||
54 | return 0; | ||
55 | |||
56 | iio_trigger_register_error: | ||
57 | free_irq(sdata->get_irq_data_ready(indio_dev), sdata->trig); | ||
58 | request_irq_error: | ||
59 | iio_trigger_free(sdata->trig); | ||
60 | iio_trigger_alloc_error: | ||
61 | return err; | ||
62 | } | ||
63 | EXPORT_SYMBOL(st_sensors_allocate_trigger); | ||
64 | |||
65 | void st_sensors_deallocate_trigger(struct iio_dev *indio_dev) | ||
66 | { | ||
67 | struct st_sensor_data *sdata = iio_priv(indio_dev); | ||
68 | |||
69 | iio_trigger_unregister(sdata->trig); | ||
70 | free_irq(sdata->get_irq_data_ready(indio_dev), sdata->trig); | ||
71 | iio_trigger_free(sdata->trig); | ||
72 | } | ||
73 | EXPORT_SYMBOL(st_sensors_deallocate_trigger); | ||
74 | |||
75 | MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>"); | ||
76 | MODULE_DESCRIPTION("STMicroelectronics ST-sensors trigger"); | ||
77 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/include/linux/iio/common/st_sensors.h b/include/linux/iio/common/st_sensors.h new file mode 100644 index 000000000000..3cc85715491f --- /dev/null +++ b/include/linux/iio/common/st_sensors.h | |||
@@ -0,0 +1,274 @@ | |||
1 | /* | ||
2 | * STMicroelectronics sensors library driver | ||
3 | * | ||
4 | * Copyright 2012-2013 STMicroelectronics Inc. | ||
5 | * | ||
6 | * Denis Ciocca <denis.ciocca@st.com> | ||
7 | * | ||
8 | * Licensed under the GPL-2. | ||
9 | */ | ||
10 | |||
11 | #ifndef ST_SENSORS_H | ||
12 | #define ST_SENSORS_H | ||
13 | |||
14 | #include <linux/i2c.h> | ||
15 | #include <linux/spi/spi.h> | ||
16 | #include <linux/irqreturn.h> | ||
17 | #include <linux/iio/trigger.h> | ||
18 | |||
19 | #define ST_SENSORS_TX_MAX_LENGTH 2 | ||
20 | #define ST_SENSORS_RX_MAX_LENGTH 6 | ||
21 | |||
22 | #define ST_SENSORS_ODR_LIST_MAX 10 | ||
23 | #define ST_SENSORS_FULLSCALE_AVL_MAX 10 | ||
24 | |||
25 | #define ST_SENSORS_NUMBER_ALL_CHANNELS 4 | ||
26 | #define ST_SENSORS_NUMBER_DATA_CHANNELS 3 | ||
27 | #define ST_SENSORS_ENABLE_ALL_AXIS 0x07 | ||
28 | #define ST_SENSORS_BYTE_FOR_CHANNEL 2 | ||
29 | #define ST_SENSORS_SCAN_X 0 | ||
30 | #define ST_SENSORS_SCAN_Y 1 | ||
31 | #define ST_SENSORS_SCAN_Z 2 | ||
32 | #define ST_SENSORS_DEFAULT_12_REALBITS 12 | ||
33 | #define ST_SENSORS_DEFAULT_16_REALBITS 16 | ||
34 | #define ST_SENSORS_DEFAULT_POWER_ON_VALUE 0x01 | ||
35 | #define ST_SENSORS_DEFAULT_POWER_OFF_VALUE 0x00 | ||
36 | #define ST_SENSORS_DEFAULT_WAI_ADDRESS 0x0f | ||
37 | #define ST_SENSORS_DEFAULT_AXIS_ADDR 0x20 | ||
38 | #define ST_SENSORS_DEFAULT_AXIS_MASK 0x07 | ||
39 | #define ST_SENSORS_DEFAULT_AXIS_N_BIT 3 | ||
40 | |||
41 | #define ST_SENSORS_MAX_NAME 17 | ||
42 | #define ST_SENSORS_MAX_4WAI 7 | ||
43 | |||
44 | #define ST_SENSORS_LSM_CHANNELS(device_type, index, mod, endian, bits, addr) \ | ||
45 | { \ | ||
46 | .type = device_type, \ | ||
47 | .modified = 1, \ | ||
48 | .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \ | ||
49 | IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \ | ||
50 | .scan_index = index, \ | ||
51 | .channel2 = mod, \ | ||
52 | .address = addr, \ | ||
53 | .scan_type = { \ | ||
54 | .sign = 's', \ | ||
55 | .realbits = bits, \ | ||
56 | .shift = 16 - bits, \ | ||
57 | .storagebits = 16, \ | ||
58 | .endianness = endian, \ | ||
59 | }, \ | ||
60 | } | ||
61 | |||
62 | #define ST_SENSOR_DEV_ATTR_SAMP_FREQ() \ | ||
63 | IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO, \ | ||
64 | st_sensors_sysfs_get_sampling_frequency, \ | ||
65 | st_sensors_sysfs_set_sampling_frequency) | ||
66 | |||
67 | #define ST_SENSORS_DEV_ATTR_SAMP_FREQ_AVAIL() \ | ||
68 | IIO_DEV_ATTR_SAMP_FREQ_AVAIL( \ | ||
69 | st_sensors_sysfs_sampling_frequency_avail) | ||
70 | |||
71 | #define ST_SENSORS_DEV_ATTR_SCALE_AVAIL(name) \ | ||
72 | IIO_DEVICE_ATTR(name, S_IRUGO, \ | ||
73 | st_sensors_sysfs_scale_avail, NULL , 0); | ||
74 | |||
75 | struct st_sensor_odr_avl { | ||
76 | unsigned int hz; | ||
77 | u8 value; | ||
78 | }; | ||
79 | |||
80 | struct st_sensor_odr { | ||
81 | u8 addr; | ||
82 | u8 mask; | ||
83 | struct st_sensor_odr_avl odr_avl[ST_SENSORS_ODR_LIST_MAX]; | ||
84 | }; | ||
85 | |||
86 | struct st_sensor_power { | ||
87 | u8 addr; | ||
88 | u8 mask; | ||
89 | u8 value_off; | ||
90 | u8 value_on; | ||
91 | }; | ||
92 | |||
93 | struct st_sensor_axis { | ||
94 | u8 addr; | ||
95 | u8 mask; | ||
96 | }; | ||
97 | |||
98 | struct st_sensor_fullscale_avl { | ||
99 | unsigned int num; | ||
100 | u8 value; | ||
101 | unsigned int gain; | ||
102 | unsigned int gain2; | ||
103 | }; | ||
104 | |||
105 | struct st_sensor_fullscale { | ||
106 | u8 addr; | ||
107 | u8 mask; | ||
108 | struct st_sensor_fullscale_avl fs_avl[ST_SENSORS_FULLSCALE_AVL_MAX]; | ||
109 | }; | ||
110 | |||
111 | /** | ||
112 | * struct st_sensor_bdu - ST sensor device block data update | ||
113 | * @addr: address of the register. | ||
114 | * @mask: mask to write the block data update flag. | ||
115 | */ | ||
116 | struct st_sensor_bdu { | ||
117 | u8 addr; | ||
118 | u8 mask; | ||
119 | }; | ||
120 | |||
121 | /** | ||
122 | * struct st_sensor_data_ready_irq - ST sensor device data-ready interrupt | ||
123 | * @addr: address of the register. | ||
124 | * @mask: mask to write the on/off value. | ||
125 | * struct ig1 - represents the Interrupt Generator 1 of sensors. | ||
126 | * @en_addr: address of the enable ig1 register. | ||
127 | * @en_mask: mask to write the on/off value for enable. | ||
128 | */ | ||
129 | struct st_sensor_data_ready_irq { | ||
130 | u8 addr; | ||
131 | u8 mask; | ||
132 | struct { | ||
133 | u8 en_addr; | ||
134 | u8 en_mask; | ||
135 | } ig1; | ||
136 | }; | ||
137 | |||
138 | /** | ||
139 | * struct st_sensor_transfer_buffer - ST sensor device I/O buffer | ||
140 | * @buf_lock: Mutex to protect rx and tx buffers. | ||
141 | * @tx_buf: Buffer used by SPI transfer function to send data to the sensors. | ||
142 | * This buffer is used to avoid DMA not-aligned issue. | ||
143 | * @rx_buf: Buffer used by SPI transfer to receive data from sensors. | ||
144 | * This buffer is used to avoid DMA not-aligned issue. | ||
145 | */ | ||
146 | struct st_sensor_transfer_buffer { | ||
147 | struct mutex buf_lock; | ||
148 | u8 rx_buf[ST_SENSORS_RX_MAX_LENGTH]; | ||
149 | u8 tx_buf[ST_SENSORS_TX_MAX_LENGTH] ____cacheline_aligned; | ||
150 | }; | ||
151 | |||
152 | /** | ||
153 | * struct st_sensor_transfer_function - ST sensor device I/O function | ||
154 | * @read_byte: Function used to read one byte. | ||
155 | * @write_byte: Function used to write one byte. | ||
156 | * @read_multiple_byte: Function used to read multiple byte. | ||
157 | */ | ||
158 | struct st_sensor_transfer_function { | ||
159 | int (*read_byte) (struct st_sensor_transfer_buffer *tb, | ||
160 | struct device *dev, u8 reg_addr, u8 *res_byte); | ||
161 | int (*write_byte) (struct st_sensor_transfer_buffer *tb, | ||
162 | struct device *dev, u8 reg_addr, u8 data); | ||
163 | int (*read_multiple_byte) (struct st_sensor_transfer_buffer *tb, | ||
164 | struct device *dev, u8 reg_addr, int len, u8 *data, | ||
165 | bool multiread_bit); | ||
166 | }; | ||
167 | |||
168 | /** | ||
169 | * struct st_sensors - ST sensors list | ||
170 | * @wai: Contents of WhoAmI register. | ||
171 | * @sensors_supported: List of supported sensors by struct itself. | ||
172 | * @ch: IIO channels for the sensor. | ||
173 | * @odr: Output data rate register and ODR list available. | ||
174 | * @pw: Power register of the sensor. | ||
175 | * @enable_axis: Enable one or more axis of the sensor. | ||
176 | * @fs: Full scale register and full scale list available. | ||
177 | * @bdu: Block data update register. | ||
178 | * @drdy_irq: Data ready register of the sensor. | ||
179 | * @multi_read_bit: Use or not particular bit for [I2C/SPI] multi-read. | ||
180 | * @bootime: samples to discard when sensor passing from power-down to power-up. | ||
181 | */ | ||
182 | struct st_sensors { | ||
183 | u8 wai; | ||
184 | char sensors_supported[ST_SENSORS_MAX_4WAI][ST_SENSORS_MAX_NAME]; | ||
185 | struct iio_chan_spec *ch; | ||
186 | struct st_sensor_odr odr; | ||
187 | struct st_sensor_power pw; | ||
188 | struct st_sensor_axis enable_axis; | ||
189 | struct st_sensor_fullscale fs; | ||
190 | struct st_sensor_bdu bdu; | ||
191 | struct st_sensor_data_ready_irq drdy_irq; | ||
192 | bool multi_read_bit; | ||
193 | unsigned int bootime; | ||
194 | }; | ||
195 | |||
196 | /** | ||
197 | * struct st_sensor_data - ST sensor device status | ||
198 | * @dev: Pointer to instance of struct device (I2C or SPI). | ||
199 | * @trig: The trigger in use by the core driver. | ||
200 | * @sensor: Pointer to the current sensor struct in use. | ||
201 | * @current_fullscale: Maximum range of measure by the sensor. | ||
202 | * @enabled: Status of the sensor (false->off, true->on). | ||
203 | * @multiread_bit: Use or not particular bit for [I2C/SPI] multiread. | ||
204 | * @buffer_data: Data used by buffer part. | ||
205 | * @odr: Output data rate of the sensor [Hz]. | ||
206 | * @get_irq_data_ready: Function to get the IRQ used for data ready signal. | ||
207 | * @tf: Transfer function structure used by I/O operations. | ||
208 | * @tb: Transfer buffers and mutex used by I/O operations. | ||
209 | */ | ||
210 | struct st_sensor_data { | ||
211 | struct device *dev; | ||
212 | struct iio_trigger *trig; | ||
213 | struct st_sensors *sensor; | ||
214 | struct st_sensor_fullscale_avl *current_fullscale; | ||
215 | |||
216 | bool enabled; | ||
217 | bool multiread_bit; | ||
218 | |||
219 | char *buffer_data; | ||
220 | |||
221 | unsigned int odr; | ||
222 | |||
223 | unsigned int (*get_irq_data_ready) (struct iio_dev *indio_dev); | ||
224 | |||
225 | const struct st_sensor_transfer_function *tf; | ||
226 | struct st_sensor_transfer_buffer tb; | ||
227 | }; | ||
228 | |||
229 | #ifdef CONFIG_IIO_BUFFER | ||
230 | int st_sensors_allocate_trigger(struct iio_dev *indio_dev, | ||
231 | const struct iio_trigger_ops *trigger_ops); | ||
232 | |||
233 | void st_sensors_deallocate_trigger(struct iio_dev *indio_dev); | ||
234 | |||
235 | irqreturn_t st_sensors_trigger_handler(int irq, void *p); | ||
236 | |||
237 | int st_sensors_get_buffer_element(struct iio_dev *indio_dev, u8 *buf); | ||
238 | #endif | ||
239 | |||
240 | int st_sensors_init_sensor(struct iio_dev *indio_dev); | ||
241 | |||
242 | int st_sensors_set_enable(struct iio_dev *indio_dev, bool enable); | ||
243 | |||
244 | int st_sensors_set_axis_enable(struct iio_dev *indio_dev, u8 axis_enable); | ||
245 | |||
246 | int st_sensors_get_sampling_frequency_avl(struct iio_dev *indio_dev, char *buf); | ||
247 | |||
248 | int st_sensors_get_scale_avl(struct iio_dev *indio_dev, char *buf); | ||
249 | |||
250 | int st_sensors_set_odr(struct iio_dev *indio_dev, unsigned int odr); | ||
251 | |||
252 | int st_sensors_set_dataready_irq(struct iio_dev *indio_dev, bool enable); | ||
253 | |||
254 | int st_sensors_set_fullscale_by_gain(struct iio_dev *indio_dev, int scale); | ||
255 | |||
256 | int st_sensors_read_info_raw(struct iio_dev *indio_dev, | ||
257 | struct iio_chan_spec const *ch, int *val); | ||
258 | |||
259 | int st_sensors_check_device_support(struct iio_dev *indio_dev, | ||
260 | int num_sensors_list, const struct st_sensors *sensors); | ||
261 | |||
262 | ssize_t st_sensors_sysfs_get_sampling_frequency(struct device *dev, | ||
263 | struct device_attribute *attr, char *buf); | ||
264 | |||
265 | ssize_t st_sensors_sysfs_set_sampling_frequency(struct device *dev, | ||
266 | struct device_attribute *attr, const char *buf, size_t size); | ||
267 | |||
268 | ssize_t st_sensors_sysfs_sampling_frequency_avail(struct device *dev, | ||
269 | struct device_attribute *attr, char *buf); | ||
270 | |||
271 | ssize_t st_sensors_sysfs_scale_avail(struct device *dev, | ||
272 | struct device_attribute *attr, char *buf); | ||
273 | |||
274 | #endif /* ST_SENSORS_H */ | ||
diff --git a/include/linux/iio/common/st_sensors_i2c.h b/include/linux/iio/common/st_sensors_i2c.h new file mode 100644 index 000000000000..67d845385ae2 --- /dev/null +++ b/include/linux/iio/common/st_sensors_i2c.h | |||
@@ -0,0 +1,20 @@ | |||
1 | /* | ||
2 | * STMicroelectronics sensors i2c library driver | ||
3 | * | ||
4 | * Copyright 2012-2013 STMicroelectronics Inc. | ||
5 | * | ||
6 | * Denis Ciocca <denis.ciocca@st.com> | ||
7 | * | ||
8 | * Licensed under the GPL-2. | ||
9 | */ | ||
10 | |||
11 | #ifndef ST_SENSORS_I2C_H | ||
12 | #define ST_SENSORS_I2C_H | ||
13 | |||
14 | #include <linux/i2c.h> | ||
15 | #include <linux/iio/common/st_sensors.h> | ||
16 | |||
17 | void st_sensors_i2c_configure(struct iio_dev *indio_dev, | ||
18 | struct i2c_client *client, struct st_sensor_data *sdata); | ||
19 | |||
20 | #endif /* ST_SENSORS_I2C_H */ | ||
diff --git a/include/linux/iio/common/st_sensors_spi.h b/include/linux/iio/common/st_sensors_spi.h new file mode 100644 index 000000000000..d964a3563dc6 --- /dev/null +++ b/include/linux/iio/common/st_sensors_spi.h | |||
@@ -0,0 +1,20 @@ | |||
1 | /* | ||
2 | * STMicroelectronics sensors spi library driver | ||
3 | * | ||
4 | * Copyright 2012-2013 STMicroelectronics Inc. | ||
5 | * | ||
6 | * Denis Ciocca <denis.ciocca@st.com> | ||
7 | * | ||
8 | * Licensed under the GPL-2. | ||
9 | */ | ||
10 | |||
11 | #ifndef ST_SENSORS_SPI_H | ||
12 | #define ST_SENSORS_SPI_H | ||
13 | |||
14 | #include <linux/spi/spi.h> | ||
15 | #include <linux/iio/common/st_sensors.h> | ||
16 | |||
17 | void st_sensors_spi_configure(struct iio_dev *indio_dev, | ||
18 | struct spi_device *spi, struct st_sensor_data *sdata); | ||
19 | |||
20 | #endif /* ST_SENSORS_SPI_H */ | ||