162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * isl29003.c - Linux kernel module for 462306a36Sopenharmony_ci * Intersil ISL29003 ambient light sensor 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * See file:Documentation/misc-devices/isl29003.rst 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * Copyright (c) 2009 Daniel Mack <daniel@caiaq.de> 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * Based on code written by 1162306a36Sopenharmony_ci * Rodolfo Giometti <giometti@linux.it> 1262306a36Sopenharmony_ci * Eurotech S.p.A. <info@eurotech.it> 1362306a36Sopenharmony_ci */ 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#include <linux/module.h> 1662306a36Sopenharmony_ci#include <linux/slab.h> 1762306a36Sopenharmony_ci#include <linux/i2c.h> 1862306a36Sopenharmony_ci#include <linux/mutex.h> 1962306a36Sopenharmony_ci#include <linux/delay.h> 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#define ISL29003_DRV_NAME "isl29003" 2262306a36Sopenharmony_ci#define DRIVER_VERSION "1.0" 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#define ISL29003_REG_COMMAND 0x00 2562306a36Sopenharmony_ci#define ISL29003_ADC_ENABLED (1 << 7) 2662306a36Sopenharmony_ci#define ISL29003_ADC_PD (1 << 6) 2762306a36Sopenharmony_ci#define ISL29003_TIMING_INT (1 << 5) 2862306a36Sopenharmony_ci#define ISL29003_MODE_SHIFT (2) 2962306a36Sopenharmony_ci#define ISL29003_MODE_MASK (0x3 << ISL29003_MODE_SHIFT) 3062306a36Sopenharmony_ci#define ISL29003_RES_SHIFT (0) 3162306a36Sopenharmony_ci#define ISL29003_RES_MASK (0x3 << ISL29003_RES_SHIFT) 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci#define ISL29003_REG_CONTROL 0x01 3462306a36Sopenharmony_ci#define ISL29003_INT_FLG (1 << 5) 3562306a36Sopenharmony_ci#define ISL29003_RANGE_SHIFT (2) 3662306a36Sopenharmony_ci#define ISL29003_RANGE_MASK (0x3 << ISL29003_RANGE_SHIFT) 3762306a36Sopenharmony_ci#define ISL29003_INT_PERSISTS_SHIFT (0) 3862306a36Sopenharmony_ci#define ISL29003_INT_PERSISTS_MASK (0xf << ISL29003_INT_PERSISTS_SHIFT) 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci#define ISL29003_REG_IRQ_THRESH_HI 0x02 4162306a36Sopenharmony_ci#define ISL29003_REG_IRQ_THRESH_LO 0x03 4262306a36Sopenharmony_ci#define ISL29003_REG_LSB_SENSOR 0x04 4362306a36Sopenharmony_ci#define ISL29003_REG_MSB_SENSOR 0x05 4462306a36Sopenharmony_ci#define ISL29003_REG_LSB_TIMER 0x06 4562306a36Sopenharmony_ci#define ISL29003_REG_MSB_TIMER 0x07 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci#define ISL29003_NUM_CACHABLE_REGS 4 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_cistruct isl29003_data { 5062306a36Sopenharmony_ci struct i2c_client *client; 5162306a36Sopenharmony_ci struct mutex lock; 5262306a36Sopenharmony_ci u8 reg_cache[ISL29003_NUM_CACHABLE_REGS]; 5362306a36Sopenharmony_ci u8 power_state_before_suspend; 5462306a36Sopenharmony_ci}; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_cistatic int gain_range[] = { 5762306a36Sopenharmony_ci 1000, 4000, 16000, 64000 5862306a36Sopenharmony_ci}; 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci/* 6162306a36Sopenharmony_ci * register access helpers 6262306a36Sopenharmony_ci */ 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_cistatic int __isl29003_read_reg(struct i2c_client *client, 6562306a36Sopenharmony_ci u32 reg, u8 mask, u8 shift) 6662306a36Sopenharmony_ci{ 6762306a36Sopenharmony_ci struct isl29003_data *data = i2c_get_clientdata(client); 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci return (data->reg_cache[reg] & mask) >> shift; 7062306a36Sopenharmony_ci} 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_cistatic int __isl29003_write_reg(struct i2c_client *client, 7362306a36Sopenharmony_ci u32 reg, u8 mask, u8 shift, u8 val) 7462306a36Sopenharmony_ci{ 7562306a36Sopenharmony_ci struct isl29003_data *data = i2c_get_clientdata(client); 7662306a36Sopenharmony_ci int ret = 0; 7762306a36Sopenharmony_ci u8 tmp; 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci if (reg >= ISL29003_NUM_CACHABLE_REGS) 8062306a36Sopenharmony_ci return -EINVAL; 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci mutex_lock(&data->lock); 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci tmp = data->reg_cache[reg]; 8562306a36Sopenharmony_ci tmp &= ~mask; 8662306a36Sopenharmony_ci tmp |= val << shift; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci ret = i2c_smbus_write_byte_data(client, reg, tmp); 8962306a36Sopenharmony_ci if (!ret) 9062306a36Sopenharmony_ci data->reg_cache[reg] = tmp; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci mutex_unlock(&data->lock); 9362306a36Sopenharmony_ci return ret; 9462306a36Sopenharmony_ci} 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci/* 9762306a36Sopenharmony_ci * internally used functions 9862306a36Sopenharmony_ci */ 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci/* range */ 10162306a36Sopenharmony_cistatic int isl29003_get_range(struct i2c_client *client) 10262306a36Sopenharmony_ci{ 10362306a36Sopenharmony_ci return __isl29003_read_reg(client, ISL29003_REG_CONTROL, 10462306a36Sopenharmony_ci ISL29003_RANGE_MASK, ISL29003_RANGE_SHIFT); 10562306a36Sopenharmony_ci} 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_cistatic int isl29003_set_range(struct i2c_client *client, int range) 10862306a36Sopenharmony_ci{ 10962306a36Sopenharmony_ci return __isl29003_write_reg(client, ISL29003_REG_CONTROL, 11062306a36Sopenharmony_ci ISL29003_RANGE_MASK, ISL29003_RANGE_SHIFT, range); 11162306a36Sopenharmony_ci} 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci/* resolution */ 11462306a36Sopenharmony_cistatic int isl29003_get_resolution(struct i2c_client *client) 11562306a36Sopenharmony_ci{ 11662306a36Sopenharmony_ci return __isl29003_read_reg(client, ISL29003_REG_COMMAND, 11762306a36Sopenharmony_ci ISL29003_RES_MASK, ISL29003_RES_SHIFT); 11862306a36Sopenharmony_ci} 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_cistatic int isl29003_set_resolution(struct i2c_client *client, int res) 12162306a36Sopenharmony_ci{ 12262306a36Sopenharmony_ci return __isl29003_write_reg(client, ISL29003_REG_COMMAND, 12362306a36Sopenharmony_ci ISL29003_RES_MASK, ISL29003_RES_SHIFT, res); 12462306a36Sopenharmony_ci} 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci/* mode */ 12762306a36Sopenharmony_cistatic int isl29003_get_mode(struct i2c_client *client) 12862306a36Sopenharmony_ci{ 12962306a36Sopenharmony_ci return __isl29003_read_reg(client, ISL29003_REG_COMMAND, 13062306a36Sopenharmony_ci ISL29003_MODE_MASK, ISL29003_MODE_SHIFT); 13162306a36Sopenharmony_ci} 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_cistatic int isl29003_set_mode(struct i2c_client *client, int mode) 13462306a36Sopenharmony_ci{ 13562306a36Sopenharmony_ci return __isl29003_write_reg(client, ISL29003_REG_COMMAND, 13662306a36Sopenharmony_ci ISL29003_MODE_MASK, ISL29003_MODE_SHIFT, mode); 13762306a36Sopenharmony_ci} 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci/* power_state */ 14062306a36Sopenharmony_cistatic int isl29003_set_power_state(struct i2c_client *client, int state) 14162306a36Sopenharmony_ci{ 14262306a36Sopenharmony_ci return __isl29003_write_reg(client, ISL29003_REG_COMMAND, 14362306a36Sopenharmony_ci ISL29003_ADC_ENABLED | ISL29003_ADC_PD, 0, 14462306a36Sopenharmony_ci state ? ISL29003_ADC_ENABLED : ISL29003_ADC_PD); 14562306a36Sopenharmony_ci} 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_cistatic int isl29003_get_power_state(struct i2c_client *client) 14862306a36Sopenharmony_ci{ 14962306a36Sopenharmony_ci struct isl29003_data *data = i2c_get_clientdata(client); 15062306a36Sopenharmony_ci u8 cmdreg = data->reg_cache[ISL29003_REG_COMMAND]; 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci return ~cmdreg & ISL29003_ADC_PD; 15362306a36Sopenharmony_ci} 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_cistatic int isl29003_get_adc_value(struct i2c_client *client) 15662306a36Sopenharmony_ci{ 15762306a36Sopenharmony_ci struct isl29003_data *data = i2c_get_clientdata(client); 15862306a36Sopenharmony_ci int lsb, msb, range, bitdepth; 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci mutex_lock(&data->lock); 16162306a36Sopenharmony_ci lsb = i2c_smbus_read_byte_data(client, ISL29003_REG_LSB_SENSOR); 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci if (lsb < 0) { 16462306a36Sopenharmony_ci mutex_unlock(&data->lock); 16562306a36Sopenharmony_ci return lsb; 16662306a36Sopenharmony_ci } 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci msb = i2c_smbus_read_byte_data(client, ISL29003_REG_MSB_SENSOR); 16962306a36Sopenharmony_ci mutex_unlock(&data->lock); 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci if (msb < 0) 17262306a36Sopenharmony_ci return msb; 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci range = isl29003_get_range(client); 17562306a36Sopenharmony_ci bitdepth = (4 - isl29003_get_resolution(client)) * 4; 17662306a36Sopenharmony_ci return (((msb << 8) | lsb) * gain_range[range]) >> bitdepth; 17762306a36Sopenharmony_ci} 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci/* 18062306a36Sopenharmony_ci * sysfs layer 18162306a36Sopenharmony_ci */ 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci/* range */ 18462306a36Sopenharmony_cistatic ssize_t isl29003_show_range(struct device *dev, 18562306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 18662306a36Sopenharmony_ci{ 18762306a36Sopenharmony_ci struct i2c_client *client = to_i2c_client(dev); 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci return sysfs_emit(buf, "%i\n", isl29003_get_range(client)); 19062306a36Sopenharmony_ci} 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_cistatic ssize_t isl29003_store_range(struct device *dev, 19362306a36Sopenharmony_ci struct device_attribute *attr, 19462306a36Sopenharmony_ci const char *buf, size_t count) 19562306a36Sopenharmony_ci{ 19662306a36Sopenharmony_ci struct i2c_client *client = to_i2c_client(dev); 19762306a36Sopenharmony_ci unsigned long val; 19862306a36Sopenharmony_ci int ret; 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci ret = kstrtoul(buf, 10, &val); 20162306a36Sopenharmony_ci if (ret) 20262306a36Sopenharmony_ci return ret; 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci if (val > 3) 20562306a36Sopenharmony_ci return -EINVAL; 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci ret = isl29003_set_range(client, val); 20862306a36Sopenharmony_ci if (ret < 0) 20962306a36Sopenharmony_ci return ret; 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci return count; 21262306a36Sopenharmony_ci} 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_cistatic DEVICE_ATTR(range, S_IWUSR | S_IRUGO, 21562306a36Sopenharmony_ci isl29003_show_range, isl29003_store_range); 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci/* resolution */ 21962306a36Sopenharmony_cistatic ssize_t isl29003_show_resolution(struct device *dev, 22062306a36Sopenharmony_ci struct device_attribute *attr, 22162306a36Sopenharmony_ci char *buf) 22262306a36Sopenharmony_ci{ 22362306a36Sopenharmony_ci struct i2c_client *client = to_i2c_client(dev); 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci return sysfs_emit(buf, "%d\n", isl29003_get_resolution(client)); 22662306a36Sopenharmony_ci} 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_cistatic ssize_t isl29003_store_resolution(struct device *dev, 22962306a36Sopenharmony_ci struct device_attribute *attr, 23062306a36Sopenharmony_ci const char *buf, size_t count) 23162306a36Sopenharmony_ci{ 23262306a36Sopenharmony_ci struct i2c_client *client = to_i2c_client(dev); 23362306a36Sopenharmony_ci unsigned long val; 23462306a36Sopenharmony_ci int ret; 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci ret = kstrtoul(buf, 10, &val); 23762306a36Sopenharmony_ci if (ret) 23862306a36Sopenharmony_ci return ret; 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci if (val > 3) 24162306a36Sopenharmony_ci return -EINVAL; 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci ret = isl29003_set_resolution(client, val); 24462306a36Sopenharmony_ci if (ret < 0) 24562306a36Sopenharmony_ci return ret; 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci return count; 24862306a36Sopenharmony_ci} 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_cistatic DEVICE_ATTR(resolution, S_IWUSR | S_IRUGO, 25162306a36Sopenharmony_ci isl29003_show_resolution, isl29003_store_resolution); 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci/* mode */ 25462306a36Sopenharmony_cistatic ssize_t isl29003_show_mode(struct device *dev, 25562306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 25662306a36Sopenharmony_ci{ 25762306a36Sopenharmony_ci struct i2c_client *client = to_i2c_client(dev); 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci return sysfs_emit(buf, "%d\n", isl29003_get_mode(client)); 26062306a36Sopenharmony_ci} 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_cistatic ssize_t isl29003_store_mode(struct device *dev, 26362306a36Sopenharmony_ci struct device_attribute *attr, const char *buf, size_t count) 26462306a36Sopenharmony_ci{ 26562306a36Sopenharmony_ci struct i2c_client *client = to_i2c_client(dev); 26662306a36Sopenharmony_ci unsigned long val; 26762306a36Sopenharmony_ci int ret; 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci ret = kstrtoul(buf, 10, &val); 27062306a36Sopenharmony_ci if (ret) 27162306a36Sopenharmony_ci return ret; 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci if (val > 2) 27462306a36Sopenharmony_ci return -EINVAL; 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci ret = isl29003_set_mode(client, val); 27762306a36Sopenharmony_ci if (ret < 0) 27862306a36Sopenharmony_ci return ret; 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci return count; 28162306a36Sopenharmony_ci} 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_cistatic DEVICE_ATTR(mode, S_IWUSR | S_IRUGO, 28462306a36Sopenharmony_ci isl29003_show_mode, isl29003_store_mode); 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci/* power state */ 28862306a36Sopenharmony_cistatic ssize_t isl29003_show_power_state(struct device *dev, 28962306a36Sopenharmony_ci struct device_attribute *attr, 29062306a36Sopenharmony_ci char *buf) 29162306a36Sopenharmony_ci{ 29262306a36Sopenharmony_ci struct i2c_client *client = to_i2c_client(dev); 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci return sysfs_emit(buf, "%d\n", isl29003_get_power_state(client)); 29562306a36Sopenharmony_ci} 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_cistatic ssize_t isl29003_store_power_state(struct device *dev, 29862306a36Sopenharmony_ci struct device_attribute *attr, 29962306a36Sopenharmony_ci const char *buf, size_t count) 30062306a36Sopenharmony_ci{ 30162306a36Sopenharmony_ci struct i2c_client *client = to_i2c_client(dev); 30262306a36Sopenharmony_ci unsigned long val; 30362306a36Sopenharmony_ci int ret; 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci ret = kstrtoul(buf, 10, &val); 30662306a36Sopenharmony_ci if (ret) 30762306a36Sopenharmony_ci return ret; 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci if (val > 1) 31062306a36Sopenharmony_ci return -EINVAL; 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci ret = isl29003_set_power_state(client, val); 31362306a36Sopenharmony_ci return ret ? ret : count; 31462306a36Sopenharmony_ci} 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_cistatic DEVICE_ATTR(power_state, S_IWUSR | S_IRUGO, 31762306a36Sopenharmony_ci isl29003_show_power_state, isl29003_store_power_state); 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci/* lux */ 32162306a36Sopenharmony_cistatic ssize_t isl29003_show_lux(struct device *dev, 32262306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 32362306a36Sopenharmony_ci{ 32462306a36Sopenharmony_ci struct i2c_client *client = to_i2c_client(dev); 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci /* No LUX data if not operational */ 32762306a36Sopenharmony_ci if (!isl29003_get_power_state(client)) 32862306a36Sopenharmony_ci return -EBUSY; 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci return sysfs_emit(buf, "%d\n", isl29003_get_adc_value(client)); 33162306a36Sopenharmony_ci} 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_cistatic DEVICE_ATTR(lux, S_IRUGO, isl29003_show_lux, NULL); 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_cistatic struct attribute *isl29003_attributes[] = { 33662306a36Sopenharmony_ci &dev_attr_range.attr, 33762306a36Sopenharmony_ci &dev_attr_resolution.attr, 33862306a36Sopenharmony_ci &dev_attr_mode.attr, 33962306a36Sopenharmony_ci &dev_attr_power_state.attr, 34062306a36Sopenharmony_ci &dev_attr_lux.attr, 34162306a36Sopenharmony_ci NULL 34262306a36Sopenharmony_ci}; 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_cistatic const struct attribute_group isl29003_attr_group = { 34562306a36Sopenharmony_ci .attrs = isl29003_attributes, 34662306a36Sopenharmony_ci}; 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_cistatic int isl29003_init_client(struct i2c_client *client) 34962306a36Sopenharmony_ci{ 35062306a36Sopenharmony_ci struct isl29003_data *data = i2c_get_clientdata(client); 35162306a36Sopenharmony_ci int i; 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci /* read all the registers once to fill the cache. 35462306a36Sopenharmony_ci * if one of the reads fails, we consider the init failed */ 35562306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(data->reg_cache); i++) { 35662306a36Sopenharmony_ci int v = i2c_smbus_read_byte_data(client, i); 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci if (v < 0) 35962306a36Sopenharmony_ci return -ENODEV; 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci data->reg_cache[i] = v; 36262306a36Sopenharmony_ci } 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci /* set defaults */ 36562306a36Sopenharmony_ci isl29003_set_range(client, 0); 36662306a36Sopenharmony_ci isl29003_set_resolution(client, 0); 36762306a36Sopenharmony_ci isl29003_set_mode(client, 0); 36862306a36Sopenharmony_ci isl29003_set_power_state(client, 0); 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci return 0; 37162306a36Sopenharmony_ci} 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci/* 37462306a36Sopenharmony_ci * I2C layer 37562306a36Sopenharmony_ci */ 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_cistatic int isl29003_probe(struct i2c_client *client) 37862306a36Sopenharmony_ci{ 37962306a36Sopenharmony_ci struct i2c_adapter *adapter = client->adapter; 38062306a36Sopenharmony_ci struct isl29003_data *data; 38162306a36Sopenharmony_ci int err = 0; 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE)) 38462306a36Sopenharmony_ci return -EIO; 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci data = kzalloc(sizeof(struct isl29003_data), GFP_KERNEL); 38762306a36Sopenharmony_ci if (!data) 38862306a36Sopenharmony_ci return -ENOMEM; 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci data->client = client; 39162306a36Sopenharmony_ci i2c_set_clientdata(client, data); 39262306a36Sopenharmony_ci mutex_init(&data->lock); 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci /* initialize the ISL29003 chip */ 39562306a36Sopenharmony_ci err = isl29003_init_client(client); 39662306a36Sopenharmony_ci if (err) 39762306a36Sopenharmony_ci goto exit_kfree; 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci /* register sysfs hooks */ 40062306a36Sopenharmony_ci err = sysfs_create_group(&client->dev.kobj, &isl29003_attr_group); 40162306a36Sopenharmony_ci if (err) 40262306a36Sopenharmony_ci goto exit_kfree; 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci dev_info(&client->dev, "driver version %s enabled\n", DRIVER_VERSION); 40562306a36Sopenharmony_ci return 0; 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ciexit_kfree: 40862306a36Sopenharmony_ci kfree(data); 40962306a36Sopenharmony_ci return err; 41062306a36Sopenharmony_ci} 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_cistatic void isl29003_remove(struct i2c_client *client) 41362306a36Sopenharmony_ci{ 41462306a36Sopenharmony_ci sysfs_remove_group(&client->dev.kobj, &isl29003_attr_group); 41562306a36Sopenharmony_ci isl29003_set_power_state(client, 0); 41662306a36Sopenharmony_ci kfree(i2c_get_clientdata(client)); 41762306a36Sopenharmony_ci} 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 42062306a36Sopenharmony_cistatic int isl29003_suspend(struct device *dev) 42162306a36Sopenharmony_ci{ 42262306a36Sopenharmony_ci struct i2c_client *client = to_i2c_client(dev); 42362306a36Sopenharmony_ci struct isl29003_data *data = i2c_get_clientdata(client); 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci data->power_state_before_suspend = isl29003_get_power_state(client); 42662306a36Sopenharmony_ci return isl29003_set_power_state(client, 0); 42762306a36Sopenharmony_ci} 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_cistatic int isl29003_resume(struct device *dev) 43062306a36Sopenharmony_ci{ 43162306a36Sopenharmony_ci int i; 43262306a36Sopenharmony_ci struct i2c_client *client = to_i2c_client(dev); 43362306a36Sopenharmony_ci struct isl29003_data *data = i2c_get_clientdata(client); 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci /* restore registers from cache */ 43662306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(data->reg_cache); i++) 43762306a36Sopenharmony_ci if (i2c_smbus_write_byte_data(client, i, data->reg_cache[i])) 43862306a36Sopenharmony_ci return -EIO; 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci return isl29003_set_power_state(client, 44162306a36Sopenharmony_ci data->power_state_before_suspend); 44262306a36Sopenharmony_ci} 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(isl29003_pm_ops, isl29003_suspend, isl29003_resume); 44562306a36Sopenharmony_ci#define ISL29003_PM_OPS (&isl29003_pm_ops) 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci#else 44862306a36Sopenharmony_ci#define ISL29003_PM_OPS NULL 44962306a36Sopenharmony_ci#endif /* CONFIG_PM_SLEEP */ 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_cistatic const struct i2c_device_id isl29003_id[] = { 45262306a36Sopenharmony_ci { "isl29003", 0 }, 45362306a36Sopenharmony_ci {} 45462306a36Sopenharmony_ci}; 45562306a36Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, isl29003_id); 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_cistatic struct i2c_driver isl29003_driver = { 45862306a36Sopenharmony_ci .driver = { 45962306a36Sopenharmony_ci .name = ISL29003_DRV_NAME, 46062306a36Sopenharmony_ci .pm = ISL29003_PM_OPS, 46162306a36Sopenharmony_ci }, 46262306a36Sopenharmony_ci .probe = isl29003_probe, 46362306a36Sopenharmony_ci .remove = isl29003_remove, 46462306a36Sopenharmony_ci .id_table = isl29003_id, 46562306a36Sopenharmony_ci}; 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_cimodule_i2c_driver(isl29003_driver); 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ciMODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>"); 47062306a36Sopenharmony_ciMODULE_DESCRIPTION("ISL29003 ambient light sensor driver"); 47162306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 47262306a36Sopenharmony_ciMODULE_VERSION(DRIVER_VERSION); 473