1 // SPDX-License-Identifier: GPL-2.0+
3 * Support for ON Semiconductor NOA1305 ambient light sensor
5 * Copyright (C) 2016 Emcraft Systems
6 * Copyright (C) 2019 Collabora Ltd.
9 #include <linux/delay.h>
10 #include <linux/err.h>
11 #include <linux/i2c.h>
12 #include <linux/iio/iio.h>
13 #include <linux/iio/sysfs.h>
14 #include <linux/module.h>
15 #include <linux/regmap.h>
16 #include <linux/regulator/consumer.h>
18 #define NOA1305_REG_POWER_CONTROL 0x0
19 #define NOA1305_POWER_CONTROL_DOWN 0x00
20 #define NOA1305_POWER_CONTROL_ON 0x08
21 #define NOA1305_REG_RESET 0x1
22 #define NOA1305_RESET_RESET 0x10
23 #define NOA1305_REG_INTEGRATION_TIME 0x2
24 #define NOA1305_INTEGR_TIME_800MS 0x00
25 #define NOA1305_INTEGR_TIME_400MS 0x01
26 #define NOA1305_INTEGR_TIME_200MS 0x02
27 #define NOA1305_INTEGR_TIME_100MS 0x03
28 #define NOA1305_INTEGR_TIME_50MS 0x04
29 #define NOA1305_INTEGR_TIME_25MS 0x05
30 #define NOA1305_INTEGR_TIME_12_5MS 0x06
31 #define NOA1305_INTEGR_TIME_6_25MS 0x07
32 #define NOA1305_REG_INT_SELECT 0x3
33 #define NOA1305_INT_SEL_ACTIVE_HIGH 0x01
34 #define NOA1305_INT_SEL_ACTIVE_LOW 0x02
35 #define NOA1305_INT_SEL_INACTIVE 0x03
36 #define NOA1305_REG_INT_THRESH_LSB 0x4
37 #define NOA1305_REG_INT_THRESH_MSB 0x5
38 #define NOA1305_REG_ALS_DATA_LSB 0x6
39 #define NOA1305_REG_ALS_DATA_MSB 0x7
40 #define NOA1305_REG_DEVICE_ID_LSB 0x8
41 #define NOA1305_REG_DEVICE_ID_MSB 0x9
43 #define NOA1305_DEVICE_ID 0x0519
44 #define NOA1305_DRIVER_NAME "noa1305"
47 struct i2c_client
*client
;
48 struct regmap
*regmap
;
49 struct regulator
*vin_reg
;
52 static int noa1305_measure(struct noa1305_priv
*priv
)
57 ret
= regmap_bulk_read(priv
->regmap
, NOA1305_REG_ALS_DATA_LSB
, &data
,
62 return le16_to_cpu(data
);
65 static int noa1305_scale(struct noa1305_priv
*priv
, int *val
, int *val2
)
70 ret
= regmap_read(priv
->regmap
, NOA1305_REG_INTEGRATION_TIME
, &data
);
75 * Lux = count / (<Integration Constant> * <Integration Time>)
77 * Integration Constant = 7.7
78 * Integration Time in Seconds
81 case NOA1305_INTEGR_TIME_800MS
:
85 case NOA1305_INTEGR_TIME_400MS
:
89 case NOA1305_INTEGR_TIME_200MS
:
93 case NOA1305_INTEGR_TIME_100MS
:
97 case NOA1305_INTEGR_TIME_50MS
:
101 case NOA1305_INTEGR_TIME_25MS
:
105 case NOA1305_INTEGR_TIME_12_5MS
:
109 case NOA1305_INTEGR_TIME_6_25MS
:
117 return IIO_VAL_FRACTIONAL
;
120 static const struct iio_chan_spec noa1305_channels
[] = {
123 .info_mask_separate
= BIT(IIO_CHAN_INFO_RAW
),
124 .info_mask_shared_by_type
= BIT(IIO_CHAN_INFO_SCALE
),
128 static int noa1305_read_raw(struct iio_dev
*indio_dev
,
129 struct iio_chan_spec
const *chan
,
130 int *val
, int *val2
, long mask
)
133 struct noa1305_priv
*priv
= iio_priv(indio_dev
);
136 case IIO_CHAN_INFO_RAW
:
137 switch (chan
->type
) {
139 ret
= noa1305_measure(priv
);
148 case IIO_CHAN_INFO_SCALE
:
149 switch (chan
->type
) {
151 return noa1305_scale(priv
, val
, val2
);
163 static const struct iio_info noa1305_info
= {
164 .read_raw
= noa1305_read_raw
,
167 static bool noa1305_writable_reg(struct device
*dev
, unsigned int reg
)
170 case NOA1305_REG_POWER_CONTROL
:
171 case NOA1305_REG_RESET
:
172 case NOA1305_REG_INTEGRATION_TIME
:
173 case NOA1305_REG_INT_SELECT
:
174 case NOA1305_REG_INT_THRESH_LSB
:
175 case NOA1305_REG_INT_THRESH_MSB
:
182 static const struct regmap_config noa1305_regmap_config
= {
183 .name
= NOA1305_DRIVER_NAME
,
186 .max_register
= NOA1305_REG_DEVICE_ID_MSB
,
187 .writeable_reg
= noa1305_writable_reg
,
190 static void noa1305_reg_remove(void *data
)
192 struct noa1305_priv
*priv
= data
;
194 regulator_disable(priv
->vin_reg
);
197 static int noa1305_probe(struct i2c_client
*client
,
198 const struct i2c_device_id
*id
)
200 struct noa1305_priv
*priv
;
201 struct iio_dev
*indio_dev
;
202 struct regmap
*regmap
;
207 indio_dev
= devm_iio_device_alloc(&client
->dev
, sizeof(*priv
));
211 regmap
= devm_regmap_init_i2c(client
, &noa1305_regmap_config
);
212 if (IS_ERR(regmap
)) {
213 dev_err(&client
->dev
, "Regmap initialization failed.\n");
214 return PTR_ERR(regmap
);
217 priv
= iio_priv(indio_dev
);
219 priv
->vin_reg
= devm_regulator_get(&client
->dev
, "vin");
220 if (IS_ERR(priv
->vin_reg
)) {
221 dev_err(&client
->dev
, "get regulator vin failed\n");
222 return PTR_ERR(priv
->vin_reg
);
225 ret
= regulator_enable(priv
->vin_reg
);
227 dev_err(&client
->dev
, "enable regulator vin failed\n");
231 ret
= devm_add_action_or_reset(&client
->dev
, noa1305_reg_remove
, priv
);
233 dev_err(&client
->dev
, "addition of devm action failed\n");
237 i2c_set_clientdata(client
, indio_dev
);
238 priv
->client
= client
;
239 priv
->regmap
= regmap
;
241 ret
= regmap_bulk_read(regmap
, NOA1305_REG_DEVICE_ID_LSB
, &data
, 2);
243 dev_err(&client
->dev
, "ID reading failed: %d\n", ret
);
247 dev_id
= le16_to_cpu(data
);
248 if (dev_id
!= NOA1305_DEVICE_ID
) {
249 dev_err(&client
->dev
, "Unknown device ID: 0x%x\n", dev_id
);
253 ret
= regmap_write(regmap
, NOA1305_REG_POWER_CONTROL
,
254 NOA1305_POWER_CONTROL_ON
);
256 dev_err(&client
->dev
, "Enabling power control failed\n");
260 ret
= regmap_write(regmap
, NOA1305_REG_RESET
, NOA1305_RESET_RESET
);
262 dev_err(&client
->dev
, "Device reset failed\n");
266 ret
= regmap_write(regmap
, NOA1305_REG_INTEGRATION_TIME
,
267 NOA1305_INTEGR_TIME_800MS
);
269 dev_err(&client
->dev
, "Setting integration time failed\n");
273 indio_dev
->dev
.parent
= &client
->dev
;
274 indio_dev
->info
= &noa1305_info
;
275 indio_dev
->channels
= noa1305_channels
;
276 indio_dev
->num_channels
= ARRAY_SIZE(noa1305_channels
);
277 indio_dev
->name
= NOA1305_DRIVER_NAME
;
278 indio_dev
->modes
= INDIO_DIRECT_MODE
;
280 ret
= devm_iio_device_register(&client
->dev
, indio_dev
);
282 dev_err(&client
->dev
, "registering device failed\n");
287 static const struct of_device_id noa1305_of_match
[] = {
288 { .compatible
= "onnn,noa1305" },
291 MODULE_DEVICE_TABLE(of
, noa1305_of_match
);
293 static const struct i2c_device_id noa1305_ids
[] = {
297 MODULE_DEVICE_TABLE(i2c
, noa1305_ids
);
299 static struct i2c_driver noa1305_driver
= {
301 .name
= NOA1305_DRIVER_NAME
,
302 .of_match_table
= noa1305_of_match
,
304 .probe
= noa1305_probe
,
305 .id_table
= noa1305_ids
,
308 module_i2c_driver(noa1305_driver
);
310 MODULE_AUTHOR("Sergei Miroshnichenko <sergeimir@emcraft.com>");
311 MODULE_AUTHOR("Martyn Welch <martyn.welch@collabora.com");
312 MODULE_DESCRIPTION("ON Semiconductor NOA1305 ambient light sensor");
313 MODULE_LICENSE("GPL");