Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

iio: light: Add APDS9160 ALS & Proximity sensor driver

APDS9160 is a combination of ALS and proximity sensors.

This patch add supports for:
- Intensity clear data and illuminance data
- Proximity data
- Gain control, rate control
- Event thresholds

Signed-off-by: Mikael Gonella-Bolduc <mgonellabolduc@dimonoff.com>
Link: https://patch.msgid.link/20250122-apds9160-driver-v5-2-5393be10279a@dimonoff.com
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>

authored by

Mikael Gonella-Bolduc and committed by
Jonathan Cameron
ec08c395 be464661

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