]>
Commit | Line | Data |
---|---|---|
be9e6229 TB |
1 | /** |
2 | * Sensortek STK3310/STK3311 Ambient Light and Proximity Sensor | |
3 | * | |
4 | * Copyright (c) 2015, Intel Corporation. | |
5 | * | |
6 | * This file is subject to the terms and conditions of version 2 of | |
7 | * the GNU General Public License. See the file COPYING in the main | |
8 | * directory of this archive for more details. | |
9 | * | |
10 | * IIO driver for STK3310/STK3311. 7-bit I2C address: 0x48. | |
11 | */ | |
12 | ||
13 | #include <linux/acpi.h> | |
14 | #include <linux/i2c.h> | |
3dd477ac | 15 | #include <linux/interrupt.h> |
be9e6229 TB |
16 | #include <linux/kernel.h> |
17 | #include <linux/module.h> | |
18 | #include <linux/regmap.h> | |
3dd477ac TB |
19 | #include <linux/gpio/consumer.h> |
20 | #include <linux/iio/events.h> | |
be9e6229 TB |
21 | #include <linux/iio/iio.h> |
22 | #include <linux/iio/sysfs.h> | |
23 | ||
24 | #define STK3310_REG_STATE 0x00 | |
25 | #define STK3310_REG_PSCTRL 0x01 | |
26 | #define STK3310_REG_ALSCTRL 0x02 | |
3dd477ac TB |
27 | #define STK3310_REG_INT 0x04 |
28 | #define STK3310_REG_THDH_PS 0x06 | |
29 | #define STK3310_REG_THDL_PS 0x08 | |
30 | #define STK3310_REG_FLAG 0x10 | |
be9e6229 TB |
31 | #define STK3310_REG_PS_DATA_MSB 0x11 |
32 | #define STK3310_REG_PS_DATA_LSB 0x12 | |
33 | #define STK3310_REG_ALS_DATA_MSB 0x13 | |
34 | #define STK3310_REG_ALS_DATA_LSB 0x14 | |
35 | #define STK3310_REG_ID 0x3E | |
36 | #define STK3310_MAX_REG 0x80 | |
37 | ||
38 | #define STK3310_STATE_EN_PS 0x01 | |
39 | #define STK3310_STATE_EN_ALS 0x02 | |
40 | #define STK3310_STATE_STANDBY 0x00 | |
41 | ||
42 | #define STK3310_CHIP_ID_VAL 0x13 | |
43 | #define STK3311_CHIP_ID_VAL 0x1D | |
3dd477ac | 44 | #define STK3310_PSINT_EN 0x01 |
be9e6229 | 45 | #define STK3310_PS_MAX_VAL 0xFFFF |
3dd477ac | 46 | #define STK3310_THRESH_MAX 0xFFFF |
be9e6229 TB |
47 | |
48 | #define STK3310_DRIVER_NAME "stk3310" | |
49 | #define STK3310_REGMAP_NAME "stk3310_regmap" | |
3dd477ac TB |
50 | #define STK3310_EVENT "stk3310_event" |
51 | #define STK3310_GPIO "stk3310_gpio" | |
be9e6229 TB |
52 | |
53 | #define STK3310_SCALE_AVAILABLE "6.4 1.6 0.4 0.1" | |
54 | ||
55 | #define STK3310_IT_AVAILABLE \ | |
56 | "0.000185 0.000370 0.000741 0.001480 0.002960 0.005920 0.011840 " \ | |
57 | "0.023680 0.047360 0.094720 0.189440 0.378880 0.757760 1.515520 " \ | |
58 | "3.031040 6.062080" | |
59 | ||
60 | #define STK3310_REGFIELD(name) \ | |
61 | do { \ | |
62 | data->reg_##name = \ | |
63 | devm_regmap_field_alloc(&client->dev, regmap, \ | |
64 | stk3310_reg_field_##name); \ | |
65 | if (IS_ERR(data->reg_##name)) { \ | |
66 | dev_err(&client->dev, "reg field alloc failed.\n"); \ | |
67 | return PTR_ERR(data->reg_##name); \ | |
68 | } \ | |
69 | } while (0) | |
70 | ||
71 | static const struct reg_field stk3310_reg_field_state = | |
72 | REG_FIELD(STK3310_REG_STATE, 0, 2); | |
73 | static const struct reg_field stk3310_reg_field_als_gain = | |
74 | REG_FIELD(STK3310_REG_ALSCTRL, 4, 5); | |
75 | static const struct reg_field stk3310_reg_field_ps_gain = | |
76 | REG_FIELD(STK3310_REG_PSCTRL, 4, 5); | |
77 | static const struct reg_field stk3310_reg_field_als_it = | |
78 | REG_FIELD(STK3310_REG_ALSCTRL, 0, 3); | |
79 | static const struct reg_field stk3310_reg_field_ps_it = | |
80 | REG_FIELD(STK3310_REG_PSCTRL, 0, 3); | |
3dd477ac TB |
81 | static const struct reg_field stk3310_reg_field_int_ps = |
82 | REG_FIELD(STK3310_REG_INT, 0, 2); | |
83 | static const struct reg_field stk3310_reg_field_flag_psint = | |
84 | REG_FIELD(STK3310_REG_FLAG, 4, 4); | |
85 | static const struct reg_field stk3310_reg_field_flag_nf = | |
86 | REG_FIELD(STK3310_REG_FLAG, 0, 0); | |
be9e6229 TB |
87 | /* |
88 | * Maximum PS values with regard to scale. Used to export the 'inverse' | |
89 | * PS value (high values for far objects, low values for near objects). | |
90 | */ | |
91 | static const int stk3310_ps_max[4] = { | |
92 | STK3310_PS_MAX_VAL / 64, | |
93 | STK3310_PS_MAX_VAL / 16, | |
94 | STK3310_PS_MAX_VAL / 4, | |
95 | STK3310_PS_MAX_VAL, | |
96 | }; | |
97 | ||
98 | static const int stk3310_scale_table[][2] = { | |
99 | {6, 400000}, {1, 600000}, {0, 400000}, {0, 100000} | |
100 | }; | |
101 | ||
102 | /* Integration time in seconds, microseconds */ | |
103 | static const int stk3310_it_table[][2] = { | |
104 | {0, 185}, {0, 370}, {0, 741}, {0, 1480}, | |
105 | {0, 2960}, {0, 5920}, {0, 11840}, {0, 23680}, | |
106 | {0, 47360}, {0, 94720}, {0, 189440}, {0, 378880}, | |
107 | {0, 757760}, {1, 515520}, {3, 31040}, {6, 62080}, | |
108 | }; | |
109 | ||
110 | struct stk3310_data { | |
111 | struct i2c_client *client; | |
112 | struct mutex lock; | |
113 | bool als_enabled; | |
114 | bool ps_enabled; | |
3dd477ac | 115 | u64 timestamp; |
be9e6229 TB |
116 | struct regmap *regmap; |
117 | struct regmap_field *reg_state; | |
118 | struct regmap_field *reg_als_gain; | |
119 | struct regmap_field *reg_ps_gain; | |
120 | struct regmap_field *reg_als_it; | |
121 | struct regmap_field *reg_ps_it; | |
3dd477ac TB |
122 | struct regmap_field *reg_int_ps; |
123 | struct regmap_field *reg_flag_psint; | |
124 | struct regmap_field *reg_flag_nf; | |
125 | }; | |
126 | ||
127 | static const struct iio_event_spec stk3310_events[] = { | |
128 | /* Proximity event */ | |
129 | { | |
130 | .type = IIO_EV_TYPE_THRESH, | |
131 | .dir = IIO_EV_DIR_FALLING, | |
132 | .mask_separate = BIT(IIO_EV_INFO_VALUE) | | |
133 | BIT(IIO_EV_INFO_ENABLE), | |
134 | }, | |
135 | /* Out-of-proximity event */ | |
136 | { | |
137 | .type = IIO_EV_TYPE_THRESH, | |
138 | .dir = IIO_EV_DIR_RISING, | |
139 | .mask_separate = BIT(IIO_EV_INFO_VALUE) | | |
140 | BIT(IIO_EV_INFO_ENABLE), | |
141 | }, | |
be9e6229 TB |
142 | }; |
143 | ||
144 | static const struct iio_chan_spec stk3310_channels[] = { | |
145 | { | |
146 | .type = IIO_LIGHT, | |
147 | .info_mask_separate = | |
148 | BIT(IIO_CHAN_INFO_RAW) | | |
149 | BIT(IIO_CHAN_INFO_SCALE) | | |
150 | BIT(IIO_CHAN_INFO_INT_TIME), | |
151 | }, | |
152 | { | |
153 | .type = IIO_PROXIMITY, | |
154 | .info_mask_separate = | |
155 | BIT(IIO_CHAN_INFO_RAW) | | |
156 | BIT(IIO_CHAN_INFO_SCALE) | | |
157 | BIT(IIO_CHAN_INFO_INT_TIME), | |
3dd477ac TB |
158 | .event_spec = stk3310_events, |
159 | .num_event_specs = ARRAY_SIZE(stk3310_events), | |
be9e6229 TB |
160 | } |
161 | }; | |
162 | ||
163 | static IIO_CONST_ATTR(in_illuminance_scale_available, STK3310_SCALE_AVAILABLE); | |
164 | ||
165 | static IIO_CONST_ATTR(in_proximity_scale_available, STK3310_SCALE_AVAILABLE); | |
166 | ||
167 | static IIO_CONST_ATTR(in_illuminance_integration_time_available, | |
168 | STK3310_IT_AVAILABLE); | |
169 | ||
170 | static IIO_CONST_ATTR(in_proximity_integration_time_available, | |
171 | STK3310_IT_AVAILABLE); | |
172 | ||
173 | static struct attribute *stk3310_attributes[] = { | |
174 | &iio_const_attr_in_illuminance_scale_available.dev_attr.attr, | |
175 | &iio_const_attr_in_proximity_scale_available.dev_attr.attr, | |
176 | &iio_const_attr_in_illuminance_integration_time_available.dev_attr.attr, | |
177 | &iio_const_attr_in_proximity_integration_time_available.dev_attr.attr, | |
178 | NULL, | |
179 | }; | |
180 | ||
181 | static const struct attribute_group stk3310_attribute_group = { | |
182 | .attrs = stk3310_attributes | |
183 | }; | |
184 | ||
185 | static int stk3310_get_index(const int table[][2], int table_size, | |
186 | int val, int val2) | |
187 | { | |
188 | int i; | |
189 | ||
190 | for (i = 0; i < table_size; i++) { | |
191 | if (val == table[i][0] && val2 == table[i][1]) | |
192 | return i; | |
193 | } | |
194 | ||
195 | return -EINVAL; | |
196 | } | |
197 | ||
3dd477ac TB |
198 | static int stk3310_read_event(struct iio_dev *indio_dev, |
199 | const struct iio_chan_spec *chan, | |
200 | enum iio_event_type type, | |
201 | enum iio_event_direction dir, | |
202 | enum iio_event_info info, | |
203 | int *val, int *val2) | |
204 | { | |
205 | u8 reg; | |
206 | u16 buf; | |
207 | int ret; | |
208 | unsigned int index; | |
209 | struct stk3310_data *data = iio_priv(indio_dev); | |
210 | ||
211 | if (info != IIO_EV_INFO_VALUE) | |
212 | return -EINVAL; | |
213 | ||
214 | /* | |
215 | * Only proximity interrupts are implemented at the moment. | |
216 | * Since we're inverting proximity values, the sensor's 'high' | |
217 | * threshold will become our 'low' threshold, associated with | |
218 | * 'near' events. Similarly, the sensor's 'low' threshold will | |
219 | * be our 'high' threshold, associated with 'far' events. | |
220 | */ | |
221 | if (dir == IIO_EV_DIR_RISING) | |
222 | reg = STK3310_REG_THDL_PS; | |
223 | else if (dir == IIO_EV_DIR_FALLING) | |
224 | reg = STK3310_REG_THDH_PS; | |
225 | else | |
226 | return -EINVAL; | |
227 | ||
228 | mutex_lock(&data->lock); | |
229 | ret = regmap_bulk_read(data->regmap, reg, &buf, 2); | |
230 | mutex_unlock(&data->lock); | |
231 | if (ret < 0) { | |
232 | dev_err(&data->client->dev, "register read failed\n"); | |
233 | return ret; | |
234 | } | |
235 | regmap_field_read(data->reg_ps_gain, &index); | |
236 | *val = swab16(stk3310_ps_max[index] - buf); | |
237 | ||
238 | return IIO_VAL_INT; | |
239 | } | |
240 | ||
241 | static int stk3310_write_event(struct iio_dev *indio_dev, | |
242 | const struct iio_chan_spec *chan, | |
243 | enum iio_event_type type, | |
244 | enum iio_event_direction dir, | |
245 | enum iio_event_info info, | |
246 | int val, int val2) | |
247 | { | |
248 | u8 reg; | |
249 | u16 buf; | |
250 | int ret; | |
251 | unsigned int index; | |
252 | struct stk3310_data *data = iio_priv(indio_dev); | |
253 | struct i2c_client *client = data->client; | |
254 | ||
255 | regmap_field_read(data->reg_ps_gain, &index); | |
256 | if (val > stk3310_ps_max[index]) | |
257 | return -EINVAL; | |
258 | ||
259 | if (dir == IIO_EV_DIR_RISING) | |
260 | reg = STK3310_REG_THDL_PS; | |
261 | else if (dir == IIO_EV_DIR_FALLING) | |
262 | reg = STK3310_REG_THDH_PS; | |
263 | else | |
264 | return -EINVAL; | |
265 | ||
266 | buf = swab16(stk3310_ps_max[index] - val); | |
267 | ret = regmap_bulk_write(data->regmap, reg, &buf, 2); | |
268 | if (ret < 0) | |
269 | dev_err(&client->dev, "failed to set PS threshold!\n"); | |
270 | ||
271 | return ret; | |
272 | } | |
273 | ||
274 | static int stk3310_read_event_config(struct iio_dev *indio_dev, | |
275 | const struct iio_chan_spec *chan, | |
276 | enum iio_event_type type, | |
277 | enum iio_event_direction dir) | |
278 | { | |
279 | unsigned int event_val; | |
280 | struct stk3310_data *data = iio_priv(indio_dev); | |
281 | ||
282 | regmap_field_read(data->reg_int_ps, &event_val); | |
283 | ||
284 | return event_val; | |
285 | } | |
286 | ||
287 | static int stk3310_write_event_config(struct iio_dev *indio_dev, | |
288 | const struct iio_chan_spec *chan, | |
289 | enum iio_event_type type, | |
290 | enum iio_event_direction dir, | |
291 | int state) | |
292 | { | |
293 | int ret; | |
294 | struct stk3310_data *data = iio_priv(indio_dev); | |
295 | struct i2c_client *client = data->client; | |
296 | ||
297 | if (state < 0 || state > 7) | |
298 | return -EINVAL; | |
299 | ||
300 | /* Set INT_PS value */ | |
301 | mutex_lock(&data->lock); | |
302 | ret = regmap_field_write(data->reg_int_ps, state); | |
303 | if (ret < 0) | |
304 | dev_err(&client->dev, "failed to set interrupt mode\n"); | |
305 | mutex_unlock(&data->lock); | |
306 | ||
307 | return ret; | |
308 | } | |
309 | ||
be9e6229 TB |
310 | static int stk3310_read_raw(struct iio_dev *indio_dev, |
311 | struct iio_chan_spec const *chan, | |
312 | int *val, int *val2, long mask) | |
313 | { | |
314 | u8 reg; | |
315 | u16 buf; | |
316 | int ret; | |
317 | unsigned int index; | |
318 | struct stk3310_data *data = iio_priv(indio_dev); | |
319 | struct i2c_client *client = data->client; | |
320 | ||
321 | switch (mask) { | |
322 | case IIO_CHAN_INFO_RAW: | |
323 | if (chan->type == IIO_LIGHT) | |
324 | reg = STK3310_REG_ALS_DATA_MSB; | |
325 | else if (chan->type == IIO_PROXIMITY) | |
326 | reg = STK3310_REG_PS_DATA_MSB; | |
327 | else | |
328 | return -EINVAL; | |
329 | mutex_lock(&data->lock); | |
330 | ret = regmap_bulk_read(data->regmap, reg, &buf, 2); | |
331 | if (ret < 0) { | |
332 | dev_err(&client->dev, "register read failed\n"); | |
333 | mutex_unlock(&data->lock); | |
334 | return ret; | |
335 | } | |
336 | *val = swab16(buf); | |
337 | if (chan->type == IIO_PROXIMITY) { | |
338 | /* | |
339 | * Invert the proximity data so we return low values | |
340 | * for close objects and high values for far ones. | |
341 | */ | |
342 | regmap_field_read(data->reg_ps_gain, &index); | |
343 | *val = stk3310_ps_max[index] - *val; | |
344 | } | |
345 | mutex_unlock(&data->lock); | |
346 | return IIO_VAL_INT; | |
347 | case IIO_CHAN_INFO_INT_TIME: | |
348 | if (chan->type == IIO_LIGHT) | |
349 | regmap_field_read(data->reg_als_it, &index); | |
350 | else | |
351 | regmap_field_read(data->reg_ps_it, &index); | |
352 | *val = stk3310_it_table[index][0]; | |
353 | *val2 = stk3310_it_table[index][1]; | |
354 | return IIO_VAL_INT_PLUS_MICRO; | |
355 | case IIO_CHAN_INFO_SCALE: | |
356 | if (chan->type == IIO_LIGHT) | |
357 | regmap_field_read(data->reg_als_gain, &index); | |
358 | else | |
359 | regmap_field_read(data->reg_ps_gain, &index); | |
360 | *val = stk3310_scale_table[index][0]; | |
361 | *val2 = stk3310_scale_table[index][1]; | |
362 | return IIO_VAL_INT_PLUS_MICRO; | |
363 | } | |
364 | ||
365 | return -EINVAL; | |
366 | } | |
367 | ||
368 | static int stk3310_write_raw(struct iio_dev *indio_dev, | |
369 | struct iio_chan_spec const *chan, | |
370 | int val, int val2, long mask) | |
371 | { | |
372 | int ret; | |
ed6e75c7 | 373 | int index; |
be9e6229 TB |
374 | struct stk3310_data *data = iio_priv(indio_dev); |
375 | ||
376 | switch (mask) { | |
377 | case IIO_CHAN_INFO_INT_TIME: | |
378 | index = stk3310_get_index(stk3310_it_table, | |
379 | ARRAY_SIZE(stk3310_it_table), | |
380 | val, val2); | |
381 | if (index < 0) | |
382 | return -EINVAL; | |
383 | mutex_lock(&data->lock); | |
384 | if (chan->type == IIO_LIGHT) | |
385 | ret = regmap_field_write(data->reg_als_it, index); | |
386 | else | |
387 | ret = regmap_field_write(data->reg_ps_it, index); | |
388 | if (ret < 0) | |
389 | dev_err(&data->client->dev, | |
390 | "sensor configuration failed\n"); | |
391 | mutex_unlock(&data->lock); | |
392 | return ret; | |
393 | ||
394 | case IIO_CHAN_INFO_SCALE: | |
395 | index = stk3310_get_index(stk3310_scale_table, | |
396 | ARRAY_SIZE(stk3310_scale_table), | |
397 | val, val2); | |
398 | if (index < 0) | |
399 | return -EINVAL; | |
400 | mutex_lock(&data->lock); | |
401 | if (chan->type == IIO_LIGHT) | |
402 | ret = regmap_field_write(data->reg_als_gain, index); | |
403 | else | |
404 | ret = regmap_field_write(data->reg_ps_gain, index); | |
405 | if (ret < 0) | |
406 | dev_err(&data->client->dev, | |
407 | "sensor configuration failed\n"); | |
408 | mutex_unlock(&data->lock); | |
409 | return ret; | |
410 | } | |
411 | ||
412 | return -EINVAL; | |
413 | } | |
414 | ||
415 | static const struct iio_info stk3310_info = { | |
416 | .driver_module = THIS_MODULE, | |
417 | .read_raw = stk3310_read_raw, | |
418 | .write_raw = stk3310_write_raw, | |
419 | .attrs = &stk3310_attribute_group, | |
3dd477ac TB |
420 | .read_event_value = stk3310_read_event, |
421 | .write_event_value = stk3310_write_event, | |
422 | .read_event_config = stk3310_read_event_config, | |
423 | .write_event_config = stk3310_write_event_config, | |
be9e6229 TB |
424 | }; |
425 | ||
426 | static int stk3310_set_state(struct stk3310_data *data, u8 state) | |
427 | { | |
428 | int ret; | |
429 | struct i2c_client *client = data->client; | |
430 | ||
431 | /* 3-bit state; 0b100 is not supported. */ | |
432 | if (state > 7 || state == 4) | |
433 | return -EINVAL; | |
434 | ||
435 | mutex_lock(&data->lock); | |
436 | ret = regmap_field_write(data->reg_state, state); | |
437 | if (ret < 0) { | |
438 | dev_err(&client->dev, "failed to change sensor state\n"); | |
439 | } else if (state != STK3310_STATE_STANDBY) { | |
440 | /* Don't reset the 'enabled' flags if we're going in standby */ | |
441 | data->ps_enabled = !!(state & 0x01); | |
442 | data->als_enabled = !!(state & 0x02); | |
443 | } | |
444 | mutex_unlock(&data->lock); | |
445 | ||
446 | return ret; | |
447 | } | |
448 | ||
449 | static int stk3310_init(struct iio_dev *indio_dev) | |
450 | { | |
451 | int ret; | |
452 | int chipid; | |
453 | u8 state; | |
454 | struct stk3310_data *data = iio_priv(indio_dev); | |
455 | struct i2c_client *client = data->client; | |
456 | ||
457 | regmap_read(data->regmap, STK3310_REG_ID, &chipid); | |
458 | if (chipid != STK3310_CHIP_ID_VAL && | |
459 | chipid != STK3311_CHIP_ID_VAL) { | |
460 | dev_err(&client->dev, "invalid chip id: 0x%x\n", chipid); | |
461 | return -ENODEV; | |
462 | } | |
463 | ||
464 | state = STK3310_STATE_EN_ALS | STK3310_STATE_EN_PS; | |
465 | ret = stk3310_set_state(data, state); | |
3dd477ac | 466 | if (ret < 0) { |
be9e6229 | 467 | dev_err(&client->dev, "failed to enable sensor"); |
3dd477ac TB |
468 | return ret; |
469 | } | |
470 | ||
471 | /* Enable PS interrupts */ | |
472 | ret = regmap_field_write(data->reg_int_ps, STK3310_PSINT_EN); | |
473 | if (ret < 0) | |
474 | dev_err(&client->dev, "failed to enable interrupts!\n"); | |
475 | ||
476 | return ret; | |
477 | } | |
478 | ||
479 | static int stk3310_gpio_probe(struct i2c_client *client) | |
480 | { | |
481 | struct device *dev; | |
482 | struct gpio_desc *gpio; | |
483 | int ret; | |
484 | ||
485 | if (!client) | |
486 | return -EINVAL; | |
487 | ||
488 | dev = &client->dev; | |
489 | ||
490 | /* gpio interrupt pin */ | |
491 | gpio = devm_gpiod_get_index(dev, STK3310_GPIO, 0); | |
492 | if (IS_ERR(gpio)) { | |
493 | dev_err(dev, "acpi gpio get index failed\n"); | |
494 | return PTR_ERR(gpio); | |
495 | } | |
496 | ||
497 | ret = gpiod_direction_input(gpio); | |
498 | if (ret) | |
499 | return ret; | |
500 | ||
501 | ret = gpiod_to_irq(gpio); | |
502 | dev_dbg(dev, "GPIO resource, no:%d irq:%d\n", desc_to_gpio(gpio), ret); | |
be9e6229 TB |
503 | |
504 | return ret; | |
505 | } | |
506 | ||
507 | static bool stk3310_is_volatile_reg(struct device *dev, unsigned int reg) | |
508 | { | |
509 | switch (reg) { | |
510 | case STK3310_REG_ALS_DATA_MSB: | |
511 | case STK3310_REG_ALS_DATA_LSB: | |
512 | case STK3310_REG_PS_DATA_LSB: | |
513 | case STK3310_REG_PS_DATA_MSB: | |
3dd477ac | 514 | case STK3310_REG_FLAG: |
be9e6229 TB |
515 | return true; |
516 | default: | |
517 | return false; | |
518 | } | |
519 | } | |
520 | ||
521 | static struct regmap_config stk3310_regmap_config = { | |
522 | .name = STK3310_REGMAP_NAME, | |
523 | .reg_bits = 8, | |
524 | .val_bits = 8, | |
525 | .max_register = STK3310_MAX_REG, | |
526 | .cache_type = REGCACHE_RBTREE, | |
527 | .volatile_reg = stk3310_is_volatile_reg, | |
528 | }; | |
529 | ||
530 | static int stk3310_regmap_init(struct stk3310_data *data) | |
531 | { | |
532 | struct regmap *regmap; | |
533 | struct i2c_client *client; | |
534 | ||
535 | client = data->client; | |
536 | regmap = devm_regmap_init_i2c(client, &stk3310_regmap_config); | |
537 | if (IS_ERR(regmap)) { | |
538 | dev_err(&client->dev, "regmap initialization failed.\n"); | |
539 | return PTR_ERR(regmap); | |
540 | } | |
541 | data->regmap = regmap; | |
542 | ||
543 | STK3310_REGFIELD(state); | |
544 | STK3310_REGFIELD(als_gain); | |
545 | STK3310_REGFIELD(ps_gain); | |
546 | STK3310_REGFIELD(als_it); | |
547 | STK3310_REGFIELD(ps_it); | |
3dd477ac TB |
548 | STK3310_REGFIELD(int_ps); |
549 | STK3310_REGFIELD(flag_psint); | |
550 | STK3310_REGFIELD(flag_nf); | |
be9e6229 TB |
551 | |
552 | return 0; | |
553 | } | |
554 | ||
3dd477ac TB |
555 | static irqreturn_t stk3310_irq_handler(int irq, void *private) |
556 | { | |
557 | struct iio_dev *indio_dev = private; | |
558 | struct stk3310_data *data = iio_priv(indio_dev); | |
559 | ||
560 | data->timestamp = iio_get_time_ns(); | |
561 | ||
562 | return IRQ_WAKE_THREAD; | |
563 | } | |
564 | ||
565 | static irqreturn_t stk3310_irq_event_handler(int irq, void *private) | |
566 | { | |
567 | int ret; | |
568 | unsigned int dir; | |
569 | u64 event; | |
570 | ||
571 | struct iio_dev *indio_dev = private; | |
572 | struct stk3310_data *data = iio_priv(indio_dev); | |
573 | ||
574 | /* Read FLAG_NF to figure out what threshold has been met. */ | |
575 | mutex_lock(&data->lock); | |
576 | ret = regmap_field_read(data->reg_flag_nf, &dir); | |
577 | if (ret < 0) { | |
578 | dev_err(&data->client->dev, "register read failed\n"); | |
579 | mutex_unlock(&data->lock); | |
580 | return ret; | |
581 | } | |
582 | event = IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, 1, | |
583 | IIO_EV_TYPE_THRESH, | |
584 | (dir ? IIO_EV_DIR_RISING : | |
585 | IIO_EV_DIR_FALLING)); | |
586 | iio_push_event(indio_dev, event, data->timestamp); | |
587 | ||
588 | /* Reset the interrupt flag */ | |
589 | ret = regmap_field_write(data->reg_flag_psint, 0); | |
590 | if (ret < 0) | |
591 | dev_err(&data->client->dev, "failed to reset interrupts\n"); | |
592 | mutex_unlock(&data->lock); | |
593 | ||
594 | return IRQ_HANDLED; | |
595 | } | |
596 | ||
be9e6229 TB |
597 | static int stk3310_probe(struct i2c_client *client, |
598 | const struct i2c_device_id *id) | |
599 | { | |
600 | int ret; | |
601 | struct iio_dev *indio_dev; | |
602 | struct stk3310_data *data; | |
603 | ||
604 | indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); | |
605 | if (!indio_dev) { | |
606 | dev_err(&client->dev, "iio allocation failed!\n"); | |
607 | return -ENOMEM; | |
608 | } | |
609 | ||
610 | data = iio_priv(indio_dev); | |
611 | data->client = client; | |
612 | i2c_set_clientdata(client, indio_dev); | |
613 | mutex_init(&data->lock); | |
614 | ||
615 | ret = stk3310_regmap_init(data); | |
616 | if (ret < 0) | |
617 | return ret; | |
618 | ||
619 | indio_dev->dev.parent = &client->dev; | |
620 | indio_dev->info = &stk3310_info; | |
621 | indio_dev->name = STK3310_DRIVER_NAME; | |
622 | indio_dev->modes = INDIO_DIRECT_MODE; | |
623 | indio_dev->channels = stk3310_channels; | |
624 | indio_dev->num_channels = ARRAY_SIZE(stk3310_channels); | |
625 | ||
626 | ret = stk3310_init(indio_dev); | |
627 | if (ret < 0) | |
628 | return ret; | |
629 | ||
630 | ret = iio_device_register(indio_dev); | |
631 | if (ret < 0) { | |
632 | dev_err(&client->dev, "device_register failed\n"); | |
633 | stk3310_set_state(data, STK3310_STATE_STANDBY); | |
634 | } | |
635 | ||
3dd477ac TB |
636 | if (client->irq <= 0) |
637 | client->irq = stk3310_gpio_probe(client); | |
638 | ||
639 | if (client->irq >= 0) { | |
640 | ret = devm_request_threaded_irq(&client->dev, client->irq, | |
641 | stk3310_irq_handler, | |
642 | stk3310_irq_event_handler, | |
643 | IRQF_TRIGGER_FALLING | | |
644 | IRQF_ONESHOT, | |
645 | STK3310_EVENT, indio_dev); | |
646 | if (ret < 0) | |
647 | dev_err(&client->dev, "request irq %d failed\n", | |
648 | client->irq); | |
649 | } | |
650 | ||
be9e6229 TB |
651 | return ret; |
652 | } | |
653 | ||
654 | static int stk3310_remove(struct i2c_client *client) | |
655 | { | |
656 | struct iio_dev *indio_dev = i2c_get_clientdata(client); | |
657 | ||
658 | iio_device_unregister(indio_dev); | |
659 | return stk3310_set_state(iio_priv(indio_dev), STK3310_STATE_STANDBY); | |
660 | } | |
661 | ||
662 | #ifdef CONFIG_PM_SLEEP | |
663 | static int stk3310_suspend(struct device *dev) | |
664 | { | |
665 | struct stk3310_data *data; | |
666 | ||
667 | data = iio_priv(i2c_get_clientdata(to_i2c_client(dev))); | |
668 | ||
669 | return stk3310_set_state(data, STK3310_STATE_STANDBY); | |
670 | } | |
671 | ||
672 | static int stk3310_resume(struct device *dev) | |
673 | { | |
674 | int state = 0; | |
675 | struct stk3310_data *data; | |
676 | ||
677 | data = iio_priv(i2c_get_clientdata(to_i2c_client(dev))); | |
678 | if (data->ps_enabled) | |
679 | state |= STK3310_STATE_EN_PS; | |
680 | if (data->als_enabled) | |
681 | state |= STK3310_STATE_EN_ALS; | |
682 | ||
683 | return stk3310_set_state(data, state); | |
684 | } | |
685 | ||
686 | static SIMPLE_DEV_PM_OPS(stk3310_pm_ops, stk3310_suspend, stk3310_resume); | |
687 | ||
688 | #define STK3310_PM_OPS (&stk3310_pm_ops) | |
689 | #else | |
690 | #define STK3310_PM_OPS NULL | |
691 | #endif | |
692 | ||
693 | static const struct i2c_device_id stk3310_i2c_id[] = { | |
694 | {"STK3310", 0}, | |
695 | {"STK3311", 0}, | |
696 | {} | |
697 | }; | |
698 | ||
699 | static const struct acpi_device_id stk3310_acpi_id[] = { | |
700 | {"STK3310", 0}, | |
701 | {"STK3311", 0}, | |
702 | {} | |
703 | }; | |
704 | ||
705 | MODULE_DEVICE_TABLE(acpi, stk3310_acpi_id); | |
706 | ||
707 | static struct i2c_driver stk3310_driver = { | |
708 | .driver = { | |
709 | .name = "stk3310", | |
710 | .pm = STK3310_PM_OPS, | |
711 | .acpi_match_table = ACPI_PTR(stk3310_acpi_id), | |
712 | }, | |
713 | .probe = stk3310_probe, | |
714 | .remove = stk3310_remove, | |
715 | .id_table = stk3310_i2c_id, | |
716 | }; | |
717 | ||
718 | module_i2c_driver(stk3310_driver); | |
719 | ||
720 | MODULE_AUTHOR("Tiberiu Breana <tiberiu.a.breana@intel.com>"); | |
721 | MODULE_DESCRIPTION("STK3310 Ambient Light and Proximity Sensor driver"); | |
722 | MODULE_LICENSE("GPL v2"); |