18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * si1133.c - Support for Silabs SI1133 combined ambient
48c2ecf20Sopenharmony_ci * light and UV index sensors
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * Copyright 2018 Maxime Roussin-Belanger <maxime.roussinbelanger@gmail.com>
78c2ecf20Sopenharmony_ci */
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include <linux/delay.h>
108c2ecf20Sopenharmony_ci#include <linux/i2c.h>
118c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
128c2ecf20Sopenharmony_ci#include <linux/module.h>
138c2ecf20Sopenharmony_ci#include <linux/regmap.h>
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci#include <linux/iio/iio.h>
168c2ecf20Sopenharmony_ci#include <linux/iio/sysfs.h>
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci#include <linux/util_macros.h>
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci#include <asm/unaligned.h>
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci#define SI1133_REG_PART_ID		0x00
238c2ecf20Sopenharmony_ci#define SI1133_REG_REV_ID		0x01
248c2ecf20Sopenharmony_ci#define SI1133_REG_MFR_ID		0x02
258c2ecf20Sopenharmony_ci#define SI1133_REG_INFO0		0x03
268c2ecf20Sopenharmony_ci#define SI1133_REG_INFO1		0x04
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci#define SI1133_PART_ID			0x33
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci#define SI1133_REG_HOSTIN0		0x0A
318c2ecf20Sopenharmony_ci#define SI1133_REG_COMMAND		0x0B
328c2ecf20Sopenharmony_ci#define SI1133_REG_IRQ_ENABLE		0x0F
338c2ecf20Sopenharmony_ci#define SI1133_REG_RESPONSE1		0x10
348c2ecf20Sopenharmony_ci#define SI1133_REG_RESPONSE0		0x11
358c2ecf20Sopenharmony_ci#define SI1133_REG_IRQ_STATUS		0x12
368c2ecf20Sopenharmony_ci#define SI1133_REG_MEAS_RATE		0x1A
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci#define SI1133_IRQ_CHANNEL_ENABLE	0xF
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci#define SI1133_CMD_RESET_CTR		0x00
418c2ecf20Sopenharmony_ci#define SI1133_CMD_RESET_SW		0x01
428c2ecf20Sopenharmony_ci#define SI1133_CMD_FORCE		0x11
438c2ecf20Sopenharmony_ci#define SI1133_CMD_START_AUTONOMOUS	0x13
448c2ecf20Sopenharmony_ci#define SI1133_CMD_PARAM_SET		0x80
458c2ecf20Sopenharmony_ci#define SI1133_CMD_PARAM_QUERY		0x40
468c2ecf20Sopenharmony_ci#define SI1133_CMD_PARAM_MASK		0x3F
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci#define SI1133_CMD_ERR_MASK		BIT(4)
498c2ecf20Sopenharmony_ci#define SI1133_CMD_SEQ_MASK		0xF
508c2ecf20Sopenharmony_ci#define SI1133_MAX_CMD_CTR		0xF
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci#define SI1133_PARAM_REG_CHAN_LIST	0x01
538c2ecf20Sopenharmony_ci#define SI1133_PARAM_REG_ADCCONFIG(x)	((x) * 4) + 2
548c2ecf20Sopenharmony_ci#define SI1133_PARAM_REG_ADCSENS(x)	((x) * 4) + 3
558c2ecf20Sopenharmony_ci#define SI1133_PARAM_REG_ADCPOST(x)	((x) * 4) + 4
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci#define SI1133_ADCMUX_MASK 0x1F
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci#define SI1133_ADCCONFIG_DECIM_RATE(x)	(x) << 5
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci#define SI1133_ADCSENS_SCALE_MASK 0x70
628c2ecf20Sopenharmony_ci#define SI1133_ADCSENS_SCALE_SHIFT 4
638c2ecf20Sopenharmony_ci#define SI1133_ADCSENS_HSIG_MASK BIT(7)
648c2ecf20Sopenharmony_ci#define SI1133_ADCSENS_HSIG_SHIFT 7
658c2ecf20Sopenharmony_ci#define SI1133_ADCSENS_HW_GAIN_MASK 0xF
668c2ecf20Sopenharmony_ci#define SI1133_ADCSENS_NB_MEAS(x)	fls(x) << SI1133_ADCSENS_SCALE_SHIFT
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci#define SI1133_ADCPOST_24BIT_EN BIT(6)
698c2ecf20Sopenharmony_ci#define SI1133_ADCPOST_POSTSHIFT_BITQTY(x) (x & GENMASK(2, 0)) << 3
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci#define SI1133_PARAM_ADCMUX_SMALL_IR	0x0
728c2ecf20Sopenharmony_ci#define SI1133_PARAM_ADCMUX_MED_IR	0x1
738c2ecf20Sopenharmony_ci#define SI1133_PARAM_ADCMUX_LARGE_IR	0x2
748c2ecf20Sopenharmony_ci#define SI1133_PARAM_ADCMUX_WHITE	0xB
758c2ecf20Sopenharmony_ci#define SI1133_PARAM_ADCMUX_LARGE_WHITE	0xD
768c2ecf20Sopenharmony_ci#define SI1133_PARAM_ADCMUX_UV		0x18
778c2ecf20Sopenharmony_ci#define SI1133_PARAM_ADCMUX_UV_DEEP	0x19
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci#define SI1133_ERR_INVALID_CMD		0x0
808c2ecf20Sopenharmony_ci#define SI1133_ERR_INVALID_LOCATION_CMD 0x1
818c2ecf20Sopenharmony_ci#define SI1133_ERR_SATURATION_ADC_OR_OVERFLOW_ACCUMULATION 0x2
828c2ecf20Sopenharmony_ci#define SI1133_ERR_OUTPUT_BUFFER_OVERFLOW 0x3
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci#define SI1133_COMPLETION_TIMEOUT_MS	500
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci#define SI1133_CMD_MINSLEEP_US_LOW	5000
878c2ecf20Sopenharmony_ci#define SI1133_CMD_MINSLEEP_US_HIGH	7500
888c2ecf20Sopenharmony_ci#define SI1133_CMD_TIMEOUT_MS		25
898c2ecf20Sopenharmony_ci#define SI1133_CMD_LUX_TIMEOUT_MS	5000
908c2ecf20Sopenharmony_ci#define SI1133_CMD_TIMEOUT_US		SI1133_CMD_TIMEOUT_MS * 1000
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci#define SI1133_REG_HOSTOUT(x)		(x) + 0x13
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci#define SI1133_MEASUREMENT_FREQUENCY 1250
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci#define SI1133_X_ORDER_MASK            0x0070
978c2ecf20Sopenharmony_ci#define SI1133_Y_ORDER_MASK            0x0007
988c2ecf20Sopenharmony_ci#define si1133_get_x_order(m)          ((m) & SI1133_X_ORDER_MASK) >> 4
998c2ecf20Sopenharmony_ci#define si1133_get_y_order(m)          ((m) & SI1133_Y_ORDER_MASK)
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci#define SI1133_LUX_ADC_MASK		0xE
1028c2ecf20Sopenharmony_ci#define SI1133_ADC_THRESHOLD		16000
1038c2ecf20Sopenharmony_ci#define SI1133_INPUT_FRACTION_HIGH	7
1048c2ecf20Sopenharmony_ci#define SI1133_INPUT_FRACTION_LOW	15
1058c2ecf20Sopenharmony_ci#define SI1133_LUX_OUTPUT_FRACTION	12
1068c2ecf20Sopenharmony_ci#define SI1133_LUX_BUFFER_SIZE		9
1078c2ecf20Sopenharmony_ci#define SI1133_MEASURE_BUFFER_SIZE	3
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_cistatic const int si1133_scale_available[] = {
1108c2ecf20Sopenharmony_ci	1, 2, 4, 8, 16, 32, 64, 128};
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_cistatic IIO_CONST_ATTR(scale_available, "1 2 4 8 16 32 64 128");
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_cistatic IIO_CONST_ATTR_INT_TIME_AVAIL("0.0244 0.0488 0.0975 0.195 0.390 0.780 "
1158c2ecf20Sopenharmony_ci				     "1.560 3.120 6.24 12.48 25.0 50.0");
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci/* A.K.A. HW_GAIN in datasheet */
1188c2ecf20Sopenharmony_cienum si1133_int_time {
1198c2ecf20Sopenharmony_ci	    _24_4_us = 0,
1208c2ecf20Sopenharmony_ci	    _48_8_us = 1,
1218c2ecf20Sopenharmony_ci	    _97_5_us = 2,
1228c2ecf20Sopenharmony_ci	   _195_0_us = 3,
1238c2ecf20Sopenharmony_ci	   _390_0_us = 4,
1248c2ecf20Sopenharmony_ci	   _780_0_us = 5,
1258c2ecf20Sopenharmony_ci	 _1_560_0_us = 6,
1268c2ecf20Sopenharmony_ci	 _3_120_0_us = 7,
1278c2ecf20Sopenharmony_ci	 _6_240_0_us = 8,
1288c2ecf20Sopenharmony_ci	_12_480_0_us = 9,
1298c2ecf20Sopenharmony_ci	_25_ms = 10,
1308c2ecf20Sopenharmony_ci	_50_ms = 11,
1318c2ecf20Sopenharmony_ci};
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci/* Integration time in milliseconds, nanoseconds */
1348c2ecf20Sopenharmony_cistatic const int si1133_int_time_table[][2] = {
1358c2ecf20Sopenharmony_ci	[_24_4_us] = {0, 24400},
1368c2ecf20Sopenharmony_ci	[_48_8_us] = {0, 48800},
1378c2ecf20Sopenharmony_ci	[_97_5_us] = {0, 97500},
1388c2ecf20Sopenharmony_ci	[_195_0_us] = {0, 195000},
1398c2ecf20Sopenharmony_ci	[_390_0_us] = {0, 390000},
1408c2ecf20Sopenharmony_ci	[_780_0_us] = {0, 780000},
1418c2ecf20Sopenharmony_ci	[_1_560_0_us] = {1, 560000},
1428c2ecf20Sopenharmony_ci	[_3_120_0_us] = {3, 120000},
1438c2ecf20Sopenharmony_ci	[_6_240_0_us] = {6, 240000},
1448c2ecf20Sopenharmony_ci	[_12_480_0_us] = {12, 480000},
1458c2ecf20Sopenharmony_ci	[_25_ms] = {25, 000000},
1468c2ecf20Sopenharmony_ci	[_50_ms] = {50, 000000},
1478c2ecf20Sopenharmony_ci};
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_cistatic const struct regmap_range si1133_reg_ranges[] = {
1508c2ecf20Sopenharmony_ci	regmap_reg_range(0x00, 0x02),
1518c2ecf20Sopenharmony_ci	regmap_reg_range(0x0A, 0x0B),
1528c2ecf20Sopenharmony_ci	regmap_reg_range(0x0F, 0x0F),
1538c2ecf20Sopenharmony_ci	regmap_reg_range(0x10, 0x12),
1548c2ecf20Sopenharmony_ci	regmap_reg_range(0x13, 0x2C),
1558c2ecf20Sopenharmony_ci};
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_cistatic const struct regmap_range si1133_reg_ro_ranges[] = {
1588c2ecf20Sopenharmony_ci	regmap_reg_range(0x00, 0x02),
1598c2ecf20Sopenharmony_ci	regmap_reg_range(0x10, 0x2C),
1608c2ecf20Sopenharmony_ci};
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_cistatic const struct regmap_range si1133_precious_ranges[] = {
1638c2ecf20Sopenharmony_ci	regmap_reg_range(0x12, 0x12),
1648c2ecf20Sopenharmony_ci};
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_cistatic const struct regmap_access_table si1133_write_ranges_table = {
1678c2ecf20Sopenharmony_ci	.yes_ranges	= si1133_reg_ranges,
1688c2ecf20Sopenharmony_ci	.n_yes_ranges	= ARRAY_SIZE(si1133_reg_ranges),
1698c2ecf20Sopenharmony_ci	.no_ranges	= si1133_reg_ro_ranges,
1708c2ecf20Sopenharmony_ci	.n_no_ranges	= ARRAY_SIZE(si1133_reg_ro_ranges),
1718c2ecf20Sopenharmony_ci};
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_cistatic const struct regmap_access_table si1133_read_ranges_table = {
1748c2ecf20Sopenharmony_ci	.yes_ranges	= si1133_reg_ranges,
1758c2ecf20Sopenharmony_ci	.n_yes_ranges	= ARRAY_SIZE(si1133_reg_ranges),
1768c2ecf20Sopenharmony_ci};
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_cistatic const struct regmap_access_table si1133_precious_table = {
1798c2ecf20Sopenharmony_ci	.yes_ranges	= si1133_precious_ranges,
1808c2ecf20Sopenharmony_ci	.n_yes_ranges	= ARRAY_SIZE(si1133_precious_ranges),
1818c2ecf20Sopenharmony_ci};
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_cistatic const struct regmap_config si1133_regmap_config = {
1848c2ecf20Sopenharmony_ci	.reg_bits = 8,
1858c2ecf20Sopenharmony_ci	.val_bits = 8,
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci	.max_register = 0x2C,
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci	.wr_table = &si1133_write_ranges_table,
1908c2ecf20Sopenharmony_ci	.rd_table = &si1133_read_ranges_table,
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci	.precious_table = &si1133_precious_table,
1938c2ecf20Sopenharmony_ci};
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_cistruct si1133_data {
1968c2ecf20Sopenharmony_ci	struct regmap *regmap;
1978c2ecf20Sopenharmony_ci	struct i2c_client *client;
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci	/* Lock protecting one command at a time can be processed */
2008c2ecf20Sopenharmony_ci	struct mutex mutex;
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci	int rsp_seq;
2038c2ecf20Sopenharmony_ci	u8 scan_mask;
2048c2ecf20Sopenharmony_ci	u8 adc_sens[6];
2058c2ecf20Sopenharmony_ci	u8 adc_config[6];
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci	struct completion completion;
2088c2ecf20Sopenharmony_ci};
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_cistruct si1133_coeff {
2118c2ecf20Sopenharmony_ci	s16 info;
2128c2ecf20Sopenharmony_ci	u16 mag;
2138c2ecf20Sopenharmony_ci};
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_cistruct si1133_lux_coeff {
2168c2ecf20Sopenharmony_ci	struct si1133_coeff coeff_high[4];
2178c2ecf20Sopenharmony_ci	struct si1133_coeff coeff_low[9];
2188c2ecf20Sopenharmony_ci};
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_cistatic const struct si1133_lux_coeff lux_coeff = {
2218c2ecf20Sopenharmony_ci	{
2228c2ecf20Sopenharmony_ci		{  0,   209},
2238c2ecf20Sopenharmony_ci		{ 1665,  93},
2248c2ecf20Sopenharmony_ci		{ 2064,  65},
2258c2ecf20Sopenharmony_ci		{-2671, 234}
2268c2ecf20Sopenharmony_ci	},
2278c2ecf20Sopenharmony_ci	{
2288c2ecf20Sopenharmony_ci		{    0,     0},
2298c2ecf20Sopenharmony_ci		{ 1921, 29053},
2308c2ecf20Sopenharmony_ci		{-1022, 36363},
2318c2ecf20Sopenharmony_ci		{ 2320, 20789},
2328c2ecf20Sopenharmony_ci		{ -367, 57909},
2338c2ecf20Sopenharmony_ci		{-1774, 38240},
2348c2ecf20Sopenharmony_ci		{ -608, 46775},
2358c2ecf20Sopenharmony_ci		{-1503, 51831},
2368c2ecf20Sopenharmony_ci		{-1886, 58928}
2378c2ecf20Sopenharmony_ci	}
2388c2ecf20Sopenharmony_ci};
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_cistatic int si1133_calculate_polynomial_inner(s32 input, u8 fraction, u16 mag,
2418c2ecf20Sopenharmony_ci					     s8 shift)
2428c2ecf20Sopenharmony_ci{
2438c2ecf20Sopenharmony_ci	return ((input << fraction) / mag) << shift;
2448c2ecf20Sopenharmony_ci}
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_cistatic int si1133_calculate_output(s32 x, s32 y, u8 x_order, u8 y_order,
2478c2ecf20Sopenharmony_ci				   u8 input_fraction, s8 sign,
2488c2ecf20Sopenharmony_ci				   const struct si1133_coeff *coeffs)
2498c2ecf20Sopenharmony_ci{
2508c2ecf20Sopenharmony_ci	s8 shift;
2518c2ecf20Sopenharmony_ci	int x1 = 1;
2528c2ecf20Sopenharmony_ci	int x2 = 1;
2538c2ecf20Sopenharmony_ci	int y1 = 1;
2548c2ecf20Sopenharmony_ci	int y2 = 1;
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_ci	shift = ((u16)coeffs->info & 0xFF00) >> 8;
2578c2ecf20Sopenharmony_ci	shift ^= 0xFF;
2588c2ecf20Sopenharmony_ci	shift += 1;
2598c2ecf20Sopenharmony_ci	shift = -shift;
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ci	if (x_order > 0) {
2628c2ecf20Sopenharmony_ci		x1 = si1133_calculate_polynomial_inner(x, input_fraction,
2638c2ecf20Sopenharmony_ci						       coeffs->mag, shift);
2648c2ecf20Sopenharmony_ci		if (x_order > 1)
2658c2ecf20Sopenharmony_ci			x2 = x1;
2668c2ecf20Sopenharmony_ci	}
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ci	if (y_order > 0) {
2698c2ecf20Sopenharmony_ci		y1 = si1133_calculate_polynomial_inner(y, input_fraction,
2708c2ecf20Sopenharmony_ci						       coeffs->mag, shift);
2718c2ecf20Sopenharmony_ci		if (y_order > 1)
2728c2ecf20Sopenharmony_ci			y2 = y1;
2738c2ecf20Sopenharmony_ci	}
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci	return sign * x1 * x2 * y1 * y2;
2768c2ecf20Sopenharmony_ci}
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci/*
2798c2ecf20Sopenharmony_ci * The algorithm is from:
2808c2ecf20Sopenharmony_ci * https://siliconlabs.github.io/Gecko_SDK_Doc/efm32zg/html/si1133_8c_source.html#l00716
2818c2ecf20Sopenharmony_ci */
2828c2ecf20Sopenharmony_cistatic int si1133_calc_polynomial(s32 x, s32 y, u8 input_fraction, u8 num_coeff,
2838c2ecf20Sopenharmony_ci				  const struct si1133_coeff *coeffs)
2848c2ecf20Sopenharmony_ci{
2858c2ecf20Sopenharmony_ci	u8 x_order, y_order;
2868c2ecf20Sopenharmony_ci	u8 counter;
2878c2ecf20Sopenharmony_ci	s8 sign;
2888c2ecf20Sopenharmony_ci	int output = 0;
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_ci	for (counter = 0; counter < num_coeff; counter++) {
2918c2ecf20Sopenharmony_ci		if (coeffs->info < 0)
2928c2ecf20Sopenharmony_ci			sign = -1;
2938c2ecf20Sopenharmony_ci		else
2948c2ecf20Sopenharmony_ci			sign = 1;
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci		x_order = si1133_get_x_order(coeffs->info);
2978c2ecf20Sopenharmony_ci		y_order = si1133_get_y_order(coeffs->info);
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci		if ((x_order == 0) && (y_order == 0))
3008c2ecf20Sopenharmony_ci			output +=
3018c2ecf20Sopenharmony_ci			       sign * coeffs->mag << SI1133_LUX_OUTPUT_FRACTION;
3028c2ecf20Sopenharmony_ci		else
3038c2ecf20Sopenharmony_ci			output += si1133_calculate_output(x, y, x_order,
3048c2ecf20Sopenharmony_ci							  y_order,
3058c2ecf20Sopenharmony_ci							  input_fraction, sign,
3068c2ecf20Sopenharmony_ci							  coeffs);
3078c2ecf20Sopenharmony_ci		coeffs++;
3088c2ecf20Sopenharmony_ci	}
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_ci	return abs(output);
3118c2ecf20Sopenharmony_ci}
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_cistatic int si1133_cmd_reset_sw(struct si1133_data *data)
3148c2ecf20Sopenharmony_ci{
3158c2ecf20Sopenharmony_ci	struct device *dev = &data->client->dev;
3168c2ecf20Sopenharmony_ci	unsigned int resp;
3178c2ecf20Sopenharmony_ci	unsigned long timeout;
3188c2ecf20Sopenharmony_ci	int err;
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_ci	err = regmap_write(data->regmap, SI1133_REG_COMMAND,
3218c2ecf20Sopenharmony_ci			   SI1133_CMD_RESET_SW);
3228c2ecf20Sopenharmony_ci	if (err)
3238c2ecf20Sopenharmony_ci		return err;
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ci	timeout = jiffies + msecs_to_jiffies(SI1133_CMD_TIMEOUT_MS);
3268c2ecf20Sopenharmony_ci	while (true) {
3278c2ecf20Sopenharmony_ci		err = regmap_read(data->regmap, SI1133_REG_RESPONSE0, &resp);
3288c2ecf20Sopenharmony_ci		if (err == -ENXIO) {
3298c2ecf20Sopenharmony_ci			usleep_range(SI1133_CMD_MINSLEEP_US_LOW,
3308c2ecf20Sopenharmony_ci				     SI1133_CMD_MINSLEEP_US_HIGH);
3318c2ecf20Sopenharmony_ci			continue;
3328c2ecf20Sopenharmony_ci		}
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci		if ((resp & SI1133_MAX_CMD_CTR) == SI1133_MAX_CMD_CTR)
3358c2ecf20Sopenharmony_ci			break;
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci		if (time_after(jiffies, timeout)) {
3388c2ecf20Sopenharmony_ci			dev_warn(dev, "Timeout on reset ctr resp: %d\n", resp);
3398c2ecf20Sopenharmony_ci			return -ETIMEDOUT;
3408c2ecf20Sopenharmony_ci		}
3418c2ecf20Sopenharmony_ci	}
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_ci	if (!err)
3448c2ecf20Sopenharmony_ci		data->rsp_seq = SI1133_MAX_CMD_CTR;
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci	return err;
3478c2ecf20Sopenharmony_ci}
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_cistatic int si1133_parse_response_err(struct device *dev, u32 resp, u8 cmd)
3508c2ecf20Sopenharmony_ci{
3518c2ecf20Sopenharmony_ci	resp &= 0xF;
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_ci	switch (resp) {
3548c2ecf20Sopenharmony_ci	case SI1133_ERR_OUTPUT_BUFFER_OVERFLOW:
3558c2ecf20Sopenharmony_ci		dev_warn(dev, "Output buffer overflow: %#02hhx\n", cmd);
3568c2ecf20Sopenharmony_ci		return -EOVERFLOW;
3578c2ecf20Sopenharmony_ci	case SI1133_ERR_SATURATION_ADC_OR_OVERFLOW_ACCUMULATION:
3588c2ecf20Sopenharmony_ci		dev_warn(dev, "Saturation of the ADC or overflow of accumulation: %#02hhx\n",
3598c2ecf20Sopenharmony_ci			 cmd);
3608c2ecf20Sopenharmony_ci		return -EOVERFLOW;
3618c2ecf20Sopenharmony_ci	case SI1133_ERR_INVALID_LOCATION_CMD:
3628c2ecf20Sopenharmony_ci		dev_warn(dev,
3638c2ecf20Sopenharmony_ci			 "Parameter access to an invalid location: %#02hhx\n",
3648c2ecf20Sopenharmony_ci			 cmd);
3658c2ecf20Sopenharmony_ci		return -EINVAL;
3668c2ecf20Sopenharmony_ci	case SI1133_ERR_INVALID_CMD:
3678c2ecf20Sopenharmony_ci		dev_warn(dev, "Invalid command %#02hhx\n", cmd);
3688c2ecf20Sopenharmony_ci		return -EINVAL;
3698c2ecf20Sopenharmony_ci	default:
3708c2ecf20Sopenharmony_ci		dev_warn(dev, "Unknown error %#02hhx\n", cmd);
3718c2ecf20Sopenharmony_ci		return -EINVAL;
3728c2ecf20Sopenharmony_ci	}
3738c2ecf20Sopenharmony_ci}
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_cistatic int si1133_cmd_reset_counter(struct si1133_data *data)
3768c2ecf20Sopenharmony_ci{
3778c2ecf20Sopenharmony_ci	int err = regmap_write(data->regmap, SI1133_REG_COMMAND,
3788c2ecf20Sopenharmony_ci			       SI1133_CMD_RESET_CTR);
3798c2ecf20Sopenharmony_ci	if (err)
3808c2ecf20Sopenharmony_ci		return err;
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_ci	data->rsp_seq = 0;
3838c2ecf20Sopenharmony_ci
3848c2ecf20Sopenharmony_ci	return 0;
3858c2ecf20Sopenharmony_ci}
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_cistatic int si1133_command(struct si1133_data *data, u8 cmd)
3888c2ecf20Sopenharmony_ci{
3898c2ecf20Sopenharmony_ci	struct device *dev = &data->client->dev;
3908c2ecf20Sopenharmony_ci	u32 resp;
3918c2ecf20Sopenharmony_ci	int err;
3928c2ecf20Sopenharmony_ci	int expected_seq;
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_ci	mutex_lock(&data->mutex);
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_ci	expected_seq = (data->rsp_seq + 1) & SI1133_MAX_CMD_CTR;
3978c2ecf20Sopenharmony_ci
3988c2ecf20Sopenharmony_ci	if (cmd == SI1133_CMD_FORCE)
3998c2ecf20Sopenharmony_ci		reinit_completion(&data->completion);
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_ci	err = regmap_write(data->regmap, SI1133_REG_COMMAND, cmd);
4028c2ecf20Sopenharmony_ci	if (err) {
4038c2ecf20Sopenharmony_ci		dev_warn(dev, "Failed to write command %#02hhx, ret=%d\n", cmd,
4048c2ecf20Sopenharmony_ci			 err);
4058c2ecf20Sopenharmony_ci		goto out;
4068c2ecf20Sopenharmony_ci	}
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_ci	if (cmd == SI1133_CMD_FORCE) {
4098c2ecf20Sopenharmony_ci		/* wait for irq */
4108c2ecf20Sopenharmony_ci		if (!wait_for_completion_timeout(&data->completion,
4118c2ecf20Sopenharmony_ci			msecs_to_jiffies(SI1133_COMPLETION_TIMEOUT_MS))) {
4128c2ecf20Sopenharmony_ci			err = -ETIMEDOUT;
4138c2ecf20Sopenharmony_ci			goto out;
4148c2ecf20Sopenharmony_ci		}
4158c2ecf20Sopenharmony_ci		err = regmap_read(data->regmap, SI1133_REG_RESPONSE0, &resp);
4168c2ecf20Sopenharmony_ci		if (err)
4178c2ecf20Sopenharmony_ci			goto out;
4188c2ecf20Sopenharmony_ci	} else {
4198c2ecf20Sopenharmony_ci		err = regmap_read_poll_timeout(data->regmap,
4208c2ecf20Sopenharmony_ci					       SI1133_REG_RESPONSE0, resp,
4218c2ecf20Sopenharmony_ci					       (resp & SI1133_CMD_SEQ_MASK) ==
4228c2ecf20Sopenharmony_ci					       expected_seq ||
4238c2ecf20Sopenharmony_ci					       (resp & SI1133_CMD_ERR_MASK),
4248c2ecf20Sopenharmony_ci					       SI1133_CMD_MINSLEEP_US_LOW,
4258c2ecf20Sopenharmony_ci					       SI1133_CMD_TIMEOUT_MS * 1000);
4268c2ecf20Sopenharmony_ci		if (err) {
4278c2ecf20Sopenharmony_ci			dev_warn(dev,
4288c2ecf20Sopenharmony_ci				 "Failed to read command %#02hhx, ret=%d\n",
4298c2ecf20Sopenharmony_ci				 cmd, err);
4308c2ecf20Sopenharmony_ci			goto out;
4318c2ecf20Sopenharmony_ci		}
4328c2ecf20Sopenharmony_ci	}
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_ci	if (resp & SI1133_CMD_ERR_MASK) {
4358c2ecf20Sopenharmony_ci		err = si1133_parse_response_err(dev, resp, cmd);
4368c2ecf20Sopenharmony_ci		si1133_cmd_reset_counter(data);
4378c2ecf20Sopenharmony_ci	} else {
4388c2ecf20Sopenharmony_ci		data->rsp_seq = expected_seq;
4398c2ecf20Sopenharmony_ci	}
4408c2ecf20Sopenharmony_ci
4418c2ecf20Sopenharmony_ciout:
4428c2ecf20Sopenharmony_ci	mutex_unlock(&data->mutex);
4438c2ecf20Sopenharmony_ci
4448c2ecf20Sopenharmony_ci	return err;
4458c2ecf20Sopenharmony_ci}
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_cistatic int si1133_param_set(struct si1133_data *data, u8 param, u32 value)
4488c2ecf20Sopenharmony_ci{
4498c2ecf20Sopenharmony_ci	int err = regmap_write(data->regmap, SI1133_REG_HOSTIN0, value);
4508c2ecf20Sopenharmony_ci
4518c2ecf20Sopenharmony_ci	if (err)
4528c2ecf20Sopenharmony_ci		return err;
4538c2ecf20Sopenharmony_ci
4548c2ecf20Sopenharmony_ci	return si1133_command(data, SI1133_CMD_PARAM_SET |
4558c2ecf20Sopenharmony_ci			      (param & SI1133_CMD_PARAM_MASK));
4568c2ecf20Sopenharmony_ci}
4578c2ecf20Sopenharmony_ci
4588c2ecf20Sopenharmony_cistatic int si1133_param_query(struct si1133_data *data, u8 param, u32 *result)
4598c2ecf20Sopenharmony_ci{
4608c2ecf20Sopenharmony_ci	int err = si1133_command(data, SI1133_CMD_PARAM_QUERY |
4618c2ecf20Sopenharmony_ci				 (param & SI1133_CMD_PARAM_MASK));
4628c2ecf20Sopenharmony_ci	if (err)
4638c2ecf20Sopenharmony_ci		return err;
4648c2ecf20Sopenharmony_ci
4658c2ecf20Sopenharmony_ci	return regmap_read(data->regmap, SI1133_REG_RESPONSE1, result);
4668c2ecf20Sopenharmony_ci}
4678c2ecf20Sopenharmony_ci
4688c2ecf20Sopenharmony_ci#define SI1133_CHANNEL(_ch, _type) \
4698c2ecf20Sopenharmony_ci	.type = _type, \
4708c2ecf20Sopenharmony_ci	.channel = _ch, \
4718c2ecf20Sopenharmony_ci	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
4728c2ecf20Sopenharmony_ci	.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME) | \
4738c2ecf20Sopenharmony_ci		BIT(IIO_CHAN_INFO_SCALE) | \
4748c2ecf20Sopenharmony_ci		BIT(IIO_CHAN_INFO_HARDWAREGAIN), \
4758c2ecf20Sopenharmony_ci
4768c2ecf20Sopenharmony_cistatic const struct iio_chan_spec si1133_channels[] = {
4778c2ecf20Sopenharmony_ci	{
4788c2ecf20Sopenharmony_ci		.type = IIO_LIGHT,
4798c2ecf20Sopenharmony_ci		.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
4808c2ecf20Sopenharmony_ci		.channel = 0,
4818c2ecf20Sopenharmony_ci	},
4828c2ecf20Sopenharmony_ci	{
4838c2ecf20Sopenharmony_ci		SI1133_CHANNEL(SI1133_PARAM_ADCMUX_WHITE, IIO_INTENSITY)
4848c2ecf20Sopenharmony_ci		.channel2 = IIO_MOD_LIGHT_BOTH,
4858c2ecf20Sopenharmony_ci	},
4868c2ecf20Sopenharmony_ci	{
4878c2ecf20Sopenharmony_ci		SI1133_CHANNEL(SI1133_PARAM_ADCMUX_LARGE_WHITE, IIO_INTENSITY)
4888c2ecf20Sopenharmony_ci		.channel2 = IIO_MOD_LIGHT_BOTH,
4898c2ecf20Sopenharmony_ci		.extend_name = "large",
4908c2ecf20Sopenharmony_ci	},
4918c2ecf20Sopenharmony_ci	{
4928c2ecf20Sopenharmony_ci		SI1133_CHANNEL(SI1133_PARAM_ADCMUX_SMALL_IR, IIO_INTENSITY)
4938c2ecf20Sopenharmony_ci		.extend_name = "small",
4948c2ecf20Sopenharmony_ci		.modified = 1,
4958c2ecf20Sopenharmony_ci		.channel2 = IIO_MOD_LIGHT_IR,
4968c2ecf20Sopenharmony_ci	},
4978c2ecf20Sopenharmony_ci	{
4988c2ecf20Sopenharmony_ci		SI1133_CHANNEL(SI1133_PARAM_ADCMUX_MED_IR, IIO_INTENSITY)
4998c2ecf20Sopenharmony_ci		.modified = 1,
5008c2ecf20Sopenharmony_ci		.channel2 = IIO_MOD_LIGHT_IR,
5018c2ecf20Sopenharmony_ci	},
5028c2ecf20Sopenharmony_ci	{
5038c2ecf20Sopenharmony_ci		SI1133_CHANNEL(SI1133_PARAM_ADCMUX_LARGE_IR, IIO_INTENSITY)
5048c2ecf20Sopenharmony_ci		.extend_name = "large",
5058c2ecf20Sopenharmony_ci		.modified = 1,
5068c2ecf20Sopenharmony_ci		.channel2 = IIO_MOD_LIGHT_IR,
5078c2ecf20Sopenharmony_ci	},
5088c2ecf20Sopenharmony_ci	{
5098c2ecf20Sopenharmony_ci		SI1133_CHANNEL(SI1133_PARAM_ADCMUX_UV, IIO_UVINDEX)
5108c2ecf20Sopenharmony_ci	},
5118c2ecf20Sopenharmony_ci	{
5128c2ecf20Sopenharmony_ci		SI1133_CHANNEL(SI1133_PARAM_ADCMUX_UV_DEEP, IIO_UVINDEX)
5138c2ecf20Sopenharmony_ci		.modified = 1,
5148c2ecf20Sopenharmony_ci		.channel2 = IIO_MOD_LIGHT_DUV,
5158c2ecf20Sopenharmony_ci	}
5168c2ecf20Sopenharmony_ci};
5178c2ecf20Sopenharmony_ci
5188c2ecf20Sopenharmony_cistatic int si1133_get_int_time_index(int milliseconds, int nanoseconds)
5198c2ecf20Sopenharmony_ci{
5208c2ecf20Sopenharmony_ci	int i;
5218c2ecf20Sopenharmony_ci
5228c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(si1133_int_time_table); i++) {
5238c2ecf20Sopenharmony_ci		if (milliseconds == si1133_int_time_table[i][0] &&
5248c2ecf20Sopenharmony_ci		    nanoseconds == si1133_int_time_table[i][1])
5258c2ecf20Sopenharmony_ci			return i;
5268c2ecf20Sopenharmony_ci	}
5278c2ecf20Sopenharmony_ci	return -EINVAL;
5288c2ecf20Sopenharmony_ci}
5298c2ecf20Sopenharmony_ci
5308c2ecf20Sopenharmony_cistatic int si1133_set_integration_time(struct si1133_data *data, u8 adc,
5318c2ecf20Sopenharmony_ci				       int milliseconds, int nanoseconds)
5328c2ecf20Sopenharmony_ci{
5338c2ecf20Sopenharmony_ci	int index;
5348c2ecf20Sopenharmony_ci
5358c2ecf20Sopenharmony_ci	index = si1133_get_int_time_index(milliseconds, nanoseconds);
5368c2ecf20Sopenharmony_ci	if (index < 0)
5378c2ecf20Sopenharmony_ci		return index;
5388c2ecf20Sopenharmony_ci
5398c2ecf20Sopenharmony_ci	data->adc_sens[adc] &= 0xF0;
5408c2ecf20Sopenharmony_ci	data->adc_sens[adc] |= index;
5418c2ecf20Sopenharmony_ci
5428c2ecf20Sopenharmony_ci	return si1133_param_set(data, SI1133_PARAM_REG_ADCSENS(0),
5438c2ecf20Sopenharmony_ci				data->adc_sens[adc]);
5448c2ecf20Sopenharmony_ci}
5458c2ecf20Sopenharmony_ci
5468c2ecf20Sopenharmony_cistatic int si1133_set_chlist(struct si1133_data *data, u8 scan_mask)
5478c2ecf20Sopenharmony_ci{
5488c2ecf20Sopenharmony_ci	/* channel list already set, no need to reprogram */
5498c2ecf20Sopenharmony_ci	if (data->scan_mask == scan_mask)
5508c2ecf20Sopenharmony_ci		return 0;
5518c2ecf20Sopenharmony_ci
5528c2ecf20Sopenharmony_ci	data->scan_mask = scan_mask;
5538c2ecf20Sopenharmony_ci
5548c2ecf20Sopenharmony_ci	return si1133_param_set(data, SI1133_PARAM_REG_CHAN_LIST, scan_mask);
5558c2ecf20Sopenharmony_ci}
5568c2ecf20Sopenharmony_ci
5578c2ecf20Sopenharmony_cistatic int si1133_chan_set_adcconfig(struct si1133_data *data, u8 adc,
5588c2ecf20Sopenharmony_ci				     u8 adc_config)
5598c2ecf20Sopenharmony_ci{
5608c2ecf20Sopenharmony_ci	int err;
5618c2ecf20Sopenharmony_ci
5628c2ecf20Sopenharmony_ci	err = si1133_param_set(data, SI1133_PARAM_REG_ADCCONFIG(adc),
5638c2ecf20Sopenharmony_ci			       adc_config);
5648c2ecf20Sopenharmony_ci	if (err)
5658c2ecf20Sopenharmony_ci		return err;
5668c2ecf20Sopenharmony_ci
5678c2ecf20Sopenharmony_ci	data->adc_config[adc] = adc_config;
5688c2ecf20Sopenharmony_ci
5698c2ecf20Sopenharmony_ci	return 0;
5708c2ecf20Sopenharmony_ci}
5718c2ecf20Sopenharmony_ci
5728c2ecf20Sopenharmony_cistatic int si1133_update_adcconfig(struct si1133_data *data, uint8_t adc,
5738c2ecf20Sopenharmony_ci				   u8 mask, u8 shift, u8 value)
5748c2ecf20Sopenharmony_ci{
5758c2ecf20Sopenharmony_ci	u32 adc_config;
5768c2ecf20Sopenharmony_ci	int err;
5778c2ecf20Sopenharmony_ci
5788c2ecf20Sopenharmony_ci	err = si1133_param_query(data, SI1133_PARAM_REG_ADCCONFIG(adc),
5798c2ecf20Sopenharmony_ci				 &adc_config);
5808c2ecf20Sopenharmony_ci	if (err)
5818c2ecf20Sopenharmony_ci		return err;
5828c2ecf20Sopenharmony_ci
5838c2ecf20Sopenharmony_ci	adc_config &= ~mask;
5848c2ecf20Sopenharmony_ci	adc_config |= (value << shift);
5858c2ecf20Sopenharmony_ci
5868c2ecf20Sopenharmony_ci	return si1133_chan_set_adcconfig(data, adc, adc_config);
5878c2ecf20Sopenharmony_ci}
5888c2ecf20Sopenharmony_ci
5898c2ecf20Sopenharmony_cistatic int si1133_set_adcmux(struct si1133_data *data, u8 adc, u8 mux)
5908c2ecf20Sopenharmony_ci{
5918c2ecf20Sopenharmony_ci	if ((mux & data->adc_config[adc]) == mux)
5928c2ecf20Sopenharmony_ci		return 0; /* mux already set to correct value */
5938c2ecf20Sopenharmony_ci
5948c2ecf20Sopenharmony_ci	return si1133_update_adcconfig(data, adc, SI1133_ADCMUX_MASK, 0, mux);
5958c2ecf20Sopenharmony_ci}
5968c2ecf20Sopenharmony_ci
5978c2ecf20Sopenharmony_cistatic int si1133_force_measurement(struct si1133_data *data)
5988c2ecf20Sopenharmony_ci{
5998c2ecf20Sopenharmony_ci	return si1133_command(data, SI1133_CMD_FORCE);
6008c2ecf20Sopenharmony_ci}
6018c2ecf20Sopenharmony_ci
6028c2ecf20Sopenharmony_cistatic int si1133_bulk_read(struct si1133_data *data, u8 start_reg, u8 length,
6038c2ecf20Sopenharmony_ci			    u8 *buffer)
6048c2ecf20Sopenharmony_ci{
6058c2ecf20Sopenharmony_ci	int err;
6068c2ecf20Sopenharmony_ci
6078c2ecf20Sopenharmony_ci	err = si1133_force_measurement(data);
6088c2ecf20Sopenharmony_ci	if (err)
6098c2ecf20Sopenharmony_ci		return err;
6108c2ecf20Sopenharmony_ci
6118c2ecf20Sopenharmony_ci	return regmap_bulk_read(data->regmap, start_reg, buffer, length);
6128c2ecf20Sopenharmony_ci}
6138c2ecf20Sopenharmony_ci
6148c2ecf20Sopenharmony_cistatic int si1133_measure(struct si1133_data *data,
6158c2ecf20Sopenharmony_ci			  struct iio_chan_spec const *chan,
6168c2ecf20Sopenharmony_ci			  int *val)
6178c2ecf20Sopenharmony_ci{
6188c2ecf20Sopenharmony_ci	int err;
6198c2ecf20Sopenharmony_ci
6208c2ecf20Sopenharmony_ci	u8 buffer[SI1133_MEASURE_BUFFER_SIZE];
6218c2ecf20Sopenharmony_ci
6228c2ecf20Sopenharmony_ci	err = si1133_set_adcmux(data, 0, chan->channel);
6238c2ecf20Sopenharmony_ci	if (err)
6248c2ecf20Sopenharmony_ci		return err;
6258c2ecf20Sopenharmony_ci
6268c2ecf20Sopenharmony_ci	/* Deactivate lux measurements if they were active */
6278c2ecf20Sopenharmony_ci	err = si1133_set_chlist(data, BIT(0));
6288c2ecf20Sopenharmony_ci	if (err)
6298c2ecf20Sopenharmony_ci		return err;
6308c2ecf20Sopenharmony_ci
6318c2ecf20Sopenharmony_ci	err = si1133_bulk_read(data, SI1133_REG_HOSTOUT(0), sizeof(buffer),
6328c2ecf20Sopenharmony_ci			       buffer);
6338c2ecf20Sopenharmony_ci	if (err)
6348c2ecf20Sopenharmony_ci		return err;
6358c2ecf20Sopenharmony_ci
6368c2ecf20Sopenharmony_ci	*val = sign_extend32(get_unaligned_be24(&buffer[0]), 23);
6378c2ecf20Sopenharmony_ci
6388c2ecf20Sopenharmony_ci	return err;
6398c2ecf20Sopenharmony_ci}
6408c2ecf20Sopenharmony_ci
6418c2ecf20Sopenharmony_cistatic irqreturn_t si1133_threaded_irq_handler(int irq, void *private)
6428c2ecf20Sopenharmony_ci{
6438c2ecf20Sopenharmony_ci	struct iio_dev *iio_dev = private;
6448c2ecf20Sopenharmony_ci	struct si1133_data *data = iio_priv(iio_dev);
6458c2ecf20Sopenharmony_ci	u32 irq_status;
6468c2ecf20Sopenharmony_ci	int err;
6478c2ecf20Sopenharmony_ci
6488c2ecf20Sopenharmony_ci	err = regmap_read(data->regmap, SI1133_REG_IRQ_STATUS, &irq_status);
6498c2ecf20Sopenharmony_ci	if (err) {
6508c2ecf20Sopenharmony_ci		dev_err_ratelimited(&iio_dev->dev, "Error reading IRQ\n");
6518c2ecf20Sopenharmony_ci		goto out;
6528c2ecf20Sopenharmony_ci	}
6538c2ecf20Sopenharmony_ci
6548c2ecf20Sopenharmony_ci	if (irq_status != data->scan_mask)
6558c2ecf20Sopenharmony_ci		return IRQ_NONE;
6568c2ecf20Sopenharmony_ci
6578c2ecf20Sopenharmony_ciout:
6588c2ecf20Sopenharmony_ci	complete(&data->completion);
6598c2ecf20Sopenharmony_ci
6608c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
6618c2ecf20Sopenharmony_ci}
6628c2ecf20Sopenharmony_ci
6638c2ecf20Sopenharmony_cistatic int si1133_scale_to_swgain(int scale_integer, int scale_fractional)
6648c2ecf20Sopenharmony_ci{
6658c2ecf20Sopenharmony_ci	scale_integer = find_closest(scale_integer, si1133_scale_available,
6668c2ecf20Sopenharmony_ci				     ARRAY_SIZE(si1133_scale_available));
6678c2ecf20Sopenharmony_ci	if (scale_integer < 0 ||
6688c2ecf20Sopenharmony_ci	    scale_integer > ARRAY_SIZE(si1133_scale_available) ||
6698c2ecf20Sopenharmony_ci	    scale_fractional != 0)
6708c2ecf20Sopenharmony_ci		return -EINVAL;
6718c2ecf20Sopenharmony_ci
6728c2ecf20Sopenharmony_ci	return scale_integer;
6738c2ecf20Sopenharmony_ci}
6748c2ecf20Sopenharmony_ci
6758c2ecf20Sopenharmony_cistatic int si1133_chan_set_adcsens(struct si1133_data *data, u8 adc,
6768c2ecf20Sopenharmony_ci				   u8 adc_sens)
6778c2ecf20Sopenharmony_ci{
6788c2ecf20Sopenharmony_ci	int err;
6798c2ecf20Sopenharmony_ci
6808c2ecf20Sopenharmony_ci	err = si1133_param_set(data, SI1133_PARAM_REG_ADCSENS(adc), adc_sens);
6818c2ecf20Sopenharmony_ci	if (err)
6828c2ecf20Sopenharmony_ci		return err;
6838c2ecf20Sopenharmony_ci
6848c2ecf20Sopenharmony_ci	data->adc_sens[adc] = adc_sens;
6858c2ecf20Sopenharmony_ci
6868c2ecf20Sopenharmony_ci	return 0;
6878c2ecf20Sopenharmony_ci}
6888c2ecf20Sopenharmony_ci
6898c2ecf20Sopenharmony_cistatic int si1133_update_adcsens(struct si1133_data *data, u8 mask,
6908c2ecf20Sopenharmony_ci				 u8 shift, u8 value)
6918c2ecf20Sopenharmony_ci{
6928c2ecf20Sopenharmony_ci	int err;
6938c2ecf20Sopenharmony_ci	u32 adc_sens;
6948c2ecf20Sopenharmony_ci
6958c2ecf20Sopenharmony_ci	err = si1133_param_query(data, SI1133_PARAM_REG_ADCSENS(0),
6968c2ecf20Sopenharmony_ci				 &adc_sens);
6978c2ecf20Sopenharmony_ci	if (err)
6988c2ecf20Sopenharmony_ci		return err;
6998c2ecf20Sopenharmony_ci
7008c2ecf20Sopenharmony_ci	adc_sens &= ~mask;
7018c2ecf20Sopenharmony_ci	adc_sens |= (value << shift);
7028c2ecf20Sopenharmony_ci
7038c2ecf20Sopenharmony_ci	return si1133_chan_set_adcsens(data, 0, adc_sens);
7048c2ecf20Sopenharmony_ci}
7058c2ecf20Sopenharmony_ci
7068c2ecf20Sopenharmony_cistatic int si1133_get_lux(struct si1133_data *data, int *val)
7078c2ecf20Sopenharmony_ci{
7088c2ecf20Sopenharmony_ci	int err;
7098c2ecf20Sopenharmony_ci	int lux;
7108c2ecf20Sopenharmony_ci	s32 high_vis;
7118c2ecf20Sopenharmony_ci	s32 low_vis;
7128c2ecf20Sopenharmony_ci	s32 ir;
7138c2ecf20Sopenharmony_ci	u8 buffer[SI1133_LUX_BUFFER_SIZE];
7148c2ecf20Sopenharmony_ci
7158c2ecf20Sopenharmony_ci	/* Activate lux channels */
7168c2ecf20Sopenharmony_ci	err = si1133_set_chlist(data, SI1133_LUX_ADC_MASK);
7178c2ecf20Sopenharmony_ci	if (err)
7188c2ecf20Sopenharmony_ci		return err;
7198c2ecf20Sopenharmony_ci
7208c2ecf20Sopenharmony_ci	err = si1133_bulk_read(data, SI1133_REG_HOSTOUT(0),
7218c2ecf20Sopenharmony_ci			       SI1133_LUX_BUFFER_SIZE, buffer);
7228c2ecf20Sopenharmony_ci	if (err)
7238c2ecf20Sopenharmony_ci		return err;
7248c2ecf20Sopenharmony_ci
7258c2ecf20Sopenharmony_ci	high_vis = sign_extend32(get_unaligned_be24(&buffer[0]), 23);
7268c2ecf20Sopenharmony_ci
7278c2ecf20Sopenharmony_ci	low_vis = sign_extend32(get_unaligned_be24(&buffer[3]), 23);
7288c2ecf20Sopenharmony_ci
7298c2ecf20Sopenharmony_ci	ir = sign_extend32(get_unaligned_be24(&buffer[6]), 23);
7308c2ecf20Sopenharmony_ci
7318c2ecf20Sopenharmony_ci	if (high_vis > SI1133_ADC_THRESHOLD || ir > SI1133_ADC_THRESHOLD)
7328c2ecf20Sopenharmony_ci		lux = si1133_calc_polynomial(high_vis, ir,
7338c2ecf20Sopenharmony_ci					     SI1133_INPUT_FRACTION_HIGH,
7348c2ecf20Sopenharmony_ci					     ARRAY_SIZE(lux_coeff.coeff_high),
7358c2ecf20Sopenharmony_ci					     &lux_coeff.coeff_high[0]);
7368c2ecf20Sopenharmony_ci	else
7378c2ecf20Sopenharmony_ci		lux = si1133_calc_polynomial(low_vis, ir,
7388c2ecf20Sopenharmony_ci					     SI1133_INPUT_FRACTION_LOW,
7398c2ecf20Sopenharmony_ci					     ARRAY_SIZE(lux_coeff.coeff_low),
7408c2ecf20Sopenharmony_ci					     &lux_coeff.coeff_low[0]);
7418c2ecf20Sopenharmony_ci
7428c2ecf20Sopenharmony_ci	*val = lux >> SI1133_LUX_OUTPUT_FRACTION;
7438c2ecf20Sopenharmony_ci
7448c2ecf20Sopenharmony_ci	return err;
7458c2ecf20Sopenharmony_ci}
7468c2ecf20Sopenharmony_ci
7478c2ecf20Sopenharmony_cistatic int si1133_read_raw(struct iio_dev *iio_dev,
7488c2ecf20Sopenharmony_ci			   struct iio_chan_spec const *chan,
7498c2ecf20Sopenharmony_ci			   int *val, int *val2, long mask)
7508c2ecf20Sopenharmony_ci{
7518c2ecf20Sopenharmony_ci	struct si1133_data *data = iio_priv(iio_dev);
7528c2ecf20Sopenharmony_ci	u8 adc_sens = data->adc_sens[0];
7538c2ecf20Sopenharmony_ci	int err;
7548c2ecf20Sopenharmony_ci
7558c2ecf20Sopenharmony_ci	switch (mask) {
7568c2ecf20Sopenharmony_ci	case IIO_CHAN_INFO_PROCESSED:
7578c2ecf20Sopenharmony_ci		switch (chan->type) {
7588c2ecf20Sopenharmony_ci		case IIO_LIGHT:
7598c2ecf20Sopenharmony_ci			err = si1133_get_lux(data, val);
7608c2ecf20Sopenharmony_ci			if (err)
7618c2ecf20Sopenharmony_ci				return err;
7628c2ecf20Sopenharmony_ci
7638c2ecf20Sopenharmony_ci			return IIO_VAL_INT;
7648c2ecf20Sopenharmony_ci		default:
7658c2ecf20Sopenharmony_ci			return -EINVAL;
7668c2ecf20Sopenharmony_ci		}
7678c2ecf20Sopenharmony_ci	case IIO_CHAN_INFO_RAW:
7688c2ecf20Sopenharmony_ci		switch (chan->type) {
7698c2ecf20Sopenharmony_ci		case IIO_INTENSITY:
7708c2ecf20Sopenharmony_ci		case IIO_UVINDEX:
7718c2ecf20Sopenharmony_ci			err = si1133_measure(data, chan, val);
7728c2ecf20Sopenharmony_ci			if (err)
7738c2ecf20Sopenharmony_ci				return err;
7748c2ecf20Sopenharmony_ci
7758c2ecf20Sopenharmony_ci			return IIO_VAL_INT;
7768c2ecf20Sopenharmony_ci		default:
7778c2ecf20Sopenharmony_ci			return -EINVAL;
7788c2ecf20Sopenharmony_ci		}
7798c2ecf20Sopenharmony_ci	case IIO_CHAN_INFO_INT_TIME:
7808c2ecf20Sopenharmony_ci		switch (chan->type) {
7818c2ecf20Sopenharmony_ci		case IIO_INTENSITY:
7828c2ecf20Sopenharmony_ci		case IIO_UVINDEX:
7838c2ecf20Sopenharmony_ci			adc_sens &= SI1133_ADCSENS_HW_GAIN_MASK;
7848c2ecf20Sopenharmony_ci
7858c2ecf20Sopenharmony_ci			*val = si1133_int_time_table[adc_sens][0];
7868c2ecf20Sopenharmony_ci			*val2 = si1133_int_time_table[adc_sens][1];
7878c2ecf20Sopenharmony_ci			return IIO_VAL_INT_PLUS_MICRO;
7888c2ecf20Sopenharmony_ci		default:
7898c2ecf20Sopenharmony_ci			return -EINVAL;
7908c2ecf20Sopenharmony_ci		}
7918c2ecf20Sopenharmony_ci	case IIO_CHAN_INFO_SCALE:
7928c2ecf20Sopenharmony_ci		switch (chan->type) {
7938c2ecf20Sopenharmony_ci		case IIO_INTENSITY:
7948c2ecf20Sopenharmony_ci		case IIO_UVINDEX:
7958c2ecf20Sopenharmony_ci			adc_sens &= SI1133_ADCSENS_SCALE_MASK;
7968c2ecf20Sopenharmony_ci			adc_sens >>= SI1133_ADCSENS_SCALE_SHIFT;
7978c2ecf20Sopenharmony_ci
7988c2ecf20Sopenharmony_ci			*val = BIT(adc_sens);
7998c2ecf20Sopenharmony_ci
8008c2ecf20Sopenharmony_ci			return IIO_VAL_INT;
8018c2ecf20Sopenharmony_ci		default:
8028c2ecf20Sopenharmony_ci			return -EINVAL;
8038c2ecf20Sopenharmony_ci		}
8048c2ecf20Sopenharmony_ci	case IIO_CHAN_INFO_HARDWAREGAIN:
8058c2ecf20Sopenharmony_ci		switch (chan->type) {
8068c2ecf20Sopenharmony_ci		case IIO_INTENSITY:
8078c2ecf20Sopenharmony_ci		case IIO_UVINDEX:
8088c2ecf20Sopenharmony_ci			adc_sens >>= SI1133_ADCSENS_HSIG_SHIFT;
8098c2ecf20Sopenharmony_ci
8108c2ecf20Sopenharmony_ci			*val = adc_sens;
8118c2ecf20Sopenharmony_ci
8128c2ecf20Sopenharmony_ci			return IIO_VAL_INT;
8138c2ecf20Sopenharmony_ci		default:
8148c2ecf20Sopenharmony_ci			return -EINVAL;
8158c2ecf20Sopenharmony_ci		}
8168c2ecf20Sopenharmony_ci	default:
8178c2ecf20Sopenharmony_ci		return -EINVAL;
8188c2ecf20Sopenharmony_ci	}
8198c2ecf20Sopenharmony_ci}
8208c2ecf20Sopenharmony_ci
8218c2ecf20Sopenharmony_cistatic int si1133_write_raw(struct iio_dev *iio_dev,
8228c2ecf20Sopenharmony_ci			    struct iio_chan_spec const *chan,
8238c2ecf20Sopenharmony_ci			    int val, int val2, long mask)
8248c2ecf20Sopenharmony_ci{
8258c2ecf20Sopenharmony_ci	struct si1133_data *data = iio_priv(iio_dev);
8268c2ecf20Sopenharmony_ci
8278c2ecf20Sopenharmony_ci	switch (mask) {
8288c2ecf20Sopenharmony_ci	case IIO_CHAN_INFO_SCALE:
8298c2ecf20Sopenharmony_ci		switch (chan->type) {
8308c2ecf20Sopenharmony_ci		case IIO_INTENSITY:
8318c2ecf20Sopenharmony_ci		case IIO_UVINDEX:
8328c2ecf20Sopenharmony_ci			val = si1133_scale_to_swgain(val, val2);
8338c2ecf20Sopenharmony_ci			if (val < 0)
8348c2ecf20Sopenharmony_ci				return val;
8358c2ecf20Sopenharmony_ci
8368c2ecf20Sopenharmony_ci			return si1133_update_adcsens(data,
8378c2ecf20Sopenharmony_ci						     SI1133_ADCSENS_SCALE_MASK,
8388c2ecf20Sopenharmony_ci						     SI1133_ADCSENS_SCALE_SHIFT,
8398c2ecf20Sopenharmony_ci						     val);
8408c2ecf20Sopenharmony_ci		default:
8418c2ecf20Sopenharmony_ci			return -EINVAL;
8428c2ecf20Sopenharmony_ci		}
8438c2ecf20Sopenharmony_ci	case IIO_CHAN_INFO_INT_TIME:
8448c2ecf20Sopenharmony_ci		return si1133_set_integration_time(data, 0, val, val2);
8458c2ecf20Sopenharmony_ci	case IIO_CHAN_INFO_HARDWAREGAIN:
8468c2ecf20Sopenharmony_ci		switch (chan->type) {
8478c2ecf20Sopenharmony_ci		case IIO_INTENSITY:
8488c2ecf20Sopenharmony_ci		case IIO_UVINDEX:
8498c2ecf20Sopenharmony_ci			if (val != 0 && val != 1)
8508c2ecf20Sopenharmony_ci				return -EINVAL;
8518c2ecf20Sopenharmony_ci
8528c2ecf20Sopenharmony_ci			return si1133_update_adcsens(data,
8538c2ecf20Sopenharmony_ci						     SI1133_ADCSENS_HSIG_MASK,
8548c2ecf20Sopenharmony_ci						     SI1133_ADCSENS_HSIG_SHIFT,
8558c2ecf20Sopenharmony_ci						     val);
8568c2ecf20Sopenharmony_ci		default:
8578c2ecf20Sopenharmony_ci			return -EINVAL;
8588c2ecf20Sopenharmony_ci		}
8598c2ecf20Sopenharmony_ci	default:
8608c2ecf20Sopenharmony_ci		return -EINVAL;
8618c2ecf20Sopenharmony_ci	}
8628c2ecf20Sopenharmony_ci}
8638c2ecf20Sopenharmony_ci
8648c2ecf20Sopenharmony_cistatic struct attribute *si1133_attributes[] = {
8658c2ecf20Sopenharmony_ci	&iio_const_attr_integration_time_available.dev_attr.attr,
8668c2ecf20Sopenharmony_ci	&iio_const_attr_scale_available.dev_attr.attr,
8678c2ecf20Sopenharmony_ci	NULL,
8688c2ecf20Sopenharmony_ci};
8698c2ecf20Sopenharmony_ci
8708c2ecf20Sopenharmony_cistatic const struct attribute_group si1133_attribute_group = {
8718c2ecf20Sopenharmony_ci	.attrs = si1133_attributes,
8728c2ecf20Sopenharmony_ci};
8738c2ecf20Sopenharmony_ci
8748c2ecf20Sopenharmony_cistatic const struct iio_info si1133_info = {
8758c2ecf20Sopenharmony_ci	.read_raw = si1133_read_raw,
8768c2ecf20Sopenharmony_ci	.write_raw = si1133_write_raw,
8778c2ecf20Sopenharmony_ci	.attrs = &si1133_attribute_group,
8788c2ecf20Sopenharmony_ci};
8798c2ecf20Sopenharmony_ci
8808c2ecf20Sopenharmony_ci/*
8818c2ecf20Sopenharmony_ci * si1133_init_lux_channels - Configure 3 different channels(adc) (1,2 and 3)
8828c2ecf20Sopenharmony_ci * The channel configuration for the lux measurement was taken from :
8838c2ecf20Sopenharmony_ci * https://siliconlabs.github.io/Gecko_SDK_Doc/efm32zg/html/si1133_8c_source.html#l00578
8848c2ecf20Sopenharmony_ci *
8858c2ecf20Sopenharmony_ci * Reserved the channel 0 for the other raw measurements
8868c2ecf20Sopenharmony_ci */
8878c2ecf20Sopenharmony_cistatic int si1133_init_lux_channels(struct si1133_data *data)
8888c2ecf20Sopenharmony_ci{
8898c2ecf20Sopenharmony_ci	int err;
8908c2ecf20Sopenharmony_ci
8918c2ecf20Sopenharmony_ci	err = si1133_chan_set_adcconfig(data, 1,
8928c2ecf20Sopenharmony_ci					SI1133_ADCCONFIG_DECIM_RATE(1) |
8938c2ecf20Sopenharmony_ci					SI1133_PARAM_ADCMUX_LARGE_WHITE);
8948c2ecf20Sopenharmony_ci	if (err)
8958c2ecf20Sopenharmony_ci		return err;
8968c2ecf20Sopenharmony_ci
8978c2ecf20Sopenharmony_ci	err = si1133_param_set(data, SI1133_PARAM_REG_ADCPOST(1),
8988c2ecf20Sopenharmony_ci			       SI1133_ADCPOST_24BIT_EN |
8998c2ecf20Sopenharmony_ci			       SI1133_ADCPOST_POSTSHIFT_BITQTY(0));
9008c2ecf20Sopenharmony_ci	if (err)
9018c2ecf20Sopenharmony_ci		return err;
9028c2ecf20Sopenharmony_ci	err = si1133_chan_set_adcsens(data, 1, SI1133_ADCSENS_HSIG_MASK |
9038c2ecf20Sopenharmony_ci				      SI1133_ADCSENS_NB_MEAS(64) | _48_8_us);
9048c2ecf20Sopenharmony_ci	if (err)
9058c2ecf20Sopenharmony_ci		return err;
9068c2ecf20Sopenharmony_ci
9078c2ecf20Sopenharmony_ci	err = si1133_chan_set_adcconfig(data, 2,
9088c2ecf20Sopenharmony_ci					SI1133_ADCCONFIG_DECIM_RATE(1) |
9098c2ecf20Sopenharmony_ci					SI1133_PARAM_ADCMUX_LARGE_WHITE);
9108c2ecf20Sopenharmony_ci	if (err)
9118c2ecf20Sopenharmony_ci		return err;
9128c2ecf20Sopenharmony_ci
9138c2ecf20Sopenharmony_ci	err = si1133_param_set(data, SI1133_PARAM_REG_ADCPOST(2),
9148c2ecf20Sopenharmony_ci			       SI1133_ADCPOST_24BIT_EN |
9158c2ecf20Sopenharmony_ci			       SI1133_ADCPOST_POSTSHIFT_BITQTY(2));
9168c2ecf20Sopenharmony_ci	if (err)
9178c2ecf20Sopenharmony_ci		return err;
9188c2ecf20Sopenharmony_ci
9198c2ecf20Sopenharmony_ci	err = si1133_chan_set_adcsens(data, 2, SI1133_ADCSENS_HSIG_MASK |
9208c2ecf20Sopenharmony_ci				      SI1133_ADCSENS_NB_MEAS(1) | _3_120_0_us);
9218c2ecf20Sopenharmony_ci	if (err)
9228c2ecf20Sopenharmony_ci		return err;
9238c2ecf20Sopenharmony_ci
9248c2ecf20Sopenharmony_ci	err = si1133_chan_set_adcconfig(data, 3,
9258c2ecf20Sopenharmony_ci					SI1133_ADCCONFIG_DECIM_RATE(1) |
9268c2ecf20Sopenharmony_ci					SI1133_PARAM_ADCMUX_MED_IR);
9278c2ecf20Sopenharmony_ci	if (err)
9288c2ecf20Sopenharmony_ci		return err;
9298c2ecf20Sopenharmony_ci
9308c2ecf20Sopenharmony_ci	err = si1133_param_set(data, SI1133_PARAM_REG_ADCPOST(3),
9318c2ecf20Sopenharmony_ci			       SI1133_ADCPOST_24BIT_EN |
9328c2ecf20Sopenharmony_ci			       SI1133_ADCPOST_POSTSHIFT_BITQTY(2));
9338c2ecf20Sopenharmony_ci	if (err)
9348c2ecf20Sopenharmony_ci		return err;
9358c2ecf20Sopenharmony_ci
9368c2ecf20Sopenharmony_ci	return  si1133_chan_set_adcsens(data, 3, SI1133_ADCSENS_HSIG_MASK |
9378c2ecf20Sopenharmony_ci					SI1133_ADCSENS_NB_MEAS(64) | _48_8_us);
9388c2ecf20Sopenharmony_ci}
9398c2ecf20Sopenharmony_ci
9408c2ecf20Sopenharmony_cistatic int si1133_initialize(struct si1133_data *data)
9418c2ecf20Sopenharmony_ci{
9428c2ecf20Sopenharmony_ci	int err;
9438c2ecf20Sopenharmony_ci
9448c2ecf20Sopenharmony_ci	err = si1133_cmd_reset_sw(data);
9458c2ecf20Sopenharmony_ci	if (err)
9468c2ecf20Sopenharmony_ci		return err;
9478c2ecf20Sopenharmony_ci
9488c2ecf20Sopenharmony_ci	/* Turn off autonomous mode */
9498c2ecf20Sopenharmony_ci	err = si1133_param_set(data, SI1133_REG_MEAS_RATE, 0);
9508c2ecf20Sopenharmony_ci	if (err)
9518c2ecf20Sopenharmony_ci		return err;
9528c2ecf20Sopenharmony_ci
9538c2ecf20Sopenharmony_ci	err = si1133_init_lux_channels(data);
9548c2ecf20Sopenharmony_ci	if (err)
9558c2ecf20Sopenharmony_ci		return err;
9568c2ecf20Sopenharmony_ci
9578c2ecf20Sopenharmony_ci	return regmap_write(data->regmap, SI1133_REG_IRQ_ENABLE,
9588c2ecf20Sopenharmony_ci			    SI1133_IRQ_CHANNEL_ENABLE);
9598c2ecf20Sopenharmony_ci}
9608c2ecf20Sopenharmony_ci
9618c2ecf20Sopenharmony_cistatic int si1133_validate_ids(struct iio_dev *iio_dev)
9628c2ecf20Sopenharmony_ci{
9638c2ecf20Sopenharmony_ci	struct si1133_data *data = iio_priv(iio_dev);
9648c2ecf20Sopenharmony_ci
9658c2ecf20Sopenharmony_ci	unsigned int part_id, rev_id, mfr_id;
9668c2ecf20Sopenharmony_ci	int err;
9678c2ecf20Sopenharmony_ci
9688c2ecf20Sopenharmony_ci	err = regmap_read(data->regmap, SI1133_REG_PART_ID, &part_id);
9698c2ecf20Sopenharmony_ci	if (err)
9708c2ecf20Sopenharmony_ci		return err;
9718c2ecf20Sopenharmony_ci
9728c2ecf20Sopenharmony_ci	err = regmap_read(data->regmap, SI1133_REG_REV_ID, &rev_id);
9738c2ecf20Sopenharmony_ci	if (err)
9748c2ecf20Sopenharmony_ci		return err;
9758c2ecf20Sopenharmony_ci
9768c2ecf20Sopenharmony_ci	err = regmap_read(data->regmap, SI1133_REG_MFR_ID, &mfr_id);
9778c2ecf20Sopenharmony_ci	if (err)
9788c2ecf20Sopenharmony_ci		return err;
9798c2ecf20Sopenharmony_ci
9808c2ecf20Sopenharmony_ci	dev_info(&iio_dev->dev,
9818c2ecf20Sopenharmony_ci		 "Device ID part %#02hhx rev %#02hhx mfr %#02hhx\n",
9828c2ecf20Sopenharmony_ci		 part_id, rev_id, mfr_id);
9838c2ecf20Sopenharmony_ci	if (part_id != SI1133_PART_ID) {
9848c2ecf20Sopenharmony_ci		dev_err(&iio_dev->dev,
9858c2ecf20Sopenharmony_ci			"Part ID mismatch got %#02hhx, expected %#02x\n",
9868c2ecf20Sopenharmony_ci			part_id, SI1133_PART_ID);
9878c2ecf20Sopenharmony_ci		return -ENODEV;
9888c2ecf20Sopenharmony_ci	}
9898c2ecf20Sopenharmony_ci
9908c2ecf20Sopenharmony_ci	return 0;
9918c2ecf20Sopenharmony_ci}
9928c2ecf20Sopenharmony_ci
9938c2ecf20Sopenharmony_cistatic int si1133_probe(struct i2c_client *client,
9948c2ecf20Sopenharmony_ci			const struct i2c_device_id *id)
9958c2ecf20Sopenharmony_ci{
9968c2ecf20Sopenharmony_ci	struct si1133_data *data;
9978c2ecf20Sopenharmony_ci	struct iio_dev *iio_dev;
9988c2ecf20Sopenharmony_ci	int err;
9998c2ecf20Sopenharmony_ci
10008c2ecf20Sopenharmony_ci	iio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
10018c2ecf20Sopenharmony_ci	if (!iio_dev)
10028c2ecf20Sopenharmony_ci		return -ENOMEM;
10038c2ecf20Sopenharmony_ci
10048c2ecf20Sopenharmony_ci	data = iio_priv(iio_dev);
10058c2ecf20Sopenharmony_ci
10068c2ecf20Sopenharmony_ci	init_completion(&data->completion);
10078c2ecf20Sopenharmony_ci
10088c2ecf20Sopenharmony_ci	data->regmap = devm_regmap_init_i2c(client, &si1133_regmap_config);
10098c2ecf20Sopenharmony_ci	if (IS_ERR(data->regmap)) {
10108c2ecf20Sopenharmony_ci		err = PTR_ERR(data->regmap);
10118c2ecf20Sopenharmony_ci		dev_err(&client->dev, "Failed to initialise regmap: %d\n", err);
10128c2ecf20Sopenharmony_ci		return err;
10138c2ecf20Sopenharmony_ci	}
10148c2ecf20Sopenharmony_ci
10158c2ecf20Sopenharmony_ci	i2c_set_clientdata(client, iio_dev);
10168c2ecf20Sopenharmony_ci	data->client = client;
10178c2ecf20Sopenharmony_ci
10188c2ecf20Sopenharmony_ci	iio_dev->name = id->name;
10198c2ecf20Sopenharmony_ci	iio_dev->channels = si1133_channels;
10208c2ecf20Sopenharmony_ci	iio_dev->num_channels = ARRAY_SIZE(si1133_channels);
10218c2ecf20Sopenharmony_ci	iio_dev->info = &si1133_info;
10228c2ecf20Sopenharmony_ci	iio_dev->modes = INDIO_DIRECT_MODE;
10238c2ecf20Sopenharmony_ci
10248c2ecf20Sopenharmony_ci	mutex_init(&data->mutex);
10258c2ecf20Sopenharmony_ci
10268c2ecf20Sopenharmony_ci	err = si1133_validate_ids(iio_dev);
10278c2ecf20Sopenharmony_ci	if (err)
10288c2ecf20Sopenharmony_ci		return err;
10298c2ecf20Sopenharmony_ci
10308c2ecf20Sopenharmony_ci	err = si1133_initialize(data);
10318c2ecf20Sopenharmony_ci	if (err) {
10328c2ecf20Sopenharmony_ci		dev_err(&client->dev,
10338c2ecf20Sopenharmony_ci			"Error when initializing chip: %d\n", err);
10348c2ecf20Sopenharmony_ci		return err;
10358c2ecf20Sopenharmony_ci	}
10368c2ecf20Sopenharmony_ci
10378c2ecf20Sopenharmony_ci	if (!client->irq) {
10388c2ecf20Sopenharmony_ci		dev_err(&client->dev,
10398c2ecf20Sopenharmony_ci			"Required interrupt not provided, cannot proceed\n");
10408c2ecf20Sopenharmony_ci		return -EINVAL;
10418c2ecf20Sopenharmony_ci	}
10428c2ecf20Sopenharmony_ci
10438c2ecf20Sopenharmony_ci	err = devm_request_threaded_irq(&client->dev, client->irq,
10448c2ecf20Sopenharmony_ci					NULL,
10458c2ecf20Sopenharmony_ci					si1133_threaded_irq_handler,
10468c2ecf20Sopenharmony_ci					IRQF_ONESHOT | IRQF_SHARED,
10478c2ecf20Sopenharmony_ci					client->name, iio_dev);
10488c2ecf20Sopenharmony_ci	if (err) {
10498c2ecf20Sopenharmony_ci		dev_warn(&client->dev, "Request irq %d failed: %i\n",
10508c2ecf20Sopenharmony_ci			 client->irq, err);
10518c2ecf20Sopenharmony_ci		return err;
10528c2ecf20Sopenharmony_ci	}
10538c2ecf20Sopenharmony_ci
10548c2ecf20Sopenharmony_ci	return devm_iio_device_register(&client->dev, iio_dev);
10558c2ecf20Sopenharmony_ci}
10568c2ecf20Sopenharmony_ci
10578c2ecf20Sopenharmony_cistatic const struct i2c_device_id si1133_ids[] = {
10588c2ecf20Sopenharmony_ci	{ "si1133", 0 },
10598c2ecf20Sopenharmony_ci	{ }
10608c2ecf20Sopenharmony_ci};
10618c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, si1133_ids);
10628c2ecf20Sopenharmony_ci
10638c2ecf20Sopenharmony_cistatic struct i2c_driver si1133_driver = {
10648c2ecf20Sopenharmony_ci	.driver = {
10658c2ecf20Sopenharmony_ci	    .name   = "si1133",
10668c2ecf20Sopenharmony_ci	},
10678c2ecf20Sopenharmony_ci	.probe  = si1133_probe,
10688c2ecf20Sopenharmony_ci	.id_table = si1133_ids,
10698c2ecf20Sopenharmony_ci};
10708c2ecf20Sopenharmony_ci
10718c2ecf20Sopenharmony_cimodule_i2c_driver(si1133_driver);
10728c2ecf20Sopenharmony_ci
10738c2ecf20Sopenharmony_ciMODULE_AUTHOR("Maxime Roussin-Belanger <maxime.roussinbelanger@gmail.com>");
10748c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Silabs SI1133, UV index sensor and ambient light sensor driver");
10758c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
1076