xref: /linux/drivers/iio/light/al3010.c (revision c36b5195ab7035cc7ee0b79f621a3a9ecd71cf9c)
1*c36b5195SDavid Heidelberg // SPDX-License-Identifier: GPL-2.0-only
2*c36b5195SDavid Heidelberg /*
3*c36b5195SDavid Heidelberg  * AL3010 - Dyna Image Ambient Light Sensor
4*c36b5195SDavid Heidelberg  *
5*c36b5195SDavid Heidelberg  * Copyright (c) 2014, Intel Corporation.
6*c36b5195SDavid Heidelberg  * Copyright (c) 2016, Dyna-Image Corp.
7*c36b5195SDavid Heidelberg  * Copyright (c) 2020, David Heidelberg, Michał Mirosław, Dmitry Osipenko
8*c36b5195SDavid Heidelberg  *
9*c36b5195SDavid Heidelberg  * IIO driver for AL3010 (7-bit I2C slave address 0x1C).
10*c36b5195SDavid Heidelberg  *
11*c36b5195SDavid Heidelberg  * TODO: interrupt support, thresholds
12*c36b5195SDavid Heidelberg  * When the driver will get support for interrupt handling, then interrupt
13*c36b5195SDavid Heidelberg  * will need to be disabled before turning sensor OFF in order to avoid
14*c36b5195SDavid Heidelberg  * potential races with the interrupt handling.
15*c36b5195SDavid Heidelberg  */
16*c36b5195SDavid Heidelberg 
17*c36b5195SDavid Heidelberg #include <linux/bitfield.h>
18*c36b5195SDavid Heidelberg #include <linux/i2c.h>
19*c36b5195SDavid Heidelberg #include <linux/module.h>
20*c36b5195SDavid Heidelberg #include <linux/of.h>
21*c36b5195SDavid Heidelberg 
22*c36b5195SDavid Heidelberg #include <linux/iio/iio.h>
23*c36b5195SDavid Heidelberg #include <linux/iio/sysfs.h>
24*c36b5195SDavid Heidelberg 
25*c36b5195SDavid Heidelberg #define AL3010_DRV_NAME "al3010"
26*c36b5195SDavid Heidelberg 
27*c36b5195SDavid Heidelberg #define AL3010_REG_SYSTEM		0x00
28*c36b5195SDavid Heidelberg #define AL3010_REG_DATA_LOW		0x0c
29*c36b5195SDavid Heidelberg #define AL3010_REG_CONFIG		0x10
30*c36b5195SDavid Heidelberg 
31*c36b5195SDavid Heidelberg #define AL3010_CONFIG_DISABLE		0x00
32*c36b5195SDavid Heidelberg #define AL3010_CONFIG_ENABLE		0x01
33*c36b5195SDavid Heidelberg 
34*c36b5195SDavid Heidelberg #define AL3010_GAIN_MASK		GENMASK(6,4)
35*c36b5195SDavid Heidelberg 
36*c36b5195SDavid Heidelberg #define AL3010_SCALE_AVAILABLE "1.1872 0.2968 0.0742 0.018"
37*c36b5195SDavid Heidelberg 
38*c36b5195SDavid Heidelberg enum al3xxxx_range {
39*c36b5195SDavid Heidelberg 	AL3XXX_RANGE_1, /* 77806 lx */
40*c36b5195SDavid Heidelberg 	AL3XXX_RANGE_2, /* 19542 lx */
41*c36b5195SDavid Heidelberg 	AL3XXX_RANGE_3, /*  4863 lx */
42*c36b5195SDavid Heidelberg 	AL3XXX_RANGE_4  /*  1216 lx */
43*c36b5195SDavid Heidelberg };
44*c36b5195SDavid Heidelberg 
45*c36b5195SDavid Heidelberg static const int al3010_scales[][2] = {
46*c36b5195SDavid Heidelberg 	{0, 1187200}, {0, 296800}, {0, 74200}, {0, 18600}
47*c36b5195SDavid Heidelberg };
48*c36b5195SDavid Heidelberg 
49*c36b5195SDavid Heidelberg struct al3010_data {
50*c36b5195SDavid Heidelberg 	struct i2c_client *client;
51*c36b5195SDavid Heidelberg };
52*c36b5195SDavid Heidelberg 
53*c36b5195SDavid Heidelberg static const struct iio_chan_spec al3010_channels[] = {
54*c36b5195SDavid Heidelberg 	{
55*c36b5195SDavid Heidelberg 		.type	= IIO_LIGHT,
56*c36b5195SDavid Heidelberg 		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
57*c36b5195SDavid Heidelberg 				      BIT(IIO_CHAN_INFO_SCALE),
58*c36b5195SDavid Heidelberg 	}
59*c36b5195SDavid Heidelberg };
60*c36b5195SDavid Heidelberg 
61*c36b5195SDavid Heidelberg static IIO_CONST_ATTR(in_illuminance_scale_available, AL3010_SCALE_AVAILABLE);
62*c36b5195SDavid Heidelberg 
63*c36b5195SDavid Heidelberg static struct attribute *al3010_attributes[] = {
64*c36b5195SDavid Heidelberg 	&iio_const_attr_in_illuminance_scale_available.dev_attr.attr,
65*c36b5195SDavid Heidelberg 	NULL,
66*c36b5195SDavid Heidelberg };
67*c36b5195SDavid Heidelberg 
68*c36b5195SDavid Heidelberg static const struct attribute_group al3010_attribute_group = {
69*c36b5195SDavid Heidelberg 	.attrs = al3010_attributes,
70*c36b5195SDavid Heidelberg };
71*c36b5195SDavid Heidelberg 
72*c36b5195SDavid Heidelberg static int al3010_set_pwr(struct i2c_client *client, bool pwr)
73*c36b5195SDavid Heidelberg {
74*c36b5195SDavid Heidelberg 	u8 val = pwr ? AL3010_CONFIG_ENABLE : AL3010_CONFIG_DISABLE;
75*c36b5195SDavid Heidelberg 	return i2c_smbus_write_byte_data(client, AL3010_REG_SYSTEM, val);
76*c36b5195SDavid Heidelberg }
77*c36b5195SDavid Heidelberg 
78*c36b5195SDavid Heidelberg static void al3010_set_pwr_off(void *_data)
79*c36b5195SDavid Heidelberg {
80*c36b5195SDavid Heidelberg 	struct al3010_data *data = _data;
81*c36b5195SDavid Heidelberg 
82*c36b5195SDavid Heidelberg 	al3010_set_pwr(data->client, false);
83*c36b5195SDavid Heidelberg }
84*c36b5195SDavid Heidelberg 
85*c36b5195SDavid Heidelberg static int al3010_init(struct al3010_data *data)
86*c36b5195SDavid Heidelberg {
87*c36b5195SDavid Heidelberg 	int ret;
88*c36b5195SDavid Heidelberg 
89*c36b5195SDavid Heidelberg 	ret = al3010_set_pwr(data->client, true);
90*c36b5195SDavid Heidelberg 
91*c36b5195SDavid Heidelberg 	if (ret < 0)
92*c36b5195SDavid Heidelberg 		return ret;
93*c36b5195SDavid Heidelberg 
94*c36b5195SDavid Heidelberg 	ret = i2c_smbus_write_byte_data(data->client, AL3010_REG_CONFIG,
95*c36b5195SDavid Heidelberg 					FIELD_PREP(AL3010_GAIN_MASK,
96*c36b5195SDavid Heidelberg 						   AL3XXX_RANGE_3));
97*c36b5195SDavid Heidelberg 	if (ret < 0)
98*c36b5195SDavid Heidelberg 		return ret;
99*c36b5195SDavid Heidelberg 
100*c36b5195SDavid Heidelberg 	return 0;
101*c36b5195SDavid Heidelberg }
102*c36b5195SDavid Heidelberg 
103*c36b5195SDavid Heidelberg static int al3010_read_raw(struct iio_dev *indio_dev,
104*c36b5195SDavid Heidelberg 			   struct iio_chan_spec const *chan, int *val,
105*c36b5195SDavid Heidelberg 			   int *val2, long mask)
106*c36b5195SDavid Heidelberg {
107*c36b5195SDavid Heidelberg 	struct al3010_data *data = iio_priv(indio_dev);
108*c36b5195SDavid Heidelberg 	int ret;
109*c36b5195SDavid Heidelberg 
110*c36b5195SDavid Heidelberg 	switch (mask) {
111*c36b5195SDavid Heidelberg 	case IIO_CHAN_INFO_RAW:
112*c36b5195SDavid Heidelberg 		/*
113*c36b5195SDavid Heidelberg 		 * ALS ADC value is stored in two adjacent registers:
114*c36b5195SDavid Heidelberg 		 * - low byte of output is stored at AL3010_REG_DATA_LOW
115*c36b5195SDavid Heidelberg 		 * - high byte of output is stored at AL3010_REG_DATA_LOW + 1
116*c36b5195SDavid Heidelberg 		 */
117*c36b5195SDavid Heidelberg 		ret = i2c_smbus_read_word_data(data->client,
118*c36b5195SDavid Heidelberg 					       AL3010_REG_DATA_LOW);
119*c36b5195SDavid Heidelberg 		if (ret < 0)
120*c36b5195SDavid Heidelberg 			return ret;
121*c36b5195SDavid Heidelberg 		*val = ret;
122*c36b5195SDavid Heidelberg 		return IIO_VAL_INT;
123*c36b5195SDavid Heidelberg 	case IIO_CHAN_INFO_SCALE:
124*c36b5195SDavid Heidelberg 		ret = i2c_smbus_read_byte_data(data->client,
125*c36b5195SDavid Heidelberg 					       AL3010_REG_CONFIG);
126*c36b5195SDavid Heidelberg 		if (ret < 0)
127*c36b5195SDavid Heidelberg 			return ret;
128*c36b5195SDavid Heidelberg 
129*c36b5195SDavid Heidelberg 		ret = FIELD_GET(AL3010_GAIN_MASK, ret);
130*c36b5195SDavid Heidelberg 		*val = al3010_scales[ret][0];
131*c36b5195SDavid Heidelberg 		*val2 = al3010_scales[ret][1];
132*c36b5195SDavid Heidelberg 
133*c36b5195SDavid Heidelberg 		return IIO_VAL_INT_PLUS_MICRO;
134*c36b5195SDavid Heidelberg 	}
135*c36b5195SDavid Heidelberg 	return -EINVAL;
136*c36b5195SDavid Heidelberg }
137*c36b5195SDavid Heidelberg 
138*c36b5195SDavid Heidelberg static int al3010_write_raw(struct iio_dev *indio_dev,
139*c36b5195SDavid Heidelberg 			    struct iio_chan_spec const *chan, int val,
140*c36b5195SDavid Heidelberg 			    int val2, long mask)
141*c36b5195SDavid Heidelberg {
142*c36b5195SDavid Heidelberg 	struct al3010_data *data = iio_priv(indio_dev);
143*c36b5195SDavid Heidelberg 	int i;
144*c36b5195SDavid Heidelberg 
145*c36b5195SDavid Heidelberg 	switch (mask) {
146*c36b5195SDavid Heidelberg 	case IIO_CHAN_INFO_SCALE:
147*c36b5195SDavid Heidelberg 		for (i = 0; i < ARRAY_SIZE(al3010_scales); i++) {
148*c36b5195SDavid Heidelberg 			if (val != al3010_scales[i][0] ||
149*c36b5195SDavid Heidelberg 			    val2 != al3010_scales[i][1])
150*c36b5195SDavid Heidelberg 				continue;
151*c36b5195SDavid Heidelberg 
152*c36b5195SDavid Heidelberg 			return i2c_smbus_write_byte_data(data->client,
153*c36b5195SDavid Heidelberg 					AL3010_REG_CONFIG,
154*c36b5195SDavid Heidelberg 					FIELD_PREP(AL3010_GAIN_MASK, i));
155*c36b5195SDavid Heidelberg 		}
156*c36b5195SDavid Heidelberg 		break;
157*c36b5195SDavid Heidelberg 	}
158*c36b5195SDavid Heidelberg 	return -EINVAL;
159*c36b5195SDavid Heidelberg }
160*c36b5195SDavid Heidelberg 
161*c36b5195SDavid Heidelberg static const struct iio_info al3010_info = {
162*c36b5195SDavid Heidelberg 	.read_raw	= al3010_read_raw,
163*c36b5195SDavid Heidelberg 	.write_raw	= al3010_write_raw,
164*c36b5195SDavid Heidelberg 	.attrs		= &al3010_attribute_group,
165*c36b5195SDavid Heidelberg };
166*c36b5195SDavid Heidelberg 
167*c36b5195SDavid Heidelberg static int al3010_probe(struct i2c_client *client,
168*c36b5195SDavid Heidelberg 			const struct i2c_device_id *id)
169*c36b5195SDavid Heidelberg {
170*c36b5195SDavid Heidelberg 	struct al3010_data *data;
171*c36b5195SDavid Heidelberg 	struct iio_dev *indio_dev;
172*c36b5195SDavid Heidelberg 	int ret;
173*c36b5195SDavid Heidelberg 
174*c36b5195SDavid Heidelberg 	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
175*c36b5195SDavid Heidelberg 	if (!indio_dev)
176*c36b5195SDavid Heidelberg 		return -ENOMEM;
177*c36b5195SDavid Heidelberg 
178*c36b5195SDavid Heidelberg 	data = iio_priv(indio_dev);
179*c36b5195SDavid Heidelberg 	i2c_set_clientdata(client, indio_dev);
180*c36b5195SDavid Heidelberg 	data->client = client;
181*c36b5195SDavid Heidelberg 
182*c36b5195SDavid Heidelberg 	indio_dev->dev.parent = &client->dev;
183*c36b5195SDavid Heidelberg 	indio_dev->info = &al3010_info;
184*c36b5195SDavid Heidelberg 	indio_dev->name = AL3010_DRV_NAME;
185*c36b5195SDavid Heidelberg 	indio_dev->channels = al3010_channels;
186*c36b5195SDavid Heidelberg 	indio_dev->num_channels = ARRAY_SIZE(al3010_channels);
187*c36b5195SDavid Heidelberg 	indio_dev->modes = INDIO_DIRECT_MODE;
188*c36b5195SDavid Heidelberg 
189*c36b5195SDavid Heidelberg 	ret = al3010_init(data);
190*c36b5195SDavid Heidelberg 	if (ret < 0) {
191*c36b5195SDavid Heidelberg 		dev_err(&client->dev, "al3010 chip init failed\n");
192*c36b5195SDavid Heidelberg 		return ret;
193*c36b5195SDavid Heidelberg 	}
194*c36b5195SDavid Heidelberg 
195*c36b5195SDavid Heidelberg 	ret = devm_add_action_or_reset(&client->dev,
196*c36b5195SDavid Heidelberg 					al3010_set_pwr_off,
197*c36b5195SDavid Heidelberg 					data);
198*c36b5195SDavid Heidelberg 	if (ret < 0)
199*c36b5195SDavid Heidelberg 		return ret;
200*c36b5195SDavid Heidelberg 
201*c36b5195SDavid Heidelberg 	return devm_iio_device_register(&client->dev, indio_dev);
202*c36b5195SDavid Heidelberg }
203*c36b5195SDavid Heidelberg 
204*c36b5195SDavid Heidelberg static int __maybe_unused al3010_suspend(struct device *dev)
205*c36b5195SDavid Heidelberg {
206*c36b5195SDavid Heidelberg 	return al3010_set_pwr(to_i2c_client(dev), false);
207*c36b5195SDavid Heidelberg }
208*c36b5195SDavid Heidelberg 
209*c36b5195SDavid Heidelberg static int __maybe_unused al3010_resume(struct device *dev)
210*c36b5195SDavid Heidelberg {
211*c36b5195SDavid Heidelberg 	return al3010_set_pwr(to_i2c_client(dev), true);
212*c36b5195SDavid Heidelberg }
213*c36b5195SDavid Heidelberg 
214*c36b5195SDavid Heidelberg static SIMPLE_DEV_PM_OPS(al3010_pm_ops, al3010_suspend, al3010_resume);
215*c36b5195SDavid Heidelberg 
216*c36b5195SDavid Heidelberg static const struct i2c_device_id al3010_id[] = {
217*c36b5195SDavid Heidelberg 	{"al3010", },
218*c36b5195SDavid Heidelberg 	{}
219*c36b5195SDavid Heidelberg };
220*c36b5195SDavid Heidelberg MODULE_DEVICE_TABLE(i2c, al3010_id);
221*c36b5195SDavid Heidelberg 
222*c36b5195SDavid Heidelberg static const struct of_device_id al3010_of_match[] = {
223*c36b5195SDavid Heidelberg 	{ .compatible = "dynaimage,al3010", },
224*c36b5195SDavid Heidelberg 	{},
225*c36b5195SDavid Heidelberg };
226*c36b5195SDavid Heidelberg MODULE_DEVICE_TABLE(of, al3010_of_match);
227*c36b5195SDavid Heidelberg 
228*c36b5195SDavid Heidelberg static struct i2c_driver al3010_driver = {
229*c36b5195SDavid Heidelberg 	.driver = {
230*c36b5195SDavid Heidelberg 		.name = AL3010_DRV_NAME,
231*c36b5195SDavid Heidelberg 		.of_match_table = al3010_of_match,
232*c36b5195SDavid Heidelberg 		.pm = &al3010_pm_ops,
233*c36b5195SDavid Heidelberg 	},
234*c36b5195SDavid Heidelberg 	.probe		= al3010_probe,
235*c36b5195SDavid Heidelberg 	.id_table	= al3010_id,
236*c36b5195SDavid Heidelberg };
237*c36b5195SDavid Heidelberg module_i2c_driver(al3010_driver);
238*c36b5195SDavid Heidelberg 
239*c36b5195SDavid Heidelberg MODULE_AUTHOR("Daniel Baluta <daniel.baluta@nxp.com>");
240*c36b5195SDavid Heidelberg MODULE_AUTHOR("David Heidelberg <david@ixit.cz>");
241*c36b5195SDavid Heidelberg MODULE_DESCRIPTION("AL3010 Ambient Light Sensor driver");
242*c36b5195SDavid Heidelberg MODULE_LICENSE("GPL v2");
243