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
5067static int veml3235_power_on (struct veml3235_data * data )
5168{
@@ -142,32 +159,17 @@ static const struct regmap_config veml3235_regmap_config = {
142159
143160static 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)
176178static 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
279281static 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
428448static int veml3235_probe (struct i2c_client * client )
@@ -524,3 +544,4 @@ module_i2c_driver(veml3235_driver);
524544MODULE_AUTHOR (
"Javier Carrasco <[email protected] >" );
525545MODULE_DESCRIPTION ("VEML3235 Ambient Light Sensor" );
526546MODULE_LICENSE ("GPL" );
547+ MODULE_IMPORT_NS ("IIO_GTS_HELPER" );
0 commit comments