518 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * apds9300.c - IIO driver for Avago APDS9300 ambient light sensor4 *5 * Copyright 2013 Oleksandr Kravchenko <o.v.kravchenko@globallogic.com>6 */7 8#include <linux/module.h>9#include <linux/slab.h>10#include <linux/pm.h>11#include <linux/i2c.h>12#include <linux/err.h>13#include <linux/mutex.h>14#include <linux/interrupt.h>15#include <linux/iio/iio.h>16#include <linux/iio/sysfs.h>17#include <linux/iio/events.h>18 19#define APDS9300_DRV_NAME "apds9300"20#define APDS9300_IRQ_NAME "apds9300_event"21 22/* Command register bits */23#define APDS9300_CMD BIT(7) /* Select command register. Must write as 1 */24#define APDS9300_WORD BIT(5) /* I2C write/read: if 1 word, if 0 byte */25#define APDS9300_CLEAR BIT(6) /* Interrupt clear. Clears pending interrupt */26 27/* Register set */28#define APDS9300_CONTROL 0x00 /* Control of basic functions */29#define APDS9300_THRESHLOWLOW 0x02 /* Low byte of low interrupt threshold */30#define APDS9300_THRESHHIGHLOW 0x04 /* Low byte of high interrupt threshold */31#define APDS9300_INTERRUPT 0x06 /* Interrupt control */32#define APDS9300_DATA0LOW 0x0c /* Low byte of ADC channel 0 */33#define APDS9300_DATA1LOW 0x0e /* Low byte of ADC channel 1 */34 35/* Power on/off value for APDS9300_CONTROL register */36#define APDS9300_POWER_ON 0x0337#define APDS9300_POWER_OFF 0x0038 39/* Interrupts */40#define APDS9300_INTR_ENABLE 0x1041/* Interrupt Persist Function: Any value outside of threshold range */42#define APDS9300_THRESH_INTR 0x0143 44#define APDS9300_THRESH_MAX 0xffff /* Max threshold value */45 46struct apds9300_data {47 struct i2c_client *client;48 struct mutex mutex;49 int power_state;50 int thresh_low;51 int thresh_hi;52 int intr_en;53};54 55/* Lux calculation */56 57/* Calculated values 1000 * (CH1/CH0)^1.4 for CH1/CH0 from 0 to 0.52 */58static const u16 apds9300_lux_ratio[] = {59 0, 2, 4, 7, 11, 15, 19, 24, 29, 34, 40, 45, 51, 57, 64, 70, 77, 84, 91,60 98, 105, 112, 120, 128, 136, 144, 152, 160, 168, 177, 185, 194, 203,61 212, 221, 230, 239, 249, 258, 268, 277, 287, 297, 307, 317, 327, 337,62 347, 358, 368, 379, 390, 400,63};64 65static unsigned long apds9300_calculate_lux(u16 ch0, u16 ch1)66{67 unsigned long lux, tmp;68 69 /* avoid division by zero */70 if (ch0 == 0)71 return 0;72 73 tmp = DIV_ROUND_UP(ch1 * 100, ch0);74 if (tmp <= 52) {75 lux = 3150 * ch0 - (unsigned long)DIV_ROUND_UP_ULL(ch076 * apds9300_lux_ratio[tmp] * 5930ull, 1000);77 } else if (tmp <= 65) {78 lux = 2290 * ch0 - 2910 * ch1;79 } else if (tmp <= 80) {80 lux = 1570 * ch0 - 1800 * ch1;81 } else if (tmp <= 130) {82 lux = 338 * ch0 - 260 * ch1;83 } else {84 lux = 0;85 }86 87 return lux / 100000;88}89 90static int apds9300_get_adc_val(struct apds9300_data *data, int adc_number)91{92 int ret;93 u8 flags = APDS9300_CMD | APDS9300_WORD;94 95 if (!data->power_state)96 return -EBUSY;97 98 /* Select ADC0 or ADC1 data register */99 flags |= adc_number ? APDS9300_DATA1LOW : APDS9300_DATA0LOW;100 101 ret = i2c_smbus_read_word_data(data->client, flags);102 if (ret < 0)103 dev_err(&data->client->dev,104 "failed to read ADC%d value\n", adc_number);105 106 return ret;107}108 109static int apds9300_set_thresh_low(struct apds9300_data *data, int value)110{111 int ret;112 113 if (!data->power_state)114 return -EBUSY;115 116 if (value > APDS9300_THRESH_MAX)117 return -EINVAL;118 119 ret = i2c_smbus_write_word_data(data->client, APDS9300_THRESHLOWLOW120 | APDS9300_CMD | APDS9300_WORD, value);121 if (ret) {122 dev_err(&data->client->dev, "failed to set thresh_low\n");123 return ret;124 }125 data->thresh_low = value;126 127 return 0;128}129 130static int apds9300_set_thresh_hi(struct apds9300_data *data, int value)131{132 int ret;133 134 if (!data->power_state)135 return -EBUSY;136 137 if (value > APDS9300_THRESH_MAX)138 return -EINVAL;139 140 ret = i2c_smbus_write_word_data(data->client, APDS9300_THRESHHIGHLOW141 | APDS9300_CMD | APDS9300_WORD, value);142 if (ret) {143 dev_err(&data->client->dev, "failed to set thresh_hi\n");144 return ret;145 }146 data->thresh_hi = value;147 148 return 0;149}150 151static int apds9300_set_intr_state(struct apds9300_data *data, int state)152{153 int ret;154 u8 cmd;155 156 if (!data->power_state)157 return -EBUSY;158 159 cmd = state ? APDS9300_INTR_ENABLE | APDS9300_THRESH_INTR : 0x00;160 ret = i2c_smbus_write_byte_data(data->client,161 APDS9300_INTERRUPT | APDS9300_CMD, cmd);162 if (ret) {163 dev_err(&data->client->dev,164 "failed to set interrupt state %d\n", state);165 return ret;166 }167 data->intr_en = state;168 169 return 0;170}171 172static int apds9300_set_power_state(struct apds9300_data *data, int state)173{174 int ret;175 u8 cmd;176 177 cmd = state ? APDS9300_POWER_ON : APDS9300_POWER_OFF;178 ret = i2c_smbus_write_byte_data(data->client,179 APDS9300_CONTROL | APDS9300_CMD, cmd);180 if (ret) {181 dev_err(&data->client->dev,182 "failed to set power state %d\n", state);183 return ret;184 }185 data->power_state = state;186 187 return 0;188}189 190static void apds9300_clear_intr(struct apds9300_data *data)191{192 int ret;193 194 ret = i2c_smbus_write_byte(data->client, APDS9300_CLEAR | APDS9300_CMD);195 if (ret < 0)196 dev_err(&data->client->dev, "failed to clear interrupt\n");197}198 199static int apds9300_chip_init(struct apds9300_data *data)200{201 int ret;202 203 /* Need to set power off to ensure that the chip is off */204 ret = apds9300_set_power_state(data, 0);205 if (ret < 0)206 goto err;207 /*208 * Probe the chip. To do so we try to power up the device and then to209 * read back the 0x03 code210 */211 ret = apds9300_set_power_state(data, 1);212 if (ret < 0)213 goto err;214 ret = i2c_smbus_read_byte_data(data->client,215 APDS9300_CONTROL | APDS9300_CMD);216 if (ret != APDS9300_POWER_ON) {217 ret = -ENODEV;218 goto err;219 }220 /*221 * Disable interrupt to ensure thai it is doesn't enable222 * i.e. after device soft reset223 */224 ret = apds9300_set_intr_state(data, 0);225 if (ret < 0)226 goto err;227 228 return 0;229 230err:231 dev_err(&data->client->dev, "failed to init the chip\n");232 return ret;233}234 235static int apds9300_read_raw(struct iio_dev *indio_dev,236 struct iio_chan_spec const *chan, int *val, int *val2,237 long mask)238{239 int ch0, ch1, ret = -EINVAL;240 struct apds9300_data *data = iio_priv(indio_dev);241 242 mutex_lock(&data->mutex);243 switch (chan->type) {244 case IIO_LIGHT:245 ch0 = apds9300_get_adc_val(data, 0);246 if (ch0 < 0) {247 ret = ch0;248 break;249 }250 ch1 = apds9300_get_adc_val(data, 1);251 if (ch1 < 0) {252 ret = ch1;253 break;254 }255 *val = apds9300_calculate_lux(ch0, ch1);256 ret = IIO_VAL_INT;257 break;258 case IIO_INTENSITY:259 ret = apds9300_get_adc_val(data, chan->channel);260 if (ret < 0)261 break;262 *val = ret;263 ret = IIO_VAL_INT;264 break;265 default:266 break;267 }268 mutex_unlock(&data->mutex);269 270 return ret;271}272 273static int apds9300_read_thresh(struct iio_dev *indio_dev,274 const struct iio_chan_spec *chan, enum iio_event_type type,275 enum iio_event_direction dir, enum iio_event_info info,276 int *val, int *val2)277{278 struct apds9300_data *data = iio_priv(indio_dev);279 280 switch (dir) {281 case IIO_EV_DIR_RISING:282 *val = data->thresh_hi;283 break;284 case IIO_EV_DIR_FALLING:285 *val = data->thresh_low;286 break;287 default:288 return -EINVAL;289 }290 291 return IIO_VAL_INT;292}293 294static int apds9300_write_thresh(struct iio_dev *indio_dev,295 const struct iio_chan_spec *chan, enum iio_event_type type,296 enum iio_event_direction dir, enum iio_event_info info, int val,297 int val2)298{299 struct apds9300_data *data = iio_priv(indio_dev);300 int ret;301 302 mutex_lock(&data->mutex);303 if (dir == IIO_EV_DIR_RISING)304 ret = apds9300_set_thresh_hi(data, val);305 else306 ret = apds9300_set_thresh_low(data, val);307 mutex_unlock(&data->mutex);308 309 return ret;310}311 312static int apds9300_read_interrupt_config(struct iio_dev *indio_dev,313 const struct iio_chan_spec *chan,314 enum iio_event_type type,315 enum iio_event_direction dir)316{317 struct apds9300_data *data = iio_priv(indio_dev);318 319 return data->intr_en;320}321 322static int apds9300_write_interrupt_config(struct iio_dev *indio_dev,323 const struct iio_chan_spec *chan, enum iio_event_type type,324 enum iio_event_direction dir, int state)325{326 struct apds9300_data *data = iio_priv(indio_dev);327 int ret;328 329 mutex_lock(&data->mutex);330 ret = apds9300_set_intr_state(data, state);331 mutex_unlock(&data->mutex);332 333 return ret;334}335 336static const struct iio_info apds9300_info_no_irq = {337 .read_raw = apds9300_read_raw,338};339 340static const struct iio_info apds9300_info = {341 .read_raw = apds9300_read_raw,342 .read_event_value = apds9300_read_thresh,343 .write_event_value = apds9300_write_thresh,344 .read_event_config = apds9300_read_interrupt_config,345 .write_event_config = apds9300_write_interrupt_config,346};347 348static const struct iio_event_spec apds9300_event_spec[] = {349 {350 .type = IIO_EV_TYPE_THRESH,351 .dir = IIO_EV_DIR_RISING,352 .mask_separate = BIT(IIO_EV_INFO_VALUE) |353 BIT(IIO_EV_INFO_ENABLE),354 }, {355 .type = IIO_EV_TYPE_THRESH,356 .dir = IIO_EV_DIR_FALLING,357 .mask_separate = BIT(IIO_EV_INFO_VALUE) |358 BIT(IIO_EV_INFO_ENABLE),359 },360};361 362static const struct iio_chan_spec apds9300_channels[] = {363 {364 .type = IIO_LIGHT,365 .channel = 0,366 .indexed = true,367 .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),368 }, {369 .type = IIO_INTENSITY,370 .channel = 0,371 .channel2 = IIO_MOD_LIGHT_BOTH,372 .indexed = true,373 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),374 .event_spec = apds9300_event_spec,375 .num_event_specs = ARRAY_SIZE(apds9300_event_spec),376 }, {377 .type = IIO_INTENSITY,378 .channel = 1,379 .channel2 = IIO_MOD_LIGHT_IR,380 .indexed = true,381 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),382 },383};384 385static irqreturn_t apds9300_interrupt_handler(int irq, void *private)386{387 struct iio_dev *dev_info = private;388 struct apds9300_data *data = iio_priv(dev_info);389 390 iio_push_event(dev_info,391 IIO_UNMOD_EVENT_CODE(IIO_INTENSITY, 0,392 IIO_EV_TYPE_THRESH,393 IIO_EV_DIR_EITHER),394 iio_get_time_ns(dev_info));395 396 apds9300_clear_intr(data);397 398 return IRQ_HANDLED;399}400 401static int apds9300_probe(struct i2c_client *client)402{403 struct apds9300_data *data;404 struct iio_dev *indio_dev;405 int ret;406 407 indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));408 if (!indio_dev)409 return -ENOMEM;410 411 data = iio_priv(indio_dev);412 i2c_set_clientdata(client, indio_dev);413 data->client = client;414 415 ret = apds9300_chip_init(data);416 if (ret < 0)417 goto err;418 419 mutex_init(&data->mutex);420 421 indio_dev->channels = apds9300_channels;422 indio_dev->num_channels = ARRAY_SIZE(apds9300_channels);423 indio_dev->name = APDS9300_DRV_NAME;424 indio_dev->modes = INDIO_DIRECT_MODE;425 426 if (client->irq)427 indio_dev->info = &apds9300_info;428 else429 indio_dev->info = &apds9300_info_no_irq;430 431 if (client->irq) {432 ret = devm_request_threaded_irq(&client->dev, client->irq,433 NULL, apds9300_interrupt_handler,434 IRQF_TRIGGER_FALLING | IRQF_ONESHOT,435 APDS9300_IRQ_NAME, indio_dev);436 if (ret) {437 dev_err(&client->dev, "irq request error %d\n", -ret);438 goto err;439 }440 }441 442 ret = iio_device_register(indio_dev);443 if (ret < 0)444 goto err;445 446 return 0;447 448err:449 /* Ensure that power off in case of error */450 apds9300_set_power_state(data, 0);451 return ret;452}453 454static void apds9300_remove(struct i2c_client *client)455{456 struct iio_dev *indio_dev = i2c_get_clientdata(client);457 struct apds9300_data *data = iio_priv(indio_dev);458 459 iio_device_unregister(indio_dev);460 461 /* Ensure that power off and interrupts are disabled */462 apds9300_set_intr_state(data, 0);463 apds9300_set_power_state(data, 0);464}465 466static int apds9300_suspend(struct device *dev)467{468 struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));469 struct apds9300_data *data = iio_priv(indio_dev);470 int ret;471 472 mutex_lock(&data->mutex);473 ret = apds9300_set_power_state(data, 0);474 mutex_unlock(&data->mutex);475 476 return ret;477}478 479static int apds9300_resume(struct device *dev)480{481 struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));482 struct apds9300_data *data = iio_priv(indio_dev);483 int ret;484 485 mutex_lock(&data->mutex);486 ret = apds9300_set_power_state(data, 1);487 mutex_unlock(&data->mutex);488 489 return ret;490}491 492static DEFINE_SIMPLE_DEV_PM_OPS(apds9300_pm_ops, apds9300_suspend,493 apds9300_resume);494 495static const struct i2c_device_id apds9300_id[] = {496 { APDS9300_DRV_NAME },497 { }498};499 500MODULE_DEVICE_TABLE(i2c, apds9300_id);501 502static struct i2c_driver apds9300_driver = {503 .driver = {504 .name = APDS9300_DRV_NAME,505 .pm = pm_sleep_ptr(&apds9300_pm_ops),506 },507 .probe = apds9300_probe,508 .remove = apds9300_remove,509 .id_table = apds9300_id,510};511 512module_i2c_driver(apds9300_driver);513 514MODULE_AUTHOR("Kravchenko Oleksandr <o.v.kravchenko@globallogic.com>");515MODULE_AUTHOR("GlobalLogic inc.");516MODULE_DESCRIPTION("APDS9300 ambient light photo sensor driver");517MODULE_LICENSE("GPL");518