File Index
Files and directories
Sign in
FILE

bh1780.c

File preview with syntax highlighting.

linux-6.19.14/drivers/iio/light/bh1780.c C
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * ROHM 1780GLI Ambient Light Sensor Driver
  4 *
  5 * Copyright (C) 2016 Linaro Ltd.
  6 * Author: Linus Walleij <linus.walleij@linaro.org>
  7 * Loosely based on the previous BH1780 ALS misc driver
  8 * Copyright (C) 2010 Texas Instruments
  9 * Author: Hemanth V <hemanthv@ti.com>
 10 */
 11#include <linux/i2c.h>
 12#include <linux/slab.h>
 13#include <linux/platform_device.h>
 14#include <linux/delay.h>
 15#include <linux/module.h>
 16#include <linux/mod_devicetable.h>
 17#include <linux/pm_runtime.h>
 18#include <linux/iio/iio.h>
 19#include <linux/iio/sysfs.h>
 20#include <linux/bitops.h>
 21
 22#define BH1780_CMD_BIT		BIT(7)
 23#define BH1780_REG_CONTROL	0x00
 24#define BH1780_REG_PARTID	0x0A
 25#define BH1780_REG_MANFID	0x0B
 26#define BH1780_REG_DLOW		0x0C
 27#define BH1780_REG_DHIGH	0x0D
 28
 29#define BH1780_REVMASK		GENMASK(3,0)
 30#define BH1780_POWMASK		GENMASK(1,0)
 31#define BH1780_POFF		(0x0)
 32#define BH1780_PON		(0x3)
 33
 34/* power on settling time in ms */
 35#define BH1780_PON_DELAY	2
 36/* max time before value available in ms */
 37#define BH1780_INTERVAL		250
 38
 39struct bh1780_data {
 40	struct i2c_client *client;
 41};
 42
 43static int bh1780_write(struct bh1780_data *bh1780, u8 reg, u8 val)
 44{
 45	int ret = i2c_smbus_write_byte_data(bh1780->client,
 46					    BH1780_CMD_BIT | reg,
 47					    val);
 48	if (ret < 0)
 49		dev_err(&bh1780->client->dev,
 50			"i2c_smbus_write_byte_data failed error "
 51			"%d, register %01x\n",
 52			ret, reg);
 53	return ret;
 54}
 55
 56static int bh1780_read(struct bh1780_data *bh1780, u8 reg)
 57{
 58	int ret = i2c_smbus_read_byte_data(bh1780->client,
 59					   BH1780_CMD_BIT | reg);
 60	if (ret < 0)
 61		dev_err(&bh1780->client->dev,
 62			"i2c_smbus_read_byte_data failed error "
 63			"%d, register %01x\n",
 64			ret, reg);
 65	return ret;
 66}
 67
 68static int bh1780_read_word(struct bh1780_data *bh1780, u8 reg)
 69{
 70	int ret = i2c_smbus_read_word_data(bh1780->client,
 71					   BH1780_CMD_BIT | reg);
 72	if (ret < 0)
 73		dev_err(&bh1780->client->dev,
 74			"i2c_smbus_read_word_data failed error "
 75			"%d, register %01x\n",
 76			ret, reg);
 77	return ret;
 78}
 79
 80static int bh1780_debugfs_reg_access(struct iio_dev *indio_dev,
 81			      unsigned int reg, unsigned int writeval,
 82			      unsigned int *readval)
 83{
 84	struct bh1780_data *bh1780 = iio_priv(indio_dev);
 85	int ret;
 86
 87	if (!readval)
 88		return bh1780_write(bh1780, (u8)reg, (u8)writeval);
 89
 90	ret = bh1780_read(bh1780, (u8)reg);
 91	if (ret < 0)
 92		return ret;
 93
 94	*readval = ret;
 95
 96	return 0;
 97}
 98
 99static int bh1780_read_raw(struct iio_dev *indio_dev,
100			   struct iio_chan_spec const *chan,
101			   int *val, int *val2, long mask)
102{
103	struct bh1780_data *bh1780 = iio_priv(indio_dev);
104	int value;
105
106	switch (mask) {
107	case IIO_CHAN_INFO_RAW:
108		switch (chan->type) {
109		case IIO_LIGHT:
110			pm_runtime_get_sync(&bh1780->client->dev);
111			value = bh1780_read_word(bh1780, BH1780_REG_DLOW);
112			pm_runtime_put_autosuspend(&bh1780->client->dev);
113			if (value < 0)
114				return value;
115			*val = value;
116
117			return IIO_VAL_INT;
118		default:
119			return -EINVAL;
120		}
121	case IIO_CHAN_INFO_INT_TIME:
122		*val = 0;
123		*val2 = BH1780_INTERVAL * 1000;
124		return IIO_VAL_INT_PLUS_MICRO;
125	default:
126		return -EINVAL;
127	}
128}
129
130static const struct iio_info bh1780_info = {
131	.read_raw = bh1780_read_raw,
132	.debugfs_reg_access = bh1780_debugfs_reg_access,
133};
134
135static const struct iio_chan_spec bh1780_channels[] = {
136	{
137		.type = IIO_LIGHT,
138		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
139				      BIT(IIO_CHAN_INFO_INT_TIME)
140	}
141};
142
143static int bh1780_probe(struct i2c_client *client)
144{
145	int ret;
146	struct bh1780_data *bh1780;
147	struct i2c_adapter *adapter = client->adapter;
148	struct iio_dev *indio_dev;
149
150	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE))
151		return -EIO;
152
153	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*bh1780));
154	if (!indio_dev)
155		return -ENOMEM;
156
157	bh1780 = iio_priv(indio_dev);
158	bh1780->client = client;
159	i2c_set_clientdata(client, indio_dev);
160
161	/* Power up the device */
162	ret = bh1780_write(bh1780, BH1780_REG_CONTROL, BH1780_PON);
163	if (ret < 0)
164		return ret;
165	msleep(BH1780_PON_DELAY);
166	pm_runtime_get_noresume(&client->dev);
167	pm_runtime_set_active(&client->dev);
168	pm_runtime_enable(&client->dev);
169
170	ret = bh1780_read(bh1780, BH1780_REG_PARTID);
171	if (ret < 0)
172		goto out_disable_pm;
173	dev_info(&client->dev,
174		 "Ambient Light Sensor, Rev : %lu\n",
175		 (ret & BH1780_REVMASK));
176
177	/*
178	 * As the device takes 250 ms to even come up with a fresh
179	 * measurement after power-on, do not shut it down unnecessarily.
180	 * Set autosuspend to a five seconds.
181	 */
182	pm_runtime_set_autosuspend_delay(&client->dev, 5000);
183	pm_runtime_use_autosuspend(&client->dev);
184	pm_runtime_put(&client->dev);
185
186	indio_dev->info = &bh1780_info;
187	indio_dev->name = "bh1780";
188	indio_dev->channels = bh1780_channels;
189	indio_dev->num_channels = ARRAY_SIZE(bh1780_channels);
190	indio_dev->modes = INDIO_DIRECT_MODE;
191
192	ret = iio_device_register(indio_dev);
193	if (ret)
194		goto out_disable_pm;
195	return 0;
196
197out_disable_pm:
198	pm_runtime_put_noidle(&client->dev);
199	pm_runtime_disable(&client->dev);
200	return ret;
201}
202
203static void bh1780_remove(struct i2c_client *client)
204{
205	struct iio_dev *indio_dev = i2c_get_clientdata(client);
206	struct bh1780_data *bh1780 = iio_priv(indio_dev);
207	int ret;
208
209	iio_device_unregister(indio_dev);
210	pm_runtime_get_sync(&client->dev);
211	pm_runtime_put_noidle(&client->dev);
212	pm_runtime_disable(&client->dev);
213	ret = bh1780_write(bh1780, BH1780_REG_CONTROL, BH1780_POFF);
214	if (ret < 0)
215		dev_err(&client->dev, "failed to power off (%pe)\n",
216			ERR_PTR(ret));
217}
218
219static int bh1780_runtime_suspend(struct device *dev)
220{
221	struct i2c_client *client = to_i2c_client(dev);
222	struct iio_dev *indio_dev = i2c_get_clientdata(client);
223	struct bh1780_data *bh1780 = iio_priv(indio_dev);
224	int ret;
225
226	ret = bh1780_write(bh1780, BH1780_REG_CONTROL, BH1780_POFF);
227	if (ret < 0) {
228		dev_err(dev, "failed to runtime suspend\n");
229		return ret;
230	}
231
232	return 0;
233}
234
235static int bh1780_runtime_resume(struct device *dev)
236{
237	struct i2c_client *client = to_i2c_client(dev);
238	struct iio_dev *indio_dev = i2c_get_clientdata(client);
239	struct bh1780_data *bh1780 = iio_priv(indio_dev);
240	int ret;
241
242	ret = bh1780_write(bh1780, BH1780_REG_CONTROL, BH1780_PON);
243	if (ret < 0) {
244		dev_err(dev, "failed to runtime resume\n");
245		return ret;
246	}
247
248	/* Wait for power on, then for a value to be available */
249	msleep(BH1780_PON_DELAY + BH1780_INTERVAL);
250
251	return 0;
252}
253
254static DEFINE_RUNTIME_DEV_PM_OPS(bh1780_dev_pm_ops, bh1780_runtime_suspend,
255				bh1780_runtime_resume, NULL);
256
257static const struct i2c_device_id bh1780_id[] = {
258	{ "bh1780" },
259	{ }
260};
261
262MODULE_DEVICE_TABLE(i2c, bh1780_id);
263
264static const struct of_device_id of_bh1780_match[] = {
265	{ .compatible = "rohm,bh1780gli", },
266	{ }
267};
268MODULE_DEVICE_TABLE(of, of_bh1780_match);
269
270static struct i2c_driver bh1780_driver = {
271	.probe		= bh1780_probe,
272	.remove		= bh1780_remove,
273	.id_table	= bh1780_id,
274	.driver = {
275		.name = "bh1780",
276		.pm = pm_ptr(&bh1780_dev_pm_ops),
277		.of_match_table = of_bh1780_match,
278	},
279};
280
281module_i2c_driver(bh1780_driver);
282
283MODULE_DESCRIPTION("ROHM BH1780GLI Ambient Light Sensor Driver");
284MODULE_LICENSE("GPL");
285MODULE_AUTHOR("Linus Walleij <linus.walleij@linaro.org>");
~/ Read-only file preview.