File Index
Files and directories
Sign in
FILE

al3000a.c

File preview with syntax highlighting.

linux-6.19.14/drivers/iio/light/al3000a.c C
  1// SPDX-License-Identifier: GPL-2.0-only
  2#include <linux/array_size.h>
  3#include <linux/bitfield.h>
  4#include <linux/device.h>
  5#include <linux/err.h>
  6#include <linux/i2c.h>
  7#include <linux/mod_devicetable.h>
  8#include <linux/module.h>
  9#include <linux/pm.h>
 10#include <linux/regmap.h>
 11#include <linux/regulator/consumer.h>
 12#include <linux/types.h>
 13
 14#include <linux/iio/iio.h>
 15
 16#define AL3000A_REG_SYSTEM		0x00
 17#define AL3000A_REG_DATA		0x05
 18
 19#define AL3000A_CONFIG_ENABLE		0x00
 20#define AL3000A_CONFIG_DISABLE		0x0b
 21#define AL3000A_CONFIG_RESET		0x0f
 22#define AL3000A_GAIN_MASK		GENMASK(5, 0)
 23
 24/*
 25 * These are pre-calculated lux values based on possible output of sensor
 26 * (range 0x00 - 0x3F)
 27 */
 28static const u32 lux_table[] = {
 29	1, 1, 1, 2, 2, 2, 3, 4,					/* 0 - 7 */
 30	4, 5, 6, 7, 9, 11, 13, 16,				/* 8 - 15 */
 31	19, 22, 27, 32, 39, 46, 56, 67,				/* 16 - 23 */
 32	80, 96, 116, 139, 167, 200, 240, 289,			/* 24 - 31 */
 33	347, 416, 499, 600, 720, 864, 1037, 1245,		/* 32 - 39 */
 34	1495, 1795, 2155, 2587, 3105, 3728, 4475, 5373,		/* 40 - 47 */
 35	6450, 7743, 9296, 11160, 13397, 16084, 19309, 23180,	/* 48 - 55 */
 36	27828, 33408, 40107, 48148, 57803, 69393, 83306, 100000 /* 56 - 63 */
 37};
 38
 39static const struct regmap_config al3000a_regmap_config = {
 40	.reg_bits = 8,
 41	.val_bits = 8,
 42	.max_register = AL3000A_REG_DATA,
 43};
 44
 45struct al3000a_data {
 46	struct regmap *regmap;
 47	struct regulator *vdd_supply;
 48};
 49
 50static const struct iio_chan_spec al3000a_channels[] = {
 51	{
 52		.type = IIO_LIGHT,
 53		.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
 54	},
 55};
 56
 57static int al3000a_set_pwr_on(struct al3000a_data *data)
 58{
 59	struct device *dev = regmap_get_device(data->regmap);
 60	int ret;
 61
 62	ret = regulator_enable(data->vdd_supply);
 63	if (ret) {
 64		dev_err(dev, "failed to enable vdd power supply\n");
 65		return ret;
 66	}
 67
 68	return regmap_write(data->regmap, AL3000A_REG_SYSTEM, AL3000A_CONFIG_ENABLE);
 69}
 70
 71static void al3000a_set_pwr_off(void *_data)
 72{
 73	struct al3000a_data *data = _data;
 74	struct device *dev = regmap_get_device(data->regmap);
 75	int ret;
 76
 77	ret = regmap_write(data->regmap, AL3000A_REG_SYSTEM, AL3000A_CONFIG_DISABLE);
 78	if (ret)
 79		dev_err(dev, "failed to write system register\n");
 80
 81	ret = regulator_disable(data->vdd_supply);
 82	if (ret)
 83		dev_err(dev, "failed to disable vdd power supply\n");
 84}
 85
 86static int al3000a_init(struct al3000a_data *data)
 87{
 88	struct device *dev = regmap_get_device(data->regmap);
 89	int ret;
 90
 91	ret = al3000a_set_pwr_on(data);
 92	if (ret)
 93		return ret;
 94
 95	ret = devm_add_action_or_reset(dev, al3000a_set_pwr_off, data);
 96	if (ret)
 97		return ret;
 98
 99	ret = regmap_write(data->regmap, AL3000A_REG_SYSTEM, AL3000A_CONFIG_RESET);
100	if (ret)
101		return ret;
102
103	return regmap_write(data->regmap, AL3000A_REG_SYSTEM, AL3000A_CONFIG_ENABLE);
104}
105
106static int al3000a_read_raw(struct iio_dev *indio_dev,
107			    struct iio_chan_spec const *chan, int *val,
108			    int *val2, long mask)
109{
110	struct al3000a_data *data = iio_priv(indio_dev);
111	int ret, gain;
112
113	switch (mask) {
114	case IIO_CHAN_INFO_PROCESSED:
115		ret = regmap_read(data->regmap, AL3000A_REG_DATA, &gain);
116		if (ret)
117			return ret;
118
119		*val = lux_table[gain & AL3000A_GAIN_MASK];
120
121		return IIO_VAL_INT;
122	default:
123		return -EINVAL;
124	}
125}
126
127static const struct iio_info al3000a_info = {
128	.read_raw = al3000a_read_raw,
129};
130
131static int al3000a_probe(struct i2c_client *client)
132{
133	struct al3000a_data *data;
134	struct device *dev = &client->dev;
135	struct iio_dev *indio_dev;
136	int ret;
137
138	indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
139	if (!indio_dev)
140		return -ENOMEM;
141
142	data = iio_priv(indio_dev);
143	i2c_set_clientdata(client, indio_dev);
144
145	data->regmap = devm_regmap_init_i2c(client, &al3000a_regmap_config);
146	if (IS_ERR(data->regmap))
147		return dev_err_probe(dev, PTR_ERR(data->regmap),
148				     "cannot allocate regmap\n");
149
150	data->vdd_supply = devm_regulator_get(dev, "vdd");
151	if (IS_ERR(data->vdd_supply))
152		return dev_err_probe(dev, PTR_ERR(data->vdd_supply),
153				     "failed to get vdd regulator\n");
154
155	indio_dev->info = &al3000a_info;
156	indio_dev->name = "al3000a";
157	indio_dev->channels = al3000a_channels;
158	indio_dev->num_channels = ARRAY_SIZE(al3000a_channels);
159	indio_dev->modes = INDIO_DIRECT_MODE;
160
161	ret = al3000a_init(data);
162	if (ret)
163		return dev_err_probe(dev, ret, "failed to init ALS\n");
164
165	return devm_iio_device_register(dev, indio_dev);
166}
167
168static int al3000a_suspend(struct device *dev)
169{
170	struct al3000a_data *data = iio_priv(dev_get_drvdata(dev));
171
172	al3000a_set_pwr_off(data);
173	return 0;
174}
175
176static int al3000a_resume(struct device *dev)
177{
178	struct al3000a_data *data = iio_priv(dev_get_drvdata(dev));
179
180	return al3000a_set_pwr_on(data);
181}
182
183static DEFINE_SIMPLE_DEV_PM_OPS(al3000a_pm_ops, al3000a_suspend, al3000a_resume);
184
185static const struct i2c_device_id al3000a_id[] = {
186	{ "al3000a" },
187	{ }
188};
189MODULE_DEVICE_TABLE(i2c, al3000a_id);
190
191static const struct of_device_id al3000a_of_match[] = {
192	{ .compatible = "dynaimage,al3000a" },
193	{ }
194};
195MODULE_DEVICE_TABLE(of, al3000a_of_match);
196
197static struct i2c_driver al3000a_driver = {
198	.driver = {
199		.name = "al3000a",
200		.of_match_table = al3000a_of_match,
201		.pm = pm_sleep_ptr(&al3000a_pm_ops),
202	},
203	.probe = al3000a_probe,
204	.id_table = al3000a_id,
205};
206module_i2c_driver(al3000a_driver);
207
208MODULE_AUTHOR("Svyatolsav Ryhel <clamor95@gmail.com>");
209MODULE_DESCRIPTION("al3000a Ambient Light Sensor driver");
210MODULE_LICENSE("GPL");
~/ Read-only file preview.