26
26
#include <linux/iio/sysfs.h>
27
27
28
28
#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 */
31
31
32
32
#define VCNL4000_COMMAND 0x80 /* Command register */
33
33
#define VCNL4000_PROD_REV 0x81 /* Product ID and Revision ID */
46
46
#define VCNL4000_AL_OD BIT(4) /* start on-demand ALS measurement */
47
47
#define VCNL4000_PS_OD BIT(3) /* start on-demand proximity measurement */
48
48
49
+ enum vcnl4000_device_ids {
50
+ VCNL4000 ,
51
+ };
52
+
49
53
struct vcnl4000_data {
50
54
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 ;
51
59
struct mutex lock ;
52
60
};
53
61
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
+
54
69
static const struct i2c_device_id vcnl4000_id [] = {
55
- { "vcnl4000" , 0 },
70
+ { "vcnl4000" , VCNL4000 },
56
71
{ }
57
72
};
58
73
MODULE_DEVICE_TABLE (i2c , vcnl4000_id );
59
74
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
+
60
93
static int vcnl4000_measure (struct vcnl4000_data * data , u8 req_mask ,
61
94
u8 rdy_mask , u8 data_reg , int * val )
62
95
{
@@ -103,6 +136,29 @@ static int vcnl4000_measure(struct vcnl4000_data *data, u8 req_mask,
103
136
return ret ;
104
137
}
105
138
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
+
106
162
static const struct iio_chan_spec vcnl4000_channels [] = {
107
163
{
108
164
.type = IIO_LIGHT ,
@@ -125,16 +181,12 @@ static int vcnl4000_read_raw(struct iio_dev *indio_dev,
125
181
case IIO_CHAN_INFO_RAW :
126
182
switch (chan -> type ) {
127
183
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 );
131
185
if (ret < 0 )
132
186
return ret ;
133
187
return IIO_VAL_INT ;
134
188
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 );
138
190
if (ret < 0 )
139
191
return ret ;
140
192
return IIO_VAL_INT ;
@@ -146,7 +198,7 @@ static int vcnl4000_read_raw(struct iio_dev *indio_dev,
146
198
return - EINVAL ;
147
199
148
200
* val = 0 ;
149
- * val2 = 250000 ;
201
+ * val2 = data -> al_scale ;
150
202
return IIO_VAL_INT_PLUS_MICRO ;
151
203
default :
152
204
return - EINVAL ;
@@ -162,7 +214,7 @@ static int vcnl4000_probe(struct i2c_client *client,
162
214
{
163
215
struct vcnl4000_data * data ;
164
216
struct iio_dev * indio_dev ;
165
- int ret , prod_id ;
217
+ int ret ;
166
218
167
219
indio_dev = devm_iio_device_alloc (& client -> dev , sizeof (* data ));
168
220
if (!indio_dev )
@@ -171,19 +223,16 @@ static int vcnl4000_probe(struct i2c_client *client,
171
223
data = iio_priv (indio_dev );
172
224
i2c_set_clientdata (client , indio_dev );
173
225
data -> client = client ;
226
+ data -> id = id -> driver_data ;
227
+ data -> chip_spec = & vcnl4000_chip_spec_cfg [data -> id ];
174
228
mutex_init (& data -> lock );
175
229
176
- ret = i2c_smbus_read_byte_data ( data -> client , VCNL4000_PROD_REV );
230
+ ret = data -> chip_spec -> init ( data );
177
231
if (ret < 0 )
178
232
return ret ;
179
233
180
- prod_id = ret >> 4 ;
181
- if (prod_id != VCNL4010_ID && prod_id != VCNL4000_ID )
182
- return - ENODEV ;
183
-
184
234
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 );
187
236
188
237
indio_dev -> dev .parent = & client -> dev ;
189
238
indio_dev -> info = & vcnl4000_info ;
0 commit comments