aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTeodora Baluta <teodora.baluta@intel.com>2015-08-20 10:37:32 -0400
committerJonathan Cameron <jic23@kernel.org>2015-08-31 12:36:56 -0400
commit1ce0eda0f75747b3131a9047aee19291f59c18c9 (patch)
treef615ac8bb863037d7741408dc38b13cac40a9c9a
parent077377fc4f74899c58e946e47352216412d0bb3a (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/Kconfig2
-rw-r--r--drivers/iio/accel/mxc4005.c79
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
140config MXC4005 140config 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
129static 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
125static int mxc4005_read_axis(struct mxc4005_data *data, 143static 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
261static 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
251static const struct iio_chan_spec mxc4005_channels[] = { 283static 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
290static 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
304err:
305 iio_trigger_notify_done(indio_dev->trig);
306
307 return IRQ_HANDLED;
308}
309
257static int mxc4005_chip_init(struct mxc4005_data *data) 310static 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
384err_buffer_cleanup:
385 iio_triggered_buffer_cleanup(indio_dev);
386
387 return ret;
319} 388}
320 389
321static int mxc4005_remove(struct i2c_client *client) 390static 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}