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

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
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -140,6 +140,8 @@ config MMA9553
config MXC4005
	tristate "Memsic MXC4005XC 3-Axis Accelerometer Driver"
	depends on I2C
	select IIO_BUFFER
	select IIO_TRIGGERED_BUFFER
	select REGMAP_I2C
	help
	  Say yes here to build support for the Memsic MXC4005XC 3-axis
+76 −3
Original line number Diff line number Diff line
@@ -19,6 +19,9 @@
#include <linux/acpi.h>
#include <linux/regmap.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_REGMAP_NAME		"mxc4005_regmap"
@@ -52,6 +55,7 @@ struct mxc4005_data {
	struct device *dev;
	struct mutex mutex;
	struct regmap *regmap;
	__be16 buffer[8];
};

/*
@@ -122,6 +126,20 @@ static const struct regmap_config mxc4005_regmap_config = {
	.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,
			     unsigned int addr)
{
@@ -197,7 +215,8 @@ static int mxc4005_read_raw(struct iio_dev *indio_dev,
			ret = mxc4005_read_axis(data, chan->address);
			if (ret < 0)
				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;
		default:
			return -EINVAL;
@@ -239,6 +258,11 @@ static const struct iio_info mxc4005_info = {
	.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) {				\
	.type = IIO_ACCEL,					\
	.modified = 1,						\
@@ -246,14 +270,43 @@ static const struct iio_info mxc4005_info = {
	.address = _addr,					\
	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),		\
	.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[] = {
	MXC4005_CHANNEL(X, MXC4005_REG_XOUT_UPPER),
	MXC4005_CHANNEL(Y, MXC4005_REG_YOUT_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)
{
	int ret;
@@ -304,23 +357,43 @@ static int mxc4005_probe(struct i2c_client *client,
	indio_dev->dev.parent = &client->dev;
	indio_dev->channels = 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->modes = INDIO_DIRECT_MODE;
	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);
	if (ret < 0) {
		dev_err(&client->dev,
			"unable to register iio device %d\n", ret);
		return ret;
		goto err_buffer_cleanup;
	}

	return 0;

err_buffer_cleanup:
	iio_triggered_buffer_cleanup(indio_dev);

	return ret;
}

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;
}