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. > > +}; > > + > > 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; 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