linux-iio.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Hartmut Knaack <knaack.h@gmx.de>
To: Octavian Purdila <octavian.purdila@intel.com>, linux-iio@vger.kernel.org
Cc: srinivas.pandruvada@intel.com
Subject: Re: [RFC 8/8] iio: bmc150: add support for hardware fifo
Date: Mon, 24 Nov 2014 11:37:24 +0100	[thread overview]
Message-ID: <54730A64.3060003@gmx.de> (raw)
In-Reply-To: <1416246966-3083-9-git-send-email-octavian.purdila@intel.com>

Octavian Purdila schrieb am 17.11.2014 18:56:
> This patch adds support for hardware fifo. Fifo and stream mode are
> supported as well as fifo-full and fifo-watermark events.
> 
> Signed-off-by: Octavian Purdila <octavian.purdila@intel.com>
> ---
>  drivers/iio/accel/bmc150-accel.c | 249 ++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 243 insertions(+), 6 deletions(-)
> 
> diff --git a/drivers/iio/accel/bmc150-accel.c b/drivers/iio/accel/bmc150-accel.c
> index 72d2dca..404cfec 100644
> --- a/drivers/iio/accel/bmc150-accel.c
> +++ b/drivers/iio/accel/bmc150-accel.c
> @@ -67,7 +67,9 @@
>  #define BMC150_ACCEL_INT_MAP_0_BIT_SLOPE	BIT(2)
>  
>  #define BMC150_ACCEL_REG_INT_MAP_1		0x1A
> -#define BMC150_ACCEL_INT_MAP_1_BIT_DATA	BIT(0)
> +#define BMC150_ACCEL_INT_MAP_1_BIT_DATA		BIT(0)
> +#define BMC150_ACCEL_INT_MAP_1_BIT_FWM		BIT(1)
> +#define BMC150_ACCEL_INT_MAP_1_BIT_FFULL	BIT(2)
>  
>  #define BMC150_ACCEL_REG_INT_RST_LATCH		0x21
>  #define BMC150_ACCEL_INT_MODE_LATCH_RESET	0x80
> @@ -80,7 +82,9 @@
>  #define BMC150_ACCEL_INT_EN_BIT_SLP_Z		BIT(2)
>  
>  #define BMC150_ACCEL_REG_INT_EN_1		0x17
> -#define BMC150_ACCEL_INT_EN_BIT_DATA_EN	BIT(4)
> +#define BMC150_ACCEL_INT_EN_BIT_DATA_EN		BIT(4)
> +#define BMC150_ACCEL_INT_EN_BIT_FFULL_EN	BIT(5)
> +#define BMC150_ACCEL_INT_EN_BIT_FWM_EN		BIT(6)
>  
>  #define BMC150_ACCEL_REG_INT_OUT_CTRL		0x20
>  #define BMC150_ACCEL_INT_OUT_CTRL_INT1_LVL	BIT(0)
> @@ -119,6 +123,13 @@
>  #define BMC150_ACCEL_AXIS_TO_REG(axis)	(BMC150_ACCEL_REG_XOUT_L + (axis * 2))
>  #define BMC150_AUTO_SUSPEND_DELAY_MS		2000
>  
> +#define BMC150_ACCEL_REG_FIFO_STATUS		0x0E
> +#define BMC150_ACCEL_REG_FIFO_CONFIG0		0x30
> +#define BMC150_ACCEL_REG_FIFO_CONFIG1		0x3E
> +#define BMC150_ACCEL_REG_FIFO_DATA		0x3F
> +#define BMC150_ACCEL_REG_FIFO_
Something got lost here?
> +#define BMC150_ACCEL_FIFO_LENGTH		32
> +
>  enum bmc150_accel_axis {
>  	AXIS_X,
>  	AXIS_Y,
> @@ -177,12 +188,13 @@ struct bmc150_accel_event {
>  			u32 duration;
>  			u32 threshold;
>  		} slope;
> +		u8 watermark;
>  	};
>  };
>  
> -#define BMC150_ACCEL_INTERRUPTS		2
> +#define BMC150_ACCEL_INTERRUPTS		4
>  #define BMC150_ACCEL_TRIGGERS		2
> -#define BMC150_ACCEL_EVENTS		1
> +#define BMC150_ACCEL_EVENTS		3
>  
>  struct bmc150_accel_data {
>  	struct i2c_client *client;
> @@ -191,6 +203,7 @@ struct bmc150_accel_data {
>  	struct bmc150_accel_trigger triggers[BMC150_ACCEL_TRIGGERS];
>  	struct bmc150_accel_event events[BMC150_ACCEL_EVENTS];
>  	struct mutex mutex;
> +	int fifo_mode;
>  	s16 buffer[8];
>  	u8 bw_bits;
>  	u32 range;
> @@ -483,6 +496,18 @@ bmc150_accel_interrupts[BMC150_ACCEL_INTERRUPTS] = {
>  			BMC150_ACCEL_INT_EN_BIT_SLP_Y |
>  			BMC150_ACCEL_INT_EN_BIT_SLP_Z
>  	},
> +	{ /* fifo full interrupt */
> +		.map_reg = BMC150_ACCEL_REG_INT_MAP_1,
> +		.map_bitmask = BMC150_ACCEL_INT_MAP_1_BIT_FFULL,
> +		.en_reg = BMC150_ACCEL_REG_INT_EN_1,
> +		.en_bitmask = BMC150_ACCEL_INT_EN_BIT_FFULL_EN,
> +	},
> +	{ /* fifo watermark interrupt */
> +		.map_reg = BMC150_ACCEL_REG_INT_MAP_1,
> +		.map_bitmask = BMC150_ACCEL_INT_MAP_1_BIT_FWM,
> +		.en_reg = BMC150_ACCEL_REG_INT_EN_1,
> +		.en_bitmask = BMC150_ACCEL_INT_EN_BIT_FWM_EN,
> +	},
>  };
>  
>  static void bmc150_accel_interrupts_setup(struct iio_dev *indio_dev,
> @@ -699,11 +724,85 @@ static int bmc150_accel_read_raw(struct iio_dev *indio_dev,
>  		ret = bmc150_accel_get_bw(data, val, val2);
>  		mutex_unlock(&data->mutex);
>  		return ret;
> +	case IIO_CHAN_INFO_FIFO_LENGTH:
> +		*val2 = 0;
> +		*val = BMC150_ACCEL_FIFO_LENGTH;
> +		return IIO_VAL_INT;
>  	default:
>  		return -EINVAL;
>  	}
>  }
>  
> +static int bmc150_accel_fifo_flush(struct iio_dev *indio_dev)
> +{
> +	struct bmc150_accel_data *data = iio_priv(indio_dev);
> +	int ret, i;
> +	u8 count;
> +	u16 buffer[BMC150_ACCEL_FIFO_LENGTH * 3];
> +	u8 reg_fifo_data = BMC150_ACCEL_REG_FIFO_DATA;
> +	struct i2c_msg msg[2];
> +	int64_t tstamp;
> +	int sample_freq = 0, sec, ms;
> +
> +	ret = bmc150_accel_get_bw(data, &sec, &ms);
> +	if (ret == 0)
ret can be IIO_VAL_INT_PLUS_MICRO or -EINVAL, but not 0.
> +		sample_freq = sec * 1000000000 + ms * 1000;
> +
> +	ret = i2c_smbus_read_byte_data(data->client,
> +				       BMC150_ACCEL_REG_FIFO_STATUS);
> +	if (ret < 0) {
> +		dev_err(&indio_dev->dev, "Error reading reg_fifo_status\n");
> +		return ret;
> +	}
> +
> +	count = ret & 0x7F;
> +
> +	i = i2c_smbus_read_byte_data(data->client,
> +				     BMC150_ACCEL_REG_FIFO_CONFIG1);
This read doesn't seem to serve a purpose
> +	if (!count)
> +		return 0;
> +
> +	msg[0].addr = data->client->addr;
> +	msg[0].flags = 0;
> +	msg[0].buf = &reg_fifo_data;
> +	msg[0].len = sizeof(reg_fifo_data);
> +
> +	msg[1].addr = data->client->addr;
> +	msg[1].flags = I2C_M_RD;
> +	msg[1].buf = (u8 *)buffer;
> +	msg[1].len = count * 3 * 2;
> +
> +	ret = i2c_transfer(data->client->adapter, msg, 2);
> +	if (ret != 2) {
> +		dev_err(&indio_dev->dev, "Error reading reg_fifo_data\n");
> +		return ret;
> +	}
> +
> +	if (!data->timestamp)
> +		data->timestamp = iio_get_time_ns();
> +
> +	tstamp = data->timestamp - count * sample_freq;
> +
> +	for (i = 0; i < count; i++) {
> +		u16 sample[8];
> +		int j, bit;
> +
> +		j = 0;
> +		for_each_set_bit(bit, indio_dev->buffer->scan_mask,
> +				 indio_dev->masklength) {
> +			memcpy(&sample[j++], &buffer[i * 3 + bit], 2);
> +		}
> +
> +		iio_push_to_buffers_with_timestamp(indio_dev, sample, tstamp);
> +
> +		tstamp += sample_freq;
> +	}
> +
> +	data->timestamp = 0;
> +
> +	return 0;
> +}
> +
>  static int bmc150_accel_write_raw(struct iio_dev *indio_dev,
>  				  struct iio_chan_spec const *chan,
>  				  int val, int val2, long mask)
> @@ -725,6 +824,8 @@ static int bmc150_accel_write_raw(struct iio_dev *indio_dev,
>  		ret = bmc150_accel_set_scale(data, val2);
>  		mutex_unlock(&data->mutex);
>  		return ret;
> +	case IIO_CHAN_INFO_FIFO_FLUSH:
> +		return bmc150_accel_fifo_flush(indio_dev);
You may want to trigger this for specific values written to that file?
>  	default:
>  		ret = -EINVAL;
>  	}
> @@ -764,6 +865,22 @@ static int bmc150_accel_event_roc_read(struct bmc150_accel_event *event,
>  	return IIO_VAL_INT;
>  }
>  
> +static int bmc150_accel_event_watermark_read(struct bmc150_accel_event *event,
> +					     enum iio_event_info info,
> +					     int *val, int *val2)
> +{
> +	*val2 = 0;
> +	switch (info) {
> +	case IIO_EV_INFO_VALUE:
> +		*val = event->watermark;
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	return IIO_VAL_INT;
> +}
> +
>  static int bmc150_accel_read_event(struct iio_dev *indio_dev,
>  				   const struct iio_chan_spec *chan,
>  				   enum iio_event_type type,
> @@ -807,6 +924,38 @@ static int bmc150_accel_event_roc_write(struct bmc150_accel_event *event,
>  	return ret;
>  }
>  
> +static int bmc150_accel_event_watermark_write(struct bmc150_accel_event *event,
> +					      enum iio_event_info info,
> +					      int val, int val2)
> +{
> +	struct bmc150_accel_data *data = event->data;
> +	int ret;
> +
> +
> +	switch (info) {
> +	case IIO_EV_INFO_VALUE:
> +		if (val > BMC150_ACCEL_FIFO_LENGTH) {
> +			ret = -EINVAL;
> +			break;
> +		}
> +		mutex_lock(&data->mutex);
> +		ret = i2c_smbus_write_byte_data(data->client,
> +						BMC150_ACCEL_REG_FIFO_CONFIG0,
> +						val);
> +		if (ret < 0) {
> +			dev_err(&data->client->dev, "Error writing reg_fifo_config0\n");
> +			break;
> +		}
> +		event->watermark = val;
> +		mutex_unlock(&data->mutex);
> +		break;
> +	default:
> +		ret = -EINVAL;
> +	}
> +
> +	return ret;
> +}
> +
>  static int bmc150_accel_write_event(struct iio_dev *indio_dev,
>  				    const struct iio_chan_spec *chan,
>  				    enum iio_event_type type,
> @@ -900,6 +1049,76 @@ static const struct iio_event_spec bmc150_accel_events[BMC150_ACCEL_EVENTS] = {
>  				 BIT(IIO_EV_INFO_ENABLE) |
>  				 BIT(IIO_EV_INFO_PERIOD)
>  	},
> +	{
> +		.type = IIO_EV_TYPE_FIFO_FULL,
> +		.dir = IIO_EV_DIR_RISING,
> +		.mask_separate = BIT(IIO_EV_INFO_ENABLE)
> +	},
> +	{
> +		.type = IIO_EV_TYPE_FIFO_WATERMARK,
> +		.dir = IIO_EV_DIR_RISING,
> +		.mask_separate = BIT(IIO_EV_INFO_ENABLE) |
> +				 BIT(IIO_EV_INFO_VALUE)
> +	},
> +};
> +
> +
> +static const char * const bmc150_accel_fifo_modes[] = {
> +	"disabled",
> +	"fifo",
> +	"stream"
> +};
> +
> +static int bmc150_accel_fifo_mode_set(struct iio_dev *indio_dev,
> +				      const struct iio_chan_spec *chan,
> +				      unsigned int mode)
> +{
> +	struct bmc150_accel_data *data = iio_priv(indio_dev);
> +	int ret;
> +	u8 val;
> +
> +	switch (mode) {
> +	case 0:
> +		val = 0;
> +		break;
> +	case 1:
> +		val = 0x40;
> +		break;
> +	case 2:
> +		val = 0x80;
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	ret = i2c_smbus_write_byte_data(data->client,
> +					BMC150_ACCEL_REG_FIFO_CONFIG1, val);
> +	if (ret < 0)
> +		dev_err(&indio_dev->dev, "Error writing reg_fifo_config1\n");
> +
> +	data->fifo_mode  = mode;
> +
> +	return ret;
> +}
> +
> +static int bmc150_accel_fifo_mode_get(struct iio_dev *indio_dev,
> +				      const struct iio_chan_spec *chan)
> +{
> +	struct bmc150_accel_data *data = iio_priv(indio_dev);
> +
> +	return data->fifo_mode;
> +}
> +
> +static const struct iio_enum bmc150_accel_fifo_mode_enum = {
> +	.items = bmc150_accel_fifo_modes,
> +	.num_items = ARRAY_SIZE(bmc150_accel_fifo_modes),
> +	.set = bmc150_accel_fifo_mode_set,
> +	.get = bmc150_accel_fifo_mode_get,
> +};
> +
> +static const struct iio_chan_spec_ext_info bmc150_accel_ext_info[] = {
> +	IIO_FIFO_EXT_INFO(&bmc150_accel_fifo_mode_enum, IIO_SHARED_BY_TYPE),
> +	{},
>  };
>  
>  #define BMC150_ACCEL_CHANNEL(_axis, bits) {				\
> @@ -908,7 +1127,9 @@ static const struct iio_event_spec bmc150_accel_events[BMC150_ACCEL_EVENTS] = {
>  	.channel2 = IIO_MOD_##_axis,					\
>  	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),			\
>  	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) |		\
> -				BIT(IIO_CHAN_INFO_SAMP_FREQ),		\
> +				BIT(IIO_CHAN_INFO_SAMP_FREQ) |		\
> +				BIT(IIO_CHAN_INFO_FIFO_LENGTH) |	\
> +				BIT(IIO_CHAN_INFO_FIFO_FLUSH),		\
>  	.scan_index = AXIS_##_axis,					\
>  	.scan_type = {							\
>  		.sign = 's',						\
> @@ -917,7 +1138,8 @@ static const struct iio_event_spec bmc150_accel_events[BMC150_ACCEL_EVENTS] = {
>  		.shift = 16 - (bits),					\
>  	},								\
>  	.event_spec = bmc150_accel_events,				\
> -	.num_event_specs = ARRAY_SIZE(bmc150_accel_events)		\
> +	.num_event_specs = ARRAY_SIZE(bmc150_accel_events),		\
> +	.ext_info = bmc150_accel_ext_info,				\
>  }
>  
>  #define BMC150_ACCEL_CHANNELS(bits) {					\
> @@ -1286,6 +1508,17 @@ static struct {
>  		.read = bmc150_accel_event_roc_read,
>  		.write = bmc150_accel_event_roc_write,
>  	},
> +	{
> +		.intr = 2,
> +		.type = IIO_EV_TYPE_FIFO_FULL,
> +	},
> +	{
> +		.intr = 3,
> +		.type = IIO_EV_TYPE_FIFO_WATERMARK,
> +		.read = bmc150_accel_event_watermark_read,
> +		.write = bmc150_accel_event_watermark_write,
> +	},
> +
>  };
>  
>  static void bmc150_accel_events_setup(struct iio_dev *indio_dev,
> @@ -1460,6 +1693,7 @@ static int bmc150_accel_resume(struct device *dev)
>  	mutex_lock(&data->mutex);
>  	if (atomic_read(&data->active_intr))
>  		bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_NORMAL, 0);
> +	bmc150_accel_fifo_mode_set(indio_dev, NULL, data->fifo_mode);
>  	mutex_unlock(&data->mutex);
>  
>  	return 0;
> @@ -1489,6 +1723,9 @@ static int bmc150_accel_runtime_resume(struct device *dev)
>  	ret = bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_NORMAL, 0);
>  	if (ret < 0)
>  		return ret;
> +	ret = bmc150_accel_fifo_mode_set(indio_dev, NULL, data->fifo_mode);
> +	if (ret < 0)
> +		return ret;
>  
>  	sleep_val = bmc150_accel_get_startup_times(data);
>  	if (sleep_val < 20)
> 


  parent reply	other threads:[~2014-11-24 10:37 UTC|newest]

Thread overview: 40+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-11-17 17:55 [RFC 0/8] iio: add support for hardware fifo Octavian Purdila
2014-11-17 17:55 ` [RFC 1/8] " Octavian Purdila
2014-11-18 13:37   ` jic23
2014-11-18 15:21     ` Octavian Purdila
2014-11-17 17:56 ` [RFC 2/8] iio: bmc150: refactor slope duration and threshold update Octavian Purdila
2014-11-23 21:58   ` Hartmut Knaack
2014-11-23 22:16     ` Octavian Purdila
2014-11-17 17:56 ` [RFC 3/8] iio: bmc150: refactor interrupt enabling Octavian Purdila
2014-11-23 22:02   ` Hartmut Knaack
2014-11-23 22:24     ` Octavian Purdila
2014-11-17 17:56 ` [RFC 4/8] iio: bmc150: exit early if event / trigger state is not changed Octavian Purdila
2014-11-17 17:56 ` [RFC 5/8] iio: bmc150: introduce bmc150_accel_interrupt Octavian Purdila
2014-11-17 17:56 ` [RFC 6/8] iio: bmc150: introduce bmc150_accel_trigger Octavian Purdila
2014-11-23 23:06   ` Hartmut Knaack
2014-11-24 10:42     ` Octavian Purdila
2014-11-24 20:26       ` Hartmut Knaack
2014-11-25 16:06         ` Octavian Purdila
2014-11-17 17:56 ` [RFC 7/8] iio: bmc150: introduce bmc150_accel_event Octavian Purdila
2014-11-17 17:56 ` [RFC 8/8] iio: bmc150: add support for hardware fifo Octavian Purdila
2014-11-18 13:49   ` jic23
2014-11-18 15:31     ` Octavian Purdila
2014-11-24 10:37   ` Hartmut Knaack [this message]
2014-11-18 13:24 ` [RFC 0/8] iio: " jic23
2014-11-18 15:03   ` Octavian Purdila
2014-11-18 16:44     ` Lars-Peter Clausen
2014-11-18 17:04       ` Octavian Purdila
2014-11-18 17:23         ` Lars-Peter Clausen
2014-11-18 19:35           ` Octavian Purdila
2014-11-19 11:48             ` Lars-Peter Clausen
2014-11-19 12:33               ` Octavian Purdila
2014-12-12 12:57                 ` Jonathan Cameron
2014-11-19 13:32             ` Octavian Purdila
2014-11-26 13:06               ` Octavian Purdila
2014-12-01 21:19                 ` Lars-Peter Clausen
2014-12-02  9:13                   ` Octavian Purdila
2014-12-12 13:10                     ` Jonathan Cameron
2014-12-12 13:04               ` Jonathan Cameron
2014-12-12 12:52     ` Jonathan Cameron
2014-11-18 15:35   ` Pandruvada, Srinivas
2014-11-18 16:41   ` Lars-Peter Clausen

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=54730A64.3060003@gmx.de \
    --to=knaack.h@gmx.de \
    --cc=linux-iio@vger.kernel.org \
    --cc=octavian.purdila@intel.com \
    --cc=srinivas.pandruvada@intel.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).