brintos

brintos / linux-shallow public Read only

0
0
Text · 24.8 KiB · 44fa152 Raw
1076 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/*3 * si1133.c - Support for Silabs SI1133 combined ambient4 * light and UV index sensors5 *6 * Copyright 2018 Maxime Roussin-Belanger <maxime.roussinbelanger@gmail.com>7 */8 9#include <linux/delay.h>10#include <linux/i2c.h>11#include <linux/interrupt.h>12#include <linux/module.h>13#include <linux/regmap.h>14 15#include <linux/iio/iio.h>16#include <linux/iio/sysfs.h>17 18#include <linux/util_macros.h>19 20#include <linux/unaligned.h>21 22#define SI1133_REG_PART_ID		0x0023#define SI1133_REG_REV_ID		0x0124#define SI1133_REG_MFR_ID		0x0225#define SI1133_REG_INFO0		0x0326#define SI1133_REG_INFO1		0x0427 28#define SI1133_PART_ID			0x3329 30#define SI1133_REG_HOSTIN0		0x0A31#define SI1133_REG_COMMAND		0x0B32#define SI1133_REG_IRQ_ENABLE		0x0F33#define SI1133_REG_RESPONSE1		0x1034#define SI1133_REG_RESPONSE0		0x1135#define SI1133_REG_IRQ_STATUS		0x1236#define SI1133_REG_MEAS_RATE		0x1A37 38#define SI1133_IRQ_CHANNEL_ENABLE	0xF39 40#define SI1133_CMD_RESET_CTR		0x0041#define SI1133_CMD_RESET_SW		0x0142#define SI1133_CMD_FORCE		0x1143#define SI1133_CMD_START_AUTONOMOUS	0x1344#define SI1133_CMD_PARAM_SET		0x8045#define SI1133_CMD_PARAM_QUERY		0x4046#define SI1133_CMD_PARAM_MASK		0x3F47 48#define SI1133_CMD_ERR_MASK		BIT(4)49#define SI1133_CMD_SEQ_MASK		0xF50#define SI1133_MAX_CMD_CTR		0xF51 52#define SI1133_PARAM_REG_CHAN_LIST	0x0153#define SI1133_PARAM_REG_ADCCONFIG(x)	((x) * 4) + 254#define SI1133_PARAM_REG_ADCSENS(x)	((x) * 4) + 355#define SI1133_PARAM_REG_ADCPOST(x)	((x) * 4) + 456 57#define SI1133_ADCMUX_MASK 0x1F58 59#define SI1133_ADCCONFIG_DECIM_RATE(x)	(x) << 560 61#define SI1133_ADCSENS_SCALE_MASK 0x7062#define SI1133_ADCSENS_SCALE_SHIFT 463#define SI1133_ADCSENS_HSIG_MASK BIT(7)64#define SI1133_ADCSENS_HSIG_SHIFT 765#define SI1133_ADCSENS_HW_GAIN_MASK 0xF66#define SI1133_ADCSENS_NB_MEAS(x)	fls(x) << SI1133_ADCSENS_SCALE_SHIFT67 68#define SI1133_ADCPOST_24BIT_EN BIT(6)69#define SI1133_ADCPOST_POSTSHIFT_BITQTY(x) (x & GENMASK(2, 0)) << 370 71#define SI1133_PARAM_ADCMUX_SMALL_IR	0x072#define SI1133_PARAM_ADCMUX_MED_IR	0x173#define SI1133_PARAM_ADCMUX_LARGE_IR	0x274#define SI1133_PARAM_ADCMUX_WHITE	0xB75#define SI1133_PARAM_ADCMUX_LARGE_WHITE	0xD76#define SI1133_PARAM_ADCMUX_UV		0x1877#define SI1133_PARAM_ADCMUX_UV_DEEP	0x1978 79#define SI1133_ERR_INVALID_CMD		0x080#define SI1133_ERR_INVALID_LOCATION_CMD 0x181#define SI1133_ERR_SATURATION_ADC_OR_OVERFLOW_ACCUMULATION 0x282#define SI1133_ERR_OUTPUT_BUFFER_OVERFLOW 0x383 84#define SI1133_COMPLETION_TIMEOUT_MS	50085 86#define SI1133_CMD_MINSLEEP_US_LOW	500087#define SI1133_CMD_MINSLEEP_US_HIGH	750088#define SI1133_CMD_TIMEOUT_MS		2589#define SI1133_CMD_LUX_TIMEOUT_MS	500090#define SI1133_CMD_TIMEOUT_US		SI1133_CMD_TIMEOUT_MS * 100091 92#define SI1133_REG_HOSTOUT(x)		(x) + 0x1393 94#define SI1133_MEASUREMENT_FREQUENCY 125095 96#define SI1133_X_ORDER_MASK            0x007097#define SI1133_Y_ORDER_MASK            0x000798#define si1133_get_x_order(m)          ((m) & SI1133_X_ORDER_MASK) >> 499#define si1133_get_y_order(m)          ((m) & SI1133_Y_ORDER_MASK)100 101#define SI1133_LUX_ADC_MASK		0xE102#define SI1133_ADC_THRESHOLD		16000103#define SI1133_INPUT_FRACTION_HIGH	7104#define SI1133_INPUT_FRACTION_LOW	15105#define SI1133_LUX_OUTPUT_FRACTION	12106#define SI1133_LUX_BUFFER_SIZE		9107#define SI1133_MEASURE_BUFFER_SIZE	3108 109static const int si1133_scale_available[] = {110	1, 2, 4, 8, 16, 32, 64, 128};111 112static IIO_CONST_ATTR(scale_available, "1 2 4 8 16 32 64 128");113 114static IIO_CONST_ATTR_INT_TIME_AVAIL("0.0244 0.0488 0.0975 0.195 0.390 0.780 "115				     "1.560 3.120 6.24 12.48 25.0 50.0");116 117/* A.K.A. HW_GAIN in datasheet */118enum si1133_int_time {119	    _24_4_us = 0,120	    _48_8_us = 1,121	    _97_5_us = 2,122	   _195_0_us = 3,123	   _390_0_us = 4,124	   _780_0_us = 5,125	 _1_560_0_us = 6,126	 _3_120_0_us = 7,127	 _6_240_0_us = 8,128	_12_480_0_us = 9,129	_25_ms = 10,130	_50_ms = 11,131};132 133/* Integration time in milliseconds, nanoseconds */134static const int si1133_int_time_table[][2] = {135	[_24_4_us] = {0, 24400},136	[_48_8_us] = {0, 48800},137	[_97_5_us] = {0, 97500},138	[_195_0_us] = {0, 195000},139	[_390_0_us] = {0, 390000},140	[_780_0_us] = {0, 780000},141	[_1_560_0_us] = {1, 560000},142	[_3_120_0_us] = {3, 120000},143	[_6_240_0_us] = {6, 240000},144	[_12_480_0_us] = {12, 480000},145	[_25_ms] = {25, 000000},146	[_50_ms] = {50, 000000},147};148 149static const struct regmap_range si1133_reg_ranges[] = {150	regmap_reg_range(0x00, 0x02),151	regmap_reg_range(0x0A, 0x0B),152	regmap_reg_range(0x0F, 0x0F),153	regmap_reg_range(0x10, 0x12),154	regmap_reg_range(0x13, 0x2C),155};156 157static const struct regmap_range si1133_reg_ro_ranges[] = {158	regmap_reg_range(0x00, 0x02),159	regmap_reg_range(0x10, 0x2C),160};161 162static const struct regmap_range si1133_precious_ranges[] = {163	regmap_reg_range(0x12, 0x12),164};165 166static const struct regmap_access_table si1133_write_ranges_table = {167	.yes_ranges	= si1133_reg_ranges,168	.n_yes_ranges	= ARRAY_SIZE(si1133_reg_ranges),169	.no_ranges	= si1133_reg_ro_ranges,170	.n_no_ranges	= ARRAY_SIZE(si1133_reg_ro_ranges),171};172 173static const struct regmap_access_table si1133_read_ranges_table = {174	.yes_ranges	= si1133_reg_ranges,175	.n_yes_ranges	= ARRAY_SIZE(si1133_reg_ranges),176};177 178static const struct regmap_access_table si1133_precious_table = {179	.yes_ranges	= si1133_precious_ranges,180	.n_yes_ranges	= ARRAY_SIZE(si1133_precious_ranges),181};182 183static const struct regmap_config si1133_regmap_config = {184	.reg_bits = 8,185	.val_bits = 8,186 187	.max_register = 0x2C,188 189	.wr_table = &si1133_write_ranges_table,190	.rd_table = &si1133_read_ranges_table,191 192	.precious_table = &si1133_precious_table,193};194 195struct si1133_data {196	struct regmap *regmap;197	struct i2c_client *client;198 199	/* Lock protecting one command at a time can be processed */200	struct mutex mutex;201 202	int rsp_seq;203	u8 scan_mask;204	u8 adc_sens[6];205	u8 adc_config[6];206 207	struct completion completion;208};209 210struct si1133_coeff {211	s16 info;212	u16 mag;213};214 215struct si1133_lux_coeff {216	struct si1133_coeff coeff_high[4];217	struct si1133_coeff coeff_low[9];218};219 220static const struct si1133_lux_coeff lux_coeff = {221	{222		{  0,   209},223		{ 1665,  93},224		{ 2064,  65},225		{-2671, 234}226	},227	{228		{    0,     0},229		{ 1921, 29053},230		{-1022, 36363},231		{ 2320, 20789},232		{ -367, 57909},233		{-1774, 38240},234		{ -608, 46775},235		{-1503, 51831},236		{-1886, 58928}237	}238};239 240static int si1133_calculate_polynomial_inner(s32 input, u8 fraction, u16 mag,241					     s8 shift)242{243	return ((input << fraction) / mag) << shift;244}245 246static int si1133_calculate_output(s32 x, s32 y, u8 x_order, u8 y_order,247				   u8 input_fraction, s8 sign,248				   const struct si1133_coeff *coeffs)249{250	s8 shift;251	int x1 = 1;252	int x2 = 1;253	int y1 = 1;254	int y2 = 1;255 256	shift = ((u16)coeffs->info & 0xFF00) >> 8;257	shift ^= 0xFF;258	shift += 1;259	shift = -shift;260 261	if (x_order > 0) {262		x1 = si1133_calculate_polynomial_inner(x, input_fraction,263						       coeffs->mag, shift);264		if (x_order > 1)265			x2 = x1;266	}267 268	if (y_order > 0) {269		y1 = si1133_calculate_polynomial_inner(y, input_fraction,270						       coeffs->mag, shift);271		if (y_order > 1)272			y2 = y1;273	}274 275	return sign * x1 * x2 * y1 * y2;276}277 278/*279 * The algorithm is from:280 * https://siliconlabs.github.io/Gecko_SDK_Doc/efm32zg/html/si1133_8c_source.html#l00716281 */282static int si1133_calc_polynomial(s32 x, s32 y, u8 input_fraction, u8 num_coeff,283				  const struct si1133_coeff *coeffs)284{285	u8 x_order, y_order;286	u8 counter;287	s8 sign;288	int output = 0;289 290	for (counter = 0; counter < num_coeff; counter++) {291		if (coeffs->info < 0)292			sign = -1;293		else294			sign = 1;295 296		x_order = si1133_get_x_order(coeffs->info);297		y_order = si1133_get_y_order(coeffs->info);298 299		if ((x_order == 0) && (y_order == 0))300			output +=301			       sign * coeffs->mag << SI1133_LUX_OUTPUT_FRACTION;302		else303			output += si1133_calculate_output(x, y, x_order,304							  y_order,305							  input_fraction, sign,306							  coeffs);307		coeffs++;308	}309 310	return abs(output);311}312 313static int si1133_cmd_reset_sw(struct si1133_data *data)314{315	struct device *dev = &data->client->dev;316	unsigned int resp;317	unsigned long timeout;318	int err;319 320	err = regmap_write(data->regmap, SI1133_REG_COMMAND,321			   SI1133_CMD_RESET_SW);322	if (err)323		return err;324 325	timeout = jiffies + msecs_to_jiffies(SI1133_CMD_TIMEOUT_MS);326	while (true) {327		err = regmap_read(data->regmap, SI1133_REG_RESPONSE0, &resp);328		if (err == -ENXIO) {329			usleep_range(SI1133_CMD_MINSLEEP_US_LOW,330				     SI1133_CMD_MINSLEEP_US_HIGH);331			continue;332		}333 334		if ((resp & SI1133_MAX_CMD_CTR) == SI1133_MAX_CMD_CTR)335			break;336 337		if (time_after(jiffies, timeout)) {338			dev_warn(dev, "Timeout on reset ctr resp: %d\n", resp);339			return -ETIMEDOUT;340		}341	}342 343	if (!err)344		data->rsp_seq = SI1133_MAX_CMD_CTR;345 346	return err;347}348 349static int si1133_parse_response_err(struct device *dev, u32 resp, u8 cmd)350{351	resp &= 0xF;352 353	switch (resp) {354	case SI1133_ERR_OUTPUT_BUFFER_OVERFLOW:355		dev_warn(dev, "Output buffer overflow: 0x%02x\n", cmd);356		return -EOVERFLOW;357	case SI1133_ERR_SATURATION_ADC_OR_OVERFLOW_ACCUMULATION:358		dev_warn(dev, "Saturation of the ADC or overflow of accumulation: 0x%02x\n",359			 cmd);360		return -EOVERFLOW;361	case SI1133_ERR_INVALID_LOCATION_CMD:362		dev_warn(dev,363			 "Parameter access to an invalid location: 0x%02x\n",364			 cmd);365		return -EINVAL;366	case SI1133_ERR_INVALID_CMD:367		dev_warn(dev, "Invalid command 0x%02x\n", cmd);368		return -EINVAL;369	default:370		dev_warn(dev, "Unknown error 0x%02x\n", cmd);371		return -EINVAL;372	}373}374 375static int si1133_cmd_reset_counter(struct si1133_data *data)376{377	int err = regmap_write(data->regmap, SI1133_REG_COMMAND,378			       SI1133_CMD_RESET_CTR);379	if (err)380		return err;381 382	data->rsp_seq = 0;383 384	return 0;385}386 387static int si1133_command(struct si1133_data *data, u8 cmd)388{389	struct device *dev = &data->client->dev;390	u32 resp;391	int err;392	int expected_seq;393 394	mutex_lock(&data->mutex);395 396	expected_seq = (data->rsp_seq + 1) & SI1133_MAX_CMD_CTR;397 398	if (cmd == SI1133_CMD_FORCE)399		reinit_completion(&data->completion);400 401	err = regmap_write(data->regmap, SI1133_REG_COMMAND, cmd);402	if (err) {403		dev_warn(dev, "Failed to write command 0x%02x, ret=%d\n", cmd,404			 err);405		goto out;406	}407 408	if (cmd == SI1133_CMD_FORCE) {409		/* wait for irq */410		if (!wait_for_completion_timeout(&data->completion,411			msecs_to_jiffies(SI1133_COMPLETION_TIMEOUT_MS))) {412			err = -ETIMEDOUT;413			goto out;414		}415		err = regmap_read(data->regmap, SI1133_REG_RESPONSE0, &resp);416		if (err)417			goto out;418	} else {419		err = regmap_read_poll_timeout(data->regmap,420					       SI1133_REG_RESPONSE0, resp,421					       (resp & SI1133_CMD_SEQ_MASK) ==422					       expected_seq ||423					       (resp & SI1133_CMD_ERR_MASK),424					       SI1133_CMD_MINSLEEP_US_LOW,425					       SI1133_CMD_TIMEOUT_MS * 1000);426		if (err) {427			dev_warn(dev,428				 "Failed to read command 0x%02x, ret=%d\n",429				 cmd, err);430			goto out;431		}432	}433 434	if (resp & SI1133_CMD_ERR_MASK) {435		err = si1133_parse_response_err(dev, resp, cmd);436		si1133_cmd_reset_counter(data);437	} else {438		data->rsp_seq = expected_seq;439	}440 441out:442	mutex_unlock(&data->mutex);443 444	return err;445}446 447static int si1133_param_set(struct si1133_data *data, u8 param, u32 value)448{449	int err = regmap_write(data->regmap, SI1133_REG_HOSTIN0, value);450 451	if (err)452		return err;453 454	return si1133_command(data, SI1133_CMD_PARAM_SET |455			      (param & SI1133_CMD_PARAM_MASK));456}457 458static int si1133_param_query(struct si1133_data *data, u8 param, u32 *result)459{460	int err = si1133_command(data, SI1133_CMD_PARAM_QUERY |461				 (param & SI1133_CMD_PARAM_MASK));462	if (err)463		return err;464 465	return regmap_read(data->regmap, SI1133_REG_RESPONSE1, result);466}467 468#define SI1133_CHANNEL(_ch, _type) \469	.type = _type, \470	.channel = _ch, \471	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \472	.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME) | \473		BIT(IIO_CHAN_INFO_SCALE) | \474		BIT(IIO_CHAN_INFO_HARDWAREGAIN), \475 476static const struct iio_chan_spec si1133_channels[] = {477	{478		.type = IIO_LIGHT,479		.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),480		.channel = 0,481	},482	{483		SI1133_CHANNEL(SI1133_PARAM_ADCMUX_WHITE, IIO_INTENSITY)484		.channel2 = IIO_MOD_LIGHT_BOTH,485	},486	{487		SI1133_CHANNEL(SI1133_PARAM_ADCMUX_LARGE_WHITE, IIO_INTENSITY)488		.channel2 = IIO_MOD_LIGHT_BOTH,489		.extend_name = "large",490	},491	{492		SI1133_CHANNEL(SI1133_PARAM_ADCMUX_SMALL_IR, IIO_INTENSITY)493		.extend_name = "small",494		.modified = 1,495		.channel2 = IIO_MOD_LIGHT_IR,496	},497	{498		SI1133_CHANNEL(SI1133_PARAM_ADCMUX_MED_IR, IIO_INTENSITY)499		.modified = 1,500		.channel2 = IIO_MOD_LIGHT_IR,501	},502	{503		SI1133_CHANNEL(SI1133_PARAM_ADCMUX_LARGE_IR, IIO_INTENSITY)504		.extend_name = "large",505		.modified = 1,506		.channel2 = IIO_MOD_LIGHT_IR,507	},508	{509		SI1133_CHANNEL(SI1133_PARAM_ADCMUX_UV, IIO_UVINDEX)510	},511	{512		SI1133_CHANNEL(SI1133_PARAM_ADCMUX_UV_DEEP, IIO_UVINDEX)513		.modified = 1,514		.channel2 = IIO_MOD_LIGHT_DUV,515	}516};517 518static int si1133_get_int_time_index(int milliseconds, int nanoseconds)519{520	int i;521 522	for (i = 0; i < ARRAY_SIZE(si1133_int_time_table); i++) {523		if (milliseconds == si1133_int_time_table[i][0] &&524		    nanoseconds == si1133_int_time_table[i][1])525			return i;526	}527	return -EINVAL;528}529 530static int si1133_set_integration_time(struct si1133_data *data, u8 adc,531				       int milliseconds, int nanoseconds)532{533	int index;534 535	index = si1133_get_int_time_index(milliseconds, nanoseconds);536	if (index < 0)537		return index;538 539	data->adc_sens[adc] &= 0xF0;540	data->adc_sens[adc] |= index;541 542	return si1133_param_set(data, SI1133_PARAM_REG_ADCSENS(0),543				data->adc_sens[adc]);544}545 546static int si1133_set_chlist(struct si1133_data *data, u8 scan_mask)547{548	/* channel list already set, no need to reprogram */549	if (data->scan_mask == scan_mask)550		return 0;551 552	data->scan_mask = scan_mask;553 554	return si1133_param_set(data, SI1133_PARAM_REG_CHAN_LIST, scan_mask);555}556 557static int si1133_chan_set_adcconfig(struct si1133_data *data, u8 adc,558				     u8 adc_config)559{560	int err;561 562	err = si1133_param_set(data, SI1133_PARAM_REG_ADCCONFIG(adc),563			       adc_config);564	if (err)565		return err;566 567	data->adc_config[adc] = adc_config;568 569	return 0;570}571 572static int si1133_update_adcconfig(struct si1133_data *data, uint8_t adc,573				   u8 mask, u8 shift, u8 value)574{575	u32 adc_config;576	int err;577 578	err = si1133_param_query(data, SI1133_PARAM_REG_ADCCONFIG(adc),579				 &adc_config);580	if (err)581		return err;582 583	adc_config &= ~mask;584	adc_config |= (value << shift);585 586	return si1133_chan_set_adcconfig(data, adc, adc_config);587}588 589static int si1133_set_adcmux(struct si1133_data *data, u8 adc, u8 mux)590{591	if ((mux & data->adc_config[adc]) == mux)592		return 0; /* mux already set to correct value */593 594	return si1133_update_adcconfig(data, adc, SI1133_ADCMUX_MASK, 0, mux);595}596 597static int si1133_force_measurement(struct si1133_data *data)598{599	return si1133_command(data, SI1133_CMD_FORCE);600}601 602static int si1133_bulk_read(struct si1133_data *data, u8 start_reg, u8 length,603			    u8 *buffer)604{605	int err;606 607	err = si1133_force_measurement(data);608	if (err)609		return err;610 611	return regmap_bulk_read(data->regmap, start_reg, buffer, length);612}613 614static int si1133_measure(struct si1133_data *data,615			  struct iio_chan_spec const *chan,616			  int *val)617{618	int err;619 620	u8 buffer[SI1133_MEASURE_BUFFER_SIZE];621 622	err = si1133_set_adcmux(data, 0, chan->channel);623	if (err)624		return err;625 626	/* Deactivate lux measurements if they were active */627	err = si1133_set_chlist(data, BIT(0));628	if (err)629		return err;630 631	err = si1133_bulk_read(data, SI1133_REG_HOSTOUT(0), sizeof(buffer),632			       buffer);633	if (err)634		return err;635 636	*val = sign_extend32(get_unaligned_be24(&buffer[0]), 23);637 638	return err;639}640 641static irqreturn_t si1133_threaded_irq_handler(int irq, void *private)642{643	struct iio_dev *iio_dev = private;644	struct si1133_data *data = iio_priv(iio_dev);645	u32 irq_status;646	int err;647 648	err = regmap_read(data->regmap, SI1133_REG_IRQ_STATUS, &irq_status);649	if (err) {650		dev_err_ratelimited(&iio_dev->dev, "Error reading IRQ\n");651		goto out;652	}653 654	if (irq_status != data->scan_mask)655		return IRQ_NONE;656 657out:658	complete(&data->completion);659 660	return IRQ_HANDLED;661}662 663static int si1133_scale_to_swgain(int scale_integer, int scale_fractional)664{665	scale_integer = find_closest(scale_integer, si1133_scale_available,666				     ARRAY_SIZE(si1133_scale_available));667	if (scale_integer < 0 ||668	    scale_integer > ARRAY_SIZE(si1133_scale_available) ||669	    scale_fractional != 0)670		return -EINVAL;671 672	return scale_integer;673}674 675static int si1133_chan_set_adcsens(struct si1133_data *data, u8 adc,676				   u8 adc_sens)677{678	int err;679 680	err = si1133_param_set(data, SI1133_PARAM_REG_ADCSENS(adc), adc_sens);681	if (err)682		return err;683 684	data->adc_sens[adc] = adc_sens;685 686	return 0;687}688 689static int si1133_update_adcsens(struct si1133_data *data, u8 mask,690				 u8 shift, u8 value)691{692	int err;693	u32 adc_sens;694 695	err = si1133_param_query(data, SI1133_PARAM_REG_ADCSENS(0),696				 &adc_sens);697	if (err)698		return err;699 700	adc_sens &= ~mask;701	adc_sens |= (value << shift);702 703	return si1133_chan_set_adcsens(data, 0, adc_sens);704}705 706static int si1133_get_lux(struct si1133_data *data, int *val)707{708	int err;709	int lux;710	s32 high_vis;711	s32 low_vis;712	s32 ir;713	u8 buffer[SI1133_LUX_BUFFER_SIZE];714 715	/* Activate lux channels */716	err = si1133_set_chlist(data, SI1133_LUX_ADC_MASK);717	if (err)718		return err;719 720	err = si1133_bulk_read(data, SI1133_REG_HOSTOUT(0),721			       SI1133_LUX_BUFFER_SIZE, buffer);722	if (err)723		return err;724 725	high_vis = sign_extend32(get_unaligned_be24(&buffer[0]), 23);726 727	low_vis = sign_extend32(get_unaligned_be24(&buffer[3]), 23);728 729	ir = sign_extend32(get_unaligned_be24(&buffer[6]), 23);730 731	if (high_vis > SI1133_ADC_THRESHOLD || ir > SI1133_ADC_THRESHOLD)732		lux = si1133_calc_polynomial(high_vis, ir,733					     SI1133_INPUT_FRACTION_HIGH,734					     ARRAY_SIZE(lux_coeff.coeff_high),735					     &lux_coeff.coeff_high[0]);736	else737		lux = si1133_calc_polynomial(low_vis, ir,738					     SI1133_INPUT_FRACTION_LOW,739					     ARRAY_SIZE(lux_coeff.coeff_low),740					     &lux_coeff.coeff_low[0]);741 742	*val = lux >> SI1133_LUX_OUTPUT_FRACTION;743 744	return err;745}746 747static int si1133_read_raw(struct iio_dev *iio_dev,748			   struct iio_chan_spec const *chan,749			   int *val, int *val2, long mask)750{751	struct si1133_data *data = iio_priv(iio_dev);752	u8 adc_sens = data->adc_sens[0];753	int err;754 755	switch (mask) {756	case IIO_CHAN_INFO_PROCESSED:757		switch (chan->type) {758		case IIO_LIGHT:759			err = si1133_get_lux(data, val);760			if (err)761				return err;762 763			return IIO_VAL_INT;764		default:765			return -EINVAL;766		}767	case IIO_CHAN_INFO_RAW:768		switch (chan->type) {769		case IIO_INTENSITY:770		case IIO_UVINDEX:771			err = si1133_measure(data, chan, val);772			if (err)773				return err;774 775			return IIO_VAL_INT;776		default:777			return -EINVAL;778		}779	case IIO_CHAN_INFO_INT_TIME:780		switch (chan->type) {781		case IIO_INTENSITY:782		case IIO_UVINDEX:783			adc_sens &= SI1133_ADCSENS_HW_GAIN_MASK;784 785			*val = si1133_int_time_table[adc_sens][0];786			*val2 = si1133_int_time_table[adc_sens][1];787			return IIO_VAL_INT_PLUS_MICRO;788		default:789			return -EINVAL;790		}791	case IIO_CHAN_INFO_SCALE:792		switch (chan->type) {793		case IIO_INTENSITY:794		case IIO_UVINDEX:795			adc_sens &= SI1133_ADCSENS_SCALE_MASK;796			adc_sens >>= SI1133_ADCSENS_SCALE_SHIFT;797 798			*val = BIT(adc_sens);799 800			return IIO_VAL_INT;801		default:802			return -EINVAL;803		}804	case IIO_CHAN_INFO_HARDWAREGAIN:805		switch (chan->type) {806		case IIO_INTENSITY:807		case IIO_UVINDEX:808			adc_sens >>= SI1133_ADCSENS_HSIG_SHIFT;809 810			*val = adc_sens;811 812			return IIO_VAL_INT;813		default:814			return -EINVAL;815		}816	default:817		return -EINVAL;818	}819}820 821static int si1133_write_raw(struct iio_dev *iio_dev,822			    struct iio_chan_spec const *chan,823			    int val, int val2, long mask)824{825	struct si1133_data *data = iio_priv(iio_dev);826 827	switch (mask) {828	case IIO_CHAN_INFO_SCALE:829		switch (chan->type) {830		case IIO_INTENSITY:831		case IIO_UVINDEX:832			val = si1133_scale_to_swgain(val, val2);833			if (val < 0)834				return val;835 836			return si1133_update_adcsens(data,837						     SI1133_ADCSENS_SCALE_MASK,838						     SI1133_ADCSENS_SCALE_SHIFT,839						     val);840		default:841			return -EINVAL;842		}843	case IIO_CHAN_INFO_INT_TIME:844		return si1133_set_integration_time(data, 0, val, val2);845	case IIO_CHAN_INFO_HARDWAREGAIN:846		switch (chan->type) {847		case IIO_INTENSITY:848		case IIO_UVINDEX:849			if (val != 0 && val != 1)850				return -EINVAL;851 852			return si1133_update_adcsens(data,853						     SI1133_ADCSENS_HSIG_MASK,854						     SI1133_ADCSENS_HSIG_SHIFT,855						     val);856		default:857			return -EINVAL;858		}859	default:860		return -EINVAL;861	}862}863 864static struct attribute *si1133_attributes[] = {865	&iio_const_attr_integration_time_available.dev_attr.attr,866	&iio_const_attr_scale_available.dev_attr.attr,867	NULL,868};869 870static const struct attribute_group si1133_attribute_group = {871	.attrs = si1133_attributes,872};873 874static const struct iio_info si1133_info = {875	.read_raw = si1133_read_raw,876	.write_raw = si1133_write_raw,877	.attrs = &si1133_attribute_group,878};879 880/*881 * si1133_init_lux_channels - Configure 3 different channels(adc) (1,2 and 3)882 * The channel configuration for the lux measurement was taken from :883 * https://siliconlabs.github.io/Gecko_SDK_Doc/efm32zg/html/si1133_8c_source.html#l00578884 *885 * Reserved the channel 0 for the other raw measurements886 */887static int si1133_init_lux_channels(struct si1133_data *data)888{889	int err;890 891	err = si1133_chan_set_adcconfig(data, 1,892					SI1133_ADCCONFIG_DECIM_RATE(1) |893					SI1133_PARAM_ADCMUX_LARGE_WHITE);894	if (err)895		return err;896 897	err = si1133_param_set(data, SI1133_PARAM_REG_ADCPOST(1),898			       SI1133_ADCPOST_24BIT_EN |899			       SI1133_ADCPOST_POSTSHIFT_BITQTY(0));900	if (err)901		return err;902	err = si1133_chan_set_adcsens(data, 1, SI1133_ADCSENS_HSIG_MASK |903				      SI1133_ADCSENS_NB_MEAS(64) | _48_8_us);904	if (err)905		return err;906 907	err = si1133_chan_set_adcconfig(data, 2,908					SI1133_ADCCONFIG_DECIM_RATE(1) |909					SI1133_PARAM_ADCMUX_LARGE_WHITE);910	if (err)911		return err;912 913	err = si1133_param_set(data, SI1133_PARAM_REG_ADCPOST(2),914			       SI1133_ADCPOST_24BIT_EN |915			       SI1133_ADCPOST_POSTSHIFT_BITQTY(2));916	if (err)917		return err;918 919	err = si1133_chan_set_adcsens(data, 2, SI1133_ADCSENS_HSIG_MASK |920				      SI1133_ADCSENS_NB_MEAS(1) | _3_120_0_us);921	if (err)922		return err;923 924	err = si1133_chan_set_adcconfig(data, 3,925					SI1133_ADCCONFIG_DECIM_RATE(1) |926					SI1133_PARAM_ADCMUX_MED_IR);927	if (err)928		return err;929 930	err = si1133_param_set(data, SI1133_PARAM_REG_ADCPOST(3),931			       SI1133_ADCPOST_24BIT_EN |932			       SI1133_ADCPOST_POSTSHIFT_BITQTY(2));933	if (err)934		return err;935 936	return  si1133_chan_set_adcsens(data, 3, SI1133_ADCSENS_HSIG_MASK |937					SI1133_ADCSENS_NB_MEAS(64) | _48_8_us);938}939 940static int si1133_initialize(struct si1133_data *data)941{942	int err;943 944	err = si1133_cmd_reset_sw(data);945	if (err)946		return err;947 948	/* Turn off autonomous mode */949	err = si1133_param_set(data, SI1133_REG_MEAS_RATE, 0);950	if (err)951		return err;952 953	err = si1133_init_lux_channels(data);954	if (err)955		return err;956 957	return regmap_write(data->regmap, SI1133_REG_IRQ_ENABLE,958			    SI1133_IRQ_CHANNEL_ENABLE);959}960 961static int si1133_validate_ids(struct iio_dev *iio_dev)962{963	struct si1133_data *data = iio_priv(iio_dev);964 965	unsigned int part_id, rev_id, mfr_id;966	int err;967 968	err = regmap_read(data->regmap, SI1133_REG_PART_ID, &part_id);969	if (err)970		return err;971 972	err = regmap_read(data->regmap, SI1133_REG_REV_ID, &rev_id);973	if (err)974		return err;975 976	err = regmap_read(data->regmap, SI1133_REG_MFR_ID, &mfr_id);977	if (err)978		return err;979 980	dev_info(&iio_dev->dev,981		 "Device ID part 0x%02x rev 0x%02x mfr 0x%02x\n",982		 part_id, rev_id, mfr_id);983	if (part_id != SI1133_PART_ID) {984		dev_err(&iio_dev->dev,985			"Part ID mismatch got 0x%02x, expected 0x%02x\n",986			part_id, SI1133_PART_ID);987		return -ENODEV;988	}989 990	return 0;991}992 993static int si1133_probe(struct i2c_client *client)994{995	const struct i2c_device_id *id = i2c_client_get_device_id(client);996	struct si1133_data *data;997	struct iio_dev *iio_dev;998	int err;999 1000	iio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));1001	if (!iio_dev)1002		return -ENOMEM;1003 1004	data = iio_priv(iio_dev);1005 1006	init_completion(&data->completion);1007 1008	data->regmap = devm_regmap_init_i2c(client, &si1133_regmap_config);1009	if (IS_ERR(data->regmap)) {1010		err = PTR_ERR(data->regmap);1011		dev_err(&client->dev, "Failed to initialise regmap: %d\n", err);1012		return err;1013	}1014 1015	i2c_set_clientdata(client, iio_dev);1016	data->client = client;1017 1018	iio_dev->name = id->name;1019	iio_dev->channels = si1133_channels;1020	iio_dev->num_channels = ARRAY_SIZE(si1133_channels);1021	iio_dev->info = &si1133_info;1022	iio_dev->modes = INDIO_DIRECT_MODE;1023 1024	mutex_init(&data->mutex);1025 1026	err = si1133_validate_ids(iio_dev);1027	if (err)1028		return err;1029 1030	err = si1133_initialize(data);1031	if (err) {1032		dev_err(&client->dev,1033			"Error when initializing chip: %d\n", err);1034		return err;1035	}1036 1037	if (!client->irq) {1038		dev_err(&client->dev,1039			"Required interrupt not provided, cannot proceed\n");1040		return -EINVAL;1041	}1042 1043	err = devm_request_threaded_irq(&client->dev, client->irq,1044					NULL,1045					si1133_threaded_irq_handler,1046					IRQF_ONESHOT | IRQF_SHARED,1047					client->name, iio_dev);1048	if (err) {1049		dev_warn(&client->dev, "Request irq %d failed: %i\n",1050			 client->irq, err);1051		return err;1052	}1053 1054	return devm_iio_device_register(&client->dev, iio_dev);1055}1056 1057static const struct i2c_device_id si1133_ids[] = {1058	{ "si1133" },1059	{ }1060};1061MODULE_DEVICE_TABLE(i2c, si1133_ids);1062 1063static struct i2c_driver si1133_driver = {1064	.driver = {1065	    .name   = "si1133",1066	},1067	.probe = si1133_probe,1068	.id_table = si1133_ids,1069};1070 1071module_i2c_driver(si1133_driver);1072 1073MODULE_AUTHOR("Maxime Roussin-Belanger <maxime.roussinbelanger@gmail.com>");1074MODULE_DESCRIPTION("Silabs SI1133, UV index sensor and ambient light sensor driver");1075MODULE_LICENSE("GPL");1076