Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  *  isl29003.c - Linux kernel module for
0004  *  Intersil ISL29003 ambient light sensor
0005  *
0006  *  See file:Documentation/misc-devices/isl29003.rst
0007  *
0008  *  Copyright (c) 2009 Daniel Mack <daniel@caiaq.de>
0009  *
0010  *  Based on code written by
0011  *      Rodolfo Giometti <giometti@linux.it>
0012  *      Eurotech S.p.A. <info@eurotech.it>
0013  */
0014 
0015 #include <linux/module.h>
0016 #include <linux/slab.h>
0017 #include <linux/i2c.h>
0018 #include <linux/mutex.h>
0019 #include <linux/delay.h>
0020 
0021 #define ISL29003_DRV_NAME   "isl29003"
0022 #define DRIVER_VERSION      "1.0"
0023 
0024 #define ISL29003_REG_COMMAND        0x00
0025 #define ISL29003_ADC_ENABLED        (1 << 7)
0026 #define ISL29003_ADC_PD         (1 << 6)
0027 #define ISL29003_TIMING_INT     (1 << 5)
0028 #define ISL29003_MODE_SHIFT     (2)
0029 #define ISL29003_MODE_MASK      (0x3 << ISL29003_MODE_SHIFT)
0030 #define ISL29003_RES_SHIFT      (0)
0031 #define ISL29003_RES_MASK       (0x3 << ISL29003_RES_SHIFT)
0032 
0033 #define ISL29003_REG_CONTROL        0x01
0034 #define ISL29003_INT_FLG        (1 << 5)
0035 #define ISL29003_RANGE_SHIFT        (2)
0036 #define ISL29003_RANGE_MASK     (0x3 << ISL29003_RANGE_SHIFT)
0037 #define ISL29003_INT_PERSISTS_SHIFT (0)
0038 #define ISL29003_INT_PERSISTS_MASK  (0xf << ISL29003_INT_PERSISTS_SHIFT)
0039 
0040 #define ISL29003_REG_IRQ_THRESH_HI  0x02
0041 #define ISL29003_REG_IRQ_THRESH_LO  0x03
0042 #define ISL29003_REG_LSB_SENSOR     0x04
0043 #define ISL29003_REG_MSB_SENSOR     0x05
0044 #define ISL29003_REG_LSB_TIMER      0x06
0045 #define ISL29003_REG_MSB_TIMER      0x07
0046 
0047 #define ISL29003_NUM_CACHABLE_REGS  4
0048 
0049 struct isl29003_data {
0050     struct i2c_client *client;
0051     struct mutex lock;
0052     u8 reg_cache[ISL29003_NUM_CACHABLE_REGS];
0053     u8 power_state_before_suspend;
0054 };
0055 
0056 static int gain_range[] = {
0057     1000, 4000, 16000, 64000
0058 };
0059 
0060 /*
0061  * register access helpers
0062  */
0063 
0064 static int __isl29003_read_reg(struct i2c_client *client,
0065                    u32 reg, u8 mask, u8 shift)
0066 {
0067     struct isl29003_data *data = i2c_get_clientdata(client);
0068 
0069     return (data->reg_cache[reg] & mask) >> shift;
0070 }
0071 
0072 static int __isl29003_write_reg(struct i2c_client *client,
0073                 u32 reg, u8 mask, u8 shift, u8 val)
0074 {
0075     struct isl29003_data *data = i2c_get_clientdata(client);
0076     int ret = 0;
0077     u8 tmp;
0078 
0079     if (reg >= ISL29003_NUM_CACHABLE_REGS)
0080         return -EINVAL;
0081 
0082     mutex_lock(&data->lock);
0083 
0084     tmp = data->reg_cache[reg];
0085     tmp &= ~mask;
0086     tmp |= val << shift;
0087 
0088     ret = i2c_smbus_write_byte_data(client, reg, tmp);
0089     if (!ret)
0090         data->reg_cache[reg] = tmp;
0091 
0092     mutex_unlock(&data->lock);
0093     return ret;
0094 }
0095 
0096 /*
0097  * internally used functions
0098  */
0099 
0100 /* range */
0101 static int isl29003_get_range(struct i2c_client *client)
0102 {
0103     return __isl29003_read_reg(client, ISL29003_REG_CONTROL,
0104         ISL29003_RANGE_MASK, ISL29003_RANGE_SHIFT);
0105 }
0106 
0107 static int isl29003_set_range(struct i2c_client *client, int range)
0108 {
0109     return __isl29003_write_reg(client, ISL29003_REG_CONTROL,
0110         ISL29003_RANGE_MASK, ISL29003_RANGE_SHIFT, range);
0111 }
0112 
0113 /* resolution */
0114 static int isl29003_get_resolution(struct i2c_client *client)
0115 {
0116     return __isl29003_read_reg(client, ISL29003_REG_COMMAND,
0117         ISL29003_RES_MASK, ISL29003_RES_SHIFT);
0118 }
0119 
0120 static int isl29003_set_resolution(struct i2c_client *client, int res)
0121 {
0122     return __isl29003_write_reg(client, ISL29003_REG_COMMAND,
0123         ISL29003_RES_MASK, ISL29003_RES_SHIFT, res);
0124 }
0125 
0126 /* mode */
0127 static int isl29003_get_mode(struct i2c_client *client)
0128 {
0129     return __isl29003_read_reg(client, ISL29003_REG_COMMAND,
0130         ISL29003_MODE_MASK, ISL29003_MODE_SHIFT);
0131 }
0132 
0133 static int isl29003_set_mode(struct i2c_client *client, int mode)
0134 {
0135     return __isl29003_write_reg(client, ISL29003_REG_COMMAND,
0136         ISL29003_MODE_MASK, ISL29003_MODE_SHIFT, mode);
0137 }
0138 
0139 /* power_state */
0140 static int isl29003_set_power_state(struct i2c_client *client, int state)
0141 {
0142     return __isl29003_write_reg(client, ISL29003_REG_COMMAND,
0143                 ISL29003_ADC_ENABLED | ISL29003_ADC_PD, 0,
0144                 state ? ISL29003_ADC_ENABLED : ISL29003_ADC_PD);
0145 }
0146 
0147 static int isl29003_get_power_state(struct i2c_client *client)
0148 {
0149     struct isl29003_data *data = i2c_get_clientdata(client);
0150     u8 cmdreg = data->reg_cache[ISL29003_REG_COMMAND];
0151 
0152     return ~cmdreg & ISL29003_ADC_PD;
0153 }
0154 
0155 static int isl29003_get_adc_value(struct i2c_client *client)
0156 {
0157     struct isl29003_data *data = i2c_get_clientdata(client);
0158     int lsb, msb, range, bitdepth;
0159 
0160     mutex_lock(&data->lock);
0161     lsb = i2c_smbus_read_byte_data(client, ISL29003_REG_LSB_SENSOR);
0162 
0163     if (lsb < 0) {
0164         mutex_unlock(&data->lock);
0165         return lsb;
0166     }
0167 
0168     msb = i2c_smbus_read_byte_data(client, ISL29003_REG_MSB_SENSOR);
0169     mutex_unlock(&data->lock);
0170 
0171     if (msb < 0)
0172         return msb;
0173 
0174     range = isl29003_get_range(client);
0175     bitdepth = (4 - isl29003_get_resolution(client)) * 4;
0176     return (((msb << 8) | lsb) * gain_range[range]) >> bitdepth;
0177 }
0178 
0179 /*
0180  * sysfs layer
0181  */
0182 
0183 /* range */
0184 static ssize_t isl29003_show_range(struct device *dev,
0185                    struct device_attribute *attr, char *buf)
0186 {
0187     struct i2c_client *client = to_i2c_client(dev);
0188 
0189     return sprintf(buf, "%i\n", isl29003_get_range(client));
0190 }
0191 
0192 static ssize_t isl29003_store_range(struct device *dev,
0193                     struct device_attribute *attr,
0194                     const char *buf, size_t count)
0195 {
0196     struct i2c_client *client = to_i2c_client(dev);
0197     unsigned long val;
0198     int ret;
0199 
0200     ret = kstrtoul(buf, 10, &val);
0201     if (ret)
0202         return ret;
0203 
0204     if (val > 3)
0205         return -EINVAL;
0206 
0207     ret = isl29003_set_range(client, val);
0208     if (ret < 0)
0209         return ret;
0210 
0211     return count;
0212 }
0213 
0214 static DEVICE_ATTR(range, S_IWUSR | S_IRUGO,
0215            isl29003_show_range, isl29003_store_range);
0216 
0217 
0218 /* resolution */
0219 static ssize_t isl29003_show_resolution(struct device *dev,
0220                     struct device_attribute *attr,
0221                     char *buf)
0222 {
0223     struct i2c_client *client = to_i2c_client(dev);
0224 
0225     return sprintf(buf, "%d\n", isl29003_get_resolution(client));
0226 }
0227 
0228 static ssize_t isl29003_store_resolution(struct device *dev,
0229                      struct device_attribute *attr,
0230                      const char *buf, size_t count)
0231 {
0232     struct i2c_client *client = to_i2c_client(dev);
0233     unsigned long val;
0234     int ret;
0235 
0236     ret = kstrtoul(buf, 10, &val);
0237     if (ret)
0238         return ret;
0239 
0240     if (val > 3)
0241         return -EINVAL;
0242 
0243     ret = isl29003_set_resolution(client, val);
0244     if (ret < 0)
0245         return ret;
0246 
0247     return count;
0248 }
0249 
0250 static DEVICE_ATTR(resolution, S_IWUSR | S_IRUGO,
0251            isl29003_show_resolution, isl29003_store_resolution);
0252 
0253 /* mode */
0254 static ssize_t isl29003_show_mode(struct device *dev,
0255                   struct device_attribute *attr, char *buf)
0256 {
0257     struct i2c_client *client = to_i2c_client(dev);
0258 
0259     return sprintf(buf, "%d\n", isl29003_get_mode(client));
0260 }
0261 
0262 static ssize_t isl29003_store_mode(struct device *dev,
0263         struct device_attribute *attr, const char *buf, size_t count)
0264 {
0265     struct i2c_client *client = to_i2c_client(dev);
0266     unsigned long val;
0267     int ret;
0268 
0269     ret = kstrtoul(buf, 10, &val);
0270     if (ret)
0271         return ret;
0272 
0273     if (val > 2)
0274         return -EINVAL;
0275 
0276     ret = isl29003_set_mode(client, val);
0277     if (ret < 0)
0278         return ret;
0279 
0280     return count;
0281 }
0282 
0283 static DEVICE_ATTR(mode, S_IWUSR | S_IRUGO,
0284            isl29003_show_mode, isl29003_store_mode);
0285 
0286 
0287 /* power state */
0288 static ssize_t isl29003_show_power_state(struct device *dev,
0289                      struct device_attribute *attr,
0290                      char *buf)
0291 {
0292     struct i2c_client *client = to_i2c_client(dev);
0293 
0294     return sprintf(buf, "%d\n", isl29003_get_power_state(client));
0295 }
0296 
0297 static ssize_t isl29003_store_power_state(struct device *dev,
0298                       struct device_attribute *attr,
0299                       const char *buf, size_t count)
0300 {
0301     struct i2c_client *client = to_i2c_client(dev);
0302     unsigned long val;
0303     int ret;
0304 
0305     ret = kstrtoul(buf, 10, &val);
0306     if (ret)
0307         return ret;
0308 
0309     if (val > 1)
0310         return -EINVAL;
0311 
0312     ret = isl29003_set_power_state(client, val);
0313     return ret ? ret : count;
0314 }
0315 
0316 static DEVICE_ATTR(power_state, S_IWUSR | S_IRUGO,
0317            isl29003_show_power_state, isl29003_store_power_state);
0318 
0319 
0320 /* lux */
0321 static ssize_t isl29003_show_lux(struct device *dev,
0322                  struct device_attribute *attr, char *buf)
0323 {
0324     struct i2c_client *client = to_i2c_client(dev);
0325 
0326     /* No LUX data if not operational */
0327     if (!isl29003_get_power_state(client))
0328         return -EBUSY;
0329 
0330     return sprintf(buf, "%d\n", isl29003_get_adc_value(client));
0331 }
0332 
0333 static DEVICE_ATTR(lux, S_IRUGO, isl29003_show_lux, NULL);
0334 
0335 static struct attribute *isl29003_attributes[] = {
0336     &dev_attr_range.attr,
0337     &dev_attr_resolution.attr,
0338     &dev_attr_mode.attr,
0339     &dev_attr_power_state.attr,
0340     &dev_attr_lux.attr,
0341     NULL
0342 };
0343 
0344 static const struct attribute_group isl29003_attr_group = {
0345     .attrs = isl29003_attributes,
0346 };
0347 
0348 static int isl29003_init_client(struct i2c_client *client)
0349 {
0350     struct isl29003_data *data = i2c_get_clientdata(client);
0351     int i;
0352 
0353     /* read all the registers once to fill the cache.
0354      * if one of the reads fails, we consider the init failed */
0355     for (i = 0; i < ARRAY_SIZE(data->reg_cache); i++) {
0356         int v = i2c_smbus_read_byte_data(client, i);
0357 
0358         if (v < 0)
0359             return -ENODEV;
0360 
0361         data->reg_cache[i] = v;
0362     }
0363 
0364     /* set defaults */
0365     isl29003_set_range(client, 0);
0366     isl29003_set_resolution(client, 0);
0367     isl29003_set_mode(client, 0);
0368     isl29003_set_power_state(client, 0);
0369 
0370     return 0;
0371 }
0372 
0373 /*
0374  * I2C layer
0375  */
0376 
0377 static int isl29003_probe(struct i2c_client *client,
0378                     const struct i2c_device_id *id)
0379 {
0380     struct i2c_adapter *adapter = client->adapter;
0381     struct isl29003_data *data;
0382     int err = 0;
0383 
0384     if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE))
0385         return -EIO;
0386 
0387     data = kzalloc(sizeof(struct isl29003_data), GFP_KERNEL);
0388     if (!data)
0389         return -ENOMEM;
0390 
0391     data->client = client;
0392     i2c_set_clientdata(client, data);
0393     mutex_init(&data->lock);
0394 
0395     /* initialize the ISL29003 chip */
0396     err = isl29003_init_client(client);
0397     if (err)
0398         goto exit_kfree;
0399 
0400     /* register sysfs hooks */
0401     err = sysfs_create_group(&client->dev.kobj, &isl29003_attr_group);
0402     if (err)
0403         goto exit_kfree;
0404 
0405     dev_info(&client->dev, "driver version %s enabled\n", DRIVER_VERSION);
0406     return 0;
0407 
0408 exit_kfree:
0409     kfree(data);
0410     return err;
0411 }
0412 
0413 static int isl29003_remove(struct i2c_client *client)
0414 {
0415     sysfs_remove_group(&client->dev.kobj, &isl29003_attr_group);
0416     isl29003_set_power_state(client, 0);
0417     kfree(i2c_get_clientdata(client));
0418     return 0;
0419 }
0420 
0421 #ifdef CONFIG_PM_SLEEP
0422 static int isl29003_suspend(struct device *dev)
0423 {
0424     struct i2c_client *client = to_i2c_client(dev);
0425     struct isl29003_data *data = i2c_get_clientdata(client);
0426 
0427     data->power_state_before_suspend = isl29003_get_power_state(client);
0428     return isl29003_set_power_state(client, 0);
0429 }
0430 
0431 static int isl29003_resume(struct device *dev)
0432 {
0433     int i;
0434     struct i2c_client *client = to_i2c_client(dev);
0435     struct isl29003_data *data = i2c_get_clientdata(client);
0436 
0437     /* restore registers from cache */
0438     for (i = 0; i < ARRAY_SIZE(data->reg_cache); i++)
0439         if (i2c_smbus_write_byte_data(client, i, data->reg_cache[i]))
0440             return -EIO;
0441 
0442     return isl29003_set_power_state(client,
0443         data->power_state_before_suspend);
0444 }
0445 
0446 static SIMPLE_DEV_PM_OPS(isl29003_pm_ops, isl29003_suspend, isl29003_resume);
0447 #define ISL29003_PM_OPS (&isl29003_pm_ops)
0448 
0449 #else
0450 #define ISL29003_PM_OPS NULL
0451 #endif /* CONFIG_PM_SLEEP */
0452 
0453 static const struct i2c_device_id isl29003_id[] = {
0454     { "isl29003", 0 },
0455     {}
0456 };
0457 MODULE_DEVICE_TABLE(i2c, isl29003_id);
0458 
0459 static struct i2c_driver isl29003_driver = {
0460     .driver = {
0461         .name   = ISL29003_DRV_NAME,
0462         .pm = ISL29003_PM_OPS,
0463     },
0464     .probe  = isl29003_probe,
0465     .remove = isl29003_remove,
0466     .id_table = isl29003_id,
0467 };
0468 
0469 module_i2c_driver(isl29003_driver);
0470 
0471 MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>");
0472 MODULE_DESCRIPTION("ISL29003 ambient light sensor driver");
0473 MODULE_LICENSE("GPL v2");
0474 MODULE_VERSION(DRIVER_VERSION);