1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * ROHM BH1710/BH1715/BH1721/BH1750/BH1751 ambient light sensor driver
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Copyright (c) Tomasz Duszynski <tduszyns@gmail.com>
6*4882a593Smuzhiyun *
7*4882a593Smuzhiyun * Data sheets:
8*4882a593Smuzhiyun * http://rohmfs.rohm.com/en/products/databook/datasheet/ic/sensor/light/bh1710fvc-e.pdf
9*4882a593Smuzhiyun * http://rohmfs.rohm.com/en/products/databook/datasheet/ic/sensor/light/bh1715fvc-e.pdf
10*4882a593Smuzhiyun * http://rohmfs.rohm.com/en/products/databook/datasheet/ic/sensor/light/bh1721fvc-e.pdf
11*4882a593Smuzhiyun * http://rohmfs.rohm.com/en/products/databook/datasheet/ic/sensor/light/bh1750fvi-e.pdf
12*4882a593Smuzhiyun * http://rohmfs.rohm.com/en/products/databook/datasheet/ic/sensor/light/bh1751fvi-e.pdf
13*4882a593Smuzhiyun *
14*4882a593Smuzhiyun * 7-bit I2C slave addresses:
15*4882a593Smuzhiyun * 0x23 (ADDR pin low)
16*4882a593Smuzhiyun * 0x5C (ADDR pin high)
17*4882a593Smuzhiyun *
18*4882a593Smuzhiyun */
19*4882a593Smuzhiyun
20*4882a593Smuzhiyun #include <linux/delay.h>
21*4882a593Smuzhiyun #include <linux/i2c.h>
22*4882a593Smuzhiyun #include <linux/iio/iio.h>
23*4882a593Smuzhiyun #include <linux/iio/sysfs.h>
24*4882a593Smuzhiyun #include <linux/module.h>
25*4882a593Smuzhiyun
26*4882a593Smuzhiyun #define BH1750_POWER_DOWN 0x00
27*4882a593Smuzhiyun #define BH1750_ONE_TIME_H_RES_MODE 0x20 /* auto-mode for BH1721 */
28*4882a593Smuzhiyun #define BH1750_CHANGE_INT_TIME_H_BIT 0x40
29*4882a593Smuzhiyun #define BH1750_CHANGE_INT_TIME_L_BIT 0x60
30*4882a593Smuzhiyun
31*4882a593Smuzhiyun enum {
32*4882a593Smuzhiyun BH1710,
33*4882a593Smuzhiyun BH1721,
34*4882a593Smuzhiyun BH1750,
35*4882a593Smuzhiyun };
36*4882a593Smuzhiyun
37*4882a593Smuzhiyun struct bh1750_chip_info;
38*4882a593Smuzhiyun struct bh1750_data {
39*4882a593Smuzhiyun struct i2c_client *client;
40*4882a593Smuzhiyun struct mutex lock;
41*4882a593Smuzhiyun const struct bh1750_chip_info *chip_info;
42*4882a593Smuzhiyun u16 mtreg;
43*4882a593Smuzhiyun };
44*4882a593Smuzhiyun
45*4882a593Smuzhiyun struct bh1750_chip_info {
46*4882a593Smuzhiyun u16 mtreg_min;
47*4882a593Smuzhiyun u16 mtreg_max;
48*4882a593Smuzhiyun u16 mtreg_default;
49*4882a593Smuzhiyun int mtreg_to_usec;
50*4882a593Smuzhiyun int mtreg_to_scale;
51*4882a593Smuzhiyun
52*4882a593Smuzhiyun /*
53*4882a593Smuzhiyun * For BH1710/BH1721 all possible integration time values won't fit
54*4882a593Smuzhiyun * into one page so displaying is limited to every second one.
55*4882a593Smuzhiyun * Note, that user can still write proper values which were not
56*4882a593Smuzhiyun * listed.
57*4882a593Smuzhiyun */
58*4882a593Smuzhiyun int inc;
59*4882a593Smuzhiyun
60*4882a593Smuzhiyun u16 int_time_low_mask;
61*4882a593Smuzhiyun u16 int_time_high_mask;
62*4882a593Smuzhiyun };
63*4882a593Smuzhiyun
64*4882a593Smuzhiyun static const struct bh1750_chip_info bh1750_chip_info_tbl[] = {
65*4882a593Smuzhiyun [BH1710] = { 140, 1022, 300, 400, 250000000, 2, 0x001F, 0x03E0 },
66*4882a593Smuzhiyun [BH1721] = { 140, 1020, 300, 400, 250000000, 2, 0x0010, 0x03E0 },
67*4882a593Smuzhiyun [BH1750] = { 31, 254, 69, 1740, 57500000, 1, 0x001F, 0x00E0 },
68*4882a593Smuzhiyun };
69*4882a593Smuzhiyun
bh1750_change_int_time(struct bh1750_data * data,int usec)70*4882a593Smuzhiyun static int bh1750_change_int_time(struct bh1750_data *data, int usec)
71*4882a593Smuzhiyun {
72*4882a593Smuzhiyun int ret;
73*4882a593Smuzhiyun u16 val;
74*4882a593Smuzhiyun u8 regval;
75*4882a593Smuzhiyun const struct bh1750_chip_info *chip_info = data->chip_info;
76*4882a593Smuzhiyun
77*4882a593Smuzhiyun if ((usec % chip_info->mtreg_to_usec) != 0)
78*4882a593Smuzhiyun return -EINVAL;
79*4882a593Smuzhiyun
80*4882a593Smuzhiyun val = usec / chip_info->mtreg_to_usec;
81*4882a593Smuzhiyun if (val < chip_info->mtreg_min || val > chip_info->mtreg_max)
82*4882a593Smuzhiyun return -EINVAL;
83*4882a593Smuzhiyun
84*4882a593Smuzhiyun ret = i2c_smbus_write_byte(data->client, BH1750_POWER_DOWN);
85*4882a593Smuzhiyun if (ret < 0)
86*4882a593Smuzhiyun return ret;
87*4882a593Smuzhiyun
88*4882a593Smuzhiyun regval = (val & chip_info->int_time_high_mask) >> 5;
89*4882a593Smuzhiyun ret = i2c_smbus_write_byte(data->client,
90*4882a593Smuzhiyun BH1750_CHANGE_INT_TIME_H_BIT | regval);
91*4882a593Smuzhiyun if (ret < 0)
92*4882a593Smuzhiyun return ret;
93*4882a593Smuzhiyun
94*4882a593Smuzhiyun regval = val & chip_info->int_time_low_mask;
95*4882a593Smuzhiyun ret = i2c_smbus_write_byte(data->client,
96*4882a593Smuzhiyun BH1750_CHANGE_INT_TIME_L_BIT | regval);
97*4882a593Smuzhiyun if (ret < 0)
98*4882a593Smuzhiyun return ret;
99*4882a593Smuzhiyun
100*4882a593Smuzhiyun data->mtreg = val;
101*4882a593Smuzhiyun
102*4882a593Smuzhiyun return 0;
103*4882a593Smuzhiyun }
104*4882a593Smuzhiyun
bh1750_read(struct bh1750_data * data,int * val)105*4882a593Smuzhiyun static int bh1750_read(struct bh1750_data *data, int *val)
106*4882a593Smuzhiyun {
107*4882a593Smuzhiyun int ret;
108*4882a593Smuzhiyun __be16 result;
109*4882a593Smuzhiyun const struct bh1750_chip_info *chip_info = data->chip_info;
110*4882a593Smuzhiyun unsigned long delay = chip_info->mtreg_to_usec * data->mtreg;
111*4882a593Smuzhiyun
112*4882a593Smuzhiyun /*
113*4882a593Smuzhiyun * BH1721 will enter continuous mode on receiving this command.
114*4882a593Smuzhiyun * Note, that this eliminates need for bh1750_resume().
115*4882a593Smuzhiyun */
116*4882a593Smuzhiyun ret = i2c_smbus_write_byte(data->client, BH1750_ONE_TIME_H_RES_MODE);
117*4882a593Smuzhiyun if (ret < 0)
118*4882a593Smuzhiyun return ret;
119*4882a593Smuzhiyun
120*4882a593Smuzhiyun usleep_range(delay + 15000, delay + 40000);
121*4882a593Smuzhiyun
122*4882a593Smuzhiyun ret = i2c_master_recv(data->client, (char *)&result, 2);
123*4882a593Smuzhiyun if (ret < 0)
124*4882a593Smuzhiyun return ret;
125*4882a593Smuzhiyun
126*4882a593Smuzhiyun *val = be16_to_cpu(result);
127*4882a593Smuzhiyun
128*4882a593Smuzhiyun return 0;
129*4882a593Smuzhiyun }
130*4882a593Smuzhiyun
bh1750_read_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int * val,int * val2,long mask)131*4882a593Smuzhiyun static int bh1750_read_raw(struct iio_dev *indio_dev,
132*4882a593Smuzhiyun struct iio_chan_spec const *chan,
133*4882a593Smuzhiyun int *val, int *val2, long mask)
134*4882a593Smuzhiyun {
135*4882a593Smuzhiyun int ret, tmp;
136*4882a593Smuzhiyun struct bh1750_data *data = iio_priv(indio_dev);
137*4882a593Smuzhiyun const struct bh1750_chip_info *chip_info = data->chip_info;
138*4882a593Smuzhiyun
139*4882a593Smuzhiyun switch (mask) {
140*4882a593Smuzhiyun case IIO_CHAN_INFO_RAW:
141*4882a593Smuzhiyun switch (chan->type) {
142*4882a593Smuzhiyun case IIO_LIGHT:
143*4882a593Smuzhiyun mutex_lock(&data->lock);
144*4882a593Smuzhiyun ret = bh1750_read(data, val);
145*4882a593Smuzhiyun mutex_unlock(&data->lock);
146*4882a593Smuzhiyun if (ret < 0)
147*4882a593Smuzhiyun return ret;
148*4882a593Smuzhiyun
149*4882a593Smuzhiyun return IIO_VAL_INT;
150*4882a593Smuzhiyun default:
151*4882a593Smuzhiyun return -EINVAL;
152*4882a593Smuzhiyun }
153*4882a593Smuzhiyun case IIO_CHAN_INFO_SCALE:
154*4882a593Smuzhiyun tmp = chip_info->mtreg_to_scale / data->mtreg;
155*4882a593Smuzhiyun *val = tmp / 1000000;
156*4882a593Smuzhiyun *val2 = tmp % 1000000;
157*4882a593Smuzhiyun return IIO_VAL_INT_PLUS_MICRO;
158*4882a593Smuzhiyun case IIO_CHAN_INFO_INT_TIME:
159*4882a593Smuzhiyun *val = 0;
160*4882a593Smuzhiyun *val2 = chip_info->mtreg_to_usec * data->mtreg;
161*4882a593Smuzhiyun return IIO_VAL_INT_PLUS_MICRO;
162*4882a593Smuzhiyun default:
163*4882a593Smuzhiyun return -EINVAL;
164*4882a593Smuzhiyun }
165*4882a593Smuzhiyun }
166*4882a593Smuzhiyun
bh1750_write_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int val,int val2,long mask)167*4882a593Smuzhiyun static int bh1750_write_raw(struct iio_dev *indio_dev,
168*4882a593Smuzhiyun struct iio_chan_spec const *chan,
169*4882a593Smuzhiyun int val, int val2, long mask)
170*4882a593Smuzhiyun {
171*4882a593Smuzhiyun int ret;
172*4882a593Smuzhiyun struct bh1750_data *data = iio_priv(indio_dev);
173*4882a593Smuzhiyun
174*4882a593Smuzhiyun switch (mask) {
175*4882a593Smuzhiyun case IIO_CHAN_INFO_INT_TIME:
176*4882a593Smuzhiyun if (val != 0)
177*4882a593Smuzhiyun return -EINVAL;
178*4882a593Smuzhiyun
179*4882a593Smuzhiyun mutex_lock(&data->lock);
180*4882a593Smuzhiyun ret = bh1750_change_int_time(data, val2);
181*4882a593Smuzhiyun mutex_unlock(&data->lock);
182*4882a593Smuzhiyun return ret;
183*4882a593Smuzhiyun default:
184*4882a593Smuzhiyun return -EINVAL;
185*4882a593Smuzhiyun }
186*4882a593Smuzhiyun }
187*4882a593Smuzhiyun
bh1750_show_int_time_available(struct device * dev,struct device_attribute * attr,char * buf)188*4882a593Smuzhiyun static ssize_t bh1750_show_int_time_available(struct device *dev,
189*4882a593Smuzhiyun struct device_attribute *attr, char *buf)
190*4882a593Smuzhiyun {
191*4882a593Smuzhiyun int i;
192*4882a593Smuzhiyun size_t len = 0;
193*4882a593Smuzhiyun struct bh1750_data *data = iio_priv(dev_to_iio_dev(dev));
194*4882a593Smuzhiyun const struct bh1750_chip_info *chip_info = data->chip_info;
195*4882a593Smuzhiyun
196*4882a593Smuzhiyun for (i = chip_info->mtreg_min; i <= chip_info->mtreg_max; i += chip_info->inc)
197*4882a593Smuzhiyun len += scnprintf(buf + len, PAGE_SIZE - len, "0.%06d ",
198*4882a593Smuzhiyun chip_info->mtreg_to_usec * i);
199*4882a593Smuzhiyun
200*4882a593Smuzhiyun buf[len - 1] = '\n';
201*4882a593Smuzhiyun
202*4882a593Smuzhiyun return len;
203*4882a593Smuzhiyun }
204*4882a593Smuzhiyun
205*4882a593Smuzhiyun static IIO_DEV_ATTR_INT_TIME_AVAIL(bh1750_show_int_time_available);
206*4882a593Smuzhiyun
207*4882a593Smuzhiyun static struct attribute *bh1750_attributes[] = {
208*4882a593Smuzhiyun &iio_dev_attr_integration_time_available.dev_attr.attr,
209*4882a593Smuzhiyun NULL,
210*4882a593Smuzhiyun };
211*4882a593Smuzhiyun
212*4882a593Smuzhiyun static const struct attribute_group bh1750_attribute_group = {
213*4882a593Smuzhiyun .attrs = bh1750_attributes,
214*4882a593Smuzhiyun };
215*4882a593Smuzhiyun
216*4882a593Smuzhiyun static const struct iio_info bh1750_info = {
217*4882a593Smuzhiyun .attrs = &bh1750_attribute_group,
218*4882a593Smuzhiyun .read_raw = bh1750_read_raw,
219*4882a593Smuzhiyun .write_raw = bh1750_write_raw,
220*4882a593Smuzhiyun };
221*4882a593Smuzhiyun
222*4882a593Smuzhiyun static const struct iio_chan_spec bh1750_channels[] = {
223*4882a593Smuzhiyun {
224*4882a593Smuzhiyun .type = IIO_LIGHT,
225*4882a593Smuzhiyun .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
226*4882a593Smuzhiyun BIT(IIO_CHAN_INFO_SCALE) |
227*4882a593Smuzhiyun BIT(IIO_CHAN_INFO_INT_TIME)
228*4882a593Smuzhiyun }
229*4882a593Smuzhiyun };
230*4882a593Smuzhiyun
bh1750_probe(struct i2c_client * client,const struct i2c_device_id * id)231*4882a593Smuzhiyun static int bh1750_probe(struct i2c_client *client,
232*4882a593Smuzhiyun const struct i2c_device_id *id)
233*4882a593Smuzhiyun {
234*4882a593Smuzhiyun int ret, usec;
235*4882a593Smuzhiyun struct bh1750_data *data;
236*4882a593Smuzhiyun struct iio_dev *indio_dev;
237*4882a593Smuzhiyun
238*4882a593Smuzhiyun if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C |
239*4882a593Smuzhiyun I2C_FUNC_SMBUS_WRITE_BYTE))
240*4882a593Smuzhiyun return -EOPNOTSUPP;
241*4882a593Smuzhiyun
242*4882a593Smuzhiyun indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
243*4882a593Smuzhiyun if (!indio_dev)
244*4882a593Smuzhiyun return -ENOMEM;
245*4882a593Smuzhiyun
246*4882a593Smuzhiyun data = iio_priv(indio_dev);
247*4882a593Smuzhiyun i2c_set_clientdata(client, indio_dev);
248*4882a593Smuzhiyun data->client = client;
249*4882a593Smuzhiyun data->chip_info = &bh1750_chip_info_tbl[id->driver_data];
250*4882a593Smuzhiyun
251*4882a593Smuzhiyun usec = data->chip_info->mtreg_to_usec * data->chip_info->mtreg_default;
252*4882a593Smuzhiyun ret = bh1750_change_int_time(data, usec);
253*4882a593Smuzhiyun if (ret < 0)
254*4882a593Smuzhiyun return ret;
255*4882a593Smuzhiyun
256*4882a593Smuzhiyun mutex_init(&data->lock);
257*4882a593Smuzhiyun indio_dev->info = &bh1750_info;
258*4882a593Smuzhiyun indio_dev->name = id->name;
259*4882a593Smuzhiyun indio_dev->channels = bh1750_channels;
260*4882a593Smuzhiyun indio_dev->num_channels = ARRAY_SIZE(bh1750_channels);
261*4882a593Smuzhiyun indio_dev->modes = INDIO_DIRECT_MODE;
262*4882a593Smuzhiyun
263*4882a593Smuzhiyun return iio_device_register(indio_dev);
264*4882a593Smuzhiyun }
265*4882a593Smuzhiyun
bh1750_remove(struct i2c_client * client)266*4882a593Smuzhiyun static int bh1750_remove(struct i2c_client *client)
267*4882a593Smuzhiyun {
268*4882a593Smuzhiyun struct iio_dev *indio_dev = i2c_get_clientdata(client);
269*4882a593Smuzhiyun struct bh1750_data *data = iio_priv(indio_dev);
270*4882a593Smuzhiyun
271*4882a593Smuzhiyun iio_device_unregister(indio_dev);
272*4882a593Smuzhiyun
273*4882a593Smuzhiyun mutex_lock(&data->lock);
274*4882a593Smuzhiyun i2c_smbus_write_byte(client, BH1750_POWER_DOWN);
275*4882a593Smuzhiyun mutex_unlock(&data->lock);
276*4882a593Smuzhiyun
277*4882a593Smuzhiyun return 0;
278*4882a593Smuzhiyun }
279*4882a593Smuzhiyun
bh1750_suspend(struct device * dev)280*4882a593Smuzhiyun static int __maybe_unused bh1750_suspend(struct device *dev)
281*4882a593Smuzhiyun {
282*4882a593Smuzhiyun int ret;
283*4882a593Smuzhiyun struct bh1750_data *data =
284*4882a593Smuzhiyun iio_priv(i2c_get_clientdata(to_i2c_client(dev)));
285*4882a593Smuzhiyun
286*4882a593Smuzhiyun /*
287*4882a593Smuzhiyun * This is mainly for BH1721 which doesn't enter power down
288*4882a593Smuzhiyun * mode automatically.
289*4882a593Smuzhiyun */
290*4882a593Smuzhiyun mutex_lock(&data->lock);
291*4882a593Smuzhiyun ret = i2c_smbus_write_byte(data->client, BH1750_POWER_DOWN);
292*4882a593Smuzhiyun mutex_unlock(&data->lock);
293*4882a593Smuzhiyun
294*4882a593Smuzhiyun return ret;
295*4882a593Smuzhiyun }
296*4882a593Smuzhiyun
297*4882a593Smuzhiyun static SIMPLE_DEV_PM_OPS(bh1750_pm_ops, bh1750_suspend, NULL);
298*4882a593Smuzhiyun
299*4882a593Smuzhiyun static const struct i2c_device_id bh1750_id[] = {
300*4882a593Smuzhiyun { "bh1710", BH1710 },
301*4882a593Smuzhiyun { "bh1715", BH1750 },
302*4882a593Smuzhiyun { "bh1721", BH1721 },
303*4882a593Smuzhiyun { "bh1750", BH1750 },
304*4882a593Smuzhiyun { "bh1751", BH1750 },
305*4882a593Smuzhiyun { }
306*4882a593Smuzhiyun };
307*4882a593Smuzhiyun MODULE_DEVICE_TABLE(i2c, bh1750_id);
308*4882a593Smuzhiyun
309*4882a593Smuzhiyun static const struct of_device_id bh1750_of_match[] = {
310*4882a593Smuzhiyun { .compatible = "rohm,bh1710", },
311*4882a593Smuzhiyun { .compatible = "rohm,bh1715", },
312*4882a593Smuzhiyun { .compatible = "rohm,bh1721", },
313*4882a593Smuzhiyun { .compatible = "rohm,bh1750", },
314*4882a593Smuzhiyun { .compatible = "rohm,bh1751", },
315*4882a593Smuzhiyun { }
316*4882a593Smuzhiyun };
317*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, bh1750_of_match);
318*4882a593Smuzhiyun
319*4882a593Smuzhiyun static struct i2c_driver bh1750_driver = {
320*4882a593Smuzhiyun .driver = {
321*4882a593Smuzhiyun .name = "bh1750",
322*4882a593Smuzhiyun .of_match_table = bh1750_of_match,
323*4882a593Smuzhiyun .pm = &bh1750_pm_ops,
324*4882a593Smuzhiyun },
325*4882a593Smuzhiyun .probe = bh1750_probe,
326*4882a593Smuzhiyun .remove = bh1750_remove,
327*4882a593Smuzhiyun .id_table = bh1750_id,
328*4882a593Smuzhiyun
329*4882a593Smuzhiyun };
330*4882a593Smuzhiyun module_i2c_driver(bh1750_driver);
331*4882a593Smuzhiyun
332*4882a593Smuzhiyun MODULE_AUTHOR("Tomasz Duszynski <tduszyns@gmail.com>");
333*4882a593Smuzhiyun MODULE_DESCRIPTION("ROHM BH1710/BH1715/BH1721/BH1750/BH1751 als driver");
334*4882a593Smuzhiyun MODULE_LICENSE("GPL v2");
335