162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * A iio driver for the light sensor ISL 29018/29023/29035. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * IIO driver for monitoring ambient light intensity in luxi, proximity 662306a36Sopenharmony_ci * sensing and infrared sensing. 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * Copyright (c) 2010, NVIDIA Corporation. 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <linux/module.h> 1262306a36Sopenharmony_ci#include <linux/i2c.h> 1362306a36Sopenharmony_ci#include <linux/err.h> 1462306a36Sopenharmony_ci#include <linux/mutex.h> 1562306a36Sopenharmony_ci#include <linux/delay.h> 1662306a36Sopenharmony_ci#include <linux/regmap.h> 1762306a36Sopenharmony_ci#include <linux/regulator/consumer.h> 1862306a36Sopenharmony_ci#include <linux/slab.h> 1962306a36Sopenharmony_ci#include <linux/iio/iio.h> 2062306a36Sopenharmony_ci#include <linux/iio/sysfs.h> 2162306a36Sopenharmony_ci#include <linux/acpi.h> 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci#define ISL29018_CONV_TIME_MS 100 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci#define ISL29018_REG_ADD_COMMAND1 0x00 2662306a36Sopenharmony_ci#define ISL29018_CMD1_OPMODE_SHIFT 5 2762306a36Sopenharmony_ci#define ISL29018_CMD1_OPMODE_MASK (7 << ISL29018_CMD1_OPMODE_SHIFT) 2862306a36Sopenharmony_ci#define ISL29018_CMD1_OPMODE_POWER_DOWN 0 2962306a36Sopenharmony_ci#define ISL29018_CMD1_OPMODE_ALS_ONCE 1 3062306a36Sopenharmony_ci#define ISL29018_CMD1_OPMODE_IR_ONCE 2 3162306a36Sopenharmony_ci#define ISL29018_CMD1_OPMODE_PROX_ONCE 3 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci#define ISL29018_REG_ADD_COMMAND2 0x01 3462306a36Sopenharmony_ci#define ISL29018_CMD2_RESOLUTION_SHIFT 2 3562306a36Sopenharmony_ci#define ISL29018_CMD2_RESOLUTION_MASK (0x3 << ISL29018_CMD2_RESOLUTION_SHIFT) 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci#define ISL29018_CMD2_RANGE_SHIFT 0 3862306a36Sopenharmony_ci#define ISL29018_CMD2_RANGE_MASK (0x3 << ISL29018_CMD2_RANGE_SHIFT) 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci#define ISL29018_CMD2_SCHEME_SHIFT 7 4162306a36Sopenharmony_ci#define ISL29018_CMD2_SCHEME_MASK (0x1 << ISL29018_CMD2_SCHEME_SHIFT) 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci#define ISL29018_REG_ADD_DATA_LSB 0x02 4462306a36Sopenharmony_ci#define ISL29018_REG_ADD_DATA_MSB 0x03 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci#define ISL29018_REG_TEST 0x08 4762306a36Sopenharmony_ci#define ISL29018_TEST_SHIFT 0 4862306a36Sopenharmony_ci#define ISL29018_TEST_MASK (0xFF << ISL29018_TEST_SHIFT) 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci#define ISL29035_REG_DEVICE_ID 0x0F 5162306a36Sopenharmony_ci#define ISL29035_DEVICE_ID_SHIFT 0x03 5262306a36Sopenharmony_ci#define ISL29035_DEVICE_ID_MASK (0x7 << ISL29035_DEVICE_ID_SHIFT) 5362306a36Sopenharmony_ci#define ISL29035_DEVICE_ID 0x5 5462306a36Sopenharmony_ci#define ISL29035_BOUT_SHIFT 0x07 5562306a36Sopenharmony_ci#define ISL29035_BOUT_MASK (0x01 << ISL29035_BOUT_SHIFT) 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_cienum isl29018_int_time { 5862306a36Sopenharmony_ci ISL29018_INT_TIME_16, 5962306a36Sopenharmony_ci ISL29018_INT_TIME_12, 6062306a36Sopenharmony_ci ISL29018_INT_TIME_8, 6162306a36Sopenharmony_ci ISL29018_INT_TIME_4, 6262306a36Sopenharmony_ci}; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_cistatic const unsigned int isl29018_int_utimes[3][4] = { 6562306a36Sopenharmony_ci {90000, 5630, 351, 21}, 6662306a36Sopenharmony_ci {90000, 5600, 352, 22}, 6762306a36Sopenharmony_ci {105000, 6500, 410, 25}, 6862306a36Sopenharmony_ci}; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_cistatic const struct isl29018_scale { 7162306a36Sopenharmony_ci unsigned int scale; 7262306a36Sopenharmony_ci unsigned int uscale; 7362306a36Sopenharmony_ci} isl29018_scales[4][4] = { 7462306a36Sopenharmony_ci { {0, 15258}, {0, 61035}, {0, 244140}, {0, 976562} }, 7562306a36Sopenharmony_ci { {0, 244140}, {0, 976562}, {3, 906250}, {15, 625000} }, 7662306a36Sopenharmony_ci { {3, 906250}, {15, 625000}, {62, 500000}, {250, 0} }, 7762306a36Sopenharmony_ci { {62, 500000}, {250, 0}, {1000, 0}, {4000, 0} } 7862306a36Sopenharmony_ci}; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_cistruct isl29018_chip { 8162306a36Sopenharmony_ci struct regmap *regmap; 8262306a36Sopenharmony_ci struct mutex lock; 8362306a36Sopenharmony_ci int type; 8462306a36Sopenharmony_ci unsigned int calibscale; 8562306a36Sopenharmony_ci unsigned int ucalibscale; 8662306a36Sopenharmony_ci unsigned int int_time; 8762306a36Sopenharmony_ci struct isl29018_scale scale; 8862306a36Sopenharmony_ci int prox_scheme; 8962306a36Sopenharmony_ci bool suspended; 9062306a36Sopenharmony_ci struct regulator *vcc_reg; 9162306a36Sopenharmony_ci}; 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_cistatic int isl29018_set_integration_time(struct isl29018_chip *chip, 9462306a36Sopenharmony_ci unsigned int utime) 9562306a36Sopenharmony_ci{ 9662306a36Sopenharmony_ci unsigned int i; 9762306a36Sopenharmony_ci int ret; 9862306a36Sopenharmony_ci unsigned int int_time, new_int_time; 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(isl29018_int_utimes[chip->type]); ++i) { 10162306a36Sopenharmony_ci if (utime == isl29018_int_utimes[chip->type][i]) { 10262306a36Sopenharmony_ci new_int_time = i; 10362306a36Sopenharmony_ci break; 10462306a36Sopenharmony_ci } 10562306a36Sopenharmony_ci } 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci if (i >= ARRAY_SIZE(isl29018_int_utimes[chip->type])) 10862306a36Sopenharmony_ci return -EINVAL; 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci ret = regmap_update_bits(chip->regmap, ISL29018_REG_ADD_COMMAND2, 11162306a36Sopenharmony_ci ISL29018_CMD2_RESOLUTION_MASK, 11262306a36Sopenharmony_ci i << ISL29018_CMD2_RESOLUTION_SHIFT); 11362306a36Sopenharmony_ci if (ret < 0) 11462306a36Sopenharmony_ci return ret; 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci /* Keep the same range when integration time changes */ 11762306a36Sopenharmony_ci int_time = chip->int_time; 11862306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(isl29018_scales[int_time]); ++i) { 11962306a36Sopenharmony_ci if (chip->scale.scale == isl29018_scales[int_time][i].scale && 12062306a36Sopenharmony_ci chip->scale.uscale == isl29018_scales[int_time][i].uscale) { 12162306a36Sopenharmony_ci chip->scale = isl29018_scales[new_int_time][i]; 12262306a36Sopenharmony_ci break; 12362306a36Sopenharmony_ci } 12462306a36Sopenharmony_ci } 12562306a36Sopenharmony_ci chip->int_time = new_int_time; 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci return 0; 12862306a36Sopenharmony_ci} 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_cistatic int isl29018_set_scale(struct isl29018_chip *chip, int scale, int uscale) 13162306a36Sopenharmony_ci{ 13262306a36Sopenharmony_ci unsigned int i; 13362306a36Sopenharmony_ci int ret; 13462306a36Sopenharmony_ci struct isl29018_scale new_scale; 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(isl29018_scales[chip->int_time]); ++i) { 13762306a36Sopenharmony_ci if (scale == isl29018_scales[chip->int_time][i].scale && 13862306a36Sopenharmony_ci uscale == isl29018_scales[chip->int_time][i].uscale) { 13962306a36Sopenharmony_ci new_scale = isl29018_scales[chip->int_time][i]; 14062306a36Sopenharmony_ci break; 14162306a36Sopenharmony_ci } 14262306a36Sopenharmony_ci } 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci if (i >= ARRAY_SIZE(isl29018_scales[chip->int_time])) 14562306a36Sopenharmony_ci return -EINVAL; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci ret = regmap_update_bits(chip->regmap, ISL29018_REG_ADD_COMMAND2, 14862306a36Sopenharmony_ci ISL29018_CMD2_RANGE_MASK, 14962306a36Sopenharmony_ci i << ISL29018_CMD2_RANGE_SHIFT); 15062306a36Sopenharmony_ci if (ret < 0) 15162306a36Sopenharmony_ci return ret; 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci chip->scale = new_scale; 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci return 0; 15662306a36Sopenharmony_ci} 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_cistatic int isl29018_read_sensor_input(struct isl29018_chip *chip, int mode) 15962306a36Sopenharmony_ci{ 16062306a36Sopenharmony_ci int status; 16162306a36Sopenharmony_ci unsigned int lsb; 16262306a36Sopenharmony_ci unsigned int msb; 16362306a36Sopenharmony_ci struct device *dev = regmap_get_device(chip->regmap); 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci /* Set mode */ 16662306a36Sopenharmony_ci status = regmap_write(chip->regmap, ISL29018_REG_ADD_COMMAND1, 16762306a36Sopenharmony_ci mode << ISL29018_CMD1_OPMODE_SHIFT); 16862306a36Sopenharmony_ci if (status) { 16962306a36Sopenharmony_ci dev_err(dev, 17062306a36Sopenharmony_ci "Error in setting operating mode err %d\n", status); 17162306a36Sopenharmony_ci return status; 17262306a36Sopenharmony_ci } 17362306a36Sopenharmony_ci msleep(ISL29018_CONV_TIME_MS); 17462306a36Sopenharmony_ci status = regmap_read(chip->regmap, ISL29018_REG_ADD_DATA_LSB, &lsb); 17562306a36Sopenharmony_ci if (status < 0) { 17662306a36Sopenharmony_ci dev_err(dev, 17762306a36Sopenharmony_ci "Error in reading LSB DATA with err %d\n", status); 17862306a36Sopenharmony_ci return status; 17962306a36Sopenharmony_ci } 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci status = regmap_read(chip->regmap, ISL29018_REG_ADD_DATA_MSB, &msb); 18262306a36Sopenharmony_ci if (status < 0) { 18362306a36Sopenharmony_ci dev_err(dev, 18462306a36Sopenharmony_ci "Error in reading MSB DATA with error %d\n", status); 18562306a36Sopenharmony_ci return status; 18662306a36Sopenharmony_ci } 18762306a36Sopenharmony_ci dev_vdbg(dev, "MSB 0x%x and LSB 0x%x\n", msb, lsb); 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci return (msb << 8) | lsb; 19062306a36Sopenharmony_ci} 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_cistatic int isl29018_read_lux(struct isl29018_chip *chip, int *lux) 19362306a36Sopenharmony_ci{ 19462306a36Sopenharmony_ci int lux_data; 19562306a36Sopenharmony_ci unsigned int data_x_range; 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci lux_data = isl29018_read_sensor_input(chip, 19862306a36Sopenharmony_ci ISL29018_CMD1_OPMODE_ALS_ONCE); 19962306a36Sopenharmony_ci if (lux_data < 0) 20062306a36Sopenharmony_ci return lux_data; 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci data_x_range = lux_data * chip->scale.scale + 20362306a36Sopenharmony_ci lux_data * chip->scale.uscale / 1000000; 20462306a36Sopenharmony_ci *lux = data_x_range * chip->calibscale + 20562306a36Sopenharmony_ci data_x_range * chip->ucalibscale / 1000000; 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci return 0; 20862306a36Sopenharmony_ci} 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_cistatic int isl29018_read_ir(struct isl29018_chip *chip, int *ir) 21162306a36Sopenharmony_ci{ 21262306a36Sopenharmony_ci int ir_data; 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci ir_data = isl29018_read_sensor_input(chip, 21562306a36Sopenharmony_ci ISL29018_CMD1_OPMODE_IR_ONCE); 21662306a36Sopenharmony_ci if (ir_data < 0) 21762306a36Sopenharmony_ci return ir_data; 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci *ir = ir_data; 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci return 0; 22262306a36Sopenharmony_ci} 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_cistatic int isl29018_read_proximity_ir(struct isl29018_chip *chip, int scheme, 22562306a36Sopenharmony_ci int *near_ir) 22662306a36Sopenharmony_ci{ 22762306a36Sopenharmony_ci int status; 22862306a36Sopenharmony_ci int prox_data = -1; 22962306a36Sopenharmony_ci int ir_data = -1; 23062306a36Sopenharmony_ci struct device *dev = regmap_get_device(chip->regmap); 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci /* Do proximity sensing with required scheme */ 23362306a36Sopenharmony_ci status = regmap_update_bits(chip->regmap, ISL29018_REG_ADD_COMMAND2, 23462306a36Sopenharmony_ci ISL29018_CMD2_SCHEME_MASK, 23562306a36Sopenharmony_ci scheme << ISL29018_CMD2_SCHEME_SHIFT); 23662306a36Sopenharmony_ci if (status) { 23762306a36Sopenharmony_ci dev_err(dev, "Error in setting operating mode\n"); 23862306a36Sopenharmony_ci return status; 23962306a36Sopenharmony_ci } 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci prox_data = isl29018_read_sensor_input(chip, 24262306a36Sopenharmony_ci ISL29018_CMD1_OPMODE_PROX_ONCE); 24362306a36Sopenharmony_ci if (prox_data < 0) 24462306a36Sopenharmony_ci return prox_data; 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci if (scheme == 1) { 24762306a36Sopenharmony_ci *near_ir = prox_data; 24862306a36Sopenharmony_ci return 0; 24962306a36Sopenharmony_ci } 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci ir_data = isl29018_read_sensor_input(chip, 25262306a36Sopenharmony_ci ISL29018_CMD1_OPMODE_IR_ONCE); 25362306a36Sopenharmony_ci if (ir_data < 0) 25462306a36Sopenharmony_ci return ir_data; 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci if (prox_data >= ir_data) 25762306a36Sopenharmony_ci *near_ir = prox_data - ir_data; 25862306a36Sopenharmony_ci else 25962306a36Sopenharmony_ci *near_ir = 0; 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci return 0; 26262306a36Sopenharmony_ci} 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_cistatic ssize_t in_illuminance_scale_available_show 26562306a36Sopenharmony_ci (struct device *dev, struct device_attribute *attr, 26662306a36Sopenharmony_ci char *buf) 26762306a36Sopenharmony_ci{ 26862306a36Sopenharmony_ci struct iio_dev *indio_dev = dev_to_iio_dev(dev); 26962306a36Sopenharmony_ci struct isl29018_chip *chip = iio_priv(indio_dev); 27062306a36Sopenharmony_ci unsigned int i; 27162306a36Sopenharmony_ci int len = 0; 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci mutex_lock(&chip->lock); 27462306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(isl29018_scales[chip->int_time]); ++i) 27562306a36Sopenharmony_ci len += sprintf(buf + len, "%d.%06d ", 27662306a36Sopenharmony_ci isl29018_scales[chip->int_time][i].scale, 27762306a36Sopenharmony_ci isl29018_scales[chip->int_time][i].uscale); 27862306a36Sopenharmony_ci mutex_unlock(&chip->lock); 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci buf[len - 1] = '\n'; 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci return len; 28362306a36Sopenharmony_ci} 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_cistatic ssize_t in_illuminance_integration_time_available_show 28662306a36Sopenharmony_ci (struct device *dev, struct device_attribute *attr, 28762306a36Sopenharmony_ci char *buf) 28862306a36Sopenharmony_ci{ 28962306a36Sopenharmony_ci struct iio_dev *indio_dev = dev_to_iio_dev(dev); 29062306a36Sopenharmony_ci struct isl29018_chip *chip = iio_priv(indio_dev); 29162306a36Sopenharmony_ci unsigned int i; 29262306a36Sopenharmony_ci int len = 0; 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(isl29018_int_utimes[chip->type]); ++i) 29562306a36Sopenharmony_ci len += sprintf(buf + len, "0.%06d ", 29662306a36Sopenharmony_ci isl29018_int_utimes[chip->type][i]); 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci buf[len - 1] = '\n'; 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci return len; 30162306a36Sopenharmony_ci} 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci/* 30462306a36Sopenharmony_ci * From ISL29018 Data Sheet (FN6619.4, Oct 8, 2012) regarding the 30562306a36Sopenharmony_ci * infrared suppression: 30662306a36Sopenharmony_ci * 30762306a36Sopenharmony_ci * Proximity Sensing Scheme: Bit 7. This bit programs the function 30862306a36Sopenharmony_ci * of the proximity detection. Logic 0 of this bit, Scheme 0, makes 30962306a36Sopenharmony_ci * full n (4, 8, 12, 16) bits (unsigned) proximity detection. The range 31062306a36Sopenharmony_ci * of Scheme 0 proximity count is from 0 to 2^n. Logic 1 of this bit, 31162306a36Sopenharmony_ci * Scheme 1, makes n-1 (3, 7, 11, 15) bits (2's complementary) 31262306a36Sopenharmony_ci * proximity_less_ambient detection. The range of Scheme 1 31362306a36Sopenharmony_ci * proximity count is from -2^(n-1) to 2^(n-1) . The sign bit is extended 31462306a36Sopenharmony_ci * for resolutions less than 16. While Scheme 0 has wider dynamic 31562306a36Sopenharmony_ci * range, Scheme 1 proximity detection is less affected by the 31662306a36Sopenharmony_ci * ambient IR noise variation. 31762306a36Sopenharmony_ci * 31862306a36Sopenharmony_ci * 0 Sensing IR from LED and ambient 31962306a36Sopenharmony_ci * 1 Sensing IR from LED with ambient IR rejection 32062306a36Sopenharmony_ci */ 32162306a36Sopenharmony_cistatic ssize_t proximity_on_chip_ambient_infrared_suppression_show 32262306a36Sopenharmony_ci (struct device *dev, struct device_attribute *attr, 32362306a36Sopenharmony_ci char *buf) 32462306a36Sopenharmony_ci{ 32562306a36Sopenharmony_ci struct iio_dev *indio_dev = dev_to_iio_dev(dev); 32662306a36Sopenharmony_ci struct isl29018_chip *chip = iio_priv(indio_dev); 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci /* 32962306a36Sopenharmony_ci * Return the "proximity scheme" i.e. if the chip does on chip 33062306a36Sopenharmony_ci * infrared suppression (1 means perform on chip suppression) 33162306a36Sopenharmony_ci */ 33262306a36Sopenharmony_ci return sprintf(buf, "%d\n", chip->prox_scheme); 33362306a36Sopenharmony_ci} 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_cistatic ssize_t proximity_on_chip_ambient_infrared_suppression_store 33662306a36Sopenharmony_ci (struct device *dev, struct device_attribute *attr, 33762306a36Sopenharmony_ci const char *buf, size_t count) 33862306a36Sopenharmony_ci{ 33962306a36Sopenharmony_ci struct iio_dev *indio_dev = dev_to_iio_dev(dev); 34062306a36Sopenharmony_ci struct isl29018_chip *chip = iio_priv(indio_dev); 34162306a36Sopenharmony_ci int val; 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci if (kstrtoint(buf, 10, &val)) 34462306a36Sopenharmony_ci return -EINVAL; 34562306a36Sopenharmony_ci if (!(val == 0 || val == 1)) 34662306a36Sopenharmony_ci return -EINVAL; 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci /* 34962306a36Sopenharmony_ci * Get the "proximity scheme" i.e. if the chip does on chip 35062306a36Sopenharmony_ci * infrared suppression (1 means perform on chip suppression) 35162306a36Sopenharmony_ci */ 35262306a36Sopenharmony_ci mutex_lock(&chip->lock); 35362306a36Sopenharmony_ci chip->prox_scheme = val; 35462306a36Sopenharmony_ci mutex_unlock(&chip->lock); 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci return count; 35762306a36Sopenharmony_ci} 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_cistatic int isl29018_write_raw(struct iio_dev *indio_dev, 36062306a36Sopenharmony_ci struct iio_chan_spec const *chan, 36162306a36Sopenharmony_ci int val, 36262306a36Sopenharmony_ci int val2, 36362306a36Sopenharmony_ci long mask) 36462306a36Sopenharmony_ci{ 36562306a36Sopenharmony_ci struct isl29018_chip *chip = iio_priv(indio_dev); 36662306a36Sopenharmony_ci int ret = -EINVAL; 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci mutex_lock(&chip->lock); 36962306a36Sopenharmony_ci if (chip->suspended) { 37062306a36Sopenharmony_ci ret = -EBUSY; 37162306a36Sopenharmony_ci goto write_done; 37262306a36Sopenharmony_ci } 37362306a36Sopenharmony_ci switch (mask) { 37462306a36Sopenharmony_ci case IIO_CHAN_INFO_CALIBSCALE: 37562306a36Sopenharmony_ci if (chan->type == IIO_LIGHT) { 37662306a36Sopenharmony_ci chip->calibscale = val; 37762306a36Sopenharmony_ci chip->ucalibscale = val2; 37862306a36Sopenharmony_ci ret = 0; 37962306a36Sopenharmony_ci } 38062306a36Sopenharmony_ci break; 38162306a36Sopenharmony_ci case IIO_CHAN_INFO_INT_TIME: 38262306a36Sopenharmony_ci if (chan->type == IIO_LIGHT && !val) 38362306a36Sopenharmony_ci ret = isl29018_set_integration_time(chip, val2); 38462306a36Sopenharmony_ci break; 38562306a36Sopenharmony_ci case IIO_CHAN_INFO_SCALE: 38662306a36Sopenharmony_ci if (chan->type == IIO_LIGHT) 38762306a36Sopenharmony_ci ret = isl29018_set_scale(chip, val, val2); 38862306a36Sopenharmony_ci break; 38962306a36Sopenharmony_ci default: 39062306a36Sopenharmony_ci break; 39162306a36Sopenharmony_ci } 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ciwrite_done: 39462306a36Sopenharmony_ci mutex_unlock(&chip->lock); 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci return ret; 39762306a36Sopenharmony_ci} 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_cistatic int isl29018_read_raw(struct iio_dev *indio_dev, 40062306a36Sopenharmony_ci struct iio_chan_spec const *chan, 40162306a36Sopenharmony_ci int *val, 40262306a36Sopenharmony_ci int *val2, 40362306a36Sopenharmony_ci long mask) 40462306a36Sopenharmony_ci{ 40562306a36Sopenharmony_ci int ret = -EINVAL; 40662306a36Sopenharmony_ci struct isl29018_chip *chip = iio_priv(indio_dev); 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci mutex_lock(&chip->lock); 40962306a36Sopenharmony_ci if (chip->suspended) { 41062306a36Sopenharmony_ci ret = -EBUSY; 41162306a36Sopenharmony_ci goto read_done; 41262306a36Sopenharmony_ci } 41362306a36Sopenharmony_ci switch (mask) { 41462306a36Sopenharmony_ci case IIO_CHAN_INFO_RAW: 41562306a36Sopenharmony_ci case IIO_CHAN_INFO_PROCESSED: 41662306a36Sopenharmony_ci switch (chan->type) { 41762306a36Sopenharmony_ci case IIO_LIGHT: 41862306a36Sopenharmony_ci ret = isl29018_read_lux(chip, val); 41962306a36Sopenharmony_ci break; 42062306a36Sopenharmony_ci case IIO_INTENSITY: 42162306a36Sopenharmony_ci ret = isl29018_read_ir(chip, val); 42262306a36Sopenharmony_ci break; 42362306a36Sopenharmony_ci case IIO_PROXIMITY: 42462306a36Sopenharmony_ci ret = isl29018_read_proximity_ir(chip, 42562306a36Sopenharmony_ci chip->prox_scheme, 42662306a36Sopenharmony_ci val); 42762306a36Sopenharmony_ci break; 42862306a36Sopenharmony_ci default: 42962306a36Sopenharmony_ci break; 43062306a36Sopenharmony_ci } 43162306a36Sopenharmony_ci if (!ret) 43262306a36Sopenharmony_ci ret = IIO_VAL_INT; 43362306a36Sopenharmony_ci break; 43462306a36Sopenharmony_ci case IIO_CHAN_INFO_INT_TIME: 43562306a36Sopenharmony_ci if (chan->type == IIO_LIGHT) { 43662306a36Sopenharmony_ci *val = 0; 43762306a36Sopenharmony_ci *val2 = isl29018_int_utimes[chip->type][chip->int_time]; 43862306a36Sopenharmony_ci ret = IIO_VAL_INT_PLUS_MICRO; 43962306a36Sopenharmony_ci } 44062306a36Sopenharmony_ci break; 44162306a36Sopenharmony_ci case IIO_CHAN_INFO_SCALE: 44262306a36Sopenharmony_ci if (chan->type == IIO_LIGHT) { 44362306a36Sopenharmony_ci *val = chip->scale.scale; 44462306a36Sopenharmony_ci *val2 = chip->scale.uscale; 44562306a36Sopenharmony_ci ret = IIO_VAL_INT_PLUS_MICRO; 44662306a36Sopenharmony_ci } 44762306a36Sopenharmony_ci break; 44862306a36Sopenharmony_ci case IIO_CHAN_INFO_CALIBSCALE: 44962306a36Sopenharmony_ci if (chan->type == IIO_LIGHT) { 45062306a36Sopenharmony_ci *val = chip->calibscale; 45162306a36Sopenharmony_ci *val2 = chip->ucalibscale; 45262306a36Sopenharmony_ci ret = IIO_VAL_INT_PLUS_MICRO; 45362306a36Sopenharmony_ci } 45462306a36Sopenharmony_ci break; 45562306a36Sopenharmony_ci default: 45662306a36Sopenharmony_ci break; 45762306a36Sopenharmony_ci } 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ciread_done: 46062306a36Sopenharmony_ci mutex_unlock(&chip->lock); 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci return ret; 46362306a36Sopenharmony_ci} 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci#define ISL29018_LIGHT_CHANNEL { \ 46662306a36Sopenharmony_ci .type = IIO_LIGHT, \ 46762306a36Sopenharmony_ci .indexed = 1, \ 46862306a36Sopenharmony_ci .channel = 0, \ 46962306a36Sopenharmony_ci .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) | \ 47062306a36Sopenharmony_ci BIT(IIO_CHAN_INFO_CALIBSCALE) | \ 47162306a36Sopenharmony_ci BIT(IIO_CHAN_INFO_SCALE) | \ 47262306a36Sopenharmony_ci BIT(IIO_CHAN_INFO_INT_TIME), \ 47362306a36Sopenharmony_ci} 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci#define ISL29018_IR_CHANNEL { \ 47662306a36Sopenharmony_ci .type = IIO_INTENSITY, \ 47762306a36Sopenharmony_ci .modified = 1, \ 47862306a36Sopenharmony_ci .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ 47962306a36Sopenharmony_ci .channel2 = IIO_MOD_LIGHT_IR, \ 48062306a36Sopenharmony_ci} 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci#define ISL29018_PROXIMITY_CHANNEL { \ 48362306a36Sopenharmony_ci .type = IIO_PROXIMITY, \ 48462306a36Sopenharmony_ci .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ 48562306a36Sopenharmony_ci} 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_cistatic const struct iio_chan_spec isl29018_channels[] = { 48862306a36Sopenharmony_ci ISL29018_LIGHT_CHANNEL, 48962306a36Sopenharmony_ci ISL29018_IR_CHANNEL, 49062306a36Sopenharmony_ci ISL29018_PROXIMITY_CHANNEL, 49162306a36Sopenharmony_ci}; 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_cistatic const struct iio_chan_spec isl29023_channels[] = { 49462306a36Sopenharmony_ci ISL29018_LIGHT_CHANNEL, 49562306a36Sopenharmony_ci ISL29018_IR_CHANNEL, 49662306a36Sopenharmony_ci}; 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_cistatic IIO_DEVICE_ATTR_RO(in_illuminance_integration_time_available, 0); 49962306a36Sopenharmony_cistatic IIO_DEVICE_ATTR_RO(in_illuminance_scale_available, 0); 50062306a36Sopenharmony_cistatic IIO_DEVICE_ATTR_RW(proximity_on_chip_ambient_infrared_suppression, 0); 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci#define ISL29018_DEV_ATTR(name) (&iio_dev_attr_##name.dev_attr.attr) 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_cistatic struct attribute *isl29018_attributes[] = { 50562306a36Sopenharmony_ci ISL29018_DEV_ATTR(in_illuminance_scale_available), 50662306a36Sopenharmony_ci ISL29018_DEV_ATTR(in_illuminance_integration_time_available), 50762306a36Sopenharmony_ci ISL29018_DEV_ATTR(proximity_on_chip_ambient_infrared_suppression), 50862306a36Sopenharmony_ci NULL 50962306a36Sopenharmony_ci}; 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_cistatic struct attribute *isl29023_attributes[] = { 51262306a36Sopenharmony_ci ISL29018_DEV_ATTR(in_illuminance_scale_available), 51362306a36Sopenharmony_ci ISL29018_DEV_ATTR(in_illuminance_integration_time_available), 51462306a36Sopenharmony_ci NULL 51562306a36Sopenharmony_ci}; 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_cistatic const struct attribute_group isl29018_group = { 51862306a36Sopenharmony_ci .attrs = isl29018_attributes, 51962306a36Sopenharmony_ci}; 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_cistatic const struct attribute_group isl29023_group = { 52262306a36Sopenharmony_ci .attrs = isl29023_attributes, 52362306a36Sopenharmony_ci}; 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_cienum { 52662306a36Sopenharmony_ci isl29018, 52762306a36Sopenharmony_ci isl29023, 52862306a36Sopenharmony_ci isl29035, 52962306a36Sopenharmony_ci}; 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_cistatic int isl29018_chip_init(struct isl29018_chip *chip) 53262306a36Sopenharmony_ci{ 53362306a36Sopenharmony_ci int status; 53462306a36Sopenharmony_ci struct device *dev = regmap_get_device(chip->regmap); 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci if (chip->type == isl29035) { 53762306a36Sopenharmony_ci unsigned int id; 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci status = regmap_read(chip->regmap, ISL29035_REG_DEVICE_ID, &id); 54062306a36Sopenharmony_ci if (status < 0) { 54162306a36Sopenharmony_ci dev_err(dev, 54262306a36Sopenharmony_ci "Error reading ID register with error %d\n", 54362306a36Sopenharmony_ci status); 54462306a36Sopenharmony_ci return status; 54562306a36Sopenharmony_ci } 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci id = (id & ISL29035_DEVICE_ID_MASK) >> ISL29035_DEVICE_ID_SHIFT; 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci if (id != ISL29035_DEVICE_ID) 55062306a36Sopenharmony_ci return -ENODEV; 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci /* Clear brownout bit */ 55362306a36Sopenharmony_ci status = regmap_update_bits(chip->regmap, 55462306a36Sopenharmony_ci ISL29035_REG_DEVICE_ID, 55562306a36Sopenharmony_ci ISL29035_BOUT_MASK, 0); 55662306a36Sopenharmony_ci if (status < 0) 55762306a36Sopenharmony_ci return status; 55862306a36Sopenharmony_ci } 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci /* 56162306a36Sopenharmony_ci * Code added per Intersil Application Note 1534: 56262306a36Sopenharmony_ci * When VDD sinks to approximately 1.8V or below, some of 56362306a36Sopenharmony_ci * the part's registers may change their state. When VDD 56462306a36Sopenharmony_ci * recovers to 2.25V (or greater), the part may thus be in an 56562306a36Sopenharmony_ci * unknown mode of operation. The user can return the part to 56662306a36Sopenharmony_ci * a known mode of operation either by (a) setting VDD = 0V for 56762306a36Sopenharmony_ci * 1 second or more and then powering back up with a slew rate 56862306a36Sopenharmony_ci * of 0.5V/ms or greater, or (b) via I2C disable all ALS/PROX 56962306a36Sopenharmony_ci * conversions, clear the test registers, and then rewrite all 57062306a36Sopenharmony_ci * registers to the desired values. 57162306a36Sopenharmony_ci * ... 57262306a36Sopenharmony_ci * For ISL29011, ISL29018, ISL29021, ISL29023 57362306a36Sopenharmony_ci * 1. Write 0x00 to register 0x08 (TEST) 57462306a36Sopenharmony_ci * 2. Write 0x00 to register 0x00 (CMD1) 57562306a36Sopenharmony_ci * 3. Rewrite all registers to the desired values 57662306a36Sopenharmony_ci * 57762306a36Sopenharmony_ci * ISL29018 Data Sheet (FN6619.1, Feb 11, 2010) essentially says 57862306a36Sopenharmony_ci * the same thing EXCEPT the data sheet asks for a 1ms delay after 57962306a36Sopenharmony_ci * writing the CMD1 register. 58062306a36Sopenharmony_ci */ 58162306a36Sopenharmony_ci status = regmap_write(chip->regmap, ISL29018_REG_TEST, 0x0); 58262306a36Sopenharmony_ci if (status < 0) { 58362306a36Sopenharmony_ci dev_err(dev, "Failed to clear isl29018 TEST reg.(%d)\n", 58462306a36Sopenharmony_ci status); 58562306a36Sopenharmony_ci return status; 58662306a36Sopenharmony_ci } 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci /* 58962306a36Sopenharmony_ci * See Intersil AN1534 comments above. 59062306a36Sopenharmony_ci * "Operating Mode" (COMMAND1) register is reprogrammed when 59162306a36Sopenharmony_ci * data is read from the device. 59262306a36Sopenharmony_ci */ 59362306a36Sopenharmony_ci status = regmap_write(chip->regmap, ISL29018_REG_ADD_COMMAND1, 0); 59462306a36Sopenharmony_ci if (status < 0) { 59562306a36Sopenharmony_ci dev_err(dev, "Failed to clear isl29018 CMD1 reg.(%d)\n", 59662306a36Sopenharmony_ci status); 59762306a36Sopenharmony_ci return status; 59862306a36Sopenharmony_ci } 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_ci usleep_range(1000, 2000); /* per data sheet, page 10 */ 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci /* Set defaults */ 60362306a36Sopenharmony_ci status = isl29018_set_scale(chip, chip->scale.scale, 60462306a36Sopenharmony_ci chip->scale.uscale); 60562306a36Sopenharmony_ci if (status < 0) { 60662306a36Sopenharmony_ci dev_err(dev, "Init of isl29018 fails\n"); 60762306a36Sopenharmony_ci return status; 60862306a36Sopenharmony_ci } 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci status = isl29018_set_integration_time(chip, 61162306a36Sopenharmony_ci isl29018_int_utimes[chip->type][chip->int_time]); 61262306a36Sopenharmony_ci if (status < 0) 61362306a36Sopenharmony_ci dev_err(dev, "Init of isl29018 fails\n"); 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci return status; 61662306a36Sopenharmony_ci} 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_cistatic const struct iio_info isl29018_info = { 61962306a36Sopenharmony_ci .attrs = &isl29018_group, 62062306a36Sopenharmony_ci .read_raw = isl29018_read_raw, 62162306a36Sopenharmony_ci .write_raw = isl29018_write_raw, 62262306a36Sopenharmony_ci}; 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_cistatic const struct iio_info isl29023_info = { 62562306a36Sopenharmony_ci .attrs = &isl29023_group, 62662306a36Sopenharmony_ci .read_raw = isl29018_read_raw, 62762306a36Sopenharmony_ci .write_raw = isl29018_write_raw, 62862306a36Sopenharmony_ci}; 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_cistatic bool isl29018_is_volatile_reg(struct device *dev, unsigned int reg) 63162306a36Sopenharmony_ci{ 63262306a36Sopenharmony_ci switch (reg) { 63362306a36Sopenharmony_ci case ISL29018_REG_ADD_DATA_LSB: 63462306a36Sopenharmony_ci case ISL29018_REG_ADD_DATA_MSB: 63562306a36Sopenharmony_ci case ISL29018_REG_ADD_COMMAND1: 63662306a36Sopenharmony_ci case ISL29018_REG_TEST: 63762306a36Sopenharmony_ci case ISL29035_REG_DEVICE_ID: 63862306a36Sopenharmony_ci return true; 63962306a36Sopenharmony_ci default: 64062306a36Sopenharmony_ci return false; 64162306a36Sopenharmony_ci } 64262306a36Sopenharmony_ci} 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_cistatic const struct regmap_config isl29018_regmap_config = { 64562306a36Sopenharmony_ci .reg_bits = 8, 64662306a36Sopenharmony_ci .val_bits = 8, 64762306a36Sopenharmony_ci .volatile_reg = isl29018_is_volatile_reg, 64862306a36Sopenharmony_ci .max_register = ISL29018_REG_TEST, 64962306a36Sopenharmony_ci .num_reg_defaults_raw = ISL29018_REG_TEST + 1, 65062306a36Sopenharmony_ci .cache_type = REGCACHE_RBTREE, 65162306a36Sopenharmony_ci}; 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_cistatic const struct regmap_config isl29035_regmap_config = { 65462306a36Sopenharmony_ci .reg_bits = 8, 65562306a36Sopenharmony_ci .val_bits = 8, 65662306a36Sopenharmony_ci .volatile_reg = isl29018_is_volatile_reg, 65762306a36Sopenharmony_ci .max_register = ISL29035_REG_DEVICE_ID, 65862306a36Sopenharmony_ci .num_reg_defaults_raw = ISL29035_REG_DEVICE_ID + 1, 65962306a36Sopenharmony_ci .cache_type = REGCACHE_RBTREE, 66062306a36Sopenharmony_ci}; 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_cistruct isl29018_chip_info { 66362306a36Sopenharmony_ci const struct iio_chan_spec *channels; 66462306a36Sopenharmony_ci int num_channels; 66562306a36Sopenharmony_ci const struct iio_info *indio_info; 66662306a36Sopenharmony_ci const struct regmap_config *regmap_cfg; 66762306a36Sopenharmony_ci}; 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_cistatic const struct isl29018_chip_info isl29018_chip_info_tbl[] = { 67062306a36Sopenharmony_ci [isl29018] = { 67162306a36Sopenharmony_ci .channels = isl29018_channels, 67262306a36Sopenharmony_ci .num_channels = ARRAY_SIZE(isl29018_channels), 67362306a36Sopenharmony_ci .indio_info = &isl29018_info, 67462306a36Sopenharmony_ci .regmap_cfg = &isl29018_regmap_config, 67562306a36Sopenharmony_ci }, 67662306a36Sopenharmony_ci [isl29023] = { 67762306a36Sopenharmony_ci .channels = isl29023_channels, 67862306a36Sopenharmony_ci .num_channels = ARRAY_SIZE(isl29023_channels), 67962306a36Sopenharmony_ci .indio_info = &isl29023_info, 68062306a36Sopenharmony_ci .regmap_cfg = &isl29018_regmap_config, 68162306a36Sopenharmony_ci }, 68262306a36Sopenharmony_ci [isl29035] = { 68362306a36Sopenharmony_ci .channels = isl29023_channels, 68462306a36Sopenharmony_ci .num_channels = ARRAY_SIZE(isl29023_channels), 68562306a36Sopenharmony_ci .indio_info = &isl29023_info, 68662306a36Sopenharmony_ci .regmap_cfg = &isl29035_regmap_config, 68762306a36Sopenharmony_ci }, 68862306a36Sopenharmony_ci}; 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_cistatic const char *isl29018_match_acpi_device(struct device *dev, int *data) 69162306a36Sopenharmony_ci{ 69262306a36Sopenharmony_ci const struct acpi_device_id *id; 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_ci id = acpi_match_device(dev->driver->acpi_match_table, dev); 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ci if (!id) 69762306a36Sopenharmony_ci return NULL; 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_ci *data = (int)id->driver_data; 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_ci return dev_name(dev); 70262306a36Sopenharmony_ci} 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_cistatic void isl29018_disable_regulator_action(void *_data) 70562306a36Sopenharmony_ci{ 70662306a36Sopenharmony_ci struct isl29018_chip *chip = _data; 70762306a36Sopenharmony_ci int err; 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_ci err = regulator_disable(chip->vcc_reg); 71062306a36Sopenharmony_ci if (err) 71162306a36Sopenharmony_ci pr_err("failed to disable isl29018's VCC regulator!\n"); 71262306a36Sopenharmony_ci} 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_cistatic int isl29018_probe(struct i2c_client *client) 71562306a36Sopenharmony_ci{ 71662306a36Sopenharmony_ci const struct i2c_device_id *id = i2c_client_get_device_id(client); 71762306a36Sopenharmony_ci struct isl29018_chip *chip; 71862306a36Sopenharmony_ci struct iio_dev *indio_dev; 71962306a36Sopenharmony_ci int err; 72062306a36Sopenharmony_ci const char *name = NULL; 72162306a36Sopenharmony_ci int dev_id = 0; 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_ci indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*chip)); 72462306a36Sopenharmony_ci if (!indio_dev) 72562306a36Sopenharmony_ci return -ENOMEM; 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci chip = iio_priv(indio_dev); 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_ci i2c_set_clientdata(client, indio_dev); 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci if (id) { 73262306a36Sopenharmony_ci name = id->name; 73362306a36Sopenharmony_ci dev_id = id->driver_data; 73462306a36Sopenharmony_ci } 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci if (ACPI_HANDLE(&client->dev)) 73762306a36Sopenharmony_ci name = isl29018_match_acpi_device(&client->dev, &dev_id); 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_ci mutex_init(&chip->lock); 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_ci chip->type = dev_id; 74262306a36Sopenharmony_ci chip->calibscale = 1; 74362306a36Sopenharmony_ci chip->ucalibscale = 0; 74462306a36Sopenharmony_ci chip->int_time = ISL29018_INT_TIME_16; 74562306a36Sopenharmony_ci chip->scale = isl29018_scales[chip->int_time][0]; 74662306a36Sopenharmony_ci chip->suspended = false; 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_ci chip->vcc_reg = devm_regulator_get(&client->dev, "vcc"); 74962306a36Sopenharmony_ci if (IS_ERR(chip->vcc_reg)) 75062306a36Sopenharmony_ci return dev_err_probe(&client->dev, PTR_ERR(chip->vcc_reg), 75162306a36Sopenharmony_ci "failed to get VCC regulator!\n"); 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_ci err = regulator_enable(chip->vcc_reg); 75462306a36Sopenharmony_ci if (err) { 75562306a36Sopenharmony_ci dev_err(&client->dev, "failed to enable VCC regulator!\n"); 75662306a36Sopenharmony_ci return err; 75762306a36Sopenharmony_ci } 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_ci err = devm_add_action_or_reset(&client->dev, isl29018_disable_regulator_action, 76062306a36Sopenharmony_ci chip); 76162306a36Sopenharmony_ci if (err) { 76262306a36Sopenharmony_ci dev_err(&client->dev, "failed to setup regulator cleanup action!\n"); 76362306a36Sopenharmony_ci return err; 76462306a36Sopenharmony_ci } 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_ci chip->regmap = devm_regmap_init_i2c(client, 76762306a36Sopenharmony_ci isl29018_chip_info_tbl[dev_id].regmap_cfg); 76862306a36Sopenharmony_ci if (IS_ERR(chip->regmap)) { 76962306a36Sopenharmony_ci err = PTR_ERR(chip->regmap); 77062306a36Sopenharmony_ci dev_err(&client->dev, "regmap initialization fails: %d\n", err); 77162306a36Sopenharmony_ci return err; 77262306a36Sopenharmony_ci } 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_ci err = isl29018_chip_init(chip); 77562306a36Sopenharmony_ci if (err) 77662306a36Sopenharmony_ci return err; 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_ci indio_dev->info = isl29018_chip_info_tbl[dev_id].indio_info; 77962306a36Sopenharmony_ci indio_dev->channels = isl29018_chip_info_tbl[dev_id].channels; 78062306a36Sopenharmony_ci indio_dev->num_channels = isl29018_chip_info_tbl[dev_id].num_channels; 78162306a36Sopenharmony_ci indio_dev->name = name; 78262306a36Sopenharmony_ci indio_dev->modes = INDIO_DIRECT_MODE; 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_ci return devm_iio_device_register(&client->dev, indio_dev); 78562306a36Sopenharmony_ci} 78662306a36Sopenharmony_ci 78762306a36Sopenharmony_cistatic int isl29018_suspend(struct device *dev) 78862306a36Sopenharmony_ci{ 78962306a36Sopenharmony_ci struct isl29018_chip *chip = iio_priv(dev_get_drvdata(dev)); 79062306a36Sopenharmony_ci int ret; 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_ci mutex_lock(&chip->lock); 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_ci /* 79562306a36Sopenharmony_ci * Since this driver uses only polling commands, we are by default in 79662306a36Sopenharmony_ci * auto shutdown (ie, power-down) mode. 79762306a36Sopenharmony_ci * So we do not have much to do here. 79862306a36Sopenharmony_ci */ 79962306a36Sopenharmony_ci chip->suspended = true; 80062306a36Sopenharmony_ci ret = regulator_disable(chip->vcc_reg); 80162306a36Sopenharmony_ci if (ret) 80262306a36Sopenharmony_ci dev_err(dev, "failed to disable VCC regulator\n"); 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_ci mutex_unlock(&chip->lock); 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_ci return ret; 80762306a36Sopenharmony_ci} 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_cistatic int isl29018_resume(struct device *dev) 81062306a36Sopenharmony_ci{ 81162306a36Sopenharmony_ci struct isl29018_chip *chip = iio_priv(dev_get_drvdata(dev)); 81262306a36Sopenharmony_ci int err; 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ci mutex_lock(&chip->lock); 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_ci err = regulator_enable(chip->vcc_reg); 81762306a36Sopenharmony_ci if (err) { 81862306a36Sopenharmony_ci dev_err(dev, "failed to enable VCC regulator\n"); 81962306a36Sopenharmony_ci mutex_unlock(&chip->lock); 82062306a36Sopenharmony_ci return err; 82162306a36Sopenharmony_ci } 82262306a36Sopenharmony_ci 82362306a36Sopenharmony_ci err = isl29018_chip_init(chip); 82462306a36Sopenharmony_ci if (!err) 82562306a36Sopenharmony_ci chip->suspended = false; 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_ci mutex_unlock(&chip->lock); 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_ci return err; 83062306a36Sopenharmony_ci} 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_cistatic DEFINE_SIMPLE_DEV_PM_OPS(isl29018_pm_ops, isl29018_suspend, 83362306a36Sopenharmony_ci isl29018_resume); 83462306a36Sopenharmony_ci 83562306a36Sopenharmony_ci#ifdef CONFIG_ACPI 83662306a36Sopenharmony_cistatic const struct acpi_device_id isl29018_acpi_match[] = { 83762306a36Sopenharmony_ci {"ISL29018", isl29018}, 83862306a36Sopenharmony_ci {"ISL29023", isl29023}, 83962306a36Sopenharmony_ci {"ISL29035", isl29035}, 84062306a36Sopenharmony_ci {}, 84162306a36Sopenharmony_ci}; 84262306a36Sopenharmony_ciMODULE_DEVICE_TABLE(acpi, isl29018_acpi_match); 84362306a36Sopenharmony_ci#endif 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_cistatic const struct i2c_device_id isl29018_id[] = { 84662306a36Sopenharmony_ci {"isl29018", isl29018}, 84762306a36Sopenharmony_ci {"isl29023", isl29023}, 84862306a36Sopenharmony_ci {"isl29035", isl29035}, 84962306a36Sopenharmony_ci {} 85062306a36Sopenharmony_ci}; 85162306a36Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, isl29018_id); 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_cistatic const struct of_device_id isl29018_of_match[] = { 85462306a36Sopenharmony_ci { .compatible = "isil,isl29018", }, 85562306a36Sopenharmony_ci { .compatible = "isil,isl29023", }, 85662306a36Sopenharmony_ci { .compatible = "isil,isl29035", }, 85762306a36Sopenharmony_ci { }, 85862306a36Sopenharmony_ci}; 85962306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, isl29018_of_match); 86062306a36Sopenharmony_ci 86162306a36Sopenharmony_cistatic struct i2c_driver isl29018_driver = { 86262306a36Sopenharmony_ci .driver = { 86362306a36Sopenharmony_ci .name = "isl29018", 86462306a36Sopenharmony_ci .acpi_match_table = ACPI_PTR(isl29018_acpi_match), 86562306a36Sopenharmony_ci .pm = pm_sleep_ptr(&isl29018_pm_ops), 86662306a36Sopenharmony_ci .of_match_table = isl29018_of_match, 86762306a36Sopenharmony_ci }, 86862306a36Sopenharmony_ci .probe = isl29018_probe, 86962306a36Sopenharmony_ci .id_table = isl29018_id, 87062306a36Sopenharmony_ci}; 87162306a36Sopenharmony_cimodule_i2c_driver(isl29018_driver); 87262306a36Sopenharmony_ci 87362306a36Sopenharmony_ciMODULE_DESCRIPTION("ISL29018 Ambient Light Sensor driver"); 87462306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 875