On Tue, 6 Feb 2018 14:17:40 +0100 Tomas Novotny <tomas@xxxxxxxxxx> wrote: > Hi Peter, > > On Mon, 5 Feb 2018 21:00:48 +0100 (CET) > Peter Meerwald-Stadler <pmeerw@xxxxxxxxxx> wrote: > > > > There are similar chips in a vcnl4xxx family. The initialization and > > > communication is a bit different for another members of the family, so > > > this patch makes the driver extendable for different chips. > > > > > There is no functional change. > > > > looks good to me, suggestion below but not mandatory > > > > > Signed-off-by: Tomas Novotny <tomas@xxxxxxxxxx> > > > --- > > > drivers/iio/light/vcnl4000.c | 86 ++++++++++++++++++++++++++++++++++---------- > > > 1 file changed, 68 insertions(+), 18 deletions(-) > > > > > > diff --git a/drivers/iio/light/vcnl4000.c b/drivers/iio/light/vcnl4000.c > > > index c599a90506ad..d7e43fd9333e 100644 > > > --- a/drivers/iio/light/vcnl4000.c > > > +++ b/drivers/iio/light/vcnl4000.c > > > @@ -26,8 +26,8 @@ > > > #include <linux/iio/sysfs.h> > > > > > > #define VCNL4000_DRV_NAME "vcnl4000" > > > -#define VCNL4000_ID 0x01 > > > -#define VCNL4010_ID 0x02 /* for VCNL4020, VCNL4010 */ > > > +#define VCNL4000_PROD_ID 0x01 > > > +#define VCNL4010_PROD_ID 0x02 /* for VCNL4020, VCNL4010 */ > > > > > > #define VCNL4000_COMMAND 0x80 /* Command register */ > > > #define VCNL4000_PROD_REV 0x81 /* Product ID and Revision ID */ > > > @@ -46,17 +46,52 @@ > > > #define VCNL4000_AL_OD BIT(4) /* start on-demand ALS measurement */ > > > #define VCNL4000_PS_OD BIT(3) /* start on-demand proximity measurement */ > > > > > > +enum vcnl4000_device_ids { > > > + VCNL4000, > > > > maybe add VCNL4010 here and in vcnl4000_chip_spec_cfg just for > > completeness, so that all IDs are actually used? > > ok, I will do. Does it make sense to be strict and return -ENODEV (with > appropriate message) when vcnl4000 i2c device is specified but > VCNL4010_PROD_ID is found (and the same for VCNL4000_PROD_ID)? There is only > a general check now, see below. Probably better to just put a warning out. People have an irritating habit of having a dt file for their board based on the wrong compatible. Given the driver can detect this and 'fix' it I think it should. Please do put a suitably worded warning in the logs though as better to fix it properly! > > > > +}; > > > + > > > struct vcnl4000_data { > > > struct i2c_client *client; > > > + enum vcnl4000_device_ids id; > > > + const char *prod; > > > + int rev; > > > + int al_scale; > > > + const struct vcnl4000_chip_spec *chip_spec; > > > struct mutex lock; > > > }; > > > > > > +struct vcnl4000_chip_spec { > > > + int (*init)(struct vcnl4000_data *data); > > > + int (*measure_light)(struct vcnl4000_data *data, int *val); > > > + int (*measure_proximity)(struct vcnl4000_data *data, int *val); > > > +}; > > > + > > > static const struct i2c_device_id vcnl4000_id[] = { > > > - { "vcnl4000", 0 }, > > > + { "vcnl4000", VCNL4000 }, > > > { } > > > }; > > > MODULE_DEVICE_TABLE(i2c, vcnl4000_id); > > > > > > +static int vcnl4000_init(struct vcnl4000_data *data) > > > +{ > > > + int ret, prod_id; > > > + > > > + ret = i2c_smbus_read_byte_data(data->client, VCNL4000_PROD_REV); > > > + if (ret < 0) > > > + return ret; > > > + > > > + prod_id = ret >> 4; > > > + if (prod_id != VCNL4010_PROD_ID && prod_id != VCNL4000_PROD_ID) > > > + return -ENODEV; > As a general scalability thing, I would do that as a switch statement. These sorts of if statements have a habit of growing every time a new variant comes along and in the end get changed to a switch statement which causes more noise than it would have done if we had allowed for the future in the first place. > here ^^^ > > Thanks, > > Tomas > > > > + data->prod = prod_id == VCNL4010_PROD_ID ? "VCNL4010/4020" : "VCNL4000"; > > > + data->rev = ret & 0xf; > > > + > > > + data->al_scale = 250000; > > > + > > > + return 0; > > > +}; > > > + > > > static int vcnl4000_measure(struct vcnl4000_data *data, u8 req_mask, > > > u8 rdy_mask, u8 data_reg, int *val) > > > { > > > @@ -103,6 +138,28 @@ static int vcnl4000_measure(struct vcnl4000_data *data, u8 req_mask, > > > return ret; > > > } > > > > > > +static int vcnl4000_measure_light(struct vcnl4000_data *data, int *val) > > > +{ > > > + return vcnl4000_measure(data, > > > + VCNL4000_AL_OD, VCNL4000_AL_RDY, > > > + VCNL4000_AL_RESULT_HI, val); > > > +} > > > + > > > +static int vcnl4000_measure_proximity(struct vcnl4000_data *data, int *val) > > > +{ > > > + return vcnl4000_measure(data, > > > + VCNL4000_PS_OD, VCNL4000_PS_RDY, > > > + VCNL4000_PS_RESULT_HI, val); > > > +} > > > + > > > +static const struct vcnl4000_chip_spec vcnl4000_chip_spec_cfg[] = { > > > + [VCNL4000] = { > > > + .init = vcnl4000_init, > > > + .measure_light = vcnl4000_measure_light, > > > + .measure_proximity = vcnl4000_measure_proximity, > > > + }, > > > +}; > > > + > > > static const struct iio_chan_spec vcnl4000_channels[] = { > > > { > > > .type = IIO_LIGHT, > > > @@ -125,16 +182,12 @@ static int vcnl4000_read_raw(struct iio_dev *indio_dev, > > > case IIO_CHAN_INFO_RAW: > > > switch (chan->type) { > > > case IIO_LIGHT: > > > - ret = vcnl4000_measure(data, > > > - VCNL4000_AL_OD, VCNL4000_AL_RDY, > > > - VCNL4000_AL_RESULT_HI, val); > > > + ret = data->chip_spec->measure_light(data, val); > > > if (ret < 0) > > > return ret; > > > return IIO_VAL_INT; > > > case IIO_PROXIMITY: > > > - ret = vcnl4000_measure(data, > > > - VCNL4000_PS_OD, VCNL4000_PS_RDY, > > > - VCNL4000_PS_RESULT_HI, val); > > > + ret = data->chip_spec->measure_proximity(data, val); > > > if (ret < 0) > > > return ret; > > > return IIO_VAL_INT; > > > @@ -146,7 +199,7 @@ static int vcnl4000_read_raw(struct iio_dev *indio_dev, > > > return -EINVAL; > > > > > > *val = 0; > > > - *val2 = 250000; > > > + *val2 = data->al_scale; > > > return IIO_VAL_INT_PLUS_MICRO; > > > default: > > > return -EINVAL; > > > @@ -162,7 +215,7 @@ static int vcnl4000_probe(struct i2c_client *client, > > > { > > > struct vcnl4000_data *data; > > > struct iio_dev *indio_dev; > > > - int ret, prod_id; > > > + int ret; > > > > > > indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); > > > if (!indio_dev) > > > @@ -171,19 +224,16 @@ static int vcnl4000_probe(struct i2c_client *client, > > > data = iio_priv(indio_dev); > > > i2c_set_clientdata(client, indio_dev); > > > data->client = client; > > > + data->id = id->driver_data; > > > + data->chip_spec = &vcnl4000_chip_spec_cfg[data->id]; > > > mutex_init(&data->lock); > > > > > > - ret = i2c_smbus_read_byte_data(data->client, VCNL4000_PROD_REV); > > > + ret = data->chip_spec->init(data); > > > if (ret < 0) > > > return ret; > > > > > > - prod_id = ret >> 4; > > > - if (prod_id != VCNL4010_ID && prod_id != VCNL4000_ID) > > > - return -ENODEV; > > > - > > > dev_dbg(&client->dev, "%s Ambient light/proximity sensor, Rev: %02x\n", > > > - (prod_id == VCNL4010_ID) ? "VCNL4010/4020" : "VCNL4000", > > > - ret & 0xf); > > > + data->prod, data->rev); > > > > > > indio_dev->dev.parent = &client->dev; > > > indio_dev->info = &vcnl4000_info; > > > > > -- To unsubscribe from this list: send the line "unsubscribe linux-iio" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html