On Tue, 7 Apr 2020 15:14:27 +0200 (CEST) yarl-baudig@xxxxxxxxxx wrote: > ---- Message d'origine ---- > > De : Jonathan Cameron <jic23@xxxxxxxxxx> > > À : yarl-baudig@xxxxxxxxxx > > Sujet : Re: lsm303dlhc magnetometer: please help > > Date : 05/04/2020 15:03:56 Europe/Paris > > Copie à : denis.ciocca@xxxxxx; > > linux-iio@xxxxxxxxxxxxxxx > > > > On Sat, 4 Apr 2020 14:43:04 +0200 (CEST) > > yarl-baudig@xxxxxxxxxx wrote: > > > > > Good afternoun, > > > > > > I have an lsm303dlhc that I'm trying to get to work with a triggered > > buffer, the magnetometer part of it. > > > The problem with this sensor is that the dataready signal has, I think, a > > different > > > meaning than the one expected by the ST sensor driver set. > > > On this sensor the signal is always high except when the sensor is writing > > new values to its data > > > registers. The problem with the driver is that it expects the sensor to > > have a register > > > to check if new data is available: > > > https://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio.git/tree/drivers/ > > iio/common/st_sensors/st_sensors_trigger.c?h=testing#n36 > > > the lsm303dlhc magnetometer is not configured with such a register: > > > https://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio.git/tree/drivers/ > > iio/magnetometer/st_magn_core.c?h=testing#n183 > > > There is one in the sensor but the dataready bit is just the value of the > > signal, so > > > even if I added the address and mask for this information, the meaning > > would be > > > wrong from the point of view of function and the while loop would run > > endlessly: > > > https://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio.git/tree/drivers/ > > iio/common/st_sensors/st_sensors_trigger.c?h=testing#n113 > > > > > Looking at the datasheet, it is a rather dumb device isn't it and the > > datasheet > > doesn't supply anywhere near enough info.. It says it's a system in > > package > > so in theory we could find out what the sensor actually is and that might > > have a better datasheet. > > > > Then we have the data ready bit as you say and a lock bit that fires when > > we > > successfully start reading (ensuring we get a full set from the same > > 'scan') > > The dataready bit description says: > > "Data-ready bit. This bit is when a new set of measurements is available." > > I admit I'm reading between the lines, but that sounds like it will clear > > when > > the data has been read. If it clears on it's own then there isn't much > > we can do reliably. > > > > We could just treat the irq as a iio-trigger-interrupt trigger as long as we > > definitely don't > > need to do anything to clear it. That will not hit any of the paths you > > are > > looking at as will directly call st_sensors_trigger_handler. > > > > Unfortunately that doesn't seem to have a device tree binding yet > > (obviously > > not much used except on very old platforms). I don't have a handy platform > > to > > test it on at the moment unfortunately but should just be a case of adding > > a device tree id table to the driver. Then the dt entry will simply > > contain > > the interrupt line. > > > > Denis, any more info on this part and whether the using a dumb interrupt > > trigger > > is the way to go or if we can do anything more clever? > > > > It may be a case where the best bet is to ignore that line and use a high > > resolution time trigger running at half the raw sampling frequency of the > > device > > (to avoid repeated values) > > > > Thanks, > > > > Jonathan > > > > Thank you for answering. I will probably try as you say, use an hrtimer. > > Anyway I want to precise one thing I just saw using the patch I showed you. > The lsm303dlhc contains an accelerometer and a magnetometer. > When the buffer for the accelerometer is disabled, the magnetometer "works" > the way I described in my last mail: one out of two times. > When the buffer for the accelerometer is enabled: the magnetometer works, > every time... That is odd. Any chance the interrupt lines are shared - i.e. wired to the same pin? Otherwise maybe there is an electrical short causing problems... Jonathan > > > > > I then modified a bit, patch below. > > > > > > Let me first tell you that it work one out of two time: > > > I boot, load this device-tree: > > > --- > > > /dts-v1/; > > > /plugin/; > > > > > > / { > > > compatible = "brcm,bcm2708"; > > > > > > fragment@0 { > > > target = <&gpio>; > > > __overlay__ { > > > magn_pins: nine_dof_pins { > > > brcm,pins = <27>; > > > brcm,function = <0>; > > > brcm,pull = <1>; > > > status = "okay"; > > > }; > > > }; > > > }; > > > > > > fragment@1 { > > > target = <&i2c_arm>; > > > __overlay__ { > > > status = "okay"; > > > #address-cells = <1>; > > > #size-cells = <0>; > > > magn@1e { > > > compatible = "st,lsm303dlhc-magn"; > > > reg = <0x1e>; > > > status = "okay"; > > > interrupt-parent = <&gpio>; > > > interrupts = <27 1>; > > > }; > > > }; > > > }; > > > }; > > > --- > > > I then enable scan_elements, enable buffer (echo 1 > buffer/enable) > > > interrupts are coming regularly at sampling_frequency. It works fine. > > > If I now disable the buffer then re-enable it, one and only interrupt, > > > doesn't work fine.. > > > re-disable, re-re-enable: works fine! > > > and it seem to be always that, it works modulo 2. > > > > > > On my first try I didn't change st_magn_buffer_preenable and > > st_magn_buffer_postenable > > > But I thought that maybe, the problem was some sort of bad writting, > > reading timing > > > because > > > (1) request_threaded_irq is called for a rising signal while it is already > > high. > > > > > > I make a break here and ask you a question: > > > As you read, I am a kernel newbie: is doing (1) bad? > > Interesting question. There is so little info in the datasheet that it is > > hard > > to tell. It might be a level_high interrupt. > > > > > end of break. > > > > > > So I added st_magn_buffer_preenable and modified st_magn_buffer_postenable > > to > > > try to mask the irq during the arppropriate interval. > > > > > > No visible change. > > > I never almost never wrote kernel code before. > > > I tried to get closer to what was happening using gdb/kgdb, first time I > > used this. > > > I am now pretty discouraged and any suggestions are welcome. > > > > > > Thank you. > > > > > > --- > > > drivers/iio/common/st_sensors/st_sensors_core.c | 11 +++++++++++ > > > .../iio/common/st_sensors/st_sensors_trigger.c | 9 +++++++++ > > > drivers/iio/magnetometer/st_magn_buffer.c | 17 ++++++++++++++++- > > > drivers/iio/magnetometer/st_magn_core.c | 3 +++ > > > include/linux/iio/common/st_sensors.h | 2 ++ > > > 5 files changed, 41 insertions(+), 1 deletion(-) > > > > > > diff --git a/drivers/iio/common/st_sensors/st_sensors_core.c > > b/drivers/iio/common/st_sensors/st_sensors_core.c > > > index 09279e40c55c..fef6b70976b4 100644 > > > --- a/drivers/iio/common/st_sensors/st_sensors_core.c > > > +++ b/drivers/iio/common/st_sensors/st_sensors_core.c > > > @@ -480,6 +480,17 @@ int st_sensors_set_dataready_irq(struct iio_dev > > *indio_dev, bool enable) > > > u8 drdy_addr, drdy_mask; > > > struct st_sensor_data *sdata = iio_priv(indio_dev); > > > > > > + if (sdata->sensor_settings->drdy_irq.simple) { > > > + /* > > > + * some devices very simple. No register to enable, disable > > > + * or configure the signal. Actually, when it is low it means that > > > + * sensor is writing data to its register, when it is high it > > > + * means that data can be read. i.e when rising new data is available. > > > + */ > > > + sdata->hw_irq_trigger = enable; > > > + return 0; > > > + } > > > + > > > if (!sdata->sensor_settings->drdy_irq.int1.addr && > > > !sdata->sensor_settings->drdy_irq.int2.addr) { > > > /* > > > diff --git a/drivers/iio/common/st_sensors/st_sensors_trigger.c > > b/drivers/iio/common/st_sensors/st_sensors_trigger.c > > > index fdcc5a891958..146aaae0a85c 100644 > > > --- a/drivers/iio/common/st_sensors/st_sensors_trigger.c > > > +++ b/drivers/iio/common/st_sensors/st_sensors_trigger.c > > > @@ -30,6 +30,13 @@ static int st_sensors_new_samples_available(struct > > iio_dev *indio_dev, > > > u8 status; > > > int ret; > > > > > > + /* We simply trust the signal */ > > > + if (sdata->sensor_settings->drdy_irq.simple) { > > > + if (indio_dev->active_scan_mask) > > > + return 1; > > > + return 0; > > > + } > > > + > > > /* How would I know if I can't check it? */ > > > if (!sdata->sensor_settings->drdy_irq.stat_drdy.addr) > > > return -EINVAL; > > > @@ -90,6 +97,8 @@ static irqreturn_t st_sensors_irq_thread(int irq, void > > *p) > > > if (sdata->hw_irq_trigger && > > > st_sensors_new_samples_available(indio_dev, sdata)) { > > > iio_trigger_poll_chained(p); > > > + if (sdata->sensor_settings->drdy_irq.simple) > > > + return IRQ_HANDLED; > > > } else { > > > dev_dbg(sdata->dev, "spurious IRQ\n"); > > > return IRQ_NONE; > > > diff --git a/drivers/iio/magnetometer/st_magn_buffer.c > > b/drivers/iio/magnetometer/st_magn_buffer.c > > > index 37ab30566464..ae13e4339127 100644 > > > --- a/drivers/iio/magnetometer/st_magn_buffer.c > > > +++ b/drivers/iio/magnetometer/st_magn_buffer.c > > > @@ -30,6 +30,16 @@ int st_magn_trig_set_state(struct iio_trigger *trig, > > bool state) > > > return st_sensors_set_dataready_irq(indio_dev, state); > > > } > > > > > > +static int st_magn_buffer_preenable(struct iio_dev *indio_dev) > > > +{ > > > + struct st_sensor_data *mdata = iio_priv(indio_dev); > > > + > > > + if (mdata->sensor_settings->drdy_irq.simple) { > > > + disable_irq(mdata->get_irq_data_ready(indio_dev)); > > > + } > > > + return 0; > > > +} > > > + > > > static int st_magn_buffer_postenable(struct iio_dev *indio_dev) > > > { > > > int err; > > > @@ -45,7 +55,11 @@ static int st_magn_buffer_postenable(struct iio_dev > > *indio_dev) > > > if (err < 0) > > > goto st_magn_buffer_postenable_error; > > > > > > - return st_sensors_set_enable(indio_dev, true); > > > + err = st_sensors_set_enable(indio_dev, true); > > > + > > > + enable_irq(mdata->get_irq_data_ready(indio_dev)); > > > + > > > + return err; > > > > > > st_magn_buffer_postenable_error: > > > kfree(mdata->buffer_data); > > > @@ -70,6 +84,7 @@ static int st_magn_buffer_predisable(struct iio_dev > > *indio_dev) > > > } > > > > > > static const struct iio_buffer_setup_ops st_magn_buffer_setup_ops = { > > > + .preenable = &st_magn_buffer_preenable, > > > .postenable = &st_magn_buffer_postenable, > > > .predisable = &st_magn_buffer_predisable, > > > }; > > > diff --git a/drivers/iio/magnetometer/st_magn_core.c > > b/drivers/iio/magnetometer/st_magn_core.c > > > index 72f6d1335a04..0fb0915529e9 100644 > > > --- a/drivers/iio/magnetometer/st_magn_core.c > > > +++ b/drivers/iio/magnetometer/st_magn_core.c > > > @@ -259,6 +259,9 @@ static const struct st_sensor_settings > > st_magn_sensors_settings[] = { > > > }, > > > }, > > > }, > > > + .drdy_irq = { > > > + .simple = true, > > > + }, > > > .multi_read_bit = false, > > > .bootime = 2, > > > }, > > > diff --git a/include/linux/iio/common/st_sensors.h > > b/include/linux/iio/common/st_sensors.h > > > index f9bd6e8ab138..e25b5f033557 100644 > > > --- a/include/linux/iio/common/st_sensors.h > > > +++ b/include/linux/iio/common/st_sensors.h > > > @@ -154,6 +154,7 @@ struct st_sensor_int_drdy { > > > * struct ig1 - represents the Interrupt Generator 1 of sensors. > > > * @en_addr: address of the enable ig1 register. > > > * @en_mask: mask to write the on/off value for enable. > > > + * @simple: the data-ready is a "very simple implementation". > > > */ > > > struct st_sensor_data_ready_irq { > > > struct st_sensor_int_drdy int1; > > > @@ -168,6 +169,7 @@ struct st_sensor_data_ready_irq { > > > u8 en_addr; > > > u8 en_mask; > > > } ig1; > > > + bool simple; > > > }; > > > > > > > > > > > >