xref: /linux/drivers/iio/proximity/isl29501.c (revision a1ff5a7d78a036d6c2178ee5acd6ba4946243800)
11c287992SMathieu Othacehe // SPDX-License-Identifier: GPL-2.0
21c287992SMathieu Othacehe /*
31c287992SMathieu Othacehe  * isl29501.c: ISL29501 Time of Flight sensor driver.
41c287992SMathieu Othacehe  *
51c287992SMathieu Othacehe  * Copyright (C) 2018
61c287992SMathieu Othacehe  * Author: Mathieu Othacehe <m.othacehe@gmail.com>
71c287992SMathieu Othacehe  *
81c287992SMathieu Othacehe  * 7-bit I2C slave address: 0x57
91c287992SMathieu Othacehe  */
101c287992SMathieu Othacehe 
111c287992SMathieu Othacehe #include <linux/kernel.h>
121c287992SMathieu Othacehe #include <linux/module.h>
131c287992SMathieu Othacehe #include <linux/i2c.h>
141c287992SMathieu Othacehe #include <linux/err.h>
151240c94cSRob Herring #include <linux/mod_devicetable.h>
161c287992SMathieu Othacehe #include <linux/iio/iio.h>
171c287992SMathieu Othacehe #include <linux/iio/sysfs.h>
181c287992SMathieu Othacehe 
191c287992SMathieu Othacehe #include <linux/iio/trigger_consumer.h>
201c287992SMathieu Othacehe #include <linux/iio/buffer.h>
211c287992SMathieu Othacehe #include <linux/iio/triggered_buffer.h>
221c287992SMathieu Othacehe 
231c287992SMathieu Othacehe /* Control, setting and status registers */
241c287992SMathieu Othacehe #define ISL29501_DEVICE_ID			0x00
251c287992SMathieu Othacehe #define ISL29501_ID				0x0A
261c287992SMathieu Othacehe 
271c287992SMathieu Othacehe /* Sampling control registers */
281c287992SMathieu Othacehe #define ISL29501_INTEGRATION_PERIOD		0x10
291c287992SMathieu Othacehe #define ISL29501_SAMPLE_PERIOD			0x11
301c287992SMathieu Othacehe 
311c287992SMathieu Othacehe /* Closed loop calibration registers */
321c287992SMathieu Othacehe #define ISL29501_CROSSTALK_I_MSB		0x24
331c287992SMathieu Othacehe #define ISL29501_CROSSTALK_I_LSB		0x25
341c287992SMathieu Othacehe #define ISL29501_CROSSTALK_I_EXPONENT		0x26
351c287992SMathieu Othacehe #define ISL29501_CROSSTALK_Q_MSB		0x27
361c287992SMathieu Othacehe #define ISL29501_CROSSTALK_Q_LSB		0x28
371c287992SMathieu Othacehe #define ISL29501_CROSSTALK_Q_EXPONENT		0x29
381c287992SMathieu Othacehe #define ISL29501_CROSSTALK_GAIN_MSB		0x2A
391c287992SMathieu Othacehe #define ISL29501_CROSSTALK_GAIN_LSB		0x2B
401c287992SMathieu Othacehe #define ISL29501_MAGNITUDE_REF_EXP		0x2C
411c287992SMathieu Othacehe #define ISL29501_MAGNITUDE_REF_MSB		0x2D
421c287992SMathieu Othacehe #define ISL29501_MAGNITUDE_REF_LSB		0x2E
431c287992SMathieu Othacehe #define ISL29501_PHASE_OFFSET_MSB		0x2F
441c287992SMathieu Othacehe #define ISL29501_PHASE_OFFSET_LSB		0x30
451c287992SMathieu Othacehe 
461c287992SMathieu Othacehe /* Analog control registers */
471c287992SMathieu Othacehe #define ISL29501_DRIVER_RANGE			0x90
481c287992SMathieu Othacehe #define ISL29501_EMITTER_DAC			0x91
491c287992SMathieu Othacehe 
501c287992SMathieu Othacehe #define ISL29501_COMMAND_REGISTER		0xB0
511c287992SMathieu Othacehe 
521c287992SMathieu Othacehe /* Commands */
531c287992SMathieu Othacehe #define ISL29501_EMUL_SAMPLE_START_PIN		0x49
541c287992SMathieu Othacehe #define ISL29501_RESET_ALL_REGISTERS		0xD7
551c287992SMathieu Othacehe #define ISL29501_RESET_INT_SM			0xD1
561c287992SMathieu Othacehe 
571c287992SMathieu Othacehe /* Ambiant light and temperature corrections */
581c287992SMathieu Othacehe #define ISL29501_TEMP_REFERENCE			0x31
591c287992SMathieu Othacehe #define ISL29501_PHASE_EXPONENT			0x33
601c287992SMathieu Othacehe #define ISL29501_TEMP_COEFF_A			0x34
611c287992SMathieu Othacehe #define ISL29501_TEMP_COEFF_B			0x39
621c287992SMathieu Othacehe #define ISL29501_AMBIANT_COEFF_A		0x36
631c287992SMathieu Othacehe #define ISL29501_AMBIANT_COEFF_B		0x3B
641c287992SMathieu Othacehe 
651c287992SMathieu Othacehe /* Data output registers */
661c287992SMathieu Othacehe #define ISL29501_DISTANCE_MSB_DATA		0xD1
671c287992SMathieu Othacehe #define ISL29501_DISTANCE_LSB_DATA		0xD2
681c287992SMathieu Othacehe #define ISL29501_PRECISION_MSB			0xD3
691c287992SMathieu Othacehe #define ISL29501_PRECISION_LSB			0xD4
701c287992SMathieu Othacehe #define ISL29501_MAGNITUDE_EXPONENT		0xD5
711c287992SMathieu Othacehe #define ISL29501_MAGNITUDE_MSB			0xD6
721c287992SMathieu Othacehe #define ISL29501_MAGNITUDE_LSB			0xD7
731c287992SMathieu Othacehe #define ISL29501_PHASE_MSB			0xD8
741c287992SMathieu Othacehe #define ISL29501_PHASE_LSB			0xD9
751c287992SMathieu Othacehe #define ISL29501_I_RAW_EXPONENT			0xDA
761c287992SMathieu Othacehe #define ISL29501_I_RAW_MSB			0xDB
771c287992SMathieu Othacehe #define ISL29501_I_RAW_LSB			0xDC
781c287992SMathieu Othacehe #define ISL29501_Q_RAW_EXPONENT			0xDD
791c287992SMathieu Othacehe #define ISL29501_Q_RAW_MSB			0xDE
801c287992SMathieu Othacehe #define ISL29501_Q_RAW_LSB			0xDF
811c287992SMathieu Othacehe #define ISL29501_DIE_TEMPERATURE		0xE2
821c287992SMathieu Othacehe #define ISL29501_AMBIENT_LIGHT			0xE3
831c287992SMathieu Othacehe #define ISL29501_GAIN_MSB			0xE6
841c287992SMathieu Othacehe #define ISL29501_GAIN_LSB			0xE7
851c287992SMathieu Othacehe 
861c287992SMathieu Othacehe #define ISL29501_MAX_EXP_VAL 15
871c287992SMathieu Othacehe 
881c287992SMathieu Othacehe #define ISL29501_INT_TIME_AVAILABLE \
891c287992SMathieu Othacehe 	"0.00007 0.00014 0.00028 0.00057 0.00114 " \
901c287992SMathieu Othacehe 	"0.00228 0.00455 0.00910 0.01820 0.03640 " \
911c287992SMathieu Othacehe 	"0.07281 0.14561"
921c287992SMathieu Othacehe 
931c287992SMathieu Othacehe #define ISL29501_CURRENT_SCALE_AVAILABLE \
941c287992SMathieu Othacehe 	"0.0039 0.0078 0.0118 0.0157 0.0196 " \
951c287992SMathieu Othacehe 	"0.0235 0.0275 0.0314 0.0352 0.0392 " \
961c287992SMathieu Othacehe 	"0.0431 0.0471 0.0510 0.0549 0.0588"
971c287992SMathieu Othacehe 
981c287992SMathieu Othacehe enum isl29501_correction_coeff {
991c287992SMathieu Othacehe 	COEFF_TEMP_A,
1001c287992SMathieu Othacehe 	COEFF_TEMP_B,
1011c287992SMathieu Othacehe 	COEFF_LIGHT_A,
1021c287992SMathieu Othacehe 	COEFF_LIGHT_B,
1031c287992SMathieu Othacehe 	COEFF_MAX,
1041c287992SMathieu Othacehe };
1051c287992SMathieu Othacehe 
1061c287992SMathieu Othacehe struct isl29501_private {
1071c287992SMathieu Othacehe 	struct i2c_client *client;
1081c287992SMathieu Othacehe 	struct mutex lock;
1091c287992SMathieu Othacehe 	/* Exact representation of correction coefficients. */
1101c287992SMathieu Othacehe 	unsigned int shadow_coeffs[COEFF_MAX];
1111c287992SMathieu Othacehe };
1121c287992SMathieu Othacehe 
1131c287992SMathieu Othacehe enum isl29501_register_name {
1141c287992SMathieu Othacehe 	REG_DISTANCE,
1151c287992SMathieu Othacehe 	REG_PHASE,
1161c287992SMathieu Othacehe 	REG_TEMPERATURE,
1171c287992SMathieu Othacehe 	REG_AMBIENT_LIGHT,
1181c287992SMathieu Othacehe 	REG_GAIN,
1191c287992SMathieu Othacehe 	REG_GAIN_BIAS,
1201c287992SMathieu Othacehe 	REG_PHASE_EXP,
1211c287992SMathieu Othacehe 	REG_CALIB_PHASE_TEMP_A,
1221c287992SMathieu Othacehe 	REG_CALIB_PHASE_TEMP_B,
1231c287992SMathieu Othacehe 	REG_CALIB_PHASE_LIGHT_A,
1241c287992SMathieu Othacehe 	REG_CALIB_PHASE_LIGHT_B,
1251c287992SMathieu Othacehe 	REG_DISTANCE_BIAS,
1261c287992SMathieu Othacehe 	REG_TEMPERATURE_BIAS,
1271c287992SMathieu Othacehe 	REG_INT_TIME,
1281c287992SMathieu Othacehe 	REG_SAMPLE_TIME,
1291c287992SMathieu Othacehe 	REG_DRIVER_RANGE,
1301c287992SMathieu Othacehe 	REG_EMITTER_DAC,
1311c287992SMathieu Othacehe };
1321c287992SMathieu Othacehe 
1331c287992SMathieu Othacehe struct isl29501_register_desc {
1341c287992SMathieu Othacehe 	u8 msb;
1351c287992SMathieu Othacehe 	u8 lsb;
1361c287992SMathieu Othacehe };
1371c287992SMathieu Othacehe 
1381c287992SMathieu Othacehe static const struct isl29501_register_desc isl29501_registers[] = {
1391c287992SMathieu Othacehe 	[REG_DISTANCE] = {
1401c287992SMathieu Othacehe 		.msb = ISL29501_DISTANCE_MSB_DATA,
1411c287992SMathieu Othacehe 		.lsb = ISL29501_DISTANCE_LSB_DATA,
1421c287992SMathieu Othacehe 	},
1431c287992SMathieu Othacehe 	[REG_PHASE] = {
1441c287992SMathieu Othacehe 		.msb = ISL29501_PHASE_MSB,
1451c287992SMathieu Othacehe 		.lsb = ISL29501_PHASE_LSB,
1461c287992SMathieu Othacehe 	},
1471c287992SMathieu Othacehe 	[REG_TEMPERATURE] = {
1481c287992SMathieu Othacehe 		.lsb = ISL29501_DIE_TEMPERATURE,
1491c287992SMathieu Othacehe 	},
1501c287992SMathieu Othacehe 	[REG_AMBIENT_LIGHT] = {
1511c287992SMathieu Othacehe 		.lsb = ISL29501_AMBIENT_LIGHT,
1521c287992SMathieu Othacehe 	},
1531c287992SMathieu Othacehe 	[REG_GAIN] = {
1541c287992SMathieu Othacehe 		.msb = ISL29501_GAIN_MSB,
1551c287992SMathieu Othacehe 		.lsb = ISL29501_GAIN_LSB,
1561c287992SMathieu Othacehe 	},
1571c287992SMathieu Othacehe 	[REG_GAIN_BIAS] = {
1581c287992SMathieu Othacehe 		.msb = ISL29501_CROSSTALK_GAIN_MSB,
1591c287992SMathieu Othacehe 		.lsb = ISL29501_CROSSTALK_GAIN_LSB,
1601c287992SMathieu Othacehe 	},
1611c287992SMathieu Othacehe 	[REG_PHASE_EXP] = {
1621c287992SMathieu Othacehe 		.lsb = ISL29501_PHASE_EXPONENT,
1631c287992SMathieu Othacehe 	},
1641c287992SMathieu Othacehe 	[REG_CALIB_PHASE_TEMP_A] = {
1651c287992SMathieu Othacehe 		.lsb = ISL29501_TEMP_COEFF_A,
1661c287992SMathieu Othacehe 	},
1671c287992SMathieu Othacehe 	[REG_CALIB_PHASE_TEMP_B] = {
1681c287992SMathieu Othacehe 		.lsb = ISL29501_TEMP_COEFF_B,
1691c287992SMathieu Othacehe 	},
1701c287992SMathieu Othacehe 	[REG_CALIB_PHASE_LIGHT_A] = {
1711c287992SMathieu Othacehe 		.lsb = ISL29501_AMBIANT_COEFF_A,
1721c287992SMathieu Othacehe 	},
1731c287992SMathieu Othacehe 	[REG_CALIB_PHASE_LIGHT_B] = {
1741c287992SMathieu Othacehe 		.lsb = ISL29501_AMBIANT_COEFF_B,
1751c287992SMathieu Othacehe 	},
1761c287992SMathieu Othacehe 	[REG_DISTANCE_BIAS] = {
1771c287992SMathieu Othacehe 		.msb = ISL29501_PHASE_OFFSET_MSB,
1781c287992SMathieu Othacehe 		.lsb = ISL29501_PHASE_OFFSET_LSB,
1791c287992SMathieu Othacehe 	},
1801c287992SMathieu Othacehe 	[REG_TEMPERATURE_BIAS] = {
1811c287992SMathieu Othacehe 		.lsb = ISL29501_TEMP_REFERENCE,
1821c287992SMathieu Othacehe 	},
1831c287992SMathieu Othacehe 	[REG_INT_TIME] = {
1841c287992SMathieu Othacehe 		.lsb = ISL29501_INTEGRATION_PERIOD,
1851c287992SMathieu Othacehe 	},
1861c287992SMathieu Othacehe 	[REG_SAMPLE_TIME] = {
1871c287992SMathieu Othacehe 		.lsb = ISL29501_SAMPLE_PERIOD,
1881c287992SMathieu Othacehe 	},
1891c287992SMathieu Othacehe 	[REG_DRIVER_RANGE] = {
1901c287992SMathieu Othacehe 		.lsb = ISL29501_DRIVER_RANGE,
1911c287992SMathieu Othacehe 	},
1921c287992SMathieu Othacehe 	[REG_EMITTER_DAC] = {
1931c287992SMathieu Othacehe 		.lsb = ISL29501_EMITTER_DAC,
1941c287992SMathieu Othacehe 	},
1951c287992SMathieu Othacehe };
1961c287992SMathieu Othacehe 
isl29501_register_read(struct isl29501_private * isl29501,enum isl29501_register_name name,u32 * val)1971c287992SMathieu Othacehe static int isl29501_register_read(struct isl29501_private *isl29501,
1981c287992SMathieu Othacehe 				  enum isl29501_register_name name,
1991c287992SMathieu Othacehe 				  u32 *val)
2001c287992SMathieu Othacehe {
2011c287992SMathieu Othacehe 	const struct isl29501_register_desc *reg = &isl29501_registers[name];
2021c287992SMathieu Othacehe 	u8 msb = 0, lsb = 0;
2031c287992SMathieu Othacehe 	s32 ret;
2041c287992SMathieu Othacehe 
2051c287992SMathieu Othacehe 	mutex_lock(&isl29501->lock);
2061c287992SMathieu Othacehe 	if (reg->msb) {
2071c287992SMathieu Othacehe 		ret = i2c_smbus_read_byte_data(isl29501->client, reg->msb);
2081c287992SMathieu Othacehe 		if (ret < 0)
2091c287992SMathieu Othacehe 			goto err;
2101c287992SMathieu Othacehe 		msb = ret;
2111c287992SMathieu Othacehe 	}
2121c287992SMathieu Othacehe 
2131c287992SMathieu Othacehe 	if (reg->lsb) {
2141c287992SMathieu Othacehe 		ret = i2c_smbus_read_byte_data(isl29501->client, reg->lsb);
2151c287992SMathieu Othacehe 		if (ret < 0)
2161c287992SMathieu Othacehe 			goto err;
2171c287992SMathieu Othacehe 		lsb = ret;
2181c287992SMathieu Othacehe 	}
2191c287992SMathieu Othacehe 	mutex_unlock(&isl29501->lock);
2201c287992SMathieu Othacehe 
2211c287992SMathieu Othacehe 	*val = (msb << 8) + lsb;
2221c287992SMathieu Othacehe 
2231c287992SMathieu Othacehe 	return 0;
2241c287992SMathieu Othacehe err:
2251c287992SMathieu Othacehe 	mutex_unlock(&isl29501->lock);
2261c287992SMathieu Othacehe 
2271c287992SMathieu Othacehe 	return ret;
2281c287992SMathieu Othacehe }
2291c287992SMathieu Othacehe 
isl29501_register_write(struct isl29501_private * isl29501,enum isl29501_register_name name,u32 value)2301c287992SMathieu Othacehe static u32 isl29501_register_write(struct isl29501_private *isl29501,
2311c287992SMathieu Othacehe 				   enum isl29501_register_name name,
2321c287992SMathieu Othacehe 				   u32 value)
2331c287992SMathieu Othacehe {
2341c287992SMathieu Othacehe 	const struct isl29501_register_desc *reg = &isl29501_registers[name];
2351c287992SMathieu Othacehe 	int ret;
2361c287992SMathieu Othacehe 
2371c287992SMathieu Othacehe 	if (!reg->msb && value > U8_MAX)
2381c287992SMathieu Othacehe 		return -ERANGE;
2391c287992SMathieu Othacehe 
2401c287992SMathieu Othacehe 	if (value > U16_MAX)
2411c287992SMathieu Othacehe 		return -ERANGE;
2421c287992SMathieu Othacehe 
2431c287992SMathieu Othacehe 	mutex_lock(&isl29501->lock);
2441c287992SMathieu Othacehe 	if (reg->msb) {
2451c287992SMathieu Othacehe 		ret = i2c_smbus_write_byte_data(isl29501->client,
24624493cceSGeert Uytterhoeven 						reg->msb, value >> 8);
2471c287992SMathieu Othacehe 		if (ret < 0)
2481c287992SMathieu Othacehe 			goto err;
2491c287992SMathieu Othacehe 	}
2501c287992SMathieu Othacehe 
25124493cceSGeert Uytterhoeven 	ret = i2c_smbus_write_byte_data(isl29501->client, reg->lsb, value);
2521c287992SMathieu Othacehe 
2531c287992SMathieu Othacehe err:
2541c287992SMathieu Othacehe 	mutex_unlock(&isl29501->lock);
2551c287992SMathieu Othacehe 	return ret;
2561c287992SMathieu Othacehe }
2571c287992SMathieu Othacehe 
isl29501_read_ext(struct iio_dev * indio_dev,uintptr_t private,const struct iio_chan_spec * chan,char * buf)2581c287992SMathieu Othacehe static ssize_t isl29501_read_ext(struct iio_dev *indio_dev,
2591c287992SMathieu Othacehe 				 uintptr_t private,
2601c287992SMathieu Othacehe 				 const struct iio_chan_spec *chan,
2611c287992SMathieu Othacehe 				 char *buf)
2621c287992SMathieu Othacehe {
2631c287992SMathieu Othacehe 	struct isl29501_private *isl29501 = iio_priv(indio_dev);
2641c287992SMathieu Othacehe 	enum isl29501_register_name reg = private;
2651c287992SMathieu Othacehe 	int ret;
2661c287992SMathieu Othacehe 	u32 value, gain, coeff, exp;
2671c287992SMathieu Othacehe 
2681c287992SMathieu Othacehe 	switch (reg) {
2691c287992SMathieu Othacehe 	case REG_GAIN:
2701c287992SMathieu Othacehe 	case REG_GAIN_BIAS:
2711c287992SMathieu Othacehe 		ret = isl29501_register_read(isl29501, reg, &gain);
2721c287992SMathieu Othacehe 		if (ret < 0)
2731c287992SMathieu Othacehe 			return ret;
2741c287992SMathieu Othacehe 
2751c287992SMathieu Othacehe 		value = gain;
2761c287992SMathieu Othacehe 		break;
2771c287992SMathieu Othacehe 	case REG_CALIB_PHASE_TEMP_A:
2781c287992SMathieu Othacehe 	case REG_CALIB_PHASE_TEMP_B:
2791c287992SMathieu Othacehe 	case REG_CALIB_PHASE_LIGHT_A:
2801c287992SMathieu Othacehe 	case REG_CALIB_PHASE_LIGHT_B:
2811c287992SMathieu Othacehe 		ret = isl29501_register_read(isl29501, REG_PHASE_EXP, &exp);
2821c287992SMathieu Othacehe 		if (ret < 0)
2831c287992SMathieu Othacehe 			return ret;
2841c287992SMathieu Othacehe 
2851c287992SMathieu Othacehe 		ret = isl29501_register_read(isl29501, reg, &coeff);
2861c287992SMathieu Othacehe 		if (ret < 0)
2871c287992SMathieu Othacehe 			return ret;
2881c287992SMathieu Othacehe 
2891c287992SMathieu Othacehe 		value = coeff << exp;
2901c287992SMathieu Othacehe 		break;
2911c287992SMathieu Othacehe 	default:
2921c287992SMathieu Othacehe 		return -EINVAL;
2931c287992SMathieu Othacehe 	}
2941c287992SMathieu Othacehe 
2951c287992SMathieu Othacehe 	return sprintf(buf, "%u\n", value);
2961c287992SMathieu Othacehe }
2971c287992SMathieu Othacehe 
isl29501_set_shadow_coeff(struct isl29501_private * isl29501,enum isl29501_register_name reg,unsigned int val)2981c287992SMathieu Othacehe static int isl29501_set_shadow_coeff(struct isl29501_private *isl29501,
2991c287992SMathieu Othacehe 				     enum isl29501_register_name reg,
3001c287992SMathieu Othacehe 				     unsigned int val)
3011c287992SMathieu Othacehe {
3021c287992SMathieu Othacehe 	enum isl29501_correction_coeff coeff;
3031c287992SMathieu Othacehe 
3041c287992SMathieu Othacehe 	switch (reg) {
3051c287992SMathieu Othacehe 	case REG_CALIB_PHASE_TEMP_A:
3061c287992SMathieu Othacehe 		coeff = COEFF_TEMP_A;
3071c287992SMathieu Othacehe 		break;
3081c287992SMathieu Othacehe 	case REG_CALIB_PHASE_TEMP_B:
3091c287992SMathieu Othacehe 		coeff = COEFF_TEMP_B;
3101c287992SMathieu Othacehe 		break;
3111c287992SMathieu Othacehe 	case REG_CALIB_PHASE_LIGHT_A:
3121c287992SMathieu Othacehe 		coeff = COEFF_LIGHT_A;
3131c287992SMathieu Othacehe 		break;
3141c287992SMathieu Othacehe 	case REG_CALIB_PHASE_LIGHT_B:
3151c287992SMathieu Othacehe 		coeff = COEFF_LIGHT_B;
3161c287992SMathieu Othacehe 		break;
3171c287992SMathieu Othacehe 	default:
3181c287992SMathieu Othacehe 		return -EINVAL;
3191c287992SMathieu Othacehe 	}
3201c287992SMathieu Othacehe 	isl29501->shadow_coeffs[coeff] = val;
3211c287992SMathieu Othacehe 
3221c287992SMathieu Othacehe 	return 0;
3231c287992SMathieu Othacehe }
3241c287992SMathieu Othacehe 
isl29501_write_coeff(struct isl29501_private * isl29501,enum isl29501_correction_coeff coeff,int val)3251c287992SMathieu Othacehe static int isl29501_write_coeff(struct isl29501_private *isl29501,
3261c287992SMathieu Othacehe 				enum isl29501_correction_coeff coeff,
3271c287992SMathieu Othacehe 				int val)
3281c287992SMathieu Othacehe {
3291c287992SMathieu Othacehe 	enum isl29501_register_name reg;
3301c287992SMathieu Othacehe 
3311c287992SMathieu Othacehe 	switch (coeff) {
3321c287992SMathieu Othacehe 	case COEFF_TEMP_A:
3331c287992SMathieu Othacehe 		reg = REG_CALIB_PHASE_TEMP_A;
3341c287992SMathieu Othacehe 		break;
3351c287992SMathieu Othacehe 	case COEFF_TEMP_B:
3361c287992SMathieu Othacehe 		reg = REG_CALIB_PHASE_TEMP_B;
3371c287992SMathieu Othacehe 		break;
3381c287992SMathieu Othacehe 	case COEFF_LIGHT_A:
3391c287992SMathieu Othacehe 		reg = REG_CALIB_PHASE_LIGHT_A;
3401c287992SMathieu Othacehe 		break;
3411c287992SMathieu Othacehe 	case COEFF_LIGHT_B:
3421c287992SMathieu Othacehe 		reg = REG_CALIB_PHASE_LIGHT_B;
3431c287992SMathieu Othacehe 		break;
3441c287992SMathieu Othacehe 	default:
3451c287992SMathieu Othacehe 		return -EINVAL;
3461c287992SMathieu Othacehe 	}
3471c287992SMathieu Othacehe 
3481c287992SMathieu Othacehe 	return isl29501_register_write(isl29501, reg, val);
3491c287992SMathieu Othacehe }
3501c287992SMathieu Othacehe 
isl29501_find_corr_exp(unsigned int val,unsigned int max_exp,unsigned int max_mantissa)3511c287992SMathieu Othacehe static unsigned int isl29501_find_corr_exp(unsigned int val,
3521c287992SMathieu Othacehe 					   unsigned int max_exp,
3531c287992SMathieu Othacehe 					   unsigned int max_mantissa)
3541c287992SMathieu Othacehe {
3551c287992SMathieu Othacehe 	unsigned int exp = 1;
3561c287992SMathieu Othacehe 
3571c287992SMathieu Othacehe 	/*
3581c287992SMathieu Othacehe 	 * Correction coefficients are represented under
3591c287992SMathieu Othacehe 	 * mantissa * 2^exponent form, where mantissa and exponent
3601c287992SMathieu Othacehe 	 * are stored in two separate registers of the sensor.
3611c287992SMathieu Othacehe 	 *
3621c287992SMathieu Othacehe 	 * Compute and return the lowest exponent such as:
3631c287992SMathieu Othacehe 	 *	     mantissa = value / 2^exponent
3641c287992SMathieu Othacehe 	 *
3651c287992SMathieu Othacehe 	 *  where mantissa < max_mantissa.
3661c287992SMathieu Othacehe 	 */
3671c287992SMathieu Othacehe 	if (val <= max_mantissa)
3681c287992SMathieu Othacehe 		return 0;
3691c287992SMathieu Othacehe 
3701c287992SMathieu Othacehe 	while ((val >> exp) > max_mantissa) {
3711c287992SMathieu Othacehe 		exp++;
3721c287992SMathieu Othacehe 
3731c287992SMathieu Othacehe 		if (exp > max_exp)
3741c287992SMathieu Othacehe 			return max_exp;
3751c287992SMathieu Othacehe 	}
3761c287992SMathieu Othacehe 
3771c287992SMathieu Othacehe 	return exp;
3781c287992SMathieu Othacehe }
3791c287992SMathieu Othacehe 
isl29501_write_ext(struct iio_dev * indio_dev,uintptr_t private,const struct iio_chan_spec * chan,const char * buf,size_t len)3801c287992SMathieu Othacehe static ssize_t isl29501_write_ext(struct iio_dev *indio_dev,
3811c287992SMathieu Othacehe 				  uintptr_t private,
3821c287992SMathieu Othacehe 				  const struct iio_chan_spec *chan,
3831c287992SMathieu Othacehe 				  const char *buf, size_t len)
3841c287992SMathieu Othacehe {
3851c287992SMathieu Othacehe 	struct isl29501_private *isl29501 = iio_priv(indio_dev);
3861c287992SMathieu Othacehe 	enum isl29501_register_name reg = private;
3871c287992SMathieu Othacehe 	unsigned int val;
3881c287992SMathieu Othacehe 	int max_exp = 0;
3891c287992SMathieu Othacehe 	int ret;
3901c287992SMathieu Othacehe 	int i;
3911c287992SMathieu Othacehe 
3921c287992SMathieu Othacehe 	ret = kstrtouint(buf, 10, &val);
3931c287992SMathieu Othacehe 	if (ret)
3941c287992SMathieu Othacehe 		return ret;
3951c287992SMathieu Othacehe 
3961c287992SMathieu Othacehe 	switch (reg) {
3971c287992SMathieu Othacehe 	case REG_GAIN_BIAS:
3981c287992SMathieu Othacehe 		if (val > U16_MAX)
3991c287992SMathieu Othacehe 			return -ERANGE;
4001c287992SMathieu Othacehe 
4011c287992SMathieu Othacehe 		ret = isl29501_register_write(isl29501, reg, val);
4021c287992SMathieu Othacehe 		if (ret < 0)
4031c287992SMathieu Othacehe 			return ret;
4041c287992SMathieu Othacehe 
4051c287992SMathieu Othacehe 		break;
4061c287992SMathieu Othacehe 	case REG_CALIB_PHASE_TEMP_A:
4071c287992SMathieu Othacehe 	case REG_CALIB_PHASE_TEMP_B:
4081c287992SMathieu Othacehe 	case REG_CALIB_PHASE_LIGHT_A:
4091c287992SMathieu Othacehe 	case REG_CALIB_PHASE_LIGHT_B:
4101c287992SMathieu Othacehe 
4111c287992SMathieu Othacehe 		if (val > (U8_MAX << ISL29501_MAX_EXP_VAL))
4121c287992SMathieu Othacehe 			return -ERANGE;
4131c287992SMathieu Othacehe 
4141c287992SMathieu Othacehe 		/* Store the correction coefficient under its exact form. */
4151c287992SMathieu Othacehe 		ret = isl29501_set_shadow_coeff(isl29501, reg, val);
4161c287992SMathieu Othacehe 		if (ret < 0)
4171c287992SMathieu Othacehe 			return ret;
4181c287992SMathieu Othacehe 
4191c287992SMathieu Othacehe 		/*
4201c287992SMathieu Othacehe 		 * Find the highest exponent needed to represent
4211c287992SMathieu Othacehe 		 * correction coefficients.
4221c287992SMathieu Othacehe 		 */
4231c287992SMathieu Othacehe 		for (i = 0; i < COEFF_MAX; i++) {
4241c287992SMathieu Othacehe 			int corr;
4251c287992SMathieu Othacehe 			int corr_exp;
4261c287992SMathieu Othacehe 
4271c287992SMathieu Othacehe 			corr = isl29501->shadow_coeffs[i];
4281c287992SMathieu Othacehe 			corr_exp = isl29501_find_corr_exp(corr,
4291c287992SMathieu Othacehe 							  ISL29501_MAX_EXP_VAL,
4301c287992SMathieu Othacehe 							  U8_MAX / 2);
4311c287992SMathieu Othacehe 			dev_dbg(&isl29501->client->dev,
4321c287992SMathieu Othacehe 				"found exp of corr(%d) = %d\n", corr, corr_exp);
4331c287992SMathieu Othacehe 
4341c287992SMathieu Othacehe 			max_exp = max(max_exp, corr_exp);
4351c287992SMathieu Othacehe 		}
4361c287992SMathieu Othacehe 
4371c287992SMathieu Othacehe 		/*
4381c287992SMathieu Othacehe 		 * Represent every correction coefficient under
4391c287992SMathieu Othacehe 		 * mantissa * 2^max_exponent form and force the
4401c287992SMathieu Othacehe 		 * writing of those coefficients on the sensor.
4411c287992SMathieu Othacehe 		 */
4421c287992SMathieu Othacehe 		for (i = 0; i < COEFF_MAX; i++) {
4431c287992SMathieu Othacehe 			int corr;
4441c287992SMathieu Othacehe 			int mantissa;
4451c287992SMathieu Othacehe 
4461c287992SMathieu Othacehe 			corr = isl29501->shadow_coeffs[i];
4471c287992SMathieu Othacehe 			if (!corr)
4481c287992SMathieu Othacehe 				continue;
4491c287992SMathieu Othacehe 
4501c287992SMathieu Othacehe 			mantissa = corr >> max_exp;
4511c287992SMathieu Othacehe 
4521c287992SMathieu Othacehe 			ret = isl29501_write_coeff(isl29501, i, mantissa);
4531c287992SMathieu Othacehe 			if (ret < 0)
4541c287992SMathieu Othacehe 				return ret;
4551c287992SMathieu Othacehe 		}
4561c287992SMathieu Othacehe 
4571c287992SMathieu Othacehe 		ret = isl29501_register_write(isl29501, REG_PHASE_EXP, max_exp);
4581c287992SMathieu Othacehe 		if (ret < 0)
4591c287992SMathieu Othacehe 			return ret;
4601c287992SMathieu Othacehe 
4611c287992SMathieu Othacehe 		break;
4621c287992SMathieu Othacehe 	default:
4631c287992SMathieu Othacehe 		return -EINVAL;
4641c287992SMathieu Othacehe 	}
4651c287992SMathieu Othacehe 
4661c287992SMathieu Othacehe 	return len;
4671c287992SMathieu Othacehe }
4681c287992SMathieu Othacehe 
4691c287992SMathieu Othacehe #define _ISL29501_EXT_INFO(_name, _ident) { \
4701c287992SMathieu Othacehe 	.name = _name, \
4711c287992SMathieu Othacehe 	.read = isl29501_read_ext, \
4721c287992SMathieu Othacehe 	.write = isl29501_write_ext, \
4731c287992SMathieu Othacehe 	.private = _ident, \
4741c287992SMathieu Othacehe 	.shared = IIO_SEPARATE, \
4751c287992SMathieu Othacehe }
4761c287992SMathieu Othacehe 
4771c287992SMathieu Othacehe static const struct iio_chan_spec_ext_info isl29501_ext_info[] = {
4781c287992SMathieu Othacehe 	_ISL29501_EXT_INFO("agc_gain", REG_GAIN),
4791c287992SMathieu Othacehe 	_ISL29501_EXT_INFO("agc_gain_bias", REG_GAIN_BIAS),
4801c287992SMathieu Othacehe 	_ISL29501_EXT_INFO("calib_phase_temp_a", REG_CALIB_PHASE_TEMP_A),
4811c287992SMathieu Othacehe 	_ISL29501_EXT_INFO("calib_phase_temp_b", REG_CALIB_PHASE_TEMP_B),
4821c287992SMathieu Othacehe 	_ISL29501_EXT_INFO("calib_phase_light_a", REG_CALIB_PHASE_LIGHT_A),
4831c287992SMathieu Othacehe 	_ISL29501_EXT_INFO("calib_phase_light_b", REG_CALIB_PHASE_LIGHT_B),
4841c287992SMathieu Othacehe 	{ },
4851c287992SMathieu Othacehe };
4861c287992SMathieu Othacehe 
4871c287992SMathieu Othacehe #define ISL29501_DISTANCE_SCAN_INDEX 0
4881c287992SMathieu Othacehe #define ISL29501_TIMESTAMP_SCAN_INDEX 1
4891c287992SMathieu Othacehe 
4901c287992SMathieu Othacehe static const struct iio_chan_spec isl29501_channels[] = {
4911c287992SMathieu Othacehe 	{
4921c287992SMathieu Othacehe 		.type = IIO_PROXIMITY,
4931c287992SMathieu Othacehe 		.scan_index = ISL29501_DISTANCE_SCAN_INDEX,
4941c287992SMathieu Othacehe 		.info_mask_separate =
4951c287992SMathieu Othacehe 			BIT(IIO_CHAN_INFO_RAW)   |
4961c287992SMathieu Othacehe 			BIT(IIO_CHAN_INFO_SCALE) |
4971c287992SMathieu Othacehe 			BIT(IIO_CHAN_INFO_CALIBBIAS),
4981c287992SMathieu Othacehe 		.scan_type = {
4991c287992SMathieu Othacehe 			.sign = 'u',
5001c287992SMathieu Othacehe 			.realbits = 16,
5011c287992SMathieu Othacehe 			.storagebits = 16,
5021c287992SMathieu Othacehe 			.endianness = IIO_CPU,
5031c287992SMathieu Othacehe 		},
5041c287992SMathieu Othacehe 		.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME) |
5051c287992SMathieu Othacehe 				BIT(IIO_CHAN_INFO_SAMP_FREQ),
5061c287992SMathieu Othacehe 		.ext_info = isl29501_ext_info,
5071c287992SMathieu Othacehe 	},
5081c287992SMathieu Othacehe 	{
5091c287992SMathieu Othacehe 		.type = IIO_PHASE,
5101c287992SMathieu Othacehe 		.scan_index = -1,
5111c287992SMathieu Othacehe 		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
5121c287992SMathieu Othacehe 				BIT(IIO_CHAN_INFO_SCALE),
5131c287992SMathieu Othacehe 	},
5141c287992SMathieu Othacehe 	{
5151c287992SMathieu Othacehe 		.type = IIO_CURRENT,
5161c287992SMathieu Othacehe 		.scan_index = -1,
5171c287992SMathieu Othacehe 		.output = 1,
5181c287992SMathieu Othacehe 		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
5191c287992SMathieu Othacehe 				BIT(IIO_CHAN_INFO_SCALE),
5201c287992SMathieu Othacehe 	},
5211c287992SMathieu Othacehe 	{
5221c287992SMathieu Othacehe 		.type = IIO_TEMP,
5231c287992SMathieu Othacehe 		.scan_index = -1,
5241c287992SMathieu Othacehe 		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
5251c287992SMathieu Othacehe 				BIT(IIO_CHAN_INFO_SCALE)     |
5261c287992SMathieu Othacehe 				BIT(IIO_CHAN_INFO_CALIBBIAS),
5271c287992SMathieu Othacehe 	},
5281c287992SMathieu Othacehe 	{
5291c287992SMathieu Othacehe 		.type = IIO_INTENSITY,
5301c287992SMathieu Othacehe 		.scan_index = -1,
5311c287992SMathieu Othacehe 		.modified = 1,
5321c287992SMathieu Othacehe 		.channel2 = IIO_MOD_LIGHT_CLEAR,
5331c287992SMathieu Othacehe 		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
5341c287992SMathieu Othacehe 				BIT(IIO_CHAN_INFO_SCALE),
5351c287992SMathieu Othacehe 	},
5361c287992SMathieu Othacehe 	IIO_CHAN_SOFT_TIMESTAMP(ISL29501_TIMESTAMP_SCAN_INDEX),
5371c287992SMathieu Othacehe };
5381c287992SMathieu Othacehe 
isl29501_reset_registers(struct isl29501_private * isl29501)5391c287992SMathieu Othacehe static int isl29501_reset_registers(struct isl29501_private *isl29501)
5401c287992SMathieu Othacehe {
5411c287992SMathieu Othacehe 	int ret;
5421c287992SMathieu Othacehe 
5431c287992SMathieu Othacehe 	ret = i2c_smbus_write_byte_data(isl29501->client,
5441c287992SMathieu Othacehe 					ISL29501_COMMAND_REGISTER,
5451c287992SMathieu Othacehe 					ISL29501_RESET_ALL_REGISTERS);
5461c287992SMathieu Othacehe 	if (ret < 0) {
5471c287992SMathieu Othacehe 		dev_err(&isl29501->client->dev,
5481c287992SMathieu Othacehe 			"cannot reset registers %d\n", ret);
5491c287992SMathieu Othacehe 		return ret;
5501c287992SMathieu Othacehe 	}
5511c287992SMathieu Othacehe 
5521c287992SMathieu Othacehe 	ret = i2c_smbus_write_byte_data(isl29501->client,
5531c287992SMathieu Othacehe 					ISL29501_COMMAND_REGISTER,
5541c287992SMathieu Othacehe 					ISL29501_RESET_INT_SM);
5551c287992SMathieu Othacehe 	if (ret < 0)
5561c287992SMathieu Othacehe 		dev_err(&isl29501->client->dev,
5571c287992SMathieu Othacehe 			"cannot reset state machine %d\n", ret);
5581c287992SMathieu Othacehe 
5591c287992SMathieu Othacehe 	return ret;
5601c287992SMathieu Othacehe }
5611c287992SMathieu Othacehe 
isl29501_begin_acquisition(struct isl29501_private * isl29501)5621c287992SMathieu Othacehe static int isl29501_begin_acquisition(struct isl29501_private *isl29501)
5631c287992SMathieu Othacehe {
5641c287992SMathieu Othacehe 	int ret;
5651c287992SMathieu Othacehe 
5661c287992SMathieu Othacehe 	ret = i2c_smbus_write_byte_data(isl29501->client,
5671c287992SMathieu Othacehe 					ISL29501_COMMAND_REGISTER,
5681c287992SMathieu Othacehe 					ISL29501_EMUL_SAMPLE_START_PIN);
5691c287992SMathieu Othacehe 	if (ret < 0)
5701c287992SMathieu Othacehe 		dev_err(&isl29501->client->dev,
5711c287992SMathieu Othacehe 			"cannot begin acquisition %d\n", ret);
5721c287992SMathieu Othacehe 
5731c287992SMathieu Othacehe 	return ret;
5741c287992SMathieu Othacehe }
5751c287992SMathieu Othacehe 
5761c287992SMathieu Othacehe static IIO_CONST_ATTR_INT_TIME_AVAIL(ISL29501_INT_TIME_AVAILABLE);
5771c287992SMathieu Othacehe static IIO_CONST_ATTR(out_current_scale_available,
5781c287992SMathieu Othacehe 		      ISL29501_CURRENT_SCALE_AVAILABLE);
5791c287992SMathieu Othacehe 
5801c287992SMathieu Othacehe static struct attribute *isl29501_attributes[] = {
5811c287992SMathieu Othacehe 	&iio_const_attr_integration_time_available.dev_attr.attr,
5821c287992SMathieu Othacehe 	&iio_const_attr_out_current_scale_available.dev_attr.attr,
5831c287992SMathieu Othacehe 	NULL
5841c287992SMathieu Othacehe };
5851c287992SMathieu Othacehe 
5861c287992SMathieu Othacehe static const struct attribute_group isl29501_attribute_group = {
5871c287992SMathieu Othacehe 	.attrs = isl29501_attributes,
5881c287992SMathieu Othacehe };
5891c287992SMathieu Othacehe 
5901c287992SMathieu Othacehe static const int isl29501_current_scale_table[][2] = {
5911c287992SMathieu Othacehe 	{0, 3900}, {0, 7800}, {0, 11800}, {0, 15700},
5921c287992SMathieu Othacehe 	{0, 19600}, {0, 23500}, {0, 27500}, {0, 31400},
5931c287992SMathieu Othacehe 	{0, 35200}, {0, 39200}, {0, 43100}, {0, 47100},
5941c287992SMathieu Othacehe 	{0, 51000}, {0, 54900}, {0, 58800},
5951c287992SMathieu Othacehe };
5961c287992SMathieu Othacehe 
5971c287992SMathieu Othacehe static const int isl29501_int_time[][2] = {
5981c287992SMathieu Othacehe 	{0, 70},    /* 0.07 ms */
5991c287992SMathieu Othacehe 	{0, 140},   /* 0.14 ms */
6001c287992SMathieu Othacehe 	{0, 280},   /* 0.28 ms */
6011c287992SMathieu Othacehe 	{0, 570},   /* 0.57 ms */
6021c287992SMathieu Othacehe 	{0, 1140},  /* 1.14 ms */
6031c287992SMathieu Othacehe 	{0, 2280},  /* 2.28 ms */
6041c287992SMathieu Othacehe 	{0, 4550},  /* 4.55 ms */
6051c287992SMathieu Othacehe 	{0, 9100},  /* 9.11 ms */
6061c287992SMathieu Othacehe 	{0, 18200}, /* 18.2 ms */
6071c287992SMathieu Othacehe 	{0, 36400}, /* 36.4 ms */
6081c287992SMathieu Othacehe 	{0, 72810}, /* 72.81 ms */
6091c287992SMathieu Othacehe 	{0, 145610} /* 145.28 ms */
6101c287992SMathieu Othacehe };
6111c287992SMathieu Othacehe 
isl29501_get_raw(struct isl29501_private * isl29501,const struct iio_chan_spec * chan,int * raw)6121c287992SMathieu Othacehe static int isl29501_get_raw(struct isl29501_private *isl29501,
6131c287992SMathieu Othacehe 			    const struct iio_chan_spec *chan,
6141c287992SMathieu Othacehe 			    int *raw)
6151c287992SMathieu Othacehe {
6161c287992SMathieu Othacehe 	int ret;
6171c287992SMathieu Othacehe 
6181c287992SMathieu Othacehe 	switch (chan->type) {
6191c287992SMathieu Othacehe 	case IIO_PROXIMITY:
6201c287992SMathieu Othacehe 		ret = isl29501_register_read(isl29501, REG_DISTANCE, raw);
6211c287992SMathieu Othacehe 		if (ret < 0)
6221c287992SMathieu Othacehe 			return ret;
6231c287992SMathieu Othacehe 
6241c287992SMathieu Othacehe 		return IIO_VAL_INT;
6251c287992SMathieu Othacehe 	case IIO_INTENSITY:
6261c287992SMathieu Othacehe 		ret = isl29501_register_read(isl29501,
6271c287992SMathieu Othacehe 					     REG_AMBIENT_LIGHT,
6281c287992SMathieu Othacehe 					     raw);
6291c287992SMathieu Othacehe 		if (ret < 0)
6301c287992SMathieu Othacehe 			return ret;
6311c287992SMathieu Othacehe 
6321c287992SMathieu Othacehe 		return IIO_VAL_INT;
6331c287992SMathieu Othacehe 	case IIO_PHASE:
6341c287992SMathieu Othacehe 		ret = isl29501_register_read(isl29501, REG_PHASE, raw);
6351c287992SMathieu Othacehe 		if (ret < 0)
6361c287992SMathieu Othacehe 			return ret;
6371c287992SMathieu Othacehe 
6381c287992SMathieu Othacehe 		return IIO_VAL_INT;
6391c287992SMathieu Othacehe 	case IIO_CURRENT:
6401c287992SMathieu Othacehe 		ret = isl29501_register_read(isl29501, REG_EMITTER_DAC, raw);
6411c287992SMathieu Othacehe 		if (ret < 0)
6421c287992SMathieu Othacehe 			return ret;
6431c287992SMathieu Othacehe 
6441c287992SMathieu Othacehe 		return IIO_VAL_INT;
6451c287992SMathieu Othacehe 	case IIO_TEMP:
6461c287992SMathieu Othacehe 		ret = isl29501_register_read(isl29501, REG_TEMPERATURE, raw);
6471c287992SMathieu Othacehe 		if (ret < 0)
6481c287992SMathieu Othacehe 			return ret;
6491c287992SMathieu Othacehe 
6501c287992SMathieu Othacehe 		return IIO_VAL_INT;
6511c287992SMathieu Othacehe 	default:
6521c287992SMathieu Othacehe 		return -EINVAL;
6531c287992SMathieu Othacehe 	}
6541c287992SMathieu Othacehe }
6551c287992SMathieu Othacehe 
isl29501_get_scale(struct isl29501_private * isl29501,const struct iio_chan_spec * chan,int * val,int * val2)6561c287992SMathieu Othacehe static int isl29501_get_scale(struct isl29501_private *isl29501,
6571c287992SMathieu Othacehe 			      const struct iio_chan_spec *chan,
6581c287992SMathieu Othacehe 			      int *val, int *val2)
6591c287992SMathieu Othacehe {
6601c287992SMathieu Othacehe 	int ret;
6611c287992SMathieu Othacehe 	u32 current_scale;
6621c287992SMathieu Othacehe 
6631c287992SMathieu Othacehe 	switch (chan->type) {
6641c287992SMathieu Othacehe 	case IIO_PROXIMITY:
6651c287992SMathieu Othacehe 		/* distance = raw_distance * 33.31 / 65536 (m) */
6661c287992SMathieu Othacehe 		*val = 3331;
6671c287992SMathieu Othacehe 		*val2 = 6553600;
6681c287992SMathieu Othacehe 
6691c287992SMathieu Othacehe 		return IIO_VAL_FRACTIONAL;
6701c287992SMathieu Othacehe 	case IIO_PHASE:
6711c287992SMathieu Othacehe 		/* phase = raw_phase * 2pi / 65536 (rad) */
6721c287992SMathieu Othacehe 		*val = 0;
6731c287992SMathieu Othacehe 		*val2 = 95874;
6741c287992SMathieu Othacehe 
6751c287992SMathieu Othacehe 		return IIO_VAL_INT_PLUS_NANO;
6761c287992SMathieu Othacehe 	case IIO_INTENSITY:
6771c287992SMathieu Othacehe 		/* light = raw_light * 35 / 10000 (mA) */
6781c287992SMathieu Othacehe 		*val = 35;
6791c287992SMathieu Othacehe 		*val2 = 10000;
6801c287992SMathieu Othacehe 
6811c287992SMathieu Othacehe 		return IIO_VAL_FRACTIONAL;
6821c287992SMathieu Othacehe 	case IIO_CURRENT:
6831c287992SMathieu Othacehe 		ret = isl29501_register_read(isl29501,
6841c287992SMathieu Othacehe 					     REG_DRIVER_RANGE,
6851c287992SMathieu Othacehe 					     &current_scale);
6861c287992SMathieu Othacehe 		if (ret < 0)
6871c287992SMathieu Othacehe 			return ret;
6881c287992SMathieu Othacehe 
6891c287992SMathieu Othacehe 		if (current_scale > ARRAY_SIZE(isl29501_current_scale_table))
6901c287992SMathieu Othacehe 			return -EINVAL;
6911c287992SMathieu Othacehe 
6921c287992SMathieu Othacehe 		if (!current_scale) {
6931c287992SMathieu Othacehe 			*val = 0;
6941c287992SMathieu Othacehe 			*val2 = 0;
6951c287992SMathieu Othacehe 			return IIO_VAL_INT;
6961c287992SMathieu Othacehe 		}
6971c287992SMathieu Othacehe 
6981c287992SMathieu Othacehe 		*val = isl29501_current_scale_table[current_scale - 1][0];
6991c287992SMathieu Othacehe 		*val2 = isl29501_current_scale_table[current_scale - 1][1];
7001c287992SMathieu Othacehe 
7011c287992SMathieu Othacehe 		return IIO_VAL_INT_PLUS_MICRO;
7021c287992SMathieu Othacehe 	case IIO_TEMP:
7031c287992SMathieu Othacehe 		/* temperature = raw_temperature * 125 / 100000 (milli °C) */
7041c287992SMathieu Othacehe 		*val = 125;
7051c287992SMathieu Othacehe 		*val2 = 100000;
7061c287992SMathieu Othacehe 
7071c287992SMathieu Othacehe 		return IIO_VAL_FRACTIONAL;
7081c287992SMathieu Othacehe 	default:
7091c287992SMathieu Othacehe 		return -EINVAL;
7101c287992SMathieu Othacehe 	}
7111c287992SMathieu Othacehe }
7121c287992SMathieu Othacehe 
isl29501_get_calibbias(struct isl29501_private * isl29501,const struct iio_chan_spec * chan,int * bias)7131c287992SMathieu Othacehe static int isl29501_get_calibbias(struct isl29501_private *isl29501,
7141c287992SMathieu Othacehe 				  const struct iio_chan_spec *chan,
7151c287992SMathieu Othacehe 				  int *bias)
7161c287992SMathieu Othacehe {
7171c287992SMathieu Othacehe 	switch (chan->type) {
7181c287992SMathieu Othacehe 	case IIO_PROXIMITY:
7191c287992SMathieu Othacehe 		return isl29501_register_read(isl29501,
7201c287992SMathieu Othacehe 					      REG_DISTANCE_BIAS,
7211c287992SMathieu Othacehe 					      bias);
7221c287992SMathieu Othacehe 	case IIO_TEMP:
7231c287992SMathieu Othacehe 		return isl29501_register_read(isl29501,
7241c287992SMathieu Othacehe 					      REG_TEMPERATURE_BIAS,
7251c287992SMathieu Othacehe 					      bias);
7261c287992SMathieu Othacehe 	default:
7271c287992SMathieu Othacehe 		return -EINVAL;
7281c287992SMathieu Othacehe 	}
7291c287992SMathieu Othacehe }
7301c287992SMathieu Othacehe 
isl29501_get_inttime(struct isl29501_private * isl29501,int * val,int * val2)7311c287992SMathieu Othacehe static int isl29501_get_inttime(struct isl29501_private *isl29501,
7321c287992SMathieu Othacehe 				int *val, int *val2)
7331c287992SMathieu Othacehe {
7341c287992SMathieu Othacehe 	int ret;
7351c287992SMathieu Othacehe 	u32 inttime;
7361c287992SMathieu Othacehe 
7371c287992SMathieu Othacehe 	ret = isl29501_register_read(isl29501, REG_INT_TIME, &inttime);
7381c287992SMathieu Othacehe 	if (ret < 0)
7391c287992SMathieu Othacehe 		return ret;
7401c287992SMathieu Othacehe 
7411c287992SMathieu Othacehe 	if (inttime >= ARRAY_SIZE(isl29501_int_time))
7421c287992SMathieu Othacehe 		return -EINVAL;
7431c287992SMathieu Othacehe 
7441c287992SMathieu Othacehe 	*val = isl29501_int_time[inttime][0];
7451c287992SMathieu Othacehe 	*val2 = isl29501_int_time[inttime][1];
7461c287992SMathieu Othacehe 
7471c287992SMathieu Othacehe 	return IIO_VAL_INT_PLUS_MICRO;
7481c287992SMathieu Othacehe }
7491c287992SMathieu Othacehe 
isl29501_get_freq(struct isl29501_private * isl29501,int * val,int * val2)7501c287992SMathieu Othacehe static int isl29501_get_freq(struct isl29501_private *isl29501,
7511c287992SMathieu Othacehe 			     int *val, int *val2)
7521c287992SMathieu Othacehe {
7531c287992SMathieu Othacehe 	int ret;
7541c287992SMathieu Othacehe 	int sample_time;
7551c287992SMathieu Othacehe 	unsigned long long freq;
7561c287992SMathieu Othacehe 	u32 temp;
7571c287992SMathieu Othacehe 
7581c287992SMathieu Othacehe 	ret = isl29501_register_read(isl29501, REG_SAMPLE_TIME, &sample_time);
7591c287992SMathieu Othacehe 	if (ret < 0)
7601c287992SMathieu Othacehe 		return ret;
7611c287992SMathieu Othacehe 
7621c287992SMathieu Othacehe 	/* freq = 1 / (0.000450 * (sample_time + 1) * 10^-6) */
7631c287992SMathieu Othacehe 	freq = 1000000ULL * 1000000ULL;
7641c287992SMathieu Othacehe 
7651c287992SMathieu Othacehe 	do_div(freq, 450 * (sample_time + 1));
7661c287992SMathieu Othacehe 
7671c287992SMathieu Othacehe 	temp = do_div(freq, 1000000);
7681c287992SMathieu Othacehe 	*val = freq;
7691c287992SMathieu Othacehe 	*val2 = temp;
7701c287992SMathieu Othacehe 
7711c287992SMathieu Othacehe 	return IIO_VAL_INT_PLUS_MICRO;
7721c287992SMathieu Othacehe }
7731c287992SMathieu Othacehe 
isl29501_read_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int * val,int * val2,long mask)7741c287992SMathieu Othacehe static int isl29501_read_raw(struct iio_dev *indio_dev,
7751c287992SMathieu Othacehe 			     struct iio_chan_spec const *chan, int *val,
7761c287992SMathieu Othacehe 			     int *val2, long mask)
7771c287992SMathieu Othacehe {
7781c287992SMathieu Othacehe 	struct isl29501_private *isl29501 = iio_priv(indio_dev);
7791c287992SMathieu Othacehe 
7801c287992SMathieu Othacehe 	switch (mask) {
7811c287992SMathieu Othacehe 	case IIO_CHAN_INFO_RAW:
7821c287992SMathieu Othacehe 		return isl29501_get_raw(isl29501, chan, val);
7831c287992SMathieu Othacehe 	case IIO_CHAN_INFO_SCALE:
7841c287992SMathieu Othacehe 		return isl29501_get_scale(isl29501, chan, val, val2);
7851c287992SMathieu Othacehe 	case IIO_CHAN_INFO_INT_TIME:
7861c287992SMathieu Othacehe 		return isl29501_get_inttime(isl29501, val, val2);
7871c287992SMathieu Othacehe 	case IIO_CHAN_INFO_SAMP_FREQ:
7881c287992SMathieu Othacehe 		return isl29501_get_freq(isl29501, val, val2);
7891c287992SMathieu Othacehe 	case IIO_CHAN_INFO_CALIBBIAS:
7901c287992SMathieu Othacehe 		return isl29501_get_calibbias(isl29501, chan, val);
7911c287992SMathieu Othacehe 	default:
7921c287992SMathieu Othacehe 		return -EINVAL;
7931c287992SMathieu Othacehe 	}
7941c287992SMathieu Othacehe }
7951c287992SMathieu Othacehe 
isl29501_set_raw(struct isl29501_private * isl29501,const struct iio_chan_spec * chan,int raw)7961c287992SMathieu Othacehe static int isl29501_set_raw(struct isl29501_private *isl29501,
7971c287992SMathieu Othacehe 			    const struct iio_chan_spec *chan,
7981c287992SMathieu Othacehe 			    int raw)
7991c287992SMathieu Othacehe {
8001c287992SMathieu Othacehe 	switch (chan->type) {
8011c287992SMathieu Othacehe 	case IIO_CURRENT:
8021c287992SMathieu Othacehe 		return isl29501_register_write(isl29501, REG_EMITTER_DAC, raw);
8031c287992SMathieu Othacehe 	default:
8041c287992SMathieu Othacehe 		return -EINVAL;
8051c287992SMathieu Othacehe 	}
8061c287992SMathieu Othacehe }
8071c287992SMathieu Othacehe 
isl29501_set_inttime(struct isl29501_private * isl29501,int val,int val2)8081c287992SMathieu Othacehe static int isl29501_set_inttime(struct isl29501_private *isl29501,
8091c287992SMathieu Othacehe 				int val, int val2)
8101c287992SMathieu Othacehe {
8111c287992SMathieu Othacehe 	int i;
8121c287992SMathieu Othacehe 
8131c287992SMathieu Othacehe 	for (i = 0; i < ARRAY_SIZE(isl29501_int_time); i++) {
8141c287992SMathieu Othacehe 		if (isl29501_int_time[i][0] == val &&
8151c287992SMathieu Othacehe 		    isl29501_int_time[i][1] == val2) {
8161c287992SMathieu Othacehe 			return isl29501_register_write(isl29501,
8171c287992SMathieu Othacehe 						       REG_INT_TIME,
8181c287992SMathieu Othacehe 						       i);
8191c287992SMathieu Othacehe 		}
8201c287992SMathieu Othacehe 	}
8211c287992SMathieu Othacehe 
8221c287992SMathieu Othacehe 	return -EINVAL;
8231c287992SMathieu Othacehe }
8241c287992SMathieu Othacehe 
isl29501_set_scale(struct isl29501_private * isl29501,const struct iio_chan_spec * chan,int val,int val2)8251c287992SMathieu Othacehe static int isl29501_set_scale(struct isl29501_private *isl29501,
8261c287992SMathieu Othacehe 			      const struct iio_chan_spec *chan,
8271c287992SMathieu Othacehe 			      int val, int val2)
8281c287992SMathieu Othacehe {
8291c287992SMathieu Othacehe 	int i;
8301c287992SMathieu Othacehe 
8311c287992SMathieu Othacehe 	if (chan->type != IIO_CURRENT)
8321c287992SMathieu Othacehe 		return -EINVAL;
8331c287992SMathieu Othacehe 
8341c287992SMathieu Othacehe 	for (i = 0; i < ARRAY_SIZE(isl29501_current_scale_table); i++) {
8351c287992SMathieu Othacehe 		if (isl29501_current_scale_table[i][0] == val &&
8361c287992SMathieu Othacehe 		    isl29501_current_scale_table[i][1] == val2) {
8371c287992SMathieu Othacehe 			return isl29501_register_write(isl29501,
8381c287992SMathieu Othacehe 						       REG_DRIVER_RANGE,
8391c287992SMathieu Othacehe 						       i + 1);
8401c287992SMathieu Othacehe 		}
8411c287992SMathieu Othacehe 	}
8421c287992SMathieu Othacehe 
8431c287992SMathieu Othacehe 	return -EINVAL;
8441c287992SMathieu Othacehe }
8451c287992SMathieu Othacehe 
isl29501_set_calibbias(struct isl29501_private * isl29501,const struct iio_chan_spec * chan,int bias)8461c287992SMathieu Othacehe static int isl29501_set_calibbias(struct isl29501_private *isl29501,
8471c287992SMathieu Othacehe 				  const struct iio_chan_spec *chan,
8481c287992SMathieu Othacehe 				  int bias)
8491c287992SMathieu Othacehe {
8501c287992SMathieu Othacehe 	switch (chan->type) {
8511c287992SMathieu Othacehe 	case IIO_PROXIMITY:
8521c287992SMathieu Othacehe 		return isl29501_register_write(isl29501,
8531c287992SMathieu Othacehe 					      REG_DISTANCE_BIAS,
8541c287992SMathieu Othacehe 					      bias);
8551c287992SMathieu Othacehe 	case IIO_TEMP:
8561c287992SMathieu Othacehe 		return isl29501_register_write(isl29501,
8571c287992SMathieu Othacehe 					       REG_TEMPERATURE_BIAS,
8581c287992SMathieu Othacehe 					       bias);
8591c287992SMathieu Othacehe 	default:
8601c287992SMathieu Othacehe 		return -EINVAL;
8611c287992SMathieu Othacehe 	}
8621c287992SMathieu Othacehe }
8631c287992SMathieu Othacehe 
isl29501_set_freq(struct isl29501_private * isl29501,int val,int val2)8641c287992SMathieu Othacehe static int isl29501_set_freq(struct isl29501_private *isl29501,
8651c287992SMathieu Othacehe 			     int val, int val2)
8661c287992SMathieu Othacehe {
8671c287992SMathieu Othacehe 	int freq;
8681c287992SMathieu Othacehe 	unsigned long long sample_time;
8691c287992SMathieu Othacehe 
8701c287992SMathieu Othacehe 	/* sample_freq = 1 / (0.000450 * (sample_time + 1) * 10^-6) */
8711c287992SMathieu Othacehe 	freq = val * 1000000 + val2 % 1000000;
8721c287992SMathieu Othacehe 	sample_time = 2222ULL * 1000000ULL;
8731c287992SMathieu Othacehe 	do_div(sample_time, freq);
8741c287992SMathieu Othacehe 
8751c287992SMathieu Othacehe 	sample_time -= 1;
8761c287992SMathieu Othacehe 
8771c287992SMathieu Othacehe 	if (sample_time > 255)
8781c287992SMathieu Othacehe 		return -ERANGE;
8791c287992SMathieu Othacehe 
8801c287992SMathieu Othacehe 	return isl29501_register_write(isl29501, REG_SAMPLE_TIME, sample_time);
8811c287992SMathieu Othacehe }
8821c287992SMathieu Othacehe 
isl29501_write_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int val,int val2,long mask)8831c287992SMathieu Othacehe static int isl29501_write_raw(struct iio_dev *indio_dev,
8841c287992SMathieu Othacehe 			      struct iio_chan_spec const *chan,
8851c287992SMathieu Othacehe 			      int val, int val2, long mask)
8861c287992SMathieu Othacehe {
8871c287992SMathieu Othacehe 	struct isl29501_private *isl29501 = iio_priv(indio_dev);
8881c287992SMathieu Othacehe 
8891c287992SMathieu Othacehe 	switch (mask) {
8901c287992SMathieu Othacehe 	case IIO_CHAN_INFO_RAW:
8911c287992SMathieu Othacehe 		return isl29501_set_raw(isl29501, chan, val);
8921c287992SMathieu Othacehe 	case IIO_CHAN_INFO_INT_TIME:
8931c287992SMathieu Othacehe 		return isl29501_set_inttime(isl29501, val, val2);
8941c287992SMathieu Othacehe 	case IIO_CHAN_INFO_SAMP_FREQ:
8951c287992SMathieu Othacehe 		return isl29501_set_freq(isl29501, val, val2);
8961c287992SMathieu Othacehe 	case IIO_CHAN_INFO_SCALE:
8971c287992SMathieu Othacehe 		return isl29501_set_scale(isl29501, chan, val, val2);
8981c287992SMathieu Othacehe 	case IIO_CHAN_INFO_CALIBBIAS:
8991c287992SMathieu Othacehe 		return isl29501_set_calibbias(isl29501, chan, val);
9001c287992SMathieu Othacehe 	default:
9011c287992SMathieu Othacehe 		return -EINVAL;
9021c287992SMathieu Othacehe 	}
9031c287992SMathieu Othacehe }
9041c287992SMathieu Othacehe 
9051c287992SMathieu Othacehe static const struct iio_info isl29501_info = {
9061c287992SMathieu Othacehe 	.read_raw = &isl29501_read_raw,
9071c287992SMathieu Othacehe 	.write_raw = &isl29501_write_raw,
9081c287992SMathieu Othacehe 	.attrs = &isl29501_attribute_group,
9091c287992SMathieu Othacehe };
9101c287992SMathieu Othacehe 
isl29501_init_chip(struct isl29501_private * isl29501)9111c287992SMathieu Othacehe static int isl29501_init_chip(struct isl29501_private *isl29501)
9121c287992SMathieu Othacehe {
9131c287992SMathieu Othacehe 	int ret;
9141c287992SMathieu Othacehe 
9151c287992SMathieu Othacehe 	ret = i2c_smbus_read_byte_data(isl29501->client, ISL29501_DEVICE_ID);
9161c287992SMathieu Othacehe 	if (ret < 0) {
9171c287992SMathieu Othacehe 		dev_err(&isl29501->client->dev, "Error reading device id\n");
9181c287992SMathieu Othacehe 		return ret;
9191c287992SMathieu Othacehe 	}
9201c287992SMathieu Othacehe 
9211c287992SMathieu Othacehe 	if (ret != ISL29501_ID) {
9221c287992SMathieu Othacehe 		dev_err(&isl29501->client->dev,
9231c287992SMathieu Othacehe 			"Wrong chip id, got %x expected %x\n",
9241c287992SMathieu Othacehe 			ret, ISL29501_DEVICE_ID);
9251c287992SMathieu Othacehe 		return -ENODEV;
9261c287992SMathieu Othacehe 	}
9271c287992SMathieu Othacehe 
9281c287992SMathieu Othacehe 	ret = isl29501_reset_registers(isl29501);
9291c287992SMathieu Othacehe 	if (ret < 0)
9301c287992SMathieu Othacehe 		return ret;
9311c287992SMathieu Othacehe 
9321c287992SMathieu Othacehe 	return isl29501_begin_acquisition(isl29501);
9331c287992SMathieu Othacehe }
9341c287992SMathieu Othacehe 
isl29501_trigger_handler(int irq,void * p)9351c287992SMathieu Othacehe static irqreturn_t isl29501_trigger_handler(int irq, void *p)
9361c287992SMathieu Othacehe {
9371c287992SMathieu Othacehe 	struct iio_poll_func *pf = p;
9381c287992SMathieu Othacehe 	struct iio_dev *indio_dev = pf->indio_dev;
9391c287992SMathieu Othacehe 	struct isl29501_private *isl29501 = iio_priv(indio_dev);
9401c287992SMathieu Othacehe 	const unsigned long *active_mask = indio_dev->active_scan_mask;
94192babc99SJonathan Cameron 	u32 buffer[4] __aligned(8) = {}; /* 1x16-bit + naturally aligned ts */
9421c287992SMathieu Othacehe 
9431c287992SMathieu Othacehe 	if (test_bit(ISL29501_DISTANCE_SCAN_INDEX, active_mask))
9441c287992SMathieu Othacehe 		isl29501_register_read(isl29501, REG_DISTANCE, buffer);
9451c287992SMathieu Othacehe 
9461c287992SMathieu Othacehe 	iio_push_to_buffers_with_timestamp(indio_dev, buffer, pf->timestamp);
9471c287992SMathieu Othacehe 	iio_trigger_notify_done(indio_dev->trig);
9481c287992SMathieu Othacehe 
9491c287992SMathieu Othacehe 	return IRQ_HANDLED;
9501c287992SMathieu Othacehe }
9511c287992SMathieu Othacehe 
isl29501_probe(struct i2c_client * client)9529d6f774dSUwe Kleine-König static int isl29501_probe(struct i2c_client *client)
9531c287992SMathieu Othacehe {
9541c287992SMathieu Othacehe 	struct iio_dev *indio_dev;
9551c287992SMathieu Othacehe 	struct isl29501_private *isl29501;
9561c287992SMathieu Othacehe 	int ret;
9571c287992SMathieu Othacehe 
9581c287992SMathieu Othacehe 	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*isl29501));
9591c287992SMathieu Othacehe 	if (!indio_dev)
9601c287992SMathieu Othacehe 		return -ENOMEM;
9611c287992SMathieu Othacehe 
9621c287992SMathieu Othacehe 	isl29501 = iio_priv(indio_dev);
9631c287992SMathieu Othacehe 
9641c287992SMathieu Othacehe 	i2c_set_clientdata(client, indio_dev);
9651c287992SMathieu Othacehe 	isl29501->client = client;
9661c287992SMathieu Othacehe 
9671c287992SMathieu Othacehe 	mutex_init(&isl29501->lock);
9681c287992SMathieu Othacehe 
9691c287992SMathieu Othacehe 	ret = isl29501_init_chip(isl29501);
9701c287992SMathieu Othacehe 	if (ret < 0)
9711c287992SMathieu Othacehe 		return ret;
9721c287992SMathieu Othacehe 
9731c287992SMathieu Othacehe 	indio_dev->modes = INDIO_DIRECT_MODE;
9741c287992SMathieu Othacehe 	indio_dev->channels = isl29501_channels;
9751c287992SMathieu Othacehe 	indio_dev->num_channels = ARRAY_SIZE(isl29501_channels);
9761c287992SMathieu Othacehe 	indio_dev->name = client->name;
9771c287992SMathieu Othacehe 	indio_dev->info = &isl29501_info;
9781c287992SMathieu Othacehe 
9791c287992SMathieu Othacehe 	ret = devm_iio_triggered_buffer_setup(&client->dev, indio_dev,
9801c287992SMathieu Othacehe 					      iio_pollfunc_store_time,
9811c287992SMathieu Othacehe 					      isl29501_trigger_handler,
9821c287992SMathieu Othacehe 					      NULL);
9831c287992SMathieu Othacehe 	if (ret < 0) {
9841c287992SMathieu Othacehe 		dev_err(&client->dev, "unable to setup iio triggered buffer\n");
9851c287992SMathieu Othacehe 		return ret;
9861c287992SMathieu Othacehe 	}
9871c287992SMathieu Othacehe 
9881c287992SMathieu Othacehe 	return devm_iio_device_register(&client->dev, indio_dev);
9891c287992SMathieu Othacehe }
9901c287992SMathieu Othacehe 
9911c287992SMathieu Othacehe static const struct i2c_device_id isl29501_id[] = {
992*4391affaSUwe Kleine-König 	{ "isl29501" },
9931c287992SMathieu Othacehe 	{}
9941c287992SMathieu Othacehe };
9951c287992SMathieu Othacehe 
9961c287992SMathieu Othacehe MODULE_DEVICE_TABLE(i2c, isl29501_id);
9971c287992SMathieu Othacehe 
9981c287992SMathieu Othacehe static const struct of_device_id isl29501_i2c_matches[] = {
9991c287992SMathieu Othacehe 	{ .compatible = "renesas,isl29501" },
10001c287992SMathieu Othacehe 	{ }
10011c287992SMathieu Othacehe };
10021c287992SMathieu Othacehe MODULE_DEVICE_TABLE(of, isl29501_i2c_matches);
10031c287992SMathieu Othacehe 
10041c287992SMathieu Othacehe static struct i2c_driver isl29501_driver = {
10051c287992SMathieu Othacehe 	.driver = {
10061c287992SMathieu Othacehe 		.name	= "isl29501",
1007051db7eeSKrzysztof Kozlowski 		.of_match_table = isl29501_i2c_matches,
10081c287992SMathieu Othacehe 	},
10091c287992SMathieu Othacehe 	.id_table	= isl29501_id,
10107cf15f42SUwe Kleine-König 	.probe		= isl29501_probe,
10111c287992SMathieu Othacehe };
10121c287992SMathieu Othacehe module_i2c_driver(isl29501_driver);
10131c287992SMathieu Othacehe 
10141c287992SMathieu Othacehe MODULE_AUTHOR("Mathieu Othacehe <m.othacehe@gmail.com>");
10151c287992SMathieu Othacehe MODULE_DESCRIPTION("ISL29501 Time of Flight sensor driver");
10161c287992SMathieu Othacehe MODULE_LICENSE("GPL v2");
1017