Skip to content

Commit 82e1ced

Browse files
javiercarrascocruzjic23
authored andcommitted
iio: light: veml3235: fix scale to conform to ABI
The current scale is not ABI-compliant as it is just the sensor gain instead of the value that acts as a multiplier to be applied to the raw value (there is no offset). Use the iio-gts helpers to obtain the proper scale values according to the gain and integration time to match the resolution tables from the datasheet. When at it, use 'scale' instead of 'gain' consistently for the get/set functions to avoid misunderstandings. Fixes: c5a23f8 ("iio: light: add support for veml3235") Reviewed-by: Matti Vaittinen <[email protected]> Signed-off-by: Javier Carrasco <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Jonathan Cameron <[email protected]>
1 parent 7716d08 commit 82e1ced

File tree

2 files changed

+130
-108
lines changed

2 files changed

+130
-108
lines changed

drivers/iio/light/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -669,6 +669,7 @@ config VCNL4035
669669
config VEML3235
670670
tristate "VEML3235 ambient light sensor"
671671
select REGMAP_I2C
672+
select IIO_GTS_HELPER
672673
depends on I2C
673674
help
674675
Say Y here if you want to build a driver for the Vishay VEML3235

drivers/iio/light/veml3235.c

Lines changed: 129 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include <linux/err.h>
1212
#include <linux/i2c.h>
1313
#include <linux/iio/iio.h>
14+
#include <linux/iio/iio-gts-helper.h>
1415
#include <linux/module.h>
1516
#include <linux/pm_runtime.h>
1617
#include <linux/regmap.h>
@@ -35,17 +36,33 @@ struct veml3235_data {
3536
struct device *dev;
3637
struct regmap *regmap;
3738
struct veml3235_rf rf;
39+
struct iio_gts gts;
3840
};
3941

40-
static const int veml3235_it_times[][2] = {
41-
{ 0, 50000 },
42-
{ 0, 100000 },
43-
{ 0, 200000 },
44-
{ 0, 400000 },
45-
{ 0, 800000 },
42+
static const struct iio_itime_sel_mul veml3235_it_sel[] = {
43+
GAIN_SCALE_ITIME_US(50000, 0, 1),
44+
GAIN_SCALE_ITIME_US(100000, 1, 2),
45+
GAIN_SCALE_ITIME_US(200000, 2, 4),
46+
GAIN_SCALE_ITIME_US(400000, 3, 8),
47+
GAIN_SCALE_ITIME_US(800000, 4, 16),
4648
};
4749

48-
static const int veml3235_scale_vals[] = { 1, 2, 4, 8 };
50+
/*
51+
* The MSB (DG) doubles the value of the rest of the field, which leads to
52+
* two possible combinations to obtain gain = 2 and gain = 4. The gain
53+
* handling can be simplified by restricting DG = 1 to the only gain that
54+
* really requires it, gain = 8. Note that "X10" is a reserved value.
55+
*/
56+
#define VEML3235_SEL_GAIN_X1 0
57+
#define VEML3235_SEL_GAIN_X2 1
58+
#define VEML3235_SEL_GAIN_X4 3
59+
#define VEML3235_SEL_GAIN_X8 7
60+
static const struct iio_gain_sel_pair veml3235_gain_sel[] = {
61+
GAIN_SCALE_GAIN(1, VEML3235_SEL_GAIN_X1),
62+
GAIN_SCALE_GAIN(2, VEML3235_SEL_GAIN_X2),
63+
GAIN_SCALE_GAIN(4, VEML3235_SEL_GAIN_X4),
64+
GAIN_SCALE_GAIN(8, VEML3235_SEL_GAIN_X8),
65+
};
4966

5067
static int veml3235_power_on(struct veml3235_data *data)
5168
{
@@ -142,32 +159,17 @@ static const struct regmap_config veml3235_regmap_config = {
142159

143160
static int veml3235_get_it(struct veml3235_data *data, int *val, int *val2)
144161
{
145-
int ret, reg;
162+
int ret, it_idx;
146163

147-
ret = regmap_field_read(data->rf.it, &reg);
164+
ret = regmap_field_read(data->rf.it, &it_idx);
148165
if (ret)
149166
return ret;
150167

151-
switch (reg) {
152-
case 0:
153-
*val2 = 50000;
154-
break;
155-
case 1:
156-
*val2 = 100000;
157-
break;
158-
case 2:
159-
*val2 = 200000;
160-
break;
161-
case 3:
162-
*val2 = 400000;
163-
break;
164-
case 4:
165-
*val2 = 800000;
166-
break;
167-
default:
168-
return -EINVAL;
169-
}
168+
ret = iio_gts_find_int_time_by_sel(&data->gts, it_idx);
169+
if (ret < 0)
170+
return ret;
170171

172+
*val2 = ret;
171173
*val = 0;
172174

173175
return IIO_VAL_INT_PLUS_MICRO;
@@ -176,104 +178,104 @@ static int veml3235_get_it(struct veml3235_data *data, int *val, int *val2)
176178
static int veml3235_set_it(struct iio_dev *indio_dev, int val, int val2)
177179
{
178180
struct veml3235_data *data = iio_priv(indio_dev);
179-
int ret, new_it;
181+
int ret, gain_idx, it_idx, new_gain, prev_gain, prev_it;
182+
bool in_range;
180183

181-
if (val)
184+
if (val || !iio_gts_valid_time(&data->gts, val2))
182185
return -EINVAL;
183186

184-
switch (val2) {
185-
case 50000:
186-
new_it = 0x00;
187-
break;
188-
case 100000:
189-
new_it = 0x01;
190-
break;
191-
case 200000:
192-
new_it = 0x02;
193-
break;
194-
case 400000:
195-
new_it = 0x03;
196-
break;
197-
case 800000:
198-
new_it = 0x04;
199-
break;
200-
default:
201-
return -EINVAL;
202-
}
187+
ret = regmap_field_read(data->rf.it, &it_idx);
188+
if (ret)
189+
return ret;
203190

204-
ret = regmap_field_write(data->rf.it, new_it);
205-
if (ret) {
206-
dev_err(data->dev,
207-
"failed to update integration time: %d\n", ret);
191+
ret = regmap_field_read(data->rf.gain, &gain_idx);
192+
if (ret)
208193
return ret;
209-
}
210194

211-
return 0;
195+
prev_it = iio_gts_find_int_time_by_sel(&data->gts, it_idx);
196+
if (prev_it < 0)
197+
return prev_it;
198+
199+
if (prev_it == val2)
200+
return 0;
201+
202+
prev_gain = iio_gts_find_gain_by_sel(&data->gts, gain_idx);
203+
if (prev_gain < 0)
204+
return prev_gain;
205+
206+
ret = iio_gts_find_new_gain_by_gain_time_min(&data->gts, prev_gain, prev_it,
207+
val2, &new_gain, &in_range);
208+
if (ret)
209+
return ret;
210+
211+
if (!in_range)
212+
dev_dbg(data->dev, "Optimal gain out of range\n");
213+
214+
ret = iio_gts_find_sel_by_int_time(&data->gts, val2);
215+
if (ret < 0)
216+
return ret;
217+
218+
ret = regmap_field_write(data->rf.it, ret);
219+
if (ret)
220+
return ret;
221+
222+
ret = iio_gts_find_sel_by_gain(&data->gts, new_gain);
223+
if (ret < 0)
224+
return ret;
225+
226+
return regmap_field_write(data->rf.gain, ret);
212227
}
213228

214-
static int veml3235_set_gain(struct iio_dev *indio_dev, int val, int val2)
229+
static int veml3235_set_scale(struct iio_dev *indio_dev, int val, int val2)
215230
{
216231
struct veml3235_data *data = iio_priv(indio_dev);
217-
int ret, new_gain;
232+
int ret, it_idx, gain_sel, time_sel;
218233

219-
if (val2 != 0)
220-
return -EINVAL;
234+
ret = regmap_field_read(data->rf.it, &it_idx);
235+
if (ret)
236+
return ret;
221237

222-
switch (val) {
223-
case 1:
224-
new_gain = 0x00;
225-
break;
226-
case 2:
227-
new_gain = 0x01;
228-
break;
229-
case 4:
230-
new_gain = 0x03;
231-
break;
232-
case 8:
233-
new_gain = 0x07;
234-
break;
235-
default:
236-
return -EINVAL;
237-
}
238+
ret = iio_gts_find_gain_time_sel_for_scale(&data->gts, val, val2,
239+
&gain_sel, &time_sel);
240+
if (ret)
241+
return ret;
238242

239-
ret = regmap_field_write(data->rf.gain, new_gain);
240-
if (ret) {
241-
dev_err(data->dev, "failed to set gain: %d\n", ret);
243+
ret = regmap_field_write(data->rf.it, time_sel);
244+
if (ret)
242245
return ret;
243-
}
244246

245-
return 0;
247+
return regmap_field_write(data->rf.gain, gain_sel);
246248
}
247249

248-
static int veml3235_get_gain(struct veml3235_data *data, int *val)
250+
static int veml3235_get_scale(struct veml3235_data *data, int *val, int *val2)
249251
{
250-
int ret, reg;
252+
int gain, it, reg, ret;
251253

252254
ret = regmap_field_read(data->rf.gain, &reg);
253255
if (ret) {
254256
dev_err(data->dev, "failed to read gain %d\n", ret);
255257
return ret;
256258
}
257259

258-
switch (reg & 0x03) {
259-
case 0:
260-
*val = 1;
261-
break;
262-
case 1:
263-
*val = 2;
264-
break;
265-
case 3:
266-
*val = 4;
267-
break;
268-
default:
269-
return -EINVAL;
260+
gain = iio_gts_find_gain_by_sel(&data->gts, reg);
261+
if (gain < 0)
262+
return gain;
263+
264+
ret = regmap_field_read(data->rf.it, &reg);
265+
if (ret) {
266+
dev_err(data->dev, "failed to read integration time %d\n", ret);
267+
return ret;
270268
}
271269

272-
/* Double gain */
273-
if (reg & 0x04)
274-
*val *= 2;
270+
it = iio_gts_find_int_time_by_sel(&data->gts, reg);
271+
if (it < 0)
272+
return it;
275273

276-
return IIO_VAL_INT;
274+
ret = iio_gts_get_scale(&data->gts, gain, it, val, val2);
275+
if (ret)
276+
return ret;
277+
278+
return IIO_VAL_INT_PLUS_NANO;
277279
}
278280

279281
static int veml3235_read_raw(struct iio_dev *indio_dev,
@@ -307,7 +309,7 @@ static int veml3235_read_raw(struct iio_dev *indio_dev,
307309
case IIO_CHAN_INFO_INT_TIME:
308310
return veml3235_get_it(data, val, val2);
309311
case IIO_CHAN_INFO_SCALE:
310-
return veml3235_get_gain(data, val);
312+
return veml3235_get_scale(data, val, val2);
311313
default:
312314
return -EINVAL;
313315
}
@@ -318,17 +320,27 @@ static int veml3235_read_avail(struct iio_dev *indio_dev,
318320
const int **vals, int *type, int *length,
319321
long mask)
320322
{
323+
struct veml3235_data *data = iio_priv(indio_dev);
324+
321325
switch (mask) {
322326
case IIO_CHAN_INFO_INT_TIME:
323-
*vals = (int *)&veml3235_it_times;
324-
*length = 2 * ARRAY_SIZE(veml3235_it_times);
325-
*type = IIO_VAL_INT_PLUS_MICRO;
326-
return IIO_AVAIL_LIST;
327+
return iio_gts_avail_times(&data->gts, vals, type, length);
327328
case IIO_CHAN_INFO_SCALE:
328-
*vals = (int *)&veml3235_scale_vals;
329-
*length = ARRAY_SIZE(veml3235_scale_vals);
330-
*type = IIO_VAL_INT;
331-
return IIO_AVAIL_LIST;
329+
return iio_gts_all_avail_scales(&data->gts, vals, type, length);
330+
default:
331+
return -EINVAL;
332+
}
333+
}
334+
335+
static int veml3235_write_raw_get_fmt(struct iio_dev *indio_dev,
336+
struct iio_chan_spec const *chan,
337+
long mask)
338+
{
339+
switch (mask) {
340+
case IIO_CHAN_INFO_SCALE:
341+
return IIO_VAL_INT_PLUS_NANO;
342+
case IIO_CHAN_INFO_INT_TIME:
343+
return IIO_VAL_INT_PLUS_MICRO;
332344
default:
333345
return -EINVAL;
334346
}
@@ -342,7 +354,7 @@ static int veml3235_write_raw(struct iio_dev *indio_dev,
342354
case IIO_CHAN_INFO_INT_TIME:
343355
return veml3235_set_it(indio_dev, val, val2);
344356
case IIO_CHAN_INFO_SCALE:
345-
return veml3235_set_gain(indio_dev, val, val2);
357+
return veml3235_set_scale(indio_dev, val, val2);
346358
}
347359

348360
return -EINVAL;
@@ -402,6 +414,13 @@ static int veml3235_hw_init(struct iio_dev *indio_dev)
402414
struct device *dev = data->dev;
403415
int ret;
404416

417+
ret = devm_iio_init_iio_gts(data->dev, 0, 272640000,
418+
veml3235_gain_sel, ARRAY_SIZE(veml3235_gain_sel),
419+
veml3235_it_sel, ARRAY_SIZE(veml3235_it_sel),
420+
&data->gts);
421+
if (ret)
422+
return dev_err_probe(data->dev, ret, "failed to init iio gts\n");
423+
405424
/* Set gain to 1 and integration time to 100 ms */
406425
ret = regmap_field_write(data->rf.gain, 0x00);
407426
if (ret)
@@ -423,6 +442,7 @@ static const struct iio_info veml3235_info = {
423442
.read_raw = veml3235_read_raw,
424443
.read_avail = veml3235_read_avail,
425444
.write_raw = veml3235_write_raw,
445+
.write_raw_get_fmt = veml3235_write_raw_get_fmt,
426446
};
427447

428448
static int veml3235_probe(struct i2c_client *client)
@@ -524,3 +544,4 @@ module_i2c_driver(veml3235_driver);
524544
MODULE_AUTHOR("Javier Carrasco <[email protected]>");
525545
MODULE_DESCRIPTION("VEML3235 Ambient Light Sensor");
526546
MODULE_LICENSE("GPL");
547+
MODULE_IMPORT_NS("IIO_GTS_HELPER");

0 commit comments

Comments
 (0)