1c5a23f80SJavier Carrasco // SPDX-License-Identifier: GPL-2.0+ 2c5a23f80SJavier Carrasco /* 3c5a23f80SJavier Carrasco * VEML3235 Ambient Light Sensor 4c5a23f80SJavier Carrasco * 5c5a23f80SJavier Carrasco * Copyright (c) 2024, Javier Carrasco <javier.carrasco.cruz@gmail.com> 6c5a23f80SJavier Carrasco * 7c5a23f80SJavier Carrasco * Datasheet: https://www.vishay.com/docs/80131/veml3235.pdf 8c5a23f80SJavier Carrasco * Appnote-80222: https://www.vishay.com/docs/80222/designingveml3235.pdf 9c5a23f80SJavier Carrasco */ 10c5a23f80SJavier Carrasco 11c5a23f80SJavier Carrasco #include <linux/err.h> 12c5a23f80SJavier Carrasco #include <linux/i2c.h> 13c5a23f80SJavier Carrasco #include <linux/iio/iio.h> 14*82e1cedeSJavier Carrasco #include <linux/iio/iio-gts-helper.h> 15c5a23f80SJavier Carrasco #include <linux/module.h> 16c5a23f80SJavier Carrasco #include <linux/pm_runtime.h> 17c5a23f80SJavier Carrasco #include <linux/regmap.h> 18c5a23f80SJavier Carrasco #include <linux/regulator/consumer.h> 19c5a23f80SJavier Carrasco 20c5a23f80SJavier Carrasco #define VEML3235_REG_CONF 0x00 21c5a23f80SJavier Carrasco #define VEML3235_REG_WH_DATA 0x04 22c5a23f80SJavier Carrasco #define VEML3235_REG_ALS_DATA 0x05 23c5a23f80SJavier Carrasco #define VEML3235_REG_ID 0x09 24c5a23f80SJavier Carrasco 25c5a23f80SJavier Carrasco #define VEML3235_CONF_SD BIT(0) 26c5a23f80SJavier Carrasco #define VEML3235_CONF_SD0 BIT(15) 27c5a23f80SJavier Carrasco 28c5a23f80SJavier Carrasco struct veml3235_rf { 29c5a23f80SJavier Carrasco struct regmap_field *it; 30c5a23f80SJavier Carrasco struct regmap_field *gain; 31c5a23f80SJavier Carrasco struct regmap_field *id; 32c5a23f80SJavier Carrasco }; 33c5a23f80SJavier Carrasco 34c5a23f80SJavier Carrasco struct veml3235_data { 35c5a23f80SJavier Carrasco struct i2c_client *client; 36c5a23f80SJavier Carrasco struct device *dev; 37c5a23f80SJavier Carrasco struct regmap *regmap; 38c5a23f80SJavier Carrasco struct veml3235_rf rf; 39*82e1cedeSJavier Carrasco struct iio_gts gts; 40c5a23f80SJavier Carrasco }; 41c5a23f80SJavier Carrasco 42*82e1cedeSJavier Carrasco static const struct iio_itime_sel_mul veml3235_it_sel[] = { 43*82e1cedeSJavier Carrasco GAIN_SCALE_ITIME_US(50000, 0, 1), 44*82e1cedeSJavier Carrasco GAIN_SCALE_ITIME_US(100000, 1, 2), 45*82e1cedeSJavier Carrasco GAIN_SCALE_ITIME_US(200000, 2, 4), 46*82e1cedeSJavier Carrasco GAIN_SCALE_ITIME_US(400000, 3, 8), 47*82e1cedeSJavier Carrasco GAIN_SCALE_ITIME_US(800000, 4, 16), 48c5a23f80SJavier Carrasco }; 49c5a23f80SJavier Carrasco 50*82e1cedeSJavier Carrasco /* 51*82e1cedeSJavier Carrasco * The MSB (DG) doubles the value of the rest of the field, which leads to 52*82e1cedeSJavier Carrasco * two possible combinations to obtain gain = 2 and gain = 4. The gain 53*82e1cedeSJavier Carrasco * handling can be simplified by restricting DG = 1 to the only gain that 54*82e1cedeSJavier Carrasco * really requires it, gain = 8. Note that "X10" is a reserved value. 55*82e1cedeSJavier Carrasco */ 56*82e1cedeSJavier Carrasco #define VEML3235_SEL_GAIN_X1 0 57*82e1cedeSJavier Carrasco #define VEML3235_SEL_GAIN_X2 1 58*82e1cedeSJavier Carrasco #define VEML3235_SEL_GAIN_X4 3 59*82e1cedeSJavier Carrasco #define VEML3235_SEL_GAIN_X8 7 60*82e1cedeSJavier Carrasco static const struct iio_gain_sel_pair veml3235_gain_sel[] = { 61*82e1cedeSJavier Carrasco GAIN_SCALE_GAIN(1, VEML3235_SEL_GAIN_X1), 62*82e1cedeSJavier Carrasco GAIN_SCALE_GAIN(2, VEML3235_SEL_GAIN_X2), 63*82e1cedeSJavier Carrasco GAIN_SCALE_GAIN(4, VEML3235_SEL_GAIN_X4), 64*82e1cedeSJavier Carrasco GAIN_SCALE_GAIN(8, VEML3235_SEL_GAIN_X8), 65*82e1cedeSJavier Carrasco }; 66c5a23f80SJavier Carrasco 67c5a23f80SJavier Carrasco static int veml3235_power_on(struct veml3235_data *data) 68c5a23f80SJavier Carrasco { 69c5a23f80SJavier Carrasco int ret; 70c5a23f80SJavier Carrasco 71c5a23f80SJavier Carrasco ret = regmap_clear_bits(data->regmap, VEML3235_REG_CONF, 72c5a23f80SJavier Carrasco VEML3235_CONF_SD | VEML3235_CONF_SD0); 73c5a23f80SJavier Carrasco if (ret) 74c5a23f80SJavier Carrasco return ret; 75c5a23f80SJavier Carrasco 76c5a23f80SJavier Carrasco /* Wait 4 ms to let processor & oscillator start correctly */ 77c5a23f80SJavier Carrasco fsleep(4000); 78c5a23f80SJavier Carrasco 79c5a23f80SJavier Carrasco return 0; 80c5a23f80SJavier Carrasco } 81c5a23f80SJavier Carrasco 82c5a23f80SJavier Carrasco static int veml3235_shut_down(struct veml3235_data *data) 83c5a23f80SJavier Carrasco { 84c5a23f80SJavier Carrasco return regmap_set_bits(data->regmap, VEML3235_REG_CONF, 85c5a23f80SJavier Carrasco VEML3235_CONF_SD | VEML3235_CONF_SD0); 86c5a23f80SJavier Carrasco } 87c5a23f80SJavier Carrasco 88c5a23f80SJavier Carrasco static void veml3235_shut_down_action(void *data) 89c5a23f80SJavier Carrasco { 90c5a23f80SJavier Carrasco veml3235_shut_down(data); 91c5a23f80SJavier Carrasco } 92c5a23f80SJavier Carrasco 93c5a23f80SJavier Carrasco enum veml3235_chan { 94c5a23f80SJavier Carrasco CH_ALS, 95c5a23f80SJavier Carrasco CH_WHITE, 96c5a23f80SJavier Carrasco }; 97c5a23f80SJavier Carrasco 98c5a23f80SJavier Carrasco static const struct iio_chan_spec veml3235_channels[] = { 99c5a23f80SJavier Carrasco { 100c5a23f80SJavier Carrasco .type = IIO_LIGHT, 101c5a23f80SJavier Carrasco .channel = CH_ALS, 102c5a23f80SJavier Carrasco .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), 103c5a23f80SJavier Carrasco .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME) | 104c5a23f80SJavier Carrasco BIT(IIO_CHAN_INFO_SCALE), 105c5a23f80SJavier Carrasco .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_INT_TIME) | 106c5a23f80SJavier Carrasco BIT(IIO_CHAN_INFO_SCALE), 107c5a23f80SJavier Carrasco }, 108c5a23f80SJavier Carrasco { 109c5a23f80SJavier Carrasco .type = IIO_INTENSITY, 110c5a23f80SJavier Carrasco .channel = CH_WHITE, 111c5a23f80SJavier Carrasco .modified = 1, 112c5a23f80SJavier Carrasco .channel2 = IIO_MOD_LIGHT_BOTH, 113c5a23f80SJavier Carrasco .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), 114c5a23f80SJavier Carrasco .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME) | 115c5a23f80SJavier Carrasco BIT(IIO_CHAN_INFO_SCALE), 116c5a23f80SJavier Carrasco .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_INT_TIME) | 117c5a23f80SJavier Carrasco BIT(IIO_CHAN_INFO_SCALE), 118c5a23f80SJavier Carrasco }, 119c5a23f80SJavier Carrasco }; 120c5a23f80SJavier Carrasco 121627f3c41SJavier Carrasco static const struct regmap_range veml3235_readable_ranges[] = { 122627f3c41SJavier Carrasco regmap_reg_range(VEML3235_REG_CONF, VEML3235_REG_ID), 123627f3c41SJavier Carrasco }; 124627f3c41SJavier Carrasco 125627f3c41SJavier Carrasco static const struct regmap_access_table veml3235_readable_table = { 126627f3c41SJavier Carrasco .yes_ranges = veml3235_readable_ranges, 127627f3c41SJavier Carrasco .n_yes_ranges = ARRAY_SIZE(veml3235_readable_ranges), 128627f3c41SJavier Carrasco }; 129627f3c41SJavier Carrasco 130627f3c41SJavier Carrasco static const struct regmap_range veml3235_writable_ranges[] = { 131627f3c41SJavier Carrasco regmap_reg_range(VEML3235_REG_CONF, VEML3235_REG_CONF), 132627f3c41SJavier Carrasco }; 133627f3c41SJavier Carrasco 134627f3c41SJavier Carrasco static const struct regmap_access_table veml3235_writable_table = { 135627f3c41SJavier Carrasco .yes_ranges = veml3235_writable_ranges, 136627f3c41SJavier Carrasco .n_yes_ranges = ARRAY_SIZE(veml3235_writable_ranges), 137627f3c41SJavier Carrasco }; 138627f3c41SJavier Carrasco 139627f3c41SJavier Carrasco static const struct regmap_range veml3235_volatile_ranges[] = { 140627f3c41SJavier Carrasco regmap_reg_range(VEML3235_REG_WH_DATA, VEML3235_REG_ALS_DATA), 141627f3c41SJavier Carrasco }; 142627f3c41SJavier Carrasco 143627f3c41SJavier Carrasco static const struct regmap_access_table veml3235_volatile_table = { 144627f3c41SJavier Carrasco .yes_ranges = veml3235_volatile_ranges, 145627f3c41SJavier Carrasco .n_yes_ranges = ARRAY_SIZE(veml3235_volatile_ranges), 146627f3c41SJavier Carrasco }; 147627f3c41SJavier Carrasco 148c5a23f80SJavier Carrasco static const struct regmap_config veml3235_regmap_config = { 149c5a23f80SJavier Carrasco .name = "veml3235_regmap", 150c5a23f80SJavier Carrasco .reg_bits = 8, 151c5a23f80SJavier Carrasco .val_bits = 16, 152c5a23f80SJavier Carrasco .max_register = VEML3235_REG_ID, 153c5a23f80SJavier Carrasco .val_format_endian = REGMAP_ENDIAN_LITTLE, 154627f3c41SJavier Carrasco .rd_table = &veml3235_readable_table, 155627f3c41SJavier Carrasco .wr_table = &veml3235_writable_table, 156627f3c41SJavier Carrasco .volatile_table = &veml3235_volatile_table, 157627f3c41SJavier Carrasco .cache_type = REGCACHE_RBTREE, 158c5a23f80SJavier Carrasco }; 159c5a23f80SJavier Carrasco 160c5a23f80SJavier Carrasco static int veml3235_get_it(struct veml3235_data *data, int *val, int *val2) 161c5a23f80SJavier Carrasco { 162*82e1cedeSJavier Carrasco int ret, it_idx; 163c5a23f80SJavier Carrasco 164*82e1cedeSJavier Carrasco ret = regmap_field_read(data->rf.it, &it_idx); 165c5a23f80SJavier Carrasco if (ret) 166c5a23f80SJavier Carrasco return ret; 167c5a23f80SJavier Carrasco 168*82e1cedeSJavier Carrasco ret = iio_gts_find_int_time_by_sel(&data->gts, it_idx); 169*82e1cedeSJavier Carrasco if (ret < 0) 170*82e1cedeSJavier Carrasco return ret; 171c5a23f80SJavier Carrasco 172*82e1cedeSJavier Carrasco *val2 = ret; 173c5a23f80SJavier Carrasco *val = 0; 174c5a23f80SJavier Carrasco 175c5a23f80SJavier Carrasco return IIO_VAL_INT_PLUS_MICRO; 176c5a23f80SJavier Carrasco } 177c5a23f80SJavier Carrasco 178c5a23f80SJavier Carrasco static int veml3235_set_it(struct iio_dev *indio_dev, int val, int val2) 179c5a23f80SJavier Carrasco { 180c5a23f80SJavier Carrasco struct veml3235_data *data = iio_priv(indio_dev); 181*82e1cedeSJavier Carrasco int ret, gain_idx, it_idx, new_gain, prev_gain, prev_it; 182*82e1cedeSJavier Carrasco bool in_range; 183c5a23f80SJavier Carrasco 184*82e1cedeSJavier Carrasco if (val || !iio_gts_valid_time(&data->gts, val2)) 185c5a23f80SJavier Carrasco return -EINVAL; 186c5a23f80SJavier Carrasco 187*82e1cedeSJavier Carrasco ret = regmap_field_read(data->rf.it, &it_idx); 188*82e1cedeSJavier Carrasco if (ret) 189c5a23f80SJavier Carrasco return ret; 190c5a23f80SJavier Carrasco 191*82e1cedeSJavier Carrasco ret = regmap_field_read(data->rf.gain, &gain_idx); 192*82e1cedeSJavier Carrasco if (ret) 193*82e1cedeSJavier Carrasco return ret; 194*82e1cedeSJavier Carrasco 195*82e1cedeSJavier Carrasco prev_it = iio_gts_find_int_time_by_sel(&data->gts, it_idx); 196*82e1cedeSJavier Carrasco if (prev_it < 0) 197*82e1cedeSJavier Carrasco return prev_it; 198*82e1cedeSJavier Carrasco 199*82e1cedeSJavier Carrasco if (prev_it == val2) 200c5a23f80SJavier Carrasco return 0; 201*82e1cedeSJavier Carrasco 202*82e1cedeSJavier Carrasco prev_gain = iio_gts_find_gain_by_sel(&data->gts, gain_idx); 203*82e1cedeSJavier Carrasco if (prev_gain < 0) 204*82e1cedeSJavier Carrasco return prev_gain; 205*82e1cedeSJavier Carrasco 206*82e1cedeSJavier Carrasco ret = iio_gts_find_new_gain_by_gain_time_min(&data->gts, prev_gain, prev_it, 207*82e1cedeSJavier Carrasco val2, &new_gain, &in_range); 208*82e1cedeSJavier Carrasco if (ret) 209*82e1cedeSJavier Carrasco return ret; 210*82e1cedeSJavier Carrasco 211*82e1cedeSJavier Carrasco if (!in_range) 212*82e1cedeSJavier Carrasco dev_dbg(data->dev, "Optimal gain out of range\n"); 213*82e1cedeSJavier Carrasco 214*82e1cedeSJavier Carrasco ret = iio_gts_find_sel_by_int_time(&data->gts, val2); 215*82e1cedeSJavier Carrasco if (ret < 0) 216*82e1cedeSJavier Carrasco return ret; 217*82e1cedeSJavier Carrasco 218*82e1cedeSJavier Carrasco ret = regmap_field_write(data->rf.it, ret); 219*82e1cedeSJavier Carrasco if (ret) 220*82e1cedeSJavier Carrasco return ret; 221*82e1cedeSJavier Carrasco 222*82e1cedeSJavier Carrasco ret = iio_gts_find_sel_by_gain(&data->gts, new_gain); 223*82e1cedeSJavier Carrasco if (ret < 0) 224*82e1cedeSJavier Carrasco return ret; 225*82e1cedeSJavier Carrasco 226*82e1cedeSJavier Carrasco return regmap_field_write(data->rf.gain, ret); 227c5a23f80SJavier Carrasco } 228c5a23f80SJavier Carrasco 229*82e1cedeSJavier Carrasco static int veml3235_set_scale(struct iio_dev *indio_dev, int val, int val2) 230c5a23f80SJavier Carrasco { 231c5a23f80SJavier Carrasco struct veml3235_data *data = iio_priv(indio_dev); 232*82e1cedeSJavier Carrasco int ret, it_idx, gain_sel, time_sel; 233c5a23f80SJavier Carrasco 234*82e1cedeSJavier Carrasco ret = regmap_field_read(data->rf.it, &it_idx); 235*82e1cedeSJavier Carrasco if (ret) 236c5a23f80SJavier Carrasco return ret; 237*82e1cedeSJavier Carrasco 238*82e1cedeSJavier Carrasco ret = iio_gts_find_gain_time_sel_for_scale(&data->gts, val, val2, 239*82e1cedeSJavier Carrasco &gain_sel, &time_sel); 240*82e1cedeSJavier Carrasco if (ret) 241*82e1cedeSJavier Carrasco return ret; 242*82e1cedeSJavier Carrasco 243*82e1cedeSJavier Carrasco ret = regmap_field_write(data->rf.it, time_sel); 244*82e1cedeSJavier Carrasco if (ret) 245*82e1cedeSJavier Carrasco return ret; 246*82e1cedeSJavier Carrasco 247*82e1cedeSJavier Carrasco return regmap_field_write(data->rf.gain, gain_sel); 248c5a23f80SJavier Carrasco } 249c5a23f80SJavier Carrasco 250*82e1cedeSJavier Carrasco static int veml3235_get_scale(struct veml3235_data *data, int *val, int *val2) 251c5a23f80SJavier Carrasco { 252*82e1cedeSJavier Carrasco int gain, it, reg, ret; 253c5a23f80SJavier Carrasco 254c5a23f80SJavier Carrasco ret = regmap_field_read(data->rf.gain, ®); 255c5a23f80SJavier Carrasco if (ret) { 256c5a23f80SJavier Carrasco dev_err(data->dev, "failed to read gain %d\n", ret); 257c5a23f80SJavier Carrasco return ret; 258c5a23f80SJavier Carrasco } 259c5a23f80SJavier Carrasco 260*82e1cedeSJavier Carrasco gain = iio_gts_find_gain_by_sel(&data->gts, reg); 261*82e1cedeSJavier Carrasco if (gain < 0) 262*82e1cedeSJavier Carrasco return gain; 263*82e1cedeSJavier Carrasco 264*82e1cedeSJavier Carrasco ret = regmap_field_read(data->rf.it, ®); 265*82e1cedeSJavier Carrasco if (ret) { 266*82e1cedeSJavier Carrasco dev_err(data->dev, "failed to read integration time %d\n", ret); 267*82e1cedeSJavier Carrasco return ret; 268c5a23f80SJavier Carrasco } 269c5a23f80SJavier Carrasco 270*82e1cedeSJavier Carrasco it = iio_gts_find_int_time_by_sel(&data->gts, reg); 271*82e1cedeSJavier Carrasco if (it < 0) 272*82e1cedeSJavier Carrasco return it; 273c5a23f80SJavier Carrasco 274*82e1cedeSJavier Carrasco ret = iio_gts_get_scale(&data->gts, gain, it, val, val2); 275*82e1cedeSJavier Carrasco if (ret) 276*82e1cedeSJavier Carrasco return ret; 277*82e1cedeSJavier Carrasco 278*82e1cedeSJavier Carrasco return IIO_VAL_INT_PLUS_NANO; 279c5a23f80SJavier Carrasco } 280c5a23f80SJavier Carrasco 281c5a23f80SJavier Carrasco static int veml3235_read_raw(struct iio_dev *indio_dev, 282c5a23f80SJavier Carrasco struct iio_chan_spec const *chan, int *val, 283c5a23f80SJavier Carrasco int *val2, long mask) 284c5a23f80SJavier Carrasco { 285c5a23f80SJavier Carrasco struct veml3235_data *data = iio_priv(indio_dev); 286c5a23f80SJavier Carrasco struct regmap *regmap = data->regmap; 287c5a23f80SJavier Carrasco int ret, reg; 288c5a23f80SJavier Carrasco 289c5a23f80SJavier Carrasco switch (mask) { 290c5a23f80SJavier Carrasco case IIO_CHAN_INFO_RAW: 291c5a23f80SJavier Carrasco switch (chan->type) { 292c5a23f80SJavier Carrasco case IIO_LIGHT: 293c5a23f80SJavier Carrasco ret = regmap_read(regmap, VEML3235_REG_ALS_DATA, ®); 294c5a23f80SJavier Carrasco if (ret < 0) 295c5a23f80SJavier Carrasco return ret; 296c5a23f80SJavier Carrasco 297c5a23f80SJavier Carrasco *val = reg; 298c5a23f80SJavier Carrasco return IIO_VAL_INT; 299c5a23f80SJavier Carrasco case IIO_INTENSITY: 300c5a23f80SJavier Carrasco ret = regmap_read(regmap, VEML3235_REG_WH_DATA, ®); 301c5a23f80SJavier Carrasco if (ret < 0) 302c5a23f80SJavier Carrasco return ret; 303c5a23f80SJavier Carrasco 304c5a23f80SJavier Carrasco *val = reg; 305c5a23f80SJavier Carrasco return IIO_VAL_INT; 306c5a23f80SJavier Carrasco default: 307c5a23f80SJavier Carrasco return -EINVAL; 308c5a23f80SJavier Carrasco } 309c5a23f80SJavier Carrasco case IIO_CHAN_INFO_INT_TIME: 310c5a23f80SJavier Carrasco return veml3235_get_it(data, val, val2); 311c5a23f80SJavier Carrasco case IIO_CHAN_INFO_SCALE: 312*82e1cedeSJavier Carrasco return veml3235_get_scale(data, val, val2); 313c5a23f80SJavier Carrasco default: 314c5a23f80SJavier Carrasco return -EINVAL; 315c5a23f80SJavier Carrasco } 316c5a23f80SJavier Carrasco } 317c5a23f80SJavier Carrasco 318c5a23f80SJavier Carrasco static int veml3235_read_avail(struct iio_dev *indio_dev, 319c5a23f80SJavier Carrasco struct iio_chan_spec const *chan, 320c5a23f80SJavier Carrasco const int **vals, int *type, int *length, 321c5a23f80SJavier Carrasco long mask) 322c5a23f80SJavier Carrasco { 323*82e1cedeSJavier Carrasco struct veml3235_data *data = iio_priv(indio_dev); 324*82e1cedeSJavier Carrasco 325c5a23f80SJavier Carrasco switch (mask) { 326c5a23f80SJavier Carrasco case IIO_CHAN_INFO_INT_TIME: 327*82e1cedeSJavier Carrasco return iio_gts_avail_times(&data->gts, vals, type, length); 328c5a23f80SJavier Carrasco case IIO_CHAN_INFO_SCALE: 329*82e1cedeSJavier Carrasco return iio_gts_all_avail_scales(&data->gts, vals, type, length); 330*82e1cedeSJavier Carrasco default: 331*82e1cedeSJavier Carrasco return -EINVAL; 332*82e1cedeSJavier Carrasco } 333*82e1cedeSJavier Carrasco } 334*82e1cedeSJavier Carrasco 335*82e1cedeSJavier Carrasco static int veml3235_write_raw_get_fmt(struct iio_dev *indio_dev, 336*82e1cedeSJavier Carrasco struct iio_chan_spec const *chan, 337*82e1cedeSJavier Carrasco long mask) 338*82e1cedeSJavier Carrasco { 339*82e1cedeSJavier Carrasco switch (mask) { 340*82e1cedeSJavier Carrasco case IIO_CHAN_INFO_SCALE: 341*82e1cedeSJavier Carrasco return IIO_VAL_INT_PLUS_NANO; 342*82e1cedeSJavier Carrasco case IIO_CHAN_INFO_INT_TIME: 343*82e1cedeSJavier Carrasco return IIO_VAL_INT_PLUS_MICRO; 344c5a23f80SJavier Carrasco default: 345c5a23f80SJavier Carrasco return -EINVAL; 346c5a23f80SJavier Carrasco } 347c5a23f80SJavier Carrasco } 348c5a23f80SJavier Carrasco 349c5a23f80SJavier Carrasco static int veml3235_write_raw(struct iio_dev *indio_dev, 350c5a23f80SJavier Carrasco struct iio_chan_spec const *chan, 351c5a23f80SJavier Carrasco int val, int val2, long mask) 352c5a23f80SJavier Carrasco { 353c5a23f80SJavier Carrasco switch (mask) { 354c5a23f80SJavier Carrasco case IIO_CHAN_INFO_INT_TIME: 355c5a23f80SJavier Carrasco return veml3235_set_it(indio_dev, val, val2); 356c5a23f80SJavier Carrasco case IIO_CHAN_INFO_SCALE: 357*82e1cedeSJavier Carrasco return veml3235_set_scale(indio_dev, val, val2); 358c5a23f80SJavier Carrasco } 359c5a23f80SJavier Carrasco 360c5a23f80SJavier Carrasco return -EINVAL; 361c5a23f80SJavier Carrasco } 362c5a23f80SJavier Carrasco 363c5a23f80SJavier Carrasco static void veml3235_read_id(struct veml3235_data *data) 364c5a23f80SJavier Carrasco { 365c5a23f80SJavier Carrasco int ret, reg; 366c5a23f80SJavier Carrasco 367c5a23f80SJavier Carrasco ret = regmap_field_read(data->rf.id, ®); 368c5a23f80SJavier Carrasco if (ret) { 369c5a23f80SJavier Carrasco dev_info(data->dev, "failed to read ID\n"); 370c5a23f80SJavier Carrasco return; 371c5a23f80SJavier Carrasco } 372c5a23f80SJavier Carrasco 373c5a23f80SJavier Carrasco if (reg != 0x35) 374c5a23f80SJavier Carrasco dev_info(data->dev, "Unknown ID %d\n", reg); 375c5a23f80SJavier Carrasco } 376c5a23f80SJavier Carrasco 377c5a23f80SJavier Carrasco static const struct reg_field veml3235_rf_it = 378c5a23f80SJavier Carrasco REG_FIELD(VEML3235_REG_CONF, 4, 6); 379c5a23f80SJavier Carrasco 380c5a23f80SJavier Carrasco static const struct reg_field veml3235_rf_gain = 381c5a23f80SJavier Carrasco REG_FIELD(VEML3235_REG_CONF, 11, 13); 382c5a23f80SJavier Carrasco 383c5a23f80SJavier Carrasco static const struct reg_field veml3235_rf_id = 384c5a23f80SJavier Carrasco REG_FIELD(VEML3235_REG_ID, 0, 7); 385c5a23f80SJavier Carrasco 386c5a23f80SJavier Carrasco static int veml3235_regfield_init(struct veml3235_data *data) 387c5a23f80SJavier Carrasco { 388c5a23f80SJavier Carrasco struct regmap *regmap = data->regmap; 389c5a23f80SJavier Carrasco struct device *dev = data->dev; 390c5a23f80SJavier Carrasco struct regmap_field *rm_field; 391c5a23f80SJavier Carrasco struct veml3235_rf *rf = &data->rf; 392c5a23f80SJavier Carrasco 393c5a23f80SJavier Carrasco rm_field = devm_regmap_field_alloc(dev, regmap, veml3235_rf_it); 394c5a23f80SJavier Carrasco if (IS_ERR(rm_field)) 395c5a23f80SJavier Carrasco return PTR_ERR(rm_field); 396c5a23f80SJavier Carrasco rf->it = rm_field; 397c5a23f80SJavier Carrasco 398c5a23f80SJavier Carrasco rm_field = devm_regmap_field_alloc(dev, regmap, veml3235_rf_gain); 399c5a23f80SJavier Carrasco if (IS_ERR(rm_field)) 400c5a23f80SJavier Carrasco return PTR_ERR(rm_field); 401c5a23f80SJavier Carrasco rf->gain = rm_field; 402c5a23f80SJavier Carrasco 403c5a23f80SJavier Carrasco rm_field = devm_regmap_field_alloc(dev, regmap, veml3235_rf_id); 404c5a23f80SJavier Carrasco if (IS_ERR(rm_field)) 405c5a23f80SJavier Carrasco return PTR_ERR(rm_field); 406c5a23f80SJavier Carrasco rf->id = rm_field; 407c5a23f80SJavier Carrasco 408c5a23f80SJavier Carrasco return 0; 409c5a23f80SJavier Carrasco } 410c5a23f80SJavier Carrasco 411c5a23f80SJavier Carrasco static int veml3235_hw_init(struct iio_dev *indio_dev) 412c5a23f80SJavier Carrasco { 413c5a23f80SJavier Carrasco struct veml3235_data *data = iio_priv(indio_dev); 414c5a23f80SJavier Carrasco struct device *dev = data->dev; 415c5a23f80SJavier Carrasco int ret; 416c5a23f80SJavier Carrasco 417*82e1cedeSJavier Carrasco ret = devm_iio_init_iio_gts(data->dev, 0, 272640000, 418*82e1cedeSJavier Carrasco veml3235_gain_sel, ARRAY_SIZE(veml3235_gain_sel), 419*82e1cedeSJavier Carrasco veml3235_it_sel, ARRAY_SIZE(veml3235_it_sel), 420*82e1cedeSJavier Carrasco &data->gts); 421*82e1cedeSJavier Carrasco if (ret) 422*82e1cedeSJavier Carrasco return dev_err_probe(data->dev, ret, "failed to init iio gts\n"); 423*82e1cedeSJavier Carrasco 424c5a23f80SJavier Carrasco /* Set gain to 1 and integration time to 100 ms */ 425c5a23f80SJavier Carrasco ret = regmap_field_write(data->rf.gain, 0x00); 426c5a23f80SJavier Carrasco if (ret) 427c5a23f80SJavier Carrasco return dev_err_probe(data->dev, ret, "failed to set gain\n"); 428c5a23f80SJavier Carrasco 429c5a23f80SJavier Carrasco ret = regmap_field_write(data->rf.it, 0x01); 430c5a23f80SJavier Carrasco if (ret) 431c5a23f80SJavier Carrasco return dev_err_probe(data->dev, ret, 432c5a23f80SJavier Carrasco "failed to set integration time\n"); 433c5a23f80SJavier Carrasco 434c5a23f80SJavier Carrasco ret = veml3235_power_on(data); 435c5a23f80SJavier Carrasco if (ret) 436c5a23f80SJavier Carrasco return dev_err_probe(dev, ret, "failed to power on\n"); 437c5a23f80SJavier Carrasco 438c5a23f80SJavier Carrasco return devm_add_action_or_reset(dev, veml3235_shut_down_action, data); 439c5a23f80SJavier Carrasco } 440c5a23f80SJavier Carrasco 441c5a23f80SJavier Carrasco static const struct iio_info veml3235_info = { 442c5a23f80SJavier Carrasco .read_raw = veml3235_read_raw, 443c5a23f80SJavier Carrasco .read_avail = veml3235_read_avail, 444c5a23f80SJavier Carrasco .write_raw = veml3235_write_raw, 445*82e1cedeSJavier Carrasco .write_raw_get_fmt = veml3235_write_raw_get_fmt, 446c5a23f80SJavier Carrasco }; 447c5a23f80SJavier Carrasco 448c5a23f80SJavier Carrasco static int veml3235_probe(struct i2c_client *client) 449c5a23f80SJavier Carrasco { 450c5a23f80SJavier Carrasco struct device *dev = &client->dev; 451c5a23f80SJavier Carrasco struct veml3235_data *data; 452c5a23f80SJavier Carrasco struct iio_dev *indio_dev; 453c5a23f80SJavier Carrasco struct regmap *regmap; 454c5a23f80SJavier Carrasco int ret; 455c5a23f80SJavier Carrasco 456c5a23f80SJavier Carrasco regmap = devm_regmap_init_i2c(client, &veml3235_regmap_config); 457c5a23f80SJavier Carrasco if (IS_ERR(regmap)) 458c5a23f80SJavier Carrasco return dev_err_probe(dev, PTR_ERR(regmap), 459c5a23f80SJavier Carrasco "failed to setup regmap\n"); 460c5a23f80SJavier Carrasco 461c5a23f80SJavier Carrasco indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); 462c5a23f80SJavier Carrasco if (!indio_dev) 463c5a23f80SJavier Carrasco return -ENOMEM; 464c5a23f80SJavier Carrasco 465c5a23f80SJavier Carrasco data = iio_priv(indio_dev); 466c5a23f80SJavier Carrasco i2c_set_clientdata(client, indio_dev); 467c5a23f80SJavier Carrasco data->client = client; 468c5a23f80SJavier Carrasco data->dev = dev; 469c5a23f80SJavier Carrasco data->regmap = regmap; 470c5a23f80SJavier Carrasco 471c5a23f80SJavier Carrasco ret = veml3235_regfield_init(data); 472c5a23f80SJavier Carrasco if (ret) 473c5a23f80SJavier Carrasco return dev_err_probe(dev, ret, "failed to init regfield\n"); 474c5a23f80SJavier Carrasco 475c5a23f80SJavier Carrasco ret = devm_regulator_get_enable(dev, "vdd"); 476c5a23f80SJavier Carrasco if (ret) 477c5a23f80SJavier Carrasco return dev_err_probe(dev, ret, "failed to enable regulator\n"); 478c5a23f80SJavier Carrasco 479c5a23f80SJavier Carrasco indio_dev->name = "veml3235"; 480c5a23f80SJavier Carrasco indio_dev->channels = veml3235_channels; 481c5a23f80SJavier Carrasco indio_dev->num_channels = ARRAY_SIZE(veml3235_channels); 482c5a23f80SJavier Carrasco indio_dev->modes = INDIO_DIRECT_MODE; 483c5a23f80SJavier Carrasco indio_dev->info = &veml3235_info; 484c5a23f80SJavier Carrasco 485c5a23f80SJavier Carrasco veml3235_read_id(data); 486c5a23f80SJavier Carrasco 487c5a23f80SJavier Carrasco ret = veml3235_hw_init(indio_dev); 488c5a23f80SJavier Carrasco if (ret < 0) 489c5a23f80SJavier Carrasco return ret; 490c5a23f80SJavier Carrasco 491c5a23f80SJavier Carrasco return devm_iio_device_register(dev, indio_dev); 492c5a23f80SJavier Carrasco } 493c5a23f80SJavier Carrasco 494c5a23f80SJavier Carrasco static int veml3235_runtime_suspend(struct device *dev) 495c5a23f80SJavier Carrasco { 496c5a23f80SJavier Carrasco struct veml3235_data *data = iio_priv(dev_get_drvdata(dev)); 497c5a23f80SJavier Carrasco int ret; 498c5a23f80SJavier Carrasco 499c5a23f80SJavier Carrasco ret = veml3235_shut_down(data); 500c5a23f80SJavier Carrasco if (ret < 0) 501c5a23f80SJavier Carrasco dev_err(data->dev, "failed to suspend: %d\n", ret); 502c5a23f80SJavier Carrasco 503c5a23f80SJavier Carrasco return ret; 504c5a23f80SJavier Carrasco } 505c5a23f80SJavier Carrasco 506c5a23f80SJavier Carrasco static int veml3235_runtime_resume(struct device *dev) 507c5a23f80SJavier Carrasco { 508c5a23f80SJavier Carrasco struct veml3235_data *data = iio_priv(dev_get_drvdata(dev)); 509c5a23f80SJavier Carrasco int ret; 510c5a23f80SJavier Carrasco 511c5a23f80SJavier Carrasco ret = veml3235_power_on(data); 512c5a23f80SJavier Carrasco if (ret < 0) 513c5a23f80SJavier Carrasco dev_err(data->dev, "failed to resume: %d\n", ret); 514c5a23f80SJavier Carrasco 515c5a23f80SJavier Carrasco return ret; 516c5a23f80SJavier Carrasco } 517c5a23f80SJavier Carrasco 518c5a23f80SJavier Carrasco static DEFINE_RUNTIME_DEV_PM_OPS(veml3235_pm_ops, veml3235_runtime_suspend, 519c5a23f80SJavier Carrasco veml3235_runtime_resume, NULL); 520c5a23f80SJavier Carrasco 521c5a23f80SJavier Carrasco static const struct of_device_id veml3235_of_match[] = { 522c5a23f80SJavier Carrasco { .compatible = "vishay,veml3235" }, 523c5a23f80SJavier Carrasco { } 524c5a23f80SJavier Carrasco }; 525c5a23f80SJavier Carrasco MODULE_DEVICE_TABLE(of, veml3235_of_match); 526c5a23f80SJavier Carrasco 527c5a23f80SJavier Carrasco static const struct i2c_device_id veml3235_id[] = { 528c5a23f80SJavier Carrasco { "veml3235" }, 529c5a23f80SJavier Carrasco { } 530c5a23f80SJavier Carrasco }; 531c5a23f80SJavier Carrasco MODULE_DEVICE_TABLE(i2c, veml3235_id); 532c5a23f80SJavier Carrasco 533c5a23f80SJavier Carrasco static struct i2c_driver veml3235_driver = { 534c5a23f80SJavier Carrasco .driver = { 535c5a23f80SJavier Carrasco .name = "veml3235", 536c5a23f80SJavier Carrasco .of_match_table = veml3235_of_match, 537c5a23f80SJavier Carrasco .pm = pm_ptr(&veml3235_pm_ops), 538c5a23f80SJavier Carrasco }, 539c5a23f80SJavier Carrasco .probe = veml3235_probe, 540c5a23f80SJavier Carrasco .id_table = veml3235_id, 541c5a23f80SJavier Carrasco }; 542c5a23f80SJavier Carrasco module_i2c_driver(veml3235_driver); 543c5a23f80SJavier Carrasco 544c5a23f80SJavier Carrasco MODULE_AUTHOR("Javier Carrasco <javier.carrasco.cruz@gmail.com>"); 545c5a23f80SJavier Carrasco MODULE_DESCRIPTION("VEML3235 Ambient Light Sensor"); 546c5a23f80SJavier Carrasco MODULE_LICENSE("GPL"); 547*82e1cedeSJavier Carrasco MODULE_IMPORT_NS("IIO_GTS_HELPER"); 548