All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] iio: accel: Add buffer mode for Sensortek STK8312
@ 2015-06-09 12:20 Tiberiu Breana
  2015-06-14 11:07 ` Jonathan Cameron
  0 siblings, 1 reply; 4+ messages in thread
From: Tiberiu Breana @ 2015-06-09 12:20 UTC (permalink / raw)
  To: linux-iio; +Cc: Jonathan Cameron

Added triggered buffer mode support for the STK8312 accelerometer.

Additional changes:
- set_mode now sets operation mode directly, no longer masking
  the register's previous value
- read_accel now returns raw acceleration data instead of the
  sign_extend32 value
- read_raw will now enable/disable the sensor with each reading

Signed-off-by: Tiberiu Breana <tiberiu.a.breana@intel.com>
---
 drivers/iio/accel/stk8312.c | 281 ++++++++++++++++++++++++++++++++++++++------
 1 file changed, 246 insertions(+), 35 deletions(-)

diff --git a/drivers/iio/accel/stk8312.c b/drivers/iio/accel/stk8312.c
index d211d9f3..12ad95e 100644
--- a/drivers/iio/accel/stk8312.c
+++ b/drivers/iio/accel/stk8312.c
@@ -11,16 +11,23 @@
  */
 
 #include <linux/acpi.h>
+#include <linux/gpio/consumer.h>
 #include <linux/i2c.h>
+#include <linux/interrupt.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/delay.h>
+#include <linux/iio/buffer.h>
 #include <linux/iio/iio.h>
 #include <linux/iio/sysfs.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/triggered_buffer.h>
+#include <linux/iio/trigger_consumer.h>
 
 #define STK8312_REG_XOUT		0x00
 #define STK8312_REG_YOUT		0x01
 #define STK8312_REG_ZOUT		0x02
+#define STK8312_REG_INTSU		0x06
 #define STK8312_REG_MODE		0x07
 #define STK8312_REG_STH			0x13
 #define STK8312_REG_RESET		0x20
@@ -29,14 +36,17 @@
 #define STK8312_REG_OTPDATA		0x3E
 #define STK8312_REG_OTPCTRL		0x3F
 
-#define STK8312_MODE_ACTIVE		1
-#define STK8312_MODE_STANDBY		0
+#define STK8312_POWER_MASK		0x01
 #define STK8312_MODE_MASK		0x01
+#define STK8312_DREADY_MASK		0x10
+#define STK8312_INT_MODE		0xC0
 #define STK8312_RNG_MASK		0xC0
 #define STK8312_RNG_SHIFT		6
 #define STK8312_READ_RETRIES		16
 
 #define STK8312_DRIVER_NAME		"stk8312"
+#define STK8312_GPIO			"stk8312_gpio"
+#define STK8312_IRQ_NAME		"stk8312_event"
 
 /*
  * The accelerometer has two measurement ranges:
@@ -53,19 +63,27 @@ static const int stk8312_scale_table[][2] = {
 	{0, 461600}, {1, 231100}
 };
 
-#define STK8312_ACCEL_CHANNEL(reg, axis) {			\
+#define STK8312_ACCEL_CHANNEL(index, reg, axis) {		\
 	.type = IIO_ACCEL,					\
 	.address = reg,						\
 	.modified = 1,						\
 	.channel2 = IIO_MOD_##axis,				\
 	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),		\
 	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),	\
+	.scan_index = index,					\
+	.scan_type = {						\
+		.sign = 's',					\
+		.realbits = 8,					\
+		.storagebits = 8,				\
+		.endianness = IIO_CPU,				\
+	},							\
 }
 
 static const struct iio_chan_spec stk8312_channels[] = {
-	STK8312_ACCEL_CHANNEL(STK8312_REG_XOUT, X),
-	STK8312_ACCEL_CHANNEL(STK8312_REG_YOUT, Y),
-	STK8312_ACCEL_CHANNEL(STK8312_REG_ZOUT, Z),
+	STK8312_ACCEL_CHANNEL(0, STK8312_REG_XOUT, X),
+	STK8312_ACCEL_CHANNEL(1, STK8312_REG_YOUT, Y),
+	STK8312_ACCEL_CHANNEL(2, STK8312_REG_ZOUT, Z),
+	IIO_CHAN_SOFT_TIMESTAMP(3),
 };
 
 struct stk8312_data {
@@ -73,6 +91,9 @@ struct stk8312_data {
 	struct mutex lock;
 	int range;
 	u8 mode;
+	struct iio_trigger *dready_trig;
+	bool dready_trigger_on;
+	s8 buffer[11]; /* 3 x 8-bit channels + 64-bit timestamp */
 };
 
 static IIO_CONST_ATTR(in_accel_scale_available, STK8312_SCALE_AVAIL);
@@ -130,31 +151,19 @@ exit_err:
 static int stk8312_set_mode(struct stk8312_data *data, u8 mode)
 {
 	int ret;
-	u8 masked_reg;
 	struct i2c_client *client = data->client;
 
-	if (mode > 1)
-		return -EINVAL;
-	else if (mode == data->mode)
+	if (mode == data->mode)
 		return 0;
 
-	ret = i2c_smbus_read_byte_data(client, STK8312_REG_MODE);
-	if (ret < 0) {
-		dev_err(&client->dev, "failed to change sensor mode\n");
-		return ret;
-	}
-	masked_reg = ret & (~STK8312_MODE_MASK);
-	masked_reg |= mode;
-
-	ret = i2c_smbus_write_byte_data(client,
-			STK8312_REG_MODE, masked_reg);
+	ret = i2c_smbus_write_byte_data(client, STK8312_REG_MODE, mode);
 	if (ret < 0) {
 		dev_err(&client->dev, "failed to change sensor mode\n");
 		return ret;
 	}
 
 	data->mode = mode;
-	if (mode == STK8312_MODE_ACTIVE) {
+	if (mode & STK8312_POWER_MASK) {
 		/* Need to run OTP sequence before entering active mode */
 		usleep_range(1000, 5000);
 		ret = stk8312_otp_init(data);
@@ -163,6 +172,50 @@ static int stk8312_set_mode(struct stk8312_data *data, u8 mode)
 	return ret;
 }
 
+static int stk8312_set_interrupts(struct stk8312_data *data, u8 int_mask)
+{
+	int ret;
+	u8 mode;
+	struct i2c_client *client = data->client;
+
+	mode = data->mode;
+	/* We need to go in standby mode to modify registers */
+	ret = stk8312_set_mode(data, !STK8312_POWER_MASK);
+	if (ret < 0)
+		return ret;
+
+	ret = i2c_smbus_write_byte_data(client, STK8312_REG_INTSU, int_mask);
+	if (ret < 0)
+		dev_err(&client->dev, "failed to set interrupts\n");
+
+	return stk8312_set_mode(data, mode);
+}
+
+static int stk8312_data_rdy_trigger_set_state(struct iio_trigger *trig,
+					      bool state)
+{
+	struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
+	struct stk8312_data *data = iio_priv(indio_dev);
+	int ret;
+
+	if (state)
+		ret = stk8312_set_interrupts(data, STK8312_DREADY_MASK);
+	else
+		ret = stk8312_set_interrupts(data, 0x00);
+
+	if (ret < 0)
+		dev_err(&data->client->dev, "failed to set trigger stare\n");
+	else
+		data->dready_trigger_on = state;
+
+	return ret;
+}
+
+static const struct iio_trigger_ops stk8312_trigger_ops = {
+	.set_trigger_state = stk8312_data_rdy_trigger_set_state,
+	.owner = THIS_MODULE,
+};
+
 static int stk8312_set_range(struct stk8312_data *data, u8 range)
 {
 	int ret;
@@ -177,7 +230,7 @@ static int stk8312_set_range(struct stk8312_data *data, u8 range)
 
 	mode = data->mode;
 	/* We need to go in standby mode to modify registers */
-	ret = stk8312_set_mode(data, STK8312_MODE_STANDBY);
+	ret = stk8312_set_mode(data, !STK8312_POWER_MASK);
 	if (ret < 0)
 		return ret;
 
@@ -208,12 +261,10 @@ static int stk8312_read_accel(struct stk8312_data *data, u8 address)
 		return -EINVAL;
 
 	ret = i2c_smbus_read_byte_data(client, address);
-	if (ret < 0) {
+	if (ret < 0)
 		dev_err(&client->dev, "register read failed\n");
-		return ret;
-	}
 
-	return sign_extend32(ret, 7);
+	return ret;
 }
 
 static int stk8312_read_raw(struct iio_dev *indio_dev,
@@ -221,14 +272,27 @@ static int stk8312_read_raw(struct iio_dev *indio_dev,
 			    int *val, int *val2, long mask)
 {
 	struct stk8312_data *data = iio_priv(indio_dev);
-
-	if (chan->type != IIO_ACCEL)
-		return -EINVAL;
+	int ret;
 
 	switch (mask) {
 	case IIO_CHAN_INFO_RAW:
+		if (iio_buffer_enabled(indio_dev))
+			return -EBUSY;
 		mutex_lock(&data->lock);
-		*val = stk8312_read_accel(data, chan->address);
+		ret = stk8312_set_mode(data, data->mode | STK8312_POWER_MASK);
+		if (ret < 0) {
+			mutex_unlock(&data->lock);
+			return -EINVAL;
+		}
+		ret = stk8312_read_accel(data, chan->address);
+		if (ret < 0) {
+			stk8312_set_mode(data,
+					 data->mode & (~STK8312_POWER_MASK));
+			mutex_unlock(&data->lock);
+			return -EINVAL;
+		}
+		*val = sign_extend32(ret, 7);
+		stk8312_set_mode(data, data->mode & (~STK8312_POWER_MASK));
 		mutex_unlock(&data->lock);
 		return IIO_VAL_INT;
 	case IIO_CHAN_INFO_SCALE:
@@ -277,6 +341,93 @@ static const struct iio_info stk8312_info = {
 	.attrs			= &stk8312_attribute_group,
 };
 
+static irqreturn_t stk8312_trigger_handler(int irq, void *p)
+{
+	struct iio_poll_func *pf = p;
+	struct iio_dev *indio_dev = pf->indio_dev;
+	struct stk8312_data *data = iio_priv(indio_dev);
+	int bit, ret, i = 0;
+
+	mutex_lock(&data->lock);
+	for_each_set_bit(bit, indio_dev->active_scan_mask,
+			 indio_dev->masklength) {
+		ret = stk8312_read_accel(data, bit);
+		if (ret < 0) {
+			mutex_unlock(&data->lock);
+			goto err;
+		}
+		data->buffer[i++] = ret;
+	}
+	mutex_unlock(&data->lock);
+
+	iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
+					   pf->timestamp);
+err:
+	iio_trigger_notify_done(indio_dev->trig);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t stk8312_data_rdy_trig_poll(int irq, void *private)
+{
+	struct iio_dev *indio_dev = private;
+	struct stk8312_data *data = iio_priv(indio_dev);
+
+	if (data->dready_trigger_on)
+		iio_trigger_poll(data->dready_trig);
+
+	return IRQ_HANDLED;
+}
+
+static int stk8312_buffer_preenable(struct iio_dev *indio_dev)
+{
+	struct stk8312_data *data = iio_priv(indio_dev);
+
+	return stk8312_set_mode(data, data->mode | STK8312_POWER_MASK);
+}
+
+static int stk8312_buffer_postdisable(struct iio_dev *indio_dev)
+{
+	struct stk8312_data *data = iio_priv(indio_dev);
+
+	return stk8312_set_mode(data, data->mode & (~STK8312_POWER_MASK));
+}
+
+static const struct iio_buffer_setup_ops stk8312_buffer_setup_ops = {
+	.preenable   = stk8312_buffer_preenable,
+	.postenable  = iio_triggered_buffer_postenable,
+	.predisable  = iio_triggered_buffer_predisable,
+	.postdisable = stk8312_buffer_postdisable,
+};
+
+static int stk8312_gpio_probe(struct i2c_client *client)
+{
+	struct device *dev;
+	struct gpio_desc *gpio;
+	int ret;
+
+	if (!client)
+		return -EINVAL;
+
+	dev = &client->dev;
+
+	/* data ready gpio interrupt pin */
+	gpio = devm_gpiod_get_index(dev, STK8312_GPIO, 0);
+	if (IS_ERR(gpio)) {
+		dev_err(dev, "acpi gpio get index failed\n");
+		return PTR_ERR(gpio);
+	}
+
+	ret = gpiod_direction_input(gpio);
+	if (ret)
+		return ret;
+
+	ret = gpiod_to_irq(gpio);
+	dev_dbg(dev, "GPIO resource, no:%d irq:%d\n", desc_to_gpio(gpio), ret);
+
+	return ret;
+}
+
 static int stk8312_probe(struct i2c_client *client,
 			 const struct i2c_device_id *id)
 {
@@ -312,26 +463,86 @@ static int stk8312_probe(struct i2c_client *client,
 	if (ret < 0)
 		return ret;
 
-	ret = stk8312_set_mode(data, STK8312_MODE_ACTIVE);
+	ret = stk8312_set_mode(data, STK8312_INT_MODE | STK8312_POWER_MASK);
 	if (ret < 0)
 		return ret;
 
+	if (client->irq < 0)
+		client->irq = stk8312_gpio_probe(client);
+
+	if (client->irq >= 0) {
+		ret = devm_request_threaded_irq(&client->dev, client->irq,
+						stk8312_data_rdy_trig_poll,
+						NULL,
+						IRQF_TRIGGER_RISING |
+						IRQF_ONESHOT,
+						STK8312_IRQ_NAME,
+						indio_dev);
+		if (ret < 0) {
+			dev_err(&client->dev, "request irq %d failed\n",
+				client->irq);
+			goto err_power_off;
+		}
+
+		data->dready_trig = devm_iio_trigger_alloc(&client->dev,
+							   "%s-dev%d",
+							   indio_dev->name,
+							   indio_dev->id);
+		if (!data->dready_trig) {
+			ret = -ENOMEM;
+			goto err_power_off;
+		}
+
+		data->dready_trig->dev.parent = &client->dev;
+		data->dready_trig->ops = &stk8312_trigger_ops;
+		iio_trigger_set_drvdata(data->dready_trig, indio_dev);
+		ret = iio_trigger_register(data->dready_trig);
+		if (ret) {
+			dev_err(&client->dev, "iio trigger register failed\n");
+			goto err_power_off;
+		}
+	}
+
+	ret = iio_triggered_buffer_setup(indio_dev,
+					 iio_pollfunc_store_time,
+					 stk8312_trigger_handler,
+					 &stk8312_buffer_setup_ops);
+	if (ret < 0) {
+		dev_err(&client->dev, "iio triggered buffer setup failed\n");
+		goto err_trigger_unregister;
+	}
+
 	ret = iio_device_register(indio_dev);
 	if (ret < 0) {
 		dev_err(&client->dev, "device_register failed\n");
-		stk8312_set_mode(data, STK8312_MODE_STANDBY);
+		goto err_buffer_cleanup;
 	}
 
 	return ret;
+
+err_buffer_cleanup:
+	iio_triggered_buffer_cleanup(indio_dev);
+err_trigger_unregister:
+	if (data->dready_trig)
+		iio_trigger_unregister(data->dready_trig);
+err_power_off:
+	stk8312_set_mode(data, !STK8312_POWER_MASK);
+	return ret;
 }
 
 static int stk8312_remove(struct i2c_client *client)
 {
 	struct iio_dev *indio_dev = i2c_get_clientdata(client);
+	struct stk8312_data *data = iio_priv(indio_dev);
 
 	iio_device_unregister(indio_dev);
 
-	return stk8312_set_mode(iio_priv(indio_dev), STK8312_MODE_STANDBY);
+	if (data->dready_trig) {
+		iio_triggered_buffer_cleanup(indio_dev);
+		iio_trigger_unregister(data->dready_trig);
+	}
+
+	return stk8312_set_mode(data, !STK8312_POWER_MASK);
 }
 
 #ifdef CONFIG_PM_SLEEP
@@ -341,7 +552,7 @@ static int stk8312_suspend(struct device *dev)
 
 	data = iio_priv(i2c_get_clientdata(to_i2c_client(dev)));
 
-	return stk8312_set_mode(data, STK8312_MODE_STANDBY);
+	return stk8312_set_mode(data, data->mode & (~STK8312_POWER_MASK));
 }
 
 static int stk8312_resume(struct device *dev)
@@ -350,7 +561,7 @@ static int stk8312_resume(struct device *dev)
 
 	data = iio_priv(i2c_get_clientdata(to_i2c_client(dev)));
 
-	return stk8312_set_mode(data, STK8312_MODE_ACTIVE);
+	return stk8312_set_mode(data, data->mode | STK8312_POWER_MASK);
 }
 
 static SIMPLE_DEV_PM_OPS(stk8312_pm_ops, stk8312_suspend, stk8312_resume);
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [PATCH] iio: accel: Add buffer mode for Sensortek STK8312
  2015-06-09 12:20 [PATCH] iio: accel: Add buffer mode for Sensortek STK8312 Tiberiu Breana
@ 2015-06-14 11:07 ` Jonathan Cameron
  2015-06-15 13:06   ` Breana, Tiberiu A
  0 siblings, 1 reply; 4+ messages in thread
From: Jonathan Cameron @ 2015-06-14 11:07 UTC (permalink / raw)
  To: Tiberiu Breana, linux-iio

On 09/06/15 13:20, Tiberiu Breana wrote:
> Added triggered buffer mode support for the STK8312 accelerometer.
> 
> Additional changes:
> - set_mode now sets operation mode directly, no longer masking
>   the register's previous value
> - read_accel now returns raw acceleration data instead of the
>   sign_extend32 value
> - read_raw will now enable/disable the sensor with each reading
> 
> Signed-off-by: Tiberiu Breana <tiberiu.a.breana@intel.com>
A few bits and bobs inline.

Jonathan
> ---
>  drivers/iio/accel/stk8312.c | 281 ++++++++++++++++++++++++++++++++++++++------
>  1 file changed, 246 insertions(+), 35 deletions(-)
> 
> diff --git a/drivers/iio/accel/stk8312.c b/drivers/iio/accel/stk8312.c
> index d211d9f3..12ad95e 100644
> --- a/drivers/iio/accel/stk8312.c
> +++ b/drivers/iio/accel/stk8312.c
> @@ -11,16 +11,23 @@
>   */
>  
>  #include <linux/acpi.h>
> +#include <linux/gpio/consumer.h>
>  #include <linux/i2c.h>
> +#include <linux/interrupt.h>
>  #include <linux/kernel.h>
>  #include <linux/module.h>
>  #include <linux/delay.h>
> +#include <linux/iio/buffer.h>
>  #include <linux/iio/iio.h>
>  #include <linux/iio/sysfs.h>
> +#include <linux/iio/trigger.h>
> +#include <linux/iio/triggered_buffer.h>
> +#include <linux/iio/trigger_consumer.h>
>  
>  #define STK8312_REG_XOUT		0x00
>  #define STK8312_REG_YOUT		0x01
>  #define STK8312_REG_ZOUT		0x02
> +#define STK8312_REG_INTSU		0x06
>  #define STK8312_REG_MODE		0x07
>  #define STK8312_REG_STH			0x13
>  #define STK8312_REG_RESET		0x20
> @@ -29,14 +36,17 @@
>  #define STK8312_REG_OTPDATA		0x3E
>  #define STK8312_REG_OTPCTRL		0x3F
>  
> -#define STK8312_MODE_ACTIVE		1
> -#define STK8312_MODE_STANDBY		0
These single bits dont' particularly strike me as 'masks'
Rather they are straight forward boolean controls.
> +#define STK8312_POWER_MASK		0x01
>  #define STK8312_MODE_MASK		0x01
> +#define STK8312_DREADY_MASK		0x10
> +#define STK8312_INT_MODE		0xC0
>  #define STK8312_RNG_MASK		0xC0
>  #define STK8312_RNG_SHIFT		6
>  #define STK8312_READ_RETRIES		16
>  
>  #define STK8312_DRIVER_NAME		"stk8312"
> +#define STK8312_GPIO			"stk8312_gpio"
> +#define STK8312_IRQ_NAME		"stk8312_event"
>  
>  /*
>   * The accelerometer has two measurement ranges:
> @@ -53,19 +63,27 @@ static const int stk8312_scale_table[][2] = {
>  	{0, 461600}, {1, 231100}
>  };
>  
> -#define STK8312_ACCEL_CHANNEL(reg, axis) {			\
> +#define STK8312_ACCEL_CHANNEL(index, reg, axis) {		\
>  	.type = IIO_ACCEL,					\
>  	.address = reg,						\
>  	.modified = 1,						\
>  	.channel2 = IIO_MOD_##axis,				\
>  	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),		\
>  	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),	\
> +	.scan_index = index,					\
> +	.scan_type = {						\
> +		.sign = 's',					\
> +		.realbits = 8,					\
> +		.storagebits = 8,				\
> +		.endianness = IIO_CPU,				\
> +	},							\
>  }
>  
>  static const struct iio_chan_spec stk8312_channels[] = {
> -	STK8312_ACCEL_CHANNEL(STK8312_REG_XOUT, X),
> -	STK8312_ACCEL_CHANNEL(STK8312_REG_YOUT, Y),
> -	STK8312_ACCEL_CHANNEL(STK8312_REG_ZOUT, Z),
> +	STK8312_ACCEL_CHANNEL(0, STK8312_REG_XOUT, X),
> +	STK8312_ACCEL_CHANNEL(1, STK8312_REG_YOUT, Y),
> +	STK8312_ACCEL_CHANNEL(2, STK8312_REG_ZOUT, Z),
> +	IIO_CHAN_SOFT_TIMESTAMP(3),
>  };
>  
>  struct stk8312_data {
> @@ -73,6 +91,9 @@ struct stk8312_data {
>  	struct mutex lock;
>  	int range;
>  	u8 mode;
> +	struct iio_trigger *dready_trig;
> +	bool dready_trigger_on;
> +	s8 buffer[11]; /* 3 x 8-bit channels + 64-bit timestamp */
Allow for alignment.  So you need to 64 bit align that timestamp.
hence 3 x 8(channels) + 7x8 padding  + 8x8 timestamp.
>  };
>  
>  static IIO_CONST_ATTR(in_accel_scale_available, STK8312_SCALE_AVAIL);
> @@ -130,31 +151,19 @@ exit_err:
>  static int stk8312_set_mode(struct stk8312_data *data, u8 mode)
>  {
>  	int ret;
> -	u8 masked_reg;
>  	struct i2c_client *client = data->client;
>  
> -	if (mode > 1)
> -		return -EINVAL;
> -	else if (mode == data->mode)
> +	if (mode == data->mode)
>  		return 0;
>  
> -	ret = i2c_smbus_read_byte_data(client, STK8312_REG_MODE);
> -	if (ret < 0) {
> -		dev_err(&client->dev, "failed to change sensor mode\n");
> -		return ret;
> -	}
> -	masked_reg = ret & (~STK8312_MODE_MASK);
> -	masked_reg |= mode;
> -
> -	ret = i2c_smbus_write_byte_data(client,
> -			STK8312_REG_MODE, masked_reg);
> +	ret = i2c_smbus_write_byte_data(client, STK8312_REG_MODE, mode);
>  	if (ret < 0) {
>  		dev_err(&client->dev, "failed to change sensor mode\n");
>  		return ret;
>  	}
>  
>  	data->mode = mode;
> -	if (mode == STK8312_MODE_ACTIVE) {
> +	if (mode & STK8312_POWER_MASK) {
>  		/* Need to run OTP sequence before entering active mode */
>  		usleep_range(1000, 5000);
>  		ret = stk8312_otp_init(data);
> @@ -163,6 +172,50 @@ static int stk8312_set_mode(struct stk8312_data *data, u8 mode)
>  	return ret;
>  }
>  
> +static int stk8312_set_interrupts(struct stk8312_data *data, u8 int_mask)
> +{
> +	int ret;
> +	u8 mode;
> +	struct i2c_client *client = data->client;
> +
> +	mode = data->mode;
> +	/* We need to go in standby mode to modify registers */
> +	ret = stk8312_set_mode(data, !STK8312_POWER_MASK);
> +	if (ret < 0)
> +		return ret;
> +
> +	ret = i2c_smbus_write_byte_data(client, STK8312_REG_INTSU, int_mask);
> +	if (ret < 0)
> +		dev_err(&client->dev, "failed to set interrupts\n");
With a failure here, should you be continuing to set the mode?
> +
> +	return stk8312_set_mode(data, mode);
> +}
> +
> +static int stk8312_data_rdy_trigger_set_state(struct iio_trigger *trig,
> +					      bool state)
> +{
> +	struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
> +	struct stk8312_data *data = iio_priv(indio_dev);
> +	int ret;
> +
> +	if (state)
> +		ret = stk8312_set_interrupts(data, STK8312_DREADY_MASK);
> +	else
> +		ret = stk8312_set_interrupts(data, 0x00);
> +
> +	if (ret < 0)
> +		dev_err(&data->client->dev, "failed to set trigger stare\n");
return in the error path here and drop the else.  Gives a more conventional
form to the function making reviewing a tiny bit easier!
> +	else
> +		data->dready_trigger_on = state;
> +
> +	return ret;
> +}
> +
> +static const struct iio_trigger_ops stk8312_trigger_ops = {
> +	.set_trigger_state = stk8312_data_rdy_trigger_set_state,
> +	.owner = THIS_MODULE,
> +};
> +
>  static int stk8312_set_range(struct stk8312_data *data, u8 range)
>  {
>  	int ret;
> @@ -177,7 +230,7 @@ static int stk8312_set_range(struct stk8312_data *data, u8 range)
>  
>  	mode = data->mode;
>  	/* We need to go in standby mode to modify registers */
> -	ret = stk8312_set_mode(data, STK8312_MODE_STANDBY);
> +	ret = stk8312_set_mode(data, !STK8312_POWER_MASK);
>  	if (ret < 0)
>  		return ret;
>  
> @@ -208,12 +261,10 @@ static int stk8312_read_accel(struct stk8312_data *data, u8 address)
>  		return -EINVAL;
>  
>  	ret = i2c_smbus_read_byte_data(client, address);
> -	if (ret < 0) {
> +	if (ret < 0)
>  		dev_err(&client->dev, "register read failed\n");
> -		return ret;
> -	}
>  
> -	return sign_extend32(ret, 7);
> +	return ret;
>  }
>  
>  static int stk8312_read_raw(struct iio_dev *indio_dev,
> @@ -221,14 +272,27 @@ static int stk8312_read_raw(struct iio_dev *indio_dev,
>  			    int *val, int *val2, long mask)
>  {
>  	struct stk8312_data *data = iio_priv(indio_dev);
> -
> -	if (chan->type != IIO_ACCEL)
> -		return -EINVAL;
> +	int ret;
>  
>  	switch (mask) {
>  	case IIO_CHAN_INFO_RAW:
> +		if (iio_buffer_enabled(indio_dev))
> +			return -EBUSY;
>  		mutex_lock(&data->lock);
> -		*val = stk8312_read_accel(data, chan->address);
> +		ret = stk8312_set_mode(data, data->mode | STK8312_POWER_MASK);
> +		if (ret < 0) {
> +			mutex_unlock(&data->lock);
> +			return -EINVAL;
> +		}
> +		ret = stk8312_read_accel(data, chan->address);
> +		if (ret < 0) {
> +			stk8312_set_mode(data,
> +					 data->mode & (~STK8312_POWER_MASK));
> +			mutex_unlock(&data->lock);
> +			return -EINVAL;
> +		}
> +		*val = sign_extend32(ret, 7);
> +		stk8312_set_mode(data, data->mode & (~STK8312_POWER_MASK));
>  		mutex_unlock(&data->lock);
>  		return IIO_VAL_INT;
>  	case IIO_CHAN_INFO_SCALE:
> @@ -277,6 +341,93 @@ static const struct iio_info stk8312_info = {
>  	.attrs			= &stk8312_attribute_group,
>  };
>  
> +static irqreturn_t stk8312_trigger_handler(int irq, void *p)
> +{
> +	struct iio_poll_func *pf = p;
> +	struct iio_dev *indio_dev = pf->indio_dev;
> +	struct stk8312_data *data = iio_priv(indio_dev);
> +	int bit, ret, i = 0;
> +
> +	mutex_lock(&data->lock);
> +	for_each_set_bit(bit, indio_dev->active_scan_mask,
> +			 indio_dev->masklength) {
> +		ret = stk8312_read_accel(data, bit);
> +		if (ret < 0) {
> +			mutex_unlock(&data->lock);
> +			goto err;
> +		}
> +		data->buffer[i++] = ret;
> +	}
> +	mutex_unlock(&data->lock);
> +
> +	iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
> +					   pf->timestamp);
> +err:
> +	iio_trigger_notify_done(indio_dev->trig);
> +
> +	return IRQ_HANDLED;
> +}
> +
> +static irqreturn_t stk8312_data_rdy_trig_poll(int irq, void *private)
> +{
> +	struct iio_dev *indio_dev = private;
> +	struct stk8312_data *data = iio_priv(indio_dev);
> +
> +	if (data->dready_trigger_on)
> +		iio_trigger_poll(data->dready_trig);
> +
> +	return IRQ_HANDLED;
> +}
> +
> +static int stk8312_buffer_preenable(struct iio_dev *indio_dev)
> +{
> +	struct stk8312_data *data = iio_priv(indio_dev);
> +
> +	return stk8312_set_mode(data, data->mode | STK8312_POWER_MASK);
> +}
> +
> +static int stk8312_buffer_postdisable(struct iio_dev *indio_dev)
> +{
> +	struct stk8312_data *data = iio_priv(indio_dev);
> +
> +	return stk8312_set_mode(data, data->mode & (~STK8312_POWER_MASK));
> +}
> +
> +static const struct iio_buffer_setup_ops stk8312_buffer_setup_ops = {
> +	.preenable   = stk8312_buffer_preenable,
> +	.postenable  = iio_triggered_buffer_postenable,
> +	.predisable  = iio_triggered_buffer_predisable,
> +	.postdisable = stk8312_buffer_postdisable,
> +};
> +
> +static int stk8312_gpio_probe(struct i2c_client *client)
> +{
> +	struct device *dev;
> +	struct gpio_desc *gpio;
> +	int ret;
> +
> +	if (!client)
> +		return -EINVAL;
> +
> +	dev = &client->dev;
> +
> +	/* data ready gpio interrupt pin */
> +	gpio = devm_gpiod_get_index(dev, STK8312_GPIO, 0);
> +	if (IS_ERR(gpio)) {
> +		dev_err(dev, "acpi gpio get index failed\n");
> +		return PTR_ERR(gpio);
> +	}
> +
> +	ret = gpiod_direction_input(gpio);
> +	if (ret)
> +		return ret;
> +
> +	ret = gpiod_to_irq(gpio);
> +	dev_dbg(dev, "GPIO resource, no:%d irq:%d\n", desc_to_gpio(gpio), ret);
> +
> +	return ret;
> +}
> +
>  static int stk8312_probe(struct i2c_client *client,
>  			 const struct i2c_device_id *id)
>  {
> @@ -312,26 +463,86 @@ static int stk8312_probe(struct i2c_client *client,
>  	if (ret < 0)
>  		return ret;
>  
> -	ret = stk8312_set_mode(data, STK8312_MODE_ACTIVE);
> +	ret = stk8312_set_mode(data, STK8312_INT_MODE | STK8312_POWER_MASK);
>  	if (ret < 0)
>  		return ret;
>  
> +	if (client->irq < 0)
> +		client->irq = stk8312_gpio_probe(client);
> +
> +	if (client->irq >= 0) {
> +		ret = devm_request_threaded_irq(&client->dev, client->irq,
> +						stk8312_data_rdy_trig_poll,
> +						NULL,
> +						IRQF_TRIGGER_RISING |
> +						IRQF_ONESHOT,
> +						STK8312_IRQ_NAME,
> +						indio_dev);
> +		if (ret < 0) {
> +			dev_err(&client->dev, "request irq %d failed\n",
> +				client->irq);
> +			goto err_power_off;
> +		}
> +
> +		data->dready_trig = devm_iio_trigger_alloc(&client->dev,
> +							   "%s-dev%d",
> +							   indio_dev->name,
> +							   indio_dev->id);
> +		if (!data->dready_trig) {
> +			ret = -ENOMEM;
> +			goto err_power_off;
> +		}
> +
> +		data->dready_trig->dev.parent = &client->dev;
> +		data->dready_trig->ops = &stk8312_trigger_ops;
> +		iio_trigger_set_drvdata(data->dready_trig, indio_dev);
> +		ret = iio_trigger_register(data->dready_trig);
> +		if (ret) {
> +			dev_err(&client->dev, "iio trigger register failed\n");
> +			goto err_power_off;
> +		}
> +	}
> +
> +	ret = iio_triggered_buffer_setup(indio_dev,
> +					 iio_pollfunc_store_time,
> +					 stk8312_trigger_handler,
> +					 &stk8312_buffer_setup_ops);
> +	if (ret < 0) {
> +		dev_err(&client->dev, "iio triggered buffer setup failed\n");
> +		goto err_trigger_unregister;
> +	}
> +
>  	ret = iio_device_register(indio_dev);
>  	if (ret < 0) {
>  		dev_err(&client->dev, "device_register failed\n");
> -		stk8312_set_mode(data, STK8312_MODE_STANDBY);
> +		goto err_buffer_cleanup;
>  	}
>  
>  	return ret;
> +
> +err_buffer_cleanup:
> +	iio_triggered_buffer_cleanup(indio_dev);
> +err_trigger_unregister:
> +	if (data->dready_trig)
> +		iio_trigger_unregister(data->dready_trig);
> +err_power_off:
> +	stk8312_set_mode(data, !STK8312_POWER_MASK);
> +	return ret;
>  }
>  
>  static int stk8312_remove(struct i2c_client *client)
>  {
>  	struct iio_dev *indio_dev = i2c_get_clientdata(client);
> +	struct stk8312_data *data = iio_priv(indio_dev);
>  
>  	iio_device_unregister(indio_dev);
>  
> -	return stk8312_set_mode(iio_priv(indio_dev), STK8312_MODE_STANDBY);
> +	if (data->dready_trig) {
> +		iio_triggered_buffer_cleanup(indio_dev);
> +		iio_trigger_unregister(data->dready_trig);
> +	}
> +
> +	return stk8312_set_mode(data, !STK8312_POWER_MASK);
Boolean not?  Not sure what intent is here, but seems likely you
just want the same write as in stk8312_suspend.
>  }
>  
>  #ifdef CONFIG_PM_SLEEP
> @@ -341,7 +552,7 @@ static int stk8312_suspend(struct device *dev)
>  
>  	data = iio_priv(i2c_get_clientdata(to_i2c_client(dev)));
>  
> -	return stk8312_set_mode(data, STK8312_MODE_STANDBY);
> +	return stk8312_set_mode(data, data->mode & (~STK8312_POWER_MASK));
>  }
>  
>  static int stk8312_resume(struct device *dev)
> @@ -350,7 +561,7 @@ static int stk8312_resume(struct device *dev)
>  
>  	data = iio_priv(i2c_get_clientdata(to_i2c_client(dev)));
>  
> -	return stk8312_set_mode(data, STK8312_MODE_ACTIVE);
> +	return stk8312_set_mode(data, data->mode | STK8312_POWER_MASK);
>  }
>  
>  static SIMPLE_DEV_PM_OPS(stk8312_pm_ops, stk8312_suspend, stk8312_resume);
> 


^ permalink raw reply	[flat|nested] 4+ messages in thread

* RE: [PATCH] iio: accel: Add buffer mode for Sensortek STK8312
  2015-06-14 11:07 ` Jonathan Cameron
@ 2015-06-15 13:06   ` Breana, Tiberiu A
  2015-06-15 17:25     ` Jonathan Cameron
  0 siblings, 1 reply; 4+ messages in thread
From: Breana, Tiberiu A @ 2015-06-15 13:06 UTC (permalink / raw)
  To: Jonathan Cameron, linux-iio

> -----Original Message-----
> From: Jonathan Cameron [mailto:jic23@kernel.org]
> Sent: Sunday, June 14, 2015 2:07 PM
> To: Breana, Tiberiu A; linux-iio@vger.kernel.org
> Subject: Re: [PATCH] iio: accel: Add buffer mode for Sensortek STK8312
> 
> On 09/06/15 13:20, Tiberiu Breana wrote:
> > Added triggered buffer mode support for the STK8312 accelerometer.
> >
> > Additional changes:
> > - set_mode now sets operation mode directly, no longer masking
> >   the register's previous value
> > - read_accel now returns raw acceleration data instead of the
> >   sign_extend32 value
> > - read_raw will now enable/disable the sensor with each reading
> >
> > Signed-off-by: Tiberiu Breana <tiberiu.a.breana@intel.com>
> A few bits and bobs inline.
> 
> Jonathan

Thanks for your review. I'm adding some clarifications inline.
v2 will follow soon.

Tiberiu

> > ---
> >  drivers/iio/accel/stk8312.c | 281
> > ++++++++++++++++++++++++++++++++++++++------
> >  1 file changed, 246 insertions(+), 35 deletions(-)
> >
> > diff --git a/drivers/iio/accel/stk8312.c b/drivers/iio/accel/stk8312.c
> > index d211d9f3..12ad95e 100644
> > --- a/drivers/iio/accel/stk8312.c
> > +++ b/drivers/iio/accel/stk8312.c
> > @@ -11,16 +11,23 @@
> >   */
> >
> >  #include <linux/acpi.h>
> > +#include <linux/gpio/consumer.h>
> >  #include <linux/i2c.h>
> > +#include <linux/interrupt.h>
> >  #include <linux/kernel.h>
> >  #include <linux/module.h>
> >  #include <linux/delay.h>
> > +#include <linux/iio/buffer.h>
> >  #include <linux/iio/iio.h>
> >  #include <linux/iio/sysfs.h>
> > +#include <linux/iio/trigger.h>
> > +#include <linux/iio/triggered_buffer.h> #include
> > +<linux/iio/trigger_consumer.h>
> >
> >  #define STK8312_REG_XOUT		0x00
> >  #define STK8312_REG_YOUT		0x01
> >  #define STK8312_REG_ZOUT		0x02
> > +#define STK8312_REG_INTSU		0x06
> >  #define STK8312_REG_MODE		0x07
> >  #define STK8312_REG_STH			0x13
> >  #define STK8312_REG_RESET		0x20
> > @@ -29,14 +36,17 @@
> >  #define STK8312_REG_OTPDATA		0x3E
> >  #define STK8312_REG_OTPCTRL		0x3F
> >
> > -#define STK8312_MODE_ACTIVE		1
> > -#define STK8312_MODE_STANDBY		0
> These single bits dont' particularly strike me as 'masks'
> Rather they are straight forward boolean controls.
> > +#define STK8312_POWER_MASK		0x01
> >  #define STK8312_MODE_MASK		0x01
> > +#define STK8312_DREADY_MASK		0x10
> > +#define STK8312_INT_MODE		0xC0
> >  #define STK8312_RNG_MASK		0xC0
> >  #define STK8312_RNG_SHIFT		6
> >  #define STK8312_READ_RETRIES		16
> >
> >  #define STK8312_DRIVER_NAME		"stk8312"
> > +#define STK8312_GPIO			"stk8312_gpio"
> > +#define STK8312_IRQ_NAME		"stk8312_event"
> >
> >  /*
> >   * The accelerometer has two measurement ranges:
> > @@ -53,19 +63,27 @@ static const int stk8312_scale_table[][2] = {
> >  	{0, 461600}, {1, 231100}
> >  };
> >
> > -#define STK8312_ACCEL_CHANNEL(reg, axis) {			\
> > +#define STK8312_ACCEL_CHANNEL(index, reg, axis) {		\
> >  	.type = IIO_ACCEL,					\
> >  	.address = reg,						\
> >  	.modified = 1,						\
> >  	.channel2 = IIO_MOD_##axis,				\
> >  	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),		\
> >  	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),	\
> > +	.scan_index = index,					\
> > +	.scan_type = {						\
> > +		.sign = 's',					\
> > +		.realbits = 8,					\
> > +		.storagebits = 8,				\
> > +		.endianness = IIO_CPU,				\
> > +	},							\
> >  }
> >
> >  static const struct iio_chan_spec stk8312_channels[] = {
> > -	STK8312_ACCEL_CHANNEL(STK8312_REG_XOUT, X),
> > -	STK8312_ACCEL_CHANNEL(STK8312_REG_YOUT, Y),
> > -	STK8312_ACCEL_CHANNEL(STK8312_REG_ZOUT, Z),
> > +	STK8312_ACCEL_CHANNEL(0, STK8312_REG_XOUT, X),
> > +	STK8312_ACCEL_CHANNEL(1, STK8312_REG_YOUT, Y),
> > +	STK8312_ACCEL_CHANNEL(2, STK8312_REG_ZOUT, Z),
> > +	IIO_CHAN_SOFT_TIMESTAMP(3),
> >  };
> >
> >  struct stk8312_data {
> > @@ -73,6 +91,9 @@ struct stk8312_data {
> >  	struct mutex lock;
> >  	int range;
> >  	u8 mode;
> > +	struct iio_trigger *dready_trig;
> > +	bool dready_trigger_on;
> > +	s8 buffer[11]; /* 3 x 8-bit channels + 64-bit timestamp */
> Allow for alignment.  So you need to 64 bit align that timestamp.
> hence 3 x 8(channels) + 7x8 padding  + 8x8 timestamp.

I think you mean 5x8 padding?
Regardless, I've tested the driver with the generic_buffer tool from tools/iio,
both with and without padding, and the timestamps looked fine.

> >  };
> >
> >  static IIO_CONST_ATTR(in_accel_scale_available, STK8312_SCALE_AVAIL);
> > @@ -130,31 +151,19 @@ exit_err:
> >  static int stk8312_set_mode(struct stk8312_data *data, u8 mode)  {
> >  	int ret;
> > -	u8 masked_reg;
> >  	struct i2c_client *client = data->client;
> >
> > -	if (mode > 1)
> > -		return -EINVAL;
> > -	else if (mode == data->mode)
> > +	if (mode == data->mode)
> >  		return 0;
> >
> > -	ret = i2c_smbus_read_byte_data(client, STK8312_REG_MODE);
> > -	if (ret < 0) {
> > -		dev_err(&client->dev, "failed to change sensor mode\n");
> > -		return ret;
> > -	}
> > -	masked_reg = ret & (~STK8312_MODE_MASK);
> > -	masked_reg |= mode;
> > -
> > -	ret = i2c_smbus_write_byte_data(client,
> > -			STK8312_REG_MODE, masked_reg);
> > +	ret = i2c_smbus_write_byte_data(client, STK8312_REG_MODE,
> mode);
> >  	if (ret < 0) {
> >  		dev_err(&client->dev, "failed to change sensor mode\n");
> >  		return ret;
> >  	}
> >
> >  	data->mode = mode;
> > -	if (mode == STK8312_MODE_ACTIVE) {
> > +	if (mode & STK8312_POWER_MASK) {
> >  		/* Need to run OTP sequence before entering active mode
> */
> >  		usleep_range(1000, 5000);
> >  		ret = stk8312_otp_init(data);
> > @@ -163,6 +172,50 @@ static int stk8312_set_mode(struct stk8312_data
> *data, u8 mode)
> >  	return ret;
> >  }
> >
> > +static int stk8312_set_interrupts(struct stk8312_data *data, u8
> > +int_mask) {
> > +	int ret;
> > +	u8 mode;
> > +	struct i2c_client *client = data->client;
> > +
> > +	mode = data->mode;
> > +	/* We need to go in standby mode to modify registers */
> > +	ret = stk8312_set_mode(data, !STK8312_POWER_MASK);
> > +	if (ret < 0)
> > +		return ret;
> > +
> > +	ret = i2c_smbus_write_byte_data(client, STK8312_REG_INTSU,
> int_mask);
> > +	if (ret < 0)
> > +		dev_err(&client->dev, "failed to set interrupts\n");
> With a failure here, should you be continuing to set the mode?

Well, regardless if we succeed or fail in setting the interrupt register,
we need to return to the mode we were in before entering this function.

> > +
> > +	return stk8312_set_mode(data, mode); }
> > +
> > +static int stk8312_data_rdy_trigger_set_state(struct iio_trigger *trig,
> > +					      bool state)
> > +{
> > +	struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
> > +	struct stk8312_data *data = iio_priv(indio_dev);
> > +	int ret;
> > +
> > +	if (state)
> > +		ret = stk8312_set_interrupts(data, STK8312_DREADY_MASK);
> > +	else
> > +		ret = stk8312_set_interrupts(data, 0x00);
> > +
> > +	if (ret < 0)
> > +		dev_err(&data->client->dev, "failed to set trigger stare\n");
> return in the error path here and drop the else.  Gives a more conventional
> form to the function making reviewing a tiny bit easier!
> > +	else
> > +		data->dready_trigger_on = state;
> > +
> > +	return ret;
> > +}
> > +
> > +static const struct iio_trigger_ops stk8312_trigger_ops = {
> > +	.set_trigger_state = stk8312_data_rdy_trigger_set_state,
> > +	.owner = THIS_MODULE,
> > +};
> > +
> >  static int stk8312_set_range(struct stk8312_data *data, u8 range)  {
> >  	int ret;
> > @@ -177,7 +230,7 @@ static int stk8312_set_range(struct stk8312_data
> > *data, u8 range)
> >
> >  	mode = data->mode;
> >  	/* We need to go in standby mode to modify registers */
> > -	ret = stk8312_set_mode(data, STK8312_MODE_STANDBY);
> > +	ret = stk8312_set_mode(data, !STK8312_POWER_MASK);
> >  	if (ret < 0)
> >  		return ret;
> >
> > @@ -208,12 +261,10 @@ static int stk8312_read_accel(struct stk8312_data
> *data, u8 address)
> >  		return -EINVAL;
> >
> >  	ret = i2c_smbus_read_byte_data(client, address);
> > -	if (ret < 0) {
> > +	if (ret < 0)
> >  		dev_err(&client->dev, "register read failed\n");
> > -		return ret;
> > -	}
> >
> > -	return sign_extend32(ret, 7);
> > +	return ret;
> >  }
> >
> >  static int stk8312_read_raw(struct iio_dev *indio_dev, @@ -221,14
> > +272,27 @@ static int stk8312_read_raw(struct iio_dev *indio_dev,
> >  			    int *val, int *val2, long mask)  {
> >  	struct stk8312_data *data = iio_priv(indio_dev);
> > -
> > -	if (chan->type != IIO_ACCEL)
> > -		return -EINVAL;
> > +	int ret;
> >
> >  	switch (mask) {
> >  	case IIO_CHAN_INFO_RAW:
> > +		if (iio_buffer_enabled(indio_dev))
> > +			return -EBUSY;
> >  		mutex_lock(&data->lock);
> > -		*val = stk8312_read_accel(data, chan->address);
> > +		ret = stk8312_set_mode(data, data->mode |
> STK8312_POWER_MASK);
> > +		if (ret < 0) {
> > +			mutex_unlock(&data->lock);
> > +			return -EINVAL;
> > +		}
> > +		ret = stk8312_read_accel(data, chan->address);
> > +		if (ret < 0) {
> > +			stk8312_set_mode(data,
> > +					 data->mode &
> (~STK8312_POWER_MASK));
> > +			mutex_unlock(&data->lock);
> > +			return -EINVAL;
> > +		}
> > +		*val = sign_extend32(ret, 7);
> > +		stk8312_set_mode(data, data->mode &
> (~STK8312_POWER_MASK));
> >  		mutex_unlock(&data->lock);
> >  		return IIO_VAL_INT;
> >  	case IIO_CHAN_INFO_SCALE:
> > @@ -277,6 +341,93 @@ static const struct iio_info stk8312_info = {
> >  	.attrs			= &stk8312_attribute_group,
> >  };
> >
> > +static irqreturn_t stk8312_trigger_handler(int irq, void *p) {
> > +	struct iio_poll_func *pf = p;
> > +	struct iio_dev *indio_dev = pf->indio_dev;
> > +	struct stk8312_data *data = iio_priv(indio_dev);
> > +	int bit, ret, i = 0;
> > +
> > +	mutex_lock(&data->lock);
> > +	for_each_set_bit(bit, indio_dev->active_scan_mask,
> > +			 indio_dev->masklength) {
> > +		ret = stk8312_read_accel(data, bit);
> > +		if (ret < 0) {
> > +			mutex_unlock(&data->lock);
> > +			goto err;
> > +		}
> > +		data->buffer[i++] = ret;
> > +	}
> > +	mutex_unlock(&data->lock);
> > +
> > +	iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
> > +					   pf->timestamp);
> > +err:
> > +	iio_trigger_notify_done(indio_dev->trig);
> > +
> > +	return IRQ_HANDLED;
> > +}
> > +
> > +static irqreturn_t stk8312_data_rdy_trig_poll(int irq, void *private)
> > +{
> > +	struct iio_dev *indio_dev = private;
> > +	struct stk8312_data *data = iio_priv(indio_dev);
> > +
> > +	if (data->dready_trigger_on)
> > +		iio_trigger_poll(data->dready_trig);
> > +
> > +	return IRQ_HANDLED;
> > +}
> > +
> > +static int stk8312_buffer_preenable(struct iio_dev *indio_dev) {
> > +	struct stk8312_data *data = iio_priv(indio_dev);
> > +
> > +	return stk8312_set_mode(data, data->mode |
> STK8312_POWER_MASK); }
> > +
> > +static int stk8312_buffer_postdisable(struct iio_dev *indio_dev) {
> > +	struct stk8312_data *data = iio_priv(indio_dev);
> > +
> > +	return stk8312_set_mode(data, data->mode &
> (~STK8312_POWER_MASK)); }
> > +
> > +static const struct iio_buffer_setup_ops stk8312_buffer_setup_ops = {
> > +	.preenable   = stk8312_buffer_preenable,
> > +	.postenable  = iio_triggered_buffer_postenable,
> > +	.predisable  = iio_triggered_buffer_predisable,
> > +	.postdisable = stk8312_buffer_postdisable, };
> > +
> > +static int stk8312_gpio_probe(struct i2c_client *client) {
> > +	struct device *dev;
> > +	struct gpio_desc *gpio;
> > +	int ret;
> > +
> > +	if (!client)
> > +		return -EINVAL;
> > +
> > +	dev = &client->dev;
> > +
> > +	/* data ready gpio interrupt pin */
> > +	gpio = devm_gpiod_get_index(dev, STK8312_GPIO, 0);
> > +	if (IS_ERR(gpio)) {
> > +		dev_err(dev, "acpi gpio get index failed\n");
> > +		return PTR_ERR(gpio);
> > +	}
> > +
> > +	ret = gpiod_direction_input(gpio);
> > +	if (ret)
> > +		return ret;
> > +
> > +	ret = gpiod_to_irq(gpio);
> > +	dev_dbg(dev, "GPIO resource, no:%d irq:%d\n", desc_to_gpio(gpio),
> > +ret);
> > +
> > +	return ret;
> > +}
> > +
> >  static int stk8312_probe(struct i2c_client *client,
> >  			 const struct i2c_device_id *id)
> >  {
> > @@ -312,26 +463,86 @@ static int stk8312_probe(struct i2c_client *client,
> >  	if (ret < 0)
> >  		return ret;
> >
> > -	ret = stk8312_set_mode(data, STK8312_MODE_ACTIVE);
> > +	ret = stk8312_set_mode(data, STK8312_INT_MODE |
> STK8312_POWER_MASK);
> >  	if (ret < 0)
> >  		return ret;
> >
> > +	if (client->irq < 0)
> > +		client->irq = stk8312_gpio_probe(client);
> > +
> > +	if (client->irq >= 0) {
> > +		ret = devm_request_threaded_irq(&client->dev, client->irq,
> > +						stk8312_data_rdy_trig_poll,
> > +						NULL,
> > +						IRQF_TRIGGER_RISING |
> > +						IRQF_ONESHOT,
> > +						STK8312_IRQ_NAME,
> > +						indio_dev);
> > +		if (ret < 0) {
> > +			dev_err(&client->dev, "request irq %d failed\n",
> > +				client->irq);
> > +			goto err_power_off;
> > +		}
> > +
> > +		data->dready_trig = devm_iio_trigger_alloc(&client->dev,
> > +							   "%s-dev%d",
> > +							   indio_dev->name,
> > +							   indio_dev->id);
> > +		if (!data->dready_trig) {
> > +			ret = -ENOMEM;
> > +			goto err_power_off;
> > +		}
> > +
> > +		data->dready_trig->dev.parent = &client->dev;
> > +		data->dready_trig->ops = &stk8312_trigger_ops;
> > +		iio_trigger_set_drvdata(data->dready_trig, indio_dev);
> > +		ret = iio_trigger_register(data->dready_trig);
> > +		if (ret) {
> > +			dev_err(&client->dev, "iio trigger register failed\n");
> > +			goto err_power_off;
> > +		}
> > +	}
> > +
> > +	ret = iio_triggered_buffer_setup(indio_dev,
> > +					 iio_pollfunc_store_time,
> > +					 stk8312_trigger_handler,
> > +					 &stk8312_buffer_setup_ops);
> > +	if (ret < 0) {
> > +		dev_err(&client->dev, "iio triggered buffer setup failed\n");
> > +		goto err_trigger_unregister;
> > +	}
> > +
> >  	ret = iio_device_register(indio_dev);
> >  	if (ret < 0) {
> >  		dev_err(&client->dev, "device_register failed\n");
> > -		stk8312_set_mode(data, STK8312_MODE_STANDBY);
> > +		goto err_buffer_cleanup;
> >  	}
> >
> >  	return ret;
> > +
> > +err_buffer_cleanup:
> > +	iio_triggered_buffer_cleanup(indio_dev);
> > +err_trigger_unregister:
> > +	if (data->dready_trig)
> > +		iio_trigger_unregister(data->dready_trig);
> > +err_power_off:
> > +	stk8312_set_mode(data, !STK8312_POWER_MASK);
> > +	return ret;
> >  }
> >
> >  static int stk8312_remove(struct i2c_client *client)  {
> >  	struct iio_dev *indio_dev = i2c_get_clientdata(client);
> > +	struct stk8312_data *data = iio_priv(indio_dev);
> >
> >  	iio_device_unregister(indio_dev);
> >
> > -	return stk8312_set_mode(iio_priv(indio_dev),
> STK8312_MODE_STANDBY);
> > +	if (data->dready_trig) {
> > +		iio_triggered_buffer_cleanup(indio_dev);
> > +		iio_trigger_unregister(data->dready_trig);
> > +	}
> > +
> > +	return stk8312_set_mode(data, !STK8312_POWER_MASK);
> Boolean not?  Not sure what intent is here, but seems likely you just want
> the same write as in stk8312_suspend.

If we're entering suspend, I assume we'll also resume the driver, so we want
the mode bits restored. If we're removing the driver module, we might as well
reset the mode to its default value (0). Also, set_mode doesn't take a bool,
but a u8 as a second parameter.

> >  }
> >
> >  #ifdef CONFIG_PM_SLEEP
> > @@ -341,7 +552,7 @@ static int stk8312_suspend(struct device *dev)
> >
> >  	data = iio_priv(i2c_get_clientdata(to_i2c_client(dev)));
> >
> > -	return stk8312_set_mode(data, STK8312_MODE_STANDBY);
> > +	return stk8312_set_mode(data, data->mode &
> (~STK8312_POWER_MASK));
> >  }
> >
> >  static int stk8312_resume(struct device *dev) @@ -350,7 +561,7 @@
> > static int stk8312_resume(struct device *dev)
> >
> >  	data = iio_priv(i2c_get_clientdata(to_i2c_client(dev)));
> >
> > -	return stk8312_set_mode(data, STK8312_MODE_ACTIVE);
> > +	return stk8312_set_mode(data, data->mode |
> STK8312_POWER_MASK);
> >  }
> >
> >  static SIMPLE_DEV_PM_OPS(stk8312_pm_ops, stk8312_suspend,
> > stk8312_resume);
> >


^ permalink raw reply	[flat|nested] 4+ messages in thread

* RE: [PATCH] iio: accel: Add buffer mode for Sensortek STK8312
  2015-06-15 13:06   ` Breana, Tiberiu A
@ 2015-06-15 17:25     ` Jonathan Cameron
  0 siblings, 0 replies; 4+ messages in thread
From: Jonathan Cameron @ 2015-06-15 17:25 UTC (permalink / raw)
  To: Breana, Tiberiu A, linux-iio



On 15 June 2015 14:06:42 BST, "Breana, Tiberiu A" <tiberiu.a.breana@intel.com> wrote:
>> -----Original Message-----
>> From: Jonathan Cameron [mailto:jic23@kernel.org]
>> Sent: Sunday, June 14, 2015 2:07 PM
>> To: Breana, Tiberiu A; linux-iio@vger.kernel.org
>> Subject: Re: [PATCH] iio: accel: Add buffer mode for Sensortek
>STK8312
>> 
>> On 09/06/15 13:20, Tiberiu Breana wrote:
>> > Added triggered buffer mode support for the STK8312 accelerometer.
>> >
>> > Additional changes:
>> > - set_mode now sets operation mode directly, no longer masking
>> >   the register's previous value
>> > - read_accel now returns raw acceleration data instead of the
>> >   sign_extend32 value
>> > - read_raw will now enable/disable the sensor with each reading
>> >
>> > Signed-off-by: Tiberiu Breana <tiberiu.a.breana@intel.com>
>> A few bits and bobs inline.
>> 
>> Jonathan
>
>Thanks for your review. I'm adding some clarifications inline.
>v2 will follow soon.
>
>Tiberiu
>
>> > ---
>> >  drivers/iio/accel/stk8312.c | 281
>> > ++++++++++++++++++++++++++++++++++++++------
>> >  1 file changed, 246 insertions(+), 35 deletions(-)
>> >
>> > diff --git a/drivers/iio/accel/stk8312.c
>b/drivers/iio/accel/stk8312.c
>> > index d211d9f3..12ad95e 100644
>> > --- a/drivers/iio/accel/stk8312.c
>> > +++ b/drivers/iio/accel/stk8312.c
>> > @@ -11,16 +11,23 @@
>> >   */
>> >
>> >  #include <linux/acpi.h>
>> > +#include <linux/gpio/consumer.h>
>> >  #include <linux/i2c.h>
>> > +#include <linux/interrupt.h>
>> >  #include <linux/kernel.h>
>> >  #include <linux/module.h>
>> >  #include <linux/delay.h>
>> > +#include <linux/iio/buffer.h>
>> >  #include <linux/iio/iio.h>
>> >  #include <linux/iio/sysfs.h>
>> > +#include <linux/iio/trigger.h>
>> > +#include <linux/iio/triggered_buffer.h> #include
>> > +<linux/iio/trigger_consumer.h>
>> >
>> >  #define STK8312_REG_XOUT		0x00
>> >  #define STK8312_REG_YOUT		0x01
>> >  #define STK8312_REG_ZOUT		0x02
>> > +#define STK8312_REG_INTSU		0x06
>> >  #define STK8312_REG_MODE		0x07
>> >  #define STK8312_REG_STH			0x13
>> >  #define STK8312_REG_RESET		0x20
>> > @@ -29,14 +36,17 @@
>> >  #define STK8312_REG_OTPDATA		0x3E
>> >  #define STK8312_REG_OTPCTRL		0x3F
>> >
>> > -#define STK8312_MODE_ACTIVE		1
>> > -#define STK8312_MODE_STANDBY		0
>> These single bits dont' particularly strike me as 'masks'
>> Rather they are straight forward boolean controls.
>> > +#define STK8312_POWER_MASK		0x01
>> >  #define STK8312_MODE_MASK		0x01
>> > +#define STK8312_DREADY_MASK		0x10
>> > +#define STK8312_INT_MODE		0xC0
>> >  #define STK8312_RNG_MASK		0xC0
>> >  #define STK8312_RNG_SHIFT		6
>> >  #define STK8312_READ_RETRIES		16
>> >
>> >  #define STK8312_DRIVER_NAME		"stk8312"
>> > +#define STK8312_GPIO			"stk8312_gpio"
>> > +#define STK8312_IRQ_NAME		"stk8312_event"
>> >
>> >  /*
>> >   * The accelerometer has two measurement ranges:
>> > @@ -53,19 +63,27 @@ static const int stk8312_scale_table[][2] = {
>> >  	{0, 461600}, {1, 231100}
>> >  };
>> >
>> > -#define STK8312_ACCEL_CHANNEL(reg, axis) {			\
>> > +#define STK8312_ACCEL_CHANNEL(index, reg, axis) {		\
>> >  	.type = IIO_ACCEL,					\
>> >  	.address = reg,						\
>> >  	.modified = 1,						\
>> >  	.channel2 = IIO_MOD_##axis,				\
>> >  	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),		\
>> >  	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),	\
>> > +	.scan_index = index,					\
>> > +	.scan_type = {						\
>> > +		.sign = 's',					\
>> > +		.realbits = 8,					\
>> > +		.storagebits = 8,				\
>> > +		.endianness = IIO_CPU,				\
>> > +	},							\
>> >  }
>> >
>> >  static const struct iio_chan_spec stk8312_channels[] = {
>> > -	STK8312_ACCEL_CHANNEL(STK8312_REG_XOUT, X),
>> > -	STK8312_ACCEL_CHANNEL(STK8312_REG_YOUT, Y),
>> > -	STK8312_ACCEL_CHANNEL(STK8312_REG_ZOUT, Z),
>> > +	STK8312_ACCEL_CHANNEL(0, STK8312_REG_XOUT, X),
>> > +	STK8312_ACCEL_CHANNEL(1, STK8312_REG_YOUT, Y),
>> > +	STK8312_ACCEL_CHANNEL(2, STK8312_REG_ZOUT, Z),
>> > +	IIO_CHAN_SOFT_TIMESTAMP(3),
>> >  };
>> >
>> >  struct stk8312_data {
>> > @@ -73,6 +91,9 @@ struct stk8312_data {
>> >  	struct mutex lock;
>> >  	int range;
>> >  	u8 mode;
>> > +	struct iio_trigger *dready_trig;
>> > +	bool dready_trigger_on;
>> > +	s8 buffer[11]; /* 3 x 8-bit channels + 64-bit timestamp */
>> Allow for alignment.  So you need to 64 bit align that timestamp.
>> hence 3 x 8(channels) + 7x8 padding  + 8x8 timestamp.
>
>I think you mean 5x8 padding?
Yup. I clearly can't count!
>Regardless, I've tested the driver with the generic_buffer tool from
>tools/iio,
>both with and without padding, and the timestamps looked fine.
Without the extra space you will be
 getting a buffer overrun but chances are there will be nothing there so you won't
 see any corruption.
>
>> >  };
>> >
>> >  static IIO_CONST_ATTR(in_accel_scale_available,
>STK8312_SCALE_AVAIL);
>> > @@ -130,31 +151,19 @@ exit_err:
>> >  static int stk8312_set_mode(struct stk8312_data *data, u8 mode)  {
>> >  	int ret;
>> > -	u8 masked_reg;
>> >  	struct i2c_client *client = data->client;
>> >
>> > -	if (mode > 1)
>> > -		return -EINVAL;
>> > -	else if (mode == data->mode)
>> > +	if (mode == data->mode)
>> >  		return 0;
>> >
>> > -	ret = i2c_smbus_read_byte_data(client, STK8312_REG_MODE);
>> > -	if (ret < 0) {
>> > -		dev_err(&client->dev, "failed to change sensor mode\n");
>> > -		return ret;
>> > -	}
>> > -	masked_reg = ret & (~STK8312_MODE_MASK);
>> > -	masked_reg |= mode;
>> > -
>> > -	ret = i2c_smbus_write_byte_data(client,
>> > -			STK8312_REG_MODE, masked_reg);
>> > +	ret = i2c_smbus_write_byte_data(client, STK8312_REG_MODE,
>> mode);
>> >  	if (ret < 0) {
>> >  		dev_err(&client->dev, "failed to change sensor mode\n");
>> >  		return ret;
>> >  	}
>> >
>> >  	data->mode = mode;
>> > -	if (mode == STK8312_MODE_ACTIVE) {
>> > +	if (mode & STK8312_POWER_MASK) {
>> >  		/* Need to run OTP sequence before entering active mode
>> */
>> >  		usleep_range(1000, 5000);
>> >  		ret = stk8312_otp_init(data);
>> > @@ -163,6 +172,50 @@ static int stk8312_set_mode(struct
>stk8312_data
>> *data, u8 mode)
>> >  	return ret;
>> >  }
>> >
>> > +static int stk8312_set_interrupts(struct stk8312_data *data, u8
>> > +int_mask) {
>> > +	int ret;
>> > +	u8 mode;
>> > +	struct i2c_client *client = data->client;
>> > +
>> > +	mode = data->mode;
>> > +	/* We need to go in standby mode to modify registers */
>> > +	ret = stk8312_set_mode(data, !STK8312_POWER_MASK);
>> > +	if (ret < 0)
>> > +		return ret;
>> > +
>> > +	ret = i2c_smbus_write_byte_data(client, STK8312_REG_INTSU,
>> int_mask);
>> > +	if (ret < 0)
>> > +		dev_err(&client->dev, "failed to set interrupts\n");
>> With a failure here, should you be continuing to set the mode?
>
>Well, regardless if we succeed or fail in setting the interrupt
>register,
>we need to return to the mode we were in before entering this function.
>
>> > +
>> > +	return stk8312_set_mode(data, mode); }
>> > +
>> > +static int stk8312_data_rdy_trigger_set_state(struct iio_trigger
>*trig,
>> > +					      bool state)
>> > +{
>> > +	struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
>> > +	struct stk8312_data *data = iio_priv(indio_dev);
>> > +	int ret;
>> > +
>> > +	if (state)
>> > +		ret = stk8312_set_interrupts(data, STK8312_DREADY_MASK);
>> > +	else
>> > +		ret = stk8312_set_interrupts(data, 0x00);
>> > +
>> > +	if (ret < 0)
>> > +		dev_err(&data->client->dev, "failed to set trigger stare\n");
>> return in the error path here and drop the else.  Gives a more
>conventional
>> form to the function making reviewing a tiny bit easier!
>> > +	else
>> > +		data->dready_trigger_on = state;
>> > +
>> > +	return ret;
>> > +}
>> > +
>> > +static const struct iio_trigger_ops stk8312_trigger_ops = {
>> > +	.set_trigger_state = stk8312_data_rdy_trigger_set_state,
>> > +	.owner = THIS_MODULE,
>> > +};
>> > +
>> >  static int stk8312_set_range(struct stk8312_data *data, u8 range) 
>{
>> >  	int ret;
>> > @@ -177,7 +230,7 @@ static int stk8312_set_range(struct
>stk8312_data
>> > *data, u8 range)
>> >
>> >  	mode = data->mode;
>> >  	/* We need to go in standby mode to modify registers */
>> > -	ret = stk8312_set_mode(data, STK8312_MODE_STANDBY);
>> > +	ret = stk8312_set_mode(data, !STK8312_POWER_MASK);
>> >  	if (ret < 0)
>> >  		return ret;
>> >
>> > @@ -208,12 +261,10 @@ static int stk8312_read_accel(struct
>stk8312_data
>> *data, u8 address)
>> >  		return -EINVAL;
>> >
>> >  	ret = i2c_smbus_read_byte_data(client, address);
>> > -	if (ret < 0) {
>> > +	if (ret < 0)
>> >  		dev_err(&client->dev, "register read failed\n");
>> > -		return ret;
>> > -	}
>> >
>> > -	return sign_extend32(ret, 7);
>> > +	return ret;
>> >  }
>> >
>> >  static int stk8312_read_raw(struct iio_dev *indio_dev, @@ -221,14
>> > +272,27 @@ static int stk8312_read_raw(struct iio_dev *indio_dev,
>> >  			    int *val, int *val2, long mask)  {
>> >  	struct stk8312_data *data = iio_priv(indio_dev);
>> > -
>> > -	if (chan->type != IIO_ACCEL)
>> > -		return -EINVAL;
>> > +	int ret;
>> >
>> >  	switch (mask) {
>> >  	case IIO_CHAN_INFO_RAW:
>> > +		if (iio_buffer_enabled(indio_dev))
>> > +			return -EBUSY;
>> >  		mutex_lock(&data->lock);
>> > -		*val = stk8312_read_accel(data, chan->address);
>> > +		ret = stk8312_set_mode(data, data->mode |
>> STK8312_POWER_MASK);
>> > +		if (ret < 0) {
>> > +			mutex_unlock(&data->lock);
>> > +			return -EINVAL;
>> > +		}
>> > +		ret = stk8312_read_accel(data, chan->address);
>> > +		if (ret < 0) {
>> > +			stk8312_set_mode(data,
>> > +					 data->mode &
>> (~STK8312_POWER_MASK));
>> > +			mutex_unlock(&data->lock);
>> > +			return -EINVAL;
>> > +		}
>> > +		*val = sign_extend32(ret, 7);
>> > +		stk8312_set_mode(data, data->mode &
>> (~STK8312_POWER_MASK));
>> >  		mutex_unlock(&data->lock);
>> >  		return IIO_VAL_INT;
>> >  	case IIO_CHAN_INFO_SCALE:
>> > @@ -277,6 +341,93 @@ static const struct iio_info stk8312_info = {
>> >  	.attrs			= &stk8312_attribute_group,
>> >  };
>> >
>> > +static irqreturn_t stk8312_trigger_handler(int irq, void *p) {
>> > +	struct iio_poll_func *pf = p;
>> > +	struct iio_dev *indio_dev = pf->indio_dev;
>> > +	struct stk8312_data *data = iio_priv(indio_dev);
>> > +	int bit, ret, i = 0;
>> > +
>> > +	mutex_lock(&data->lock);
>> > +	for_each_set_bit(bit, indio_dev->active_scan_mask,
>> > +			 indio_dev->masklength) {
>> > +		ret = stk8312_read_accel(data, bit);
>> > +		if (ret < 0) {
>> > +			mutex_unlock(&data->lock);
>> > +			goto err;
>> > +		}
>> > +		data->buffer[i++] = ret;
>> > +	}
>> > +	mutex_unlock(&data->lock);
>> > +
>> > +	iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
>> > +					   pf->timestamp);
>> > +err:
>> > +	iio_trigger_notify_done(indio_dev->trig);
>> > +
>> > +	return IRQ_HANDLED;
>> > +}
>> > +
>> > +static irqreturn_t stk8312_data_rdy_trig_poll(int irq, void
>*private)
>> > +{
>> > +	struct iio_dev *indio_dev = private;
>> > +	struct stk8312_data *data = iio_priv(indio_dev);
>> > +
>> > +	if (data->dready_trigger_on)
>> > +		iio_trigger_poll(data->dready_trig);
>> > +
>> > +	return IRQ_HANDLED;
>> > +}
>> > +
>> > +static int stk8312_buffer_preenable(struct iio_dev *indio_dev) {
>> > +	struct stk8312_data *data = iio_priv(indio_dev);
>> > +
>> > +	return stk8312_set_mode(data, data->mode |
>> STK8312_POWER_MASK); }
>> > +
>> > +static int stk8312_buffer_postdisable(struct iio_dev *indio_dev) {
>> > +	struct stk8312_data *data = iio_priv(indio_dev);
>> > +
>> > +	return stk8312_set_mode(data, data->mode &
>> (~STK8312_POWER_MASK)); }
>> > +
>> > +static const struct iio_buffer_setup_ops stk8312_buffer_setup_ops
>= {
>> > +	.preenable   = stk8312_buffer_preenable,
>> > +	.postenable  = iio_triggered_buffer_postenable,
>> > +	.predisable  = iio_triggered_buffer_predisable,
>> > +	.postdisable = stk8312_buffer_postdisable, };
>> > +
>> > +static int stk8312_gpio_probe(struct i2c_client *client) {
>> > +	struct device *dev;
>> > +	struct gpio_desc *gpio;
>> > +	int ret;
>> > +
>> > +	if (!client)
>> > +		return -EINVAL;
>> > +
>> > +	dev = &client->dev;
>> > +
>> > +	/* data ready gpio interrupt pin */
>> > +	gpio = devm_gpiod_get_index(dev, STK8312_GPIO, 0);
>> > +	if (IS_ERR(gpio)) {
>> > +		dev_err(dev, "acpi gpio get index failed\n");
>> > +		return PTR_ERR(gpio);
>> > +	}
>> > +
>> > +	ret = gpiod_direction_input(gpio);
>> > +	if (ret)
>> > +		return ret;
>> > +
>> > +	ret = gpiod_to_irq(gpio);
>> > +	dev_dbg(dev, "GPIO resource, no:%d irq:%d\n", desc_to_gpio(gpio),
>> > +ret);
>> > +
>> > +	return ret;
>> > +}
>> > +
>> >  static int stk8312_probe(struct i2c_client *client,
>> >  			 const struct i2c_device_id *id)
>> >  {
>> > @@ -312,26 +463,86 @@ static int stk8312_probe(struct i2c_client
>*client,
>> >  	if (ret < 0)
>> >  		return ret;
>> >
>> > -	ret = stk8312_set_mode(data, STK8312_MODE_ACTIVE);
>> > +	ret = stk8312_set_mode(data, STK8312_INT_MODE |
>> STK8312_POWER_MASK);
>> >  	if (ret < 0)
>> >  		return ret;
>> >
>> > +	if (client->irq < 0)
>> > +		client->irq = stk8312_gpio_probe(client);
>> > +
>> > +	if (client->irq >= 0) {
>> > +		ret = devm_request_threaded_irq(&client->dev, client->irq,
>> > +						stk8312_data_rdy_trig_poll,
>> > +						NULL,
>> > +						IRQF_TRIGGER_RISING |
>> > +						IRQF_ONESHOT,
>> > +						STK8312_IRQ_NAME,
>> > +						indio_dev);
>> > +		if (ret < 0) {
>> > +			dev_err(&client->dev, "request irq %d failed\n",
>> > +				client->irq);
>> > +			goto err_power_off;
>> > +		}
>> > +
>> > +		data->dready_trig = devm_iio_trigger_alloc(&client->dev,
>> > +							   "%s-dev%d",
>> > +							   indio_dev->name,
>> > +							   indio_dev->id);
>> > +		if (!data->dready_trig) {
>> > +			ret = -ENOMEM;
>> > +			goto err_power_off;
>> > +		}
>> > +
>> > +		data->dready_trig->dev.parent = &client->dev;
>> > +		data->dready_trig->ops = &stk8312_trigger_ops;
>> > +		iio_trigger_set_drvdata(data->dready_trig, indio_dev);
>> > +		ret = iio_trigger_register(data->dready_trig);
>> > +		if (ret) {
>> > +			dev_err(&client->dev, "iio trigger register failed\n");
>> > +			goto err_power_off;
>> > +		}
>> > +	}
>> > +
>> > +	ret = iio_triggered_buffer_setup(indio_dev,
>> > +					 iio_pollfunc_store_time,
>> > +					 stk8312_trigger_handler,
>> > +					 &stk8312_buffer_setup_ops);
>> > +	if (ret < 0) {
>> > +		dev_err(&client->dev, "iio triggered buffer setup failed\n");
>> > +		goto err_trigger_unregister;
>> > +	}
>> > +
>> >  	ret = iio_device_register(indio_dev);
>> >  	if (ret < 0) {
>> >  		dev_err(&client->dev, "device_register failed\n");
>> > -		stk8312_set_mode(data, STK8312_MODE_STANDBY);
>> > +		goto err_buffer_cleanup;
>> >  	}
>> >
>> >  	return ret;
>> > +
>> > +err_buffer_cleanup:
>> > +	iio_triggered_buffer_cleanup(indio_dev);
>> > +err_trigger_unregister:
>> > +	if (data->dready_trig)
>> > +		iio_trigger_unregister(data->dready_trig);
>> > +err_power_off:
>> > +	stk8312_set_mode(data, !STK8312_POWER_MASK);
>> > +	return ret;
>> >  }
>> >
>> >  static int stk8312_remove(struct i2c_client *client)  {
>> >  	struct iio_dev *indio_dev = i2c_get_clientdata(client);
>> > +	struct stk8312_data *data = iio_priv(indio_dev);
>> >
>> >  	iio_device_unregister(indio_dev);
>> >
>> > -	return stk8312_set_mode(iio_priv(indio_dev),
>> STK8312_MODE_STANDBY);
>> > +	if (data->dready_trig) {
>> > +		iio_triggered_buffer_cleanup(indio_dev);
>> > +		iio_trigger_unregister(data->dready_trig);
>> > +	}
>> > +
>> > +	return stk8312_set_mode(data, !STK8312_POWER_MASK);
>> Boolean not?  Not sure what intent is here, but seems likely you just
>want
>> the same write as in stk8312_suspend.
>
>If we're entering suspend, I assume we'll also resume the driver, so we
>want
>the mode bits restored. If we're removing the driver module, we might
>as well
>reset the mode to its default value (0). Also, set_mode doesn't take a
>bool,
>but a u8 as a second parameter.
Quite. The ! Above gives a boolean.
That is the bug. You mean ~.

>
>> >  }
>> >
>> >  #ifdef CONFIG_PM_SLEEP
>> > @@ -341,7 +552,7 @@ static int stk8312_suspend(struct device *dev)
>> >
>> >  	data = iio_priv(i2c_get_clientdata(to_i2c_client(dev)));
>> >
>> > -	return stk8312_set_mode(data, STK8312_MODE_STANDBY);
>> > +	return stk8312_set_mode(data, data->mode &
>> (~STK8312_POWER_MASK));
>> >  }
>> >
>> >  static int stk8312_resume(struct device *dev) @@ -350,7 +561,7 @@
>> > static int stk8312_resume(struct device *dev)
>> >
>> >  	data = iio_priv(i2c_get_clientdata(to_i2c_client(dev)));
>> >
>> > -	return stk8312_set_mode(data, STK8312_MODE_ACTIVE);
>> > +	return stk8312_set_mode(data, data->mode |
>> STK8312_POWER_MASK);
>> >  }
>> >
>> >  static SIMPLE_DEV_PM_OPS(stk8312_pm_ops, stk8312_suspend,
>> > stk8312_resume);
>> >
>
>--
>To unsubscribe from this list: send the line "unsubscribe linux-iio" in
>the body of a message to majordomo@vger.kernel.org
>More majordomo info at  http://vger.kernel.org/majordomo-info.html

-- 
Sent from my Android device with K-9 Mail. Please excuse my brevity.

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2015-06-15 17:26 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-06-09 12:20 [PATCH] iio: accel: Add buffer mode for Sensortek STK8312 Tiberiu Breana
2015-06-14 11:07 ` Jonathan Cameron
2015-06-15 13:06   ` Breana, Tiberiu A
2015-06-15 17:25     ` Jonathan Cameron

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.