diff options
author | Tiberiu Breana <tiberiu.a.breana@intel.com> | 2016-05-16 07:58:23 -0400 |
---|---|---|
committer | Jonathan Cameron <jic23@kernel.org> | 2016-05-21 15:06:50 -0400 |
commit | 194dc4c714132a63a7a731fe4debeccbdfab13e1 (patch) | |
tree | 4cf7bfca5467c807d14c81497f16cacd9151f569 /drivers/iio | |
parent | ba35f111aa6f386df33f950aeaea53a2bf040cc2 (diff) |
iio: accel: Add triggered buffer support for BMA220
Signed-off-by: Tiberiu Breana <tiberiu.a.breana@intel.com>
Signed-off-by: Jonathan Cameron <jic23@kernel.org>
Diffstat (limited to 'drivers/iio')
-rw-r--r-- | drivers/iio/accel/bma220_spi.c | 65 |
1 files changed, 63 insertions, 2 deletions
diff --git a/drivers/iio/accel/bma220_spi.c b/drivers/iio/accel/bma220_spi.c index 7343575e84ba..1098d10df8e8 100644 --- a/drivers/iio/accel/bma220_spi.c +++ b/drivers/iio/accel/bma220_spi.c | |||
@@ -11,9 +11,12 @@ | |||
11 | #include <linux/acpi.h> | 11 | #include <linux/acpi.h> |
12 | #include <linux/kernel.h> | 12 | #include <linux/kernel.h> |
13 | #include <linux/module.h> | 13 | #include <linux/module.h> |
14 | #include <linux/iio/buffer.h> | ||
14 | #include <linux/iio/iio.h> | 15 | #include <linux/iio/iio.h> |
15 | #include <linux/iio/sysfs.h> | 16 | #include <linux/iio/sysfs.h> |
16 | #include <linux/spi/spi.h> | 17 | #include <linux/spi/spi.h> |
18 | #include <linux/iio/trigger_consumer.h> | ||
19 | #include <linux/iio/triggered_buffer.h> | ||
17 | 20 | ||
18 | #define BMA220_REG_ID 0x00 | 21 | #define BMA220_REG_ID 0x00 |
19 | #define BMA220_REG_ACCEL_X 0x02 | 22 | #define BMA220_REG_ACCEL_X 0x02 |
@@ -39,8 +42,22 @@ | |||
39 | .channel2 = IIO_MOD_##axis, \ | 42 | .channel2 = IIO_MOD_##axis, \ |
40 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ | 43 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ |
41 | .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ | 44 | .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ |
45 | .scan_index = index, \ | ||
46 | .scan_type = { \ | ||
47 | .sign = 's', \ | ||
48 | .realbits = 6, \ | ||
49 | .storagebits = 8, \ | ||
50 | .shift = BMA220_DATA_SHIFT, \ | ||
51 | .endianness = IIO_CPU, \ | ||
52 | }, \ | ||
42 | } | 53 | } |
43 | 54 | ||
55 | enum bma220_axis { | ||
56 | AXIS_X, | ||
57 | AXIS_Y, | ||
58 | AXIS_Z, | ||
59 | }; | ||
60 | |||
44 | static IIO_CONST_ATTR(in_accel_scale_available, BMA220_SCALE_AVAILABLE); | 61 | static IIO_CONST_ATTR(in_accel_scale_available, BMA220_SCALE_AVAILABLE); |
45 | 62 | ||
46 | static struct attribute *bma220_attributes[] = { | 63 | static struct attribute *bma220_attributes[] = { |
@@ -59,6 +76,7 @@ static const int bma220_scale_table[][4] = { | |||
59 | struct bma220_data { | 76 | struct bma220_data { |
60 | struct spi_device *spi_device; | 77 | struct spi_device *spi_device; |
61 | struct mutex lock; | 78 | struct mutex lock; |
79 | s8 buffer[16]; /* 3x8-bit channels + 5x8 padding + 8x8 timestamp */ | ||
62 | u8 tx_buf[2] ____cacheline_aligned; | 80 | u8 tx_buf[2] ____cacheline_aligned; |
63 | }; | 81 | }; |
64 | 82 | ||
@@ -66,6 +84,7 @@ static const struct iio_chan_spec bma220_channels[] = { | |||
66 | BMA220_ACCEL_CHANNEL(0, BMA220_REG_ACCEL_X, X), | 84 | BMA220_ACCEL_CHANNEL(0, BMA220_REG_ACCEL_X, X), |
67 | BMA220_ACCEL_CHANNEL(1, BMA220_REG_ACCEL_Y, Y), | 85 | BMA220_ACCEL_CHANNEL(1, BMA220_REG_ACCEL_Y, Y), |
68 | BMA220_ACCEL_CHANNEL(2, BMA220_REG_ACCEL_Z, Z), | 86 | BMA220_ACCEL_CHANNEL(2, BMA220_REG_ACCEL_Z, Z), |
87 | IIO_CHAN_SOFT_TIMESTAMP(3), | ||
69 | }; | 88 | }; |
70 | 89 | ||
71 | static inline int bma220_read_reg(struct spi_device *spi, u8 reg) | 90 | static inline int bma220_read_reg(struct spi_device *spi, u8 reg) |
@@ -73,6 +92,35 @@ static inline int bma220_read_reg(struct spi_device *spi, u8 reg) | |||
73 | return spi_w8r8(spi, reg | BMA220_READ_MASK); | 92 | return spi_w8r8(spi, reg | BMA220_READ_MASK); |
74 | } | 93 | } |
75 | 94 | ||
95 | static const unsigned long bma220_accel_scan_masks[] = { | ||
96 | BIT(AXIS_X) | BIT(AXIS_Y) | BIT(AXIS_Z), | ||
97 | 0 | ||
98 | }; | ||
99 | |||
100 | static irqreturn_t bma220_trigger_handler(int irq, void *p) | ||
101 | { | ||
102 | int ret; | ||
103 | struct iio_poll_func *pf = p; | ||
104 | struct iio_dev *indio_dev = pf->indio_dev; | ||
105 | struct bma220_data *data = iio_priv(indio_dev); | ||
106 | struct spi_device *spi = data->spi_device; | ||
107 | |||
108 | mutex_lock(&data->lock); | ||
109 | data->tx_buf[0] = BMA220_REG_ACCEL_X | BMA220_READ_MASK; | ||
110 | ret = spi_write_then_read(spi, data->tx_buf, 1, data->buffer, | ||
111 | ARRAY_SIZE(bma220_channels) - 1); | ||
112 | if (ret < 0) | ||
113 | goto err; | ||
114 | |||
115 | iio_push_to_buffers_with_timestamp(indio_dev, data->buffer, | ||
116 | pf->timestamp); | ||
117 | err: | ||
118 | mutex_unlock(&data->lock); | ||
119 | iio_trigger_notify_done(indio_dev->trig); | ||
120 | |||
121 | return IRQ_HANDLED; | ||
122 | } | ||
123 | |||
76 | static int bma220_read_raw(struct iio_dev *indio_dev, | 124 | static int bma220_read_raw(struct iio_dev *indio_dev, |
77 | struct iio_chan_spec const *chan, | 125 | struct iio_chan_spec const *chan, |
78 | int *val, int *val2, long mask) | 126 | int *val, int *val2, long mask) |
@@ -199,18 +247,30 @@ static int bma220_probe(struct spi_device *spi) | |||
199 | indio_dev->modes = INDIO_DIRECT_MODE; | 247 | indio_dev->modes = INDIO_DIRECT_MODE; |
200 | indio_dev->channels = bma220_channels; | 248 | indio_dev->channels = bma220_channels; |
201 | indio_dev->num_channels = ARRAY_SIZE(bma220_channels); | 249 | indio_dev->num_channels = ARRAY_SIZE(bma220_channels); |
250 | indio_dev->available_scan_masks = bma220_accel_scan_masks; | ||
202 | 251 | ||
203 | ret = bma220_init(data->spi_device); | 252 | ret = bma220_init(data->spi_device); |
204 | if (ret < 0) | 253 | if (ret < 0) |
205 | return ret; | 254 | return ret; |
206 | 255 | ||
256 | ret = iio_triggered_buffer_setup(indio_dev, NULL, | ||
257 | bma220_trigger_handler, NULL); | ||
258 | if (ret < 0) { | ||
259 | dev_err(&spi->dev, "iio triggered buffer setup failed\n"); | ||
260 | goto err_suspend; | ||
261 | } | ||
262 | |||
207 | ret = iio_device_register(indio_dev); | 263 | ret = iio_device_register(indio_dev); |
208 | if (ret < 0) { | 264 | if (ret < 0) { |
209 | dev_err(&spi->dev, "iio_device_register failed\n"); | 265 | dev_err(&spi->dev, "iio_device_register failed\n"); |
210 | return bma220_deinit(spi); | 266 | iio_triggered_buffer_cleanup(indio_dev); |
267 | goto err_suspend; | ||
211 | } | 268 | } |
212 | 269 | ||
213 | return ret; | 270 | return 0; |
271 | |||
272 | err_suspend: | ||
273 | return bma220_deinit(spi); | ||
214 | } | 274 | } |
215 | 275 | ||
216 | static int bma220_remove(struct spi_device *spi) | 276 | static int bma220_remove(struct spi_device *spi) |
@@ -218,6 +278,7 @@ static int bma220_remove(struct spi_device *spi) | |||
218 | struct iio_dev *indio_dev = spi_get_drvdata(spi); | 278 | struct iio_dev *indio_dev = spi_get_drvdata(spi); |
219 | 279 | ||
220 | iio_device_unregister(indio_dev); | 280 | iio_device_unregister(indio_dev); |
281 | iio_triggered_buffer_cleanup(indio_dev); | ||
221 | 282 | ||
222 | return bma220_deinit(spi); | 283 | return bma220_deinit(spi); |
223 | } | 284 | } |