diff options
author | Teodora Baluta <teodora.baluta@intel.com> | 2015-08-20 10:37:32 -0400 |
---|---|---|
committer | Jonathan Cameron <jic23@kernel.org> | 2015-08-31 12:36:56 -0400 |
commit | 1ce0eda0f75747b3131a9047aee19291f59c18c9 (patch) | |
tree | f615ac8bb863037d7741408dc38b13cac40a9c9a | |
parent | 077377fc4f74899c58e946e47352216412d0bb3a (diff) |
iio: mxc4005: add triggered buffer mode for mxc4005
This patch adds support for buffered readings for the 3-axis
accelerometer mxc4005.
Signed-off-by: Teodora Baluta <teodora.baluta@intel.com>
Signed-off-by: Jonathan Cameron <jic23@kernel.org>
-rw-r--r-- | drivers/iio/accel/Kconfig | 2 | ||||
-rw-r--r-- | drivers/iio/accel/mxc4005.c | 79 |
2 files changed, 78 insertions, 3 deletions
diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig index 69302bed2860..cd5cd246792d 100644 --- a/drivers/iio/accel/Kconfig +++ b/drivers/iio/accel/Kconfig | |||
@@ -140,6 +140,8 @@ config MMA9553 | |||
140 | config MXC4005 | 140 | config MXC4005 |
141 | tristate "Memsic MXC4005XC 3-Axis Accelerometer Driver" | 141 | tristate "Memsic MXC4005XC 3-Axis Accelerometer Driver" |
142 | depends on I2C | 142 | depends on I2C |
143 | select IIO_BUFFER | ||
144 | select IIO_TRIGGERED_BUFFER | ||
143 | select REGMAP_I2C | 145 | select REGMAP_I2C |
144 | help | 146 | help |
145 | Say yes here to build support for the Memsic MXC4005XC 3-axis | 147 | Say yes here to build support for the Memsic MXC4005XC 3-axis |
diff --git a/drivers/iio/accel/mxc4005.c b/drivers/iio/accel/mxc4005.c index e15c1bd26bd1..390eaf8cb2f8 100644 --- a/drivers/iio/accel/mxc4005.c +++ b/drivers/iio/accel/mxc4005.c | |||
@@ -19,6 +19,9 @@ | |||
19 | #include <linux/acpi.h> | 19 | #include <linux/acpi.h> |
20 | #include <linux/regmap.h> | 20 | #include <linux/regmap.h> |
21 | #include <linux/iio/sysfs.h> | 21 | #include <linux/iio/sysfs.h> |
22 | #include <linux/iio/buffer.h> | ||
23 | #include <linux/iio/triggered_buffer.h> | ||
24 | #include <linux/iio/trigger_consumer.h> | ||
22 | 25 | ||
23 | #define MXC4005_DRV_NAME "mxc4005" | 26 | #define MXC4005_DRV_NAME "mxc4005" |
24 | #define MXC4005_REGMAP_NAME "mxc4005_regmap" | 27 | #define MXC4005_REGMAP_NAME "mxc4005_regmap" |
@@ -52,6 +55,7 @@ struct mxc4005_data { | |||
52 | struct device *dev; | 55 | struct device *dev; |
53 | struct mutex mutex; | 56 | struct mutex mutex; |
54 | struct regmap *regmap; | 57 | struct regmap *regmap; |
58 | __be16 buffer[8]; | ||
55 | }; | 59 | }; |
56 | 60 | ||
57 | /* | 61 | /* |
@@ -122,6 +126,20 @@ static const struct regmap_config mxc4005_regmap_config = { | |||
122 | .writeable_reg = mxc4005_is_writeable_reg, | 126 | .writeable_reg = mxc4005_is_writeable_reg, |
123 | }; | 127 | }; |
124 | 128 | ||
129 | static int mxc4005_read_xyz(struct mxc4005_data *data) | ||
130 | { | ||
131 | int ret; | ||
132 | |||
133 | ret = regmap_bulk_read(data->regmap, MXC4005_REG_XOUT_UPPER, | ||
134 | (u8 *) data->buffer, sizeof(data->buffer)); | ||
135 | if (ret < 0) { | ||
136 | dev_err(data->dev, "failed to read axes\n"); | ||
137 | return ret; | ||
138 | } | ||
139 | |||
140 | return 0; | ||
141 | } | ||
142 | |||
125 | static int mxc4005_read_axis(struct mxc4005_data *data, | 143 | static int mxc4005_read_axis(struct mxc4005_data *data, |
126 | unsigned int addr) | 144 | unsigned int addr) |
127 | { | 145 | { |
@@ -197,7 +215,8 @@ static int mxc4005_read_raw(struct iio_dev *indio_dev, | |||
197 | ret = mxc4005_read_axis(data, chan->address); | 215 | ret = mxc4005_read_axis(data, chan->address); |
198 | if (ret < 0) | 216 | if (ret < 0) |
199 | return ret; | 217 | return ret; |
200 | *val = sign_extend32(ret >> 4, 11); | 218 | *val = sign_extend32(ret >> chan->scan_type.shift, |
219 | chan->scan_type.realbits - 1); | ||
201 | return IIO_VAL_INT; | 220 | return IIO_VAL_INT; |
202 | default: | 221 | default: |
203 | return -EINVAL; | 222 | return -EINVAL; |
@@ -239,6 +258,11 @@ static const struct iio_info mxc4005_info = { | |||
239 | .attrs = &mxc4005_attrs_group, | 258 | .attrs = &mxc4005_attrs_group, |
240 | }; | 259 | }; |
241 | 260 | ||
261 | static const unsigned long mxc4005_scan_masks[] = { | ||
262 | BIT(AXIS_X) | BIT(AXIS_Y) | BIT(AXIS_Z), | ||
263 | 0 | ||
264 | }; | ||
265 | |||
242 | #define MXC4005_CHANNEL(_axis, _addr) { \ | 266 | #define MXC4005_CHANNEL(_axis, _addr) { \ |
243 | .type = IIO_ACCEL, \ | 267 | .type = IIO_ACCEL, \ |
244 | .modified = 1, \ | 268 | .modified = 1, \ |
@@ -246,14 +270,43 @@ static const struct iio_info mxc4005_info = { | |||
246 | .address = _addr, \ | 270 | .address = _addr, \ |
247 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ | 271 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ |
248 | .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ | 272 | .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ |
273 | .scan_index = AXIS_##_axis, \ | ||
274 | .scan_type = { \ | ||
275 | .sign = 's', \ | ||
276 | .realbits = 12, \ | ||
277 | .storagebits = 16, \ | ||
278 | .shift = 4, \ | ||
279 | .endianness = IIO_BE, \ | ||
280 | }, \ | ||
249 | } | 281 | } |
250 | 282 | ||
251 | static const struct iio_chan_spec mxc4005_channels[] = { | 283 | static const struct iio_chan_spec mxc4005_channels[] = { |
252 | MXC4005_CHANNEL(X, MXC4005_REG_XOUT_UPPER), | 284 | MXC4005_CHANNEL(X, MXC4005_REG_XOUT_UPPER), |
253 | MXC4005_CHANNEL(Y, MXC4005_REG_YOUT_UPPER), | 285 | MXC4005_CHANNEL(Y, MXC4005_REG_YOUT_UPPER), |
254 | MXC4005_CHANNEL(Z, MXC4005_REG_ZOUT_UPPER), | 286 | MXC4005_CHANNEL(Z, MXC4005_REG_ZOUT_UPPER), |
287 | IIO_CHAN_SOFT_TIMESTAMP(3), | ||
255 | }; | 288 | }; |
256 | 289 | ||
290 | static irqreturn_t mxc4005_trigger_handler(int irq, void *private) | ||
291 | { | ||
292 | struct iio_poll_func *pf = private; | ||
293 | struct iio_dev *indio_dev = pf->indio_dev; | ||
294 | struct mxc4005_data *data = iio_priv(indio_dev); | ||
295 | int ret; | ||
296 | |||
297 | ret = mxc4005_read_xyz(data); | ||
298 | if (ret < 0) | ||
299 | goto err; | ||
300 | |||
301 | iio_push_to_buffers_with_timestamp(indio_dev, data->buffer, | ||
302 | pf->timestamp); | ||
303 | |||
304 | err: | ||
305 | iio_trigger_notify_done(indio_dev->trig); | ||
306 | |||
307 | return IRQ_HANDLED; | ||
308 | } | ||
309 | |||
257 | static int mxc4005_chip_init(struct mxc4005_data *data) | 310 | static int mxc4005_chip_init(struct mxc4005_data *data) |
258 | { | 311 | { |
259 | int ret; | 312 | int ret; |
@@ -304,23 +357,43 @@ static int mxc4005_probe(struct i2c_client *client, | |||
304 | indio_dev->dev.parent = &client->dev; | 357 | indio_dev->dev.parent = &client->dev; |
305 | indio_dev->channels = mxc4005_channels; | 358 | indio_dev->channels = mxc4005_channels; |
306 | indio_dev->num_channels = ARRAY_SIZE(mxc4005_channels); | 359 | indio_dev->num_channels = ARRAY_SIZE(mxc4005_channels); |
360 | indio_dev->available_scan_masks = mxc4005_scan_masks; | ||
307 | indio_dev->name = MXC4005_DRV_NAME; | 361 | indio_dev->name = MXC4005_DRV_NAME; |
308 | indio_dev->modes = INDIO_DIRECT_MODE; | 362 | indio_dev->modes = INDIO_DIRECT_MODE; |
309 | indio_dev->info = &mxc4005_info; | 363 | indio_dev->info = &mxc4005_info; |
310 | 364 | ||
365 | ret = iio_triggered_buffer_setup(indio_dev, | ||
366 | &iio_pollfunc_store_time, | ||
367 | mxc4005_trigger_handler, | ||
368 | NULL); | ||
369 | if (ret < 0) { | ||
370 | dev_err(&client->dev, | ||
371 | "failed to setup iio triggered buffer\n"); | ||
372 | return ret; | ||
373 | } | ||
374 | |||
311 | ret = iio_device_register(indio_dev); | 375 | ret = iio_device_register(indio_dev); |
312 | if (ret < 0) { | 376 | if (ret < 0) { |
313 | dev_err(&client->dev, | 377 | dev_err(&client->dev, |
314 | "unable to register iio device %d\n", ret); | 378 | "unable to register iio device %d\n", ret); |
315 | return ret; | 379 | goto err_buffer_cleanup; |
316 | } | 380 | } |
317 | 381 | ||
318 | return 0; | 382 | return 0; |
383 | |||
384 | err_buffer_cleanup: | ||
385 | iio_triggered_buffer_cleanup(indio_dev); | ||
386 | |||
387 | return ret; | ||
319 | } | 388 | } |
320 | 389 | ||
321 | static int mxc4005_remove(struct i2c_client *client) | 390 | static int mxc4005_remove(struct i2c_client *client) |
322 | { | 391 | { |
323 | iio_device_unregister(i2c_get_clientdata(client)); | 392 | struct iio_dev *indio_dev = i2c_get_clientdata(client); |
393 | |||
394 | iio_device_unregister(indio_dev); | ||
395 | |||
396 | iio_triggered_buffer_cleanup(indio_dev); | ||
324 | 397 | ||
325 | return 0; | 398 | return 0; |
326 | } | 399 | } |