root/drivers/iio/proximity/isl29501.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. isl29501_register_read
  2. isl29501_register_write
  3. isl29501_read_ext
  4. isl29501_set_shadow_coeff
  5. isl29501_write_coeff
  6. isl29501_find_corr_exp
  7. isl29501_write_ext
  8. isl29501_reset_registers
  9. isl29501_begin_acquisition
  10. isl29501_get_raw
  11. isl29501_get_scale
  12. isl29501_get_calibbias
  13. isl29501_get_inttime
  14. isl29501_get_freq
  15. isl29501_read_raw
  16. isl29501_set_raw
  17. isl29501_set_inttime
  18. isl29501_set_scale
  19. isl29501_set_calibbias
  20. isl29501_set_freq
  21. isl29501_write_raw
  22. isl29501_init_chip
  23. isl29501_trigger_handler
  24. isl29501_probe

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * isl29501.c: ISL29501 Time of Flight sensor driver.
   4  *
   5  * Copyright (C) 2018
   6  * Author: Mathieu Othacehe <m.othacehe@gmail.com>
   7  *
   8  * 7-bit I2C slave address: 0x57
   9  */
  10 
  11 #include <linux/kernel.h>
  12 #include <linux/module.h>
  13 #include <linux/i2c.h>
  14 #include <linux/err.h>
  15 #include <linux/of_device.h>
  16 #include <linux/iio/iio.h>
  17 #include <linux/iio/sysfs.h>
  18 
  19 #include <linux/iio/trigger_consumer.h>
  20 #include <linux/iio/buffer.h>
  21 #include <linux/iio/triggered_buffer.h>
  22 
  23 /* Control, setting and status registers */
  24 #define ISL29501_DEVICE_ID                      0x00
  25 #define ISL29501_ID                             0x0A
  26 
  27 /* Sampling control registers */
  28 #define ISL29501_INTEGRATION_PERIOD             0x10
  29 #define ISL29501_SAMPLE_PERIOD                  0x11
  30 
  31 /* Closed loop calibration registers */
  32 #define ISL29501_CROSSTALK_I_MSB                0x24
  33 #define ISL29501_CROSSTALK_I_LSB                0x25
  34 #define ISL29501_CROSSTALK_I_EXPONENT           0x26
  35 #define ISL29501_CROSSTALK_Q_MSB                0x27
  36 #define ISL29501_CROSSTALK_Q_LSB                0x28
  37 #define ISL29501_CROSSTALK_Q_EXPONENT           0x29
  38 #define ISL29501_CROSSTALK_GAIN_MSB             0x2A
  39 #define ISL29501_CROSSTALK_GAIN_LSB             0x2B
  40 #define ISL29501_MAGNITUDE_REF_EXP              0x2C
  41 #define ISL29501_MAGNITUDE_REF_MSB              0x2D
  42 #define ISL29501_MAGNITUDE_REF_LSB              0x2E
  43 #define ISL29501_PHASE_OFFSET_MSB               0x2F
  44 #define ISL29501_PHASE_OFFSET_LSB               0x30
  45 
  46 /* Analog control registers */
  47 #define ISL29501_DRIVER_RANGE                   0x90
  48 #define ISL29501_EMITTER_DAC                    0x91
  49 
  50 #define ISL29501_COMMAND_REGISTER               0xB0
  51 
  52 /* Commands */
  53 #define ISL29501_EMUL_SAMPLE_START_PIN          0x49
  54 #define ISL29501_RESET_ALL_REGISTERS            0xD7
  55 #define ISL29501_RESET_INT_SM                   0xD1
  56 
  57 /* Ambiant light and temperature corrections */
  58 #define ISL29501_TEMP_REFERENCE                 0x31
  59 #define ISL29501_PHASE_EXPONENT                 0x33
  60 #define ISL29501_TEMP_COEFF_A                   0x34
  61 #define ISL29501_TEMP_COEFF_B                   0x39
  62 #define ISL29501_AMBIANT_COEFF_A                0x36
  63 #define ISL29501_AMBIANT_COEFF_B                0x3B
  64 
  65 /* Data output registers */
  66 #define ISL29501_DISTANCE_MSB_DATA              0xD1
  67 #define ISL29501_DISTANCE_LSB_DATA              0xD2
  68 #define ISL29501_PRECISION_MSB                  0xD3
  69 #define ISL29501_PRECISION_LSB                  0xD4
  70 #define ISL29501_MAGNITUDE_EXPONENT             0xD5
  71 #define ISL29501_MAGNITUDE_MSB                  0xD6
  72 #define ISL29501_MAGNITUDE_LSB                  0xD7
  73 #define ISL29501_PHASE_MSB                      0xD8
  74 #define ISL29501_PHASE_LSB                      0xD9
  75 #define ISL29501_I_RAW_EXPONENT                 0xDA
  76 #define ISL29501_I_RAW_MSB                      0xDB
  77 #define ISL29501_I_RAW_LSB                      0xDC
  78 #define ISL29501_Q_RAW_EXPONENT                 0xDD
  79 #define ISL29501_Q_RAW_MSB                      0xDE
  80 #define ISL29501_Q_RAW_LSB                      0xDF
  81 #define ISL29501_DIE_TEMPERATURE                0xE2
  82 #define ISL29501_AMBIENT_LIGHT                  0xE3
  83 #define ISL29501_GAIN_MSB                       0xE6
  84 #define ISL29501_GAIN_LSB                       0xE7
  85 
  86 #define ISL29501_MAX_EXP_VAL 15
  87 
  88 #define ISL29501_INT_TIME_AVAILABLE \
  89         "0.00007 0.00014 0.00028 0.00057 0.00114 " \
  90         "0.00228 0.00455 0.00910 0.01820 0.03640 " \
  91         "0.07281 0.14561"
  92 
  93 #define ISL29501_CURRENT_SCALE_AVAILABLE \
  94         "0.0039 0.0078 0.0118 0.0157 0.0196 " \
  95         "0.0235 0.0275 0.0314 0.0352 0.0392 " \
  96         "0.0431 0.0471 0.0510 0.0549 0.0588"
  97 
  98 enum isl29501_correction_coeff {
  99         COEFF_TEMP_A,
 100         COEFF_TEMP_B,
 101         COEFF_LIGHT_A,
 102         COEFF_LIGHT_B,
 103         COEFF_MAX,
 104 };
 105 
 106 struct isl29501_private {
 107         struct i2c_client *client;
 108         struct mutex lock;
 109         /* Exact representation of correction coefficients. */
 110         unsigned int shadow_coeffs[COEFF_MAX];
 111 };
 112 
 113 enum isl29501_register_name {
 114         REG_DISTANCE,
 115         REG_PHASE,
 116         REG_TEMPERATURE,
 117         REG_AMBIENT_LIGHT,
 118         REG_GAIN,
 119         REG_GAIN_BIAS,
 120         REG_PHASE_EXP,
 121         REG_CALIB_PHASE_TEMP_A,
 122         REG_CALIB_PHASE_TEMP_B,
 123         REG_CALIB_PHASE_LIGHT_A,
 124         REG_CALIB_PHASE_LIGHT_B,
 125         REG_DISTANCE_BIAS,
 126         REG_TEMPERATURE_BIAS,
 127         REG_INT_TIME,
 128         REG_SAMPLE_TIME,
 129         REG_DRIVER_RANGE,
 130         REG_EMITTER_DAC,
 131 };
 132 
 133 struct isl29501_register_desc {
 134         u8 msb;
 135         u8 lsb;
 136 };
 137 
 138 static const struct isl29501_register_desc isl29501_registers[] = {
 139         [REG_DISTANCE] = {
 140                 .msb = ISL29501_DISTANCE_MSB_DATA,
 141                 .lsb = ISL29501_DISTANCE_LSB_DATA,
 142         },
 143         [REG_PHASE] = {
 144                 .msb = ISL29501_PHASE_MSB,
 145                 .lsb = ISL29501_PHASE_LSB,
 146         },
 147         [REG_TEMPERATURE] = {
 148                 .lsb = ISL29501_DIE_TEMPERATURE,
 149         },
 150         [REG_AMBIENT_LIGHT] = {
 151                 .lsb = ISL29501_AMBIENT_LIGHT,
 152         },
 153         [REG_GAIN] = {
 154                 .msb = ISL29501_GAIN_MSB,
 155                 .lsb = ISL29501_GAIN_LSB,
 156         },
 157         [REG_GAIN_BIAS] = {
 158                 .msb = ISL29501_CROSSTALK_GAIN_MSB,
 159                 .lsb = ISL29501_CROSSTALK_GAIN_LSB,
 160         },
 161         [REG_PHASE_EXP] = {
 162                 .lsb = ISL29501_PHASE_EXPONENT,
 163         },
 164         [REG_CALIB_PHASE_TEMP_A] = {
 165                 .lsb = ISL29501_TEMP_COEFF_A,
 166         },
 167         [REG_CALIB_PHASE_TEMP_B] = {
 168                 .lsb = ISL29501_TEMP_COEFF_B,
 169         },
 170         [REG_CALIB_PHASE_LIGHT_A] = {
 171                 .lsb = ISL29501_AMBIANT_COEFF_A,
 172         },
 173         [REG_CALIB_PHASE_LIGHT_B] = {
 174                 .lsb = ISL29501_AMBIANT_COEFF_B,
 175         },
 176         [REG_DISTANCE_BIAS] = {
 177                 .msb = ISL29501_PHASE_OFFSET_MSB,
 178                 .lsb = ISL29501_PHASE_OFFSET_LSB,
 179         },
 180         [REG_TEMPERATURE_BIAS] = {
 181                 .lsb = ISL29501_TEMP_REFERENCE,
 182         },
 183         [REG_INT_TIME] = {
 184                 .lsb = ISL29501_INTEGRATION_PERIOD,
 185         },
 186         [REG_SAMPLE_TIME] = {
 187                 .lsb = ISL29501_SAMPLE_PERIOD,
 188         },
 189         [REG_DRIVER_RANGE] = {
 190                 .lsb = ISL29501_DRIVER_RANGE,
 191         },
 192         [REG_EMITTER_DAC] = {
 193                 .lsb = ISL29501_EMITTER_DAC,
 194         },
 195 };
 196 
 197 static int isl29501_register_read(struct isl29501_private *isl29501,
 198                                   enum isl29501_register_name name,
 199                                   u32 *val)
 200 {
 201         const struct isl29501_register_desc *reg = &isl29501_registers[name];
 202         u8 msb = 0, lsb = 0;
 203         s32 ret;
 204 
 205         mutex_lock(&isl29501->lock);
 206         if (reg->msb) {
 207                 ret = i2c_smbus_read_byte_data(isl29501->client, reg->msb);
 208                 if (ret < 0)
 209                         goto err;
 210                 msb = ret;
 211         }
 212 
 213         if (reg->lsb) {
 214                 ret = i2c_smbus_read_byte_data(isl29501->client, reg->lsb);
 215                 if (ret < 0)
 216                         goto err;
 217                 lsb = ret;
 218         }
 219         mutex_unlock(&isl29501->lock);
 220 
 221         *val = (msb << 8) + lsb;
 222 
 223         return 0;
 224 err:
 225         mutex_unlock(&isl29501->lock);
 226 
 227         return ret;
 228 }
 229 
 230 static u32 isl29501_register_write(struct isl29501_private *isl29501,
 231                                    enum isl29501_register_name name,
 232                                    u32 value)
 233 {
 234         const struct isl29501_register_desc *reg = &isl29501_registers[name];
 235         int ret;
 236 
 237         if (!reg->msb && value > U8_MAX)
 238                 return -ERANGE;
 239 
 240         if (value > U16_MAX)
 241                 return -ERANGE;
 242 
 243         mutex_lock(&isl29501->lock);
 244         if (reg->msb) {
 245                 ret = i2c_smbus_write_byte_data(isl29501->client,
 246                                                 reg->msb, value >> 8);
 247                 if (ret < 0)
 248                         goto err;
 249         }
 250 
 251         ret = i2c_smbus_write_byte_data(isl29501->client, reg->lsb, value);
 252 
 253 err:
 254         mutex_unlock(&isl29501->lock);
 255         return ret;
 256 }
 257 
 258 static ssize_t isl29501_read_ext(struct iio_dev *indio_dev,
 259                                  uintptr_t private,
 260                                  const struct iio_chan_spec *chan,
 261                                  char *buf)
 262 {
 263         struct isl29501_private *isl29501 = iio_priv(indio_dev);
 264         enum isl29501_register_name reg = private;
 265         int ret;
 266         u32 value, gain, coeff, exp;
 267 
 268         switch (reg) {
 269         case REG_GAIN:
 270         case REG_GAIN_BIAS:
 271                 ret = isl29501_register_read(isl29501, reg, &gain);
 272                 if (ret < 0)
 273                         return ret;
 274 
 275                 value = gain;
 276                 break;
 277         case REG_CALIB_PHASE_TEMP_A:
 278         case REG_CALIB_PHASE_TEMP_B:
 279         case REG_CALIB_PHASE_LIGHT_A:
 280         case REG_CALIB_PHASE_LIGHT_B:
 281                 ret = isl29501_register_read(isl29501, REG_PHASE_EXP, &exp);
 282                 if (ret < 0)
 283                         return ret;
 284 
 285                 ret = isl29501_register_read(isl29501, reg, &coeff);
 286                 if (ret < 0)
 287                         return ret;
 288 
 289                 value = coeff << exp;
 290                 break;
 291         default:
 292                 return -EINVAL;
 293         }
 294 
 295         return sprintf(buf, "%u\n", value);
 296 }
 297 
 298 static int isl29501_set_shadow_coeff(struct isl29501_private *isl29501,
 299                                      enum isl29501_register_name reg,
 300                                      unsigned int val)
 301 {
 302         enum isl29501_correction_coeff coeff;
 303 
 304         switch (reg) {
 305         case REG_CALIB_PHASE_TEMP_A:
 306                 coeff = COEFF_TEMP_A;
 307                 break;
 308         case REG_CALIB_PHASE_TEMP_B:
 309                 coeff = COEFF_TEMP_B;
 310                 break;
 311         case REG_CALIB_PHASE_LIGHT_A:
 312                 coeff = COEFF_LIGHT_A;
 313                 break;
 314         case REG_CALIB_PHASE_LIGHT_B:
 315                 coeff = COEFF_LIGHT_B;
 316                 break;
 317         default:
 318                 return -EINVAL;
 319         }
 320         isl29501->shadow_coeffs[coeff] = val;
 321 
 322         return 0;
 323 }
 324 
 325 static int isl29501_write_coeff(struct isl29501_private *isl29501,
 326                                 enum isl29501_correction_coeff coeff,
 327                                 int val)
 328 {
 329         enum isl29501_register_name reg;
 330 
 331         switch (coeff) {
 332         case COEFF_TEMP_A:
 333                 reg = REG_CALIB_PHASE_TEMP_A;
 334                 break;
 335         case COEFF_TEMP_B:
 336                 reg = REG_CALIB_PHASE_TEMP_B;
 337                 break;
 338         case COEFF_LIGHT_A:
 339                 reg = REG_CALIB_PHASE_LIGHT_A;
 340                 break;
 341         case COEFF_LIGHT_B:
 342                 reg = REG_CALIB_PHASE_LIGHT_B;
 343                 break;
 344         default:
 345                 return -EINVAL;
 346         }
 347 
 348         return isl29501_register_write(isl29501, reg, val);
 349 }
 350 
 351 static unsigned int isl29501_find_corr_exp(unsigned int val,
 352                                            unsigned int max_exp,
 353                                            unsigned int max_mantissa)
 354 {
 355         unsigned int exp = 1;
 356 
 357         /*
 358          * Correction coefficients are represented under
 359          * mantissa * 2^exponent form, where mantissa and exponent
 360          * are stored in two separate registers of the sensor.
 361          *
 362          * Compute and return the lowest exponent such as:
 363          *           mantissa = value / 2^exponent
 364          *
 365          *  where mantissa < max_mantissa.
 366          */
 367         if (val <= max_mantissa)
 368                 return 0;
 369 
 370         while ((val >> exp) > max_mantissa) {
 371                 exp++;
 372 
 373                 if (exp > max_exp)
 374                         return max_exp;
 375         }
 376 
 377         return exp;
 378 }
 379 
 380 static ssize_t isl29501_write_ext(struct iio_dev *indio_dev,
 381                                   uintptr_t private,
 382                                   const struct iio_chan_spec *chan,
 383                                   const char *buf, size_t len)
 384 {
 385         struct isl29501_private *isl29501 = iio_priv(indio_dev);
 386         enum isl29501_register_name reg = private;
 387         unsigned int val;
 388         int max_exp = 0;
 389         int ret;
 390         int i;
 391 
 392         ret = kstrtouint(buf, 10, &val);
 393         if (ret)
 394                 return ret;
 395 
 396         switch (reg) {
 397         case REG_GAIN_BIAS:
 398                 if (val > U16_MAX)
 399                         return -ERANGE;
 400 
 401                 ret = isl29501_register_write(isl29501, reg, val);
 402                 if (ret < 0)
 403                         return ret;
 404 
 405                 break;
 406         case REG_CALIB_PHASE_TEMP_A:
 407         case REG_CALIB_PHASE_TEMP_B:
 408         case REG_CALIB_PHASE_LIGHT_A:
 409         case REG_CALIB_PHASE_LIGHT_B:
 410 
 411                 if (val > (U8_MAX << ISL29501_MAX_EXP_VAL))
 412                         return -ERANGE;
 413 
 414                 /* Store the correction coefficient under its exact form. */
 415                 ret = isl29501_set_shadow_coeff(isl29501, reg, val);
 416                 if (ret < 0)
 417                         return ret;
 418 
 419                 /*
 420                  * Find the highest exponent needed to represent
 421                  * correction coefficients.
 422                  */
 423                 for (i = 0; i < COEFF_MAX; i++) {
 424                         int corr;
 425                         int corr_exp;
 426 
 427                         corr = isl29501->shadow_coeffs[i];
 428                         corr_exp = isl29501_find_corr_exp(corr,
 429                                                           ISL29501_MAX_EXP_VAL,
 430                                                           U8_MAX / 2);
 431                         dev_dbg(&isl29501->client->dev,
 432                                 "found exp of corr(%d) = %d\n", corr, corr_exp);
 433 
 434                         max_exp = max(max_exp, corr_exp);
 435                 }
 436 
 437                 /*
 438                  * Represent every correction coefficient under
 439                  * mantissa * 2^max_exponent form and force the
 440                  * writing of those coefficients on the sensor.
 441                  */
 442                 for (i = 0; i < COEFF_MAX; i++) {
 443                         int corr;
 444                         int mantissa;
 445 
 446                         corr = isl29501->shadow_coeffs[i];
 447                         if (!corr)
 448                                 continue;
 449 
 450                         mantissa = corr >> max_exp;
 451 
 452                         ret = isl29501_write_coeff(isl29501, i, mantissa);
 453                         if (ret < 0)
 454                                 return ret;
 455                 }
 456 
 457                 ret = isl29501_register_write(isl29501, REG_PHASE_EXP, max_exp);
 458                 if (ret < 0)
 459                         return ret;
 460 
 461                 break;
 462         default:
 463                 return -EINVAL;
 464         }
 465 
 466         return len;
 467 }
 468 
 469 #define _ISL29501_EXT_INFO(_name, _ident) { \
 470         .name = _name, \
 471         .read = isl29501_read_ext, \
 472         .write = isl29501_write_ext, \
 473         .private = _ident, \
 474         .shared = IIO_SEPARATE, \
 475 }
 476 
 477 static const struct iio_chan_spec_ext_info isl29501_ext_info[] = {
 478         _ISL29501_EXT_INFO("agc_gain", REG_GAIN),
 479         _ISL29501_EXT_INFO("agc_gain_bias", REG_GAIN_BIAS),
 480         _ISL29501_EXT_INFO("calib_phase_temp_a", REG_CALIB_PHASE_TEMP_A),
 481         _ISL29501_EXT_INFO("calib_phase_temp_b", REG_CALIB_PHASE_TEMP_B),
 482         _ISL29501_EXT_INFO("calib_phase_light_a", REG_CALIB_PHASE_LIGHT_A),
 483         _ISL29501_EXT_INFO("calib_phase_light_b", REG_CALIB_PHASE_LIGHT_B),
 484         { },
 485 };
 486 
 487 #define ISL29501_DISTANCE_SCAN_INDEX 0
 488 #define ISL29501_TIMESTAMP_SCAN_INDEX 1
 489 
 490 static const struct iio_chan_spec isl29501_channels[] = {
 491         {
 492                 .type = IIO_PROXIMITY,
 493                 .scan_index = ISL29501_DISTANCE_SCAN_INDEX,
 494                 .info_mask_separate =
 495                         BIT(IIO_CHAN_INFO_RAW)   |
 496                         BIT(IIO_CHAN_INFO_SCALE) |
 497                         BIT(IIO_CHAN_INFO_CALIBBIAS),
 498                 .scan_type = {
 499                         .sign = 'u',
 500                         .realbits = 16,
 501                         .storagebits = 16,
 502                         .endianness = IIO_CPU,
 503                 },
 504                 .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME) |
 505                                 BIT(IIO_CHAN_INFO_SAMP_FREQ),
 506                 .ext_info = isl29501_ext_info,
 507         },
 508         {
 509                 .type = IIO_PHASE,
 510                 .scan_index = -1,
 511                 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
 512                                 BIT(IIO_CHAN_INFO_SCALE),
 513         },
 514         {
 515                 .type = IIO_CURRENT,
 516                 .scan_index = -1,
 517                 .output = 1,
 518                 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
 519                                 BIT(IIO_CHAN_INFO_SCALE),
 520         },
 521         {
 522                 .type = IIO_TEMP,
 523                 .scan_index = -1,
 524                 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
 525                                 BIT(IIO_CHAN_INFO_SCALE)     |
 526                                 BIT(IIO_CHAN_INFO_CALIBBIAS),
 527         },
 528         {
 529                 .type = IIO_INTENSITY,
 530                 .scan_index = -1,
 531                 .modified = 1,
 532                 .channel2 = IIO_MOD_LIGHT_CLEAR,
 533                 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
 534                                 BIT(IIO_CHAN_INFO_SCALE),
 535         },
 536         IIO_CHAN_SOFT_TIMESTAMP(ISL29501_TIMESTAMP_SCAN_INDEX),
 537 };
 538 
 539 static int isl29501_reset_registers(struct isl29501_private *isl29501)
 540 {
 541         int ret;
 542 
 543         ret = i2c_smbus_write_byte_data(isl29501->client,
 544                                         ISL29501_COMMAND_REGISTER,
 545                                         ISL29501_RESET_ALL_REGISTERS);
 546         if (ret < 0) {
 547                 dev_err(&isl29501->client->dev,
 548                         "cannot reset registers %d\n", ret);
 549                 return ret;
 550         }
 551 
 552         ret = i2c_smbus_write_byte_data(isl29501->client,
 553                                         ISL29501_COMMAND_REGISTER,
 554                                         ISL29501_RESET_INT_SM);
 555         if (ret < 0)
 556                 dev_err(&isl29501->client->dev,
 557                         "cannot reset state machine %d\n", ret);
 558 
 559         return ret;
 560 }
 561 
 562 static int isl29501_begin_acquisition(struct isl29501_private *isl29501)
 563 {
 564         int ret;
 565 
 566         ret = i2c_smbus_write_byte_data(isl29501->client,
 567                                         ISL29501_COMMAND_REGISTER,
 568                                         ISL29501_EMUL_SAMPLE_START_PIN);
 569         if (ret < 0)
 570                 dev_err(&isl29501->client->dev,
 571                         "cannot begin acquisition %d\n", ret);
 572 
 573         return ret;
 574 }
 575 
 576 static IIO_CONST_ATTR_INT_TIME_AVAIL(ISL29501_INT_TIME_AVAILABLE);
 577 static IIO_CONST_ATTR(out_current_scale_available,
 578                       ISL29501_CURRENT_SCALE_AVAILABLE);
 579 
 580 static struct attribute *isl29501_attributes[] = {
 581         &iio_const_attr_integration_time_available.dev_attr.attr,
 582         &iio_const_attr_out_current_scale_available.dev_attr.attr,
 583         NULL
 584 };
 585 
 586 static const struct attribute_group isl29501_attribute_group = {
 587         .attrs = isl29501_attributes,
 588 };
 589 
 590 static const int isl29501_current_scale_table[][2] = {
 591         {0, 3900}, {0, 7800}, {0, 11800}, {0, 15700},
 592         {0, 19600}, {0, 23500}, {0, 27500}, {0, 31400},
 593         {0, 35200}, {0, 39200}, {0, 43100}, {0, 47100},
 594         {0, 51000}, {0, 54900}, {0, 58800},
 595 };
 596 
 597 static const int isl29501_int_time[][2] = {
 598         {0, 70},    /* 0.07 ms */
 599         {0, 140},   /* 0.14 ms */
 600         {0, 280},   /* 0.28 ms */
 601         {0, 570},   /* 0.57 ms */
 602         {0, 1140},  /* 1.14 ms */
 603         {0, 2280},  /* 2.28 ms */
 604         {0, 4550},  /* 4.55 ms */
 605         {0, 9100},  /* 9.11 ms */
 606         {0, 18200}, /* 18.2 ms */
 607         {0, 36400}, /* 36.4 ms */
 608         {0, 72810}, /* 72.81 ms */
 609         {0, 145610} /* 145.28 ms */
 610 };
 611 
 612 static int isl29501_get_raw(struct isl29501_private *isl29501,
 613                             const struct iio_chan_spec *chan,
 614                             int *raw)
 615 {
 616         int ret;
 617 
 618         switch (chan->type) {
 619         case IIO_PROXIMITY:
 620                 ret = isl29501_register_read(isl29501, REG_DISTANCE, raw);
 621                 if (ret < 0)
 622                         return ret;
 623 
 624                 return IIO_VAL_INT;
 625         case IIO_INTENSITY:
 626                 ret = isl29501_register_read(isl29501,
 627                                              REG_AMBIENT_LIGHT,
 628                                              raw);
 629                 if (ret < 0)
 630                         return ret;
 631 
 632                 return IIO_VAL_INT;
 633         case IIO_PHASE:
 634                 ret = isl29501_register_read(isl29501, REG_PHASE, raw);
 635                 if (ret < 0)
 636                         return ret;
 637 
 638                 return IIO_VAL_INT;
 639         case IIO_CURRENT:
 640                 ret = isl29501_register_read(isl29501, REG_EMITTER_DAC, raw);
 641                 if (ret < 0)
 642                         return ret;
 643 
 644                 return IIO_VAL_INT;
 645         case IIO_TEMP:
 646                 ret = isl29501_register_read(isl29501, REG_TEMPERATURE, raw);
 647                 if (ret < 0)
 648                         return ret;
 649 
 650                 return IIO_VAL_INT;
 651         default:
 652                 return -EINVAL;
 653         }
 654 }
 655 
 656 static int isl29501_get_scale(struct isl29501_private *isl29501,
 657                               const struct iio_chan_spec *chan,
 658                               int *val, int *val2)
 659 {
 660         int ret;
 661         u32 current_scale;
 662 
 663         switch (chan->type) {
 664         case IIO_PROXIMITY:
 665                 /* distance = raw_distance * 33.31 / 65536 (m) */
 666                 *val = 3331;
 667                 *val2 = 6553600;
 668 
 669                 return IIO_VAL_FRACTIONAL;
 670         case IIO_PHASE:
 671                 /* phase = raw_phase * 2pi / 65536 (rad) */
 672                 *val = 0;
 673                 *val2 = 95874;
 674 
 675                 return IIO_VAL_INT_PLUS_NANO;
 676         case IIO_INTENSITY:
 677                 /* light = raw_light * 35 / 10000 (mA) */
 678                 *val = 35;
 679                 *val2 = 10000;
 680 
 681                 return IIO_VAL_FRACTIONAL;
 682         case IIO_CURRENT:
 683                 ret = isl29501_register_read(isl29501,
 684                                              REG_DRIVER_RANGE,
 685                                              &current_scale);
 686                 if (ret < 0)
 687                         return ret;
 688 
 689                 if (current_scale > ARRAY_SIZE(isl29501_current_scale_table))
 690                         return -EINVAL;
 691 
 692                 if (!current_scale) {
 693                         *val = 0;
 694                         *val2 = 0;
 695                         return IIO_VAL_INT;
 696                 }
 697 
 698                 *val = isl29501_current_scale_table[current_scale - 1][0];
 699                 *val2 = isl29501_current_scale_table[current_scale - 1][1];
 700 
 701                 return IIO_VAL_INT_PLUS_MICRO;
 702         case IIO_TEMP:
 703                 /* temperature = raw_temperature * 125 / 100000 (milli °C) */
 704                 *val = 125;
 705                 *val2 = 100000;
 706 
 707                 return IIO_VAL_FRACTIONAL;
 708         default:
 709                 return -EINVAL;
 710         }
 711 }
 712 
 713 static int isl29501_get_calibbias(struct isl29501_private *isl29501,
 714                                   const struct iio_chan_spec *chan,
 715                                   int *bias)
 716 {
 717         switch (chan->type) {
 718         case IIO_PROXIMITY:
 719                 return isl29501_register_read(isl29501,
 720                                               REG_DISTANCE_BIAS,
 721                                               bias);
 722         case IIO_TEMP:
 723                 return isl29501_register_read(isl29501,
 724                                               REG_TEMPERATURE_BIAS,
 725                                               bias);
 726         default:
 727                 return -EINVAL;
 728         }
 729 }
 730 
 731 static int isl29501_get_inttime(struct isl29501_private *isl29501,
 732                                 int *val, int *val2)
 733 {
 734         int ret;
 735         u32 inttime;
 736 
 737         ret = isl29501_register_read(isl29501, REG_INT_TIME, &inttime);
 738         if (ret < 0)
 739                 return ret;
 740 
 741         if (inttime >= ARRAY_SIZE(isl29501_int_time))
 742                 return -EINVAL;
 743 
 744         *val = isl29501_int_time[inttime][0];
 745         *val2 = isl29501_int_time[inttime][1];
 746 
 747         return IIO_VAL_INT_PLUS_MICRO;
 748 }
 749 
 750 static int isl29501_get_freq(struct isl29501_private *isl29501,
 751                              int *val, int *val2)
 752 {
 753         int ret;
 754         int sample_time;
 755         unsigned long long freq;
 756         u32 temp;
 757 
 758         ret = isl29501_register_read(isl29501, REG_SAMPLE_TIME, &sample_time);
 759         if (ret < 0)
 760                 return ret;
 761 
 762         /* freq = 1 / (0.000450 * (sample_time + 1) * 10^-6) */
 763         freq = 1000000ULL * 1000000ULL;
 764 
 765         do_div(freq, 450 * (sample_time + 1));
 766 
 767         temp = do_div(freq, 1000000);
 768         *val = freq;
 769         *val2 = temp;
 770 
 771         return IIO_VAL_INT_PLUS_MICRO;
 772 }
 773 
 774 static int isl29501_read_raw(struct iio_dev *indio_dev,
 775                              struct iio_chan_spec const *chan, int *val,
 776                              int *val2, long mask)
 777 {
 778         struct isl29501_private *isl29501 = iio_priv(indio_dev);
 779 
 780         switch (mask) {
 781         case IIO_CHAN_INFO_RAW:
 782                 return isl29501_get_raw(isl29501, chan, val);
 783         case IIO_CHAN_INFO_SCALE:
 784                 return isl29501_get_scale(isl29501, chan, val, val2);
 785         case IIO_CHAN_INFO_INT_TIME:
 786                 return isl29501_get_inttime(isl29501, val, val2);
 787         case IIO_CHAN_INFO_SAMP_FREQ:
 788                 return isl29501_get_freq(isl29501, val, val2);
 789         case IIO_CHAN_INFO_CALIBBIAS:
 790                 return isl29501_get_calibbias(isl29501, chan, val);
 791         default:
 792                 return -EINVAL;
 793         }
 794 }
 795 
 796 static int isl29501_set_raw(struct isl29501_private *isl29501,
 797                             const struct iio_chan_spec *chan,
 798                             int raw)
 799 {
 800         switch (chan->type) {
 801         case IIO_CURRENT:
 802                 return isl29501_register_write(isl29501, REG_EMITTER_DAC, raw);
 803         default:
 804                 return -EINVAL;
 805         }
 806 }
 807 
 808 static int isl29501_set_inttime(struct isl29501_private *isl29501,
 809                                 int val, int val2)
 810 {
 811         int i;
 812 
 813         for (i = 0; i < ARRAY_SIZE(isl29501_int_time); i++) {
 814                 if (isl29501_int_time[i][0] == val &&
 815                     isl29501_int_time[i][1] == val2) {
 816                         return isl29501_register_write(isl29501,
 817                                                        REG_INT_TIME,
 818                                                        i);
 819                 }
 820         }
 821 
 822         return -EINVAL;
 823 }
 824 
 825 static int isl29501_set_scale(struct isl29501_private *isl29501,
 826                               const struct iio_chan_spec *chan,
 827                               int val, int val2)
 828 {
 829         int i;
 830 
 831         if (chan->type != IIO_CURRENT)
 832                 return -EINVAL;
 833 
 834         for (i = 0; i < ARRAY_SIZE(isl29501_current_scale_table); i++) {
 835                 if (isl29501_current_scale_table[i][0] == val &&
 836                     isl29501_current_scale_table[i][1] == val2) {
 837                         return isl29501_register_write(isl29501,
 838                                                        REG_DRIVER_RANGE,
 839                                                        i + 1);
 840                 }
 841         }
 842 
 843         return -EINVAL;
 844 }
 845 
 846 static int isl29501_set_calibbias(struct isl29501_private *isl29501,
 847                                   const struct iio_chan_spec *chan,
 848                                   int bias)
 849 {
 850         switch (chan->type) {
 851         case IIO_PROXIMITY:
 852                 return isl29501_register_write(isl29501,
 853                                               REG_DISTANCE_BIAS,
 854                                               bias);
 855         case IIO_TEMP:
 856                 return isl29501_register_write(isl29501,
 857                                                REG_TEMPERATURE_BIAS,
 858                                                bias);
 859         default:
 860                 return -EINVAL;
 861         }
 862 }
 863 
 864 static int isl29501_set_freq(struct isl29501_private *isl29501,
 865                              int val, int val2)
 866 {
 867         int freq;
 868         unsigned long long sample_time;
 869 
 870         /* sample_freq = 1 / (0.000450 * (sample_time + 1) * 10^-6) */
 871         freq = val * 1000000 + val2 % 1000000;
 872         sample_time = 2222ULL * 1000000ULL;
 873         do_div(sample_time, freq);
 874 
 875         sample_time -= 1;
 876 
 877         if (sample_time > 255)
 878                 return -ERANGE;
 879 
 880         return isl29501_register_write(isl29501, REG_SAMPLE_TIME, sample_time);
 881 }
 882 
 883 static int isl29501_write_raw(struct iio_dev *indio_dev,
 884                               struct iio_chan_spec const *chan,
 885                               int val, int val2, long mask)
 886 {
 887         struct isl29501_private *isl29501 = iio_priv(indio_dev);
 888 
 889         switch (mask) {
 890         case IIO_CHAN_INFO_RAW:
 891                 return isl29501_set_raw(isl29501, chan, val);
 892         case IIO_CHAN_INFO_INT_TIME:
 893                 return isl29501_set_inttime(isl29501, val, val2);
 894         case IIO_CHAN_INFO_SAMP_FREQ:
 895                 return isl29501_set_freq(isl29501, val, val2);
 896         case IIO_CHAN_INFO_SCALE:
 897                 return isl29501_set_scale(isl29501, chan, val, val2);
 898         case IIO_CHAN_INFO_CALIBBIAS:
 899                 return isl29501_set_calibbias(isl29501, chan, val);
 900         default:
 901                 return -EINVAL;
 902         }
 903 }
 904 
 905 static const struct iio_info isl29501_info = {
 906         .read_raw = &isl29501_read_raw,
 907         .write_raw = &isl29501_write_raw,
 908         .attrs = &isl29501_attribute_group,
 909 };
 910 
 911 static int isl29501_init_chip(struct isl29501_private *isl29501)
 912 {
 913         int ret;
 914 
 915         ret = i2c_smbus_read_byte_data(isl29501->client, ISL29501_DEVICE_ID);
 916         if (ret < 0) {
 917                 dev_err(&isl29501->client->dev, "Error reading device id\n");
 918                 return ret;
 919         }
 920 
 921         if (ret != ISL29501_ID) {
 922                 dev_err(&isl29501->client->dev,
 923                         "Wrong chip id, got %x expected %x\n",
 924                         ret, ISL29501_DEVICE_ID);
 925                 return -ENODEV;
 926         }
 927 
 928         ret = isl29501_reset_registers(isl29501);
 929         if (ret < 0)
 930                 return ret;
 931 
 932         return isl29501_begin_acquisition(isl29501);
 933 }
 934 
 935 static irqreturn_t isl29501_trigger_handler(int irq, void *p)
 936 {
 937         struct iio_poll_func *pf = p;
 938         struct iio_dev *indio_dev = pf->indio_dev;
 939         struct isl29501_private *isl29501 = iio_priv(indio_dev);
 940         const unsigned long *active_mask = indio_dev->active_scan_mask;
 941         u32 buffer[4] = {}; /* 1x16-bit + ts */
 942 
 943         if (test_bit(ISL29501_DISTANCE_SCAN_INDEX, active_mask))
 944                 isl29501_register_read(isl29501, REG_DISTANCE, buffer);
 945 
 946         iio_push_to_buffers_with_timestamp(indio_dev, buffer, pf->timestamp);
 947         iio_trigger_notify_done(indio_dev->trig);
 948 
 949         return IRQ_HANDLED;
 950 }
 951 
 952 static int isl29501_probe(struct i2c_client *client,
 953                           const struct i2c_device_id *id)
 954 {
 955         struct iio_dev *indio_dev;
 956         struct isl29501_private *isl29501;
 957         int ret;
 958 
 959         indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*isl29501));
 960         if (!indio_dev)
 961                 return -ENOMEM;
 962 
 963         isl29501 = iio_priv(indio_dev);
 964 
 965         i2c_set_clientdata(client, indio_dev);
 966         isl29501->client = client;
 967 
 968         mutex_init(&isl29501->lock);
 969 
 970         ret = isl29501_init_chip(isl29501);
 971         if (ret < 0)
 972                 return ret;
 973 
 974         indio_dev->modes = INDIO_DIRECT_MODE;
 975         indio_dev->dev.parent = &client->dev;
 976         indio_dev->channels = isl29501_channels;
 977         indio_dev->num_channels = ARRAY_SIZE(isl29501_channels);
 978         indio_dev->name = client->name;
 979         indio_dev->info = &isl29501_info;
 980 
 981         ret = devm_iio_triggered_buffer_setup(&client->dev, indio_dev,
 982                                               iio_pollfunc_store_time,
 983                                               isl29501_trigger_handler,
 984                                               NULL);
 985         if (ret < 0) {
 986                 dev_err(&client->dev, "unable to setup iio triggered buffer\n");
 987                 return ret;
 988         }
 989 
 990         return devm_iio_device_register(&client->dev, indio_dev);
 991 }
 992 
 993 static const struct i2c_device_id isl29501_id[] = {
 994         {"isl29501", 0},
 995         {}
 996 };
 997 
 998 MODULE_DEVICE_TABLE(i2c, isl29501_id);
 999 
1000 #if defined(CONFIG_OF)
1001 static const struct of_device_id isl29501_i2c_matches[] = {
1002         { .compatible = "renesas,isl29501" },
1003         { }
1004 };
1005 MODULE_DEVICE_TABLE(of, isl29501_i2c_matches);
1006 #endif
1007 
1008 static struct i2c_driver isl29501_driver = {
1009         .driver = {
1010                 .name   = "isl29501",
1011         },
1012         .id_table       = isl29501_id,
1013         .probe          = isl29501_probe,
1014 };
1015 module_i2c_driver(isl29501_driver);
1016 
1017 MODULE_AUTHOR("Mathieu Othacehe <m.othacehe@gmail.com>");
1018 MODULE_DESCRIPTION("ISL29501 Time of Flight sensor driver");
1019 MODULE_LICENSE("GPL v2");

/* [<][>][^][v][top][bottom][index][help] */