1*ec08c395SMikael Gonella-Bolduc // SPDX-License-Identifier: GPL-2.0-or-later 2*ec08c395SMikael Gonella-Bolduc /* 3*ec08c395SMikael Gonella-Bolduc * APDS9160 sensor driver. 4*ec08c395SMikael Gonella-Bolduc * Chip is combined proximity and ambient light sensor. 5*ec08c395SMikael Gonella-Bolduc * Author: 2024 Mikael Gonella-Bolduc <m.gonella.bolduc@gmail.com> 6*ec08c395SMikael Gonella-Bolduc */ 7*ec08c395SMikael Gonella-Bolduc 8*ec08c395SMikael Gonella-Bolduc #include <linux/bits.h> 9*ec08c395SMikael Gonella-Bolduc #include <linux/bitfield.h> 10*ec08c395SMikael Gonella-Bolduc #include <linux/cleanup.h> 11*ec08c395SMikael Gonella-Bolduc #include <linux/delay.h> 12*ec08c395SMikael Gonella-Bolduc #include <linux/err.h> 13*ec08c395SMikael Gonella-Bolduc #include <linux/i2c.h> 14*ec08c395SMikael Gonella-Bolduc #include <linux/interrupt.h> 15*ec08c395SMikael Gonella-Bolduc #include <linux/module.h> 16*ec08c395SMikael Gonella-Bolduc #include <linux/mutex.h> 17*ec08c395SMikael Gonella-Bolduc #include <linux/regmap.h> 18*ec08c395SMikael Gonella-Bolduc #include <linux/regulator/consumer.h> 19*ec08c395SMikael Gonella-Bolduc #include <linux/types.h> 20*ec08c395SMikael Gonella-Bolduc #include <linux/units.h> 21*ec08c395SMikael Gonella-Bolduc 22*ec08c395SMikael Gonella-Bolduc #include <linux/iio/iio.h> 23*ec08c395SMikael Gonella-Bolduc #include <linux/iio/events.h> 24*ec08c395SMikael Gonella-Bolduc #include <linux/iio/sysfs.h> 25*ec08c395SMikael Gonella-Bolduc 26*ec08c395SMikael Gonella-Bolduc #include <linux/unaligned.h> 27*ec08c395SMikael Gonella-Bolduc 28*ec08c395SMikael Gonella-Bolduc #define APDS9160_REGMAP_NAME "apds9160_regmap" 29*ec08c395SMikael Gonella-Bolduc 30*ec08c395SMikael Gonella-Bolduc /* Main control register */ 31*ec08c395SMikael Gonella-Bolduc #define APDS9160_REG_CTRL 0x00 32*ec08c395SMikael Gonella-Bolduc #define APDS9160_CTRL_SWRESET BIT(4) /* 1: Activate reset */ 33*ec08c395SMikael Gonella-Bolduc #define APDS9160_CTRL_MODE_RGB BIT(2) /* 0: ALS & IR, 1: RGB & IR */ 34*ec08c395SMikael Gonella-Bolduc #define APDS9160_CTRL_EN_ALS BIT(1) /* 1: ALS active */ 35*ec08c395SMikael Gonella-Bolduc #define APDS9160_CTLR_EN_PS BIT(0) /* 1: PS active */ 36*ec08c395SMikael Gonella-Bolduc 37*ec08c395SMikael Gonella-Bolduc /* Status register */ 38*ec08c395SMikael Gonella-Bolduc #define APDS9160_SR_LS_INT BIT(4) 39*ec08c395SMikael Gonella-Bolduc #define APDS9160_SR_LS_NEW_DATA BIT(3) 40*ec08c395SMikael Gonella-Bolduc #define APDS9160_SR_PS_INT BIT(1) 41*ec08c395SMikael Gonella-Bolduc #define APDS9160_SR_PS_NEW_DATA BIT(0) 42*ec08c395SMikael Gonella-Bolduc 43*ec08c395SMikael Gonella-Bolduc /* Interrupt configuration registers */ 44*ec08c395SMikael Gonella-Bolduc #define APDS9160_REG_INT_CFG 0x19 45*ec08c395SMikael Gonella-Bolduc #define APDS9160_REG_INT_PST 0x1A 46*ec08c395SMikael Gonella-Bolduc #define APDS9160_INT_CFG_EN_LS BIT(2) /* LS int enable */ 47*ec08c395SMikael Gonella-Bolduc #define APDS9160_INT_CFG_EN_PS BIT(0) /* PS int enable */ 48*ec08c395SMikael Gonella-Bolduc 49*ec08c395SMikael Gonella-Bolduc /* Proximity registers */ 50*ec08c395SMikael Gonella-Bolduc #define APDS9160_REG_PS_LED 0x01 51*ec08c395SMikael Gonella-Bolduc #define APDS9160_REG_PS_PULSES 0x02 52*ec08c395SMikael Gonella-Bolduc #define APDS9160_REG_PS_MEAS_RATE 0x03 53*ec08c395SMikael Gonella-Bolduc #define APDS9160_REG_PS_THRES_HI_LSB 0x1B 54*ec08c395SMikael Gonella-Bolduc #define APDS9160_REG_PS_THRES_HI_MSB 0x1C 55*ec08c395SMikael Gonella-Bolduc #define APDS9160_REG_PS_THRES_LO_LSB 0x1D 56*ec08c395SMikael Gonella-Bolduc #define APDS9160_REG_PS_THRES_LO_MSB 0x1E 57*ec08c395SMikael Gonella-Bolduc #define APDS9160_REG_PS_DATA_LSB 0x08 58*ec08c395SMikael Gonella-Bolduc #define APDS9160_REG_PS_DATA_MSB 0x09 59*ec08c395SMikael Gonella-Bolduc #define APDS9160_REG_PS_CAN_LEVEL_DIG_LSB 0x1F 60*ec08c395SMikael Gonella-Bolduc #define APDS9160_REG_PS_CAN_LEVEL_DIG_MSB 0x20 61*ec08c395SMikael Gonella-Bolduc #define APDS9160_REG_PS_CAN_LEVEL_ANA_DUR 0x21 62*ec08c395SMikael Gonella-Bolduc #define APDS9160_REG_PS_CAN_LEVEL_ANA_CURRENT 0x22 63*ec08c395SMikael Gonella-Bolduc 64*ec08c395SMikael Gonella-Bolduc /* Light sensor registers */ 65*ec08c395SMikael Gonella-Bolduc #define APDS9160_REG_LS_MEAS_RATE 0x04 66*ec08c395SMikael Gonella-Bolduc #define APDS9160_REG_LS_GAIN 0x05 67*ec08c395SMikael Gonella-Bolduc #define APDS9160_REG_LS_DATA_CLEAR_LSB 0x0A 68*ec08c395SMikael Gonella-Bolduc #define APDS9160_REG_LS_DATA_CLEAR 0x0B 69*ec08c395SMikael Gonella-Bolduc #define APDS9160_REG_LS_DATA_CLEAR_MSB 0x0C 70*ec08c395SMikael Gonella-Bolduc #define APDS9160_REG_LS_DATA_ALS_LSB 0x0D 71*ec08c395SMikael Gonella-Bolduc #define APDS9160_REG_LS_DATA_ALS 0x0E 72*ec08c395SMikael Gonella-Bolduc #define APDS9160_REG_LS_DATA_ALS_MSB 0x0F 73*ec08c395SMikael Gonella-Bolduc #define APDS9160_REG_LS_THRES_UP_LSB 0x24 74*ec08c395SMikael Gonella-Bolduc #define APDS9160_REG_LS_THRES_UP 0x25 75*ec08c395SMikael Gonella-Bolduc #define APDS9160_REG_LS_THRES_UP_MSB 0x26 76*ec08c395SMikael Gonella-Bolduc #define APDS9160_REG_LS_THRES_LO_LSB 0x27 77*ec08c395SMikael Gonella-Bolduc #define APDS9160_REG_LS_THRES_LO 0x28 78*ec08c395SMikael Gonella-Bolduc #define APDS9160_REG_LS_THRES_LO_MSB 0x29 79*ec08c395SMikael Gonella-Bolduc #define APDS9160_REG_LS_THRES_VAR 0x2A 80*ec08c395SMikael Gonella-Bolduc 81*ec08c395SMikael Gonella-Bolduc /* Part identification number register */ 82*ec08c395SMikael Gonella-Bolduc #define APDS9160_REG_ID 0x06 83*ec08c395SMikael Gonella-Bolduc 84*ec08c395SMikael Gonella-Bolduc /* Status register */ 85*ec08c395SMikael Gonella-Bolduc #define APDS9160_REG_SR 0x07 86*ec08c395SMikael Gonella-Bolduc #define APDS9160_SR_DATA_ALS BIT(3) 87*ec08c395SMikael Gonella-Bolduc #define APDS9160_SR_DATA_PS BIT(0) 88*ec08c395SMikael Gonella-Bolduc 89*ec08c395SMikael Gonella-Bolduc /* Supported ID:s */ 90*ec08c395SMikael Gonella-Bolduc #define APDS9160_PART_ID_0 0x03 91*ec08c395SMikael Gonella-Bolduc 92*ec08c395SMikael Gonella-Bolduc #define APDS9160_PS_THRES_MAX 0x7FF 93*ec08c395SMikael Gonella-Bolduc #define APDS9160_LS_THRES_MAX 0xFFFFF 94*ec08c395SMikael Gonella-Bolduc #define APDS9160_CMD_LS_RESOLUTION_25MS 0x04 95*ec08c395SMikael Gonella-Bolduc #define APDS9160_CMD_LS_RESOLUTION_50MS 0x03 96*ec08c395SMikael Gonella-Bolduc #define APDS9160_CMD_LS_RESOLUTION_100MS 0x02 97*ec08c395SMikael Gonella-Bolduc #define APDS9160_CMD_LS_RESOLUTION_200MS 0x01 98*ec08c395SMikael Gonella-Bolduc #define APDS9160_PS_DATA_MASK 0x7FF 99*ec08c395SMikael Gonella-Bolduc 100*ec08c395SMikael Gonella-Bolduc #define APDS9160_DEFAULT_LS_GAIN 3 101*ec08c395SMikael Gonella-Bolduc #define APDS9160_DEFAULT_LS_RATE 100 102*ec08c395SMikael Gonella-Bolduc #define APDS9160_DEFAULT_PS_RATE 100 103*ec08c395SMikael Gonella-Bolduc #define APDS9160_DEFAULT_PS_CANCELLATION_LEVEL 0 104*ec08c395SMikael Gonella-Bolduc #define APDS9160_DEFAULT_PS_ANALOG_CANCELLATION 0 105*ec08c395SMikael Gonella-Bolduc #define APDS9160_DEFAULT_PS_GAIN 1 106*ec08c395SMikael Gonella-Bolduc #define APDS9160_DEFAULT_PS_CURRENT 100 107*ec08c395SMikael Gonella-Bolduc #define APDS9160_DEFAULT_PS_RESOLUTION_11BITS 0x03 108*ec08c395SMikael Gonella-Bolduc 109*ec08c395SMikael Gonella-Bolduc static const struct reg_default apds9160_reg_defaults[] = { 110*ec08c395SMikael Gonella-Bolduc { APDS9160_REG_CTRL, 0x00 }, /* Sensors disabled by default */ 111*ec08c395SMikael Gonella-Bolduc { APDS9160_REG_PS_LED, 0x33 }, /* 60 kHz frequency, 100 mA */ 112*ec08c395SMikael Gonella-Bolduc { APDS9160_REG_PS_PULSES, 0x08 }, /* 8 pulses */ 113*ec08c395SMikael Gonella-Bolduc { APDS9160_REG_PS_MEAS_RATE, 0x05 }, /* 100ms */ 114*ec08c395SMikael Gonella-Bolduc { APDS9160_REG_LS_MEAS_RATE, 0x22 }, /* 100ms */ 115*ec08c395SMikael Gonella-Bolduc { APDS9160_REG_LS_GAIN, 0x01 }, /* 3x */ 116*ec08c395SMikael Gonella-Bolduc { APDS9160_REG_INT_CFG, 0x10 }, /* Interrupts disabled */ 117*ec08c395SMikael Gonella-Bolduc { APDS9160_REG_INT_PST, 0x00 }, 118*ec08c395SMikael Gonella-Bolduc { APDS9160_REG_PS_THRES_HI_LSB, 0xFF }, 119*ec08c395SMikael Gonella-Bolduc { APDS9160_REG_PS_THRES_HI_MSB, 0x07 }, 120*ec08c395SMikael Gonella-Bolduc { APDS9160_REG_PS_THRES_LO_LSB, 0x00 }, 121*ec08c395SMikael Gonella-Bolduc { APDS9160_REG_PS_THRES_LO_MSB, 0x00 }, 122*ec08c395SMikael Gonella-Bolduc { APDS9160_REG_PS_CAN_LEVEL_DIG_LSB, 0x00 }, 123*ec08c395SMikael Gonella-Bolduc { APDS9160_REG_PS_CAN_LEVEL_DIG_MSB, 0x00 }, 124*ec08c395SMikael Gonella-Bolduc { APDS9160_REG_PS_CAN_LEVEL_ANA_DUR, 0x00 }, 125*ec08c395SMikael Gonella-Bolduc { APDS9160_REG_PS_CAN_LEVEL_ANA_CURRENT, 0x00 }, 126*ec08c395SMikael Gonella-Bolduc { APDS9160_REG_LS_THRES_UP_LSB, 0xFF }, 127*ec08c395SMikael Gonella-Bolduc { APDS9160_REG_LS_THRES_UP, 0xFF }, 128*ec08c395SMikael Gonella-Bolduc { APDS9160_REG_LS_THRES_UP_MSB, 0x0F }, 129*ec08c395SMikael Gonella-Bolduc { APDS9160_REG_LS_THRES_LO_LSB, 0x00 }, 130*ec08c395SMikael Gonella-Bolduc { APDS9160_REG_LS_THRES_LO, 0x00 }, 131*ec08c395SMikael Gonella-Bolduc { APDS9160_REG_LS_THRES_LO_MSB, 0x00 }, 132*ec08c395SMikael Gonella-Bolduc { APDS9160_REG_LS_THRES_VAR, 0x00 }, 133*ec08c395SMikael Gonella-Bolduc }; 134*ec08c395SMikael Gonella-Bolduc 135*ec08c395SMikael Gonella-Bolduc static const struct regmap_range apds9160_readable_ranges[] = { 136*ec08c395SMikael Gonella-Bolduc regmap_reg_range(APDS9160_REG_CTRL, APDS9160_REG_LS_THRES_VAR), 137*ec08c395SMikael Gonella-Bolduc }; 138*ec08c395SMikael Gonella-Bolduc 139*ec08c395SMikael Gonella-Bolduc static const struct regmap_access_table apds9160_readable_table = { 140*ec08c395SMikael Gonella-Bolduc .yes_ranges = apds9160_readable_ranges, 141*ec08c395SMikael Gonella-Bolduc .n_yes_ranges = ARRAY_SIZE(apds9160_readable_ranges), 142*ec08c395SMikael Gonella-Bolduc }; 143*ec08c395SMikael Gonella-Bolduc 144*ec08c395SMikael Gonella-Bolduc static const struct regmap_range apds9160_writeable_ranges[] = { 145*ec08c395SMikael Gonella-Bolduc regmap_reg_range(APDS9160_REG_CTRL, APDS9160_REG_LS_GAIN), 146*ec08c395SMikael Gonella-Bolduc regmap_reg_range(APDS9160_REG_INT_CFG, APDS9160_REG_LS_THRES_VAR), 147*ec08c395SMikael Gonella-Bolduc }; 148*ec08c395SMikael Gonella-Bolduc 149*ec08c395SMikael Gonella-Bolduc static const struct regmap_access_table apds9160_writeable_table = { 150*ec08c395SMikael Gonella-Bolduc .yes_ranges = apds9160_writeable_ranges, 151*ec08c395SMikael Gonella-Bolduc .n_yes_ranges = ARRAY_SIZE(apds9160_writeable_ranges), 152*ec08c395SMikael Gonella-Bolduc }; 153*ec08c395SMikael Gonella-Bolduc 154*ec08c395SMikael Gonella-Bolduc static const struct regmap_range apds9160_volatile_ranges[] = { 155*ec08c395SMikael Gonella-Bolduc regmap_reg_range(APDS9160_REG_SR, APDS9160_REG_LS_DATA_ALS_MSB), 156*ec08c395SMikael Gonella-Bolduc }; 157*ec08c395SMikael Gonella-Bolduc 158*ec08c395SMikael Gonella-Bolduc static const struct regmap_access_table apds9160_volatile_table = { 159*ec08c395SMikael Gonella-Bolduc .yes_ranges = apds9160_volatile_ranges, 160*ec08c395SMikael Gonella-Bolduc .n_yes_ranges = ARRAY_SIZE(apds9160_volatile_ranges), 161*ec08c395SMikael Gonella-Bolduc }; 162*ec08c395SMikael Gonella-Bolduc 163*ec08c395SMikael Gonella-Bolduc static const struct regmap_config apds9160_regmap_config = { 164*ec08c395SMikael Gonella-Bolduc .name = APDS9160_REGMAP_NAME, 165*ec08c395SMikael Gonella-Bolduc .reg_bits = 8, 166*ec08c395SMikael Gonella-Bolduc .val_bits = 8, 167*ec08c395SMikael Gonella-Bolduc .use_single_read = true, 168*ec08c395SMikael Gonella-Bolduc .use_single_write = true, 169*ec08c395SMikael Gonella-Bolduc 170*ec08c395SMikael Gonella-Bolduc .rd_table = &apds9160_readable_table, 171*ec08c395SMikael Gonella-Bolduc .wr_table = &apds9160_writeable_table, 172*ec08c395SMikael Gonella-Bolduc .volatile_table = &apds9160_volatile_table, 173*ec08c395SMikael Gonella-Bolduc 174*ec08c395SMikael Gonella-Bolduc .reg_defaults = apds9160_reg_defaults, 175*ec08c395SMikael Gonella-Bolduc .num_reg_defaults = ARRAY_SIZE(apds9160_reg_defaults), 176*ec08c395SMikael Gonella-Bolduc .max_register = 37, 177*ec08c395SMikael Gonella-Bolduc .cache_type = REGCACHE_RBTREE, 178*ec08c395SMikael Gonella-Bolduc }; 179*ec08c395SMikael Gonella-Bolduc 180*ec08c395SMikael Gonella-Bolduc static const struct iio_event_spec apds9160_event_spec[] = { 181*ec08c395SMikael Gonella-Bolduc { 182*ec08c395SMikael Gonella-Bolduc .type = IIO_EV_TYPE_THRESH, 183*ec08c395SMikael Gonella-Bolduc .dir = IIO_EV_DIR_RISING, 184*ec08c395SMikael Gonella-Bolduc .mask_separate = BIT(IIO_EV_INFO_VALUE), 185*ec08c395SMikael Gonella-Bolduc }, 186*ec08c395SMikael Gonella-Bolduc { 187*ec08c395SMikael Gonella-Bolduc .type = IIO_EV_TYPE_THRESH, 188*ec08c395SMikael Gonella-Bolduc .dir = IIO_EV_DIR_FALLING, 189*ec08c395SMikael Gonella-Bolduc .mask_separate = BIT(IIO_EV_INFO_VALUE), 190*ec08c395SMikael Gonella-Bolduc }, 191*ec08c395SMikael Gonella-Bolduc { 192*ec08c395SMikael Gonella-Bolduc .type = IIO_EV_TYPE_THRESH, 193*ec08c395SMikael Gonella-Bolduc .dir = IIO_EV_DIR_EITHER, 194*ec08c395SMikael Gonella-Bolduc .mask_separate = BIT(IIO_EV_INFO_ENABLE), 195*ec08c395SMikael Gonella-Bolduc }, 196*ec08c395SMikael Gonella-Bolduc }; 197*ec08c395SMikael Gonella-Bolduc 198*ec08c395SMikael Gonella-Bolduc static const struct iio_chan_spec apds9160_channels[] = { 199*ec08c395SMikael Gonella-Bolduc { 200*ec08c395SMikael Gonella-Bolduc /* Proximity sensor channel */ 201*ec08c395SMikael Gonella-Bolduc .type = IIO_PROXIMITY, 202*ec08c395SMikael Gonella-Bolduc .address = APDS9160_REG_PS_DATA_LSB, 203*ec08c395SMikael Gonella-Bolduc .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), 204*ec08c395SMikael Gonella-Bolduc .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_INT_TIME) | 205*ec08c395SMikael Gonella-Bolduc BIT(IIO_CHAN_INFO_SCALE) | 206*ec08c395SMikael Gonella-Bolduc BIT(IIO_CHAN_INFO_CALIBBIAS), 207*ec08c395SMikael Gonella-Bolduc .info_mask_separate_available = BIT(IIO_CHAN_INFO_INT_TIME) | 208*ec08c395SMikael Gonella-Bolduc BIT(IIO_CHAN_INFO_SCALE), 209*ec08c395SMikael Gonella-Bolduc .event_spec = apds9160_event_spec, 210*ec08c395SMikael Gonella-Bolduc .num_event_specs = ARRAY_SIZE(apds9160_event_spec), 211*ec08c395SMikael Gonella-Bolduc }, 212*ec08c395SMikael Gonella-Bolduc { 213*ec08c395SMikael Gonella-Bolduc /* Proximity sensor led current */ 214*ec08c395SMikael Gonella-Bolduc .type = IIO_CURRENT, 215*ec08c395SMikael Gonella-Bolduc .output = 1, 216*ec08c395SMikael Gonella-Bolduc .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), 217*ec08c395SMikael Gonella-Bolduc .info_mask_separate_available = BIT(IIO_CHAN_INFO_RAW), 218*ec08c395SMikael Gonella-Bolduc }, 219*ec08c395SMikael Gonella-Bolduc { 220*ec08c395SMikael Gonella-Bolduc /* Illuminance */ 221*ec08c395SMikael Gonella-Bolduc .type = IIO_LIGHT, 222*ec08c395SMikael Gonella-Bolduc .address = APDS9160_REG_LS_DATA_ALS_LSB, 223*ec08c395SMikael Gonella-Bolduc .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), 224*ec08c395SMikael Gonella-Bolduc .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_INT_TIME) | 225*ec08c395SMikael Gonella-Bolduc BIT(IIO_CHAN_INFO_HARDWAREGAIN) | 226*ec08c395SMikael Gonella-Bolduc BIT(IIO_CHAN_INFO_SCALE), 227*ec08c395SMikael Gonella-Bolduc .info_mask_separate_available = BIT(IIO_CHAN_INFO_INT_TIME) | 228*ec08c395SMikael Gonella-Bolduc BIT(IIO_CHAN_INFO_SCALE), 229*ec08c395SMikael Gonella-Bolduc .event_spec = apds9160_event_spec, 230*ec08c395SMikael Gonella-Bolduc .num_event_specs = ARRAY_SIZE(apds9160_event_spec), 231*ec08c395SMikael Gonella-Bolduc }, 232*ec08c395SMikael Gonella-Bolduc { 233*ec08c395SMikael Gonella-Bolduc /* Clear channel */ 234*ec08c395SMikael Gonella-Bolduc .type = IIO_INTENSITY, 235*ec08c395SMikael Gonella-Bolduc .address = APDS9160_REG_LS_DATA_CLEAR_LSB, 236*ec08c395SMikael Gonella-Bolduc .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), 237*ec08c395SMikael Gonella-Bolduc .channel2 = IIO_MOD_LIGHT_CLEAR, 238*ec08c395SMikael Gonella-Bolduc .modified = 1, 239*ec08c395SMikael Gonella-Bolduc }, 240*ec08c395SMikael Gonella-Bolduc }; 241*ec08c395SMikael Gonella-Bolduc 242*ec08c395SMikael Gonella-Bolduc static const struct iio_chan_spec apds9160_channels_without_events[] = { 243*ec08c395SMikael Gonella-Bolduc { 244*ec08c395SMikael Gonella-Bolduc /* Proximity sensor channel */ 245*ec08c395SMikael Gonella-Bolduc .type = IIO_PROXIMITY, 246*ec08c395SMikael Gonella-Bolduc .address = APDS9160_REG_PS_DATA_LSB, 247*ec08c395SMikael Gonella-Bolduc .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), 248*ec08c395SMikael Gonella-Bolduc .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_INT_TIME) | 249*ec08c395SMikael Gonella-Bolduc BIT(IIO_CHAN_INFO_SCALE) | 250*ec08c395SMikael Gonella-Bolduc BIT(IIO_CHAN_INFO_CALIBBIAS), 251*ec08c395SMikael Gonella-Bolduc .info_mask_separate_available = BIT(IIO_CHAN_INFO_INT_TIME) | 252*ec08c395SMikael Gonella-Bolduc BIT(IIO_CHAN_INFO_SCALE), 253*ec08c395SMikael Gonella-Bolduc }, 254*ec08c395SMikael Gonella-Bolduc { 255*ec08c395SMikael Gonella-Bolduc /* Proximity sensor led current */ 256*ec08c395SMikael Gonella-Bolduc .type = IIO_CURRENT, 257*ec08c395SMikael Gonella-Bolduc .output = 1, 258*ec08c395SMikael Gonella-Bolduc .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), 259*ec08c395SMikael Gonella-Bolduc .info_mask_separate_available = BIT(IIO_CHAN_INFO_RAW), 260*ec08c395SMikael Gonella-Bolduc }, 261*ec08c395SMikael Gonella-Bolduc { 262*ec08c395SMikael Gonella-Bolduc /* Illuminance */ 263*ec08c395SMikael Gonella-Bolduc .type = IIO_LIGHT, 264*ec08c395SMikael Gonella-Bolduc .address = APDS9160_REG_LS_DATA_ALS_LSB, 265*ec08c395SMikael Gonella-Bolduc .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), 266*ec08c395SMikael Gonella-Bolduc .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_INT_TIME) | 267*ec08c395SMikael Gonella-Bolduc BIT(IIO_CHAN_INFO_HARDWAREGAIN) | 268*ec08c395SMikael Gonella-Bolduc BIT(IIO_CHAN_INFO_SCALE), 269*ec08c395SMikael Gonella-Bolduc .info_mask_separate_available = BIT(IIO_CHAN_INFO_INT_TIME) | 270*ec08c395SMikael Gonella-Bolduc BIT(IIO_CHAN_INFO_SCALE), 271*ec08c395SMikael Gonella-Bolduc }, 272*ec08c395SMikael Gonella-Bolduc { 273*ec08c395SMikael Gonella-Bolduc /* Clear channel */ 274*ec08c395SMikael Gonella-Bolduc .type = IIO_INTENSITY, 275*ec08c395SMikael Gonella-Bolduc .address = APDS9160_REG_LS_DATA_CLEAR_LSB, 276*ec08c395SMikael Gonella-Bolduc .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), 277*ec08c395SMikael Gonella-Bolduc .channel2 = IIO_MOD_LIGHT_CLEAR, 278*ec08c395SMikael Gonella-Bolduc .modified = 1, 279*ec08c395SMikael Gonella-Bolduc }, 280*ec08c395SMikael Gonella-Bolduc }; 281*ec08c395SMikael Gonella-Bolduc 282*ec08c395SMikael Gonella-Bolduc static const int apds9160_als_rate_avail[] = { 283*ec08c395SMikael Gonella-Bolduc 25, 50, 100, 200 284*ec08c395SMikael Gonella-Bolduc }; 285*ec08c395SMikael Gonella-Bolduc 286*ec08c395SMikael Gonella-Bolduc static const int apds9160_als_rate_map[][2] = { 287*ec08c395SMikael Gonella-Bolduc { 25, 0x00 }, 288*ec08c395SMikael Gonella-Bolduc { 50, 0x01 }, 289*ec08c395SMikael Gonella-Bolduc { 100, 0x02 }, 290*ec08c395SMikael Gonella-Bolduc { 200, 0x03 }, 291*ec08c395SMikael Gonella-Bolduc }; 292*ec08c395SMikael Gonella-Bolduc 293*ec08c395SMikael Gonella-Bolduc static const int apds9160_als_gain_map[][2] = { 294*ec08c395SMikael Gonella-Bolduc { 1, 0x00 }, 295*ec08c395SMikael Gonella-Bolduc { 3, 0x01 }, 296*ec08c395SMikael Gonella-Bolduc { 6, 0x02 }, 297*ec08c395SMikael Gonella-Bolduc { 18, 0x03 }, 298*ec08c395SMikael Gonella-Bolduc { 54, 0x04 }, 299*ec08c395SMikael Gonella-Bolduc }; 300*ec08c395SMikael Gonella-Bolduc 301*ec08c395SMikael Gonella-Bolduc static const int apds9160_ps_gain_avail[] = { 302*ec08c395SMikael Gonella-Bolduc 1, 2, 4, 8 303*ec08c395SMikael Gonella-Bolduc }; 304*ec08c395SMikael Gonella-Bolduc 305*ec08c395SMikael Gonella-Bolduc static const int apds9160_ps_gain_map[][2] = { 306*ec08c395SMikael Gonella-Bolduc { 1, 0x00 }, 307*ec08c395SMikael Gonella-Bolduc { 2, 0x01 }, 308*ec08c395SMikael Gonella-Bolduc { 4, 0x02 }, 309*ec08c395SMikael Gonella-Bolduc { 8, 0x03 }, 310*ec08c395SMikael Gonella-Bolduc }; 311*ec08c395SMikael Gonella-Bolduc 312*ec08c395SMikael Gonella-Bolduc static const int apds9160_ps_rate_avail[] = { 313*ec08c395SMikael Gonella-Bolduc 25, 50, 100, 200, 400 314*ec08c395SMikael Gonella-Bolduc }; 315*ec08c395SMikael Gonella-Bolduc 316*ec08c395SMikael Gonella-Bolduc static const int apds9160_ps_rate_map[][2] = { 317*ec08c395SMikael Gonella-Bolduc { 25, 0x03 }, 318*ec08c395SMikael Gonella-Bolduc { 50, 0x04 }, 319*ec08c395SMikael Gonella-Bolduc { 100, 0x05 }, 320*ec08c395SMikael Gonella-Bolduc { 200, 0x06 }, 321*ec08c395SMikael Gonella-Bolduc { 400, 0x07 }, 322*ec08c395SMikael Gonella-Bolduc }; 323*ec08c395SMikael Gonella-Bolduc 324*ec08c395SMikael Gonella-Bolduc static const int apds9160_ps_led_current_avail[] = { 325*ec08c395SMikael Gonella-Bolduc 10, 25, 50, 100, 150, 175, 200 326*ec08c395SMikael Gonella-Bolduc }; 327*ec08c395SMikael Gonella-Bolduc 328*ec08c395SMikael Gonella-Bolduc static const int apds9160_ps_led_current_map[][2] = { 329*ec08c395SMikael Gonella-Bolduc { 10, 0x00 }, 330*ec08c395SMikael Gonella-Bolduc { 25, 0x01 }, 331*ec08c395SMikael Gonella-Bolduc { 50, 0x02 }, 332*ec08c395SMikael Gonella-Bolduc { 100, 0x03 }, 333*ec08c395SMikael Gonella-Bolduc { 150, 0x04 }, 334*ec08c395SMikael Gonella-Bolduc { 175, 0x05 }, 335*ec08c395SMikael Gonella-Bolduc { 200, 0x06 }, 336*ec08c395SMikael Gonella-Bolduc }; 337*ec08c395SMikael Gonella-Bolduc 338*ec08c395SMikael Gonella-Bolduc /** 339*ec08c395SMikael Gonella-Bolduc * struct apds9160_scale - apds9160 scale mapping definition 340*ec08c395SMikael Gonella-Bolduc * 341*ec08c395SMikael Gonella-Bolduc * @itime: Integration time in ms 342*ec08c395SMikael Gonella-Bolduc * @gain: Gain multiplier 343*ec08c395SMikael Gonella-Bolduc * @scale1: lux/count resolution 344*ec08c395SMikael Gonella-Bolduc * @scale2: micro lux/count 345*ec08c395SMikael Gonella-Bolduc */ 346*ec08c395SMikael Gonella-Bolduc struct apds9160_scale { 347*ec08c395SMikael Gonella-Bolduc int itime; 348*ec08c395SMikael Gonella-Bolduc int gain; 349*ec08c395SMikael Gonella-Bolduc int scale1; 350*ec08c395SMikael Gonella-Bolduc int scale2; 351*ec08c395SMikael Gonella-Bolduc }; 352*ec08c395SMikael Gonella-Bolduc 353*ec08c395SMikael Gonella-Bolduc /* Scale mapping extracted from datasheet */ 354*ec08c395SMikael Gonella-Bolduc static const struct apds9160_scale apds9160_als_scale_map[] = { 355*ec08c395SMikael Gonella-Bolduc { 356*ec08c395SMikael Gonella-Bolduc .itime = 25, 357*ec08c395SMikael Gonella-Bolduc .gain = 1, 358*ec08c395SMikael Gonella-Bolduc .scale1 = 3, 359*ec08c395SMikael Gonella-Bolduc .scale2 = 272000, 360*ec08c395SMikael Gonella-Bolduc }, 361*ec08c395SMikael Gonella-Bolduc { 362*ec08c395SMikael Gonella-Bolduc .itime = 25, 363*ec08c395SMikael Gonella-Bolduc .gain = 3, 364*ec08c395SMikael Gonella-Bolduc .scale1 = 1, 365*ec08c395SMikael Gonella-Bolduc .scale2 = 77000, 366*ec08c395SMikael Gonella-Bolduc }, 367*ec08c395SMikael Gonella-Bolduc { 368*ec08c395SMikael Gonella-Bolduc .itime = 25, 369*ec08c395SMikael Gonella-Bolduc .gain = 6, 370*ec08c395SMikael Gonella-Bolduc .scale1 = 0, 371*ec08c395SMikael Gonella-Bolduc .scale2 = 525000, 372*ec08c395SMikael Gonella-Bolduc }, 373*ec08c395SMikael Gonella-Bolduc { 374*ec08c395SMikael Gonella-Bolduc .itime = 25, 375*ec08c395SMikael Gonella-Bolduc .gain = 18, 376*ec08c395SMikael Gonella-Bolduc .scale1 = 0, 377*ec08c395SMikael Gonella-Bolduc .scale2 = 169000, 378*ec08c395SMikael Gonella-Bolduc }, 379*ec08c395SMikael Gonella-Bolduc { 380*ec08c395SMikael Gonella-Bolduc .itime = 25, 381*ec08c395SMikael Gonella-Bolduc .gain = 54, 382*ec08c395SMikael Gonella-Bolduc .scale1 = 0, 383*ec08c395SMikael Gonella-Bolduc .scale2 = 49000, 384*ec08c395SMikael Gonella-Bolduc }, 385*ec08c395SMikael Gonella-Bolduc { 386*ec08c395SMikael Gonella-Bolduc .itime = 50, 387*ec08c395SMikael Gonella-Bolduc .gain = 1, 388*ec08c395SMikael Gonella-Bolduc .scale1 = 1, 389*ec08c395SMikael Gonella-Bolduc .scale2 = 639000, 390*ec08c395SMikael Gonella-Bolduc }, 391*ec08c395SMikael Gonella-Bolduc { 392*ec08c395SMikael Gonella-Bolduc .itime = 50, 393*ec08c395SMikael Gonella-Bolduc .gain = 3, 394*ec08c395SMikael Gonella-Bolduc .scale1 = 0, 395*ec08c395SMikael Gonella-Bolduc .scale2 = 538000, 396*ec08c395SMikael Gonella-Bolduc }, 397*ec08c395SMikael Gonella-Bolduc { 398*ec08c395SMikael Gonella-Bolduc .itime = 50, 399*ec08c395SMikael Gonella-Bolduc .gain = 6, 400*ec08c395SMikael Gonella-Bolduc .scale1 = 0, 401*ec08c395SMikael Gonella-Bolduc .scale2 = 263000, 402*ec08c395SMikael Gonella-Bolduc }, 403*ec08c395SMikael Gonella-Bolduc { 404*ec08c395SMikael Gonella-Bolduc .itime = 50, 405*ec08c395SMikael Gonella-Bolduc .gain = 18, 406*ec08c395SMikael Gonella-Bolduc .scale1 = 0, 407*ec08c395SMikael Gonella-Bolduc .scale2 = 84000, 408*ec08c395SMikael Gonella-Bolduc }, 409*ec08c395SMikael Gonella-Bolduc { 410*ec08c395SMikael Gonella-Bolduc .itime = 50, 411*ec08c395SMikael Gonella-Bolduc .gain = 54, 412*ec08c395SMikael Gonella-Bolduc .scale1 = 0, 413*ec08c395SMikael Gonella-Bolduc .scale2 = 25000, 414*ec08c395SMikael Gonella-Bolduc }, 415*ec08c395SMikael Gonella-Bolduc { 416*ec08c395SMikael Gonella-Bolduc .itime = 100, 417*ec08c395SMikael Gonella-Bolduc .gain = 1, 418*ec08c395SMikael Gonella-Bolduc .scale1 = 0, 419*ec08c395SMikael Gonella-Bolduc .scale2 = 819000, 420*ec08c395SMikael Gonella-Bolduc }, 421*ec08c395SMikael Gonella-Bolduc { 422*ec08c395SMikael Gonella-Bolduc .itime = 100, 423*ec08c395SMikael Gonella-Bolduc .gain = 3, 424*ec08c395SMikael Gonella-Bolduc .scale1 = 0, 425*ec08c395SMikael Gonella-Bolduc .scale2 = 269000, 426*ec08c395SMikael Gonella-Bolduc }, 427*ec08c395SMikael Gonella-Bolduc { 428*ec08c395SMikael Gonella-Bolduc .itime = 100, 429*ec08c395SMikael Gonella-Bolduc .gain = 6, 430*ec08c395SMikael Gonella-Bolduc .scale1 = 0, 431*ec08c395SMikael Gonella-Bolduc .scale2 = 131000, 432*ec08c395SMikael Gonella-Bolduc }, 433*ec08c395SMikael Gonella-Bolduc { 434*ec08c395SMikael Gonella-Bolduc .itime = 100, 435*ec08c395SMikael Gonella-Bolduc .gain = 18, 436*ec08c395SMikael Gonella-Bolduc .scale1 = 0, 437*ec08c395SMikael Gonella-Bolduc .scale2 = 42000, 438*ec08c395SMikael Gonella-Bolduc }, 439*ec08c395SMikael Gonella-Bolduc { 440*ec08c395SMikael Gonella-Bolduc .itime = 100, 441*ec08c395SMikael Gonella-Bolduc .gain = 54, 442*ec08c395SMikael Gonella-Bolduc .scale1 = 0, 443*ec08c395SMikael Gonella-Bolduc .scale2 = 12000, 444*ec08c395SMikael Gonella-Bolduc }, 445*ec08c395SMikael Gonella-Bolduc { 446*ec08c395SMikael Gonella-Bolduc .itime = 200, 447*ec08c395SMikael Gonella-Bolduc .gain = 1, 448*ec08c395SMikael Gonella-Bolduc .scale1 = 0, 449*ec08c395SMikael Gonella-Bolduc .scale2 = 409000, 450*ec08c395SMikael Gonella-Bolduc }, 451*ec08c395SMikael Gonella-Bolduc { 452*ec08c395SMikael Gonella-Bolduc .itime = 200, 453*ec08c395SMikael Gonella-Bolduc .gain = 3, 454*ec08c395SMikael Gonella-Bolduc .scale1 = 0, 455*ec08c395SMikael Gonella-Bolduc .scale2 = 135000, 456*ec08c395SMikael Gonella-Bolduc }, 457*ec08c395SMikael Gonella-Bolduc { 458*ec08c395SMikael Gonella-Bolduc .itime = 200, 459*ec08c395SMikael Gonella-Bolduc .gain = 6, 460*ec08c395SMikael Gonella-Bolduc .scale1 = 0, 461*ec08c395SMikael Gonella-Bolduc .scale2 = 66000, 462*ec08c395SMikael Gonella-Bolduc }, 463*ec08c395SMikael Gonella-Bolduc { 464*ec08c395SMikael Gonella-Bolduc .itime = 200, 465*ec08c395SMikael Gonella-Bolduc .gain = 18, 466*ec08c395SMikael Gonella-Bolduc .scale1 = 0, 467*ec08c395SMikael Gonella-Bolduc .scale2 = 21000, 468*ec08c395SMikael Gonella-Bolduc }, 469*ec08c395SMikael Gonella-Bolduc { 470*ec08c395SMikael Gonella-Bolduc .itime = 200, 471*ec08c395SMikael Gonella-Bolduc .gain = 54, 472*ec08c395SMikael Gonella-Bolduc .scale1 = 0, 473*ec08c395SMikael Gonella-Bolduc .scale2 = 6000, 474*ec08c395SMikael Gonella-Bolduc }, 475*ec08c395SMikael Gonella-Bolduc }; 476*ec08c395SMikael Gonella-Bolduc 477*ec08c395SMikael Gonella-Bolduc static const int apds9160_25ms_avail[][2] = { 478*ec08c395SMikael Gonella-Bolduc { 3, 272000 }, 479*ec08c395SMikael Gonella-Bolduc { 1, 77000 }, 480*ec08c395SMikael Gonella-Bolduc { 0, 525000 }, 481*ec08c395SMikael Gonella-Bolduc { 0, 169000 }, 482*ec08c395SMikael Gonella-Bolduc { 0, 49000 }, 483*ec08c395SMikael Gonella-Bolduc }; 484*ec08c395SMikael Gonella-Bolduc 485*ec08c395SMikael Gonella-Bolduc static const int apds9160_50ms_avail[][2] = { 486*ec08c395SMikael Gonella-Bolduc { 1, 639000 }, 487*ec08c395SMikael Gonella-Bolduc { 0, 538000 }, 488*ec08c395SMikael Gonella-Bolduc { 0, 263000 }, 489*ec08c395SMikael Gonella-Bolduc { 0, 84000 }, 490*ec08c395SMikael Gonella-Bolduc { 0, 25000 }, 491*ec08c395SMikael Gonella-Bolduc }; 492*ec08c395SMikael Gonella-Bolduc 493*ec08c395SMikael Gonella-Bolduc static const int apds9160_100ms_avail[][2] = { 494*ec08c395SMikael Gonella-Bolduc { 0, 819000 }, 495*ec08c395SMikael Gonella-Bolduc { 0, 269000 }, 496*ec08c395SMikael Gonella-Bolduc { 0, 131000 }, 497*ec08c395SMikael Gonella-Bolduc { 0, 42000 }, 498*ec08c395SMikael Gonella-Bolduc { 0, 12000 }, 499*ec08c395SMikael Gonella-Bolduc }; 500*ec08c395SMikael Gonella-Bolduc 501*ec08c395SMikael Gonella-Bolduc static const int apds9160_200ms_avail[][2] = { 502*ec08c395SMikael Gonella-Bolduc { 0, 409000 }, 503*ec08c395SMikael Gonella-Bolduc { 0, 135000 }, 504*ec08c395SMikael Gonella-Bolduc { 0, 66000 }, 505*ec08c395SMikael Gonella-Bolduc { 0, 21000 }, 506*ec08c395SMikael Gonella-Bolduc { 0, 6000 }, 507*ec08c395SMikael Gonella-Bolduc }; 508*ec08c395SMikael Gonella-Bolduc 509*ec08c395SMikael Gonella-Bolduc static const struct reg_field apds9160_reg_field_ls_en = 510*ec08c395SMikael Gonella-Bolduc REG_FIELD(APDS9160_REG_CTRL, 1, 1); 511*ec08c395SMikael Gonella-Bolduc 512*ec08c395SMikael Gonella-Bolduc static const struct reg_field apds9160_reg_field_ps_en = 513*ec08c395SMikael Gonella-Bolduc REG_FIELD(APDS9160_REG_CTRL, 0, 0); 514*ec08c395SMikael Gonella-Bolduc 515*ec08c395SMikael Gonella-Bolduc static const struct reg_field apds9160_reg_field_int_ps = 516*ec08c395SMikael Gonella-Bolduc REG_FIELD(APDS9160_REG_INT_CFG, 0, 0); 517*ec08c395SMikael Gonella-Bolduc 518*ec08c395SMikael Gonella-Bolduc static const struct reg_field apds9160_reg_field_int_als = 519*ec08c395SMikael Gonella-Bolduc REG_FIELD(APDS9160_REG_INT_CFG, 2, 2); 520*ec08c395SMikael Gonella-Bolduc 521*ec08c395SMikael Gonella-Bolduc static const struct reg_field apds9160_reg_field_ps_overflow = 522*ec08c395SMikael Gonella-Bolduc REG_FIELD(APDS9160_REG_PS_DATA_MSB, 3, 3); 523*ec08c395SMikael Gonella-Bolduc 524*ec08c395SMikael Gonella-Bolduc static const struct reg_field apds9160_reg_field_als_rate = 525*ec08c395SMikael Gonella-Bolduc REG_FIELD(APDS9160_REG_LS_MEAS_RATE, 0, 2); 526*ec08c395SMikael Gonella-Bolduc 527*ec08c395SMikael Gonella-Bolduc static const struct reg_field apds9160_reg_field_als_gain = 528*ec08c395SMikael Gonella-Bolduc REG_FIELD(APDS9160_REG_LS_GAIN, 0, 2); 529*ec08c395SMikael Gonella-Bolduc 530*ec08c395SMikael Gonella-Bolduc static const struct reg_field apds9160_reg_field_ps_rate = 531*ec08c395SMikael Gonella-Bolduc REG_FIELD(APDS9160_REG_PS_MEAS_RATE, 0, 2); 532*ec08c395SMikael Gonella-Bolduc 533*ec08c395SMikael Gonella-Bolduc static const struct reg_field apds9160_reg_field_als_res = 534*ec08c395SMikael Gonella-Bolduc REG_FIELD(APDS9160_REG_LS_MEAS_RATE, 4, 6); 535*ec08c395SMikael Gonella-Bolduc 536*ec08c395SMikael Gonella-Bolduc static const struct reg_field apds9160_reg_field_ps_current = 537*ec08c395SMikael Gonella-Bolduc REG_FIELD(APDS9160_REG_PS_LED, 0, 2); 538*ec08c395SMikael Gonella-Bolduc 539*ec08c395SMikael Gonella-Bolduc static const struct reg_field apds9160_reg_field_ps_gain = 540*ec08c395SMikael Gonella-Bolduc REG_FIELD(APDS9160_REG_PS_MEAS_RATE, 6, 7); 541*ec08c395SMikael Gonella-Bolduc 542*ec08c395SMikael Gonella-Bolduc static const struct reg_field apds9160_reg_field_ps_resolution = 543*ec08c395SMikael Gonella-Bolduc REG_FIELD(APDS9160_REG_PS_MEAS_RATE, 3, 4); 544*ec08c395SMikael Gonella-Bolduc 545*ec08c395SMikael Gonella-Bolduc struct apds9160_chip { 546*ec08c395SMikael Gonella-Bolduc struct i2c_client *client; 547*ec08c395SMikael Gonella-Bolduc struct regmap *regmap; 548*ec08c395SMikael Gonella-Bolduc 549*ec08c395SMikael Gonella-Bolduc struct regmap_field *reg_enable_ps; 550*ec08c395SMikael Gonella-Bolduc struct regmap_field *reg_enable_als; 551*ec08c395SMikael Gonella-Bolduc struct regmap_field *reg_int_ps; 552*ec08c395SMikael Gonella-Bolduc struct regmap_field *reg_int_als; 553*ec08c395SMikael Gonella-Bolduc struct regmap_field *reg_ps_overflow; 554*ec08c395SMikael Gonella-Bolduc struct regmap_field *reg_als_rate; 555*ec08c395SMikael Gonella-Bolduc struct regmap_field *reg_als_resolution; 556*ec08c395SMikael Gonella-Bolduc struct regmap_field *reg_ps_rate; 557*ec08c395SMikael Gonella-Bolduc struct regmap_field *reg_als_gain; 558*ec08c395SMikael Gonella-Bolduc struct regmap_field *reg_ps_current; 559*ec08c395SMikael Gonella-Bolduc struct regmap_field *reg_ps_gain; 560*ec08c395SMikael Gonella-Bolduc struct regmap_field *reg_ps_resolution; 561*ec08c395SMikael Gonella-Bolduc 562*ec08c395SMikael Gonella-Bolduc struct mutex lock; /* protects state and config data */ 563*ec08c395SMikael Gonella-Bolduc 564*ec08c395SMikael Gonella-Bolduc /* State data */ 565*ec08c395SMikael Gonella-Bolduc int als_int; 566*ec08c395SMikael Gonella-Bolduc int ps_int; 567*ec08c395SMikael Gonella-Bolduc 568*ec08c395SMikael Gonella-Bolduc /* Configuration values */ 569*ec08c395SMikael Gonella-Bolduc int als_itime; 570*ec08c395SMikael Gonella-Bolduc int als_hwgain; 571*ec08c395SMikael Gonella-Bolduc int als_scale1; 572*ec08c395SMikael Gonella-Bolduc int als_scale2; 573*ec08c395SMikael Gonella-Bolduc int ps_rate; 574*ec08c395SMikael Gonella-Bolduc int ps_cancellation_level; 575*ec08c395SMikael Gonella-Bolduc int ps_current; 576*ec08c395SMikael Gonella-Bolduc int ps_gain; 577*ec08c395SMikael Gonella-Bolduc }; 578*ec08c395SMikael Gonella-Bolduc 579*ec08c395SMikael Gonella-Bolduc static int apds9160_set_ps_rate(struct apds9160_chip *data, int val) 580*ec08c395SMikael Gonella-Bolduc { 581*ec08c395SMikael Gonella-Bolduc int idx; 582*ec08c395SMikael Gonella-Bolduc 583*ec08c395SMikael Gonella-Bolduc for (idx = 0; idx < ARRAY_SIZE(apds9160_ps_rate_map); idx++) { 584*ec08c395SMikael Gonella-Bolduc int ret; 585*ec08c395SMikael Gonella-Bolduc 586*ec08c395SMikael Gonella-Bolduc if (apds9160_ps_rate_map[idx][0] != val) 587*ec08c395SMikael Gonella-Bolduc continue; 588*ec08c395SMikael Gonella-Bolduc 589*ec08c395SMikael Gonella-Bolduc ret = regmap_field_write(data->reg_ps_rate, 590*ec08c395SMikael Gonella-Bolduc apds9160_ps_rate_map[idx][1]); 591*ec08c395SMikael Gonella-Bolduc if (ret) 592*ec08c395SMikael Gonella-Bolduc return ret; 593*ec08c395SMikael Gonella-Bolduc data->ps_rate = val; 594*ec08c395SMikael Gonella-Bolduc 595*ec08c395SMikael Gonella-Bolduc return ret; 596*ec08c395SMikael Gonella-Bolduc } 597*ec08c395SMikael Gonella-Bolduc 598*ec08c395SMikael Gonella-Bolduc return -EINVAL; 599*ec08c395SMikael Gonella-Bolduc } 600*ec08c395SMikael Gonella-Bolduc 601*ec08c395SMikael Gonella-Bolduc static int apds9160_set_ps_gain(struct apds9160_chip *data, int val) 602*ec08c395SMikael Gonella-Bolduc { 603*ec08c395SMikael Gonella-Bolduc int idx; 604*ec08c395SMikael Gonella-Bolduc 605*ec08c395SMikael Gonella-Bolduc for (idx = 0; idx < ARRAY_SIZE(apds9160_ps_gain_map); idx++) { 606*ec08c395SMikael Gonella-Bolduc int ret; 607*ec08c395SMikael Gonella-Bolduc 608*ec08c395SMikael Gonella-Bolduc if (apds9160_ps_gain_map[idx][0] != val) 609*ec08c395SMikael Gonella-Bolduc continue; 610*ec08c395SMikael Gonella-Bolduc 611*ec08c395SMikael Gonella-Bolduc ret = regmap_field_write(data->reg_ps_gain, 612*ec08c395SMikael Gonella-Bolduc apds9160_ps_gain_map[idx][1]); 613*ec08c395SMikael Gonella-Bolduc if (ret) 614*ec08c395SMikael Gonella-Bolduc return ret; 615*ec08c395SMikael Gonella-Bolduc data->ps_gain = val; 616*ec08c395SMikael Gonella-Bolduc 617*ec08c395SMikael Gonella-Bolduc return ret; 618*ec08c395SMikael Gonella-Bolduc } 619*ec08c395SMikael Gonella-Bolduc 620*ec08c395SMikael Gonella-Bolduc return -EINVAL; 621*ec08c395SMikael Gonella-Bolduc } 622*ec08c395SMikael Gonella-Bolduc 623*ec08c395SMikael Gonella-Bolduc /* 624*ec08c395SMikael Gonella-Bolduc * The PS intelligent cancellation level register allows 625*ec08c395SMikael Gonella-Bolduc * for an on-chip substraction of the ADC count caused by 626*ec08c395SMikael Gonella-Bolduc * unwanted reflected light from PS ADC output. 627*ec08c395SMikael Gonella-Bolduc */ 628*ec08c395SMikael Gonella-Bolduc static int apds9160_set_ps_cancellation_level(struct apds9160_chip *data, 629*ec08c395SMikael Gonella-Bolduc int val) 630*ec08c395SMikael Gonella-Bolduc { 631*ec08c395SMikael Gonella-Bolduc int ret; 632*ec08c395SMikael Gonella-Bolduc __le16 buf; 633*ec08c395SMikael Gonella-Bolduc 634*ec08c395SMikael Gonella-Bolduc if (val < 0 || val > 0xFFFF) 635*ec08c395SMikael Gonella-Bolduc return -EINVAL; 636*ec08c395SMikael Gonella-Bolduc 637*ec08c395SMikael Gonella-Bolduc buf = cpu_to_le16(val); 638*ec08c395SMikael Gonella-Bolduc ret = regmap_bulk_write(data->regmap, APDS9160_REG_PS_CAN_LEVEL_DIG_LSB, 639*ec08c395SMikael Gonella-Bolduc &buf, 2); 640*ec08c395SMikael Gonella-Bolduc if (ret) 641*ec08c395SMikael Gonella-Bolduc return ret; 642*ec08c395SMikael Gonella-Bolduc 643*ec08c395SMikael Gonella-Bolduc data->ps_cancellation_level = val; 644*ec08c395SMikael Gonella-Bolduc 645*ec08c395SMikael Gonella-Bolduc return ret; 646*ec08c395SMikael Gonella-Bolduc } 647*ec08c395SMikael Gonella-Bolduc 648*ec08c395SMikael Gonella-Bolduc /* 649*ec08c395SMikael Gonella-Bolduc * This parameter determines the cancellation pulse duration 650*ec08c395SMikael Gonella-Bolduc * in each of the PWM pulse. The cancellation is applied during the 651*ec08c395SMikael Gonella-Bolduc * integration phase of the PS measurement. 652*ec08c395SMikael Gonella-Bolduc * Duration is programmed in half clock cycles 653*ec08c395SMikael Gonella-Bolduc * A duration value of 0 or 1 will not generate any cancellation pulse 654*ec08c395SMikael Gonella-Bolduc */ 655*ec08c395SMikael Gonella-Bolduc static int apds9160_set_ps_analog_cancellation(struct apds9160_chip *data, 656*ec08c395SMikael Gonella-Bolduc int val) 657*ec08c395SMikael Gonella-Bolduc { 658*ec08c395SMikael Gonella-Bolduc if (val < 0 || val > 63) 659*ec08c395SMikael Gonella-Bolduc return -EINVAL; 660*ec08c395SMikael Gonella-Bolduc 661*ec08c395SMikael Gonella-Bolduc return regmap_write(data->regmap, APDS9160_REG_PS_CAN_LEVEL_ANA_DUR, 662*ec08c395SMikael Gonella-Bolduc val); 663*ec08c395SMikael Gonella-Bolduc } 664*ec08c395SMikael Gonella-Bolduc 665*ec08c395SMikael Gonella-Bolduc /* 666*ec08c395SMikael Gonella-Bolduc * This parameter works in conjunction with the cancellation pulse duration 667*ec08c395SMikael Gonella-Bolduc * The value determines the current used for crosstalk cancellation 668*ec08c395SMikael Gonella-Bolduc * Coarse value is in steps of 60 nA 669*ec08c395SMikael Gonella-Bolduc * Fine value is in steps of 2.4 nA 670*ec08c395SMikael Gonella-Bolduc */ 671*ec08c395SMikael Gonella-Bolduc static int apds9160_set_ps_cancellation_current(struct apds9160_chip *data, 672*ec08c395SMikael Gonella-Bolduc int coarse_val, 673*ec08c395SMikael Gonella-Bolduc int fine_val) 674*ec08c395SMikael Gonella-Bolduc { 675*ec08c395SMikael Gonella-Bolduc int val; 676*ec08c395SMikael Gonella-Bolduc 677*ec08c395SMikael Gonella-Bolduc if (coarse_val < 0 || coarse_val > 4) 678*ec08c395SMikael Gonella-Bolduc return -EINVAL; 679*ec08c395SMikael Gonella-Bolduc 680*ec08c395SMikael Gonella-Bolduc if (fine_val < 0 || fine_val > 15) 681*ec08c395SMikael Gonella-Bolduc return -EINVAL; 682*ec08c395SMikael Gonella-Bolduc 683*ec08c395SMikael Gonella-Bolduc /* Coarse value at B4:B5 and fine value at B0:B3 */ 684*ec08c395SMikael Gonella-Bolduc val = (coarse_val << 4) | fine_val; 685*ec08c395SMikael Gonella-Bolduc 686*ec08c395SMikael Gonella-Bolduc return regmap_write(data->regmap, APDS9160_REG_PS_CAN_LEVEL_ANA_CURRENT, 687*ec08c395SMikael Gonella-Bolduc val); 688*ec08c395SMikael Gonella-Bolduc } 689*ec08c395SMikael Gonella-Bolduc 690*ec08c395SMikael Gonella-Bolduc static int apds9160_ps_init_analog_cancellation(struct device *dev, 691*ec08c395SMikael Gonella-Bolduc struct apds9160_chip *data) 692*ec08c395SMikael Gonella-Bolduc { 693*ec08c395SMikael Gonella-Bolduc int ret, duration, picoamp, idx, coarse, fine; 694*ec08c395SMikael Gonella-Bolduc 695*ec08c395SMikael Gonella-Bolduc ret = device_property_read_u32(dev, 696*ec08c395SMikael Gonella-Bolduc "ps-cancellation-duration", &duration); 697*ec08c395SMikael Gonella-Bolduc if (ret || duration == 0) { 698*ec08c395SMikael Gonella-Bolduc /* Don't fail since this is not required */ 699*ec08c395SMikael Gonella-Bolduc return 0; 700*ec08c395SMikael Gonella-Bolduc } 701*ec08c395SMikael Gonella-Bolduc 702*ec08c395SMikael Gonella-Bolduc ret = device_property_read_u32(dev, 703*ec08c395SMikael Gonella-Bolduc "ps-cancellation-current-picoamp", &picoamp); 704*ec08c395SMikael Gonella-Bolduc if (ret) 705*ec08c395SMikael Gonella-Bolduc return ret; 706*ec08c395SMikael Gonella-Bolduc 707*ec08c395SMikael Gonella-Bolduc if (picoamp < 60000 || picoamp > 276000 || picoamp % 2400 != 0) 708*ec08c395SMikael Gonella-Bolduc return dev_err_probe(dev, -EINVAL, 709*ec08c395SMikael Gonella-Bolduc "Invalid cancellation current\n"); 710*ec08c395SMikael Gonella-Bolduc 711*ec08c395SMikael Gonella-Bolduc /* Compute required coarse and fine value from requested current */ 712*ec08c395SMikael Gonella-Bolduc fine = 0; 713*ec08c395SMikael Gonella-Bolduc coarse = 0; 714*ec08c395SMikael Gonella-Bolduc for (idx = 60000; idx < picoamp; idx += 2400) { 715*ec08c395SMikael Gonella-Bolduc if (fine == 15) { 716*ec08c395SMikael Gonella-Bolduc fine = 0; 717*ec08c395SMikael Gonella-Bolduc coarse++; 718*ec08c395SMikael Gonella-Bolduc idx += 21600; 719*ec08c395SMikael Gonella-Bolduc } else { 720*ec08c395SMikael Gonella-Bolduc fine++; 721*ec08c395SMikael Gonella-Bolduc } 722*ec08c395SMikael Gonella-Bolduc } 723*ec08c395SMikael Gonella-Bolduc 724*ec08c395SMikael Gonella-Bolduc if (picoamp != idx) 725*ec08c395SMikael Gonella-Bolduc dev_warn(dev, 726*ec08c395SMikael Gonella-Bolduc "Invalid cancellation current %i, rounding to %i\n", 727*ec08c395SMikael Gonella-Bolduc picoamp, idx); 728*ec08c395SMikael Gonella-Bolduc 729*ec08c395SMikael Gonella-Bolduc ret = apds9160_set_ps_analog_cancellation(data, duration); 730*ec08c395SMikael Gonella-Bolduc if (ret) 731*ec08c395SMikael Gonella-Bolduc return ret; 732*ec08c395SMikael Gonella-Bolduc 733*ec08c395SMikael Gonella-Bolduc return apds9160_set_ps_cancellation_current(data, coarse, fine); 734*ec08c395SMikael Gonella-Bolduc } 735*ec08c395SMikael Gonella-Bolduc 736*ec08c395SMikael Gonella-Bolduc static int apds9160_set_ps_current(struct apds9160_chip *data, int val) 737*ec08c395SMikael Gonella-Bolduc { 738*ec08c395SMikael Gonella-Bolduc int idx; 739*ec08c395SMikael Gonella-Bolduc 740*ec08c395SMikael Gonella-Bolduc for (idx = 0; idx < ARRAY_SIZE(apds9160_ps_led_current_map); idx++) { 741*ec08c395SMikael Gonella-Bolduc int ret; 742*ec08c395SMikael Gonella-Bolduc 743*ec08c395SMikael Gonella-Bolduc if (apds9160_ps_led_current_map[idx][0] != val) 744*ec08c395SMikael Gonella-Bolduc continue; 745*ec08c395SMikael Gonella-Bolduc 746*ec08c395SMikael Gonella-Bolduc ret = regmap_field_write( 747*ec08c395SMikael Gonella-Bolduc data->reg_ps_current, 748*ec08c395SMikael Gonella-Bolduc apds9160_ps_led_current_map[idx][1]); 749*ec08c395SMikael Gonella-Bolduc if (ret) 750*ec08c395SMikael Gonella-Bolduc return ret; 751*ec08c395SMikael Gonella-Bolduc data->ps_current = val; 752*ec08c395SMikael Gonella-Bolduc 753*ec08c395SMikael Gonella-Bolduc return ret; 754*ec08c395SMikael Gonella-Bolduc } 755*ec08c395SMikael Gonella-Bolduc 756*ec08c395SMikael Gonella-Bolduc return -EINVAL; 757*ec08c395SMikael Gonella-Bolduc } 758*ec08c395SMikael Gonella-Bolduc 759*ec08c395SMikael Gonella-Bolduc static int apds9160_set_als_gain(struct apds9160_chip *data, int gain) 760*ec08c395SMikael Gonella-Bolduc { 761*ec08c395SMikael Gonella-Bolduc int idx; 762*ec08c395SMikael Gonella-Bolduc 763*ec08c395SMikael Gonella-Bolduc for (idx = 0; idx < ARRAY_SIZE(apds9160_als_gain_map); idx++) { 764*ec08c395SMikael Gonella-Bolduc int ret; 765*ec08c395SMikael Gonella-Bolduc 766*ec08c395SMikael Gonella-Bolduc if (gain != apds9160_als_gain_map[idx][0]) 767*ec08c395SMikael Gonella-Bolduc continue; 768*ec08c395SMikael Gonella-Bolduc 769*ec08c395SMikael Gonella-Bolduc ret = regmap_field_write(data->reg_als_gain, 770*ec08c395SMikael Gonella-Bolduc apds9160_als_gain_map[idx][1]); 771*ec08c395SMikael Gonella-Bolduc if (ret) 772*ec08c395SMikael Gonella-Bolduc return ret; 773*ec08c395SMikael Gonella-Bolduc data->als_hwgain = gain; 774*ec08c395SMikael Gonella-Bolduc 775*ec08c395SMikael Gonella-Bolduc return ret; 776*ec08c395SMikael Gonella-Bolduc } 777*ec08c395SMikael Gonella-Bolduc 778*ec08c395SMikael Gonella-Bolduc return -EINVAL; 779*ec08c395SMikael Gonella-Bolduc } 780*ec08c395SMikael Gonella-Bolduc 781*ec08c395SMikael Gonella-Bolduc static int apds9160_set_als_scale(struct apds9160_chip *data, int val, int val2) 782*ec08c395SMikael Gonella-Bolduc { 783*ec08c395SMikael Gonella-Bolduc int idx; 784*ec08c395SMikael Gonella-Bolduc 785*ec08c395SMikael Gonella-Bolduc for (idx = 0; idx < ARRAY_SIZE(apds9160_als_scale_map); idx++) { 786*ec08c395SMikael Gonella-Bolduc if (apds9160_als_scale_map[idx].itime == data->als_itime && 787*ec08c395SMikael Gonella-Bolduc apds9160_als_scale_map[idx].scale1 == val && 788*ec08c395SMikael Gonella-Bolduc apds9160_als_scale_map[idx].scale2 == val2) { 789*ec08c395SMikael Gonella-Bolduc int ret = apds9160_set_als_gain(data, 790*ec08c395SMikael Gonella-Bolduc apds9160_als_scale_map[idx].gain); 791*ec08c395SMikael Gonella-Bolduc if (ret) 792*ec08c395SMikael Gonella-Bolduc return ret; 793*ec08c395SMikael Gonella-Bolduc data->als_scale1 = val; 794*ec08c395SMikael Gonella-Bolduc data->als_scale2 = val2; 795*ec08c395SMikael Gonella-Bolduc 796*ec08c395SMikael Gonella-Bolduc return ret; 797*ec08c395SMikael Gonella-Bolduc } 798*ec08c395SMikael Gonella-Bolduc } 799*ec08c395SMikael Gonella-Bolduc 800*ec08c395SMikael Gonella-Bolduc return -EINVAL; 801*ec08c395SMikael Gonella-Bolduc } 802*ec08c395SMikael Gonella-Bolduc 803*ec08c395SMikael Gonella-Bolduc static int apds9160_set_als_resolution(struct apds9160_chip *data, int val) 804*ec08c395SMikael Gonella-Bolduc { 805*ec08c395SMikael Gonella-Bolduc switch (val) { 806*ec08c395SMikael Gonella-Bolduc case 25: 807*ec08c395SMikael Gonella-Bolduc return regmap_field_write(data->reg_als_resolution, 808*ec08c395SMikael Gonella-Bolduc APDS9160_CMD_LS_RESOLUTION_25MS); 809*ec08c395SMikael Gonella-Bolduc case 50: 810*ec08c395SMikael Gonella-Bolduc return regmap_field_write(data->reg_als_resolution, 811*ec08c395SMikael Gonella-Bolduc APDS9160_CMD_LS_RESOLUTION_50MS); 812*ec08c395SMikael Gonella-Bolduc case 200: 813*ec08c395SMikael Gonella-Bolduc return regmap_field_write(data->reg_als_resolution, 814*ec08c395SMikael Gonella-Bolduc APDS9160_CMD_LS_RESOLUTION_200MS); 815*ec08c395SMikael Gonella-Bolduc default: 816*ec08c395SMikael Gonella-Bolduc return regmap_field_write(data->reg_als_resolution, 817*ec08c395SMikael Gonella-Bolduc APDS9160_CMD_LS_RESOLUTION_100MS); 818*ec08c395SMikael Gonella-Bolduc } 819*ec08c395SMikael Gonella-Bolduc } 820*ec08c395SMikael Gonella-Bolduc 821*ec08c395SMikael Gonella-Bolduc static int apds9160_set_als_rate(struct apds9160_chip *data, int val) 822*ec08c395SMikael Gonella-Bolduc { 823*ec08c395SMikael Gonella-Bolduc int idx; 824*ec08c395SMikael Gonella-Bolduc 825*ec08c395SMikael Gonella-Bolduc for (idx = 0; idx < ARRAY_SIZE(apds9160_als_rate_map); idx++) { 826*ec08c395SMikael Gonella-Bolduc if (apds9160_als_rate_map[idx][0] != val) 827*ec08c395SMikael Gonella-Bolduc continue; 828*ec08c395SMikael Gonella-Bolduc 829*ec08c395SMikael Gonella-Bolduc return regmap_field_write(data->reg_als_rate, 830*ec08c395SMikael Gonella-Bolduc apds9160_als_rate_map[idx][1]); 831*ec08c395SMikael Gonella-Bolduc } 832*ec08c395SMikael Gonella-Bolduc 833*ec08c395SMikael Gonella-Bolduc return -EINVAL; 834*ec08c395SMikael Gonella-Bolduc } 835*ec08c395SMikael Gonella-Bolduc 836*ec08c395SMikael Gonella-Bolduc /* 837*ec08c395SMikael Gonella-Bolduc * Setting the integration time ajusts resolution, rate, scale and gain 838*ec08c395SMikael Gonella-Bolduc */ 839*ec08c395SMikael Gonella-Bolduc static int apds9160_set_als_int_time(struct apds9160_chip *data, int val) 840*ec08c395SMikael Gonella-Bolduc { 841*ec08c395SMikael Gonella-Bolduc int ret; 842*ec08c395SMikael Gonella-Bolduc int idx; 843*ec08c395SMikael Gonella-Bolduc 844*ec08c395SMikael Gonella-Bolduc ret = apds9160_set_als_rate(data, val); 845*ec08c395SMikael Gonella-Bolduc if (ret) 846*ec08c395SMikael Gonella-Bolduc return ret; 847*ec08c395SMikael Gonella-Bolduc 848*ec08c395SMikael Gonella-Bolduc /* Match resolution register with rate */ 849*ec08c395SMikael Gonella-Bolduc ret = apds9160_set_als_resolution(data, val); 850*ec08c395SMikael Gonella-Bolduc if (ret) 851*ec08c395SMikael Gonella-Bolduc return ret; 852*ec08c395SMikael Gonella-Bolduc 853*ec08c395SMikael Gonella-Bolduc data->als_itime = val; 854*ec08c395SMikael Gonella-Bolduc 855*ec08c395SMikael Gonella-Bolduc /* Set the scale minimum gain */ 856*ec08c395SMikael Gonella-Bolduc for (idx = 0; idx < ARRAY_SIZE(apds9160_als_scale_map); idx++) { 857*ec08c395SMikael Gonella-Bolduc if (data->als_itime != apds9160_als_scale_map[idx].itime) 858*ec08c395SMikael Gonella-Bolduc continue; 859*ec08c395SMikael Gonella-Bolduc 860*ec08c395SMikael Gonella-Bolduc return apds9160_set_als_scale(data, 861*ec08c395SMikael Gonella-Bolduc apds9160_als_scale_map[idx].scale1, 862*ec08c395SMikael Gonella-Bolduc apds9160_als_scale_map[idx].scale2); 863*ec08c395SMikael Gonella-Bolduc } 864*ec08c395SMikael Gonella-Bolduc 865*ec08c395SMikael Gonella-Bolduc return -EINVAL; 866*ec08c395SMikael Gonella-Bolduc } 867*ec08c395SMikael Gonella-Bolduc 868*ec08c395SMikael Gonella-Bolduc static int apds9160_read_avail(struct iio_dev *indio_dev, 869*ec08c395SMikael Gonella-Bolduc struct iio_chan_spec const *chan, 870*ec08c395SMikael Gonella-Bolduc const int **vals, int *type, int *length, 871*ec08c395SMikael Gonella-Bolduc long mask) 872*ec08c395SMikael Gonella-Bolduc { 873*ec08c395SMikael Gonella-Bolduc struct apds9160_chip *data = iio_priv(indio_dev); 874*ec08c395SMikael Gonella-Bolduc 875*ec08c395SMikael Gonella-Bolduc switch (mask) { 876*ec08c395SMikael Gonella-Bolduc case IIO_CHAN_INFO_INT_TIME: 877*ec08c395SMikael Gonella-Bolduc switch (chan->type) { 878*ec08c395SMikael Gonella-Bolduc case IIO_LIGHT: 879*ec08c395SMikael Gonella-Bolduc *length = ARRAY_SIZE(apds9160_als_rate_avail); 880*ec08c395SMikael Gonella-Bolduc *vals = (const int *)apds9160_als_rate_avail; 881*ec08c395SMikael Gonella-Bolduc *type = IIO_VAL_INT; 882*ec08c395SMikael Gonella-Bolduc 883*ec08c395SMikael Gonella-Bolduc return IIO_AVAIL_LIST; 884*ec08c395SMikael Gonella-Bolduc case IIO_PROXIMITY: 885*ec08c395SMikael Gonella-Bolduc *length = ARRAY_SIZE(apds9160_ps_rate_avail); 886*ec08c395SMikael Gonella-Bolduc *vals = (const int *)apds9160_ps_rate_avail; 887*ec08c395SMikael Gonella-Bolduc *type = IIO_VAL_INT; 888*ec08c395SMikael Gonella-Bolduc 889*ec08c395SMikael Gonella-Bolduc return IIO_AVAIL_LIST; 890*ec08c395SMikael Gonella-Bolduc default: 891*ec08c395SMikael Gonella-Bolduc return -EINVAL; 892*ec08c395SMikael Gonella-Bolduc } 893*ec08c395SMikael Gonella-Bolduc case IIO_CHAN_INFO_SCALE: 894*ec08c395SMikael Gonella-Bolduc switch (chan->type) { 895*ec08c395SMikael Gonella-Bolduc case IIO_PROXIMITY: 896*ec08c395SMikael Gonella-Bolduc *length = ARRAY_SIZE(apds9160_ps_gain_avail); 897*ec08c395SMikael Gonella-Bolduc *vals = (const int *)apds9160_ps_gain_avail; 898*ec08c395SMikael Gonella-Bolduc *type = IIO_VAL_INT; 899*ec08c395SMikael Gonella-Bolduc 900*ec08c395SMikael Gonella-Bolduc return IIO_AVAIL_LIST; 901*ec08c395SMikael Gonella-Bolduc case IIO_LIGHT: 902*ec08c395SMikael Gonella-Bolduc /* The available scales changes depending on itime */ 903*ec08c395SMikael Gonella-Bolduc switch (data->als_itime) { 904*ec08c395SMikael Gonella-Bolduc case 25: 905*ec08c395SMikael Gonella-Bolduc *length = ARRAY_SIZE(apds9160_25ms_avail) * 2; 906*ec08c395SMikael Gonella-Bolduc *vals = (const int *)apds9160_25ms_avail; 907*ec08c395SMikael Gonella-Bolduc *type = IIO_VAL_INT_PLUS_MICRO; 908*ec08c395SMikael Gonella-Bolduc 909*ec08c395SMikael Gonella-Bolduc return IIO_AVAIL_LIST; 910*ec08c395SMikael Gonella-Bolduc case 50: 911*ec08c395SMikael Gonella-Bolduc *length = ARRAY_SIZE(apds9160_50ms_avail) * 2; 912*ec08c395SMikael Gonella-Bolduc *vals = (const int *)apds9160_50ms_avail; 913*ec08c395SMikael Gonella-Bolduc *type = IIO_VAL_INT_PLUS_MICRO; 914*ec08c395SMikael Gonella-Bolduc 915*ec08c395SMikael Gonella-Bolduc return IIO_AVAIL_LIST; 916*ec08c395SMikael Gonella-Bolduc case 100: 917*ec08c395SMikael Gonella-Bolduc *length = ARRAY_SIZE(apds9160_100ms_avail) * 2; 918*ec08c395SMikael Gonella-Bolduc *vals = (const int *)apds9160_100ms_avail; 919*ec08c395SMikael Gonella-Bolduc *type = IIO_VAL_INT_PLUS_MICRO; 920*ec08c395SMikael Gonella-Bolduc 921*ec08c395SMikael Gonella-Bolduc return IIO_AVAIL_LIST; 922*ec08c395SMikael Gonella-Bolduc case 200: 923*ec08c395SMikael Gonella-Bolduc *length = ARRAY_SIZE(apds9160_200ms_avail) * 2; 924*ec08c395SMikael Gonella-Bolduc *vals = (const int *)apds9160_200ms_avail; 925*ec08c395SMikael Gonella-Bolduc *type = IIO_VAL_INT_PLUS_MICRO; 926*ec08c395SMikael Gonella-Bolduc 927*ec08c395SMikael Gonella-Bolduc return IIO_AVAIL_LIST; 928*ec08c395SMikael Gonella-Bolduc default: 929*ec08c395SMikael Gonella-Bolduc return -EINVAL; 930*ec08c395SMikael Gonella-Bolduc } 931*ec08c395SMikael Gonella-Bolduc default: 932*ec08c395SMikael Gonella-Bolduc return -EINVAL; 933*ec08c395SMikael Gonella-Bolduc } 934*ec08c395SMikael Gonella-Bolduc case IIO_CHAN_INFO_RAW: 935*ec08c395SMikael Gonella-Bolduc switch (chan->type) { 936*ec08c395SMikael Gonella-Bolduc case IIO_CURRENT: 937*ec08c395SMikael Gonella-Bolduc *length = ARRAY_SIZE(apds9160_ps_led_current_avail); 938*ec08c395SMikael Gonella-Bolduc *vals = (const int *)apds9160_ps_led_current_avail; 939*ec08c395SMikael Gonella-Bolduc *type = IIO_VAL_INT; 940*ec08c395SMikael Gonella-Bolduc 941*ec08c395SMikael Gonella-Bolduc return IIO_AVAIL_LIST; 942*ec08c395SMikael Gonella-Bolduc default: 943*ec08c395SMikael Gonella-Bolduc return -EINVAL; 944*ec08c395SMikael Gonella-Bolduc } 945*ec08c395SMikael Gonella-Bolduc 946*ec08c395SMikael Gonella-Bolduc default: 947*ec08c395SMikael Gonella-Bolduc return -EINVAL; 948*ec08c395SMikael Gonella-Bolduc } 949*ec08c395SMikael Gonella-Bolduc } 950*ec08c395SMikael Gonella-Bolduc 951*ec08c395SMikael Gonella-Bolduc static int apds9160_write_raw_get_fmt(struct iio_dev *indio_dev, 952*ec08c395SMikael Gonella-Bolduc struct iio_chan_spec const *chan, 953*ec08c395SMikael Gonella-Bolduc long mask) 954*ec08c395SMikael Gonella-Bolduc { 955*ec08c395SMikael Gonella-Bolduc switch (mask) { 956*ec08c395SMikael Gonella-Bolduc case IIO_CHAN_INFO_INT_TIME: 957*ec08c395SMikael Gonella-Bolduc return IIO_VAL_INT; 958*ec08c395SMikael Gonella-Bolduc case IIO_CHAN_INFO_CALIBBIAS: 959*ec08c395SMikael Gonella-Bolduc return IIO_VAL_INT; 960*ec08c395SMikael Gonella-Bolduc case IIO_CHAN_INFO_HARDWAREGAIN: 961*ec08c395SMikael Gonella-Bolduc return IIO_VAL_INT; 962*ec08c395SMikael Gonella-Bolduc case IIO_CHAN_INFO_RAW: 963*ec08c395SMikael Gonella-Bolduc return IIO_VAL_INT; 964*ec08c395SMikael Gonella-Bolduc case IIO_CHAN_INFO_SCALE: 965*ec08c395SMikael Gonella-Bolduc return IIO_VAL_INT_PLUS_MICRO; 966*ec08c395SMikael Gonella-Bolduc default: 967*ec08c395SMikael Gonella-Bolduc return -EINVAL; 968*ec08c395SMikael Gonella-Bolduc } 969*ec08c395SMikael Gonella-Bolduc } 970*ec08c395SMikael Gonella-Bolduc 971*ec08c395SMikael Gonella-Bolduc static int apds9160_read_raw(struct iio_dev *indio_dev, 972*ec08c395SMikael Gonella-Bolduc struct iio_chan_spec const *chan, int *val, 973*ec08c395SMikael Gonella-Bolduc int *val2, long mask) 974*ec08c395SMikael Gonella-Bolduc { 975*ec08c395SMikael Gonella-Bolduc struct apds9160_chip *data = iio_priv(indio_dev); 976*ec08c395SMikael Gonella-Bolduc int ret; 977*ec08c395SMikael Gonella-Bolduc 978*ec08c395SMikael Gonella-Bolduc switch (mask) { 979*ec08c395SMikael Gonella-Bolduc case IIO_CHAN_INFO_RAW: 980*ec08c395SMikael Gonella-Bolduc switch (chan->type) { 981*ec08c395SMikael Gonella-Bolduc case IIO_PROXIMITY: { 982*ec08c395SMikael Gonella-Bolduc __le16 buf; 983*ec08c395SMikael Gonella-Bolduc 984*ec08c395SMikael Gonella-Bolduc ret = regmap_bulk_read(data->regmap, chan->address, 985*ec08c395SMikael Gonella-Bolduc &buf, 2); 986*ec08c395SMikael Gonella-Bolduc if (ret) 987*ec08c395SMikael Gonella-Bolduc return ret; 988*ec08c395SMikael Gonella-Bolduc *val = le16_to_cpu(buf); 989*ec08c395SMikael Gonella-Bolduc /* Remove overflow bits from result */ 990*ec08c395SMikael Gonella-Bolduc *val = FIELD_GET(APDS9160_PS_DATA_MASK, *val); 991*ec08c395SMikael Gonella-Bolduc 992*ec08c395SMikael Gonella-Bolduc return IIO_VAL_INT; 993*ec08c395SMikael Gonella-Bolduc } 994*ec08c395SMikael Gonella-Bolduc case IIO_LIGHT: 995*ec08c395SMikael Gonella-Bolduc case IIO_INTENSITY: { 996*ec08c395SMikael Gonella-Bolduc u8 buf[3]; 997*ec08c395SMikael Gonella-Bolduc 998*ec08c395SMikael Gonella-Bolduc ret = regmap_bulk_read(data->regmap, chan->address, 999*ec08c395SMikael Gonella-Bolduc &buf, 3); 1000*ec08c395SMikael Gonella-Bolduc if (ret) 1001*ec08c395SMikael Gonella-Bolduc return ret; 1002*ec08c395SMikael Gonella-Bolduc *val = get_unaligned_le24(buf); 1003*ec08c395SMikael Gonella-Bolduc 1004*ec08c395SMikael Gonella-Bolduc return IIO_VAL_INT; 1005*ec08c395SMikael Gonella-Bolduc } 1006*ec08c395SMikael Gonella-Bolduc case IIO_CURRENT: 1007*ec08c395SMikael Gonella-Bolduc *val = data->ps_current; 1008*ec08c395SMikael Gonella-Bolduc 1009*ec08c395SMikael Gonella-Bolduc return IIO_VAL_INT; 1010*ec08c395SMikael Gonella-Bolduc default: 1011*ec08c395SMikael Gonella-Bolduc return -EINVAL; 1012*ec08c395SMikael Gonella-Bolduc } 1013*ec08c395SMikael Gonella-Bolduc case IIO_CHAN_INFO_HARDWAREGAIN: 1014*ec08c395SMikael Gonella-Bolduc switch (chan->type) { 1015*ec08c395SMikael Gonella-Bolduc case IIO_LIGHT: 1016*ec08c395SMikael Gonella-Bolduc *val = data->als_hwgain; 1017*ec08c395SMikael Gonella-Bolduc 1018*ec08c395SMikael Gonella-Bolduc return IIO_VAL_INT; 1019*ec08c395SMikael Gonella-Bolduc default: 1020*ec08c395SMikael Gonella-Bolduc return -EINVAL; 1021*ec08c395SMikael Gonella-Bolduc } 1022*ec08c395SMikael Gonella-Bolduc case IIO_CHAN_INFO_INT_TIME: 1023*ec08c395SMikael Gonella-Bolduc switch (chan->type) { 1024*ec08c395SMikael Gonella-Bolduc case IIO_PROXIMITY: 1025*ec08c395SMikael Gonella-Bolduc *val = data->ps_rate; 1026*ec08c395SMikael Gonella-Bolduc 1027*ec08c395SMikael Gonella-Bolduc return IIO_VAL_INT; 1028*ec08c395SMikael Gonella-Bolduc case IIO_LIGHT: 1029*ec08c395SMikael Gonella-Bolduc *val = data->als_itime; 1030*ec08c395SMikael Gonella-Bolduc 1031*ec08c395SMikael Gonella-Bolduc return IIO_VAL_INT; 1032*ec08c395SMikael Gonella-Bolduc default: 1033*ec08c395SMikael Gonella-Bolduc return -EINVAL; 1034*ec08c395SMikael Gonella-Bolduc } 1035*ec08c395SMikael Gonella-Bolduc case IIO_CHAN_INFO_CALIBBIAS: 1036*ec08c395SMikael Gonella-Bolduc switch (chan->type) { 1037*ec08c395SMikael Gonella-Bolduc case IIO_PROXIMITY: 1038*ec08c395SMikael Gonella-Bolduc *val = data->ps_cancellation_level; 1039*ec08c395SMikael Gonella-Bolduc 1040*ec08c395SMikael Gonella-Bolduc return IIO_VAL_INT; 1041*ec08c395SMikael Gonella-Bolduc default: 1042*ec08c395SMikael Gonella-Bolduc return -EINVAL; 1043*ec08c395SMikael Gonella-Bolduc } 1044*ec08c395SMikael Gonella-Bolduc case IIO_CHAN_INFO_SCALE: 1045*ec08c395SMikael Gonella-Bolduc switch (chan->type) { 1046*ec08c395SMikael Gonella-Bolduc case IIO_PROXIMITY: 1047*ec08c395SMikael Gonella-Bolduc *val = data->ps_gain; 1048*ec08c395SMikael Gonella-Bolduc 1049*ec08c395SMikael Gonella-Bolduc return IIO_VAL_INT; 1050*ec08c395SMikael Gonella-Bolduc case IIO_LIGHT: 1051*ec08c395SMikael Gonella-Bolduc *val = data->als_scale1; 1052*ec08c395SMikael Gonella-Bolduc *val2 = data->als_scale2; 1053*ec08c395SMikael Gonella-Bolduc 1054*ec08c395SMikael Gonella-Bolduc return IIO_VAL_INT_PLUS_MICRO; 1055*ec08c395SMikael Gonella-Bolduc default: 1056*ec08c395SMikael Gonella-Bolduc return -EINVAL; 1057*ec08c395SMikael Gonella-Bolduc } 1058*ec08c395SMikael Gonella-Bolduc default: 1059*ec08c395SMikael Gonella-Bolduc return -EINVAL; 1060*ec08c395SMikael Gonella-Bolduc } 1061*ec08c395SMikael Gonella-Bolduc }; 1062*ec08c395SMikael Gonella-Bolduc 1063*ec08c395SMikael Gonella-Bolduc static int apds9160_write_raw(struct iio_dev *indio_dev, 1064*ec08c395SMikael Gonella-Bolduc struct iio_chan_spec const *chan, int val, 1065*ec08c395SMikael Gonella-Bolduc int val2, long mask) 1066*ec08c395SMikael Gonella-Bolduc { 1067*ec08c395SMikael Gonella-Bolduc struct apds9160_chip *data = iio_priv(indio_dev); 1068*ec08c395SMikael Gonella-Bolduc 1069*ec08c395SMikael Gonella-Bolduc guard(mutex)(&data->lock); 1070*ec08c395SMikael Gonella-Bolduc 1071*ec08c395SMikael Gonella-Bolduc switch (mask) { 1072*ec08c395SMikael Gonella-Bolduc case IIO_CHAN_INFO_INT_TIME: 1073*ec08c395SMikael Gonella-Bolduc if (val2 != 0) 1074*ec08c395SMikael Gonella-Bolduc return -EINVAL; 1075*ec08c395SMikael Gonella-Bolduc switch (chan->type) { 1076*ec08c395SMikael Gonella-Bolduc case IIO_PROXIMITY: 1077*ec08c395SMikael Gonella-Bolduc return apds9160_set_ps_rate(data, val); 1078*ec08c395SMikael Gonella-Bolduc case IIO_LIGHT: 1079*ec08c395SMikael Gonella-Bolduc return apds9160_set_als_int_time(data, val); 1080*ec08c395SMikael Gonella-Bolduc default: 1081*ec08c395SMikael Gonella-Bolduc return -EINVAL; 1082*ec08c395SMikael Gonella-Bolduc } 1083*ec08c395SMikael Gonella-Bolduc case IIO_CHAN_INFO_SCALE: 1084*ec08c395SMikael Gonella-Bolduc switch (chan->type) { 1085*ec08c395SMikael Gonella-Bolduc case IIO_PROXIMITY: 1086*ec08c395SMikael Gonella-Bolduc return apds9160_set_ps_gain(data, val); 1087*ec08c395SMikael Gonella-Bolduc case IIO_LIGHT: 1088*ec08c395SMikael Gonella-Bolduc return apds9160_set_als_scale(data, val, val2); 1089*ec08c395SMikael Gonella-Bolduc default: 1090*ec08c395SMikael Gonella-Bolduc return -EINVAL; 1091*ec08c395SMikael Gonella-Bolduc } 1092*ec08c395SMikael Gonella-Bolduc case IIO_CHAN_INFO_CALIBBIAS: 1093*ec08c395SMikael Gonella-Bolduc if (val2 != 0) 1094*ec08c395SMikael Gonella-Bolduc return -EINVAL; 1095*ec08c395SMikael Gonella-Bolduc switch (chan->type) { 1096*ec08c395SMikael Gonella-Bolduc case IIO_PROXIMITY: 1097*ec08c395SMikael Gonella-Bolduc return apds9160_set_ps_cancellation_level(data, val); 1098*ec08c395SMikael Gonella-Bolduc default: 1099*ec08c395SMikael Gonella-Bolduc return -EINVAL; 1100*ec08c395SMikael Gonella-Bolduc } 1101*ec08c395SMikael Gonella-Bolduc case IIO_CHAN_INFO_RAW: 1102*ec08c395SMikael Gonella-Bolduc if (val2 != 0) 1103*ec08c395SMikael Gonella-Bolduc return -EINVAL; 1104*ec08c395SMikael Gonella-Bolduc switch (chan->type) { 1105*ec08c395SMikael Gonella-Bolduc case IIO_CURRENT: 1106*ec08c395SMikael Gonella-Bolduc return apds9160_set_ps_current(data, val); 1107*ec08c395SMikael Gonella-Bolduc default: 1108*ec08c395SMikael Gonella-Bolduc return -EINVAL; 1109*ec08c395SMikael Gonella-Bolduc } 1110*ec08c395SMikael Gonella-Bolduc default: 1111*ec08c395SMikael Gonella-Bolduc return -EINVAL; 1112*ec08c395SMikael Gonella-Bolduc } 1113*ec08c395SMikael Gonella-Bolduc } 1114*ec08c395SMikael Gonella-Bolduc 1115*ec08c395SMikael Gonella-Bolduc static inline int apds9160_get_thres_reg(const struct iio_chan_spec *chan, 1116*ec08c395SMikael Gonella-Bolduc enum iio_event_direction dir, u8 *reg) 1117*ec08c395SMikael Gonella-Bolduc { 1118*ec08c395SMikael Gonella-Bolduc switch (dir) { 1119*ec08c395SMikael Gonella-Bolduc case IIO_EV_DIR_RISING: 1120*ec08c395SMikael Gonella-Bolduc switch (chan->type) { 1121*ec08c395SMikael Gonella-Bolduc case IIO_PROXIMITY: 1122*ec08c395SMikael Gonella-Bolduc *reg = APDS9160_REG_PS_THRES_HI_LSB; 1123*ec08c395SMikael Gonella-Bolduc break; 1124*ec08c395SMikael Gonella-Bolduc case IIO_LIGHT: 1125*ec08c395SMikael Gonella-Bolduc *reg = APDS9160_REG_LS_THRES_UP_LSB; 1126*ec08c395SMikael Gonella-Bolduc break; 1127*ec08c395SMikael Gonella-Bolduc default: 1128*ec08c395SMikael Gonella-Bolduc return -EINVAL; 1129*ec08c395SMikael Gonella-Bolduc } break; 1130*ec08c395SMikael Gonella-Bolduc case IIO_EV_DIR_FALLING: 1131*ec08c395SMikael Gonella-Bolduc switch (chan->type) { 1132*ec08c395SMikael Gonella-Bolduc case IIO_PROXIMITY: 1133*ec08c395SMikael Gonella-Bolduc *reg = APDS9160_REG_PS_THRES_LO_LSB; 1134*ec08c395SMikael Gonella-Bolduc break; 1135*ec08c395SMikael Gonella-Bolduc case IIO_LIGHT: 1136*ec08c395SMikael Gonella-Bolduc *reg = APDS9160_REG_LS_THRES_LO_LSB; 1137*ec08c395SMikael Gonella-Bolduc break; 1138*ec08c395SMikael Gonella-Bolduc default: 1139*ec08c395SMikael Gonella-Bolduc return -EINVAL; 1140*ec08c395SMikael Gonella-Bolduc } 1141*ec08c395SMikael Gonella-Bolduc break; 1142*ec08c395SMikael Gonella-Bolduc default: 1143*ec08c395SMikael Gonella-Bolduc return -EINVAL; 1144*ec08c395SMikael Gonella-Bolduc } 1145*ec08c395SMikael Gonella-Bolduc 1146*ec08c395SMikael Gonella-Bolduc return 0; 1147*ec08c395SMikael Gonella-Bolduc } 1148*ec08c395SMikael Gonella-Bolduc 1149*ec08c395SMikael Gonella-Bolduc static int apds9160_read_event(struct iio_dev *indio_dev, 1150*ec08c395SMikael Gonella-Bolduc const struct iio_chan_spec *chan, 1151*ec08c395SMikael Gonella-Bolduc enum iio_event_type type, 1152*ec08c395SMikael Gonella-Bolduc enum iio_event_direction dir, 1153*ec08c395SMikael Gonella-Bolduc enum iio_event_info info, int *val, int *val2) 1154*ec08c395SMikael Gonella-Bolduc { 1155*ec08c395SMikael Gonella-Bolduc u8 reg; 1156*ec08c395SMikael Gonella-Bolduc int ret; 1157*ec08c395SMikael Gonella-Bolduc struct apds9160_chip *data = iio_priv(indio_dev); 1158*ec08c395SMikael Gonella-Bolduc 1159*ec08c395SMikael Gonella-Bolduc if (info != IIO_EV_INFO_VALUE) 1160*ec08c395SMikael Gonella-Bolduc return -EINVAL; 1161*ec08c395SMikael Gonella-Bolduc 1162*ec08c395SMikael Gonella-Bolduc ret = apds9160_get_thres_reg(chan, dir, ®); 1163*ec08c395SMikael Gonella-Bolduc if (ret < 0) 1164*ec08c395SMikael Gonella-Bolduc return ret; 1165*ec08c395SMikael Gonella-Bolduc 1166*ec08c395SMikael Gonella-Bolduc switch (chan->type) { 1167*ec08c395SMikael Gonella-Bolduc case IIO_PROXIMITY: { 1168*ec08c395SMikael Gonella-Bolduc __le16 buf; 1169*ec08c395SMikael Gonella-Bolduc 1170*ec08c395SMikael Gonella-Bolduc ret = regmap_bulk_read(data->regmap, reg, &buf, 2); 1171*ec08c395SMikael Gonella-Bolduc if (ret < 0) 1172*ec08c395SMikael Gonella-Bolduc return ret; 1173*ec08c395SMikael Gonella-Bolduc *val = le16_to_cpu(buf); 1174*ec08c395SMikael Gonella-Bolduc return IIO_VAL_INT; 1175*ec08c395SMikael Gonella-Bolduc } 1176*ec08c395SMikael Gonella-Bolduc case IIO_LIGHT: { 1177*ec08c395SMikael Gonella-Bolduc u8 buf[3]; 1178*ec08c395SMikael Gonella-Bolduc 1179*ec08c395SMikael Gonella-Bolduc ret = regmap_bulk_read(data->regmap, reg, &buf, 3); 1180*ec08c395SMikael Gonella-Bolduc if (ret < 0) 1181*ec08c395SMikael Gonella-Bolduc return ret; 1182*ec08c395SMikael Gonella-Bolduc *val = get_unaligned_le24(buf); 1183*ec08c395SMikael Gonella-Bolduc return IIO_VAL_INT; 1184*ec08c395SMikael Gonella-Bolduc } 1185*ec08c395SMikael Gonella-Bolduc default: 1186*ec08c395SMikael Gonella-Bolduc return -EINVAL; 1187*ec08c395SMikael Gonella-Bolduc } 1188*ec08c395SMikael Gonella-Bolduc } 1189*ec08c395SMikael Gonella-Bolduc 1190*ec08c395SMikael Gonella-Bolduc static int apds9160_write_event(struct iio_dev *indio_dev, 1191*ec08c395SMikael Gonella-Bolduc const struct iio_chan_spec *chan, 1192*ec08c395SMikael Gonella-Bolduc enum iio_event_type type, 1193*ec08c395SMikael Gonella-Bolduc enum iio_event_direction dir, 1194*ec08c395SMikael Gonella-Bolduc enum iio_event_info info, int val, int val2) 1195*ec08c395SMikael Gonella-Bolduc { 1196*ec08c395SMikael Gonella-Bolduc u8 reg; 1197*ec08c395SMikael Gonella-Bolduc int ret = 0; 1198*ec08c395SMikael Gonella-Bolduc struct apds9160_chip *data = iio_priv(indio_dev); 1199*ec08c395SMikael Gonella-Bolduc 1200*ec08c395SMikael Gonella-Bolduc if (info != IIO_EV_INFO_VALUE) 1201*ec08c395SMikael Gonella-Bolduc return -EINVAL; 1202*ec08c395SMikael Gonella-Bolduc 1203*ec08c395SMikael Gonella-Bolduc ret = apds9160_get_thres_reg(chan, dir, ®); 1204*ec08c395SMikael Gonella-Bolduc if (ret < 0) 1205*ec08c395SMikael Gonella-Bolduc return ret; 1206*ec08c395SMikael Gonella-Bolduc 1207*ec08c395SMikael Gonella-Bolduc switch (chan->type) { 1208*ec08c395SMikael Gonella-Bolduc case IIO_PROXIMITY: { 1209*ec08c395SMikael Gonella-Bolduc __le16 buf; 1210*ec08c395SMikael Gonella-Bolduc 1211*ec08c395SMikael Gonella-Bolduc if (val < 0 || val > APDS9160_PS_THRES_MAX) 1212*ec08c395SMikael Gonella-Bolduc return -EINVAL; 1213*ec08c395SMikael Gonella-Bolduc 1214*ec08c395SMikael Gonella-Bolduc buf = cpu_to_le16(val); 1215*ec08c395SMikael Gonella-Bolduc return regmap_bulk_write(data->regmap, reg, &buf, 2); 1216*ec08c395SMikael Gonella-Bolduc } 1217*ec08c395SMikael Gonella-Bolduc case IIO_LIGHT: { 1218*ec08c395SMikael Gonella-Bolduc u8 buf[3]; 1219*ec08c395SMikael Gonella-Bolduc 1220*ec08c395SMikael Gonella-Bolduc if (val < 0 || val > APDS9160_LS_THRES_MAX) 1221*ec08c395SMikael Gonella-Bolduc return -EINVAL; 1222*ec08c395SMikael Gonella-Bolduc 1223*ec08c395SMikael Gonella-Bolduc put_unaligned_le24(val, buf); 1224*ec08c395SMikael Gonella-Bolduc return regmap_bulk_write(data->regmap, reg, &buf, 3); 1225*ec08c395SMikael Gonella-Bolduc } 1226*ec08c395SMikael Gonella-Bolduc default: 1227*ec08c395SMikael Gonella-Bolduc return -EINVAL; 1228*ec08c395SMikael Gonella-Bolduc } 1229*ec08c395SMikael Gonella-Bolduc } 1230*ec08c395SMikael Gonella-Bolduc 1231*ec08c395SMikael Gonella-Bolduc static int apds9160_read_event_config(struct iio_dev *indio_dev, 1232*ec08c395SMikael Gonella-Bolduc const struct iio_chan_spec *chan, 1233*ec08c395SMikael Gonella-Bolduc enum iio_event_type type, 1234*ec08c395SMikael Gonella-Bolduc enum iio_event_direction dir) 1235*ec08c395SMikael Gonella-Bolduc { 1236*ec08c395SMikael Gonella-Bolduc struct apds9160_chip *data = iio_priv(indio_dev); 1237*ec08c395SMikael Gonella-Bolduc 1238*ec08c395SMikael Gonella-Bolduc switch (chan->type) { 1239*ec08c395SMikael Gonella-Bolduc case IIO_PROXIMITY: 1240*ec08c395SMikael Gonella-Bolduc return data->ps_int; 1241*ec08c395SMikael Gonella-Bolduc case IIO_LIGHT: 1242*ec08c395SMikael Gonella-Bolduc return data->als_int; 1243*ec08c395SMikael Gonella-Bolduc default: 1244*ec08c395SMikael Gonella-Bolduc return -EINVAL; 1245*ec08c395SMikael Gonella-Bolduc } 1246*ec08c395SMikael Gonella-Bolduc } 1247*ec08c395SMikael Gonella-Bolduc 1248*ec08c395SMikael Gonella-Bolduc static int apds9160_write_event_config(struct iio_dev *indio_dev, 1249*ec08c395SMikael Gonella-Bolduc const struct iio_chan_spec *chan, 1250*ec08c395SMikael Gonella-Bolduc enum iio_event_type type, 1251*ec08c395SMikael Gonella-Bolduc enum iio_event_direction dir, bool state) 1252*ec08c395SMikael Gonella-Bolduc { 1253*ec08c395SMikael Gonella-Bolduc struct apds9160_chip *data = iio_priv(indio_dev); 1254*ec08c395SMikael Gonella-Bolduc int ret; 1255*ec08c395SMikael Gonella-Bolduc 1256*ec08c395SMikael Gonella-Bolduc switch (chan->type) { 1257*ec08c395SMikael Gonella-Bolduc case IIO_PROXIMITY: 1258*ec08c395SMikael Gonella-Bolduc ret = regmap_field_write(data->reg_int_ps, state); 1259*ec08c395SMikael Gonella-Bolduc if (ret) 1260*ec08c395SMikael Gonella-Bolduc return ret; 1261*ec08c395SMikael Gonella-Bolduc data->ps_int = state; 1262*ec08c395SMikael Gonella-Bolduc 1263*ec08c395SMikael Gonella-Bolduc return 0; 1264*ec08c395SMikael Gonella-Bolduc case IIO_LIGHT: 1265*ec08c395SMikael Gonella-Bolduc ret = regmap_field_write(data->reg_int_als, state); 1266*ec08c395SMikael Gonella-Bolduc if (ret) 1267*ec08c395SMikael Gonella-Bolduc return ret; 1268*ec08c395SMikael Gonella-Bolduc data->als_int = state; 1269*ec08c395SMikael Gonella-Bolduc 1270*ec08c395SMikael Gonella-Bolduc return 0; 1271*ec08c395SMikael Gonella-Bolduc default: 1272*ec08c395SMikael Gonella-Bolduc return -EINVAL; 1273*ec08c395SMikael Gonella-Bolduc } 1274*ec08c395SMikael Gonella-Bolduc } 1275*ec08c395SMikael Gonella-Bolduc 1276*ec08c395SMikael Gonella-Bolduc static irqreturn_t apds9160_irq_handler(int irq, void *private) 1277*ec08c395SMikael Gonella-Bolduc { 1278*ec08c395SMikael Gonella-Bolduc struct iio_dev *indio_dev = private; 1279*ec08c395SMikael Gonella-Bolduc struct apds9160_chip *data = iio_priv(indio_dev); 1280*ec08c395SMikael Gonella-Bolduc int ret, status; 1281*ec08c395SMikael Gonella-Bolduc 1282*ec08c395SMikael Gonella-Bolduc /* Reading status register clears the interrupt flag */ 1283*ec08c395SMikael Gonella-Bolduc ret = regmap_read(data->regmap, APDS9160_REG_SR, &status); 1284*ec08c395SMikael Gonella-Bolduc if (ret < 0) { 1285*ec08c395SMikael Gonella-Bolduc dev_err_ratelimited(&data->client->dev, 1286*ec08c395SMikael Gonella-Bolduc "irq status reg read failed\n"); 1287*ec08c395SMikael Gonella-Bolduc return IRQ_HANDLED; 1288*ec08c395SMikael Gonella-Bolduc } 1289*ec08c395SMikael Gonella-Bolduc 1290*ec08c395SMikael Gonella-Bolduc if ((status & APDS9160_SR_LS_INT) && 1291*ec08c395SMikael Gonella-Bolduc (status & APDS9160_SR_LS_NEW_DATA) && data->als_int) { 1292*ec08c395SMikael Gonella-Bolduc iio_push_event(indio_dev, 1293*ec08c395SMikael Gonella-Bolduc IIO_UNMOD_EVENT_CODE(IIO_LIGHT, 0, 1294*ec08c395SMikael Gonella-Bolduc IIO_EV_TYPE_THRESH, 1295*ec08c395SMikael Gonella-Bolduc IIO_EV_DIR_EITHER), 1296*ec08c395SMikael Gonella-Bolduc iio_get_time_ns(indio_dev)); 1297*ec08c395SMikael Gonella-Bolduc } 1298*ec08c395SMikael Gonella-Bolduc 1299*ec08c395SMikael Gonella-Bolduc if ((status & APDS9160_SR_PS_INT) && 1300*ec08c395SMikael Gonella-Bolduc (status & APDS9160_SR_PS_NEW_DATA) && data->ps_int) { 1301*ec08c395SMikael Gonella-Bolduc iio_push_event(indio_dev, 1302*ec08c395SMikael Gonella-Bolduc IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, 0, 1303*ec08c395SMikael Gonella-Bolduc IIO_EV_TYPE_THRESH, 1304*ec08c395SMikael Gonella-Bolduc IIO_EV_DIR_EITHER), 1305*ec08c395SMikael Gonella-Bolduc iio_get_time_ns(indio_dev)); 1306*ec08c395SMikael Gonella-Bolduc } 1307*ec08c395SMikael Gonella-Bolduc 1308*ec08c395SMikael Gonella-Bolduc return IRQ_HANDLED; 1309*ec08c395SMikael Gonella-Bolduc } 1310*ec08c395SMikael Gonella-Bolduc 1311*ec08c395SMikael Gonella-Bolduc static int apds9160_detect(struct apds9160_chip *chip) 1312*ec08c395SMikael Gonella-Bolduc { 1313*ec08c395SMikael Gonella-Bolduc struct i2c_client *client = chip->client; 1314*ec08c395SMikael Gonella-Bolduc int ret; 1315*ec08c395SMikael Gonella-Bolduc u32 val; 1316*ec08c395SMikael Gonella-Bolduc 1317*ec08c395SMikael Gonella-Bolduc ret = regmap_read(chip->regmap, APDS9160_REG_ID, &val); 1318*ec08c395SMikael Gonella-Bolduc if (ret < 0) { 1319*ec08c395SMikael Gonella-Bolduc dev_err(&client->dev, "ID read failed\n"); 1320*ec08c395SMikael Gonella-Bolduc return ret; 1321*ec08c395SMikael Gonella-Bolduc } 1322*ec08c395SMikael Gonella-Bolduc 1323*ec08c395SMikael Gonella-Bolduc if (val != APDS9160_PART_ID_0) 1324*ec08c395SMikael Gonella-Bolduc dev_info(&client->dev, "Unknown part id %u\n", val); 1325*ec08c395SMikael Gonella-Bolduc 1326*ec08c395SMikael Gonella-Bolduc return 0; 1327*ec08c395SMikael Gonella-Bolduc } 1328*ec08c395SMikael Gonella-Bolduc 1329*ec08c395SMikael Gonella-Bolduc static void apds9160_disable(void *chip) 1330*ec08c395SMikael Gonella-Bolduc { 1331*ec08c395SMikael Gonella-Bolduc struct apds9160_chip *data = chip; 1332*ec08c395SMikael Gonella-Bolduc int ret; 1333*ec08c395SMikael Gonella-Bolduc 1334*ec08c395SMikael Gonella-Bolduc ret = regmap_field_write(data->reg_enable_als, 0); 1335*ec08c395SMikael Gonella-Bolduc if (ret) 1336*ec08c395SMikael Gonella-Bolduc return; 1337*ec08c395SMikael Gonella-Bolduc 1338*ec08c395SMikael Gonella-Bolduc regmap_field_write(data->reg_enable_ps, 0); 1339*ec08c395SMikael Gonella-Bolduc } 1340*ec08c395SMikael Gonella-Bolduc 1341*ec08c395SMikael Gonella-Bolduc static int apds9160_chip_init(struct apds9160_chip *chip) 1342*ec08c395SMikael Gonella-Bolduc { 1343*ec08c395SMikael Gonella-Bolduc int ret; 1344*ec08c395SMikael Gonella-Bolduc 1345*ec08c395SMikael Gonella-Bolduc /* Write default values to interrupt register */ 1346*ec08c395SMikael Gonella-Bolduc ret = regmap_field_write(chip->reg_int_ps, 0); 1347*ec08c395SMikael Gonella-Bolduc chip->ps_int = 0; 1348*ec08c395SMikael Gonella-Bolduc if (ret) 1349*ec08c395SMikael Gonella-Bolduc return ret; 1350*ec08c395SMikael Gonella-Bolduc 1351*ec08c395SMikael Gonella-Bolduc ret = regmap_field_write(chip->reg_int_als, 0); 1352*ec08c395SMikael Gonella-Bolduc chip->als_int = 0; 1353*ec08c395SMikael Gonella-Bolduc if (ret) 1354*ec08c395SMikael Gonella-Bolduc return ret; 1355*ec08c395SMikael Gonella-Bolduc 1356*ec08c395SMikael Gonella-Bolduc /* Write default values to control register */ 1357*ec08c395SMikael Gonella-Bolduc ret = regmap_field_write(chip->reg_enable_als, 1); 1358*ec08c395SMikael Gonella-Bolduc if (ret) 1359*ec08c395SMikael Gonella-Bolduc return ret; 1360*ec08c395SMikael Gonella-Bolduc 1361*ec08c395SMikael Gonella-Bolduc ret = regmap_field_write(chip->reg_enable_ps, 1); 1362*ec08c395SMikael Gonella-Bolduc if (ret) 1363*ec08c395SMikael Gonella-Bolduc return ret; 1364*ec08c395SMikael Gonella-Bolduc 1365*ec08c395SMikael Gonella-Bolduc /* Write other default values */ 1366*ec08c395SMikael Gonella-Bolduc ret = regmap_field_write(chip->reg_ps_resolution, 1367*ec08c395SMikael Gonella-Bolduc APDS9160_DEFAULT_PS_RESOLUTION_11BITS); 1368*ec08c395SMikael Gonella-Bolduc if (ret) 1369*ec08c395SMikael Gonella-Bolduc return ret; 1370*ec08c395SMikael Gonella-Bolduc 1371*ec08c395SMikael Gonella-Bolduc /* Write default values to configuration registers */ 1372*ec08c395SMikael Gonella-Bolduc ret = apds9160_set_ps_current(chip, APDS9160_DEFAULT_PS_CURRENT); 1373*ec08c395SMikael Gonella-Bolduc if (ret) 1374*ec08c395SMikael Gonella-Bolduc return ret; 1375*ec08c395SMikael Gonella-Bolduc 1376*ec08c395SMikael Gonella-Bolduc ret = apds9160_set_ps_rate(chip, APDS9160_DEFAULT_PS_RATE); 1377*ec08c395SMikael Gonella-Bolduc if (ret) 1378*ec08c395SMikael Gonella-Bolduc return ret; 1379*ec08c395SMikael Gonella-Bolduc 1380*ec08c395SMikael Gonella-Bolduc ret = apds9160_set_als_int_time(chip, APDS9160_DEFAULT_LS_RATE); 1381*ec08c395SMikael Gonella-Bolduc if (ret) 1382*ec08c395SMikael Gonella-Bolduc return ret; 1383*ec08c395SMikael Gonella-Bolduc 1384*ec08c395SMikael Gonella-Bolduc ret = apds9160_set_als_scale(chip, 1385*ec08c395SMikael Gonella-Bolduc apds9160_100ms_avail[0][0], 1386*ec08c395SMikael Gonella-Bolduc apds9160_100ms_avail[0][1]); 1387*ec08c395SMikael Gonella-Bolduc if (ret) 1388*ec08c395SMikael Gonella-Bolduc return ret; 1389*ec08c395SMikael Gonella-Bolduc 1390*ec08c395SMikael Gonella-Bolduc ret = apds9160_set_ps_gain(chip, APDS9160_DEFAULT_PS_GAIN); 1391*ec08c395SMikael Gonella-Bolduc if (ret) 1392*ec08c395SMikael Gonella-Bolduc return ret; 1393*ec08c395SMikael Gonella-Bolduc 1394*ec08c395SMikael Gonella-Bolduc ret = apds9160_set_ps_analog_cancellation( 1395*ec08c395SMikael Gonella-Bolduc chip, APDS9160_DEFAULT_PS_ANALOG_CANCELLATION); 1396*ec08c395SMikael Gonella-Bolduc if (ret) 1397*ec08c395SMikael Gonella-Bolduc return ret; 1398*ec08c395SMikael Gonella-Bolduc 1399*ec08c395SMikael Gonella-Bolduc ret = apds9160_set_ps_cancellation_level( 1400*ec08c395SMikael Gonella-Bolduc chip, APDS9160_DEFAULT_PS_CANCELLATION_LEVEL); 1401*ec08c395SMikael Gonella-Bolduc if (ret) 1402*ec08c395SMikael Gonella-Bolduc return ret; 1403*ec08c395SMikael Gonella-Bolduc 1404*ec08c395SMikael Gonella-Bolduc return devm_add_action_or_reset(&chip->client->dev, apds9160_disable, 1405*ec08c395SMikael Gonella-Bolduc chip); 1406*ec08c395SMikael Gonella-Bolduc } 1407*ec08c395SMikael Gonella-Bolduc 1408*ec08c395SMikael Gonella-Bolduc static int apds9160_regfield_init(struct apds9160_chip *data) 1409*ec08c395SMikael Gonella-Bolduc { 1410*ec08c395SMikael Gonella-Bolduc struct device *dev = &data->client->dev; 1411*ec08c395SMikael Gonella-Bolduc struct regmap *regmap = data->regmap; 1412*ec08c395SMikael Gonella-Bolduc struct regmap_field *tmp; 1413*ec08c395SMikael Gonella-Bolduc 1414*ec08c395SMikael Gonella-Bolduc tmp = devm_regmap_field_alloc(dev, regmap, apds9160_reg_field_int_als); 1415*ec08c395SMikael Gonella-Bolduc if (IS_ERR(tmp)) 1416*ec08c395SMikael Gonella-Bolduc return PTR_ERR(tmp); 1417*ec08c395SMikael Gonella-Bolduc data->reg_int_als = tmp; 1418*ec08c395SMikael Gonella-Bolduc 1419*ec08c395SMikael Gonella-Bolduc tmp = devm_regmap_field_alloc(dev, regmap, apds9160_reg_field_int_ps); 1420*ec08c395SMikael Gonella-Bolduc if (IS_ERR(tmp)) 1421*ec08c395SMikael Gonella-Bolduc return PTR_ERR(tmp); 1422*ec08c395SMikael Gonella-Bolduc data->reg_int_ps = tmp; 1423*ec08c395SMikael Gonella-Bolduc 1424*ec08c395SMikael Gonella-Bolduc tmp = devm_regmap_field_alloc(dev, regmap, apds9160_reg_field_ls_en); 1425*ec08c395SMikael Gonella-Bolduc if (IS_ERR(tmp)) 1426*ec08c395SMikael Gonella-Bolduc return PTR_ERR(tmp); 1427*ec08c395SMikael Gonella-Bolduc data->reg_enable_als = tmp; 1428*ec08c395SMikael Gonella-Bolduc 1429*ec08c395SMikael Gonella-Bolduc tmp = devm_regmap_field_alloc(dev, regmap, apds9160_reg_field_ps_en); 1430*ec08c395SMikael Gonella-Bolduc if (IS_ERR(tmp)) 1431*ec08c395SMikael Gonella-Bolduc return PTR_ERR(tmp); 1432*ec08c395SMikael Gonella-Bolduc data->reg_enable_ps = tmp; 1433*ec08c395SMikael Gonella-Bolduc 1434*ec08c395SMikael Gonella-Bolduc tmp = devm_regmap_field_alloc(dev, regmap, 1435*ec08c395SMikael Gonella-Bolduc apds9160_reg_field_ps_overflow); 1436*ec08c395SMikael Gonella-Bolduc if (IS_ERR(tmp)) 1437*ec08c395SMikael Gonella-Bolduc return PTR_ERR(tmp); 1438*ec08c395SMikael Gonella-Bolduc data->reg_ps_overflow = tmp; 1439*ec08c395SMikael Gonella-Bolduc 1440*ec08c395SMikael Gonella-Bolduc tmp = devm_regmap_field_alloc(dev, regmap, apds9160_reg_field_als_rate); 1441*ec08c395SMikael Gonella-Bolduc if (IS_ERR(tmp)) 1442*ec08c395SMikael Gonella-Bolduc return PTR_ERR(tmp); 1443*ec08c395SMikael Gonella-Bolduc data->reg_als_rate = tmp; 1444*ec08c395SMikael Gonella-Bolduc 1445*ec08c395SMikael Gonella-Bolduc tmp = devm_regmap_field_alloc(dev, regmap, apds9160_reg_field_als_res); 1446*ec08c395SMikael Gonella-Bolduc if (IS_ERR(tmp)) 1447*ec08c395SMikael Gonella-Bolduc return PTR_ERR(tmp); 1448*ec08c395SMikael Gonella-Bolduc data->reg_als_resolution = tmp; 1449*ec08c395SMikael Gonella-Bolduc 1450*ec08c395SMikael Gonella-Bolduc tmp = devm_regmap_field_alloc(dev, regmap, apds9160_reg_field_ps_rate); 1451*ec08c395SMikael Gonella-Bolduc if (IS_ERR(tmp)) 1452*ec08c395SMikael Gonella-Bolduc return PTR_ERR(tmp); 1453*ec08c395SMikael Gonella-Bolduc data->reg_ps_rate = tmp; 1454*ec08c395SMikael Gonella-Bolduc 1455*ec08c395SMikael Gonella-Bolduc tmp = devm_regmap_field_alloc(dev, regmap, apds9160_reg_field_als_gain); 1456*ec08c395SMikael Gonella-Bolduc if (IS_ERR(tmp)) 1457*ec08c395SMikael Gonella-Bolduc return PTR_ERR(tmp); 1458*ec08c395SMikael Gonella-Bolduc data->reg_als_gain = tmp; 1459*ec08c395SMikael Gonella-Bolduc 1460*ec08c395SMikael Gonella-Bolduc tmp = devm_regmap_field_alloc(dev, regmap, 1461*ec08c395SMikael Gonella-Bolduc apds9160_reg_field_ps_current); 1462*ec08c395SMikael Gonella-Bolduc if (IS_ERR(tmp)) 1463*ec08c395SMikael Gonella-Bolduc return PTR_ERR(tmp); 1464*ec08c395SMikael Gonella-Bolduc data->reg_ps_current = tmp; 1465*ec08c395SMikael Gonella-Bolduc 1466*ec08c395SMikael Gonella-Bolduc tmp = devm_regmap_field_alloc(dev, regmap, apds9160_reg_field_ps_gain); 1467*ec08c395SMikael Gonella-Bolduc if (IS_ERR(tmp)) 1468*ec08c395SMikael Gonella-Bolduc return PTR_ERR(tmp); 1469*ec08c395SMikael Gonella-Bolduc data->reg_ps_gain = tmp; 1470*ec08c395SMikael Gonella-Bolduc 1471*ec08c395SMikael Gonella-Bolduc tmp = devm_regmap_field_alloc(dev, regmap, 1472*ec08c395SMikael Gonella-Bolduc apds9160_reg_field_ps_resolution); 1473*ec08c395SMikael Gonella-Bolduc if (IS_ERR(tmp)) 1474*ec08c395SMikael Gonella-Bolduc return PTR_ERR(tmp); 1475*ec08c395SMikael Gonella-Bolduc data->reg_ps_resolution = tmp; 1476*ec08c395SMikael Gonella-Bolduc 1477*ec08c395SMikael Gonella-Bolduc return 0; 1478*ec08c395SMikael Gonella-Bolduc } 1479*ec08c395SMikael Gonella-Bolduc 1480*ec08c395SMikael Gonella-Bolduc static const struct iio_info apds9160_info = { 1481*ec08c395SMikael Gonella-Bolduc .read_avail = apds9160_read_avail, 1482*ec08c395SMikael Gonella-Bolduc .read_raw = apds9160_read_raw, 1483*ec08c395SMikael Gonella-Bolduc .write_raw = apds9160_write_raw, 1484*ec08c395SMikael Gonella-Bolduc .write_raw_get_fmt = apds9160_write_raw_get_fmt, 1485*ec08c395SMikael Gonella-Bolduc .read_event_value = apds9160_read_event, 1486*ec08c395SMikael Gonella-Bolduc .write_event_value = apds9160_write_event, 1487*ec08c395SMikael Gonella-Bolduc .read_event_config = apds9160_read_event_config, 1488*ec08c395SMikael Gonella-Bolduc .write_event_config = apds9160_write_event_config, 1489*ec08c395SMikael Gonella-Bolduc }; 1490*ec08c395SMikael Gonella-Bolduc 1491*ec08c395SMikael Gonella-Bolduc static const struct iio_info apds9160_info_no_events = { 1492*ec08c395SMikael Gonella-Bolduc .read_avail = apds9160_read_avail, 1493*ec08c395SMikael Gonella-Bolduc .read_raw = apds9160_read_raw, 1494*ec08c395SMikael Gonella-Bolduc .write_raw = apds9160_write_raw, 1495*ec08c395SMikael Gonella-Bolduc .write_raw_get_fmt = apds9160_write_raw_get_fmt, 1496*ec08c395SMikael Gonella-Bolduc }; 1497*ec08c395SMikael Gonella-Bolduc 1498*ec08c395SMikael Gonella-Bolduc static int apds9160_probe(struct i2c_client *client) 1499*ec08c395SMikael Gonella-Bolduc { 1500*ec08c395SMikael Gonella-Bolduc struct device *dev = &client->dev; 1501*ec08c395SMikael Gonella-Bolduc struct apds9160_chip *chip; 1502*ec08c395SMikael Gonella-Bolduc struct iio_dev *indio_dev; 1503*ec08c395SMikael Gonella-Bolduc int ret; 1504*ec08c395SMikael Gonella-Bolduc 1505*ec08c395SMikael Gonella-Bolduc indio_dev = devm_iio_device_alloc(dev, sizeof(*chip)); 1506*ec08c395SMikael Gonella-Bolduc if (!indio_dev) 1507*ec08c395SMikael Gonella-Bolduc return -ENOMEM; 1508*ec08c395SMikael Gonella-Bolduc 1509*ec08c395SMikael Gonella-Bolduc ret = devm_regulator_get_enable(dev, "vdd"); 1510*ec08c395SMikael Gonella-Bolduc if (ret) 1511*ec08c395SMikael Gonella-Bolduc return dev_err_probe(dev, ret, "Failed to enable vdd supply\n"); 1512*ec08c395SMikael Gonella-Bolduc 1513*ec08c395SMikael Gonella-Bolduc indio_dev->name = "apds9160"; 1514*ec08c395SMikael Gonella-Bolduc indio_dev->modes = INDIO_DIRECT_MODE; 1515*ec08c395SMikael Gonella-Bolduc 1516*ec08c395SMikael Gonella-Bolduc chip = iio_priv(indio_dev); 1517*ec08c395SMikael Gonella-Bolduc chip->client = client; 1518*ec08c395SMikael Gonella-Bolduc chip->regmap = devm_regmap_init_i2c(client, &apds9160_regmap_config); 1519*ec08c395SMikael Gonella-Bolduc if (IS_ERR(chip->regmap)) 1520*ec08c395SMikael Gonella-Bolduc return dev_err_probe(dev, PTR_ERR(chip->regmap), 1521*ec08c395SMikael Gonella-Bolduc "regmap initialization failed.\n"); 1522*ec08c395SMikael Gonella-Bolduc 1523*ec08c395SMikael Gonella-Bolduc chip->client = client; 1524*ec08c395SMikael Gonella-Bolduc mutex_init(&chip->lock); 1525*ec08c395SMikael Gonella-Bolduc 1526*ec08c395SMikael Gonella-Bolduc ret = apds9160_detect(chip); 1527*ec08c395SMikael Gonella-Bolduc if (ret < 0) 1528*ec08c395SMikael Gonella-Bolduc return dev_err_probe(dev, ret, "apds9160 not found\n"); 1529*ec08c395SMikael Gonella-Bolduc 1530*ec08c395SMikael Gonella-Bolduc ret = apds9160_regfield_init(chip); 1531*ec08c395SMikael Gonella-Bolduc if (ret) 1532*ec08c395SMikael Gonella-Bolduc return ret; 1533*ec08c395SMikael Gonella-Bolduc 1534*ec08c395SMikael Gonella-Bolduc ret = apds9160_chip_init(chip); 1535*ec08c395SMikael Gonella-Bolduc if (ret) 1536*ec08c395SMikael Gonella-Bolduc return ret; 1537*ec08c395SMikael Gonella-Bolduc 1538*ec08c395SMikael Gonella-Bolduc ret = apds9160_ps_init_analog_cancellation(dev, chip); 1539*ec08c395SMikael Gonella-Bolduc if (ret) 1540*ec08c395SMikael Gonella-Bolduc return ret; 1541*ec08c395SMikael Gonella-Bolduc 1542*ec08c395SMikael Gonella-Bolduc if (client->irq > 0) { 1543*ec08c395SMikael Gonella-Bolduc indio_dev->info = &apds9160_info; 1544*ec08c395SMikael Gonella-Bolduc indio_dev->channels = apds9160_channels; 1545*ec08c395SMikael Gonella-Bolduc indio_dev->num_channels = ARRAY_SIZE(apds9160_channels); 1546*ec08c395SMikael Gonella-Bolduc ret = devm_request_threaded_irq(dev, client->irq, NULL, 1547*ec08c395SMikael Gonella-Bolduc apds9160_irq_handler, 1548*ec08c395SMikael Gonella-Bolduc IRQF_ONESHOT, "apds9160_event", 1549*ec08c395SMikael Gonella-Bolduc indio_dev); 1550*ec08c395SMikael Gonella-Bolduc if (ret) { 1551*ec08c395SMikael Gonella-Bolduc return dev_err_probe(dev, ret, 1552*ec08c395SMikael Gonella-Bolduc "request irq (%d) failed\n", 1553*ec08c395SMikael Gonella-Bolduc client->irq); 1554*ec08c395SMikael Gonella-Bolduc } 1555*ec08c395SMikael Gonella-Bolduc } else { 1556*ec08c395SMikael Gonella-Bolduc indio_dev->info = &apds9160_info_no_events; 1557*ec08c395SMikael Gonella-Bolduc indio_dev->channels = apds9160_channels_without_events; 1558*ec08c395SMikael Gonella-Bolduc indio_dev->num_channels = 1559*ec08c395SMikael Gonella-Bolduc ARRAY_SIZE(apds9160_channels_without_events); 1560*ec08c395SMikael Gonella-Bolduc } 1561*ec08c395SMikael Gonella-Bolduc 1562*ec08c395SMikael Gonella-Bolduc ret = devm_iio_device_register(dev, indio_dev); 1563*ec08c395SMikael Gonella-Bolduc if (ret) 1564*ec08c395SMikael Gonella-Bolduc return dev_err_probe(dev, ret, 1565*ec08c395SMikael Gonella-Bolduc "failed iio device registration\n"); 1566*ec08c395SMikael Gonella-Bolduc 1567*ec08c395SMikael Gonella-Bolduc return ret; 1568*ec08c395SMikael Gonella-Bolduc } 1569*ec08c395SMikael Gonella-Bolduc 1570*ec08c395SMikael Gonella-Bolduc static const struct of_device_id apds9160_of_match[] = { 1571*ec08c395SMikael Gonella-Bolduc { .compatible = "brcm,apds9160" }, 1572*ec08c395SMikael Gonella-Bolduc { } 1573*ec08c395SMikael Gonella-Bolduc }; 1574*ec08c395SMikael Gonella-Bolduc MODULE_DEVICE_TABLE(of, apds9160_of_match); 1575*ec08c395SMikael Gonella-Bolduc 1576*ec08c395SMikael Gonella-Bolduc static const struct i2c_device_id apds9160_id[] = { 1577*ec08c395SMikael Gonella-Bolduc { "apds9160", 0 }, 1578*ec08c395SMikael Gonella-Bolduc { } 1579*ec08c395SMikael Gonella-Bolduc }; 1580*ec08c395SMikael Gonella-Bolduc MODULE_DEVICE_TABLE(i2c, apds9160_id); 1581*ec08c395SMikael Gonella-Bolduc 1582*ec08c395SMikael Gonella-Bolduc static struct i2c_driver apds9160_driver = { 1583*ec08c395SMikael Gonella-Bolduc .driver = { 1584*ec08c395SMikael Gonella-Bolduc .name = "apds9160", 1585*ec08c395SMikael Gonella-Bolduc .of_match_table = apds9160_of_match, 1586*ec08c395SMikael Gonella-Bolduc }, 1587*ec08c395SMikael Gonella-Bolduc .probe = apds9160_probe, 1588*ec08c395SMikael Gonella-Bolduc .id_table = apds9160_id, 1589*ec08c395SMikael Gonella-Bolduc }; 1590*ec08c395SMikael Gonella-Bolduc module_i2c_driver(apds9160_driver); 1591*ec08c395SMikael Gonella-Bolduc 1592*ec08c395SMikael Gonella-Bolduc MODULE_DESCRIPTION("APDS9160 combined ALS and proximity sensor"); 1593*ec08c395SMikael Gonella-Bolduc MODULE_AUTHOR("Mikael Gonella-Bolduc <m.gonella.bolduc@gmail.com>"); 1594*ec08c395SMikael Gonella-Bolduc MODULE_LICENSE("GPL"); 1595