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>
This commit is contained in:
parent
077377fc4f
commit
1ce0eda0f7
2 changed files with 78 additions and 3 deletions
|
@ -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 @@
|
||||||
#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 {
|
||||||
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 = {
|
||||||
.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,
|
||||||
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 = {
|
||||||
.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 = {
|
||||||
.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,
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue