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 = ®_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)
>
next prev 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).