Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * apds9300.c - IIO driver for Avago APDS9300 ambient light sensor
0004  *
0005  * Copyright 2013 Oleksandr Kravchenko <o.v.kravchenko@globallogic.com>
0006  */
0007 
0008 #include <linux/module.h>
0009 #include <linux/slab.h>
0010 #include <linux/pm.h>
0011 #include <linux/i2c.h>
0012 #include <linux/err.h>
0013 #include <linux/mutex.h>
0014 #include <linux/interrupt.h>
0015 #include <linux/iio/iio.h>
0016 #include <linux/iio/sysfs.h>
0017 #include <linux/iio/events.h>
0018 
0019 #define APDS9300_DRV_NAME "apds9300"
0020 #define APDS9300_IRQ_NAME "apds9300_event"
0021 
0022 /* Command register bits */
0023 #define APDS9300_CMD    BIT(7) /* Select command register. Must write as 1 */
0024 #define APDS9300_WORD   BIT(5) /* I2C write/read: if 1 word, if 0 byte */
0025 #define APDS9300_CLEAR  BIT(6) /* Interrupt clear. Clears pending interrupt */
0026 
0027 /* Register set */
0028 #define APDS9300_CONTROL    0x00 /* Control of basic functions */
0029 #define APDS9300_THRESHLOWLOW   0x02 /* Low byte of low interrupt threshold */
0030 #define APDS9300_THRESHHIGHLOW  0x04 /* Low byte of high interrupt threshold */
0031 #define APDS9300_INTERRUPT  0x06 /* Interrupt control */
0032 #define APDS9300_DATA0LOW   0x0c /* Low byte of ADC channel 0 */
0033 #define APDS9300_DATA1LOW   0x0e /* Low byte of ADC channel 1 */
0034 
0035 /* Power on/off value for APDS9300_CONTROL register */
0036 #define APDS9300_POWER_ON   0x03
0037 #define APDS9300_POWER_OFF  0x00
0038 
0039 /* Interrupts */
0040 #define APDS9300_INTR_ENABLE    0x10
0041 /* Interrupt Persist Function: Any value outside of threshold range */
0042 #define APDS9300_THRESH_INTR    0x01
0043 
0044 #define APDS9300_THRESH_MAX 0xffff /* Max threshold value */
0045 
0046 struct apds9300_data {
0047     struct i2c_client *client;
0048     struct mutex mutex;
0049     int power_state;
0050     int thresh_low;
0051     int thresh_hi;
0052     int intr_en;
0053 };
0054 
0055 /* Lux calculation */
0056 
0057 /* Calculated values 1000 * (CH1/CH0)^1.4 for CH1/CH0 from 0 to 0.52 */
0058 static const u16 apds9300_lux_ratio[] = {
0059     0, 2, 4, 7, 11, 15, 19, 24, 29, 34, 40, 45, 51, 57, 64, 70, 77, 84, 91,
0060     98, 105, 112, 120, 128, 136, 144, 152, 160, 168, 177, 185, 194, 203,
0061     212, 221, 230, 239, 249, 258, 268, 277, 287, 297, 307, 317, 327, 337,
0062     347, 358, 368, 379, 390, 400,
0063 };
0064 
0065 static unsigned long apds9300_calculate_lux(u16 ch0, u16 ch1)
0066 {
0067     unsigned long lux, tmp;
0068 
0069     /* avoid division by zero */
0070     if (ch0 == 0)
0071         return 0;
0072 
0073     tmp = DIV_ROUND_UP(ch1 * 100, ch0);
0074     if (tmp <= 52) {
0075         lux = 3150 * ch0 - (unsigned long)DIV_ROUND_UP_ULL(ch0
0076                 * apds9300_lux_ratio[tmp] * 5930ull, 1000);
0077     } else if (tmp <= 65) {
0078         lux = 2290 * ch0 - 2910 * ch1;
0079     } else if (tmp <= 80) {
0080         lux = 1570 * ch0 - 1800 * ch1;
0081     } else if (tmp <= 130) {
0082         lux = 338 * ch0 - 260 * ch1;
0083     } else {
0084         lux = 0;
0085     }
0086 
0087     return lux / 100000;
0088 }
0089 
0090 static int apds9300_get_adc_val(struct apds9300_data *data, int adc_number)
0091 {
0092     int ret;
0093     u8 flags = APDS9300_CMD | APDS9300_WORD;
0094 
0095     if (!data->power_state)
0096         return -EBUSY;
0097 
0098     /* Select ADC0 or ADC1 data register */
0099     flags |= adc_number ? APDS9300_DATA1LOW : APDS9300_DATA0LOW;
0100 
0101     ret = i2c_smbus_read_word_data(data->client, flags);
0102     if (ret < 0)
0103         dev_err(&data->client->dev,
0104             "failed to read ADC%d value\n", adc_number);
0105 
0106     return ret;
0107 }
0108 
0109 static int apds9300_set_thresh_low(struct apds9300_data *data, int value)
0110 {
0111     int ret;
0112 
0113     if (!data->power_state)
0114         return -EBUSY;
0115 
0116     if (value > APDS9300_THRESH_MAX)
0117         return -EINVAL;
0118 
0119     ret = i2c_smbus_write_word_data(data->client, APDS9300_THRESHLOWLOW
0120             | APDS9300_CMD | APDS9300_WORD, value);
0121     if (ret) {
0122         dev_err(&data->client->dev, "failed to set thresh_low\n");
0123         return ret;
0124     }
0125     data->thresh_low = value;
0126 
0127     return 0;
0128 }
0129 
0130 static int apds9300_set_thresh_hi(struct apds9300_data *data, int value)
0131 {
0132     int ret;
0133 
0134     if (!data->power_state)
0135         return -EBUSY;
0136 
0137     if (value > APDS9300_THRESH_MAX)
0138         return -EINVAL;
0139 
0140     ret = i2c_smbus_write_word_data(data->client, APDS9300_THRESHHIGHLOW
0141             | APDS9300_CMD | APDS9300_WORD, value);
0142     if (ret) {
0143         dev_err(&data->client->dev, "failed to set thresh_hi\n");
0144         return ret;
0145     }
0146     data->thresh_hi = value;
0147 
0148     return 0;
0149 }
0150 
0151 static int apds9300_set_intr_state(struct apds9300_data *data, int state)
0152 {
0153     int ret;
0154     u8 cmd;
0155 
0156     if (!data->power_state)
0157         return -EBUSY;
0158 
0159     cmd = state ? APDS9300_INTR_ENABLE | APDS9300_THRESH_INTR : 0x00;
0160     ret = i2c_smbus_write_byte_data(data->client,
0161             APDS9300_INTERRUPT | APDS9300_CMD, cmd);
0162     if (ret) {
0163         dev_err(&data->client->dev,
0164             "failed to set interrupt state %d\n", state);
0165         return ret;
0166     }
0167     data->intr_en = state;
0168 
0169     return 0;
0170 }
0171 
0172 static int apds9300_set_power_state(struct apds9300_data *data, int state)
0173 {
0174     int ret;
0175     u8 cmd;
0176 
0177     cmd = state ? APDS9300_POWER_ON : APDS9300_POWER_OFF;
0178     ret = i2c_smbus_write_byte_data(data->client,
0179             APDS9300_CONTROL | APDS9300_CMD, cmd);
0180     if (ret) {
0181         dev_err(&data->client->dev,
0182             "failed to set power state %d\n", state);
0183         return ret;
0184     }
0185     data->power_state = state;
0186 
0187     return 0;
0188 }
0189 
0190 static void apds9300_clear_intr(struct apds9300_data *data)
0191 {
0192     int ret;
0193 
0194     ret = i2c_smbus_write_byte(data->client, APDS9300_CLEAR | APDS9300_CMD);
0195     if (ret < 0)
0196         dev_err(&data->client->dev, "failed to clear interrupt\n");
0197 }
0198 
0199 static int apds9300_chip_init(struct apds9300_data *data)
0200 {
0201     int ret;
0202 
0203     /* Need to set power off to ensure that the chip is off */
0204     ret = apds9300_set_power_state(data, 0);
0205     if (ret < 0)
0206         goto err;
0207     /*
0208      * Probe the chip. To do so we try to power up the device and then to
0209      * read back the 0x03 code
0210      */
0211     ret = apds9300_set_power_state(data, 1);
0212     if (ret < 0)
0213         goto err;
0214     ret = i2c_smbus_read_byte_data(data->client,
0215             APDS9300_CONTROL | APDS9300_CMD);
0216     if (ret != APDS9300_POWER_ON) {
0217         ret = -ENODEV;
0218         goto err;
0219     }
0220     /*
0221      * Disable interrupt to ensure thai it is doesn't enable
0222      * i.e. after device soft reset
0223      */
0224     ret = apds9300_set_intr_state(data, 0);
0225     if (ret < 0)
0226         goto err;
0227 
0228     return 0;
0229 
0230 err:
0231     dev_err(&data->client->dev, "failed to init the chip\n");
0232     return ret;
0233 }
0234 
0235 static int apds9300_read_raw(struct iio_dev *indio_dev,
0236         struct iio_chan_spec const *chan, int *val, int *val2,
0237         long mask)
0238 {
0239     int ch0, ch1, ret = -EINVAL;
0240     struct apds9300_data *data = iio_priv(indio_dev);
0241 
0242     mutex_lock(&data->mutex);
0243     switch (chan->type) {
0244     case IIO_LIGHT:
0245         ch0 = apds9300_get_adc_val(data, 0);
0246         if (ch0 < 0) {
0247             ret = ch0;
0248             break;
0249         }
0250         ch1 = apds9300_get_adc_val(data, 1);
0251         if (ch1 < 0) {
0252             ret = ch1;
0253             break;
0254         }
0255         *val = apds9300_calculate_lux(ch0, ch1);
0256         ret = IIO_VAL_INT;
0257         break;
0258     case IIO_INTENSITY:
0259         ret = apds9300_get_adc_val(data, chan->channel);
0260         if (ret < 0)
0261             break;
0262         *val = ret;
0263         ret = IIO_VAL_INT;
0264         break;
0265     default:
0266         break;
0267     }
0268     mutex_unlock(&data->mutex);
0269 
0270     return ret;
0271 }
0272 
0273 static int apds9300_read_thresh(struct iio_dev *indio_dev,
0274         const struct iio_chan_spec *chan, enum iio_event_type type,
0275         enum iio_event_direction dir, enum iio_event_info info,
0276         int *val, int *val2)
0277 {
0278     struct apds9300_data *data = iio_priv(indio_dev);
0279 
0280     switch (dir) {
0281     case IIO_EV_DIR_RISING:
0282         *val = data->thresh_hi;
0283         break;
0284     case IIO_EV_DIR_FALLING:
0285         *val = data->thresh_low;
0286         break;
0287     default:
0288         return -EINVAL;
0289     }
0290 
0291     return IIO_VAL_INT;
0292 }
0293 
0294 static int apds9300_write_thresh(struct iio_dev *indio_dev,
0295         const struct iio_chan_spec *chan, enum iio_event_type type,
0296         enum iio_event_direction dir, enum iio_event_info info, int val,
0297         int val2)
0298 {
0299     struct apds9300_data *data = iio_priv(indio_dev);
0300     int ret;
0301 
0302     mutex_lock(&data->mutex);
0303     if (dir == IIO_EV_DIR_RISING)
0304         ret = apds9300_set_thresh_hi(data, val);
0305     else
0306         ret = apds9300_set_thresh_low(data, val);
0307     mutex_unlock(&data->mutex);
0308 
0309     return ret;
0310 }
0311 
0312 static int apds9300_read_interrupt_config(struct iio_dev *indio_dev,
0313         const struct iio_chan_spec *chan,
0314         enum iio_event_type type,
0315         enum iio_event_direction dir)
0316 {
0317     struct apds9300_data *data = iio_priv(indio_dev);
0318 
0319     return data->intr_en;
0320 }
0321 
0322 static int apds9300_write_interrupt_config(struct iio_dev *indio_dev,
0323         const struct iio_chan_spec *chan, enum iio_event_type type,
0324         enum iio_event_direction dir, int state)
0325 {
0326     struct apds9300_data *data = iio_priv(indio_dev);
0327     int ret;
0328 
0329     mutex_lock(&data->mutex);
0330     ret = apds9300_set_intr_state(data, state);
0331     mutex_unlock(&data->mutex);
0332 
0333     return ret;
0334 }
0335 
0336 static const struct iio_info apds9300_info_no_irq = {
0337     .read_raw   = apds9300_read_raw,
0338 };
0339 
0340 static const struct iio_info apds9300_info = {
0341     .read_raw       = apds9300_read_raw,
0342     .read_event_value   = apds9300_read_thresh,
0343     .write_event_value  = apds9300_write_thresh,
0344     .read_event_config  = apds9300_read_interrupt_config,
0345     .write_event_config = apds9300_write_interrupt_config,
0346 };
0347 
0348 static const struct iio_event_spec apds9300_event_spec[] = {
0349     {
0350         .type = IIO_EV_TYPE_THRESH,
0351         .dir = IIO_EV_DIR_RISING,
0352         .mask_separate = BIT(IIO_EV_INFO_VALUE) |
0353             BIT(IIO_EV_INFO_ENABLE),
0354     }, {
0355         .type = IIO_EV_TYPE_THRESH,
0356         .dir = IIO_EV_DIR_FALLING,
0357         .mask_separate = BIT(IIO_EV_INFO_VALUE) |
0358             BIT(IIO_EV_INFO_ENABLE),
0359     },
0360 };
0361 
0362 static const struct iio_chan_spec apds9300_channels[] = {
0363     {
0364         .type = IIO_LIGHT,
0365         .channel = 0,
0366         .indexed = true,
0367         .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
0368     }, {
0369         .type = IIO_INTENSITY,
0370         .channel = 0,
0371         .channel2 = IIO_MOD_LIGHT_BOTH,
0372         .indexed = true,
0373         .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
0374         .event_spec = apds9300_event_spec,
0375         .num_event_specs = ARRAY_SIZE(apds9300_event_spec),
0376     }, {
0377         .type = IIO_INTENSITY,
0378         .channel = 1,
0379         .channel2 = IIO_MOD_LIGHT_IR,
0380         .indexed = true,
0381         .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
0382     },
0383 };
0384 
0385 static irqreturn_t apds9300_interrupt_handler(int irq, void *private)
0386 {
0387     struct iio_dev *dev_info = private;
0388     struct apds9300_data *data = iio_priv(dev_info);
0389 
0390     iio_push_event(dev_info,
0391                IIO_UNMOD_EVENT_CODE(IIO_INTENSITY, 0,
0392                         IIO_EV_TYPE_THRESH,
0393                         IIO_EV_DIR_EITHER),
0394                iio_get_time_ns(dev_info));
0395 
0396     apds9300_clear_intr(data);
0397 
0398     return IRQ_HANDLED;
0399 }
0400 
0401 static int apds9300_probe(struct i2c_client *client,
0402         const struct i2c_device_id *id)
0403 {
0404     struct apds9300_data *data;
0405     struct iio_dev *indio_dev;
0406     int ret;
0407 
0408     indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
0409     if (!indio_dev)
0410         return -ENOMEM;
0411 
0412     data = iio_priv(indio_dev);
0413     i2c_set_clientdata(client, indio_dev);
0414     data->client = client;
0415 
0416     ret = apds9300_chip_init(data);
0417     if (ret < 0)
0418         goto err;
0419 
0420     mutex_init(&data->mutex);
0421 
0422     indio_dev->channels = apds9300_channels;
0423     indio_dev->num_channels = ARRAY_SIZE(apds9300_channels);
0424     indio_dev->name = APDS9300_DRV_NAME;
0425     indio_dev->modes = INDIO_DIRECT_MODE;
0426 
0427     if (client->irq)
0428         indio_dev->info = &apds9300_info;
0429     else
0430         indio_dev->info = &apds9300_info_no_irq;
0431 
0432     if (client->irq) {
0433         ret = devm_request_threaded_irq(&client->dev, client->irq,
0434                 NULL, apds9300_interrupt_handler,
0435                 IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
0436                 APDS9300_IRQ_NAME, indio_dev);
0437         if (ret) {
0438             dev_err(&client->dev, "irq request error %d\n", -ret);
0439             goto err;
0440         }
0441     }
0442 
0443     ret = iio_device_register(indio_dev);
0444     if (ret < 0)
0445         goto err;
0446 
0447     return 0;
0448 
0449 err:
0450     /* Ensure that power off in case of error */
0451     apds9300_set_power_state(data, 0);
0452     return ret;
0453 }
0454 
0455 static int apds9300_remove(struct i2c_client *client)
0456 {
0457     struct iio_dev *indio_dev = i2c_get_clientdata(client);
0458     struct apds9300_data *data = iio_priv(indio_dev);
0459 
0460     iio_device_unregister(indio_dev);
0461 
0462     /* Ensure that power off and interrupts are disabled */
0463     apds9300_set_intr_state(data, 0);
0464     apds9300_set_power_state(data, 0);
0465 
0466     return 0;
0467 }
0468 
0469 static int apds9300_suspend(struct device *dev)
0470 {
0471     struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
0472     struct apds9300_data *data = iio_priv(indio_dev);
0473     int ret;
0474 
0475     mutex_lock(&data->mutex);
0476     ret = apds9300_set_power_state(data, 0);
0477     mutex_unlock(&data->mutex);
0478 
0479     return ret;
0480 }
0481 
0482 static int apds9300_resume(struct device *dev)
0483 {
0484     struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
0485     struct apds9300_data *data = iio_priv(indio_dev);
0486     int ret;
0487 
0488     mutex_lock(&data->mutex);
0489     ret = apds9300_set_power_state(data, 1);
0490     mutex_unlock(&data->mutex);
0491 
0492     return ret;
0493 }
0494 
0495 static DEFINE_SIMPLE_DEV_PM_OPS(apds9300_pm_ops, apds9300_suspend,
0496                 apds9300_resume);
0497 
0498 static const struct i2c_device_id apds9300_id[] = {
0499     { APDS9300_DRV_NAME, 0 },
0500     { }
0501 };
0502 
0503 MODULE_DEVICE_TABLE(i2c, apds9300_id);
0504 
0505 static struct i2c_driver apds9300_driver = {
0506     .driver = {
0507         .name   = APDS9300_DRV_NAME,
0508         .pm = pm_sleep_ptr(&apds9300_pm_ops),
0509     },
0510     .probe      = apds9300_probe,
0511     .remove     = apds9300_remove,
0512     .id_table   = apds9300_id,
0513 };
0514 
0515 module_i2c_driver(apds9300_driver);
0516 
0517 MODULE_AUTHOR("Kravchenko Oleksandr <o.v.kravchenko@globallogic.com>");
0518 MODULE_AUTHOR("GlobalLogic inc.");
0519 MODULE_DESCRIPTION("APDS9300 ambient light photo sensor driver");
0520 MODULE_LICENSE("GPL");