2 * Copyright (c) 2015 Intel Corporation
4 * Driver for UPISEMI us5182d Proximity and Ambient Light Sensor.
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License version 2 as published by
8 * the Free Software Foundation.
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * To do: Interrupt support.
18 #include <linux/kernel.h>
19 #include <linux/module.h>
20 #include <linux/acpi.h>
21 #include <linux/delay.h>
22 #include <linux/i2c.h>
23 #include <linux/iio/iio.h>
24 #include <linux/iio/sysfs.h>
25 #include <linux/mutex.h>
27 #define US5182D_REG_CFG0 0x00
28 #define US5182D_CFG0_ONESHOT_EN BIT(6)
29 #define US5182D_CFG0_SHUTDOWN_EN BIT(7)
30 #define US5182D_CFG0_WORD_ENABLE BIT(0)
32 #define US5182D_REG_CFG1 0x01
33 #define US5182D_CFG1_ALS_RES16 BIT(4)
34 #define US5182D_CFG1_AGAIN_DEFAULT 0x00
36 #define US5182D_REG_CFG2 0x02
37 #define US5182D_CFG2_PX_RES16 BIT(4)
38 #define US5182D_CFG2_PXGAIN_DEFAULT BIT(2)
40 #define US5182D_REG_CFG3 0x03
41 #define US5182D_CFG3_LED_CURRENT100 (BIT(4) | BIT(5))
43 #define US5182D_REG_CFG4 0x10
46 * Registers for tuning the auto dark current cancelling feature.
47 * DARK_TH(reg 0x27,0x28) - threshold (counts) for auto dark cancelling.
48 * when ALS > DARK_TH --> ALS_Code = ALS - Upper(0x2A) * Dark
49 * when ALS < DARK_TH --> ALS_Code = ALS - Lower(0x29) * Dark
51 #define US5182D_REG_UDARK_TH 0x27
52 #define US5182D_REG_DARK_AUTO_EN 0x2b
53 #define US5182D_REG_AUTO_LDARK_GAIN 0x29
54 #define US5182D_REG_AUTO_HDARK_GAIN 0x2a
56 #define US5182D_OPMODE_ALS 0x01
57 #define US5182D_OPMODE_PX 0x02
58 #define US5182D_OPMODE_SHIFT 4
60 #define US5182D_REG_DARK_AUTO_EN_DEFAULT 0x80
61 #define US5182D_REG_AUTO_LDARK_GAIN_DEFAULT 0x16
62 #define US5182D_REG_AUTO_HDARK_GAIN_DEFAULT 0x00
64 #define US5182D_REG_ADL 0x0c
65 #define US5182D_REG_PDL 0x0e
67 #define US5182D_REG_MODE_STORE 0x21
68 #define US5182D_STORE_MODE 0x01
70 #define US5182D_REG_CHIPID 0xb2
72 #define US5182D_OPMODE_MASK GENMASK(5, 4)
73 #define US5182D_AGAIN_MASK 0x07
74 #define US5182D_RESET_CHIP 0x01
76 #define US5182D_CHIPID 0x26
77 #define US5182D_DRV_NAME "us5182d"
79 #define US5182D_GA_RESOLUTION 1000
81 #define US5182D_READ_BYTE 1
82 #define US5182D_READ_WORD 2
83 #define US5182D_OPSTORE_SLEEP_TIME 20 /* ms */
85 /* Available ranges: [12354, 7065, 3998, 2202, 1285, 498, 256, 138] lux */
86 static const int us5182d_scales
[] = {188500, 107800, 61000, 33600, 19600, 7600,
90 * Experimental thresholds that work with US5182D sensor on evaluation board
91 * roughly between 12-32 lux
93 static u16 us5182d_dark_ths_vals
[] = {170, 200, 512, 512, 800, 2000, 4000,
102 struct us5182d_data
{
103 struct i2c_client
*client
;
106 /* Glass attenuation factor */
109 /* Dark gain tuning */
112 u16
*us5182d_dark_ths
;
117 static IIO_CONST_ATTR(in_illuminance_scale_available
,
118 "0.0021 0.0039 0.0076 0.0196 0.0336 0.061 0.1078 0.1885");
120 static struct attribute
*us5182d_attrs
[] = {
121 &iio_const_attr_in_illuminance_scale_available
.dev_attr
.attr
,
125 static const struct attribute_group us5182d_attr_group
= {
126 .attrs
= us5182d_attrs
,
129 static const struct {
132 } us5182d_regvals
[] = {
133 {US5182D_REG_CFG0
, (US5182D_CFG0_SHUTDOWN_EN
|
134 US5182D_CFG0_WORD_ENABLE
)},
135 {US5182D_REG_CFG1
, US5182D_CFG1_ALS_RES16
},
136 {US5182D_REG_CFG2
, (US5182D_CFG2_PX_RES16
|
137 US5182D_CFG2_PXGAIN_DEFAULT
)},
138 {US5182D_REG_CFG3
, US5182D_CFG3_LED_CURRENT100
},
139 {US5182D_REG_MODE_STORE
, US5182D_STORE_MODE
},
140 {US5182D_REG_CFG4
, 0x00},
143 static const struct iio_chan_spec us5182d_channels
[] = {
146 .info_mask_separate
= BIT(IIO_CHAN_INFO_RAW
) |
147 BIT(IIO_CHAN_INFO_SCALE
),
150 .type
= IIO_PROXIMITY
,
151 .info_mask_separate
= BIT(IIO_CHAN_INFO_RAW
),
155 static int us5182d_get_als(struct us5182d_data
*data
)
158 unsigned long result
;
160 ret
= i2c_smbus_read_word_data(data
->client
,
165 result
= ret
* data
->ga
/ US5182D_GA_RESOLUTION
;
172 static int us5182d_set_opmode(struct us5182d_data
*data
, u8 mode
)
176 ret
= i2c_smbus_read_byte_data(data
->client
, US5182D_REG_CFG0
);
181 * In oneshot mode the chip will power itself down after taking the
182 * required measurement.
184 ret
= ret
| US5182D_CFG0_ONESHOT_EN
;
187 ret
= ret
& ~US5182D_OPMODE_MASK
;
188 ret
= ret
| (mode
<< US5182D_OPMODE_SHIFT
);
191 * After updating the operating mode, the chip requires that
192 * the operation is stored, by writing 1 in the STORE_MODE
193 * register (auto-clearing).
195 ret
= i2c_smbus_write_byte_data(data
->client
, US5182D_REG_CFG0
, ret
);
199 if (mode
== data
->opmode
)
202 ret
= i2c_smbus_write_byte_data(data
->client
, US5182D_REG_MODE_STORE
,
208 msleep(US5182D_OPSTORE_SLEEP_TIME
);
213 static int us5182d_read_raw(struct iio_dev
*indio_dev
,
214 struct iio_chan_spec
const *chan
, int *val
,
215 int *val2
, long mask
)
217 struct us5182d_data
*data
= iio_priv(indio_dev
);
221 case IIO_CHAN_INFO_RAW
:
222 switch (chan
->type
) {
224 mutex_lock(&data
->lock
);
225 ret
= us5182d_set_opmode(data
, US5182D_OPMODE_ALS
);
229 ret
= us5182d_get_als(data
);
232 mutex_unlock(&data
->lock
);
236 mutex_lock(&data
->lock
);
237 ret
= us5182d_set_opmode(data
, US5182D_OPMODE_PX
);
241 ret
= i2c_smbus_read_word_data(data
->client
,
245 mutex_unlock(&data
->lock
);
252 case IIO_CHAN_INFO_SCALE
:
253 ret
= i2c_smbus_read_byte_data(data
->client
, US5182D_REG_CFG1
);
258 *val2
= us5182d_scales
[ret
& US5182D_AGAIN_MASK
];
260 return IIO_VAL_INT_PLUS_MICRO
;
267 mutex_unlock(&data
->lock
);
272 * us5182d_update_dark_th - update Darh_Th registers
273 * @data us5182d_data structure
274 * @index index in us5182d_dark_ths array to use for the updated value
276 * Function needs to be called with a lock held because it needs two i2c write
277 * byte operations as these registers (0x27 0x28) don't work in word mode
280 static int us5182d_update_dark_th(struct us5182d_data
*data
, int index
)
282 __be16 dark_th
= cpu_to_be16(data
->us5182d_dark_ths
[index
]);
285 ret
= i2c_smbus_write_byte_data(data
->client
, US5182D_REG_UDARK_TH
,
286 ((u8
*)&dark_th
)[0]);
290 return i2c_smbus_write_byte_data(data
->client
, US5182D_REG_UDARK_TH
+ 1,
291 ((u8
*)&dark_th
)[1]);
295 * us5182d_apply_scale - update the ALS scale
296 * @data us5182d_data structure
297 * @index index in us5182d_scales array to use for the updated value
299 * Function needs to be called with a lock held as we're having more than one
302 static int us5182d_apply_scale(struct us5182d_data
*data
, int index
)
306 ret
= i2c_smbus_read_byte_data(data
->client
, US5182D_REG_CFG1
);
310 ret
= ret
& (~US5182D_AGAIN_MASK
);
313 ret
= i2c_smbus_write_byte_data(data
->client
, US5182D_REG_CFG1
, ret
);
317 return us5182d_update_dark_th(data
, index
);
320 static int us5182d_write_raw(struct iio_dev
*indio_dev
,
321 struct iio_chan_spec
const *chan
, int val
,
324 struct us5182d_data
*data
= iio_priv(indio_dev
);
328 case IIO_CHAN_INFO_SCALE
:
331 for (i
= 0; i
< ARRAY_SIZE(us5182d_scales
); i
++)
332 if (val2
== us5182d_scales
[i
]) {
333 mutex_lock(&data
->lock
);
334 ret
= us5182d_apply_scale(data
, i
);
335 mutex_unlock(&data
->lock
);
346 static const struct iio_info us5182d_info
= {
347 .driver_module
= THIS_MODULE
,
348 .read_raw
= us5182d_read_raw
,
349 .write_raw
= us5182d_write_raw
,
350 .attrs
= &us5182d_attr_group
,
353 static int us5182d_reset(struct iio_dev
*indio_dev
)
355 struct us5182d_data
*data
= iio_priv(indio_dev
);
357 return i2c_smbus_write_byte_data(data
->client
, US5182D_REG_CFG3
,
361 static int us5182d_init(struct iio_dev
*indio_dev
)
363 struct us5182d_data
*data
= iio_priv(indio_dev
);
366 ret
= us5182d_reset(indio_dev
);
371 for (i
= 0; i
< ARRAY_SIZE(us5182d_regvals
); i
++) {
372 ret
= i2c_smbus_write_byte_data(data
->client
,
373 us5182d_regvals
[i
].reg
,
374 us5182d_regvals
[i
].val
);
382 static void us5182d_get_platform_data(struct iio_dev
*indio_dev
)
384 struct us5182d_data
*data
= iio_priv(indio_dev
);
386 if (device_property_read_u32(&data
->client
->dev
, "upisemi,glass-coef",
388 data
->ga
= US5182D_GA_RESOLUTION
;
389 if (device_property_read_u16_array(&data
->client
->dev
,
391 data
->us5182d_dark_ths
,
392 ARRAY_SIZE(us5182d_dark_ths_vals
)))
393 data
->us5182d_dark_ths
= us5182d_dark_ths_vals
;
394 if (device_property_read_u8(&data
->client
->dev
,
395 "upisemi,upper-dark-gain",
396 &data
->upper_dark_gain
))
397 data
->upper_dark_gain
= US5182D_REG_AUTO_HDARK_GAIN_DEFAULT
;
398 if (device_property_read_u8(&data
->client
->dev
,
399 "upisemi,lower-dark-gain",
400 &data
->lower_dark_gain
))
401 data
->lower_dark_gain
= US5182D_REG_AUTO_LDARK_GAIN_DEFAULT
;
404 static int us5182d_dark_gain_config(struct iio_dev
*indio_dev
)
406 struct us5182d_data
*data
= iio_priv(indio_dev
);
409 ret
= us5182d_update_dark_th(data
, US5182D_CFG1_AGAIN_DEFAULT
);
413 ret
= i2c_smbus_write_byte_data(data
->client
,
414 US5182D_REG_AUTO_LDARK_GAIN
,
415 data
->lower_dark_gain
);
419 ret
= i2c_smbus_write_byte_data(data
->client
,
420 US5182D_REG_AUTO_HDARK_GAIN
,
421 data
->upper_dark_gain
);
425 return i2c_smbus_write_byte_data(data
->client
, US5182D_REG_DARK_AUTO_EN
,
426 US5182D_REG_DARK_AUTO_EN_DEFAULT
);
429 static int us5182d_probe(struct i2c_client
*client
,
430 const struct i2c_device_id
*id
)
432 struct us5182d_data
*data
;
433 struct iio_dev
*indio_dev
;
436 indio_dev
= devm_iio_device_alloc(&client
->dev
, sizeof(*data
));
440 data
= iio_priv(indio_dev
);
441 i2c_set_clientdata(client
, indio_dev
);
442 data
->client
= client
;
444 mutex_init(&data
->lock
);
446 indio_dev
->dev
.parent
= &client
->dev
;
447 indio_dev
->info
= &us5182d_info
;
448 indio_dev
->name
= US5182D_DRV_NAME
;
449 indio_dev
->channels
= us5182d_channels
;
450 indio_dev
->num_channels
= ARRAY_SIZE(us5182d_channels
);
451 indio_dev
->modes
= INDIO_DIRECT_MODE
;
453 ret
= i2c_smbus_read_byte_data(data
->client
, US5182D_REG_CHIPID
);
454 if (ret
!= US5182D_CHIPID
) {
455 dev_err(&data
->client
->dev
,
456 "Failed to detect US5182 light chip\n");
457 return (ret
< 0) ? ret
: -ENODEV
;
460 us5182d_get_platform_data(indio_dev
);
461 ret
= us5182d_init(indio_dev
);
465 ret
= us5182d_dark_gain_config(indio_dev
);
469 return iio_device_register(indio_dev
);
472 static int us5182d_remove(struct i2c_client
*client
)
474 iio_device_unregister(i2c_get_clientdata(client
));
475 return i2c_smbus_write_byte_data(client
, US5182D_REG_CFG0
,
476 US5182D_CFG0_SHUTDOWN_EN
);
479 static const struct acpi_device_id us5182d_acpi_match
[] = {
484 MODULE_DEVICE_TABLE(acpi
, us5182d_acpi_match
);
486 static const struct i2c_device_id us5182d_id
[] = {
491 MODULE_DEVICE_TABLE(i2c
, us5182d_id
);
493 static struct i2c_driver us5182d_driver
= {
495 .name
= US5182D_DRV_NAME
,
496 .acpi_match_table
= ACPI_PTR(us5182d_acpi_match
),
498 .probe
= us5182d_probe
,
499 .remove
= us5182d_remove
,
500 .id_table
= us5182d_id
,
503 module_i2c_driver(us5182d_driver
);
505 MODULE_AUTHOR("Adriana Reus <adriana.reus@intel.com>");
506 MODULE_DESCRIPTION("Driver for us5182d Proximity and Light Sensor");
507 MODULE_LICENSE("GPL v2");