Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit bc11ca4a authored by Gregor Boirie's avatar Gregor Boirie Committed by Jonathan Cameron
Browse files

iio:magnetometer:ak8975: triggered buffer support



This will be used together with an external trigger (e.g hrtimer based
software trigger).

Signed-off-by: default avatarGregor Boirie <gregor.boirie@parrot.com>
Signed-off-by: default avatarJonathan Cameron <jic23@kernel.org>
parent fbbc5e70
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -9,6 +9,8 @@ config AK8975
	tristate "Asahi Kasei AK 3-Axis Magnetometer"
	depends on I2C
	depends on GPIOLIB || COMPILE_TEST
	select IIO_BUFFER
	select IIO_TRIGGERED_BUFFER
	help
	  Say yes here to build support for Asahi Kasei AK8975, AK8963,
	  AK09911 or AK09912 3-Axis Magnetometer.
+110 −25
Original line number Diff line number Diff line
@@ -36,6 +36,12 @@

#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/buffer.h>
#include <linux/iio/trigger.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
#include <linux/regulator/consumer.h>

/*
 * Register definitions, as well as various shifts and masks to get at the
 * individual fields of the registers.
@@ -633,22 +639,15 @@ static int wait_conversion_complete_interrupt(struct ak8975_data *data)
	return ret > 0 ? 0 : -ETIME;
}

/*
 * Emits the raw flux value for the x, y, or z axis.
 */
static int ak8975_read_axis(struct iio_dev *indio_dev, int index, int *val)
static int ak8975_start_read_axis(struct ak8975_data *data,
				  const struct i2c_client *client)
{
	struct ak8975_data *data = iio_priv(indio_dev);
	struct i2c_client *client = data->client;
	int ret;

	mutex_lock(&data->lock);

	/* Set up the device for taking a sample. */
	ret = ak8975_set_mode(data, MODE_ONCE);
	int ret = ak8975_set_mode(data, MODE_ONCE);

	if (ret < 0) {
		dev_err(&client->dev, "Error in setting operating mode\n");
		goto exit;
		return ret;
	}

	/* Wait for the conversion to complete. */
@@ -659,7 +658,7 @@ static int ak8975_read_axis(struct iio_dev *indio_dev, int index, int *val)
	else
		ret = wait_conversion_complete_polled(data);
	if (ret < 0)
		goto exit;
		return ret;

	/* This will be executed only for non-interrupt based waiting case */
	if (ret & data->def->ctrl_masks[ST1_DRDY]) {
@@ -667,32 +666,45 @@ static int ak8975_read_axis(struct iio_dev *indio_dev, int index, int *val)
					       data->def->ctrl_regs[ST2]);
		if (ret < 0) {
			dev_err(&client->dev, "Error in reading ST2\n");
			goto exit;
			return ret;
		}
		if (ret & (data->def->ctrl_masks[ST2_DERR] |
			   data->def->ctrl_masks[ST2_HOFL])) {
			dev_err(&client->dev, "ST2 status error 0x%x\n", ret);
			ret = -EINVAL;
			goto exit;
			return -EINVAL;
		}
	}

	/* Read the flux value from the appropriate register
	   (the register is specified in the iio device attributes). */
	ret = i2c_smbus_read_word_data(client, data->def->data_regs[index]);
	if (ret < 0) {
		dev_err(&client->dev, "Read axis data fails\n");
		goto exit;
	return 0;
}

/* Retrieve raw flux value for one of the x, y, or z axis.  */
static int ak8975_read_axis(struct iio_dev *indio_dev, int index, int *val)
{
	struct ak8975_data *data = iio_priv(indio_dev);
	const struct i2c_client *client = data->client;
	const struct ak_def *def = data->def;
	int ret;

	mutex_lock(&data->lock);

	ret = ak8975_start_read_axis(data, client);
	if (ret)
		goto exit;

	ret = i2c_smbus_read_word_data(client, def->data_regs[index]);
	if (ret < 0)
		goto exit;

	mutex_unlock(&data->lock);

	/* Clamp to valid range. */
	*val = clamp_t(s16, ret, -data->def->range, data->def->range);
	*val = clamp_t(s16, ret, -def->range, def->range);
	return IIO_VAL_INT;

exit:
	mutex_unlock(&data->lock);
	dev_err(&client->dev, "Error in reading axis\n");
	return ret;
}

@@ -722,12 +734,22 @@ static int ak8975_read_raw(struct iio_dev *indio_dev,
		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |		\
			     BIT(IIO_CHAN_INFO_SCALE),			\
		.address = index,					\
		.scan_index = index,					\
		.scan_type = {						\
			.sign = 's',					\
			.realbits = 16,					\
			.storagebits = 16,				\
			.endianness = IIO_CPU				\
		}							\
	}

static const struct iio_chan_spec ak8975_channels[] = {
	AK8975_CHANNEL(X, 0), AK8975_CHANNEL(Y, 1), AK8975_CHANNEL(Z, 2),
	IIO_CHAN_SOFT_TIMESTAMP(3),
};

static const unsigned long ak8975_scan_masks[] = { 0x7, 0 };

static const struct iio_info ak8975_info = {
	.read_raw = &ak8975_read_raw,
	.driver_module = THIS_MODULE,
@@ -756,6 +778,56 @@ static const char *ak8975_match_acpi_device(struct device *dev,
	return dev_name(dev);
}

static void ak8975_fill_buffer(struct iio_dev *indio_dev)
{
	struct ak8975_data *data = iio_priv(indio_dev);
	const struct i2c_client *client = data->client;
	const struct ak_def *def = data->def;
	int ret;
	s16 buff[8]; /* 3 x 16 bits axis values + 1 aligned 64 bits timestamp */

	mutex_lock(&data->lock);

	ret = ak8975_start_read_axis(data, client);
	if (ret)
		goto unlock;

	/*
	 * For each axis, read the flux value from the appropriate register
	 * (the register is specified in the iio device attributes).
	 */
	ret = i2c_smbus_read_i2c_block_data_or_emulated(client,
							def->data_regs[0],
							3 * sizeof(buff[0]),
							(u8 *)buff);
	if (ret < 0)
		goto unlock;

	mutex_unlock(&data->lock);

	/* Clamp to valid range. */
	buff[0] = clamp_t(s16, le16_to_cpu(buff[0]), -def->range, def->range);
	buff[1] = clamp_t(s16, le16_to_cpu(buff[1]), -def->range, def->range);
	buff[2] = clamp_t(s16, le16_to_cpu(buff[2]), -def->range, def->range);

	iio_push_to_buffers_with_timestamp(indio_dev, buff, iio_get_time_ns());
	return;

unlock:
	mutex_unlock(&data->lock);
	dev_err(&client->dev, "Error in reading axes block\n");
}

static irqreturn_t ak8975_handle_trigger(int irq, void *p)
{
	const struct iio_poll_func *pf = p;
	struct iio_dev *indio_dev = pf->indio_dev;

	ak8975_fill_buffer(indio_dev);
	iio_trigger_notify_done(indio_dev->trig);
	return IRQ_HANDLED;
}

static int ak8975_probe(struct i2c_client *client,
			const struct i2c_device_id *id)
{
@@ -845,15 +917,27 @@ static int ak8975_probe(struct i2c_client *client,
	indio_dev->channels = ak8975_channels;
	indio_dev->num_channels = ARRAY_SIZE(ak8975_channels);
	indio_dev->info = &ak8975_info;
	indio_dev->available_scan_masks = ak8975_scan_masks;
	indio_dev->modes = INDIO_DIRECT_MODE;
	indio_dev->name = name;

	err = iio_device_register(indio_dev);
	if (err)
	err = iio_triggered_buffer_setup(indio_dev, NULL, ak8975_handle_trigger,
					 NULL);
	if (err) {
		dev_err(&client->dev, "triggered buffer setup failed\n");
		goto power_off;
	}

	err = iio_device_register(indio_dev);
	if (err) {
		dev_err(&client->dev, "device register failed\n");
		goto cleanup_buffer;
	}

	return 0;

cleanup_buffer:
	iio_triggered_buffer_cleanup(indio_dev);
power_off:
	ak8975_power_off(client);
	return err;
@@ -864,6 +948,7 @@ static int ak8975_remove(struct i2c_client *client)
	struct iio_dev *indio_dev = i2c_get_clientdata(client);

	iio_device_unregister(indio_dev);
	iio_triggered_buffer_cleanup(indio_dev);
	ak8975_power_off(client);

	return 0;