aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/iio
diff options
context:
space:
mode:
authorLinus Walleij <linus.walleij@linaro.org>2016-09-01 05:44:44 -0400
committerJonathan Cameron <jic23@kernel.org>2016-09-18 06:32:15 -0400
commit0427a106a98adf94b53cc88607ceabc2ecebd2cc (patch)
tree2c5680c62e137e639da1dea434469d1f26c3628d /drivers/iio
parent84e2f6f9583f195b9851a8f6340bb526749ea609 (diff)
iio: accel: kxsd9: Add triggered buffer handling
As is custom with all modern sensors, add a clever burst mode that will just stream out values from the sensor and provide it to userspace to do the proper offsetting and scaling. This is the result when tested with an HRTimer trigger: $ generic_buffer -a -c 10 -n kxsd9 -t foo /sys/bus/iio/devices/iio:device1 foo 0.371318 0.718680 9.869872 1795.000000 97545896129 -0.586922 0.179670 9.378775 2398.000000 97555864721 -0.299450 0.179670 10.348992 2672.000000 97565874055 0.371318 0.335384 11.103606 2816.000000 97575883240 0.179670 0.574944 10.540640 2847.000000 97585862351 0.335384 0.754614 9.953718 2840.000000 97595872425 0.179670 0.754614 10.732288 2879.000000 97605882351 0.000000 0.754614 10.348992 2872.000000 97615891832 -0.730658 0.574944 9.570422 2831.000000 97625871536 0.000000 1.137910 10.732288 2872.000000 97635881610 Columns shown are x, y, z acceleration, so a positive acceleration of ~9.81 (shaky due to bad calibration) along the z axis. The fourth column is the AUX IN which is floating on this system, it seems to float up to the 2.85V VDD voltage. To be able to cleanup the triggered buffer, we need to add .remove() callbacks to the I2C and SPI subdrivers and call back into an exported .remove() callback in the core. Signed-off-by: Linus Walleij <linus.walleij@linaro.org> Tested-by: Jonathan Cameron <jic23@kernel.org> Signed-off-by: Jonathan Cameron <jic23@kernel.org>
Diffstat (limited to 'drivers/iio')
-rw-r--r--drivers/iio/accel/Kconfig2
-rw-r--r--drivers/iio/accel/kxsd9.c82
2 files changed, 78 insertions, 6 deletions
diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig
index 8824400d4911..a8e9ed47bbb4 100644
--- a/drivers/iio/accel/Kconfig
+++ b/drivers/iio/accel/Kconfig
@@ -119,6 +119,8 @@ config IIO_ST_ACCEL_SPI_3AXIS
119 119
120config KXSD9 120config KXSD9
121 tristate "Kionix KXSD9 Accelerometer Driver" 121 tristate "Kionix KXSD9 Accelerometer Driver"
122 select IIO_BUFFER
123 select IIO_TRIGGERED_BUFFER
122 help 124 help
123 Say yes here to build support for the Kionix KXSD9 accelerometer. 125 Say yes here to build support for the Kionix KXSD9 accelerometer.
124 It can be accessed using an (optional) SPI or I2C interface. 126 It can be accessed using an (optional) SPI or I2C interface.
diff --git a/drivers/iio/accel/kxsd9.c b/drivers/iio/accel/kxsd9.c
index 6a1e67723d0c..d84413ae14b1 100644
--- a/drivers/iio/accel/kxsd9.c
+++ b/drivers/iio/accel/kxsd9.c
@@ -12,8 +12,6 @@
12 * I have a suitable wire made up. 12 * I have a suitable wire made up.
13 * 13 *
14 * TODO: Support the motion detector 14 * TODO: Support the motion detector
15 * Uses register address incrementing so could have a
16 * heavily optimized ring buffer access function.
17 */ 15 */
18 16
19#include <linux/device.h> 17#include <linux/device.h>
@@ -24,6 +22,9 @@
24#include <linux/regmap.h> 22#include <linux/regmap.h>
25#include <linux/iio/iio.h> 23#include <linux/iio/iio.h>
26#include <linux/iio/sysfs.h> 24#include <linux/iio/sysfs.h>
25#include <linux/iio/buffer.h>
26#include <linux/iio/triggered_buffer.h>
27#include <linux/iio/trigger_consumer.h>
27 28
28#include "kxsd9.h" 29#include "kxsd9.h"
29 30
@@ -41,9 +42,11 @@
41 42
42/** 43/**
43 * struct kxsd9_state - device related storage 44 * struct kxsd9_state - device related storage
45 * @dev: pointer to the parent device
44 * @map: regmap to the device 46 * @map: regmap to the device
45 */ 47 */
46struct kxsd9_state { 48struct kxsd9_state {
49 struct device *dev;
47 struct regmap *map; 50 struct regmap *map;
48}; 51};
49 52
@@ -155,7 +158,35 @@ static int kxsd9_read_raw(struct iio_dev *indio_dev,
155error_ret: 158error_ret:
156 return ret; 159 return ret;
157}; 160};
158#define KXSD9_ACCEL_CHAN(axis) \ 161
162static irqreturn_t kxsd9_trigger_handler(int irq, void *p)
163{
164 const struct iio_poll_func *pf = p;
165 struct iio_dev *indio_dev = pf->indio_dev;
166 struct kxsd9_state *st = iio_priv(indio_dev);
167 int ret;
168 /* 4 * 16bit values AND timestamp */
169 __be16 hw_values[8];
170
171 ret = regmap_bulk_read(st->map,
172 KXSD9_REG_X,
173 &hw_values,
174 8);
175 if (ret) {
176 dev_err(st->dev,
177 "error reading data\n");
178 return ret;
179 }
180
181 iio_push_to_buffers_with_timestamp(indio_dev,
182 hw_values,
183 iio_get_time_ns(indio_dev));
184 iio_trigger_notify_done(indio_dev->trig);
185
186 return IRQ_HANDLED;
187}
188
189#define KXSD9_ACCEL_CHAN(axis, index) \
159 { \ 190 { \
160 .type = IIO_ACCEL, \ 191 .type = IIO_ACCEL, \
161 .modified = 1, \ 192 .modified = 1, \
@@ -164,16 +195,35 @@ error_ret:
164 .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \ 195 .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
165 BIT(IIO_CHAN_INFO_OFFSET), \ 196 BIT(IIO_CHAN_INFO_OFFSET), \
166 .address = KXSD9_REG_##axis, \ 197 .address = KXSD9_REG_##axis, \
198 .scan_index = index, \
199 .scan_type = { \
200 .sign = 'u', \
201 .realbits = 12, \
202 .storagebits = 16, \
203 .shift = 4, \
204 .endianness = IIO_BE, \
205 }, \
167 } 206 }
168 207
169static const struct iio_chan_spec kxsd9_channels[] = { 208static const struct iio_chan_spec kxsd9_channels[] = {
170 KXSD9_ACCEL_CHAN(X), KXSD9_ACCEL_CHAN(Y), KXSD9_ACCEL_CHAN(Z), 209 KXSD9_ACCEL_CHAN(X, 0),
210 KXSD9_ACCEL_CHAN(Y, 1),
211 KXSD9_ACCEL_CHAN(Z, 2),
171 { 212 {
172 .type = IIO_VOLTAGE, 213 .type = IIO_VOLTAGE,
173 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), 214 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
174 .indexed = 1, 215 .indexed = 1,
175 .address = KXSD9_REG_AUX, 216 .address = KXSD9_REG_AUX,
176 } 217 .scan_index = 3,
218 .scan_type = {
219 .sign = 'u',
220 .realbits = 12,
221 .storagebits = 16,
222 .shift = 4,
223 .endianness = IIO_BE,
224 },
225 },
226 IIO_CHAN_SOFT_TIMESTAMP(4),
177}; 227};
178 228
179static const struct attribute_group kxsd9_attribute_group = { 229static const struct attribute_group kxsd9_attribute_group = {
@@ -197,6 +247,9 @@ static const struct iio_info kxsd9_info = {
197 .driver_module = THIS_MODULE, 247 .driver_module = THIS_MODULE,
198}; 248};
199 249
250/* Four channels apart from timestamp, scan mask = 0x0f */
251static const unsigned long kxsd9_scan_masks[] = { 0xf, 0 };
252
200int kxsd9_common_probe(struct device *parent, 253int kxsd9_common_probe(struct device *parent,
201 struct regmap *map, 254 struct regmap *map,
202 const char *name) 255 const char *name)
@@ -210,6 +263,7 @@ int kxsd9_common_probe(struct device *parent,
210 return -ENOMEM; 263 return -ENOMEM;
211 264
212 st = iio_priv(indio_dev); 265 st = iio_priv(indio_dev);
266 st->dev = parent;
213 st->map = map; 267 st->map = map;
214 268
215 indio_dev->channels = kxsd9_channels; 269 indio_dev->channels = kxsd9_channels;
@@ -218,16 +272,31 @@ int kxsd9_common_probe(struct device *parent,
218 indio_dev->dev.parent = parent; 272 indio_dev->dev.parent = parent;
219 indio_dev->info = &kxsd9_info; 273 indio_dev->info = &kxsd9_info;
220 indio_dev->modes = INDIO_DIRECT_MODE; 274 indio_dev->modes = INDIO_DIRECT_MODE;
275 indio_dev->available_scan_masks = kxsd9_scan_masks;
221 276
222 kxsd9_power_up(st); 277 kxsd9_power_up(st);
223 278
279 ret = iio_triggered_buffer_setup(indio_dev,
280 iio_pollfunc_store_time,
281 kxsd9_trigger_handler,
282 NULL);
283 if (ret) {
284 dev_err(parent, "triggered buffer setup failed\n");
285 return ret;
286 }
287
224 ret = iio_device_register(indio_dev); 288 ret = iio_device_register(indio_dev);
225 if (ret) 289 if (ret)
226 return ret; 290 goto err_cleanup_buffer;
227 291
228 dev_set_drvdata(parent, indio_dev); 292 dev_set_drvdata(parent, indio_dev);
229 293
230 return 0; 294 return 0;
295
296err_cleanup_buffer:
297 iio_triggered_buffer_cleanup(indio_dev);
298
299 return ret;
231} 300}
232EXPORT_SYMBOL(kxsd9_common_probe); 301EXPORT_SYMBOL(kxsd9_common_probe);
233 302
@@ -235,6 +304,7 @@ int kxsd9_common_remove(struct device *parent)
235{ 304{
236 struct iio_dev *indio_dev = dev_get_drvdata(parent); 305 struct iio_dev *indio_dev = dev_get_drvdata(parent);
237 306
307 iio_triggered_buffer_cleanup(indio_dev);
238 iio_device_unregister(indio_dev); 308 iio_device_unregister(indio_dev);
239 309
240 return 0; 310 return 0;