> 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? > +}; > + > 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; > + > + 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; > -- Peter Meerwald-Stadler Mobile: +43 664 24 44 418 -- 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