All of lore.kernel.org
 help / color / mirror / Atom feed
From: Jonathan Cameron <jic23@kernel.org>
To: Lorenzo Bianconi <lorenzo@kernel.org>
Cc: Sean Nyekjaer <sean@geanix.com>,
	linux-iio@vger.kernel.org, lorenzo.bianconi83@gmail.com,
	martin@geanix.com, denis.ciocca@st.com, mario.tesi@st.com,
	armando.visconti@st.com
Subject: Re: [PATCH v2 3/6] iio: imu: st_lsm6dsx: add motion events
Date: Sat, 27 Jul 2019 22:11:24 +0100	[thread overview]
Message-ID: <20190727221124.1184a056@archlinux> (raw)
In-Reply-To: <20190716082927.GB13440@localhost.localdomain>

On Tue, 16 Jul 2019 10:29:27 +0200
Lorenzo Bianconi <lorenzo@kernel.org> wrote:

> > Add event channels that controls the creation of motion events.
> > 
> > Signed-off-by: Sean Nyekjaer <sean@geanix.com>
> > ---
> > 
> > Changes since v1:
> >  * added handling of LSM6
> >  * added CHANNEL info with events for ACC
> >  * removed st_lsm6dsx_set_event_threshold function
> >  * added check of event type to event channels
> > 
> > Issues:
> >  * This currently breaks buffered reads, as the interrupt stays high.
> >    This happens when MD1_CFG INT1_WU (wakeup event routes to INT1) is
> >    enabled.
> >    The datasheet doesn't seem to decribe whats happening and I can't
> >    find a status register to read somehing useful.
> >    Maybe it's impossible to share the buffered reads interrupt with
> >    the wakeup interrupt?  
> 
> Could you explain this issue a bit more? adding st folks...

This isn't totally unheard of for other hardware. If it turns out to be
a hardware restriction then the software approach is to return -EBUSY
if anyone tries to enable an event whilst in buffered mode, and -EBUSY
if anyone tries to enable buffered mode with an event enabled.

It's rather ugly though definitely good to see if there is a proper
solution!

Thanks,

Jonathan

> 
> > 
> >  drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h      |  30 ++++
> >  drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c | 164 +++++++++++++++++--
> >  2 files changed, 182 insertions(+), 12 deletions(-)
> > 
> > diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h
> > index 738bed4a9752..fef08b7cf2a0 100644
> > --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h
> > +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h
> > @@ -12,6 +12,7 @@
> >  #define ST_LSM6DSX_H
> >  
> >  #include <linux/device.h>
> > +#include <linux/iio/iio.h>
> >  
> >  #define ST_LSM6DS3_DEV_NAME	"lsm6ds3"
> >  #define ST_LSM6DS3H_DEV_NAME	"lsm6ds3h"
> > @@ -50,6 +51,26 @@ enum st_lsm6dsx_hw_id {
> >  					 * ST_LSM6DSX_TAGGED_SAMPLE_SIZE)
> >  #define ST_LSM6DSX_SHIFT_VAL(val, mask)	(((val) << __ffs(mask)) & (mask))
> >  
> > +#define ST_LSM6DSX_CHANNEL_ACC(chan_type, addr, mod, scan_idx)		\
> > +{									\
> > +	.type = chan_type,						\
> > +	.address = addr,						\
> > +	.modified = 1,							\
> > +	.channel2 = mod,						\
> > +	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |			\
> > +			      BIT(IIO_CHAN_INFO_SCALE),			\
> > +	.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),	\
> > +	.scan_index = scan_idx,						\
> > +	.scan_type = {							\
> > +		.sign = 's',						\
> > +		.realbits = 16,						\
> > +		.storagebits = 16,					\
> > +		.endianness = IIO_LE,					\
> > +	},								\
> > +	.event_spec = &st_lsm6dsx_event,				\
> > +	.num_event_specs = 1,						\
> > +}  
> 
> I would prefer to extend existing macros
> 
> > +
> >  #define ST_LSM6DSX_CHANNEL(chan_type, addr, mod, scan_idx)		\
> >  {									\
> >  	.type = chan_type,						\
> > @@ -297,6 +318,8 @@ struct st_lsm6dsx_hw {
> >  	u8 enable_mask;
> >  	u8 ts_sip;
> >  	u8 sip;
> > +	u8 event_threshold;
> > +	bool enable_event;
> >  	int drdy_pin;
> >  
> >  	u8 *buff;
> > @@ -306,6 +329,13 @@ struct st_lsm6dsx_hw {
> >  	const struct st_lsm6dsx_settings *settings;
> >  };
> >  
> > +static const struct iio_event_spec st_lsm6dsx_event = {
> > +	.type = IIO_EV_TYPE_THRESH,
> > +	.dir = IIO_EV_DIR_EITHER,
> > +	.mask_separate = BIT(IIO_EV_INFO_VALUE) |
> > +			 BIT(IIO_EV_INFO_ENABLE)
> > +};
> > +
> >  static const unsigned long st_lsm6dsx_available_scan_masks[] = {0x7, 0x0};
> >  extern const struct dev_pm_ops st_lsm6dsx_pm_ops;
> >  
> > diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c
> > index 2c11addf568b..6decb0846f1a 100644
> > --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c
> > +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c
> > @@ -76,6 +76,16 @@
> >  #define ST_LSM6DSX_REG_GYRO_OUT_Y_L_ADDR	0x24
> >  #define ST_LSM6DSX_REG_GYRO_OUT_Z_L_ADDR	0x26
> >  
> > +#define ST_LSM6DSX_REG_TAP_CFG_ADDR		0x58
> > +#define ST_LSM6DSX_REG_TAP_CFG_INT_EN_MASK	BIT(7)  
> 
> I am pretty sure this is not true at least for lsm6ds3/lsm6ds3h
> 
> > +
> > +#define ST_LSM6DSX_REG_WAKE_UP_ADDR		0x5B
> > +#define ST_LSM6DSX_REG_WAKE_UP_THRES_MASK	GENMASK(5, 0)
> > +
> > +#define ST_LSM6DSX_REG_MD1_CFG_ADDR		0x5E
> > +#define ST_LSM6DSX_REG_MD2_CFG_ADDR		0x5F
> > +#define ST_LSM6DSX_REG_MD_CFG_INT_WU_MASK	BIT(5)
> > +
> >  static const struct st_lsm6dsx_odr_table_entry st_lsm6dsx_odr_table[] = {
> >  	[ST_LSM6DSX_ID_ACC] = {
> >  		.reg = {
> > @@ -470,12 +480,12 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
> >  };
> >  
> >  static const struct iio_chan_spec st_lsm6dsx_acc_channels[] = {
> > -	ST_LSM6DSX_CHANNEL(IIO_ACCEL, ST_LSM6DSX_REG_ACC_OUT_X_L_ADDR,
> > -			   IIO_MOD_X, 0),
> > -	ST_LSM6DSX_CHANNEL(IIO_ACCEL, ST_LSM6DSX_REG_ACC_OUT_Y_L_ADDR,
> > -			   IIO_MOD_Y, 1),
> > -	ST_LSM6DSX_CHANNEL(IIO_ACCEL, ST_LSM6DSX_REG_ACC_OUT_Z_L_ADDR,
> > -			   IIO_MOD_Z, 2),
> > +	ST_LSM6DSX_CHANNEL_ACC(IIO_ACCEL, ST_LSM6DSX_REG_ACC_OUT_X_L_ADDR,
> > +			       IIO_MOD_X, 0),
> > +	ST_LSM6DSX_CHANNEL_ACC(IIO_ACCEL, ST_LSM6DSX_REG_ACC_OUT_Y_L_ADDR,
> > +			       IIO_MOD_Y, 1),
> > +	ST_LSM6DSX_CHANNEL_ACC(IIO_ACCEL, ST_LSM6DSX_REG_ACC_OUT_Z_L_ADDR,
> > +			       IIO_MOD_Z, 2),
> >  	IIO_CHAN_SOFT_TIMESTAMP(3),
> >  };
> >  
> > @@ -679,18 +689,21 @@ static int st_lsm6dsx_read_oneshot(struct st_lsm6dsx_sensor *sensor,
> >  	int err, delay;
> >  	__le16 data;
> >  
> > -	err = st_lsm6dsx_sensor_set_enable(sensor, true);
> > -	if (err < 0)
> > -		return err;
> > +	if (!hw->enable_event) {
> > +		err = st_lsm6dsx_sensor_set_enable(sensor, true);
> > +		if (err < 0)
> > +			return err;
> >  
> > -	delay = 1000000 / sensor->odr;
> > -	usleep_range(delay, 2 * delay);
> > +		delay = 1000000 / sensor->odr;
> > +		usleep_range(delay, 2 * delay);
> > +	}
> >  
> >  	err = st_lsm6dsx_read_locked(hw, addr, &data, sizeof(data));
> >  	if (err < 0)
> >  		return err;
> >  
> > -	st_lsm6dsx_sensor_set_enable(sensor, false);
> > +	if (!hw->enable_event)
> > +		st_lsm6dsx_sensor_set_enable(sensor, false);
> >  
> >  	*val = (s16)le16_to_cpu(data);
> >  
> > @@ -763,6 +776,94 @@ static int st_lsm6dsx_write_raw(struct iio_dev *iio_dev,
> >  	return err;
> >  }
> >  
> > +static int st_lsm6dsx_read_event(struct iio_dev *iio_dev,
> > +				   const struct iio_chan_spec *chan,
> > +				   enum iio_event_type type,
> > +				   enum iio_event_direction dir,
> > +				   enum iio_event_info info,
> > +				   int *val, int *val2)
> > +{
> > +	struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev);
> > +	struct st_lsm6dsx_hw *hw = sensor->hw;
> > +
> > +	if (type != IIO_EV_TYPE_THRESH)
> > +		return -EINVAL;
> > +
> > +	*val2 = 0;
> > +	*val = hw->event_threshold;
> > +
> > +	return IIO_VAL_INT;
> > +}
> > +
> > +static int st_lsm6dsx_write_event(struct iio_dev *iio_dev,
> > +				    const struct iio_chan_spec *chan,
> > +				    enum iio_event_type type,
> > +				    enum iio_event_direction dir,
> > +				    enum iio_event_info info,
> > +				    int val, int val2)
> > +{
> > +	struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev);
> > +	struct st_lsm6dsx_hw *hw = sensor->hw;
> > +	int err;
> > +
> > +	if (type != IIO_EV_TYPE_THRESH)
> > +		return -EINVAL;
> > +
> > +	if (!hw->enable_event)
> > +		return -EBUSY;  
> 
> I guess it is ok to configure the threshold first, no?
> 
> > +
> > +	if (val < 0 || val > 31)
> > +		return -EINVAL;
> > +
> > +	err = regmap_update_bits(hw->regmap, ST_LSM6DSX_REG_WAKE_UP_ADDR,
> > +				 ST_LSM6DSX_REG_WAKE_UP_THRES_MASK,
> > +				 val);
> > +	if (err)
> > +		return -EINVAL;
> > +
> > +	hw->event_threshold = val;
> > +
> > +	return 0;
> > +}
> > +
> > +static int st_lsm6dsx_read_event_config(struct iio_dev *iio_dev,
> > +					  const struct iio_chan_spec *chan,
> > +					  enum iio_event_type type,
> > +					  enum iio_event_direction dir)
> > +{
> > +	struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev);
> > +	struct st_lsm6dsx_hw *hw = sensor->hw;
> > +
> > +	if (type != IIO_EV_TYPE_THRESH)
> > +		return -EINVAL;
> > +
> > +	return hw->enable_event;
> > +}
> > +
> > +static int st_lsm6dsx_write_event_config(struct iio_dev *iio_dev,
> > +					   const struct iio_chan_spec *chan,
> > +					   enum iio_event_type type,
> > +					   enum iio_event_direction dir,
> > +					   int state)
> > +{
> > +	struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev);
> > +	struct st_lsm6dsx_hw *hw = sensor->hw;
> > +
> > +	if (type != IIO_EV_TYPE_THRESH)
> > +		return -EINVAL;
> > +
> > +	if (state && hw->enable_event)
> > +		return 0;
> > +
> > +	hw->enable_event = state;
> > +	if (state)
> > +		st_lsm6dsx_sensor_set_enable(sensor, true);
> > +	else
> > +		st_lsm6dsx_sensor_set_enable(sensor, false);  
> 
> st_lsm6dsx_sensor_set_enable can fails. Why not do
> 
> 	err = st_lsm6dsx_sensor_set_enable(sensor, state);
> 	if (err < 0)
> 		return err;
> 
> 	hw->enable_event = state;;
> 	return 0;
> 
> > +
> > +	return 0;
> > +}
> > +
> >  int st_lsm6dsx_set_watermark(struct iio_dev *iio_dev, unsigned int val)
> >  {
> >  	struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev);
> > @@ -839,6 +940,10 @@ static const struct iio_info st_lsm6dsx_acc_info = {
> >  	.attrs = &st_lsm6dsx_acc_attribute_group,
> >  	.read_raw = st_lsm6dsx_read_raw,
> >  	.write_raw = st_lsm6dsx_write_raw,
> > +	.read_event_value = st_lsm6dsx_read_event,
> > +	.write_event_value = st_lsm6dsx_write_event,
> > +	.read_event_config = st_lsm6dsx_read_event_config,
> > +	.write_event_config = st_lsm6dsx_write_event_config,
> >  	.hwfifo_set_watermark = st_lsm6dsx_set_watermark,
> >  };
> >  
> > @@ -1076,6 +1181,38 @@ static struct iio_dev *st_lsm6dsx_alloc_iiodev(struct st_lsm6dsx_hw *hw,
> >  	return iio_dev;
> >  }
> >  
> > +int st_lsm6dsx_event_setup(int id, struct st_lsm6dsx_hw *hw)
> > +{
> > +	int err;
> > +	unsigned int md_reg;
> > +
> > +	if (id == ST_ISM330DLC_ID) {
> > +		/* Enable basic interrupts for ISM330 */
> > +		err = regmap_update_bits(hw->regmap, ST_LSM6DSX_REG_TAP_CFG_ADDR,
> > +					 ST_LSM6DSX_REG_TAP_CFG_INT_EN_MASK,
> > +					 ST_LSM6DSX_REG_TAP_CFG_INT_EN_MASK);  
> 
> please put device differences in st_lsm6dsx_sensor_settings[]
> 
> > +		if (err < 0)
> > +			return err;
> > +	}
> > +
> > +	switch (hw->drdy_pin) {  
> 
> drdy_pin it is only used here right? If so we do not need it just enable this
> configuration by default. I would prefer to maintain the code simple
> 
> > +	case 1:
> > +		md_reg = ST_LSM6DSX_REG_MD1_CFG_ADDR;
> > +		break;
> > +	case 2:
> > +		md_reg = ST_LSM6DSX_REG_MD2_CFG_ADDR;
> > +		break;
> > +	default:
> > +		return -EINVAL;
> > +	}
> > +	/* Enable wakeup interrupt */
> > +	err = regmap_update_bits(hw->regmap, md_reg,
> > +				 ST_LSM6DSX_REG_MD_CFG_INT_WU_MASK,
> > +				 ST_LSM6DSX_REG_MD_CFG_INT_WU_MASK);
> > +
> > +	return err;
> > +}
> > +
> >  static irqreturn_t st_lsm6dsx_handler_irq(int irq, void *private)
> >  {
> >  	struct st_lsm6dsx_hw *hw = private;
> > @@ -1207,6 +1344,9 @@ int st_lsm6dsx_probe(struct device *dev, int irq, int hw_id,
> >  		err = st_lsm6dsx_fifo_setup(hw);
> >  		if (err < 0)
> >  			return err;  
> 
> newline here please
> 
> > +		err = st_lsm6dsx_event_setup(hw_id, hw);
> > +		if (err < 0)
> > +			return err;
> >  	}
> >  
> >  	for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) {
> > -- 
> > 2.22.0
> >   


  reply	other threads:[~2019-07-27 21:11 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-07-15  8:15 [PATCH v2 1/6] iio: imu: st_lsm6dsx: move interrupt thread to core Sean Nyekjaer
2019-07-15  8:15 ` [PATCH v2 2/6] iio: imu: st_lsm6dsx: save drdy_pin in device struct Sean Nyekjaer
2019-07-15  8:15 ` [PATCH v2 3/6] iio: imu: st_lsm6dsx: add motion events Sean Nyekjaer
2019-07-16  8:29   ` Lorenzo Bianconi
2019-07-27 21:11     ` Jonathan Cameron [this message]
2019-08-09 11:05     ` Sean Nyekjaer
2019-08-21 11:11     ` Sean Nyekjaer
2019-07-15  8:15 ` [PATCH v2 4/6] iio: imu: st_lsm6dsx: add wakeup-source option Sean Nyekjaer
2019-07-16  8:04   ` Lorenzo Bianconi
2019-07-15  8:15 ` [PATCH v2 5/6] iio: imu: st_lsm6dsx: always enter interrupt thread Sean Nyekjaer
2019-07-16  6:14   ` Lorenzo Bianconi
2019-07-15  8:15 ` [PATCH v2 6/6] iio: imu: st_lsm6dsx: add motion report function and call from interrupt Sean Nyekjaer
2019-07-16  6:11   ` Lorenzo Bianconi
2019-07-16  5:57 ` [PATCH v2 1/6] iio: imu: st_lsm6dsx: move interrupt thread to core Lorenzo Bianconi

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=20190727221124.1184a056@archlinux \
    --to=jic23@kernel.org \
    --cc=armando.visconti@st.com \
    --cc=denis.ciocca@st.com \
    --cc=linux-iio@vger.kernel.org \
    --cc=lorenzo.bianconi83@gmail.com \
    --cc=lorenzo@kernel.org \
    --cc=mario.tesi@st.com \
    --cc=martin@geanix.com \
    --cc=sean@geanix.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 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.