ltr390.c (13fad2607dad14afd0633d9c869499f6e7c998bd) ltr390.c (14e0d914a855f9ad2669c0a2ed35f0003f771be5)
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * IIO driver for Lite-On LTR390 ALS and UV sensor
4 * (7-bit I2C slave address 0x53)
5 *
6 * Based on the work of:
7 * Shreeya Patel and Shi Zhigang (LTRF216 Driver)
8 *

--- 49 unchanged lines hidden (view full) ---

58
59/*
60 * Window Factor is needed when the device is under Window glass with coated
61 * tinted ink. This is to compensate for the light loss due to the lower
62 * transmission rate of the window glass and helps * in calculating lux.
63 */
64#define LTR390_WINDOW_FACTOR 1
65
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * IIO driver for Lite-On LTR390 ALS and UV sensor
4 * (7-bit I2C slave address 0x53)
5 *
6 * Based on the work of:
7 * Shreeya Patel and Shi Zhigang (LTRF216 Driver)
8 *

--- 49 unchanged lines hidden (view full) ---

58
59/*
60 * Window Factor is needed when the device is under Window glass with coated
61 * tinted ink. This is to compensate for the light loss due to the lower
62 * transmission rate of the window glass and helps * in calculating lux.
63 */
64#define LTR390_WINDOW_FACTOR 1
65
66enum ltr390_mode {
67 LTR390_SET_ALS_MODE,
68 LTR390_SET_UVS_MODE,
69};
70
66struct ltr390_data {
67 struct regmap *regmap;
68 struct i2c_client *client;
69 /* Protects device from simulataneous reads */
70 struct mutex lock;
71struct ltr390_data {
72 struct regmap *regmap;
73 struct i2c_client *client;
74 /* Protects device from simulataneous reads */
75 struct mutex lock;
76 enum ltr390_mode mode;
71 int gain;
72 int int_time_us;
73};
74
75static const struct regmap_config ltr390_regmap_config = {
76 .name = "ltr390",
77 .reg_bits = 8,
78 .reg_stride = 1,

--- 11 unchanged lines hidden (view full) ---

90 if (ret) {
91 dev_err(dev, "failed to read measurement data");
92 return ret;
93 }
94
95 return get_unaligned_le24(recieve_buffer);
96}
97
77 int gain;
78 int int_time_us;
79};
80
81static const struct regmap_config ltr390_regmap_config = {
82 .name = "ltr390",
83 .reg_bits = 8,
84 .reg_stride = 1,

--- 11 unchanged lines hidden (view full) ---

96 if (ret) {
97 dev_err(dev, "failed to read measurement data");
98 return ret;
99 }
100
101 return get_unaligned_le24(recieve_buffer);
102}
103
104static int ltr390_set_mode(struct ltr390_data *data, enum ltr390_mode mode)
105{
106 int ret;
107
108 if (data->mode == mode)
109 return 0;
110
111 switch (mode) {
112 case LTR390_SET_ALS_MODE:
113 ret = regmap_clear_bits(data->regmap, LTR390_MAIN_CTRL, LTR390_UVS_MODE);
114 break;
115
116 case LTR390_SET_UVS_MODE:
117 ret = regmap_set_bits(data->regmap, LTR390_MAIN_CTRL, LTR390_UVS_MODE);
118 break;
119 }
120
121 if (ret)
122 return ret;
123
124 data->mode = mode;
125 return 0;
126}
127
98static int ltr390_read_raw(struct iio_dev *iio_device,
99 struct iio_chan_spec const *chan, int *val,
100 int *val2, long mask)
101{
102 int ret;
103 struct ltr390_data *data = iio_priv(iio_device);
104
105 guard(mutex)(&data->lock);
106 switch (mask) {
107 case IIO_CHAN_INFO_RAW:
128static int ltr390_read_raw(struct iio_dev *iio_device,
129 struct iio_chan_spec const *chan, int *val,
130 int *val2, long mask)
131{
132 int ret;
133 struct ltr390_data *data = iio_priv(iio_device);
134
135 guard(mutex)(&data->lock);
136 switch (mask) {
137 case IIO_CHAN_INFO_RAW:
108 ret = ltr390_register_read(data, LTR390_UVS_DATA);
109 if (ret < 0)
110 return ret;
138 switch (chan->type) {
139 case IIO_UVINDEX:
140 ret = ltr390_set_mode(data, LTR390_SET_UVS_MODE);
141 if (ret < 0)
142 return ret;
143
144 ret = ltr390_register_read(data, LTR390_UVS_DATA);
145 if (ret < 0)
146 return ret;
147 break;
148
149 case IIO_LIGHT:
150 ret = ltr390_set_mode(data, LTR390_SET_ALS_MODE);
151 if (ret < 0)
152 return ret;
153
154 ret = ltr390_register_read(data, LTR390_ALS_DATA);
155 if (ret < 0)
156 return ret;
157 break;
158
159 default:
160 return -EINVAL;
161 }
111 *val = ret;
112 return IIO_VAL_INT;
113 case IIO_CHAN_INFO_SCALE:
162 *val = ret;
163 return IIO_VAL_INT;
164 case IIO_CHAN_INFO_SCALE:
114 *val = LTR390_WINDOW_FACTOR;
115 *val2 = LTR390_COUNTS_PER_UVI;
116 return IIO_VAL_FRACTIONAL;
165 switch (chan->type) {
166 case IIO_UVINDEX:
167 *val = LTR390_WINDOW_FACTOR;
168 *val2 = LTR390_COUNTS_PER_UVI;
169 return IIO_VAL_FRACTIONAL;
117
170
171 case IIO_LIGHT:
172 *val = LTR390_WINDOW_FACTOR * 6 * 100;
173 *val2 = data->gain * data->int_time_us;
174 return IIO_VAL_FRACTIONAL;
175
176 default:
177 return -EINVAL;
178 }
179
118 case IIO_CHAN_INFO_INT_TIME:
119 *val = data->int_time_us;
120 return IIO_VAL_INT;
121
122 default:
123 return -EINVAL;
124 }
125}
126
127/* integration time in us */
128static const int ltr390_int_time_map_us[] = { 400000, 200000, 100000, 50000, 25000, 12500 };
129static const int ltr390_gain_map[] = { 1, 3, 6, 9, 18 };
130
180 case IIO_CHAN_INFO_INT_TIME:
181 *val = data->int_time_us;
182 return IIO_VAL_INT;
183
184 default:
185 return -EINVAL;
186 }
187}
188
189/* integration time in us */
190static const int ltr390_int_time_map_us[] = { 400000, 200000, 100000, 50000, 25000, 12500 };
191static const int ltr390_gain_map[] = { 1, 3, 6, 9, 18 };
192
131static const struct iio_chan_spec ltr390_channel = {
132 .type = IIO_UVINDEX,
133 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
134 .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME),
135 .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_INT_TIME) | BIT(IIO_CHAN_INFO_SCALE)
193static const struct iio_chan_spec ltr390_channels[] = {
194 /* UV sensor */
195 {
196 .type = IIO_UVINDEX,
197 .scan_index = 0,
198 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
199 .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME),
200 .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_INT_TIME) | BIT(IIO_CHAN_INFO_SCALE)
201 },
202 /* ALS sensor */
203 {
204 .type = IIO_LIGHT,
205 .scan_index = 1,
206 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
207 .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME),
208 .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_INT_TIME) | BIT(IIO_CHAN_INFO_SCALE)
209 },
136};
137
138static int ltr390_set_gain(struct ltr390_data *data, int val)
139{
140 int ret, idx;
141
142 for (idx = 0; idx < ARRAY_SIZE(ltr390_gain_map); idx++) {
143 if (ltr390_gain_map[idx] != val)

--- 103 unchanged lines hidden (view full) ---

247 return dev_err_probe(dev, PTR_ERR(data->regmap),
248 "regmap initialization failed\n");
249
250 data->client = client;
251 /* default value of integration time from pg: 15 of the datasheet */
252 data->int_time_us = 100000;
253 /* default value of gain from pg: 16 of the datasheet */
254 data->gain = 3;
210};
211
212static int ltr390_set_gain(struct ltr390_data *data, int val)
213{
214 int ret, idx;
215
216 for (idx = 0; idx < ARRAY_SIZE(ltr390_gain_map); idx++) {
217 if (ltr390_gain_map[idx] != val)

--- 103 unchanged lines hidden (view full) ---

321 return dev_err_probe(dev, PTR_ERR(data->regmap),
322 "regmap initialization failed\n");
323
324 data->client = client;
325 /* default value of integration time from pg: 15 of the datasheet */
326 data->int_time_us = 100000;
327 /* default value of gain from pg: 16 of the datasheet */
328 data->gain = 3;
329 /* default mode for ltr390 is ALS mode */
330 data->mode = LTR390_SET_ALS_MODE;
255
256 mutex_init(&data->lock);
257
258 indio_dev->info = &ltr390_info;
331
332 mutex_init(&data->lock);
333
334 indio_dev->info = &ltr390_info;
259 indio_dev->channels = &ltr390_channel;
260 indio_dev->num_channels = 1;
335 indio_dev->channels = ltr390_channels;
336 indio_dev->num_channels = ARRAY_SIZE(ltr390_channels);
261 indio_dev->name = "ltr390";
262
263 ret = regmap_read(data->regmap, LTR390_PART_ID, &part_number);
264 if (ret)
265 return dev_err_probe(dev, ret,
266 "failed to get sensor's part id\n");
267 /* Lower 4 bits of `part_number` change with hardware revisions */
268 if (part_number >> 4 != LTR390_PART_NUMBER_ID)
269 dev_info(dev, "received invalid product id: 0x%x", part_number);
270 dev_dbg(dev, "LTR390, product id: 0x%x\n", part_number);
271
272 /* reset sensor, chip fails to respond to this, so ignore any errors */
273 regmap_set_bits(data->regmap, LTR390_MAIN_CTRL, LTR390_SW_RESET);
274
275 /* Wait for the registers to reset before proceeding */
276 usleep_range(1000, 2000);
277
337 indio_dev->name = "ltr390";
338
339 ret = regmap_read(data->regmap, LTR390_PART_ID, &part_number);
340 if (ret)
341 return dev_err_probe(dev, ret,
342 "failed to get sensor's part id\n");
343 /* Lower 4 bits of `part_number` change with hardware revisions */
344 if (part_number >> 4 != LTR390_PART_NUMBER_ID)
345 dev_info(dev, "received invalid product id: 0x%x", part_number);
346 dev_dbg(dev, "LTR390, product id: 0x%x\n", part_number);
347
348 /* reset sensor, chip fails to respond to this, so ignore any errors */
349 regmap_set_bits(data->regmap, LTR390_MAIN_CTRL, LTR390_SW_RESET);
350
351 /* Wait for the registers to reset before proceeding */
352 usleep_range(1000, 2000);
353
278 ret = regmap_set_bits(data->regmap, LTR390_MAIN_CTRL,
279 LTR390_SENSOR_ENABLE | LTR390_UVS_MODE);
354 ret = regmap_set_bits(data->regmap, LTR390_MAIN_CTRL, LTR390_SENSOR_ENABLE);
280 if (ret)
281 return dev_err_probe(dev, ret, "failed to enable the sensor\n");
282
283 return devm_iio_device_register(dev, indio_dev);
284}
285
286static const struct i2c_device_id ltr390_id[] = {
287 { "ltr390" },

--- 23 unchanged lines hidden ---
355 if (ret)
356 return dev_err_probe(dev, ret, "failed to enable the sensor\n");
357
358 return devm_iio_device_register(dev, indio_dev);
359}
360
361static const struct i2c_device_id ltr390_id[] = {
362 { "ltr390" },

--- 23 unchanged lines hidden ---