Commit 1ce0eda0 authored by Teodora Baluta's avatar Teodora Baluta Committed by Jonathan Cameron

iio: mxc4005: add triggered buffer mode for mxc4005

This patch adds support for buffered readings for the 3-axis
accelerometer mxc4005.
Signed-off-by: default avatarTeodora Baluta <teodora.baluta@intel.com>
Signed-off-by: default avatarJonathan Cameron <jic23@kernel.org>
parent 077377fc
...@@ -140,6 +140,8 @@ config MMA9553 ...@@ -140,6 +140,8 @@ config MMA9553
config MXC4005 config MXC4005
tristate "Memsic MXC4005XC 3-Axis Accelerometer Driver" tristate "Memsic MXC4005XC 3-Axis Accelerometer Driver"
depends on I2C depends on I2C
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
select REGMAP_I2C select REGMAP_I2C
help help
Say yes here to build support for the Memsic MXC4005XC 3-axis Say yes here to build support for the Memsic MXC4005XC 3-axis
......
...@@ -19,6 +19,9 @@ ...@@ -19,6 +19,9 @@
#include <linux/acpi.h> #include <linux/acpi.h>
#include <linux/regmap.h> #include <linux/regmap.h>
#include <linux/iio/sysfs.h> #include <linux/iio/sysfs.h>
#include <linux/iio/buffer.h>
#include <linux/iio/triggered_buffer.h>
#include <linux/iio/trigger_consumer.h>
#define MXC4005_DRV_NAME "mxc4005" #define MXC4005_DRV_NAME "mxc4005"
#define MXC4005_REGMAP_NAME "mxc4005_regmap" #define MXC4005_REGMAP_NAME "mxc4005_regmap"
...@@ -52,6 +55,7 @@ struct mxc4005_data { ...@@ -52,6 +55,7 @@ struct mxc4005_data {
struct device *dev; struct device *dev;
struct mutex mutex; struct mutex mutex;
struct regmap *regmap; struct regmap *regmap;
__be16 buffer[8];
}; };
/* /*
...@@ -122,6 +126,20 @@ static const struct regmap_config mxc4005_regmap_config = { ...@@ -122,6 +126,20 @@ static const struct regmap_config mxc4005_regmap_config = {
.writeable_reg = mxc4005_is_writeable_reg, .writeable_reg = mxc4005_is_writeable_reg,
}; };
static int mxc4005_read_xyz(struct mxc4005_data *data)
{
int ret;
ret = regmap_bulk_read(data->regmap, MXC4005_REG_XOUT_UPPER,
(u8 *) data->buffer, sizeof(data->buffer));
if (ret < 0) {
dev_err(data->dev, "failed to read axes\n");
return ret;
}
return 0;
}
static int mxc4005_read_axis(struct mxc4005_data *data, static int mxc4005_read_axis(struct mxc4005_data *data,
unsigned int addr) unsigned int addr)
{ {
...@@ -197,7 +215,8 @@ static int mxc4005_read_raw(struct iio_dev *indio_dev, ...@@ -197,7 +215,8 @@ static int mxc4005_read_raw(struct iio_dev *indio_dev,
ret = mxc4005_read_axis(data, chan->address); ret = mxc4005_read_axis(data, chan->address);
if (ret < 0) if (ret < 0)
return ret; return ret;
*val = sign_extend32(ret >> 4, 11); *val = sign_extend32(ret >> chan->scan_type.shift,
chan->scan_type.realbits - 1);
return IIO_VAL_INT; return IIO_VAL_INT;
default: default:
return -EINVAL; return -EINVAL;
...@@ -239,6 +258,11 @@ static const struct iio_info mxc4005_info = { ...@@ -239,6 +258,11 @@ static const struct iio_info mxc4005_info = {
.attrs = &mxc4005_attrs_group, .attrs = &mxc4005_attrs_group,
}; };
static const unsigned long mxc4005_scan_masks[] = {
BIT(AXIS_X) | BIT(AXIS_Y) | BIT(AXIS_Z),
0
};
#define MXC4005_CHANNEL(_axis, _addr) { \ #define MXC4005_CHANNEL(_axis, _addr) { \
.type = IIO_ACCEL, \ .type = IIO_ACCEL, \
.modified = 1, \ .modified = 1, \
...@@ -246,14 +270,43 @@ static const struct iio_info mxc4005_info = { ...@@ -246,14 +270,43 @@ static const struct iio_info mxc4005_info = {
.address = _addr, \ .address = _addr, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
.scan_index = AXIS_##_axis, \
.scan_type = { \
.sign = 's', \
.realbits = 12, \
.storagebits = 16, \
.shift = 4, \
.endianness = IIO_BE, \
}, \
} }
static const struct iio_chan_spec mxc4005_channels[] = { static const struct iio_chan_spec mxc4005_channels[] = {
MXC4005_CHANNEL(X, MXC4005_REG_XOUT_UPPER), MXC4005_CHANNEL(X, MXC4005_REG_XOUT_UPPER),
MXC4005_CHANNEL(Y, MXC4005_REG_YOUT_UPPER), MXC4005_CHANNEL(Y, MXC4005_REG_YOUT_UPPER),
MXC4005_CHANNEL(Z, MXC4005_REG_ZOUT_UPPER), MXC4005_CHANNEL(Z, MXC4005_REG_ZOUT_UPPER),
IIO_CHAN_SOFT_TIMESTAMP(3),
}; };
static irqreturn_t mxc4005_trigger_handler(int irq, void *private)
{
struct iio_poll_func *pf = private;
struct iio_dev *indio_dev = pf->indio_dev;
struct mxc4005_data *data = iio_priv(indio_dev);
int ret;
ret = mxc4005_read_xyz(data);
if (ret < 0)
goto err;
iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
pf->timestamp);
err:
iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;
}
static int mxc4005_chip_init(struct mxc4005_data *data) static int mxc4005_chip_init(struct mxc4005_data *data)
{ {
int ret; int ret;
...@@ -304,23 +357,43 @@ static int mxc4005_probe(struct i2c_client *client, ...@@ -304,23 +357,43 @@ static int mxc4005_probe(struct i2c_client *client,
indio_dev->dev.parent = &client->dev; indio_dev->dev.parent = &client->dev;
indio_dev->channels = mxc4005_channels; indio_dev->channels = mxc4005_channels;
indio_dev->num_channels = ARRAY_SIZE(mxc4005_channels); indio_dev->num_channels = ARRAY_SIZE(mxc4005_channels);
indio_dev->available_scan_masks = mxc4005_scan_masks;
indio_dev->name = MXC4005_DRV_NAME; indio_dev->name = MXC4005_DRV_NAME;
indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &mxc4005_info; indio_dev->info = &mxc4005_info;
ret = iio_triggered_buffer_setup(indio_dev,
&iio_pollfunc_store_time,
mxc4005_trigger_handler,
NULL);
if (ret < 0) {
dev_err(&client->dev,
"failed to setup iio triggered buffer\n");
return ret;
}
ret = iio_device_register(indio_dev); ret = iio_device_register(indio_dev);
if (ret < 0) { if (ret < 0) {
dev_err(&client->dev, dev_err(&client->dev,
"unable to register iio device %d\n", ret); "unable to register iio device %d\n", ret);
return ret; goto err_buffer_cleanup;
} }
return 0; return 0;
err_buffer_cleanup:
iio_triggered_buffer_cleanup(indio_dev);
return ret;
} }
static int mxc4005_remove(struct i2c_client *client) static int mxc4005_remove(struct i2c_client *client)
{ {
iio_device_unregister(i2c_get_clientdata(client)); struct iio_dev *indio_dev = i2c_get_clientdata(client);
iio_device_unregister(indio_dev);
iio_triggered_buffer_cleanup(indio_dev);
return 0; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment