18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * isl29501.c: ISL29501 Time of Flight sensor driver.
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2018
68c2ecf20Sopenharmony_ci * Author: Mathieu Othacehe <m.othacehe@gmail.com>
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci * 7-bit I2C slave address: 0x57
98c2ecf20Sopenharmony_ci */
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#include <linux/kernel.h>
128c2ecf20Sopenharmony_ci#include <linux/module.h>
138c2ecf20Sopenharmony_ci#include <linux/i2c.h>
148c2ecf20Sopenharmony_ci#include <linux/err.h>
158c2ecf20Sopenharmony_ci#include <linux/of_device.h>
168c2ecf20Sopenharmony_ci#include <linux/iio/iio.h>
178c2ecf20Sopenharmony_ci#include <linux/iio/sysfs.h>
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci#include <linux/iio/trigger_consumer.h>
208c2ecf20Sopenharmony_ci#include <linux/iio/buffer.h>
218c2ecf20Sopenharmony_ci#include <linux/iio/triggered_buffer.h>
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci/* Control, setting and status registers */
248c2ecf20Sopenharmony_ci#define ISL29501_DEVICE_ID			0x00
258c2ecf20Sopenharmony_ci#define ISL29501_ID				0x0A
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci/* Sampling control registers */
288c2ecf20Sopenharmony_ci#define ISL29501_INTEGRATION_PERIOD		0x10
298c2ecf20Sopenharmony_ci#define ISL29501_SAMPLE_PERIOD			0x11
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci/* Closed loop calibration registers */
328c2ecf20Sopenharmony_ci#define ISL29501_CROSSTALK_I_MSB		0x24
338c2ecf20Sopenharmony_ci#define ISL29501_CROSSTALK_I_LSB		0x25
348c2ecf20Sopenharmony_ci#define ISL29501_CROSSTALK_I_EXPONENT		0x26
358c2ecf20Sopenharmony_ci#define ISL29501_CROSSTALK_Q_MSB		0x27
368c2ecf20Sopenharmony_ci#define ISL29501_CROSSTALK_Q_LSB		0x28
378c2ecf20Sopenharmony_ci#define ISL29501_CROSSTALK_Q_EXPONENT		0x29
388c2ecf20Sopenharmony_ci#define ISL29501_CROSSTALK_GAIN_MSB		0x2A
398c2ecf20Sopenharmony_ci#define ISL29501_CROSSTALK_GAIN_LSB		0x2B
408c2ecf20Sopenharmony_ci#define ISL29501_MAGNITUDE_REF_EXP		0x2C
418c2ecf20Sopenharmony_ci#define ISL29501_MAGNITUDE_REF_MSB		0x2D
428c2ecf20Sopenharmony_ci#define ISL29501_MAGNITUDE_REF_LSB		0x2E
438c2ecf20Sopenharmony_ci#define ISL29501_PHASE_OFFSET_MSB		0x2F
448c2ecf20Sopenharmony_ci#define ISL29501_PHASE_OFFSET_LSB		0x30
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci/* Analog control registers */
478c2ecf20Sopenharmony_ci#define ISL29501_DRIVER_RANGE			0x90
488c2ecf20Sopenharmony_ci#define ISL29501_EMITTER_DAC			0x91
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci#define ISL29501_COMMAND_REGISTER		0xB0
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci/* Commands */
538c2ecf20Sopenharmony_ci#define ISL29501_EMUL_SAMPLE_START_PIN		0x49
548c2ecf20Sopenharmony_ci#define ISL29501_RESET_ALL_REGISTERS		0xD7
558c2ecf20Sopenharmony_ci#define ISL29501_RESET_INT_SM			0xD1
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci/* Ambiant light and temperature corrections */
588c2ecf20Sopenharmony_ci#define ISL29501_TEMP_REFERENCE			0x31
598c2ecf20Sopenharmony_ci#define ISL29501_PHASE_EXPONENT			0x33
608c2ecf20Sopenharmony_ci#define ISL29501_TEMP_COEFF_A			0x34
618c2ecf20Sopenharmony_ci#define ISL29501_TEMP_COEFF_B			0x39
628c2ecf20Sopenharmony_ci#define ISL29501_AMBIANT_COEFF_A		0x36
638c2ecf20Sopenharmony_ci#define ISL29501_AMBIANT_COEFF_B		0x3B
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci/* Data output registers */
668c2ecf20Sopenharmony_ci#define ISL29501_DISTANCE_MSB_DATA		0xD1
678c2ecf20Sopenharmony_ci#define ISL29501_DISTANCE_LSB_DATA		0xD2
688c2ecf20Sopenharmony_ci#define ISL29501_PRECISION_MSB			0xD3
698c2ecf20Sopenharmony_ci#define ISL29501_PRECISION_LSB			0xD4
708c2ecf20Sopenharmony_ci#define ISL29501_MAGNITUDE_EXPONENT		0xD5
718c2ecf20Sopenharmony_ci#define ISL29501_MAGNITUDE_MSB			0xD6
728c2ecf20Sopenharmony_ci#define ISL29501_MAGNITUDE_LSB			0xD7
738c2ecf20Sopenharmony_ci#define ISL29501_PHASE_MSB			0xD8
748c2ecf20Sopenharmony_ci#define ISL29501_PHASE_LSB			0xD9
758c2ecf20Sopenharmony_ci#define ISL29501_I_RAW_EXPONENT			0xDA
768c2ecf20Sopenharmony_ci#define ISL29501_I_RAW_MSB			0xDB
778c2ecf20Sopenharmony_ci#define ISL29501_I_RAW_LSB			0xDC
788c2ecf20Sopenharmony_ci#define ISL29501_Q_RAW_EXPONENT			0xDD
798c2ecf20Sopenharmony_ci#define ISL29501_Q_RAW_MSB			0xDE
808c2ecf20Sopenharmony_ci#define ISL29501_Q_RAW_LSB			0xDF
818c2ecf20Sopenharmony_ci#define ISL29501_DIE_TEMPERATURE		0xE2
828c2ecf20Sopenharmony_ci#define ISL29501_AMBIENT_LIGHT			0xE3
838c2ecf20Sopenharmony_ci#define ISL29501_GAIN_MSB			0xE6
848c2ecf20Sopenharmony_ci#define ISL29501_GAIN_LSB			0xE7
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci#define ISL29501_MAX_EXP_VAL 15
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci#define ISL29501_INT_TIME_AVAILABLE \
898c2ecf20Sopenharmony_ci	"0.00007 0.00014 0.00028 0.00057 0.00114 " \
908c2ecf20Sopenharmony_ci	"0.00228 0.00455 0.00910 0.01820 0.03640 " \
918c2ecf20Sopenharmony_ci	"0.07281 0.14561"
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci#define ISL29501_CURRENT_SCALE_AVAILABLE \
948c2ecf20Sopenharmony_ci	"0.0039 0.0078 0.0118 0.0157 0.0196 " \
958c2ecf20Sopenharmony_ci	"0.0235 0.0275 0.0314 0.0352 0.0392 " \
968c2ecf20Sopenharmony_ci	"0.0431 0.0471 0.0510 0.0549 0.0588"
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_cienum isl29501_correction_coeff {
998c2ecf20Sopenharmony_ci	COEFF_TEMP_A,
1008c2ecf20Sopenharmony_ci	COEFF_TEMP_B,
1018c2ecf20Sopenharmony_ci	COEFF_LIGHT_A,
1028c2ecf20Sopenharmony_ci	COEFF_LIGHT_B,
1038c2ecf20Sopenharmony_ci	COEFF_MAX,
1048c2ecf20Sopenharmony_ci};
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_cistruct isl29501_private {
1078c2ecf20Sopenharmony_ci	struct i2c_client *client;
1088c2ecf20Sopenharmony_ci	struct mutex lock;
1098c2ecf20Sopenharmony_ci	/* Exact representation of correction coefficients. */
1108c2ecf20Sopenharmony_ci	unsigned int shadow_coeffs[COEFF_MAX];
1118c2ecf20Sopenharmony_ci};
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_cienum isl29501_register_name {
1148c2ecf20Sopenharmony_ci	REG_DISTANCE,
1158c2ecf20Sopenharmony_ci	REG_PHASE,
1168c2ecf20Sopenharmony_ci	REG_TEMPERATURE,
1178c2ecf20Sopenharmony_ci	REG_AMBIENT_LIGHT,
1188c2ecf20Sopenharmony_ci	REG_GAIN,
1198c2ecf20Sopenharmony_ci	REG_GAIN_BIAS,
1208c2ecf20Sopenharmony_ci	REG_PHASE_EXP,
1218c2ecf20Sopenharmony_ci	REG_CALIB_PHASE_TEMP_A,
1228c2ecf20Sopenharmony_ci	REG_CALIB_PHASE_TEMP_B,
1238c2ecf20Sopenharmony_ci	REG_CALIB_PHASE_LIGHT_A,
1248c2ecf20Sopenharmony_ci	REG_CALIB_PHASE_LIGHT_B,
1258c2ecf20Sopenharmony_ci	REG_DISTANCE_BIAS,
1268c2ecf20Sopenharmony_ci	REG_TEMPERATURE_BIAS,
1278c2ecf20Sopenharmony_ci	REG_INT_TIME,
1288c2ecf20Sopenharmony_ci	REG_SAMPLE_TIME,
1298c2ecf20Sopenharmony_ci	REG_DRIVER_RANGE,
1308c2ecf20Sopenharmony_ci	REG_EMITTER_DAC,
1318c2ecf20Sopenharmony_ci};
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_cistruct isl29501_register_desc {
1348c2ecf20Sopenharmony_ci	u8 msb;
1358c2ecf20Sopenharmony_ci	u8 lsb;
1368c2ecf20Sopenharmony_ci};
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_cistatic const struct isl29501_register_desc isl29501_registers[] = {
1398c2ecf20Sopenharmony_ci	[REG_DISTANCE] = {
1408c2ecf20Sopenharmony_ci		.msb = ISL29501_DISTANCE_MSB_DATA,
1418c2ecf20Sopenharmony_ci		.lsb = ISL29501_DISTANCE_LSB_DATA,
1428c2ecf20Sopenharmony_ci	},
1438c2ecf20Sopenharmony_ci	[REG_PHASE] = {
1448c2ecf20Sopenharmony_ci		.msb = ISL29501_PHASE_MSB,
1458c2ecf20Sopenharmony_ci		.lsb = ISL29501_PHASE_LSB,
1468c2ecf20Sopenharmony_ci	},
1478c2ecf20Sopenharmony_ci	[REG_TEMPERATURE] = {
1488c2ecf20Sopenharmony_ci		.lsb = ISL29501_DIE_TEMPERATURE,
1498c2ecf20Sopenharmony_ci	},
1508c2ecf20Sopenharmony_ci	[REG_AMBIENT_LIGHT] = {
1518c2ecf20Sopenharmony_ci		.lsb = ISL29501_AMBIENT_LIGHT,
1528c2ecf20Sopenharmony_ci	},
1538c2ecf20Sopenharmony_ci	[REG_GAIN] = {
1548c2ecf20Sopenharmony_ci		.msb = ISL29501_GAIN_MSB,
1558c2ecf20Sopenharmony_ci		.lsb = ISL29501_GAIN_LSB,
1568c2ecf20Sopenharmony_ci	},
1578c2ecf20Sopenharmony_ci	[REG_GAIN_BIAS] = {
1588c2ecf20Sopenharmony_ci		.msb = ISL29501_CROSSTALK_GAIN_MSB,
1598c2ecf20Sopenharmony_ci		.lsb = ISL29501_CROSSTALK_GAIN_LSB,
1608c2ecf20Sopenharmony_ci	},
1618c2ecf20Sopenharmony_ci	[REG_PHASE_EXP] = {
1628c2ecf20Sopenharmony_ci		.lsb = ISL29501_PHASE_EXPONENT,
1638c2ecf20Sopenharmony_ci	},
1648c2ecf20Sopenharmony_ci	[REG_CALIB_PHASE_TEMP_A] = {
1658c2ecf20Sopenharmony_ci		.lsb = ISL29501_TEMP_COEFF_A,
1668c2ecf20Sopenharmony_ci	},
1678c2ecf20Sopenharmony_ci	[REG_CALIB_PHASE_TEMP_B] = {
1688c2ecf20Sopenharmony_ci		.lsb = ISL29501_TEMP_COEFF_B,
1698c2ecf20Sopenharmony_ci	},
1708c2ecf20Sopenharmony_ci	[REG_CALIB_PHASE_LIGHT_A] = {
1718c2ecf20Sopenharmony_ci		.lsb = ISL29501_AMBIANT_COEFF_A,
1728c2ecf20Sopenharmony_ci	},
1738c2ecf20Sopenharmony_ci	[REG_CALIB_PHASE_LIGHT_B] = {
1748c2ecf20Sopenharmony_ci		.lsb = ISL29501_AMBIANT_COEFF_B,
1758c2ecf20Sopenharmony_ci	},
1768c2ecf20Sopenharmony_ci	[REG_DISTANCE_BIAS] = {
1778c2ecf20Sopenharmony_ci		.msb = ISL29501_PHASE_OFFSET_MSB,
1788c2ecf20Sopenharmony_ci		.lsb = ISL29501_PHASE_OFFSET_LSB,
1798c2ecf20Sopenharmony_ci	},
1808c2ecf20Sopenharmony_ci	[REG_TEMPERATURE_BIAS] = {
1818c2ecf20Sopenharmony_ci		.lsb = ISL29501_TEMP_REFERENCE,
1828c2ecf20Sopenharmony_ci	},
1838c2ecf20Sopenharmony_ci	[REG_INT_TIME] = {
1848c2ecf20Sopenharmony_ci		.lsb = ISL29501_INTEGRATION_PERIOD,
1858c2ecf20Sopenharmony_ci	},
1868c2ecf20Sopenharmony_ci	[REG_SAMPLE_TIME] = {
1878c2ecf20Sopenharmony_ci		.lsb = ISL29501_SAMPLE_PERIOD,
1888c2ecf20Sopenharmony_ci	},
1898c2ecf20Sopenharmony_ci	[REG_DRIVER_RANGE] = {
1908c2ecf20Sopenharmony_ci		.lsb = ISL29501_DRIVER_RANGE,
1918c2ecf20Sopenharmony_ci	},
1928c2ecf20Sopenharmony_ci	[REG_EMITTER_DAC] = {
1938c2ecf20Sopenharmony_ci		.lsb = ISL29501_EMITTER_DAC,
1948c2ecf20Sopenharmony_ci	},
1958c2ecf20Sopenharmony_ci};
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_cistatic int isl29501_register_read(struct isl29501_private *isl29501,
1988c2ecf20Sopenharmony_ci				  enum isl29501_register_name name,
1998c2ecf20Sopenharmony_ci				  u32 *val)
2008c2ecf20Sopenharmony_ci{
2018c2ecf20Sopenharmony_ci	const struct isl29501_register_desc *reg = &isl29501_registers[name];
2028c2ecf20Sopenharmony_ci	u8 msb = 0, lsb = 0;
2038c2ecf20Sopenharmony_ci	s32 ret;
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci	mutex_lock(&isl29501->lock);
2068c2ecf20Sopenharmony_ci	if (reg->msb) {
2078c2ecf20Sopenharmony_ci		ret = i2c_smbus_read_byte_data(isl29501->client, reg->msb);
2088c2ecf20Sopenharmony_ci		if (ret < 0)
2098c2ecf20Sopenharmony_ci			goto err;
2108c2ecf20Sopenharmony_ci		msb = ret;
2118c2ecf20Sopenharmony_ci	}
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci	if (reg->lsb) {
2148c2ecf20Sopenharmony_ci		ret = i2c_smbus_read_byte_data(isl29501->client, reg->lsb);
2158c2ecf20Sopenharmony_ci		if (ret < 0)
2168c2ecf20Sopenharmony_ci			goto err;
2178c2ecf20Sopenharmony_ci		lsb = ret;
2188c2ecf20Sopenharmony_ci	}
2198c2ecf20Sopenharmony_ci	mutex_unlock(&isl29501->lock);
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci	*val = (msb << 8) + lsb;
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ci	return 0;
2248c2ecf20Sopenharmony_cierr:
2258c2ecf20Sopenharmony_ci	mutex_unlock(&isl29501->lock);
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci	return ret;
2288c2ecf20Sopenharmony_ci}
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_cistatic u32 isl29501_register_write(struct isl29501_private *isl29501,
2318c2ecf20Sopenharmony_ci				   enum isl29501_register_name name,
2328c2ecf20Sopenharmony_ci				   u32 value)
2338c2ecf20Sopenharmony_ci{
2348c2ecf20Sopenharmony_ci	const struct isl29501_register_desc *reg = &isl29501_registers[name];
2358c2ecf20Sopenharmony_ci	int ret;
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci	if (!reg->msb && value > U8_MAX)
2388c2ecf20Sopenharmony_ci		return -ERANGE;
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ci	if (value > U16_MAX)
2418c2ecf20Sopenharmony_ci		return -ERANGE;
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_ci	mutex_lock(&isl29501->lock);
2448c2ecf20Sopenharmony_ci	if (reg->msb) {
2458c2ecf20Sopenharmony_ci		ret = i2c_smbus_write_byte_data(isl29501->client,
2468c2ecf20Sopenharmony_ci						reg->msb, value >> 8);
2478c2ecf20Sopenharmony_ci		if (ret < 0)
2488c2ecf20Sopenharmony_ci			goto err;
2498c2ecf20Sopenharmony_ci	}
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci	ret = i2c_smbus_write_byte_data(isl29501->client, reg->lsb, value);
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_cierr:
2548c2ecf20Sopenharmony_ci	mutex_unlock(&isl29501->lock);
2558c2ecf20Sopenharmony_ci	return ret;
2568c2ecf20Sopenharmony_ci}
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_cistatic ssize_t isl29501_read_ext(struct iio_dev *indio_dev,
2598c2ecf20Sopenharmony_ci				 uintptr_t private,
2608c2ecf20Sopenharmony_ci				 const struct iio_chan_spec *chan,
2618c2ecf20Sopenharmony_ci				 char *buf)
2628c2ecf20Sopenharmony_ci{
2638c2ecf20Sopenharmony_ci	struct isl29501_private *isl29501 = iio_priv(indio_dev);
2648c2ecf20Sopenharmony_ci	enum isl29501_register_name reg = private;
2658c2ecf20Sopenharmony_ci	int ret;
2668c2ecf20Sopenharmony_ci	u32 value, gain, coeff, exp;
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ci	switch (reg) {
2698c2ecf20Sopenharmony_ci	case REG_GAIN:
2708c2ecf20Sopenharmony_ci	case REG_GAIN_BIAS:
2718c2ecf20Sopenharmony_ci		ret = isl29501_register_read(isl29501, reg, &gain);
2728c2ecf20Sopenharmony_ci		if (ret < 0)
2738c2ecf20Sopenharmony_ci			return ret;
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci		value = gain;
2768c2ecf20Sopenharmony_ci		break;
2778c2ecf20Sopenharmony_ci	case REG_CALIB_PHASE_TEMP_A:
2788c2ecf20Sopenharmony_ci	case REG_CALIB_PHASE_TEMP_B:
2798c2ecf20Sopenharmony_ci	case REG_CALIB_PHASE_LIGHT_A:
2808c2ecf20Sopenharmony_ci	case REG_CALIB_PHASE_LIGHT_B:
2818c2ecf20Sopenharmony_ci		ret = isl29501_register_read(isl29501, REG_PHASE_EXP, &exp);
2828c2ecf20Sopenharmony_ci		if (ret < 0)
2838c2ecf20Sopenharmony_ci			return ret;
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ci		ret = isl29501_register_read(isl29501, reg, &coeff);
2868c2ecf20Sopenharmony_ci		if (ret < 0)
2878c2ecf20Sopenharmony_ci			return ret;
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_ci		value = coeff << exp;
2908c2ecf20Sopenharmony_ci		break;
2918c2ecf20Sopenharmony_ci	default:
2928c2ecf20Sopenharmony_ci		return -EINVAL;
2938c2ecf20Sopenharmony_ci	}
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_ci	return sprintf(buf, "%u\n", value);
2968c2ecf20Sopenharmony_ci}
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_cistatic int isl29501_set_shadow_coeff(struct isl29501_private *isl29501,
2998c2ecf20Sopenharmony_ci				     enum isl29501_register_name reg,
3008c2ecf20Sopenharmony_ci				     unsigned int val)
3018c2ecf20Sopenharmony_ci{
3028c2ecf20Sopenharmony_ci	enum isl29501_correction_coeff coeff;
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_ci	switch (reg) {
3058c2ecf20Sopenharmony_ci	case REG_CALIB_PHASE_TEMP_A:
3068c2ecf20Sopenharmony_ci		coeff = COEFF_TEMP_A;
3078c2ecf20Sopenharmony_ci		break;
3088c2ecf20Sopenharmony_ci	case REG_CALIB_PHASE_TEMP_B:
3098c2ecf20Sopenharmony_ci		coeff = COEFF_TEMP_B;
3108c2ecf20Sopenharmony_ci		break;
3118c2ecf20Sopenharmony_ci	case REG_CALIB_PHASE_LIGHT_A:
3128c2ecf20Sopenharmony_ci		coeff = COEFF_LIGHT_A;
3138c2ecf20Sopenharmony_ci		break;
3148c2ecf20Sopenharmony_ci	case REG_CALIB_PHASE_LIGHT_B:
3158c2ecf20Sopenharmony_ci		coeff = COEFF_LIGHT_B;
3168c2ecf20Sopenharmony_ci		break;
3178c2ecf20Sopenharmony_ci	default:
3188c2ecf20Sopenharmony_ci		return -EINVAL;
3198c2ecf20Sopenharmony_ci	}
3208c2ecf20Sopenharmony_ci	isl29501->shadow_coeffs[coeff] = val;
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci	return 0;
3238c2ecf20Sopenharmony_ci}
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_cistatic int isl29501_write_coeff(struct isl29501_private *isl29501,
3268c2ecf20Sopenharmony_ci				enum isl29501_correction_coeff coeff,
3278c2ecf20Sopenharmony_ci				int val)
3288c2ecf20Sopenharmony_ci{
3298c2ecf20Sopenharmony_ci	enum isl29501_register_name reg;
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_ci	switch (coeff) {
3328c2ecf20Sopenharmony_ci	case COEFF_TEMP_A:
3338c2ecf20Sopenharmony_ci		reg = REG_CALIB_PHASE_TEMP_A;
3348c2ecf20Sopenharmony_ci		break;
3358c2ecf20Sopenharmony_ci	case COEFF_TEMP_B:
3368c2ecf20Sopenharmony_ci		reg = REG_CALIB_PHASE_TEMP_B;
3378c2ecf20Sopenharmony_ci		break;
3388c2ecf20Sopenharmony_ci	case COEFF_LIGHT_A:
3398c2ecf20Sopenharmony_ci		reg = REG_CALIB_PHASE_LIGHT_A;
3408c2ecf20Sopenharmony_ci		break;
3418c2ecf20Sopenharmony_ci	case COEFF_LIGHT_B:
3428c2ecf20Sopenharmony_ci		reg = REG_CALIB_PHASE_LIGHT_B;
3438c2ecf20Sopenharmony_ci		break;
3448c2ecf20Sopenharmony_ci	default:
3458c2ecf20Sopenharmony_ci		return -EINVAL;
3468c2ecf20Sopenharmony_ci	}
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ci	return isl29501_register_write(isl29501, reg, val);
3498c2ecf20Sopenharmony_ci}
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_cistatic unsigned int isl29501_find_corr_exp(unsigned int val,
3528c2ecf20Sopenharmony_ci					   unsigned int max_exp,
3538c2ecf20Sopenharmony_ci					   unsigned int max_mantissa)
3548c2ecf20Sopenharmony_ci{
3558c2ecf20Sopenharmony_ci	unsigned int exp = 1;
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_ci	/*
3588c2ecf20Sopenharmony_ci	 * Correction coefficients are represented under
3598c2ecf20Sopenharmony_ci	 * mantissa * 2^exponent form, where mantissa and exponent
3608c2ecf20Sopenharmony_ci	 * are stored in two separate registers of the sensor.
3618c2ecf20Sopenharmony_ci	 *
3628c2ecf20Sopenharmony_ci	 * Compute and return the lowest exponent such as:
3638c2ecf20Sopenharmony_ci	 *	     mantissa = value / 2^exponent
3648c2ecf20Sopenharmony_ci	 *
3658c2ecf20Sopenharmony_ci	 *  where mantissa < max_mantissa.
3668c2ecf20Sopenharmony_ci	 */
3678c2ecf20Sopenharmony_ci	if (val <= max_mantissa)
3688c2ecf20Sopenharmony_ci		return 0;
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci	while ((val >> exp) > max_mantissa) {
3718c2ecf20Sopenharmony_ci		exp++;
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_ci		if (exp > max_exp)
3748c2ecf20Sopenharmony_ci			return max_exp;
3758c2ecf20Sopenharmony_ci	}
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_ci	return exp;
3788c2ecf20Sopenharmony_ci}
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_cistatic ssize_t isl29501_write_ext(struct iio_dev *indio_dev,
3818c2ecf20Sopenharmony_ci				  uintptr_t private,
3828c2ecf20Sopenharmony_ci				  const struct iio_chan_spec *chan,
3838c2ecf20Sopenharmony_ci				  const char *buf, size_t len)
3848c2ecf20Sopenharmony_ci{
3858c2ecf20Sopenharmony_ci	struct isl29501_private *isl29501 = iio_priv(indio_dev);
3868c2ecf20Sopenharmony_ci	enum isl29501_register_name reg = private;
3878c2ecf20Sopenharmony_ci	unsigned int val;
3888c2ecf20Sopenharmony_ci	int max_exp = 0;
3898c2ecf20Sopenharmony_ci	int ret;
3908c2ecf20Sopenharmony_ci	int i;
3918c2ecf20Sopenharmony_ci
3928c2ecf20Sopenharmony_ci	ret = kstrtouint(buf, 10, &val);
3938c2ecf20Sopenharmony_ci	if (ret)
3948c2ecf20Sopenharmony_ci		return ret;
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_ci	switch (reg) {
3978c2ecf20Sopenharmony_ci	case REG_GAIN_BIAS:
3988c2ecf20Sopenharmony_ci		if (val > U16_MAX)
3998c2ecf20Sopenharmony_ci			return -ERANGE;
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_ci		ret = isl29501_register_write(isl29501, reg, val);
4028c2ecf20Sopenharmony_ci		if (ret < 0)
4038c2ecf20Sopenharmony_ci			return ret;
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_ci		break;
4068c2ecf20Sopenharmony_ci	case REG_CALIB_PHASE_TEMP_A:
4078c2ecf20Sopenharmony_ci	case REG_CALIB_PHASE_TEMP_B:
4088c2ecf20Sopenharmony_ci	case REG_CALIB_PHASE_LIGHT_A:
4098c2ecf20Sopenharmony_ci	case REG_CALIB_PHASE_LIGHT_B:
4108c2ecf20Sopenharmony_ci
4118c2ecf20Sopenharmony_ci		if (val > (U8_MAX << ISL29501_MAX_EXP_VAL))
4128c2ecf20Sopenharmony_ci			return -ERANGE;
4138c2ecf20Sopenharmony_ci
4148c2ecf20Sopenharmony_ci		/* Store the correction coefficient under its exact form. */
4158c2ecf20Sopenharmony_ci		ret = isl29501_set_shadow_coeff(isl29501, reg, val);
4168c2ecf20Sopenharmony_ci		if (ret < 0)
4178c2ecf20Sopenharmony_ci			return ret;
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_ci		/*
4208c2ecf20Sopenharmony_ci		 * Find the highest exponent needed to represent
4218c2ecf20Sopenharmony_ci		 * correction coefficients.
4228c2ecf20Sopenharmony_ci		 */
4238c2ecf20Sopenharmony_ci		for (i = 0; i < COEFF_MAX; i++) {
4248c2ecf20Sopenharmony_ci			int corr;
4258c2ecf20Sopenharmony_ci			int corr_exp;
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_ci			corr = isl29501->shadow_coeffs[i];
4288c2ecf20Sopenharmony_ci			corr_exp = isl29501_find_corr_exp(corr,
4298c2ecf20Sopenharmony_ci							  ISL29501_MAX_EXP_VAL,
4308c2ecf20Sopenharmony_ci							  U8_MAX / 2);
4318c2ecf20Sopenharmony_ci			dev_dbg(&isl29501->client->dev,
4328c2ecf20Sopenharmony_ci				"found exp of corr(%d) = %d\n", corr, corr_exp);
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_ci			max_exp = max(max_exp, corr_exp);
4358c2ecf20Sopenharmony_ci		}
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_ci		/*
4388c2ecf20Sopenharmony_ci		 * Represent every correction coefficient under
4398c2ecf20Sopenharmony_ci		 * mantissa * 2^max_exponent form and force the
4408c2ecf20Sopenharmony_ci		 * writing of those coefficients on the sensor.
4418c2ecf20Sopenharmony_ci		 */
4428c2ecf20Sopenharmony_ci		for (i = 0; i < COEFF_MAX; i++) {
4438c2ecf20Sopenharmony_ci			int corr;
4448c2ecf20Sopenharmony_ci			int mantissa;
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_ci			corr = isl29501->shadow_coeffs[i];
4478c2ecf20Sopenharmony_ci			if (!corr)
4488c2ecf20Sopenharmony_ci				continue;
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_ci			mantissa = corr >> max_exp;
4518c2ecf20Sopenharmony_ci
4528c2ecf20Sopenharmony_ci			ret = isl29501_write_coeff(isl29501, i, mantissa);
4538c2ecf20Sopenharmony_ci			if (ret < 0)
4548c2ecf20Sopenharmony_ci				return ret;
4558c2ecf20Sopenharmony_ci		}
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_ci		ret = isl29501_register_write(isl29501, REG_PHASE_EXP, max_exp);
4588c2ecf20Sopenharmony_ci		if (ret < 0)
4598c2ecf20Sopenharmony_ci			return ret;
4608c2ecf20Sopenharmony_ci
4618c2ecf20Sopenharmony_ci		break;
4628c2ecf20Sopenharmony_ci	default:
4638c2ecf20Sopenharmony_ci		return -EINVAL;
4648c2ecf20Sopenharmony_ci	}
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_ci	return len;
4678c2ecf20Sopenharmony_ci}
4688c2ecf20Sopenharmony_ci
4698c2ecf20Sopenharmony_ci#define _ISL29501_EXT_INFO(_name, _ident) { \
4708c2ecf20Sopenharmony_ci	.name = _name, \
4718c2ecf20Sopenharmony_ci	.read = isl29501_read_ext, \
4728c2ecf20Sopenharmony_ci	.write = isl29501_write_ext, \
4738c2ecf20Sopenharmony_ci	.private = _ident, \
4748c2ecf20Sopenharmony_ci	.shared = IIO_SEPARATE, \
4758c2ecf20Sopenharmony_ci}
4768c2ecf20Sopenharmony_ci
4778c2ecf20Sopenharmony_cistatic const struct iio_chan_spec_ext_info isl29501_ext_info[] = {
4788c2ecf20Sopenharmony_ci	_ISL29501_EXT_INFO("agc_gain", REG_GAIN),
4798c2ecf20Sopenharmony_ci	_ISL29501_EXT_INFO("agc_gain_bias", REG_GAIN_BIAS),
4808c2ecf20Sopenharmony_ci	_ISL29501_EXT_INFO("calib_phase_temp_a", REG_CALIB_PHASE_TEMP_A),
4818c2ecf20Sopenharmony_ci	_ISL29501_EXT_INFO("calib_phase_temp_b", REG_CALIB_PHASE_TEMP_B),
4828c2ecf20Sopenharmony_ci	_ISL29501_EXT_INFO("calib_phase_light_a", REG_CALIB_PHASE_LIGHT_A),
4838c2ecf20Sopenharmony_ci	_ISL29501_EXT_INFO("calib_phase_light_b", REG_CALIB_PHASE_LIGHT_B),
4848c2ecf20Sopenharmony_ci	{ },
4858c2ecf20Sopenharmony_ci};
4868c2ecf20Sopenharmony_ci
4878c2ecf20Sopenharmony_ci#define ISL29501_DISTANCE_SCAN_INDEX 0
4888c2ecf20Sopenharmony_ci#define ISL29501_TIMESTAMP_SCAN_INDEX 1
4898c2ecf20Sopenharmony_ci
4908c2ecf20Sopenharmony_cistatic const struct iio_chan_spec isl29501_channels[] = {
4918c2ecf20Sopenharmony_ci	{
4928c2ecf20Sopenharmony_ci		.type = IIO_PROXIMITY,
4938c2ecf20Sopenharmony_ci		.scan_index = ISL29501_DISTANCE_SCAN_INDEX,
4948c2ecf20Sopenharmony_ci		.info_mask_separate =
4958c2ecf20Sopenharmony_ci			BIT(IIO_CHAN_INFO_RAW)   |
4968c2ecf20Sopenharmony_ci			BIT(IIO_CHAN_INFO_SCALE) |
4978c2ecf20Sopenharmony_ci			BIT(IIO_CHAN_INFO_CALIBBIAS),
4988c2ecf20Sopenharmony_ci		.scan_type = {
4998c2ecf20Sopenharmony_ci			.sign = 'u',
5008c2ecf20Sopenharmony_ci			.realbits = 16,
5018c2ecf20Sopenharmony_ci			.storagebits = 16,
5028c2ecf20Sopenharmony_ci			.endianness = IIO_CPU,
5038c2ecf20Sopenharmony_ci		},
5048c2ecf20Sopenharmony_ci		.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME) |
5058c2ecf20Sopenharmony_ci				BIT(IIO_CHAN_INFO_SAMP_FREQ),
5068c2ecf20Sopenharmony_ci		.ext_info = isl29501_ext_info,
5078c2ecf20Sopenharmony_ci	},
5088c2ecf20Sopenharmony_ci	{
5098c2ecf20Sopenharmony_ci		.type = IIO_PHASE,
5108c2ecf20Sopenharmony_ci		.scan_index = -1,
5118c2ecf20Sopenharmony_ci		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
5128c2ecf20Sopenharmony_ci				BIT(IIO_CHAN_INFO_SCALE),
5138c2ecf20Sopenharmony_ci	},
5148c2ecf20Sopenharmony_ci	{
5158c2ecf20Sopenharmony_ci		.type = IIO_CURRENT,
5168c2ecf20Sopenharmony_ci		.scan_index = -1,
5178c2ecf20Sopenharmony_ci		.output = 1,
5188c2ecf20Sopenharmony_ci		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
5198c2ecf20Sopenharmony_ci				BIT(IIO_CHAN_INFO_SCALE),
5208c2ecf20Sopenharmony_ci	},
5218c2ecf20Sopenharmony_ci	{
5228c2ecf20Sopenharmony_ci		.type = IIO_TEMP,
5238c2ecf20Sopenharmony_ci		.scan_index = -1,
5248c2ecf20Sopenharmony_ci		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
5258c2ecf20Sopenharmony_ci				BIT(IIO_CHAN_INFO_SCALE)     |
5268c2ecf20Sopenharmony_ci				BIT(IIO_CHAN_INFO_CALIBBIAS),
5278c2ecf20Sopenharmony_ci	},
5288c2ecf20Sopenharmony_ci	{
5298c2ecf20Sopenharmony_ci		.type = IIO_INTENSITY,
5308c2ecf20Sopenharmony_ci		.scan_index = -1,
5318c2ecf20Sopenharmony_ci		.modified = 1,
5328c2ecf20Sopenharmony_ci		.channel2 = IIO_MOD_LIGHT_CLEAR,
5338c2ecf20Sopenharmony_ci		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
5348c2ecf20Sopenharmony_ci				BIT(IIO_CHAN_INFO_SCALE),
5358c2ecf20Sopenharmony_ci	},
5368c2ecf20Sopenharmony_ci	IIO_CHAN_SOFT_TIMESTAMP(ISL29501_TIMESTAMP_SCAN_INDEX),
5378c2ecf20Sopenharmony_ci};
5388c2ecf20Sopenharmony_ci
5398c2ecf20Sopenharmony_cistatic int isl29501_reset_registers(struct isl29501_private *isl29501)
5408c2ecf20Sopenharmony_ci{
5418c2ecf20Sopenharmony_ci	int ret;
5428c2ecf20Sopenharmony_ci
5438c2ecf20Sopenharmony_ci	ret = i2c_smbus_write_byte_data(isl29501->client,
5448c2ecf20Sopenharmony_ci					ISL29501_COMMAND_REGISTER,
5458c2ecf20Sopenharmony_ci					ISL29501_RESET_ALL_REGISTERS);
5468c2ecf20Sopenharmony_ci	if (ret < 0) {
5478c2ecf20Sopenharmony_ci		dev_err(&isl29501->client->dev,
5488c2ecf20Sopenharmony_ci			"cannot reset registers %d\n", ret);
5498c2ecf20Sopenharmony_ci		return ret;
5508c2ecf20Sopenharmony_ci	}
5518c2ecf20Sopenharmony_ci
5528c2ecf20Sopenharmony_ci	ret = i2c_smbus_write_byte_data(isl29501->client,
5538c2ecf20Sopenharmony_ci					ISL29501_COMMAND_REGISTER,
5548c2ecf20Sopenharmony_ci					ISL29501_RESET_INT_SM);
5558c2ecf20Sopenharmony_ci	if (ret < 0)
5568c2ecf20Sopenharmony_ci		dev_err(&isl29501->client->dev,
5578c2ecf20Sopenharmony_ci			"cannot reset state machine %d\n", ret);
5588c2ecf20Sopenharmony_ci
5598c2ecf20Sopenharmony_ci	return ret;
5608c2ecf20Sopenharmony_ci}
5618c2ecf20Sopenharmony_ci
5628c2ecf20Sopenharmony_cistatic int isl29501_begin_acquisition(struct isl29501_private *isl29501)
5638c2ecf20Sopenharmony_ci{
5648c2ecf20Sopenharmony_ci	int ret;
5658c2ecf20Sopenharmony_ci
5668c2ecf20Sopenharmony_ci	ret = i2c_smbus_write_byte_data(isl29501->client,
5678c2ecf20Sopenharmony_ci					ISL29501_COMMAND_REGISTER,
5688c2ecf20Sopenharmony_ci					ISL29501_EMUL_SAMPLE_START_PIN);
5698c2ecf20Sopenharmony_ci	if (ret < 0)
5708c2ecf20Sopenharmony_ci		dev_err(&isl29501->client->dev,
5718c2ecf20Sopenharmony_ci			"cannot begin acquisition %d\n", ret);
5728c2ecf20Sopenharmony_ci
5738c2ecf20Sopenharmony_ci	return ret;
5748c2ecf20Sopenharmony_ci}
5758c2ecf20Sopenharmony_ci
5768c2ecf20Sopenharmony_cistatic IIO_CONST_ATTR_INT_TIME_AVAIL(ISL29501_INT_TIME_AVAILABLE);
5778c2ecf20Sopenharmony_cistatic IIO_CONST_ATTR(out_current_scale_available,
5788c2ecf20Sopenharmony_ci		      ISL29501_CURRENT_SCALE_AVAILABLE);
5798c2ecf20Sopenharmony_ci
5808c2ecf20Sopenharmony_cistatic struct attribute *isl29501_attributes[] = {
5818c2ecf20Sopenharmony_ci	&iio_const_attr_integration_time_available.dev_attr.attr,
5828c2ecf20Sopenharmony_ci	&iio_const_attr_out_current_scale_available.dev_attr.attr,
5838c2ecf20Sopenharmony_ci	NULL
5848c2ecf20Sopenharmony_ci};
5858c2ecf20Sopenharmony_ci
5868c2ecf20Sopenharmony_cistatic const struct attribute_group isl29501_attribute_group = {
5878c2ecf20Sopenharmony_ci	.attrs = isl29501_attributes,
5888c2ecf20Sopenharmony_ci};
5898c2ecf20Sopenharmony_ci
5908c2ecf20Sopenharmony_cistatic const int isl29501_current_scale_table[][2] = {
5918c2ecf20Sopenharmony_ci	{0, 3900}, {0, 7800}, {0, 11800}, {0, 15700},
5928c2ecf20Sopenharmony_ci	{0, 19600}, {0, 23500}, {0, 27500}, {0, 31400},
5938c2ecf20Sopenharmony_ci	{0, 35200}, {0, 39200}, {0, 43100}, {0, 47100},
5948c2ecf20Sopenharmony_ci	{0, 51000}, {0, 54900}, {0, 58800},
5958c2ecf20Sopenharmony_ci};
5968c2ecf20Sopenharmony_ci
5978c2ecf20Sopenharmony_cistatic const int isl29501_int_time[][2] = {
5988c2ecf20Sopenharmony_ci	{0, 70},    /* 0.07 ms */
5998c2ecf20Sopenharmony_ci	{0, 140},   /* 0.14 ms */
6008c2ecf20Sopenharmony_ci	{0, 280},   /* 0.28 ms */
6018c2ecf20Sopenharmony_ci	{0, 570},   /* 0.57 ms */
6028c2ecf20Sopenharmony_ci	{0, 1140},  /* 1.14 ms */
6038c2ecf20Sopenharmony_ci	{0, 2280},  /* 2.28 ms */
6048c2ecf20Sopenharmony_ci	{0, 4550},  /* 4.55 ms */
6058c2ecf20Sopenharmony_ci	{0, 9100},  /* 9.11 ms */
6068c2ecf20Sopenharmony_ci	{0, 18200}, /* 18.2 ms */
6078c2ecf20Sopenharmony_ci	{0, 36400}, /* 36.4 ms */
6088c2ecf20Sopenharmony_ci	{0, 72810}, /* 72.81 ms */
6098c2ecf20Sopenharmony_ci	{0, 145610} /* 145.28 ms */
6108c2ecf20Sopenharmony_ci};
6118c2ecf20Sopenharmony_ci
6128c2ecf20Sopenharmony_cistatic int isl29501_get_raw(struct isl29501_private *isl29501,
6138c2ecf20Sopenharmony_ci			    const struct iio_chan_spec *chan,
6148c2ecf20Sopenharmony_ci			    int *raw)
6158c2ecf20Sopenharmony_ci{
6168c2ecf20Sopenharmony_ci	int ret;
6178c2ecf20Sopenharmony_ci
6188c2ecf20Sopenharmony_ci	switch (chan->type) {
6198c2ecf20Sopenharmony_ci	case IIO_PROXIMITY:
6208c2ecf20Sopenharmony_ci		ret = isl29501_register_read(isl29501, REG_DISTANCE, raw);
6218c2ecf20Sopenharmony_ci		if (ret < 0)
6228c2ecf20Sopenharmony_ci			return ret;
6238c2ecf20Sopenharmony_ci
6248c2ecf20Sopenharmony_ci		return IIO_VAL_INT;
6258c2ecf20Sopenharmony_ci	case IIO_INTENSITY:
6268c2ecf20Sopenharmony_ci		ret = isl29501_register_read(isl29501,
6278c2ecf20Sopenharmony_ci					     REG_AMBIENT_LIGHT,
6288c2ecf20Sopenharmony_ci					     raw);
6298c2ecf20Sopenharmony_ci		if (ret < 0)
6308c2ecf20Sopenharmony_ci			return ret;
6318c2ecf20Sopenharmony_ci
6328c2ecf20Sopenharmony_ci		return IIO_VAL_INT;
6338c2ecf20Sopenharmony_ci	case IIO_PHASE:
6348c2ecf20Sopenharmony_ci		ret = isl29501_register_read(isl29501, REG_PHASE, raw);
6358c2ecf20Sopenharmony_ci		if (ret < 0)
6368c2ecf20Sopenharmony_ci			return ret;
6378c2ecf20Sopenharmony_ci
6388c2ecf20Sopenharmony_ci		return IIO_VAL_INT;
6398c2ecf20Sopenharmony_ci	case IIO_CURRENT:
6408c2ecf20Sopenharmony_ci		ret = isl29501_register_read(isl29501, REG_EMITTER_DAC, raw);
6418c2ecf20Sopenharmony_ci		if (ret < 0)
6428c2ecf20Sopenharmony_ci			return ret;
6438c2ecf20Sopenharmony_ci
6448c2ecf20Sopenharmony_ci		return IIO_VAL_INT;
6458c2ecf20Sopenharmony_ci	case IIO_TEMP:
6468c2ecf20Sopenharmony_ci		ret = isl29501_register_read(isl29501, REG_TEMPERATURE, raw);
6478c2ecf20Sopenharmony_ci		if (ret < 0)
6488c2ecf20Sopenharmony_ci			return ret;
6498c2ecf20Sopenharmony_ci
6508c2ecf20Sopenharmony_ci		return IIO_VAL_INT;
6518c2ecf20Sopenharmony_ci	default:
6528c2ecf20Sopenharmony_ci		return -EINVAL;
6538c2ecf20Sopenharmony_ci	}
6548c2ecf20Sopenharmony_ci}
6558c2ecf20Sopenharmony_ci
6568c2ecf20Sopenharmony_cistatic int isl29501_get_scale(struct isl29501_private *isl29501,
6578c2ecf20Sopenharmony_ci			      const struct iio_chan_spec *chan,
6588c2ecf20Sopenharmony_ci			      int *val, int *val2)
6598c2ecf20Sopenharmony_ci{
6608c2ecf20Sopenharmony_ci	int ret;
6618c2ecf20Sopenharmony_ci	u32 current_scale;
6628c2ecf20Sopenharmony_ci
6638c2ecf20Sopenharmony_ci	switch (chan->type) {
6648c2ecf20Sopenharmony_ci	case IIO_PROXIMITY:
6658c2ecf20Sopenharmony_ci		/* distance = raw_distance * 33.31 / 65536 (m) */
6668c2ecf20Sopenharmony_ci		*val = 3331;
6678c2ecf20Sopenharmony_ci		*val2 = 6553600;
6688c2ecf20Sopenharmony_ci
6698c2ecf20Sopenharmony_ci		return IIO_VAL_FRACTIONAL;
6708c2ecf20Sopenharmony_ci	case IIO_PHASE:
6718c2ecf20Sopenharmony_ci		/* phase = raw_phase * 2pi / 65536 (rad) */
6728c2ecf20Sopenharmony_ci		*val = 0;
6738c2ecf20Sopenharmony_ci		*val2 = 95874;
6748c2ecf20Sopenharmony_ci
6758c2ecf20Sopenharmony_ci		return IIO_VAL_INT_PLUS_NANO;
6768c2ecf20Sopenharmony_ci	case IIO_INTENSITY:
6778c2ecf20Sopenharmony_ci		/* light = raw_light * 35 / 10000 (mA) */
6788c2ecf20Sopenharmony_ci		*val = 35;
6798c2ecf20Sopenharmony_ci		*val2 = 10000;
6808c2ecf20Sopenharmony_ci
6818c2ecf20Sopenharmony_ci		return IIO_VAL_FRACTIONAL;
6828c2ecf20Sopenharmony_ci	case IIO_CURRENT:
6838c2ecf20Sopenharmony_ci		ret = isl29501_register_read(isl29501,
6848c2ecf20Sopenharmony_ci					     REG_DRIVER_RANGE,
6858c2ecf20Sopenharmony_ci					     &current_scale);
6868c2ecf20Sopenharmony_ci		if (ret < 0)
6878c2ecf20Sopenharmony_ci			return ret;
6888c2ecf20Sopenharmony_ci
6898c2ecf20Sopenharmony_ci		if (current_scale > ARRAY_SIZE(isl29501_current_scale_table))
6908c2ecf20Sopenharmony_ci			return -EINVAL;
6918c2ecf20Sopenharmony_ci
6928c2ecf20Sopenharmony_ci		if (!current_scale) {
6938c2ecf20Sopenharmony_ci			*val = 0;
6948c2ecf20Sopenharmony_ci			*val2 = 0;
6958c2ecf20Sopenharmony_ci			return IIO_VAL_INT;
6968c2ecf20Sopenharmony_ci		}
6978c2ecf20Sopenharmony_ci
6988c2ecf20Sopenharmony_ci		*val = isl29501_current_scale_table[current_scale - 1][0];
6998c2ecf20Sopenharmony_ci		*val2 = isl29501_current_scale_table[current_scale - 1][1];
7008c2ecf20Sopenharmony_ci
7018c2ecf20Sopenharmony_ci		return IIO_VAL_INT_PLUS_MICRO;
7028c2ecf20Sopenharmony_ci	case IIO_TEMP:
7038c2ecf20Sopenharmony_ci		/* temperature = raw_temperature * 125 / 100000 (milli °C) */
7048c2ecf20Sopenharmony_ci		*val = 125;
7058c2ecf20Sopenharmony_ci		*val2 = 100000;
7068c2ecf20Sopenharmony_ci
7078c2ecf20Sopenharmony_ci		return IIO_VAL_FRACTIONAL;
7088c2ecf20Sopenharmony_ci	default:
7098c2ecf20Sopenharmony_ci		return -EINVAL;
7108c2ecf20Sopenharmony_ci	}
7118c2ecf20Sopenharmony_ci}
7128c2ecf20Sopenharmony_ci
7138c2ecf20Sopenharmony_cistatic int isl29501_get_calibbias(struct isl29501_private *isl29501,
7148c2ecf20Sopenharmony_ci				  const struct iio_chan_spec *chan,
7158c2ecf20Sopenharmony_ci				  int *bias)
7168c2ecf20Sopenharmony_ci{
7178c2ecf20Sopenharmony_ci	switch (chan->type) {
7188c2ecf20Sopenharmony_ci	case IIO_PROXIMITY:
7198c2ecf20Sopenharmony_ci		return isl29501_register_read(isl29501,
7208c2ecf20Sopenharmony_ci					      REG_DISTANCE_BIAS,
7218c2ecf20Sopenharmony_ci					      bias);
7228c2ecf20Sopenharmony_ci	case IIO_TEMP:
7238c2ecf20Sopenharmony_ci		return isl29501_register_read(isl29501,
7248c2ecf20Sopenharmony_ci					      REG_TEMPERATURE_BIAS,
7258c2ecf20Sopenharmony_ci					      bias);
7268c2ecf20Sopenharmony_ci	default:
7278c2ecf20Sopenharmony_ci		return -EINVAL;
7288c2ecf20Sopenharmony_ci	}
7298c2ecf20Sopenharmony_ci}
7308c2ecf20Sopenharmony_ci
7318c2ecf20Sopenharmony_cistatic int isl29501_get_inttime(struct isl29501_private *isl29501,
7328c2ecf20Sopenharmony_ci				int *val, int *val2)
7338c2ecf20Sopenharmony_ci{
7348c2ecf20Sopenharmony_ci	int ret;
7358c2ecf20Sopenharmony_ci	u32 inttime;
7368c2ecf20Sopenharmony_ci
7378c2ecf20Sopenharmony_ci	ret = isl29501_register_read(isl29501, REG_INT_TIME, &inttime);
7388c2ecf20Sopenharmony_ci	if (ret < 0)
7398c2ecf20Sopenharmony_ci		return ret;
7408c2ecf20Sopenharmony_ci
7418c2ecf20Sopenharmony_ci	if (inttime >= ARRAY_SIZE(isl29501_int_time))
7428c2ecf20Sopenharmony_ci		return -EINVAL;
7438c2ecf20Sopenharmony_ci
7448c2ecf20Sopenharmony_ci	*val = isl29501_int_time[inttime][0];
7458c2ecf20Sopenharmony_ci	*val2 = isl29501_int_time[inttime][1];
7468c2ecf20Sopenharmony_ci
7478c2ecf20Sopenharmony_ci	return IIO_VAL_INT_PLUS_MICRO;
7488c2ecf20Sopenharmony_ci}
7498c2ecf20Sopenharmony_ci
7508c2ecf20Sopenharmony_cistatic int isl29501_get_freq(struct isl29501_private *isl29501,
7518c2ecf20Sopenharmony_ci			     int *val, int *val2)
7528c2ecf20Sopenharmony_ci{
7538c2ecf20Sopenharmony_ci	int ret;
7548c2ecf20Sopenharmony_ci	int sample_time;
7558c2ecf20Sopenharmony_ci	unsigned long long freq;
7568c2ecf20Sopenharmony_ci	u32 temp;
7578c2ecf20Sopenharmony_ci
7588c2ecf20Sopenharmony_ci	ret = isl29501_register_read(isl29501, REG_SAMPLE_TIME, &sample_time);
7598c2ecf20Sopenharmony_ci	if (ret < 0)
7608c2ecf20Sopenharmony_ci		return ret;
7618c2ecf20Sopenharmony_ci
7628c2ecf20Sopenharmony_ci	/* freq = 1 / (0.000450 * (sample_time + 1) * 10^-6) */
7638c2ecf20Sopenharmony_ci	freq = 1000000ULL * 1000000ULL;
7648c2ecf20Sopenharmony_ci
7658c2ecf20Sopenharmony_ci	do_div(freq, 450 * (sample_time + 1));
7668c2ecf20Sopenharmony_ci
7678c2ecf20Sopenharmony_ci	temp = do_div(freq, 1000000);
7688c2ecf20Sopenharmony_ci	*val = freq;
7698c2ecf20Sopenharmony_ci	*val2 = temp;
7708c2ecf20Sopenharmony_ci
7718c2ecf20Sopenharmony_ci	return IIO_VAL_INT_PLUS_MICRO;
7728c2ecf20Sopenharmony_ci}
7738c2ecf20Sopenharmony_ci
7748c2ecf20Sopenharmony_cistatic int isl29501_read_raw(struct iio_dev *indio_dev,
7758c2ecf20Sopenharmony_ci			     struct iio_chan_spec const *chan, int *val,
7768c2ecf20Sopenharmony_ci			     int *val2, long mask)
7778c2ecf20Sopenharmony_ci{
7788c2ecf20Sopenharmony_ci	struct isl29501_private *isl29501 = iio_priv(indio_dev);
7798c2ecf20Sopenharmony_ci
7808c2ecf20Sopenharmony_ci	switch (mask) {
7818c2ecf20Sopenharmony_ci	case IIO_CHAN_INFO_RAW:
7828c2ecf20Sopenharmony_ci		return isl29501_get_raw(isl29501, chan, val);
7838c2ecf20Sopenharmony_ci	case IIO_CHAN_INFO_SCALE:
7848c2ecf20Sopenharmony_ci		return isl29501_get_scale(isl29501, chan, val, val2);
7858c2ecf20Sopenharmony_ci	case IIO_CHAN_INFO_INT_TIME:
7868c2ecf20Sopenharmony_ci		return isl29501_get_inttime(isl29501, val, val2);
7878c2ecf20Sopenharmony_ci	case IIO_CHAN_INFO_SAMP_FREQ:
7888c2ecf20Sopenharmony_ci		return isl29501_get_freq(isl29501, val, val2);
7898c2ecf20Sopenharmony_ci	case IIO_CHAN_INFO_CALIBBIAS:
7908c2ecf20Sopenharmony_ci		return isl29501_get_calibbias(isl29501, chan, val);
7918c2ecf20Sopenharmony_ci	default:
7928c2ecf20Sopenharmony_ci		return -EINVAL;
7938c2ecf20Sopenharmony_ci	}
7948c2ecf20Sopenharmony_ci}
7958c2ecf20Sopenharmony_ci
7968c2ecf20Sopenharmony_cistatic int isl29501_set_raw(struct isl29501_private *isl29501,
7978c2ecf20Sopenharmony_ci			    const struct iio_chan_spec *chan,
7988c2ecf20Sopenharmony_ci			    int raw)
7998c2ecf20Sopenharmony_ci{
8008c2ecf20Sopenharmony_ci	switch (chan->type) {
8018c2ecf20Sopenharmony_ci	case IIO_CURRENT:
8028c2ecf20Sopenharmony_ci		return isl29501_register_write(isl29501, REG_EMITTER_DAC, raw);
8038c2ecf20Sopenharmony_ci	default:
8048c2ecf20Sopenharmony_ci		return -EINVAL;
8058c2ecf20Sopenharmony_ci	}
8068c2ecf20Sopenharmony_ci}
8078c2ecf20Sopenharmony_ci
8088c2ecf20Sopenharmony_cistatic int isl29501_set_inttime(struct isl29501_private *isl29501,
8098c2ecf20Sopenharmony_ci				int val, int val2)
8108c2ecf20Sopenharmony_ci{
8118c2ecf20Sopenharmony_ci	int i;
8128c2ecf20Sopenharmony_ci
8138c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(isl29501_int_time); i++) {
8148c2ecf20Sopenharmony_ci		if (isl29501_int_time[i][0] == val &&
8158c2ecf20Sopenharmony_ci		    isl29501_int_time[i][1] == val2) {
8168c2ecf20Sopenharmony_ci			return isl29501_register_write(isl29501,
8178c2ecf20Sopenharmony_ci						       REG_INT_TIME,
8188c2ecf20Sopenharmony_ci						       i);
8198c2ecf20Sopenharmony_ci		}
8208c2ecf20Sopenharmony_ci	}
8218c2ecf20Sopenharmony_ci
8228c2ecf20Sopenharmony_ci	return -EINVAL;
8238c2ecf20Sopenharmony_ci}
8248c2ecf20Sopenharmony_ci
8258c2ecf20Sopenharmony_cistatic int isl29501_set_scale(struct isl29501_private *isl29501,
8268c2ecf20Sopenharmony_ci			      const struct iio_chan_spec *chan,
8278c2ecf20Sopenharmony_ci			      int val, int val2)
8288c2ecf20Sopenharmony_ci{
8298c2ecf20Sopenharmony_ci	int i;
8308c2ecf20Sopenharmony_ci
8318c2ecf20Sopenharmony_ci	if (chan->type != IIO_CURRENT)
8328c2ecf20Sopenharmony_ci		return -EINVAL;
8338c2ecf20Sopenharmony_ci
8348c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(isl29501_current_scale_table); i++) {
8358c2ecf20Sopenharmony_ci		if (isl29501_current_scale_table[i][0] == val &&
8368c2ecf20Sopenharmony_ci		    isl29501_current_scale_table[i][1] == val2) {
8378c2ecf20Sopenharmony_ci			return isl29501_register_write(isl29501,
8388c2ecf20Sopenharmony_ci						       REG_DRIVER_RANGE,
8398c2ecf20Sopenharmony_ci						       i + 1);
8408c2ecf20Sopenharmony_ci		}
8418c2ecf20Sopenharmony_ci	}
8428c2ecf20Sopenharmony_ci
8438c2ecf20Sopenharmony_ci	return -EINVAL;
8448c2ecf20Sopenharmony_ci}
8458c2ecf20Sopenharmony_ci
8468c2ecf20Sopenharmony_cistatic int isl29501_set_calibbias(struct isl29501_private *isl29501,
8478c2ecf20Sopenharmony_ci				  const struct iio_chan_spec *chan,
8488c2ecf20Sopenharmony_ci				  int bias)
8498c2ecf20Sopenharmony_ci{
8508c2ecf20Sopenharmony_ci	switch (chan->type) {
8518c2ecf20Sopenharmony_ci	case IIO_PROXIMITY:
8528c2ecf20Sopenharmony_ci		return isl29501_register_write(isl29501,
8538c2ecf20Sopenharmony_ci					      REG_DISTANCE_BIAS,
8548c2ecf20Sopenharmony_ci					      bias);
8558c2ecf20Sopenharmony_ci	case IIO_TEMP:
8568c2ecf20Sopenharmony_ci		return isl29501_register_write(isl29501,
8578c2ecf20Sopenharmony_ci					       REG_TEMPERATURE_BIAS,
8588c2ecf20Sopenharmony_ci					       bias);
8598c2ecf20Sopenharmony_ci	default:
8608c2ecf20Sopenharmony_ci		return -EINVAL;
8618c2ecf20Sopenharmony_ci	}
8628c2ecf20Sopenharmony_ci}
8638c2ecf20Sopenharmony_ci
8648c2ecf20Sopenharmony_cistatic int isl29501_set_freq(struct isl29501_private *isl29501,
8658c2ecf20Sopenharmony_ci			     int val, int val2)
8668c2ecf20Sopenharmony_ci{
8678c2ecf20Sopenharmony_ci	int freq;
8688c2ecf20Sopenharmony_ci	unsigned long long sample_time;
8698c2ecf20Sopenharmony_ci
8708c2ecf20Sopenharmony_ci	/* sample_freq = 1 / (0.000450 * (sample_time + 1) * 10^-6) */
8718c2ecf20Sopenharmony_ci	freq = val * 1000000 + val2 % 1000000;
8728c2ecf20Sopenharmony_ci	sample_time = 2222ULL * 1000000ULL;
8738c2ecf20Sopenharmony_ci	do_div(sample_time, freq);
8748c2ecf20Sopenharmony_ci
8758c2ecf20Sopenharmony_ci	sample_time -= 1;
8768c2ecf20Sopenharmony_ci
8778c2ecf20Sopenharmony_ci	if (sample_time > 255)
8788c2ecf20Sopenharmony_ci		return -ERANGE;
8798c2ecf20Sopenharmony_ci
8808c2ecf20Sopenharmony_ci	return isl29501_register_write(isl29501, REG_SAMPLE_TIME, sample_time);
8818c2ecf20Sopenharmony_ci}
8828c2ecf20Sopenharmony_ci
8838c2ecf20Sopenharmony_cistatic int isl29501_write_raw(struct iio_dev *indio_dev,
8848c2ecf20Sopenharmony_ci			      struct iio_chan_spec const *chan,
8858c2ecf20Sopenharmony_ci			      int val, int val2, long mask)
8868c2ecf20Sopenharmony_ci{
8878c2ecf20Sopenharmony_ci	struct isl29501_private *isl29501 = iio_priv(indio_dev);
8888c2ecf20Sopenharmony_ci
8898c2ecf20Sopenharmony_ci	switch (mask) {
8908c2ecf20Sopenharmony_ci	case IIO_CHAN_INFO_RAW:
8918c2ecf20Sopenharmony_ci		return isl29501_set_raw(isl29501, chan, val);
8928c2ecf20Sopenharmony_ci	case IIO_CHAN_INFO_INT_TIME:
8938c2ecf20Sopenharmony_ci		return isl29501_set_inttime(isl29501, val, val2);
8948c2ecf20Sopenharmony_ci	case IIO_CHAN_INFO_SAMP_FREQ:
8958c2ecf20Sopenharmony_ci		return isl29501_set_freq(isl29501, val, val2);
8968c2ecf20Sopenharmony_ci	case IIO_CHAN_INFO_SCALE:
8978c2ecf20Sopenharmony_ci		return isl29501_set_scale(isl29501, chan, val, val2);
8988c2ecf20Sopenharmony_ci	case IIO_CHAN_INFO_CALIBBIAS:
8998c2ecf20Sopenharmony_ci		return isl29501_set_calibbias(isl29501, chan, val);
9008c2ecf20Sopenharmony_ci	default:
9018c2ecf20Sopenharmony_ci		return -EINVAL;
9028c2ecf20Sopenharmony_ci	}
9038c2ecf20Sopenharmony_ci}
9048c2ecf20Sopenharmony_ci
9058c2ecf20Sopenharmony_cistatic const struct iio_info isl29501_info = {
9068c2ecf20Sopenharmony_ci	.read_raw = &isl29501_read_raw,
9078c2ecf20Sopenharmony_ci	.write_raw = &isl29501_write_raw,
9088c2ecf20Sopenharmony_ci	.attrs = &isl29501_attribute_group,
9098c2ecf20Sopenharmony_ci};
9108c2ecf20Sopenharmony_ci
9118c2ecf20Sopenharmony_cistatic int isl29501_init_chip(struct isl29501_private *isl29501)
9128c2ecf20Sopenharmony_ci{
9138c2ecf20Sopenharmony_ci	int ret;
9148c2ecf20Sopenharmony_ci
9158c2ecf20Sopenharmony_ci	ret = i2c_smbus_read_byte_data(isl29501->client, ISL29501_DEVICE_ID);
9168c2ecf20Sopenharmony_ci	if (ret < 0) {
9178c2ecf20Sopenharmony_ci		dev_err(&isl29501->client->dev, "Error reading device id\n");
9188c2ecf20Sopenharmony_ci		return ret;
9198c2ecf20Sopenharmony_ci	}
9208c2ecf20Sopenharmony_ci
9218c2ecf20Sopenharmony_ci	if (ret != ISL29501_ID) {
9228c2ecf20Sopenharmony_ci		dev_err(&isl29501->client->dev,
9238c2ecf20Sopenharmony_ci			"Wrong chip id, got %x expected %x\n",
9248c2ecf20Sopenharmony_ci			ret, ISL29501_DEVICE_ID);
9258c2ecf20Sopenharmony_ci		return -ENODEV;
9268c2ecf20Sopenharmony_ci	}
9278c2ecf20Sopenharmony_ci
9288c2ecf20Sopenharmony_ci	ret = isl29501_reset_registers(isl29501);
9298c2ecf20Sopenharmony_ci	if (ret < 0)
9308c2ecf20Sopenharmony_ci		return ret;
9318c2ecf20Sopenharmony_ci
9328c2ecf20Sopenharmony_ci	return isl29501_begin_acquisition(isl29501);
9338c2ecf20Sopenharmony_ci}
9348c2ecf20Sopenharmony_ci
9358c2ecf20Sopenharmony_cistatic irqreturn_t isl29501_trigger_handler(int irq, void *p)
9368c2ecf20Sopenharmony_ci{
9378c2ecf20Sopenharmony_ci	struct iio_poll_func *pf = p;
9388c2ecf20Sopenharmony_ci	struct iio_dev *indio_dev = pf->indio_dev;
9398c2ecf20Sopenharmony_ci	struct isl29501_private *isl29501 = iio_priv(indio_dev);
9408c2ecf20Sopenharmony_ci	const unsigned long *active_mask = indio_dev->active_scan_mask;
9418c2ecf20Sopenharmony_ci	u32 buffer[4] __aligned(8) = {}; /* 1x16-bit + naturally aligned ts */
9428c2ecf20Sopenharmony_ci
9438c2ecf20Sopenharmony_ci	if (test_bit(ISL29501_DISTANCE_SCAN_INDEX, active_mask))
9448c2ecf20Sopenharmony_ci		isl29501_register_read(isl29501, REG_DISTANCE, buffer);
9458c2ecf20Sopenharmony_ci
9468c2ecf20Sopenharmony_ci	iio_push_to_buffers_with_timestamp(indio_dev, buffer, pf->timestamp);
9478c2ecf20Sopenharmony_ci	iio_trigger_notify_done(indio_dev->trig);
9488c2ecf20Sopenharmony_ci
9498c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
9508c2ecf20Sopenharmony_ci}
9518c2ecf20Sopenharmony_ci
9528c2ecf20Sopenharmony_cistatic int isl29501_probe(struct i2c_client *client,
9538c2ecf20Sopenharmony_ci			  const struct i2c_device_id *id)
9548c2ecf20Sopenharmony_ci{
9558c2ecf20Sopenharmony_ci	struct iio_dev *indio_dev;
9568c2ecf20Sopenharmony_ci	struct isl29501_private *isl29501;
9578c2ecf20Sopenharmony_ci	int ret;
9588c2ecf20Sopenharmony_ci
9598c2ecf20Sopenharmony_ci	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*isl29501));
9608c2ecf20Sopenharmony_ci	if (!indio_dev)
9618c2ecf20Sopenharmony_ci		return -ENOMEM;
9628c2ecf20Sopenharmony_ci
9638c2ecf20Sopenharmony_ci	isl29501 = iio_priv(indio_dev);
9648c2ecf20Sopenharmony_ci
9658c2ecf20Sopenharmony_ci	i2c_set_clientdata(client, indio_dev);
9668c2ecf20Sopenharmony_ci	isl29501->client = client;
9678c2ecf20Sopenharmony_ci
9688c2ecf20Sopenharmony_ci	mutex_init(&isl29501->lock);
9698c2ecf20Sopenharmony_ci
9708c2ecf20Sopenharmony_ci	ret = isl29501_init_chip(isl29501);
9718c2ecf20Sopenharmony_ci	if (ret < 0)
9728c2ecf20Sopenharmony_ci		return ret;
9738c2ecf20Sopenharmony_ci
9748c2ecf20Sopenharmony_ci	indio_dev->modes = INDIO_DIRECT_MODE;
9758c2ecf20Sopenharmony_ci	indio_dev->channels = isl29501_channels;
9768c2ecf20Sopenharmony_ci	indio_dev->num_channels = ARRAY_SIZE(isl29501_channels);
9778c2ecf20Sopenharmony_ci	indio_dev->name = client->name;
9788c2ecf20Sopenharmony_ci	indio_dev->info = &isl29501_info;
9798c2ecf20Sopenharmony_ci
9808c2ecf20Sopenharmony_ci	ret = devm_iio_triggered_buffer_setup(&client->dev, indio_dev,
9818c2ecf20Sopenharmony_ci					      iio_pollfunc_store_time,
9828c2ecf20Sopenharmony_ci					      isl29501_trigger_handler,
9838c2ecf20Sopenharmony_ci					      NULL);
9848c2ecf20Sopenharmony_ci	if (ret < 0) {
9858c2ecf20Sopenharmony_ci		dev_err(&client->dev, "unable to setup iio triggered buffer\n");
9868c2ecf20Sopenharmony_ci		return ret;
9878c2ecf20Sopenharmony_ci	}
9888c2ecf20Sopenharmony_ci
9898c2ecf20Sopenharmony_ci	return devm_iio_device_register(&client->dev, indio_dev);
9908c2ecf20Sopenharmony_ci}
9918c2ecf20Sopenharmony_ci
9928c2ecf20Sopenharmony_cistatic const struct i2c_device_id isl29501_id[] = {
9938c2ecf20Sopenharmony_ci	{"isl29501", 0},
9948c2ecf20Sopenharmony_ci	{}
9958c2ecf20Sopenharmony_ci};
9968c2ecf20Sopenharmony_ci
9978c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, isl29501_id);
9988c2ecf20Sopenharmony_ci
9998c2ecf20Sopenharmony_ci#if defined(CONFIG_OF)
10008c2ecf20Sopenharmony_cistatic const struct of_device_id isl29501_i2c_matches[] = {
10018c2ecf20Sopenharmony_ci	{ .compatible = "renesas,isl29501" },
10028c2ecf20Sopenharmony_ci	{ }
10038c2ecf20Sopenharmony_ci};
10048c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, isl29501_i2c_matches);
10058c2ecf20Sopenharmony_ci#endif
10068c2ecf20Sopenharmony_ci
10078c2ecf20Sopenharmony_cistatic struct i2c_driver isl29501_driver = {
10088c2ecf20Sopenharmony_ci	.driver = {
10098c2ecf20Sopenharmony_ci		.name	= "isl29501",
10108c2ecf20Sopenharmony_ci	},
10118c2ecf20Sopenharmony_ci	.id_table	= isl29501_id,
10128c2ecf20Sopenharmony_ci	.probe		= isl29501_probe,
10138c2ecf20Sopenharmony_ci};
10148c2ecf20Sopenharmony_cimodule_i2c_driver(isl29501_driver);
10158c2ecf20Sopenharmony_ci
10168c2ecf20Sopenharmony_ciMODULE_AUTHOR("Mathieu Othacehe <m.othacehe@gmail.com>");
10178c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("ISL29501 Time of Flight sensor driver");
10188c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2");
1019