Skip to content

Commit 1ebc787

Browse files
stoupa-czjic23
authored andcommitted
iio: vcnl4000: make the driver extendable
There are similar chips in the vcnl4xxx family. The initialization and communication is a bit different for members of the family, so this patch makes the driver extendable for different chips. There is no functional change. Signed-off-by: Tomas Novotny <[email protected]> Signed-off-by: Jonathan Cameron <[email protected]>
1 parent cebc458 commit 1ebc787

File tree

1 file changed

+67
-18
lines changed

1 file changed

+67
-18
lines changed

drivers/iio/light/vcnl4000.c

Lines changed: 67 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@
2626
#include <linux/iio/sysfs.h>
2727

2828
#define VCNL4000_DRV_NAME "vcnl4000"
29-
#define VCNL4000_ID 0x01
30-
#define VCNL4010_ID 0x02 /* for VCNL4020, VCNL4010 */
29+
#define VCNL4000_PROD_ID 0x01
30+
#define VCNL4010_PROD_ID 0x02 /* for VCNL4020, VCNL4010 */
3131

3232
#define VCNL4000_COMMAND 0x80 /* Command register */
3333
#define VCNL4000_PROD_REV 0x81 /* Product ID and Revision ID */
@@ -46,17 +46,50 @@
4646
#define VCNL4000_AL_OD BIT(4) /* start on-demand ALS measurement */
4747
#define VCNL4000_PS_OD BIT(3) /* start on-demand proximity measurement */
4848

49+
enum vcnl4000_device_ids {
50+
VCNL4000,
51+
};
52+
4953
struct vcnl4000_data {
5054
struct i2c_client *client;
55+
enum vcnl4000_device_ids id;
56+
int rev;
57+
int al_scale;
58+
const struct vcnl4000_chip_spec *chip_spec;
5159
struct mutex lock;
5260
};
5361

62+
struct vcnl4000_chip_spec {
63+
const char *prod;
64+
int (*init)(struct vcnl4000_data *data);
65+
int (*measure_light)(struct vcnl4000_data *data, int *val);
66+
int (*measure_proximity)(struct vcnl4000_data *data, int *val);
67+
};
68+
5469
static const struct i2c_device_id vcnl4000_id[] = {
55-
{ "vcnl4000", 0 },
70+
{ "vcnl4000", VCNL4000 },
5671
{ }
5772
};
5873
MODULE_DEVICE_TABLE(i2c, vcnl4000_id);
5974

75+
static int vcnl4000_init(struct vcnl4000_data *data)
76+
{
77+
int ret, prod_id;
78+
79+
ret = i2c_smbus_read_byte_data(data->client, VCNL4000_PROD_REV);
80+
if (ret < 0)
81+
return ret;
82+
83+
prod_id = ret >> 4;
84+
if (prod_id != VCNL4010_PROD_ID && prod_id != VCNL4000_PROD_ID)
85+
return -ENODEV;
86+
87+
data->rev = ret & 0xf;
88+
data->al_scale = 250000;
89+
90+
return 0;
91+
};
92+
6093
static int vcnl4000_measure(struct vcnl4000_data *data, u8 req_mask,
6194
u8 rdy_mask, u8 data_reg, int *val)
6295
{
@@ -103,6 +136,29 @@ static int vcnl4000_measure(struct vcnl4000_data *data, u8 req_mask,
103136
return ret;
104137
}
105138

139+
static int vcnl4000_measure_light(struct vcnl4000_data *data, int *val)
140+
{
141+
return vcnl4000_measure(data,
142+
VCNL4000_AL_OD, VCNL4000_AL_RDY,
143+
VCNL4000_AL_RESULT_HI, val);
144+
}
145+
146+
static int vcnl4000_measure_proximity(struct vcnl4000_data *data, int *val)
147+
{
148+
return vcnl4000_measure(data,
149+
VCNL4000_PS_OD, VCNL4000_PS_RDY,
150+
VCNL4000_PS_RESULT_HI, val);
151+
}
152+
153+
static const struct vcnl4000_chip_spec vcnl4000_chip_spec_cfg[] = {
154+
[VCNL4000] = {
155+
.prod = "VCNL4000",
156+
.init = vcnl4000_init,
157+
.measure_light = vcnl4000_measure_light,
158+
.measure_proximity = vcnl4000_measure_proximity,
159+
},
160+
};
161+
106162
static const struct iio_chan_spec vcnl4000_channels[] = {
107163
{
108164
.type = IIO_LIGHT,
@@ -125,16 +181,12 @@ static int vcnl4000_read_raw(struct iio_dev *indio_dev,
125181
case IIO_CHAN_INFO_RAW:
126182
switch (chan->type) {
127183
case IIO_LIGHT:
128-
ret = vcnl4000_measure(data,
129-
VCNL4000_AL_OD, VCNL4000_AL_RDY,
130-
VCNL4000_AL_RESULT_HI, val);
184+
ret = data->chip_spec->measure_light(data, val);
131185
if (ret < 0)
132186
return ret;
133187
return IIO_VAL_INT;
134188
case IIO_PROXIMITY:
135-
ret = vcnl4000_measure(data,
136-
VCNL4000_PS_OD, VCNL4000_PS_RDY,
137-
VCNL4000_PS_RESULT_HI, val);
189+
ret = data->chip_spec->measure_proximity(data, val);
138190
if (ret < 0)
139191
return ret;
140192
return IIO_VAL_INT;
@@ -146,7 +198,7 @@ static int vcnl4000_read_raw(struct iio_dev *indio_dev,
146198
return -EINVAL;
147199

148200
*val = 0;
149-
*val2 = 250000;
201+
*val2 = data->al_scale;
150202
return IIO_VAL_INT_PLUS_MICRO;
151203
default:
152204
return -EINVAL;
@@ -162,7 +214,7 @@ static int vcnl4000_probe(struct i2c_client *client,
162214
{
163215
struct vcnl4000_data *data;
164216
struct iio_dev *indio_dev;
165-
int ret, prod_id;
217+
int ret;
166218

167219
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
168220
if (!indio_dev)
@@ -171,19 +223,16 @@ static int vcnl4000_probe(struct i2c_client *client,
171223
data = iio_priv(indio_dev);
172224
i2c_set_clientdata(client, indio_dev);
173225
data->client = client;
226+
data->id = id->driver_data;
227+
data->chip_spec = &vcnl4000_chip_spec_cfg[data->id];
174228
mutex_init(&data->lock);
175229

176-
ret = i2c_smbus_read_byte_data(data->client, VCNL4000_PROD_REV);
230+
ret = data->chip_spec->init(data);
177231
if (ret < 0)
178232
return ret;
179233

180-
prod_id = ret >> 4;
181-
if (prod_id != VCNL4010_ID && prod_id != VCNL4000_ID)
182-
return -ENODEV;
183-
184234
dev_dbg(&client->dev, "%s Ambient light/proximity sensor, Rev: %02x\n",
185-
(prod_id == VCNL4010_ID) ? "VCNL4010/4020" : "VCNL4000",
186-
ret & 0xf);
235+
data->chip_spec->prod, data->rev);
187236

188237
indio_dev->dev.parent = &client->dev;
189238
indio_dev->info = &vcnl4000_info;

0 commit comments

Comments
 (0)