Re: [PATCH v5] iio: proximity: Add driver support for ST's VL53L0X ToF ranging sensor.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Mon, Sep 17, 2018 at 09:25:21AM +0100, Jonathan Cameron wrote:
> On Sun, 16 Sep 2018 21:36:51 +0800
> Song Qiang <songqiang1304521@xxxxxxxxx> wrote:
> 
> > On Sun, Sep 16, 2018 at 12:01:49PM +0100, Jonathan Cameron wrote:
> > > On Sat, 15 Sep 2018 17:57:52 +0800
> > > Song Qiang <songqiang1304521@xxxxxxxxx> wrote:
> > >   
> > > > This driver was originally written by ST in 2016 as a misc input device
> > > > driver, and hasn't been maintained for a long time. I grabbed some code
> > > > from it's API and reformed it into an iio proximity device driver.
> > > > This version of driver uses i2c bus to talk to the sensor and
> > > > polling for measuring completes, so no irq line is needed.
> > > > This version of driver supports only one-shot mode, and it can be
> > > > tested with reading from
> > > > /sys/bus/iio/devices/iio:deviceX/in_distance_raw
> > > > 
> > > > Signed-off-by: Song Qiang <songqiang.1304521@xxxxxxxxx>  
> > > Hi Song,
> > > 
> > > My first comment was going to be don't use wild cards in a part name
> > > in a driver, but a quick sanity check confirmed that ST were actually
> > > crazy enough to end a part number with an X.  Ah well ;)
> > > 
> > > Otherwise a few minor things, mostly around naming.  There is some
> > > confusion around endian stuff as well
> > > 
> > > Looks pretty good for a first go at upstreaming a driver!
> > > 
> > > Are you planning on adding more features?  Seems like a capable little device
> > > and would be good to have fuller support in the long term if you have time
> > > to look at it!
> > > 
> > > Jonathan
> > >   
> > 
> > Hi Jonathan,
> > 
> > Thanks for spending time with my patch!
> > Since I'm now just a student and intrested in embedded linux very much,
> > there are plenty of free time for me to work on this, and working with
> > the community is not only interesting but helpful to my knowledge.
> > People reviewed my patch gave me a lot helpful suggestions, espacially
> > Himanshu. :)
> Cool.
> 
> > 
> > When I was writing this patch, I thought maybe I should go one step
> > each time, so this driver may seems like a little simple, but I believe
> > it's just for now.
> Agreed. It makes complete sense to start simple and build up.  I was
> just being curious on how far you were planning on going ;)
> 

I was just working on the interrupt. I think I'll submit the second
patch to make interrupt working tommorow.

> > 
> > Actually there is a question, ST released a new version of this device
> > called VL53L1X in June, which still has no support for linux drivers,
> > but compitable with VL53L0X. Do you have any suggestions for my
> > driver's name? The first one came to my mind would be VL53LxX, which is
> > a little crazy I think. ;)
> Yes. Wild cards are almost always a bad idea. Just go with the name
> of the first part you support.
> 
> If you want example of this see the max1363 ADC driver.  That supports
> lots of seemingly unconnected part numbers so a wild card approach would
> have caused all sorts of mess.
> 

I see, that's a good idea.

> > 
> >
> ...
> 
> > > > +// SPDX-License-Identifier: GPL-2.0+
> > > > +/*
> > > > + * Support for ST VL53L0X FlightSense ToF Ranging Sensor on a i2c bus.
> > > > + *
> > > > + * Copyright (C) 2016 STMicroelectronics Imaging Division.
> > > > + * Copyright (C) 2018 Song Qiang <songqiang.1304521@xxxxxxxxx>
> > > > + *
> > > > + * Datasheet available at
> > > > + * <https://www.st.com/resource/en/datasheet/vl53l0x.pdf>
> > > > + *
> > > > + * Default 7-bit i2c slave address 0x29.
> > > > + *
> > > > + * TODO: FIFO buffer, continuous mode, interrupts, range selection,
> > > > + * sensor ID check.
> > > > + */
> > > > +
> > > > +#include <linux/module.h>
> > > > +#include <linux/i2c.h>
> > > > +#include <linux/delay.h>
> > > > +
> > > > +#include <linux/iio/iio.h>
> > > > +
> > > > +#define VL53L0X_DRV_NAME				"vl53l0x-i2c"  
> > > 
> > > A quick google suggests this only has an i2c interface.  Hence I'd argue
> > > there is no point in having -i2c in the driver name.  Lots of other
> > > i2c only parts don't on the basis it doesn't add anything.  In fact
> > > the only time we tend to do this is if we have a driver that splits
> > > into a shared core and two or more bus specific drivers.
> > >   
> > 
> > Actually this device do has a CCI(Camera Control Interface) for
> > communication and it's original API has two kinds of ways for accessing
> > this device. 
> Hmm. That one is a bit of a surprise.
> 
> OK.  Fine to do the driver name as *-i2c but don't have it in the
> iio_dev.name field as it's not really useful to pass on.  That
> usually just contains the part number. Userspace doesn't care about the
> interface.
> 

I'll remove that.

> > 
> > > > +
> > > > +#define VL_REG_SYSRANGE_START				0x00
> > > > +
> > > > +#define VL_REG_SYSRANGE_MODE_MASK			GENMASK(3, 0)
> > > > +#define VL_REG_SYSRANGE_MODE_SINGLESHOT			0x00
> > > > +#define VL_REG_SYSRANGE_MODE_START_STOP			BIT(0)
> > > > +#define VL_REG_SYSRANGE_MODE_BACKTOBACK			BIT(1)
> > > > +#define VL_REG_SYSRANGE_MODE_TIMED			BIT(2)
> > > > +#define VL_REG_SYSRANGE_MODE_HISTOGRAM			BIT(3)
> > > > +
> > > > +#define VL_REG_SYS_SEQUENCE_CFG				BIT(0)
> > > > +#define VL_REG_SYS_INTERMEASUREMENT_PERIOD		BIT(2)
> > > > +#define VL_REG_SYS_RANGE_CFG				0x09
> > > > +#define VL_REG_SYS_INT_GPIO_DISABLED			0x00
> > > > +#define VL_REG_SYS_INT_GPIO_LEVEL_LOW			BIT(0)
> > > > +#define VL_REG_SYS_INT_GPIO_LEVEL_HIGH			BIT(1)
> > > > +#define VL_REG_SYS_INT_GPIO_OUT_OF_WINDOW		0x03
> > > > +#define VL_REG_SYS_INT_GPIO_NEW_SAMPLE_READY		BIT(2)
> > > > +#define VL_REG_SYS_INT_CFG_GPIO				0x0A
> > > > +#define VL_REG_SYS_INT_CLEAR				0x0B
> > > > +#define VL_REG_GPIO_HV_MUX_ACTIVE_HIGH			0x84
> > > > +
> > > > +#define VL_REG_RESULT_INT_STATUS			0x13
> > > > +#define VL_REG_RESULT_RANGE_STATUS			0x14
> > > > +#define VL_REG_RESULT_RANGE_STATUS_COMPLETE		BIT(0)
> > > > +
> > > > +/* Check contents of these registers to verify the device. */
> > > > +#define VL_REG_IDENTIFICATION_MODEL_ID			0xC0
> > > > +#define VL_REG_IDENTIFICATION_REVISION_ID		0xC2
> > > > +
> > > > +struct vl53l0x_data {
> > > > +	struct i2c_client *client;
> > > > +};
> > > > +
> > > > +static int vl53l0x_read_proximity(struct vl53l0x_data *data,
> > > > +				  const struct iio_chan_spec *chan,
> > > > +				  int *val)
> > > > +{
> > > > +	struct i2c_client *client = data->client;
> > > > +	unsigned int tries = 20;
> > > > +	u8 buffer[12];
> > > > +	int ret;
> > > > +
> > > > +	ret = i2c_smbus_write_byte_data(client,
> > > > +		VL_REG_SYSRANGE_START, 1);  
> > > 
> > > Looks like the above would fit on one line.  Please do a quick check
> > > through the driver for other cases of this.
> > >   
> > 
> > Oops, I'll change that. 
> > 
> > > > +	if (ret < 0)
> > > > +		return ret;
> > > > +
> > > > +	do {
> > > > +		ret = i2c_smbus_read_byte_data(client,
> > > > +			VL_REG_RESULT_RANGE_STATUS);
> > > > +		if (ret < 0)
> > > > +			return ret;
> > > > +
> > > > +		if (ret & VL_REG_RESULT_RANGE_STATUS_COMPLETE)
> > > > +			break;
> > > > +
> > > > +		usleep_range(1000, 5000);
> > > > +	} while (--tries);
> > > > +	if (!tries)
> > > > +		return -ETIMEDOUT;
> > > > +
> > > > +	ret = i2c_smbus_read_i2c_block_data(client, VL_REG_RESULT_RANGE_STATUS,
> > > > +		12, buffer);
> > > > +	if (ret < 0)
> > > > +		return ret;
> > > > +	else if (ret != 12)
> > > > +		return -EREMOTEIO;
> > > > +
> > > > +	/* Values should be between 30~1200. */
> > > > +	*val = le16_to_cpu((buffer[10] << 8) + buffer[11]);  
> > > This worries me as a conversion.  The shift and addition is
> > > unwinding the endianness already. You then do it again with le16_to_cpu
> > > 
> > > As it's aligned you could have done
> > > *val = le16_to_cpu(*(le16 *)(&buffer[10]));  That's obviously
> > > a bit ugly though, mainly because we are handling the buffer as
> > > a u8.  Is there a reason to not directly handle it as an le16 array?
> > > 
> > > I'm having trouble finding the relevant section of the manual to actually
> > > figure out what is in the first 10 bytes!
> > > 
> > > 
> > >   
> > 
> > Sorry for this insanity, actually, I was writing this driver without a
> > full memory layout. I tried to look for one, but then I found the poor ST
> > support seems like doesn't want to release one at all! Have a look at
> > this thread on Soren Karlsen's reply:
> > <https://community.st.com/s/question/0D50X00009XkYTtSAN/request-of-vl53l0x>
> > All those documents on ST's support websites mentioned only several
> > registers for connection check.
> > 
> > I can't say this is a very big deal because at least ST released a full
> > API source with documentation. I analyzed their API source and also
> > looked up some usage examples on google to get this device working.
> > The protocal in the datasheet P19-20 shows that this device has to read
> > consecutive bytes stream to get all data. I tried to access these
> > registers one by one but it's not working. 
> > Datasheet:
> > <https://www.st.com/resource/en/datasheet/vl53l0x.pdf> P19-20
> > 
> > Something I know from arduino's example code is that the 11th and 12th
> > bytes hold distance, the 9th and 10th bytes hold signal countdown
> > value and 7th and 8th bytes hold ambient countdown value. 
> 
> Hmm. One of 'those' parts.  They give almost but not quite enough information
> to use it in a sane fashion...  Oh well, we work with what we have and good
> there is at least some example code to get things going!
> 
> > 
> > > > +
> > > > +	return 0;
> > > > +}
> > > > +
> > > > +static const struct iio_chan_spec vl53l0x_channels[] = {
> > > > +	{
> > > > +		.type = IIO_DISTANCE,
> > > > +		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),  
> > > 
> > > This is a time of flight sensor?  As such I would kind of assume it is possible
> > > to get to a real world distance?  Adding scale and offset to do this can
> > > of course be a follow up patch,  but it would be good to have!
> > >   
> > 
> > That's right, there was a scale channel, but since this device returns
> > value in millimeters I thought there isn't a need for that channel, so
> > I just return raw value.
> 
> If it's already in mm then you should use _PROCESSED not _RAW
> to indicate that to userspace.  Right now userspace would think that there
> was no known scaling.
> 

That's something I didn't know, seems like more documents should to
read.

> > Usually in our production, we do some linear calibration for it's return
> > values, but I think this may should be left with userspace to do.
> 
> That's normal.  We give as much information as possible, but if you want any 
> really precise values off a sensor then it's up to you to calibrate it offline.
> 
> > 
> > > > +	},
> > > > +};
> > > > +
> ...
> 
> Jonathan
> 
> 

yours,
Song Qiang



[Index of Archives]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Input]     [Linux Kernel]     [Linux SCSI]     [X.org]

  Powered by Linux