max44009.c (13344B)
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * max44009.c - Support for MAX44009 Ambient Light Sensor 4 * 5 * Copyright (c) 2019 Robert Eshleman <bobbyeshleman@gmail.com> 6 * 7 * Datasheet: https://datasheets.maximintegrated.com/en/ds/MAX44009.pdf 8 * 9 * TODO: Support continuous mode and configuring from manual mode to 10 * automatic mode. 11 * 12 * Default I2C address: 0x4a 13 */ 14 15#include <linux/init.h> 16#include <linux/kernel.h> 17#include <linux/bits.h> 18#include <linux/i2c.h> 19#include <linux/iio/events.h> 20#include <linux/iio/iio.h> 21#include <linux/iio/sysfs.h> 22#include <linux/interrupt.h> 23#include <linux/module.h> 24#include <linux/util_macros.h> 25 26#define MAX44009_DRV_NAME "max44009" 27 28/* Registers in datasheet order */ 29#define MAX44009_REG_INT_STATUS 0x0 30#define MAX44009_REG_INT_EN 0x1 31#define MAX44009_REG_CFG 0x2 32#define MAX44009_REG_LUX_HI 0x3 33#define MAX44009_REG_LUX_LO 0x4 34#define MAX44009_REG_UPPER_THR 0x5 35#define MAX44009_REG_LOWER_THR 0x6 36#define MAX44009_REG_THR_TIMER 0x7 37 38#define MAX44009_CFG_TIM_MASK GENMASK(2, 0) 39#define MAX44009_CFG_MAN_MODE_MASK BIT(6) 40 41/* The maximum rising threshold for the max44009 */ 42#define MAX44009_MAXIMUM_THRESHOLD 7520256 43 44#define MAX44009_THRESH_EXP_MASK (0xf << 4) 45#define MAX44009_THRESH_EXP_RSHIFT 4 46#define MAX44009_THRESH_MANT_LSHIFT 4 47#define MAX44009_THRESH_MANT_MASK 0xf 48 49#define MAX44009_UPPER_THR_MINIMUM 15 50 51/* The max44009 always scales raw readings by 0.045 and is non-configurable */ 52#define MAX44009_SCALE_NUMERATOR 45 53#define MAX44009_SCALE_DENOMINATOR 1000 54 55/* The fixed-point fractional multiplier for de-scaling threshold values */ 56#define MAX44009_FRACT_MULT 1000000 57 58static const u32 max44009_int_time_ns_array[] = { 59 800000000, 60 400000000, 61 200000000, 62 100000000, 63 50000000, /* Manual mode only */ 64 25000000, /* Manual mode only */ 65 12500000, /* Manual mode only */ 66 6250000, /* Manual mode only */ 67}; 68 69static const char max44009_int_time_str[] = 70 "0.8 " 71 "0.4 " 72 "0.2 " 73 "0.1 " 74 "0.05 " 75 "0.025 " 76 "0.0125 " 77 "0.00625"; 78 79struct max44009_data { 80 struct i2c_client *client; 81 struct mutex lock; 82}; 83 84static const struct iio_event_spec max44009_event_spec[] = { 85 { 86 .type = IIO_EV_TYPE_THRESH, 87 .dir = IIO_EV_DIR_RISING, 88 .mask_separate = BIT(IIO_EV_INFO_VALUE) | 89 BIT(IIO_EV_INFO_ENABLE), 90 }, 91 { 92 .type = IIO_EV_TYPE_THRESH, 93 .dir = IIO_EV_DIR_FALLING, 94 .mask_separate = BIT(IIO_EV_INFO_VALUE) | 95 BIT(IIO_EV_INFO_ENABLE), 96 }, 97}; 98 99static const struct iio_chan_spec max44009_channels[] = { 100 { 101 .type = IIO_LIGHT, 102 .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) | 103 BIT(IIO_CHAN_INFO_INT_TIME), 104 .event_spec = max44009_event_spec, 105 .num_event_specs = ARRAY_SIZE(max44009_event_spec), 106 }, 107}; 108 109static int max44009_read_int_time(struct max44009_data *data) 110{ 111 112 int ret = i2c_smbus_read_byte_data(data->client, MAX44009_REG_CFG); 113 114 if (ret < 0) 115 return ret; 116 117 return max44009_int_time_ns_array[ret & MAX44009_CFG_TIM_MASK]; 118} 119 120static int max44009_write_int_time(struct max44009_data *data, 121 int val, int val2) 122{ 123 struct i2c_client *client = data->client; 124 int ret, int_time, config; 125 s64 ns; 126 127 ns = val * NSEC_PER_SEC + val2; 128 int_time = find_closest_descending( 129 ns, 130 max44009_int_time_ns_array, 131 ARRAY_SIZE(max44009_int_time_ns_array)); 132 133 ret = i2c_smbus_read_byte_data(client, MAX44009_REG_CFG); 134 if (ret < 0) 135 return ret; 136 137 config = ret; 138 config &= int_time; 139 140 /* 141 * To set the integration time, the device must also be in manual 142 * mode. 143 */ 144 config |= MAX44009_CFG_MAN_MODE_MASK; 145 146 return i2c_smbus_write_byte_data(client, MAX44009_REG_CFG, config); 147} 148 149static int max44009_write_raw(struct iio_dev *indio_dev, 150 struct iio_chan_spec const *chan, int val, 151 int val2, long mask) 152{ 153 struct max44009_data *data = iio_priv(indio_dev); 154 int ret; 155 156 if (mask == IIO_CHAN_INFO_INT_TIME && chan->type == IIO_LIGHT) { 157 mutex_lock(&data->lock); 158 ret = max44009_write_int_time(data, val, val2); 159 mutex_unlock(&data->lock); 160 return ret; 161 } 162 return -EINVAL; 163} 164 165static int max44009_write_raw_get_fmt(struct iio_dev *indio_dev, 166 struct iio_chan_spec const *chan, 167 long mask) 168{ 169 return IIO_VAL_INT_PLUS_NANO; 170} 171 172static int max44009_lux_raw(u8 hi, u8 lo) 173{ 174 int mantissa; 175 int exponent; 176 177 /* 178 * The mantissa consists of the low nibble of the Lux High Byte 179 * and the low nibble of the Lux Low Byte. 180 */ 181 mantissa = ((hi & 0xf) << 4) | (lo & 0xf); 182 183 /* The exponent byte is just the upper nibble of the Lux High Byte */ 184 exponent = (hi >> 4) & 0xf; 185 186 /* 187 * The exponent value is base 2 to the power of the raw exponent byte. 188 */ 189 exponent = 1 << exponent; 190 191 return exponent * mantissa; 192} 193 194#define MAX44009_READ_LUX_XFER_LEN (4) 195 196static int max44009_read_lux_raw(struct max44009_data *data) 197{ 198 int ret; 199 u8 hireg = MAX44009_REG_LUX_HI; 200 u8 loreg = MAX44009_REG_LUX_LO; 201 u8 lo = 0; 202 u8 hi = 0; 203 204 struct i2c_msg msgs[] = { 205 { 206 .addr = data->client->addr, 207 .flags = 0, 208 .len = sizeof(hireg), 209 .buf = &hireg, 210 }, 211 { 212 .addr = data->client->addr, 213 .flags = I2C_M_RD, 214 .len = sizeof(hi), 215 .buf = &hi, 216 }, 217 { 218 .addr = data->client->addr, 219 .flags = 0, 220 .len = sizeof(loreg), 221 .buf = &loreg, 222 }, 223 { 224 .addr = data->client->addr, 225 .flags = I2C_M_RD, 226 .len = sizeof(lo), 227 .buf = &lo, 228 } 229 }; 230 231 /* 232 * Use i2c_transfer instead of smbus read because i2c_transfer 233 * does NOT use a stop bit between address write and data read. 234 * Using a stop bit causes disjoint upper/lower byte reads and 235 * reduces accuracy. 236 */ 237 ret = i2c_transfer(data->client->adapter, 238 msgs, MAX44009_READ_LUX_XFER_LEN); 239 240 if (ret != MAX44009_READ_LUX_XFER_LEN) 241 return -EIO; 242 243 return max44009_lux_raw(hi, lo); 244} 245 246static int max44009_read_raw(struct iio_dev *indio_dev, 247 struct iio_chan_spec const *chan, int *val, 248 int *val2, long mask) 249{ 250 struct max44009_data *data = iio_priv(indio_dev); 251 int lux_raw; 252 int ret; 253 254 switch (mask) { 255 case IIO_CHAN_INFO_PROCESSED: 256 switch (chan->type) { 257 case IIO_LIGHT: 258 ret = max44009_read_lux_raw(data); 259 if (ret < 0) 260 return ret; 261 lux_raw = ret; 262 263 *val = lux_raw * MAX44009_SCALE_NUMERATOR; 264 *val2 = MAX44009_SCALE_DENOMINATOR; 265 return IIO_VAL_FRACTIONAL; 266 default: 267 return -EINVAL; 268 } 269 case IIO_CHAN_INFO_INT_TIME: 270 switch (chan->type) { 271 case IIO_LIGHT: 272 ret = max44009_read_int_time(data); 273 if (ret < 0) 274 return ret; 275 276 *val2 = ret; 277 *val = 0; 278 return IIO_VAL_INT_PLUS_NANO; 279 default: 280 return -EINVAL; 281 } 282 default: 283 return -EINVAL; 284 } 285} 286 287static IIO_CONST_ATTR(illuminance_integration_time_available, 288 max44009_int_time_str); 289 290static struct attribute *max44009_attributes[] = { 291 &iio_const_attr_illuminance_integration_time_available.dev_attr.attr, 292 NULL, 293}; 294 295static const struct attribute_group max44009_attribute_group = { 296 .attrs = max44009_attributes, 297}; 298 299static int max44009_threshold_byte_from_fraction(int integral, int fractional) 300{ 301 int mantissa, exp; 302 303 if ((integral <= 0 && fractional <= 0) || 304 integral > MAX44009_MAXIMUM_THRESHOLD || 305 (integral == MAX44009_MAXIMUM_THRESHOLD && fractional != 0)) 306 return -EINVAL; 307 308 /* Reverse scaling of fixed-point integral */ 309 mantissa = integral * MAX44009_SCALE_DENOMINATOR; 310 mantissa /= MAX44009_SCALE_NUMERATOR; 311 312 /* Reverse scaling of fixed-point fractional */ 313 mantissa += fractional / MAX44009_FRACT_MULT * 314 (MAX44009_SCALE_DENOMINATOR / MAX44009_SCALE_NUMERATOR); 315 316 for (exp = 0; mantissa > 0xff; exp++) 317 mantissa >>= 1; 318 319 mantissa >>= 4; 320 mantissa &= 0xf; 321 exp <<= 4; 322 323 return exp | mantissa; 324} 325 326static int max44009_get_thr_reg(enum iio_event_direction dir) 327{ 328 switch (dir) { 329 case IIO_EV_DIR_RISING: 330 return MAX44009_REG_UPPER_THR; 331 case IIO_EV_DIR_FALLING: 332 return MAX44009_REG_LOWER_THR; 333 default: 334 return -EINVAL; 335 } 336} 337 338static int max44009_write_event_value(struct iio_dev *indio_dev, 339 const struct iio_chan_spec *chan, 340 enum iio_event_type type, 341 enum iio_event_direction dir, 342 enum iio_event_info info, 343 int val, int val2) 344{ 345 struct max44009_data *data = iio_priv(indio_dev); 346 int reg, threshold; 347 348 if (info != IIO_EV_INFO_VALUE || chan->type != IIO_LIGHT) 349 return -EINVAL; 350 351 threshold = max44009_threshold_byte_from_fraction(val, val2); 352 if (threshold < 0) 353 return threshold; 354 355 reg = max44009_get_thr_reg(dir); 356 if (reg < 0) 357 return reg; 358 359 return i2c_smbus_write_byte_data(data->client, reg, threshold); 360} 361 362static int max44009_read_threshold(struct iio_dev *indio_dev, 363 enum iio_event_direction dir) 364{ 365 struct max44009_data *data = iio_priv(indio_dev); 366 int byte, reg; 367 int mantissa, exponent; 368 369 reg = max44009_get_thr_reg(dir); 370 if (reg < 0) 371 return reg; 372 373 byte = i2c_smbus_read_byte_data(data->client, reg); 374 if (byte < 0) 375 return byte; 376 377 mantissa = byte & MAX44009_THRESH_MANT_MASK; 378 mantissa <<= MAX44009_THRESH_MANT_LSHIFT; 379 380 /* 381 * To get the upper threshold, always adds the minimum upper threshold 382 * value to the shifted byte value (see datasheet). 383 */ 384 if (dir == IIO_EV_DIR_RISING) 385 mantissa += MAX44009_UPPER_THR_MINIMUM; 386 387 /* 388 * Exponent is base 2 to the power of the threshold exponent byte 389 * value 390 */ 391 exponent = byte & MAX44009_THRESH_EXP_MASK; 392 exponent >>= MAX44009_THRESH_EXP_RSHIFT; 393 394 return (1 << exponent) * mantissa; 395} 396 397static int max44009_read_event_value(struct iio_dev *indio_dev, 398 const struct iio_chan_spec *chan, 399 enum iio_event_type type, 400 enum iio_event_direction dir, 401 enum iio_event_info info, 402 int *val, int *val2) 403{ 404 int ret; 405 int threshold; 406 407 if (chan->type != IIO_LIGHT || type != IIO_EV_TYPE_THRESH) 408 return -EINVAL; 409 410 ret = max44009_read_threshold(indio_dev, dir); 411 if (ret < 0) 412 return ret; 413 threshold = ret; 414 415 *val = threshold * MAX44009_SCALE_NUMERATOR; 416 *val2 = MAX44009_SCALE_DENOMINATOR; 417 418 return IIO_VAL_FRACTIONAL; 419} 420 421static int max44009_write_event_config(struct iio_dev *indio_dev, 422 const struct iio_chan_spec *chan, 423 enum iio_event_type type, 424 enum iio_event_direction dir, 425 int state) 426{ 427 struct max44009_data *data = iio_priv(indio_dev); 428 int ret; 429 430 if (chan->type != IIO_LIGHT || type != IIO_EV_TYPE_THRESH) 431 return -EINVAL; 432 433 ret = i2c_smbus_write_byte_data(data->client, 434 MAX44009_REG_INT_EN, state); 435 if (ret < 0) 436 return ret; 437 438 /* 439 * Set device to trigger interrupt immediately upon exceeding 440 * the threshold limit. 441 */ 442 return i2c_smbus_write_byte_data(data->client, 443 MAX44009_REG_THR_TIMER, 0); 444} 445 446static int max44009_read_event_config(struct iio_dev *indio_dev, 447 const struct iio_chan_spec *chan, 448 enum iio_event_type type, 449 enum iio_event_direction dir) 450{ 451 struct max44009_data *data = iio_priv(indio_dev); 452 453 if (chan->type != IIO_LIGHT || type != IIO_EV_TYPE_THRESH) 454 return -EINVAL; 455 456 return i2c_smbus_read_byte_data(data->client, MAX44009_REG_INT_EN); 457} 458 459static const struct iio_info max44009_info = { 460 .read_raw = max44009_read_raw, 461 .write_raw = max44009_write_raw, 462 .write_raw_get_fmt = max44009_write_raw_get_fmt, 463 .read_event_value = max44009_read_event_value, 464 .read_event_config = max44009_read_event_config, 465 .write_event_value = max44009_write_event_value, 466 .write_event_config = max44009_write_event_config, 467 .attrs = &max44009_attribute_group, 468}; 469 470static irqreturn_t max44009_threaded_irq_handler(int irq, void *p) 471{ 472 struct iio_dev *indio_dev = p; 473 struct max44009_data *data = iio_priv(indio_dev); 474 int ret; 475 476 ret = i2c_smbus_read_byte_data(data->client, MAX44009_REG_INT_STATUS); 477 if (ret) { 478 iio_push_event(indio_dev, 479 IIO_UNMOD_EVENT_CODE(IIO_LIGHT, 0, 480 IIO_EV_TYPE_THRESH, 481 IIO_EV_DIR_EITHER), 482 iio_get_time_ns(indio_dev)); 483 484 return IRQ_HANDLED; 485 } 486 487 return IRQ_NONE; 488} 489 490static int max44009_probe(struct i2c_client *client, 491 const struct i2c_device_id *id) 492{ 493 struct max44009_data *data; 494 struct iio_dev *indio_dev; 495 int ret; 496 497 indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); 498 if (!indio_dev) 499 return -ENOMEM; 500 501 data = iio_priv(indio_dev); 502 i2c_set_clientdata(client, indio_dev); 503 data->client = client; 504 indio_dev->info = &max44009_info; 505 indio_dev->modes = INDIO_DIRECT_MODE; 506 indio_dev->name = MAX44009_DRV_NAME; 507 indio_dev->channels = max44009_channels; 508 indio_dev->num_channels = ARRAY_SIZE(max44009_channels); 509 mutex_init(&data->lock); 510 511 /* Clear any stale interrupt bit */ 512 ret = i2c_smbus_read_byte_data(client, MAX44009_REG_CFG); 513 if (ret < 0) 514 return ret; 515 516 if (client->irq > 0) { 517 ret = devm_request_threaded_irq(&client->dev, client->irq, 518 NULL, 519 max44009_threaded_irq_handler, 520 IRQF_TRIGGER_FALLING | 521 IRQF_ONESHOT | IRQF_SHARED, 522 "max44009_event", 523 indio_dev); 524 if (ret < 0) 525 return ret; 526 } 527 528 return devm_iio_device_register(&client->dev, indio_dev); 529} 530 531static const struct i2c_device_id max44009_id[] = { 532 { "max44009", 0 }, 533 { } 534}; 535MODULE_DEVICE_TABLE(i2c, max44009_id); 536 537static struct i2c_driver max44009_driver = { 538 .driver = { 539 .name = MAX44009_DRV_NAME, 540 }, 541 .probe = max44009_probe, 542 .id_table = max44009_id, 543}; 544module_i2c_driver(max44009_driver); 545 546static const struct of_device_id max44009_of_match[] = { 547 { .compatible = "maxim,max44009" }, 548 { } 549}; 550MODULE_DEVICE_TABLE(of, max44009_of_match); 551 552MODULE_AUTHOR("Robert Eshleman <bobbyeshleman@gmail.com>"); 553MODULE_LICENSE("GPL v2"); 554MODULE_DESCRIPTION("MAX44009 ambient light sensor driver");