1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * zopt2201.c - Support for IDT ZOPT2201 ambient light and UV B sensor
4 *
5 * Copyright 2017 Peter Meerwald-Stadler <pmeerw@pmeerw.net>
6 *
7 * Datasheet: https://www.idt.com/document/dst/zopt2201-datasheet
8 * 7-bit I2C slave addresses 0x53 (default) or 0x52 (programmed)
9 *
10 * TODO: interrupt support, ALS/UVB raw mode
11 */
12
13#include <linux/module.h>
14#include <linux/i2c.h>
15#include <linux/mutex.h>
16#include <linux/err.h>
17#include <linux/delay.h>
18
19#include <linux/iio/iio.h>
20#include <linux/iio/sysfs.h>
21
22#include <asm/unaligned.h>
23
24#define ZOPT2201_DRV_NAME "zopt2201"
25
26/* Registers */
27#define ZOPT2201_MAIN_CTRL		0x00
28#define ZOPT2201_LS_MEAS_RATE		0x04
29#define ZOPT2201_LS_GAIN		0x05
30#define ZOPT2201_PART_ID		0x06
31#define ZOPT2201_MAIN_STATUS		0x07
32#define ZOPT2201_ALS_DATA		0x0d /* LSB first, 13 to 20 bits */
33#define ZOPT2201_UVB_DATA		0x10 /* LSB first, 13 to 20 bits */
34#define ZOPT2201_UV_COMP_DATA		0x13 /* LSB first, 13 to 20 bits */
35#define ZOPT2201_COMP_DATA		0x16 /* LSB first, 13 to 20 bits */
36#define ZOPT2201_INT_CFG		0x19
37#define ZOPT2201_INT_PST		0x1a
38
39#define ZOPT2201_MAIN_CTRL_LS_MODE	BIT(3) /* 0 .. ALS, 1 .. UV B */
40#define ZOPT2201_MAIN_CTRL_LS_EN	BIT(1)
41
42/* Values for ZOPT2201_LS_MEAS_RATE resolution / bit width */
43#define ZOPT2201_MEAS_RES_20BIT		0 /* takes 400 ms */
44#define ZOPT2201_MEAS_RES_19BIT		1 /* takes 200 ms */
45#define ZOPT2201_MEAS_RES_18BIT		2 /* takes 100 ms, default */
46#define ZOPT2201_MEAS_RES_17BIT		3 /* takes 50 ms */
47#define ZOPT2201_MEAS_RES_16BIT		4 /* takes 25 ms */
48#define ZOPT2201_MEAS_RES_13BIT		5 /* takes 3.125 ms */
49#define ZOPT2201_MEAS_RES_SHIFT		4
50
51/* Values for ZOPT2201_LS_MEAS_RATE measurement rate */
52#define ZOPT2201_MEAS_FREQ_25MS		0
53#define ZOPT2201_MEAS_FREQ_50MS		1
54#define ZOPT2201_MEAS_FREQ_100MS	2 /* default */
55#define ZOPT2201_MEAS_FREQ_200MS	3
56#define ZOPT2201_MEAS_FREQ_500MS	4
57#define ZOPT2201_MEAS_FREQ_1000MS	5
58#define ZOPT2201_MEAS_FREQ_2000MS	6
59
60/* Values for ZOPT2201_LS_GAIN */
61#define ZOPT2201_LS_GAIN_1		0
62#define ZOPT2201_LS_GAIN_3		1
63#define ZOPT2201_LS_GAIN_6		2
64#define ZOPT2201_LS_GAIN_9		3
65#define ZOPT2201_LS_GAIN_18		4
66
67/* Values for ZOPT2201_MAIN_STATUS */
68#define ZOPT2201_MAIN_STATUS_POWERON	BIT(5)
69#define ZOPT2201_MAIN_STATUS_INT	BIT(4)
70#define ZOPT2201_MAIN_STATUS_DRDY	BIT(3)
71
72#define ZOPT2201_PART_NUMBER		0xb2
73
74struct zopt2201_data {
75	struct i2c_client *client;
76	struct mutex lock;
77	u8 gain;
78	u8 res;
79	u8 rate;
80};
81
82static const struct {
83	unsigned int gain; /* gain factor */
84	unsigned int scale; /* micro lux per count */
85} zopt2201_gain_als[] = {
86	{  1, 19200000 },
87	{  3,  6400000 },
88	{  6,  3200000 },
89	{  9,  2133333 },
90	{ 18,  1066666 },
91};
92
93static const struct {
94	unsigned int gain; /* gain factor */
95	unsigned int scale; /* micro W/m2 per count */
96} zopt2201_gain_uvb[] = {
97	{  1, 460800 },
98	{  3, 153600 },
99	{  6,  76800 },
100	{  9,  51200 },
101	{ 18,  25600 },
102};
103
104static const struct {
105	unsigned int bits; /* sensor resolution in bits */
106	unsigned long us; /* measurement time in micro seconds */
107} zopt2201_resolution[] = {
108	{ 20, 400000 },
109	{ 19, 200000 },
110	{ 18, 100000 },
111	{ 17,  50000 },
112	{ 16,  25000 },
113	{ 13,   3125 },
114};
115
116static const struct {
117	unsigned int scale, uscale; /* scale factor as integer + micro */
118	u8 gain; /* gain register value */
119	u8 res; /* resolution register value */
120} zopt2201_scale_als[] = {
121	{ 19, 200000, 0, 5 },
122	{  6, 400000, 1, 5 },
123	{  3, 200000, 2, 5 },
124	{  2, 400000, 0, 4 },
125	{  2, 133333, 3, 5 },
126	{  1, 200000, 0, 3 },
127	{  1,  66666, 4, 5 },
128	{  0, 800000, 1, 4 },
129	{  0, 600000, 0, 2 },
130	{  0, 400000, 2, 4 },
131	{  0, 300000, 0, 1 },
132	{  0, 266666, 3, 4 },
133	{  0, 200000, 2, 3 },
134	{  0, 150000, 0, 0 },
135	{  0, 133333, 4, 4 },
136	{  0, 100000, 2, 2 },
137	{  0,  66666, 4, 3 },
138	{  0,  50000, 2, 1 },
139	{  0,  33333, 4, 2 },
140	{  0,  25000, 2, 0 },
141	{  0,  16666, 4, 1 },
142	{  0,   8333, 4, 0 },
143};
144
145static const struct {
146	unsigned int scale, uscale; /* scale factor as integer + micro */
147	u8 gain; /* gain register value */
148	u8 res; /* resolution register value */
149} zopt2201_scale_uvb[] = {
150	{ 0, 460800, 0, 5 },
151	{ 0, 153600, 1, 5 },
152	{ 0,  76800, 2, 5 },
153	{ 0,  57600, 0, 4 },
154	{ 0,  51200, 3, 5 },
155	{ 0,  28800, 0, 3 },
156	{ 0,  25600, 4, 5 },
157	{ 0,  19200, 1, 4 },
158	{ 0,  14400, 0, 2 },
159	{ 0,   9600, 2, 4 },
160	{ 0,   7200, 0, 1 },
161	{ 0,   6400, 3, 4 },
162	{ 0,   4800, 2, 3 },
163	{ 0,   3600, 0, 0 },
164	{ 0,   3200, 4, 4 },
165	{ 0,   2400, 2, 2 },
166	{ 0,   1600, 4, 3 },
167	{ 0,   1200, 2, 1 },
168	{ 0,    800, 4, 2 },
169	{ 0,    600, 2, 0 },
170	{ 0,    400, 4, 1 },
171	{ 0,    200, 4, 0 },
172};
173
174static int zopt2201_enable_mode(struct zopt2201_data *data, bool uvb_mode)
175{
176	u8 out = ZOPT2201_MAIN_CTRL_LS_EN;
177
178	if (uvb_mode)
179		out |= ZOPT2201_MAIN_CTRL_LS_MODE;
180
181	return i2c_smbus_write_byte_data(data->client, ZOPT2201_MAIN_CTRL, out);
182}
183
184static int zopt2201_read(struct zopt2201_data *data, u8 reg)
185{
186	struct i2c_client *client = data->client;
187	int tries = 10;
188	u8 buf[3];
189	int ret;
190
191	mutex_lock(&data->lock);
192	ret = zopt2201_enable_mode(data, reg == ZOPT2201_UVB_DATA);
193	if (ret < 0)
194		goto fail;
195
196	while (tries--) {
197		unsigned long t = zopt2201_resolution[data->res].us;
198
199		if (t <= 20000)
200			usleep_range(t, t + 1000);
201		else
202			msleep(t / 1000);
203		ret = i2c_smbus_read_byte_data(client, ZOPT2201_MAIN_STATUS);
204		if (ret < 0)
205			goto fail;
206		if (ret & ZOPT2201_MAIN_STATUS_DRDY)
207			break;
208	}
209
210	if (tries < 0) {
211		ret = -ETIMEDOUT;
212		goto fail;
213	}
214
215	ret = i2c_smbus_read_i2c_block_data(client, reg, sizeof(buf), buf);
216	if (ret < 0)
217		goto fail;
218
219	ret = i2c_smbus_write_byte_data(client, ZOPT2201_MAIN_CTRL, 0x00);
220	if (ret < 0)
221		goto fail;
222	mutex_unlock(&data->lock);
223
224	return get_unaligned_le24(&buf[0]);
225
226fail:
227	mutex_unlock(&data->lock);
228	return ret;
229}
230
231static const struct iio_chan_spec zopt2201_channels[] = {
232	{
233		.type = IIO_LIGHT,
234		.address = ZOPT2201_ALS_DATA,
235		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
236				      BIT(IIO_CHAN_INFO_SCALE),
237		.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME),
238	},
239	{
240		.type = IIO_INTENSITY,
241		.modified = 1,
242		.channel2 = IIO_MOD_LIGHT_UV,
243		.address = ZOPT2201_UVB_DATA,
244		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
245				      BIT(IIO_CHAN_INFO_SCALE),
246		.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME),
247	},
248	{
249		.type = IIO_UVINDEX,
250		.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
251	},
252};
253
254static int zopt2201_read_raw(struct iio_dev *indio_dev,
255				struct iio_chan_spec const *chan,
256				int *val, int *val2, long mask)
257{
258	struct zopt2201_data *data = iio_priv(indio_dev);
259	u64 tmp;
260	int ret;
261
262	switch (mask) {
263	case IIO_CHAN_INFO_RAW:
264		ret = zopt2201_read(data, chan->address);
265		if (ret < 0)
266			return ret;
267		*val = ret;
268		return IIO_VAL_INT;
269	case IIO_CHAN_INFO_PROCESSED:
270		ret = zopt2201_read(data, ZOPT2201_UVB_DATA);
271		if (ret < 0)
272			return ret;
273		*val = ret * 18 *
274			(1 << (20 - zopt2201_resolution[data->res].bits)) /
275			zopt2201_gain_uvb[data->gain].gain;
276		return IIO_VAL_INT;
277	case IIO_CHAN_INFO_SCALE:
278		switch (chan->address) {
279		case ZOPT2201_ALS_DATA:
280			*val = zopt2201_gain_als[data->gain].scale;
281			break;
282		case ZOPT2201_UVB_DATA:
283			*val = zopt2201_gain_uvb[data->gain].scale;
284			break;
285		default:
286			return -EINVAL;
287		}
288
289		*val2 = 1000000;
290		*val2 *= (1 << (zopt2201_resolution[data->res].bits - 13));
291		tmp = div_s64(*val * 1000000ULL, *val2);
292		*val = div_s64_rem(tmp, 1000000, val2);
293
294		return IIO_VAL_INT_PLUS_MICRO;
295	case IIO_CHAN_INFO_INT_TIME:
296		*val = 0;
297		*val2 = zopt2201_resolution[data->res].us;
298		return IIO_VAL_INT_PLUS_MICRO;
299	default:
300		return -EINVAL;
301	}
302}
303
304static int zopt2201_set_resolution(struct zopt2201_data *data, u8 res)
305{
306	int ret;
307
308	ret = i2c_smbus_write_byte_data(data->client, ZOPT2201_LS_MEAS_RATE,
309					(res << ZOPT2201_MEAS_RES_SHIFT) |
310					data->rate);
311	if (ret < 0)
312		return ret;
313
314	data->res = res;
315
316	return 0;
317}
318
319static int zopt2201_write_resolution(struct zopt2201_data *data,
320				     int val, int val2)
321{
322	int i, ret;
323
324	if (val != 0)
325		return -EINVAL;
326
327	for (i = 0; i < ARRAY_SIZE(zopt2201_resolution); i++)
328		if (val2 == zopt2201_resolution[i].us) {
329			mutex_lock(&data->lock);
330			ret = zopt2201_set_resolution(data, i);
331			mutex_unlock(&data->lock);
332			return ret;
333		}
334
335	return -EINVAL;
336}
337
338static int zopt2201_set_gain(struct zopt2201_data *data, u8 gain)
339{
340	int ret;
341
342	ret = i2c_smbus_write_byte_data(data->client, ZOPT2201_LS_GAIN, gain);
343	if (ret < 0)
344		return ret;
345
346	data->gain = gain;
347
348	return 0;
349}
350
351static int zopt2201_write_scale_als_by_idx(struct zopt2201_data *data, int idx)
352{
353	int ret;
354
355	mutex_lock(&data->lock);
356	ret = zopt2201_set_resolution(data, zopt2201_scale_als[idx].res);
357	if (ret < 0)
358		goto unlock;
359
360	ret = zopt2201_set_gain(data, zopt2201_scale_als[idx].gain);
361
362unlock:
363	mutex_unlock(&data->lock);
364	return ret;
365}
366
367static int zopt2201_write_scale_als(struct zopt2201_data *data,
368				     int val, int val2)
369{
370	int i;
371
372	for (i = 0; i < ARRAY_SIZE(zopt2201_scale_als); i++)
373		if (val == zopt2201_scale_als[i].scale &&
374		    val2 == zopt2201_scale_als[i].uscale) {
375			return zopt2201_write_scale_als_by_idx(data, i);
376		}
377
378	return -EINVAL;
379}
380
381static int zopt2201_write_scale_uvb_by_idx(struct zopt2201_data *data, int idx)
382{
383	int ret;
384
385	mutex_lock(&data->lock);
386	ret = zopt2201_set_resolution(data, zopt2201_scale_als[idx].res);
387	if (ret < 0)
388		goto unlock;
389
390	ret = zopt2201_set_gain(data, zopt2201_scale_als[idx].gain);
391
392unlock:
393	mutex_unlock(&data->lock);
394	return ret;
395}
396
397static int zopt2201_write_scale_uvb(struct zopt2201_data *data,
398				     int val, int val2)
399{
400	int i;
401
402	for (i = 0; i < ARRAY_SIZE(zopt2201_scale_uvb); i++)
403		if (val == zopt2201_scale_uvb[i].scale &&
404		    val2 == zopt2201_scale_uvb[i].uscale)
405			return zopt2201_write_scale_uvb_by_idx(data, i);
406
407	return -EINVAL;
408}
409
410static int zopt2201_write_raw(struct iio_dev *indio_dev,
411			      struct iio_chan_spec const *chan,
412			      int val, int val2, long mask)
413{
414	struct zopt2201_data *data = iio_priv(indio_dev);
415
416	switch (mask) {
417	case IIO_CHAN_INFO_INT_TIME:
418		return zopt2201_write_resolution(data, val, val2);
419	case IIO_CHAN_INFO_SCALE:
420		switch (chan->address) {
421		case ZOPT2201_ALS_DATA:
422			return zopt2201_write_scale_als(data, val, val2);
423		case ZOPT2201_UVB_DATA:
424			return zopt2201_write_scale_uvb(data, val, val2);
425		default:
426			return -EINVAL;
427		}
428	}
429
430	return -EINVAL;
431}
432
433static ssize_t zopt2201_show_int_time_available(struct device *dev,
434						struct device_attribute *attr,
435						char *buf)
436{
437	size_t len = 0;
438	int i;
439
440	for (i = 0; i < ARRAY_SIZE(zopt2201_resolution); i++)
441		len += scnprintf(buf + len, PAGE_SIZE - len, "0.%06lu ",
442				 zopt2201_resolution[i].us);
443	buf[len - 1] = '\n';
444
445	return len;
446}
447
448static IIO_DEV_ATTR_INT_TIME_AVAIL(zopt2201_show_int_time_available);
449
450static ssize_t zopt2201_show_als_scale_avail(struct device *dev,
451					     struct device_attribute *attr,
452					     char *buf)
453{
454	ssize_t len = 0;
455	int i;
456
457	for (i = 0; i < ARRAY_SIZE(zopt2201_scale_als); i++)
458		len += scnprintf(buf + len, PAGE_SIZE - len, "%d.%06u ",
459				 zopt2201_scale_als[i].scale,
460				 zopt2201_scale_als[i].uscale);
461	buf[len - 1] = '\n';
462
463	return len;
464}
465
466static ssize_t zopt2201_show_uvb_scale_avail(struct device *dev,
467					     struct device_attribute *attr,
468					     char *buf)
469{
470	ssize_t len = 0;
471	int i;
472
473	for (i = 0; i < ARRAY_SIZE(zopt2201_scale_uvb); i++)
474		len += scnprintf(buf + len, PAGE_SIZE - len, "%d.%06u ",
475				 zopt2201_scale_uvb[i].scale,
476				 zopt2201_scale_uvb[i].uscale);
477	buf[len - 1] = '\n';
478
479	return len;
480}
481
482static IIO_DEVICE_ATTR(in_illuminance_scale_available, 0444,
483		       zopt2201_show_als_scale_avail, NULL, 0);
484static IIO_DEVICE_ATTR(in_intensity_uv_scale_available, 0444,
485		       zopt2201_show_uvb_scale_avail, NULL, 0);
486
487static struct attribute *zopt2201_attributes[] = {
488	&iio_dev_attr_integration_time_available.dev_attr.attr,
489	&iio_dev_attr_in_illuminance_scale_available.dev_attr.attr,
490	&iio_dev_attr_in_intensity_uv_scale_available.dev_attr.attr,
491	NULL
492};
493
494static const struct attribute_group zopt2201_attribute_group = {
495	.attrs = zopt2201_attributes,
496};
497
498static const struct iio_info zopt2201_info = {
499	.read_raw = zopt2201_read_raw,
500	.write_raw = zopt2201_write_raw,
501	.attrs = &zopt2201_attribute_group,
502};
503
504static int zopt2201_probe(struct i2c_client *client)
505{
506	struct zopt2201_data *data;
507	struct iio_dev *indio_dev;
508	int ret;
509
510	if (!i2c_check_functionality(client->adapter,
511				     I2C_FUNC_SMBUS_READ_I2C_BLOCK))
512		return -EOPNOTSUPP;
513
514	ret = i2c_smbus_read_byte_data(client, ZOPT2201_PART_ID);
515	if (ret < 0)
516		return ret;
517	if (ret != ZOPT2201_PART_NUMBER)
518		return -ENODEV;
519
520	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
521	if (!indio_dev)
522		return -ENOMEM;
523
524	data = iio_priv(indio_dev);
525	i2c_set_clientdata(client, indio_dev);
526	data->client = client;
527	mutex_init(&data->lock);
528
529	indio_dev->info = &zopt2201_info;
530	indio_dev->channels = zopt2201_channels;
531	indio_dev->num_channels = ARRAY_SIZE(zopt2201_channels);
532	indio_dev->name = ZOPT2201_DRV_NAME;
533	indio_dev->modes = INDIO_DIRECT_MODE;
534
535	data->rate = ZOPT2201_MEAS_FREQ_100MS;
536	ret = zopt2201_set_resolution(data, ZOPT2201_MEAS_RES_18BIT);
537	if (ret < 0)
538		return ret;
539
540	ret = zopt2201_set_gain(data, ZOPT2201_LS_GAIN_3);
541	if (ret < 0)
542		return ret;
543
544	return devm_iio_device_register(&client->dev, indio_dev);
545}
546
547static const struct i2c_device_id zopt2201_id[] = {
548	{ "zopt2201", 0 },
549	{ }
550};
551MODULE_DEVICE_TABLE(i2c, zopt2201_id);
552
553static struct i2c_driver zopt2201_driver = {
554	.driver = {
555		.name   = ZOPT2201_DRV_NAME,
556	},
557	.probe = zopt2201_probe,
558	.id_table = zopt2201_id,
559};
560
561module_i2c_driver(zopt2201_driver);
562
563MODULE_AUTHOR("Peter Meerwald-Stadler <pmeerw@pmeerw.net>");
564MODULE_DESCRIPTION("IDT ZOPT2201 ambient light and UV B sensor driver");
565MODULE_LICENSE("GPL");
566