Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * isl29501.c: ISL29501 Time of Flight sensor driver.
0004  *
0005  * Copyright (C) 2018
0006  * Author: Mathieu Othacehe <m.othacehe@gmail.com>
0007  *
0008  * 7-bit I2C slave address: 0x57
0009  */
0010 
0011 #include <linux/kernel.h>
0012 #include <linux/module.h>
0013 #include <linux/i2c.h>
0014 #include <linux/err.h>
0015 #include <linux/of_device.h>
0016 #include <linux/iio/iio.h>
0017 #include <linux/iio/sysfs.h>
0018 
0019 #include <linux/iio/trigger_consumer.h>
0020 #include <linux/iio/buffer.h>
0021 #include <linux/iio/triggered_buffer.h>
0022 
0023 /* Control, setting and status registers */
0024 #define ISL29501_DEVICE_ID          0x00
0025 #define ISL29501_ID             0x0A
0026 
0027 /* Sampling control registers */
0028 #define ISL29501_INTEGRATION_PERIOD     0x10
0029 #define ISL29501_SAMPLE_PERIOD          0x11
0030 
0031 /* Closed loop calibration registers */
0032 #define ISL29501_CROSSTALK_I_MSB        0x24
0033 #define ISL29501_CROSSTALK_I_LSB        0x25
0034 #define ISL29501_CROSSTALK_I_EXPONENT       0x26
0035 #define ISL29501_CROSSTALK_Q_MSB        0x27
0036 #define ISL29501_CROSSTALK_Q_LSB        0x28
0037 #define ISL29501_CROSSTALK_Q_EXPONENT       0x29
0038 #define ISL29501_CROSSTALK_GAIN_MSB     0x2A
0039 #define ISL29501_CROSSTALK_GAIN_LSB     0x2B
0040 #define ISL29501_MAGNITUDE_REF_EXP      0x2C
0041 #define ISL29501_MAGNITUDE_REF_MSB      0x2D
0042 #define ISL29501_MAGNITUDE_REF_LSB      0x2E
0043 #define ISL29501_PHASE_OFFSET_MSB       0x2F
0044 #define ISL29501_PHASE_OFFSET_LSB       0x30
0045 
0046 /* Analog control registers */
0047 #define ISL29501_DRIVER_RANGE           0x90
0048 #define ISL29501_EMITTER_DAC            0x91
0049 
0050 #define ISL29501_COMMAND_REGISTER       0xB0
0051 
0052 /* Commands */
0053 #define ISL29501_EMUL_SAMPLE_START_PIN      0x49
0054 #define ISL29501_RESET_ALL_REGISTERS        0xD7
0055 #define ISL29501_RESET_INT_SM           0xD1
0056 
0057 /* Ambiant light and temperature corrections */
0058 #define ISL29501_TEMP_REFERENCE         0x31
0059 #define ISL29501_PHASE_EXPONENT         0x33
0060 #define ISL29501_TEMP_COEFF_A           0x34
0061 #define ISL29501_TEMP_COEFF_B           0x39
0062 #define ISL29501_AMBIANT_COEFF_A        0x36
0063 #define ISL29501_AMBIANT_COEFF_B        0x3B
0064 
0065 /* Data output registers */
0066 #define ISL29501_DISTANCE_MSB_DATA      0xD1
0067 #define ISL29501_DISTANCE_LSB_DATA      0xD2
0068 #define ISL29501_PRECISION_MSB          0xD3
0069 #define ISL29501_PRECISION_LSB          0xD4
0070 #define ISL29501_MAGNITUDE_EXPONENT     0xD5
0071 #define ISL29501_MAGNITUDE_MSB          0xD6
0072 #define ISL29501_MAGNITUDE_LSB          0xD7
0073 #define ISL29501_PHASE_MSB          0xD8
0074 #define ISL29501_PHASE_LSB          0xD9
0075 #define ISL29501_I_RAW_EXPONENT         0xDA
0076 #define ISL29501_I_RAW_MSB          0xDB
0077 #define ISL29501_I_RAW_LSB          0xDC
0078 #define ISL29501_Q_RAW_EXPONENT         0xDD
0079 #define ISL29501_Q_RAW_MSB          0xDE
0080 #define ISL29501_Q_RAW_LSB          0xDF
0081 #define ISL29501_DIE_TEMPERATURE        0xE2
0082 #define ISL29501_AMBIENT_LIGHT          0xE3
0083 #define ISL29501_GAIN_MSB           0xE6
0084 #define ISL29501_GAIN_LSB           0xE7
0085 
0086 #define ISL29501_MAX_EXP_VAL 15
0087 
0088 #define ISL29501_INT_TIME_AVAILABLE \
0089     "0.00007 0.00014 0.00028 0.00057 0.00114 " \
0090     "0.00228 0.00455 0.00910 0.01820 0.03640 " \
0091     "0.07281 0.14561"
0092 
0093 #define ISL29501_CURRENT_SCALE_AVAILABLE \
0094     "0.0039 0.0078 0.0118 0.0157 0.0196 " \
0095     "0.0235 0.0275 0.0314 0.0352 0.0392 " \
0096     "0.0431 0.0471 0.0510 0.0549 0.0588"
0097 
0098 enum isl29501_correction_coeff {
0099     COEFF_TEMP_A,
0100     COEFF_TEMP_B,
0101     COEFF_LIGHT_A,
0102     COEFF_LIGHT_B,
0103     COEFF_MAX,
0104 };
0105 
0106 struct isl29501_private {
0107     struct i2c_client *client;
0108     struct mutex lock;
0109     /* Exact representation of correction coefficients. */
0110     unsigned int shadow_coeffs[COEFF_MAX];
0111 };
0112 
0113 enum isl29501_register_name {
0114     REG_DISTANCE,
0115     REG_PHASE,
0116     REG_TEMPERATURE,
0117     REG_AMBIENT_LIGHT,
0118     REG_GAIN,
0119     REG_GAIN_BIAS,
0120     REG_PHASE_EXP,
0121     REG_CALIB_PHASE_TEMP_A,
0122     REG_CALIB_PHASE_TEMP_B,
0123     REG_CALIB_PHASE_LIGHT_A,
0124     REG_CALIB_PHASE_LIGHT_B,
0125     REG_DISTANCE_BIAS,
0126     REG_TEMPERATURE_BIAS,
0127     REG_INT_TIME,
0128     REG_SAMPLE_TIME,
0129     REG_DRIVER_RANGE,
0130     REG_EMITTER_DAC,
0131 };
0132 
0133 struct isl29501_register_desc {
0134     u8 msb;
0135     u8 lsb;
0136 };
0137 
0138 static const struct isl29501_register_desc isl29501_registers[] = {
0139     [REG_DISTANCE] = {
0140         .msb = ISL29501_DISTANCE_MSB_DATA,
0141         .lsb = ISL29501_DISTANCE_LSB_DATA,
0142     },
0143     [REG_PHASE] = {
0144         .msb = ISL29501_PHASE_MSB,
0145         .lsb = ISL29501_PHASE_LSB,
0146     },
0147     [REG_TEMPERATURE] = {
0148         .lsb = ISL29501_DIE_TEMPERATURE,
0149     },
0150     [REG_AMBIENT_LIGHT] = {
0151         .lsb = ISL29501_AMBIENT_LIGHT,
0152     },
0153     [REG_GAIN] = {
0154         .msb = ISL29501_GAIN_MSB,
0155         .lsb = ISL29501_GAIN_LSB,
0156     },
0157     [REG_GAIN_BIAS] = {
0158         .msb = ISL29501_CROSSTALK_GAIN_MSB,
0159         .lsb = ISL29501_CROSSTALK_GAIN_LSB,
0160     },
0161     [REG_PHASE_EXP] = {
0162         .lsb = ISL29501_PHASE_EXPONENT,
0163     },
0164     [REG_CALIB_PHASE_TEMP_A] = {
0165         .lsb = ISL29501_TEMP_COEFF_A,
0166     },
0167     [REG_CALIB_PHASE_TEMP_B] = {
0168         .lsb = ISL29501_TEMP_COEFF_B,
0169     },
0170     [REG_CALIB_PHASE_LIGHT_A] = {
0171         .lsb = ISL29501_AMBIANT_COEFF_A,
0172     },
0173     [REG_CALIB_PHASE_LIGHT_B] = {
0174         .lsb = ISL29501_AMBIANT_COEFF_B,
0175     },
0176     [REG_DISTANCE_BIAS] = {
0177         .msb = ISL29501_PHASE_OFFSET_MSB,
0178         .lsb = ISL29501_PHASE_OFFSET_LSB,
0179     },
0180     [REG_TEMPERATURE_BIAS] = {
0181         .lsb = ISL29501_TEMP_REFERENCE,
0182     },
0183     [REG_INT_TIME] = {
0184         .lsb = ISL29501_INTEGRATION_PERIOD,
0185     },
0186     [REG_SAMPLE_TIME] = {
0187         .lsb = ISL29501_SAMPLE_PERIOD,
0188     },
0189     [REG_DRIVER_RANGE] = {
0190         .lsb = ISL29501_DRIVER_RANGE,
0191     },
0192     [REG_EMITTER_DAC] = {
0193         .lsb = ISL29501_EMITTER_DAC,
0194     },
0195 };
0196 
0197 static int isl29501_register_read(struct isl29501_private *isl29501,
0198                   enum isl29501_register_name name,
0199                   u32 *val)
0200 {
0201     const struct isl29501_register_desc *reg = &isl29501_registers[name];
0202     u8 msb = 0, lsb = 0;
0203     s32 ret;
0204 
0205     mutex_lock(&isl29501->lock);
0206     if (reg->msb) {
0207         ret = i2c_smbus_read_byte_data(isl29501->client, reg->msb);
0208         if (ret < 0)
0209             goto err;
0210         msb = ret;
0211     }
0212 
0213     if (reg->lsb) {
0214         ret = i2c_smbus_read_byte_data(isl29501->client, reg->lsb);
0215         if (ret < 0)
0216             goto err;
0217         lsb = ret;
0218     }
0219     mutex_unlock(&isl29501->lock);
0220 
0221     *val = (msb << 8) + lsb;
0222 
0223     return 0;
0224 err:
0225     mutex_unlock(&isl29501->lock);
0226 
0227     return ret;
0228 }
0229 
0230 static u32 isl29501_register_write(struct isl29501_private *isl29501,
0231                    enum isl29501_register_name name,
0232                    u32 value)
0233 {
0234     const struct isl29501_register_desc *reg = &isl29501_registers[name];
0235     int ret;
0236 
0237     if (!reg->msb && value > U8_MAX)
0238         return -ERANGE;
0239 
0240     if (value > U16_MAX)
0241         return -ERANGE;
0242 
0243     mutex_lock(&isl29501->lock);
0244     if (reg->msb) {
0245         ret = i2c_smbus_write_byte_data(isl29501->client,
0246                         reg->msb, value >> 8);
0247         if (ret < 0)
0248             goto err;
0249     }
0250 
0251     ret = i2c_smbus_write_byte_data(isl29501->client, reg->lsb, value);
0252 
0253 err:
0254     mutex_unlock(&isl29501->lock);
0255     return ret;
0256 }
0257 
0258 static ssize_t isl29501_read_ext(struct iio_dev *indio_dev,
0259                  uintptr_t private,
0260                  const struct iio_chan_spec *chan,
0261                  char *buf)
0262 {
0263     struct isl29501_private *isl29501 = iio_priv(indio_dev);
0264     enum isl29501_register_name reg = private;
0265     int ret;
0266     u32 value, gain, coeff, exp;
0267 
0268     switch (reg) {
0269     case REG_GAIN:
0270     case REG_GAIN_BIAS:
0271         ret = isl29501_register_read(isl29501, reg, &gain);
0272         if (ret < 0)
0273             return ret;
0274 
0275         value = gain;
0276         break;
0277     case REG_CALIB_PHASE_TEMP_A:
0278     case REG_CALIB_PHASE_TEMP_B:
0279     case REG_CALIB_PHASE_LIGHT_A:
0280     case REG_CALIB_PHASE_LIGHT_B:
0281         ret = isl29501_register_read(isl29501, REG_PHASE_EXP, &exp);
0282         if (ret < 0)
0283             return ret;
0284 
0285         ret = isl29501_register_read(isl29501, reg, &coeff);
0286         if (ret < 0)
0287             return ret;
0288 
0289         value = coeff << exp;
0290         break;
0291     default:
0292         return -EINVAL;
0293     }
0294 
0295     return sprintf(buf, "%u\n", value);
0296 }
0297 
0298 static int isl29501_set_shadow_coeff(struct isl29501_private *isl29501,
0299                      enum isl29501_register_name reg,
0300                      unsigned int val)
0301 {
0302     enum isl29501_correction_coeff coeff;
0303 
0304     switch (reg) {
0305     case REG_CALIB_PHASE_TEMP_A:
0306         coeff = COEFF_TEMP_A;
0307         break;
0308     case REG_CALIB_PHASE_TEMP_B:
0309         coeff = COEFF_TEMP_B;
0310         break;
0311     case REG_CALIB_PHASE_LIGHT_A:
0312         coeff = COEFF_LIGHT_A;
0313         break;
0314     case REG_CALIB_PHASE_LIGHT_B:
0315         coeff = COEFF_LIGHT_B;
0316         break;
0317     default:
0318         return -EINVAL;
0319     }
0320     isl29501->shadow_coeffs[coeff] = val;
0321 
0322     return 0;
0323 }
0324 
0325 static int isl29501_write_coeff(struct isl29501_private *isl29501,
0326                 enum isl29501_correction_coeff coeff,
0327                 int val)
0328 {
0329     enum isl29501_register_name reg;
0330 
0331     switch (coeff) {
0332     case COEFF_TEMP_A:
0333         reg = REG_CALIB_PHASE_TEMP_A;
0334         break;
0335     case COEFF_TEMP_B:
0336         reg = REG_CALIB_PHASE_TEMP_B;
0337         break;
0338     case COEFF_LIGHT_A:
0339         reg = REG_CALIB_PHASE_LIGHT_A;
0340         break;
0341     case COEFF_LIGHT_B:
0342         reg = REG_CALIB_PHASE_LIGHT_B;
0343         break;
0344     default:
0345         return -EINVAL;
0346     }
0347 
0348     return isl29501_register_write(isl29501, reg, val);
0349 }
0350 
0351 static unsigned int isl29501_find_corr_exp(unsigned int val,
0352                        unsigned int max_exp,
0353                        unsigned int max_mantissa)
0354 {
0355     unsigned int exp = 1;
0356 
0357     /*
0358      * Correction coefficients are represented under
0359      * mantissa * 2^exponent form, where mantissa and exponent
0360      * are stored in two separate registers of the sensor.
0361      *
0362      * Compute and return the lowest exponent such as:
0363      *       mantissa = value / 2^exponent
0364      *
0365      *  where mantissa < max_mantissa.
0366      */
0367     if (val <= max_mantissa)
0368         return 0;
0369 
0370     while ((val >> exp) > max_mantissa) {
0371         exp++;
0372 
0373         if (exp > max_exp)
0374             return max_exp;
0375     }
0376 
0377     return exp;
0378 }
0379 
0380 static ssize_t isl29501_write_ext(struct iio_dev *indio_dev,
0381                   uintptr_t private,
0382                   const struct iio_chan_spec *chan,
0383                   const char *buf, size_t len)
0384 {
0385     struct isl29501_private *isl29501 = iio_priv(indio_dev);
0386     enum isl29501_register_name reg = private;
0387     unsigned int val;
0388     int max_exp = 0;
0389     int ret;
0390     int i;
0391 
0392     ret = kstrtouint(buf, 10, &val);
0393     if (ret)
0394         return ret;
0395 
0396     switch (reg) {
0397     case REG_GAIN_BIAS:
0398         if (val > U16_MAX)
0399             return -ERANGE;
0400 
0401         ret = isl29501_register_write(isl29501, reg, val);
0402         if (ret < 0)
0403             return ret;
0404 
0405         break;
0406     case REG_CALIB_PHASE_TEMP_A:
0407     case REG_CALIB_PHASE_TEMP_B:
0408     case REG_CALIB_PHASE_LIGHT_A:
0409     case REG_CALIB_PHASE_LIGHT_B:
0410 
0411         if (val > (U8_MAX << ISL29501_MAX_EXP_VAL))
0412             return -ERANGE;
0413 
0414         /* Store the correction coefficient under its exact form. */
0415         ret = isl29501_set_shadow_coeff(isl29501, reg, val);
0416         if (ret < 0)
0417             return ret;
0418 
0419         /*
0420          * Find the highest exponent needed to represent
0421          * correction coefficients.
0422          */
0423         for (i = 0; i < COEFF_MAX; i++) {
0424             int corr;
0425             int corr_exp;
0426 
0427             corr = isl29501->shadow_coeffs[i];
0428             corr_exp = isl29501_find_corr_exp(corr,
0429                               ISL29501_MAX_EXP_VAL,
0430                               U8_MAX / 2);
0431             dev_dbg(&isl29501->client->dev,
0432                 "found exp of corr(%d) = %d\n", corr, corr_exp);
0433 
0434             max_exp = max(max_exp, corr_exp);
0435         }
0436 
0437         /*
0438          * Represent every correction coefficient under
0439          * mantissa * 2^max_exponent form and force the
0440          * writing of those coefficients on the sensor.
0441          */
0442         for (i = 0; i < COEFF_MAX; i++) {
0443             int corr;
0444             int mantissa;
0445 
0446             corr = isl29501->shadow_coeffs[i];
0447             if (!corr)
0448                 continue;
0449 
0450             mantissa = corr >> max_exp;
0451 
0452             ret = isl29501_write_coeff(isl29501, i, mantissa);
0453             if (ret < 0)
0454                 return ret;
0455         }
0456 
0457         ret = isl29501_register_write(isl29501, REG_PHASE_EXP, max_exp);
0458         if (ret < 0)
0459             return ret;
0460 
0461         break;
0462     default:
0463         return -EINVAL;
0464     }
0465 
0466     return len;
0467 }
0468 
0469 #define _ISL29501_EXT_INFO(_name, _ident) { \
0470     .name = _name, \
0471     .read = isl29501_read_ext, \
0472     .write = isl29501_write_ext, \
0473     .private = _ident, \
0474     .shared = IIO_SEPARATE, \
0475 }
0476 
0477 static const struct iio_chan_spec_ext_info isl29501_ext_info[] = {
0478     _ISL29501_EXT_INFO("agc_gain", REG_GAIN),
0479     _ISL29501_EXT_INFO("agc_gain_bias", REG_GAIN_BIAS),
0480     _ISL29501_EXT_INFO("calib_phase_temp_a", REG_CALIB_PHASE_TEMP_A),
0481     _ISL29501_EXT_INFO("calib_phase_temp_b", REG_CALIB_PHASE_TEMP_B),
0482     _ISL29501_EXT_INFO("calib_phase_light_a", REG_CALIB_PHASE_LIGHT_A),
0483     _ISL29501_EXT_INFO("calib_phase_light_b", REG_CALIB_PHASE_LIGHT_B),
0484     { },
0485 };
0486 
0487 #define ISL29501_DISTANCE_SCAN_INDEX 0
0488 #define ISL29501_TIMESTAMP_SCAN_INDEX 1
0489 
0490 static const struct iio_chan_spec isl29501_channels[] = {
0491     {
0492         .type = IIO_PROXIMITY,
0493         .scan_index = ISL29501_DISTANCE_SCAN_INDEX,
0494         .info_mask_separate =
0495             BIT(IIO_CHAN_INFO_RAW)   |
0496             BIT(IIO_CHAN_INFO_SCALE) |
0497             BIT(IIO_CHAN_INFO_CALIBBIAS),
0498         .scan_type = {
0499             .sign = 'u',
0500             .realbits = 16,
0501             .storagebits = 16,
0502             .endianness = IIO_CPU,
0503         },
0504         .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME) |
0505                 BIT(IIO_CHAN_INFO_SAMP_FREQ),
0506         .ext_info = isl29501_ext_info,
0507     },
0508     {
0509         .type = IIO_PHASE,
0510         .scan_index = -1,
0511         .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
0512                 BIT(IIO_CHAN_INFO_SCALE),
0513     },
0514     {
0515         .type = IIO_CURRENT,
0516         .scan_index = -1,
0517         .output = 1,
0518         .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
0519                 BIT(IIO_CHAN_INFO_SCALE),
0520     },
0521     {
0522         .type = IIO_TEMP,
0523         .scan_index = -1,
0524         .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
0525                 BIT(IIO_CHAN_INFO_SCALE)     |
0526                 BIT(IIO_CHAN_INFO_CALIBBIAS),
0527     },
0528     {
0529         .type = IIO_INTENSITY,
0530         .scan_index = -1,
0531         .modified = 1,
0532         .channel2 = IIO_MOD_LIGHT_CLEAR,
0533         .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
0534                 BIT(IIO_CHAN_INFO_SCALE),
0535     },
0536     IIO_CHAN_SOFT_TIMESTAMP(ISL29501_TIMESTAMP_SCAN_INDEX),
0537 };
0538 
0539 static int isl29501_reset_registers(struct isl29501_private *isl29501)
0540 {
0541     int ret;
0542 
0543     ret = i2c_smbus_write_byte_data(isl29501->client,
0544                     ISL29501_COMMAND_REGISTER,
0545                     ISL29501_RESET_ALL_REGISTERS);
0546     if (ret < 0) {
0547         dev_err(&isl29501->client->dev,
0548             "cannot reset registers %d\n", ret);
0549         return ret;
0550     }
0551 
0552     ret = i2c_smbus_write_byte_data(isl29501->client,
0553                     ISL29501_COMMAND_REGISTER,
0554                     ISL29501_RESET_INT_SM);
0555     if (ret < 0)
0556         dev_err(&isl29501->client->dev,
0557             "cannot reset state machine %d\n", ret);
0558 
0559     return ret;
0560 }
0561 
0562 static int isl29501_begin_acquisition(struct isl29501_private *isl29501)
0563 {
0564     int ret;
0565 
0566     ret = i2c_smbus_write_byte_data(isl29501->client,
0567                     ISL29501_COMMAND_REGISTER,
0568                     ISL29501_EMUL_SAMPLE_START_PIN);
0569     if (ret < 0)
0570         dev_err(&isl29501->client->dev,
0571             "cannot begin acquisition %d\n", ret);
0572 
0573     return ret;
0574 }
0575 
0576 static IIO_CONST_ATTR_INT_TIME_AVAIL(ISL29501_INT_TIME_AVAILABLE);
0577 static IIO_CONST_ATTR(out_current_scale_available,
0578               ISL29501_CURRENT_SCALE_AVAILABLE);
0579 
0580 static struct attribute *isl29501_attributes[] = {
0581     &iio_const_attr_integration_time_available.dev_attr.attr,
0582     &iio_const_attr_out_current_scale_available.dev_attr.attr,
0583     NULL
0584 };
0585 
0586 static const struct attribute_group isl29501_attribute_group = {
0587     .attrs = isl29501_attributes,
0588 };
0589 
0590 static const int isl29501_current_scale_table[][2] = {
0591     {0, 3900}, {0, 7800}, {0, 11800}, {0, 15700},
0592     {0, 19600}, {0, 23500}, {0, 27500}, {0, 31400},
0593     {0, 35200}, {0, 39200}, {0, 43100}, {0, 47100},
0594     {0, 51000}, {0, 54900}, {0, 58800},
0595 };
0596 
0597 static const int isl29501_int_time[][2] = {
0598     {0, 70},    /* 0.07 ms */
0599     {0, 140},   /* 0.14 ms */
0600     {0, 280},   /* 0.28 ms */
0601     {0, 570},   /* 0.57 ms */
0602     {0, 1140},  /* 1.14 ms */
0603     {0, 2280},  /* 2.28 ms */
0604     {0, 4550},  /* 4.55 ms */
0605     {0, 9100},  /* 9.11 ms */
0606     {0, 18200}, /* 18.2 ms */
0607     {0, 36400}, /* 36.4 ms */
0608     {0, 72810}, /* 72.81 ms */
0609     {0, 145610} /* 145.28 ms */
0610 };
0611 
0612 static int isl29501_get_raw(struct isl29501_private *isl29501,
0613                 const struct iio_chan_spec *chan,
0614                 int *raw)
0615 {
0616     int ret;
0617 
0618     switch (chan->type) {
0619     case IIO_PROXIMITY:
0620         ret = isl29501_register_read(isl29501, REG_DISTANCE, raw);
0621         if (ret < 0)
0622             return ret;
0623 
0624         return IIO_VAL_INT;
0625     case IIO_INTENSITY:
0626         ret = isl29501_register_read(isl29501,
0627                          REG_AMBIENT_LIGHT,
0628                          raw);
0629         if (ret < 0)
0630             return ret;
0631 
0632         return IIO_VAL_INT;
0633     case IIO_PHASE:
0634         ret = isl29501_register_read(isl29501, REG_PHASE, raw);
0635         if (ret < 0)
0636             return ret;
0637 
0638         return IIO_VAL_INT;
0639     case IIO_CURRENT:
0640         ret = isl29501_register_read(isl29501, REG_EMITTER_DAC, raw);
0641         if (ret < 0)
0642             return ret;
0643 
0644         return IIO_VAL_INT;
0645     case IIO_TEMP:
0646         ret = isl29501_register_read(isl29501, REG_TEMPERATURE, raw);
0647         if (ret < 0)
0648             return ret;
0649 
0650         return IIO_VAL_INT;
0651     default:
0652         return -EINVAL;
0653     }
0654 }
0655 
0656 static int isl29501_get_scale(struct isl29501_private *isl29501,
0657                   const struct iio_chan_spec *chan,
0658                   int *val, int *val2)
0659 {
0660     int ret;
0661     u32 current_scale;
0662 
0663     switch (chan->type) {
0664     case IIO_PROXIMITY:
0665         /* distance = raw_distance * 33.31 / 65536 (m) */
0666         *val = 3331;
0667         *val2 = 6553600;
0668 
0669         return IIO_VAL_FRACTIONAL;
0670     case IIO_PHASE:
0671         /* phase = raw_phase * 2pi / 65536 (rad) */
0672         *val = 0;
0673         *val2 = 95874;
0674 
0675         return IIO_VAL_INT_PLUS_NANO;
0676     case IIO_INTENSITY:
0677         /* light = raw_light * 35 / 10000 (mA) */
0678         *val = 35;
0679         *val2 = 10000;
0680 
0681         return IIO_VAL_FRACTIONAL;
0682     case IIO_CURRENT:
0683         ret = isl29501_register_read(isl29501,
0684                          REG_DRIVER_RANGE,
0685                          &current_scale);
0686         if (ret < 0)
0687             return ret;
0688 
0689         if (current_scale > ARRAY_SIZE(isl29501_current_scale_table))
0690             return -EINVAL;
0691 
0692         if (!current_scale) {
0693             *val = 0;
0694             *val2 = 0;
0695             return IIO_VAL_INT;
0696         }
0697 
0698         *val = isl29501_current_scale_table[current_scale - 1][0];
0699         *val2 = isl29501_current_scale_table[current_scale - 1][1];
0700 
0701         return IIO_VAL_INT_PLUS_MICRO;
0702     case IIO_TEMP:
0703         /* temperature = raw_temperature * 125 / 100000 (milli °C) */
0704         *val = 125;
0705         *val2 = 100000;
0706 
0707         return IIO_VAL_FRACTIONAL;
0708     default:
0709         return -EINVAL;
0710     }
0711 }
0712 
0713 static int isl29501_get_calibbias(struct isl29501_private *isl29501,
0714                   const struct iio_chan_spec *chan,
0715                   int *bias)
0716 {
0717     switch (chan->type) {
0718     case IIO_PROXIMITY:
0719         return isl29501_register_read(isl29501,
0720                           REG_DISTANCE_BIAS,
0721                           bias);
0722     case IIO_TEMP:
0723         return isl29501_register_read(isl29501,
0724                           REG_TEMPERATURE_BIAS,
0725                           bias);
0726     default:
0727         return -EINVAL;
0728     }
0729 }
0730 
0731 static int isl29501_get_inttime(struct isl29501_private *isl29501,
0732                 int *val, int *val2)
0733 {
0734     int ret;
0735     u32 inttime;
0736 
0737     ret = isl29501_register_read(isl29501, REG_INT_TIME, &inttime);
0738     if (ret < 0)
0739         return ret;
0740 
0741     if (inttime >= ARRAY_SIZE(isl29501_int_time))
0742         return -EINVAL;
0743 
0744     *val = isl29501_int_time[inttime][0];
0745     *val2 = isl29501_int_time[inttime][1];
0746 
0747     return IIO_VAL_INT_PLUS_MICRO;
0748 }
0749 
0750 static int isl29501_get_freq(struct isl29501_private *isl29501,
0751                  int *val, int *val2)
0752 {
0753     int ret;
0754     int sample_time;
0755     unsigned long long freq;
0756     u32 temp;
0757 
0758     ret = isl29501_register_read(isl29501, REG_SAMPLE_TIME, &sample_time);
0759     if (ret < 0)
0760         return ret;
0761 
0762     /* freq = 1 / (0.000450 * (sample_time + 1) * 10^-6) */
0763     freq = 1000000ULL * 1000000ULL;
0764 
0765     do_div(freq, 450 * (sample_time + 1));
0766 
0767     temp = do_div(freq, 1000000);
0768     *val = freq;
0769     *val2 = temp;
0770 
0771     return IIO_VAL_INT_PLUS_MICRO;
0772 }
0773 
0774 static int isl29501_read_raw(struct iio_dev *indio_dev,
0775                  struct iio_chan_spec const *chan, int *val,
0776                  int *val2, long mask)
0777 {
0778     struct isl29501_private *isl29501 = iio_priv(indio_dev);
0779 
0780     switch (mask) {
0781     case IIO_CHAN_INFO_RAW:
0782         return isl29501_get_raw(isl29501, chan, val);
0783     case IIO_CHAN_INFO_SCALE:
0784         return isl29501_get_scale(isl29501, chan, val, val2);
0785     case IIO_CHAN_INFO_INT_TIME:
0786         return isl29501_get_inttime(isl29501, val, val2);
0787     case IIO_CHAN_INFO_SAMP_FREQ:
0788         return isl29501_get_freq(isl29501, val, val2);
0789     case IIO_CHAN_INFO_CALIBBIAS:
0790         return isl29501_get_calibbias(isl29501, chan, val);
0791     default:
0792         return -EINVAL;
0793     }
0794 }
0795 
0796 static int isl29501_set_raw(struct isl29501_private *isl29501,
0797                 const struct iio_chan_spec *chan,
0798                 int raw)
0799 {
0800     switch (chan->type) {
0801     case IIO_CURRENT:
0802         return isl29501_register_write(isl29501, REG_EMITTER_DAC, raw);
0803     default:
0804         return -EINVAL;
0805     }
0806 }
0807 
0808 static int isl29501_set_inttime(struct isl29501_private *isl29501,
0809                 int val, int val2)
0810 {
0811     int i;
0812 
0813     for (i = 0; i < ARRAY_SIZE(isl29501_int_time); i++) {
0814         if (isl29501_int_time[i][0] == val &&
0815             isl29501_int_time[i][1] == val2) {
0816             return isl29501_register_write(isl29501,
0817                                REG_INT_TIME,
0818                                i);
0819         }
0820     }
0821 
0822     return -EINVAL;
0823 }
0824 
0825 static int isl29501_set_scale(struct isl29501_private *isl29501,
0826                   const struct iio_chan_spec *chan,
0827                   int val, int val2)
0828 {
0829     int i;
0830 
0831     if (chan->type != IIO_CURRENT)
0832         return -EINVAL;
0833 
0834     for (i = 0; i < ARRAY_SIZE(isl29501_current_scale_table); i++) {
0835         if (isl29501_current_scale_table[i][0] == val &&
0836             isl29501_current_scale_table[i][1] == val2) {
0837             return isl29501_register_write(isl29501,
0838                                REG_DRIVER_RANGE,
0839                                i + 1);
0840         }
0841     }
0842 
0843     return -EINVAL;
0844 }
0845 
0846 static int isl29501_set_calibbias(struct isl29501_private *isl29501,
0847                   const struct iio_chan_spec *chan,
0848                   int bias)
0849 {
0850     switch (chan->type) {
0851     case IIO_PROXIMITY:
0852         return isl29501_register_write(isl29501,
0853                           REG_DISTANCE_BIAS,
0854                           bias);
0855     case IIO_TEMP:
0856         return isl29501_register_write(isl29501,
0857                            REG_TEMPERATURE_BIAS,
0858                            bias);
0859     default:
0860         return -EINVAL;
0861     }
0862 }
0863 
0864 static int isl29501_set_freq(struct isl29501_private *isl29501,
0865                  int val, int val2)
0866 {
0867     int freq;
0868     unsigned long long sample_time;
0869 
0870     /* sample_freq = 1 / (0.000450 * (sample_time + 1) * 10^-6) */
0871     freq = val * 1000000 + val2 % 1000000;
0872     sample_time = 2222ULL * 1000000ULL;
0873     do_div(sample_time, freq);
0874 
0875     sample_time -= 1;
0876 
0877     if (sample_time > 255)
0878         return -ERANGE;
0879 
0880     return isl29501_register_write(isl29501, REG_SAMPLE_TIME, sample_time);
0881 }
0882 
0883 static int isl29501_write_raw(struct iio_dev *indio_dev,
0884                   struct iio_chan_spec const *chan,
0885                   int val, int val2, long mask)
0886 {
0887     struct isl29501_private *isl29501 = iio_priv(indio_dev);
0888 
0889     switch (mask) {
0890     case IIO_CHAN_INFO_RAW:
0891         return isl29501_set_raw(isl29501, chan, val);
0892     case IIO_CHAN_INFO_INT_TIME:
0893         return isl29501_set_inttime(isl29501, val, val2);
0894     case IIO_CHAN_INFO_SAMP_FREQ:
0895         return isl29501_set_freq(isl29501, val, val2);
0896     case IIO_CHAN_INFO_SCALE:
0897         return isl29501_set_scale(isl29501, chan, val, val2);
0898     case IIO_CHAN_INFO_CALIBBIAS:
0899         return isl29501_set_calibbias(isl29501, chan, val);
0900     default:
0901         return -EINVAL;
0902     }
0903 }
0904 
0905 static const struct iio_info isl29501_info = {
0906     .read_raw = &isl29501_read_raw,
0907     .write_raw = &isl29501_write_raw,
0908     .attrs = &isl29501_attribute_group,
0909 };
0910 
0911 static int isl29501_init_chip(struct isl29501_private *isl29501)
0912 {
0913     int ret;
0914 
0915     ret = i2c_smbus_read_byte_data(isl29501->client, ISL29501_DEVICE_ID);
0916     if (ret < 0) {
0917         dev_err(&isl29501->client->dev, "Error reading device id\n");
0918         return ret;
0919     }
0920 
0921     if (ret != ISL29501_ID) {
0922         dev_err(&isl29501->client->dev,
0923             "Wrong chip id, got %x expected %x\n",
0924             ret, ISL29501_DEVICE_ID);
0925         return -ENODEV;
0926     }
0927 
0928     ret = isl29501_reset_registers(isl29501);
0929     if (ret < 0)
0930         return ret;
0931 
0932     return isl29501_begin_acquisition(isl29501);
0933 }
0934 
0935 static irqreturn_t isl29501_trigger_handler(int irq, void *p)
0936 {
0937     struct iio_poll_func *pf = p;
0938     struct iio_dev *indio_dev = pf->indio_dev;
0939     struct isl29501_private *isl29501 = iio_priv(indio_dev);
0940     const unsigned long *active_mask = indio_dev->active_scan_mask;
0941     u32 buffer[4] __aligned(8) = {}; /* 1x16-bit + naturally aligned ts */
0942 
0943     if (test_bit(ISL29501_DISTANCE_SCAN_INDEX, active_mask))
0944         isl29501_register_read(isl29501, REG_DISTANCE, buffer);
0945 
0946     iio_push_to_buffers_with_timestamp(indio_dev, buffer, pf->timestamp);
0947     iio_trigger_notify_done(indio_dev->trig);
0948 
0949     return IRQ_HANDLED;
0950 }
0951 
0952 static int isl29501_probe(struct i2c_client *client,
0953               const struct i2c_device_id *id)
0954 {
0955     struct iio_dev *indio_dev;
0956     struct isl29501_private *isl29501;
0957     int ret;
0958 
0959     indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*isl29501));
0960     if (!indio_dev)
0961         return -ENOMEM;
0962 
0963     isl29501 = iio_priv(indio_dev);
0964 
0965     i2c_set_clientdata(client, indio_dev);
0966     isl29501->client = client;
0967 
0968     mutex_init(&isl29501->lock);
0969 
0970     ret = isl29501_init_chip(isl29501);
0971     if (ret < 0)
0972         return ret;
0973 
0974     indio_dev->modes = INDIO_DIRECT_MODE;
0975     indio_dev->channels = isl29501_channels;
0976     indio_dev->num_channels = ARRAY_SIZE(isl29501_channels);
0977     indio_dev->name = client->name;
0978     indio_dev->info = &isl29501_info;
0979 
0980     ret = devm_iio_triggered_buffer_setup(&client->dev, indio_dev,
0981                           iio_pollfunc_store_time,
0982                           isl29501_trigger_handler,
0983                           NULL);
0984     if (ret < 0) {
0985         dev_err(&client->dev, "unable to setup iio triggered buffer\n");
0986         return ret;
0987     }
0988 
0989     return devm_iio_device_register(&client->dev, indio_dev);
0990 }
0991 
0992 static const struct i2c_device_id isl29501_id[] = {
0993     {"isl29501", 0},
0994     {}
0995 };
0996 
0997 MODULE_DEVICE_TABLE(i2c, isl29501_id);
0998 
0999 #if defined(CONFIG_OF)
1000 static const struct of_device_id isl29501_i2c_matches[] = {
1001     { .compatible = "renesas,isl29501" },
1002     { }
1003 };
1004 MODULE_DEVICE_TABLE(of, isl29501_i2c_matches);
1005 #endif
1006 
1007 static struct i2c_driver isl29501_driver = {
1008     .driver = {
1009         .name   = "isl29501",
1010     },
1011     .id_table   = isl29501_id,
1012     .probe      = isl29501_probe,
1013 };
1014 module_i2c_driver(isl29501_driver);
1015 
1016 MODULE_AUTHOR("Mathieu Othacehe <m.othacehe@gmail.com>");
1017 MODULE_DESCRIPTION("ISL29501 Time of Flight sensor driver");
1018 MODULE_LICENSE("GPL v2");