brintos

brintos / linux-shallow public Read only

0
0
Text · 36.0 KiB · 079e02b Raw
1362 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * APDS-9306/APDS-9306-065 Ambient Light Sensor4 * I2C Address: 0x525 * Datasheet: https://docs.broadcom.com/doc/AV02-4755EN6 *7 * Copyright (C) 2024 Subhajit Ghosh <subhajit.ghosh@tweaklogic.com>8 */9 10#include <linux/bits.h>11#include <linux/cleanup.h>12#include <linux/delay.h>13#include <linux/err.h>14#include <linux/i2c.h>15#include <linux/interrupt.h>16#include <linux/minmax.h>17#include <linux/module.h>18#include <linux/mutex.h>19#include <linux/pm.h>20#include <linux/pm_runtime.h>21#include <linux/regmap.h>22#include <linux/regulator/consumer.h>23#include <linux/types.h>24#include <linux/units.h>25 26#include <linux/iio/iio.h>27#include <linux/iio/iio-gts-helper.h>28#include <linux/iio/events.h>29#include <linux/iio/sysfs.h>30 31#include <linux/unaligned.h>32 33#define APDS9306_MAIN_CTRL_REG		0x0034#define APDS9306_ALS_MEAS_RATE_REG	0x0435#define APDS9306_ALS_GAIN_REG		0x0536#define APDS9306_PART_ID_REG		0x0637#define APDS9306_MAIN_STATUS_REG	0x0738#define APDS9306_CLEAR_DATA_0_REG	0x0A39#define APDS9306_CLEAR_DATA_1_REG	0x0B40#define APDS9306_CLEAR_DATA_2_REG	0x0C41#define APDS9306_ALS_DATA_0_REG		0x0D42#define APDS9306_ALS_DATA_1_REG		0x0E43#define APDS9306_ALS_DATA_2_REG		0x0F44#define APDS9306_INT_CFG_REG		0x1945#define APDS9306_INT_PERSISTENCE_REG	0x1A46#define APDS9306_ALS_THRES_UP_0_REG	0x2147#define APDS9306_ALS_THRES_UP_1_REG	0x2248#define APDS9306_ALS_THRES_UP_2_REG	0x2349#define APDS9306_ALS_THRES_LOW_0_REG	0x2450#define APDS9306_ALS_THRES_LOW_1_REG	0x2551#define APDS9306_ALS_THRES_LOW_2_REG	0x2652#define APDS9306_ALS_THRES_VAR_REG	0x2753 54#define APDS9306_ALS_INT_STAT_MASK	BIT(4)55#define APDS9306_ALS_DATA_STAT_MASK	BIT(3)56 57#define APDS9306_ALS_THRES_VAL_MAX	(BIT(20) - 1)58#define APDS9306_ALS_THRES_VAR_NUM_VALS	859#define APDS9306_ALS_PERSIST_NUM_VALS	1660#define APDS9306_ALS_READ_DATA_DELAY_US	(20 * USEC_PER_MSEC)61#define APDS9306_NUM_REPEAT_RATES	762#define APDS9306_INT_SRC_CLEAR	063#define APDS9306_INT_SRC_ALS	164#define APDS9306_SAMP_FREQ_10HZ	065 66/**67 * struct part_id_gts_multiplier - Part no. and corresponding gts multiplier68 *69 * GTS (Gain Time Scale) are helper functions for Light sensors which along70 * with hardware gains also has gains associated with Integration times.71 *72 * There are two variants of the device with slightly different characteristics,73 * they have same ADC count for different Lux levels as mentioned in the74 * datasheet. This multiplier array is used to store the derived Lux per count75 * value for the two variants to be used by the GTS helper functions.76 *77 * @part_id: Part ID of the device78 * @max_scale_int: Multiplier for iio_init_iio_gts()79 * @max_scale_nano: Multiplier for iio_init_iio_gts()80 */81struct part_id_gts_multiplier {82	int part_id;83	int max_scale_int;84	int max_scale_nano;85};86 87/*88 * As per the datasheet, at HW Gain = 3x, Integration time 100mS (32x),89 * typical 2000 ADC counts are observed for 49.8 uW per sq cm (340.134 lux)90 * for apds9306 and 43 uW per sq cm (293.69 lux) for apds9306-065.91 * Assuming lux per count is linear across all integration time ranges.92 *93 * Lux = (raw + offset) * scale; offset can be any value by userspace.94 * HG = Hardware Gain; ITG = Gain by changing integration time.95 * Scale table by IIO GTS Helpers = (1 / HG) * (1 / ITG) * Multiplier.96 *97 * The Lux values provided in the datasheet are at ITG=32x and HG=3x,98 * at typical 2000 count for both variants of the device.99 *100 * Lux per ADC count at 3x and 32x for apds9306 = 340.134 / 2000101 * Lux per ADC count at 3x and 32x for apds9306-065 = 293.69 / 2000102 *103 * The Multiplier for the scale table provided to userspace:104 * IIO GTS scale Multiplier for apds9306 = (340.134 / 2000) * 32 * 3 = 16.326432105 * and for apds9306-065 = (293.69 / 2000) * 32 * 3 = 14.09712106 */107static const struct part_id_gts_multiplier apds9306_gts_mul[] = {108	{109		.part_id = 0xB1,110		.max_scale_int = 16,111		.max_scale_nano = 3264320,112	}, {113		.part_id = 0xB3,114		.max_scale_int = 14,115		.max_scale_nano = 9712000,116	},117};118 119static const int apds9306_repeat_rate_freq[APDS9306_NUM_REPEAT_RATES][2] = {120	{ 40, 0 },121	{ 20, 0 },122	{ 10, 0 },123	{ 5,  0 },124	{ 2,  0 },125	{ 1,  0 },126	{ 0,  500000 },127};128 129static const int apds9306_repeat_rate_period[APDS9306_NUM_REPEAT_RATES] = {130	25000, 50000, 100000, 200000, 500000, 1000000, 2000000,131};132 133/**134 * struct apds9306_regfields - apds9306 regmap fields definitions135 *136 * @sw_reset: Software reset regfield137 * @en: Enable regfield138 * @intg_time: Resolution regfield139 * @repeat_rate: Measurement Rate regfield140 * @gain: Hardware gain regfield141 * @int_src: Interrupt channel regfield142 * @int_thresh_var_en: Interrupt variance threshold regfield143 * @int_en: Interrupt enable regfield144 * @int_persist_val: Interrupt persistence regfield145 * @int_thresh_var_val: Interrupt threshold variance value regfield146 */147struct apds9306_regfields {148	struct regmap_field *sw_reset;149	struct regmap_field *en;150	struct regmap_field *intg_time;151	struct regmap_field *repeat_rate;152	struct regmap_field *gain;153	struct regmap_field *int_src;154	struct regmap_field *int_thresh_var_en;155	struct regmap_field *int_en;156	struct regmap_field *int_persist_val;157	struct regmap_field *int_thresh_var_val;158};159 160/**161 * struct apds9306_data - apds9306 private data and registers definitions162 *163 * @dev: Pointer to the device structure164 * @gts: IIO Gain Time Scale structure165 * @mutex: Lock for protecting adc reads, device settings changes where166 *         some calculations are required before or after setting or167 *         getting the raw settings values from regmap writes or reads168 *         respectively.169 * @regmap: Regmap structure pointer170 * @rf: Regmap register fields structure171 * @nlux_per_count: Nano lux per ADC count for a particular model172 * @read_data_available: Flag set by IRQ handler for ADC data available173 */174struct apds9306_data {175	struct device *dev;176	struct iio_gts gts;177 178	struct mutex mutex;179 180	struct regmap *regmap;181	struct apds9306_regfields rf;182 183	int nlux_per_count;184	int read_data_available;185};186 187/*188 * Available scales with gain 1x - 18x, timings 3.125, 25, 50, 100, 200, 400 ms189 * Time impacts to gain: 1x, 8x, 16x, 32x, 64x, 128x190 */191#define APDS9306_GSEL_1X	0x00192#define APDS9306_GSEL_3X	0x01193#define APDS9306_GSEL_6X	0x02194#define APDS9306_GSEL_9X	0x03195#define APDS9306_GSEL_18X	0x04196 197static const struct iio_gain_sel_pair apds9306_gains[] = {198	GAIN_SCALE_GAIN(1, APDS9306_GSEL_1X),199	GAIN_SCALE_GAIN(3, APDS9306_GSEL_3X),200	GAIN_SCALE_GAIN(6, APDS9306_GSEL_6X),201	GAIN_SCALE_GAIN(9, APDS9306_GSEL_9X),202	GAIN_SCALE_GAIN(18, APDS9306_GSEL_18X),203};204 205#define APDS9306_MEAS_MODE_400MS	0x00206#define APDS9306_MEAS_MODE_200MS	0x01207#define APDS9306_MEAS_MODE_100MS	0x02208#define APDS9306_MEAS_MODE_50MS		0x03209#define APDS9306_MEAS_MODE_25MS		0x04210#define APDS9306_MEAS_MODE_3125US	0x05211 212static const struct iio_itime_sel_mul apds9306_itimes[] = {213	GAIN_SCALE_ITIME_US(400000, APDS9306_MEAS_MODE_400MS, BIT(7)),214	GAIN_SCALE_ITIME_US(200000, APDS9306_MEAS_MODE_200MS, BIT(6)),215	GAIN_SCALE_ITIME_US(100000, APDS9306_MEAS_MODE_100MS, BIT(5)),216	GAIN_SCALE_ITIME_US(50000, APDS9306_MEAS_MODE_50MS, BIT(4)),217	GAIN_SCALE_ITIME_US(25000, APDS9306_MEAS_MODE_25MS, BIT(3)),218	GAIN_SCALE_ITIME_US(3125, APDS9306_MEAS_MODE_3125US, BIT(0)),219};220 221static const struct iio_event_spec apds9306_event_spec[] = {222	{223		.type = IIO_EV_TYPE_THRESH,224		.dir = IIO_EV_DIR_RISING,225		.mask_shared_by_all = BIT(IIO_EV_INFO_VALUE),226	}, {227		.type = IIO_EV_TYPE_THRESH,228		.dir = IIO_EV_DIR_FALLING,229		.mask_shared_by_all = BIT(IIO_EV_INFO_VALUE),230	}, {231		.type = IIO_EV_TYPE_THRESH,232		.dir = IIO_EV_DIR_EITHER,233		.mask_shared_by_all = BIT(IIO_EV_INFO_PERIOD),234		.mask_separate = BIT(IIO_EV_INFO_ENABLE),235	}, {236		.type = IIO_EV_TYPE_THRESH_ADAPTIVE,237		.mask_shared_by_all = BIT(IIO_EV_INFO_VALUE) |238			BIT(IIO_EV_INFO_ENABLE),239	},240};241 242static const struct iio_chan_spec apds9306_channels_with_events[] = {243	{244		.type = IIO_LIGHT,245		.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME) |246					   BIT(IIO_CHAN_INFO_SAMP_FREQ),247		.info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_INT_TIME) |248						     BIT(IIO_CHAN_INFO_SAMP_FREQ),249		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |250				      BIT(IIO_CHAN_INFO_SCALE),251		.info_mask_separate_available = BIT(IIO_CHAN_INFO_SCALE),252		.event_spec = apds9306_event_spec,253		.num_event_specs = ARRAY_SIZE(apds9306_event_spec),254	}, {255		.type = IIO_INTENSITY,256		.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME) |257					   BIT(IIO_CHAN_INFO_SAMP_FREQ),258		.info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_INT_TIME) |259						     BIT(IIO_CHAN_INFO_SAMP_FREQ),260		.channel2 = IIO_MOD_LIGHT_CLEAR,261		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),262		.modified = 1,263		.event_spec = apds9306_event_spec,264		.num_event_specs = ARRAY_SIZE(apds9306_event_spec),265	},266};267 268static const struct iio_chan_spec apds9306_channels_without_events[] = {269	{270		.type = IIO_LIGHT,271		.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME) |272					   BIT(IIO_CHAN_INFO_SAMP_FREQ),273		.info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_INT_TIME) |274						     BIT(IIO_CHAN_INFO_SAMP_FREQ),275		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |276				      BIT(IIO_CHAN_INFO_SCALE),277		.info_mask_separate_available = BIT(IIO_CHAN_INFO_SCALE),278	}, {279		.type = IIO_INTENSITY,280		.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME) |281					   BIT(IIO_CHAN_INFO_SAMP_FREQ),282		.info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_INT_TIME) |283						     BIT(IIO_CHAN_INFO_SAMP_FREQ),284		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),285		.modified = 1,286		.channel2 = IIO_MOD_LIGHT_CLEAR,287	},288};289 290/* INT_PERSISTENCE available */291static IIO_CONST_ATTR(thresh_either_period_available, "[0 1 15]");292 293/* ALS_THRESH_VAR available */294static IIO_CONST_ATTR(thresh_adaptive_either_values_available, "[0 1 7]");295 296static struct attribute *apds9306_event_attributes[] = {297	&iio_const_attr_thresh_either_period_available.dev_attr.attr,298	&iio_const_attr_thresh_adaptive_either_values_available.dev_attr.attr,299	NULL300};301 302static const struct attribute_group apds9306_event_attr_group = {303	.attrs = apds9306_event_attributes,304};305 306static const struct regmap_range apds9306_readable_ranges[] = {307	regmap_reg_range(APDS9306_MAIN_CTRL_REG, APDS9306_ALS_THRES_VAR_REG)308};309 310static const struct regmap_range apds9306_writable_ranges[] = {311	regmap_reg_range(APDS9306_MAIN_CTRL_REG, APDS9306_ALS_GAIN_REG),312	regmap_reg_range(APDS9306_INT_CFG_REG, APDS9306_ALS_THRES_VAR_REG)313};314 315static const struct regmap_range apds9306_volatile_ranges[] = {316	regmap_reg_range(APDS9306_MAIN_STATUS_REG, APDS9306_MAIN_STATUS_REG),317	regmap_reg_range(APDS9306_CLEAR_DATA_0_REG, APDS9306_ALS_DATA_2_REG)318};319 320static const struct regmap_range apds9306_precious_ranges[] = {321	regmap_reg_range(APDS9306_MAIN_STATUS_REG, APDS9306_MAIN_STATUS_REG)322};323 324static const struct regmap_access_table apds9306_readable_table = {325	.yes_ranges = apds9306_readable_ranges,326	.n_yes_ranges = ARRAY_SIZE(apds9306_readable_ranges)327};328 329static const struct regmap_access_table apds9306_writable_table = {330	.yes_ranges = apds9306_writable_ranges,331	.n_yes_ranges = ARRAY_SIZE(apds9306_writable_ranges)332};333 334static const struct regmap_access_table apds9306_volatile_table = {335	.yes_ranges = apds9306_volatile_ranges,336	.n_yes_ranges = ARRAY_SIZE(apds9306_volatile_ranges)337};338 339static const struct regmap_access_table apds9306_precious_table = {340	.yes_ranges = apds9306_precious_ranges,341	.n_yes_ranges = ARRAY_SIZE(apds9306_precious_ranges)342};343 344static const struct regmap_config apds9306_regmap = {345	.name = "apds9306_regmap",346	.reg_bits = 8,347	.val_bits = 8,348	.rd_table = &apds9306_readable_table,349	.wr_table = &apds9306_writable_table,350	.volatile_table = &apds9306_volatile_table,351	.precious_table = &apds9306_precious_table,352	.max_register = APDS9306_ALS_THRES_VAR_REG,353	.cache_type = REGCACHE_RBTREE,354};355 356static const struct reg_field apds9306_rf_sw_reset =357	REG_FIELD(APDS9306_MAIN_CTRL_REG, 4, 4);358 359static const struct reg_field apds9306_rf_en =360	REG_FIELD(APDS9306_MAIN_CTRL_REG, 1, 1);361 362static const struct reg_field apds9306_rf_intg_time =363	REG_FIELD(APDS9306_ALS_MEAS_RATE_REG, 4, 6);364 365static const struct reg_field apds9306_rf_repeat_rate =366	REG_FIELD(APDS9306_ALS_MEAS_RATE_REG, 0, 2);367 368static const struct reg_field apds9306_rf_gain =369	REG_FIELD(APDS9306_ALS_GAIN_REG, 0, 2);370 371static const struct reg_field apds9306_rf_int_src =372	REG_FIELD(APDS9306_INT_CFG_REG, 4, 5);373 374static const struct reg_field apds9306_rf_int_thresh_var_en =375	REG_FIELD(APDS9306_INT_CFG_REG, 3, 3);376 377static const struct reg_field apds9306_rf_int_en =378	REG_FIELD(APDS9306_INT_CFG_REG, 2, 2);379 380static const struct reg_field apds9306_rf_int_persist_val =381	REG_FIELD(APDS9306_INT_PERSISTENCE_REG, 4, 7);382 383static const struct reg_field apds9306_rf_int_thresh_var_val =384	REG_FIELD(APDS9306_ALS_THRES_VAR_REG, 0, 2);385 386static int apds9306_regfield_init(struct apds9306_data *data)387{388	struct device *dev = data->dev;389	struct regmap *regmap = data->regmap;390	struct regmap_field *tmp;391	struct apds9306_regfields *rf = &data->rf;392 393	tmp = devm_regmap_field_alloc(dev, regmap, apds9306_rf_sw_reset);394	if (IS_ERR(tmp))395		return PTR_ERR(tmp);396	rf->sw_reset = tmp;397 398	tmp = devm_regmap_field_alloc(dev, regmap, apds9306_rf_en);399	if (IS_ERR(tmp))400		return PTR_ERR(tmp);401	rf->en = tmp;402 403	tmp = devm_regmap_field_alloc(dev, regmap, apds9306_rf_intg_time);404	if (IS_ERR(tmp))405		return PTR_ERR(tmp);406	rf->intg_time = tmp;407 408	tmp = devm_regmap_field_alloc(dev, regmap, apds9306_rf_repeat_rate);409	if (IS_ERR(tmp))410		return PTR_ERR(tmp);411	rf->repeat_rate = tmp;412 413	tmp = devm_regmap_field_alloc(dev, regmap, apds9306_rf_gain);414	if (IS_ERR(tmp))415		return PTR_ERR(tmp);416	rf->gain = tmp;417 418	tmp = devm_regmap_field_alloc(dev, regmap, apds9306_rf_int_src);419	if (IS_ERR(tmp))420		return PTR_ERR(tmp);421	rf->int_src = tmp;422 423	tmp = devm_regmap_field_alloc(dev, regmap, apds9306_rf_int_thresh_var_en);424	if (IS_ERR(tmp))425		return PTR_ERR(tmp);426	rf->int_thresh_var_en = tmp;427 428	tmp = devm_regmap_field_alloc(dev, regmap, apds9306_rf_int_en);429	if (IS_ERR(tmp))430		return PTR_ERR(tmp);431	rf->int_en = tmp;432 433	tmp = devm_regmap_field_alloc(dev, regmap, apds9306_rf_int_persist_val);434	if (IS_ERR(tmp))435		return PTR_ERR(tmp);436	rf->int_persist_val = tmp;437 438	tmp = devm_regmap_field_alloc(dev, regmap, apds9306_rf_int_thresh_var_val);439	if (IS_ERR(tmp))440		return PTR_ERR(tmp);441	rf->int_thresh_var_val = tmp;442 443	return 0;444}445 446static int apds9306_power_state(struct apds9306_data *data, bool state)447{448	struct apds9306_regfields *rf = &data->rf;449	int ret;450 451	/* Reset not included as it causes ugly I2C bus error */452	if (state) {453		ret = regmap_field_write(rf->en, 1);454		if (ret)455			return ret;456		/* 5ms wake up time */457		fsleep(5000);458		return 0;459	}460 461	return regmap_field_write(rf->en, 0);462}463 464static int apds9306_read_data(struct apds9306_data *data, int *val, int reg)465{466	struct device *dev = data->dev;467	struct iio_dev *indio_dev = dev_to_iio_dev(dev);468	struct apds9306_regfields *rf = &data->rf;469	u64 ev_code;470	int ret, delay, intg_time, intg_time_idx, repeat_rate_idx, int_src;471	int status = 0;472	u8 buff[3];473 474	ret = pm_runtime_resume_and_get(data->dev);475	if (ret)476		return ret;477 478	ret = regmap_field_read(rf->intg_time, &intg_time_idx);479	if (ret)480		return ret;481 482	ret = regmap_field_read(rf->repeat_rate, &repeat_rate_idx);483	if (ret)484		return ret;485 486	ret = regmap_field_read(rf->int_src, &int_src);487	if (ret)488		return ret;489 490	intg_time = iio_gts_find_int_time_by_sel(&data->gts, intg_time_idx);491	if (intg_time < 0)492		return intg_time;493 494	/* Whichever is greater - integration time period or sampling period. */495	delay = max(intg_time, apds9306_repeat_rate_period[repeat_rate_idx]);496 497	/*498	 * Clear stale data flag that might have been set by the interrupt499	 * handler if it got data available flag set in the status reg.500	 */501	data->read_data_available = 0;502 503	/*504	 * If this function runs parallel with the interrupt handler, either505	 * this reads and clears the status registers or the interrupt handler506	 * does. The interrupt handler sets a flag for read data available507	 * in our private structure which we read here.508	 */509	ret = regmap_read_poll_timeout(data->regmap, APDS9306_MAIN_STATUS_REG,510				       status, data->read_data_available ||511				       (status & (APDS9306_ALS_DATA_STAT_MASK |512						  APDS9306_ALS_INT_STAT_MASK)),513				       APDS9306_ALS_READ_DATA_DELAY_US, delay * 2);514	if (ret)515		return ret;516 517	/* If we reach here before the interrupt handler we push an event */518	if ((status & APDS9306_ALS_INT_STAT_MASK)) {519		if (int_src == APDS9306_INT_SRC_ALS)520			ev_code = IIO_UNMOD_EVENT_CODE(IIO_LIGHT, 0,521						       IIO_EV_TYPE_THRESH,522						       IIO_EV_DIR_EITHER);523		else524			ev_code = IIO_MOD_EVENT_CODE(IIO_INTENSITY, 0,525						     IIO_MOD_LIGHT_CLEAR,526						     IIO_EV_TYPE_THRESH,527						     IIO_EV_DIR_EITHER);528 529		iio_push_event(indio_dev, ev_code, iio_get_time_ns(indio_dev));530	}531 532	ret = regmap_bulk_read(data->regmap, reg, buff, sizeof(buff));533	if (ret) {534		dev_err_ratelimited(dev, "read data failed\n");535		return ret;536	}537 538	*val = get_unaligned_le24(&buff);539 540	pm_runtime_mark_last_busy(data->dev);541	pm_runtime_put_autosuspend(data->dev);542 543	return 0;544}545 546static int apds9306_intg_time_get(struct apds9306_data *data, int *val2)547{548	struct apds9306_regfields *rf = &data->rf;549	int ret, intg_time_idx;550 551	ret = regmap_field_read(rf->intg_time, &intg_time_idx);552	if (ret)553		return ret;554 555	ret = iio_gts_find_int_time_by_sel(&data->gts, intg_time_idx);556	if (ret < 0)557		return ret;558 559	*val2 = ret;560 561	return 0;562}563 564static int apds9306_intg_time_set(struct apds9306_data *data, int val2)565{566	struct device *dev = data->dev;567	struct apds9306_regfields *rf = &data->rf;568	int ret, intg_old, gain_old, gain_new, gain_new_closest, intg_time_idx;569	int gain_idx;570	bool ok;571 572	if (!iio_gts_valid_time(&data->gts, val2)) {573		dev_err_ratelimited(dev, "Unsupported integration time %u\n", val2);574		return -EINVAL;575	}576 577	ret = regmap_field_read(rf->intg_time, &intg_time_idx);578	if (ret)579		return ret;580 581	ret = regmap_field_read(rf->gain, &gain_idx);582	if (ret)583		return ret;584 585	intg_old = iio_gts_find_int_time_by_sel(&data->gts, intg_time_idx);586	if (intg_old < 0)587		return intg_old;588 589	if (intg_old == val2)590		return 0;591 592	gain_old = iio_gts_find_gain_by_sel(&data->gts, gain_idx);593	if (gain_old < 0)594		return gain_old;595 596	iio_gts_find_new_gain_by_old_gain_time(&data->gts, gain_old, intg_old,597					       val2, &gain_new);598 599	if (gain_new < 0) {600		dev_err_ratelimited(dev, "Unsupported gain with time\n");601		return gain_new;602	}603 604	gain_new_closest = iio_find_closest_gain_low(&data->gts, gain_new, &ok);605	if (gain_new_closest < 0) {606		gain_new_closest = iio_gts_get_min_gain(&data->gts);607		if (gain_new_closest < 0)608			return gain_new_closest;609	}610	if (!ok)611		dev_dbg(dev, "Unable to find optimum gain, setting minimum");612 613	ret = iio_gts_find_sel_by_int_time(&data->gts, val2);614	if (ret < 0)615		return ret;616 617	ret = regmap_field_write(rf->intg_time, ret);618	if (ret)619		return ret;620 621	ret = iio_gts_find_sel_by_gain(&data->gts, gain_new_closest);622	if (ret < 0)623		return ret;624 625	return regmap_field_write(rf->gain, ret);626}627 628static int apds9306_sampling_freq_get(struct apds9306_data *data, int *val,629				      int *val2)630{631	struct apds9306_regfields *rf = &data->rf;632	int ret, repeat_rate_idx;633 634	ret = regmap_field_read(rf->repeat_rate, &repeat_rate_idx);635	if (ret)636		return ret;637 638	if (repeat_rate_idx >= ARRAY_SIZE(apds9306_repeat_rate_freq))639		return -EINVAL;640 641	*val = apds9306_repeat_rate_freq[repeat_rate_idx][0];642	*val2 = apds9306_repeat_rate_freq[repeat_rate_idx][1];643 644	return 0;645}646 647static int apds9306_sampling_freq_set(struct apds9306_data *data, int val,648				      int val2)649{650	struct apds9306_regfields *rf = &data->rf;651	int i;652 653	for (i = 0; i < ARRAY_SIZE(apds9306_repeat_rate_freq); i++) {654		if (apds9306_repeat_rate_freq[i][0] == val &&655		    apds9306_repeat_rate_freq[i][1] == val2)656			return regmap_field_write(rf->repeat_rate, i);657	}658 659	return -EINVAL;660}661 662static int apds9306_scale_get(struct apds9306_data *data, int *val, int *val2)663{664	struct apds9306_regfields *rf = &data->rf;665	int gain, intg, ret, intg_time_idx, gain_idx;666 667	ret = regmap_field_read(rf->gain, &gain_idx);668	if (ret)669		return ret;670 671	ret = regmap_field_read(rf->intg_time, &intg_time_idx);672	if (ret)673		return ret;674 675	gain = iio_gts_find_gain_by_sel(&data->gts, gain_idx);676	if (gain < 0)677		return gain;678 679	intg = iio_gts_find_int_time_by_sel(&data->gts, intg_time_idx);680	if (intg < 0)681		return intg;682 683	return iio_gts_get_scale(&data->gts, gain, intg, val, val2);684}685 686static int apds9306_scale_set(struct apds9306_data *data, int val, int val2)687{688	struct apds9306_regfields *rf = &data->rf;689	int i, ret, time_sel, gain_sel, intg_time_idx;690 691	ret = regmap_field_read(rf->intg_time, &intg_time_idx);692	if (ret)693		return ret;694 695	ret = iio_gts_find_gain_sel_for_scale_using_time(&data->gts,696					intg_time_idx, val, val2, &gain_sel);697	if (ret) {698		for (i = 0; i < data->gts.num_itime; i++) {699			time_sel = data->gts.itime_table[i].sel;700 701			if (time_sel == intg_time_idx)702				continue;703 704			ret = iio_gts_find_gain_sel_for_scale_using_time(&data->gts,705						time_sel, val, val2, &gain_sel);706			if (!ret)707				break;708		}709		if (ret)710			return -EINVAL;711 712		ret = regmap_field_write(rf->intg_time, time_sel);713		if (ret)714			return ret;715	}716 717	return regmap_field_write(rf->gain, gain_sel);718}719 720static int apds9306_event_period_get(struct apds9306_data *data, int *val)721{722	struct apds9306_regfields *rf = &data->rf;723	int period, ret;724 725	ret = regmap_field_read(rf->int_persist_val, &period);726	if (ret)727		return ret;728 729	if (!in_range(period, 0, APDS9306_ALS_PERSIST_NUM_VALS))730		return -EINVAL;731 732	*val = period;733 734	return ret;735}736 737static int apds9306_event_period_set(struct apds9306_data *data, int val)738{739	struct apds9306_regfields *rf = &data->rf;740 741	if (!in_range(val, 0, APDS9306_ALS_PERSIST_NUM_VALS))742		return -EINVAL;743 744	return regmap_field_write(rf->int_persist_val, val);745}746 747static int apds9306_event_thresh_get(struct apds9306_data *data, int dir,748				     int *val)749{750	int var, ret;751	u8 buff[3];752 753	if (dir == IIO_EV_DIR_RISING)754		var = APDS9306_ALS_THRES_UP_0_REG;755	else if (dir == IIO_EV_DIR_FALLING)756		var = APDS9306_ALS_THRES_LOW_0_REG;757	else758		return -EINVAL;759 760	ret = regmap_bulk_read(data->regmap, var, buff, sizeof(buff));761	if (ret)762		return ret;763 764	*val = get_unaligned_le24(&buff);765 766	return 0;767}768 769static int apds9306_event_thresh_set(struct apds9306_data *data, int dir,770				     int val)771{772	int var;773	u8 buff[3];774 775	if (dir == IIO_EV_DIR_RISING)776		var = APDS9306_ALS_THRES_UP_0_REG;777	else if (dir == IIO_EV_DIR_FALLING)778		var = APDS9306_ALS_THRES_LOW_0_REG;779	else780		return -EINVAL;781 782	if (!in_range(val, 0, APDS9306_ALS_THRES_VAL_MAX))783		return -EINVAL;784 785	put_unaligned_le24(val, buff);786 787	return regmap_bulk_write(data->regmap, var, buff, sizeof(buff));788}789 790static int apds9306_event_thresh_adaptive_get(struct apds9306_data *data, int *val)791{792	struct apds9306_regfields *rf = &data->rf;793	int thr_adpt, ret;794 795	ret = regmap_field_read(rf->int_thresh_var_val, &thr_adpt);796	if (ret)797		return ret;798 799	if (!in_range(thr_adpt, 0, APDS9306_ALS_THRES_VAR_NUM_VALS))800		return -EINVAL;801 802	*val = thr_adpt;803 804	return ret;805}806 807static int apds9306_event_thresh_adaptive_set(struct apds9306_data *data, int val)808{809	struct apds9306_regfields *rf = &data->rf;810 811	if (!in_range(val, 0, APDS9306_ALS_THRES_VAR_NUM_VALS))812		return -EINVAL;813 814	return regmap_field_write(rf->int_thresh_var_val, val);815}816 817static int apds9306_read_raw(struct iio_dev *indio_dev,818			     struct iio_chan_spec const *chan, int *val,819			     int *val2, long mask)820{821	struct apds9306_data *data = iio_priv(indio_dev);822	int ret, reg;823 824	switch (mask) {825	case IIO_CHAN_INFO_RAW:826		if (chan->channel2 == IIO_MOD_LIGHT_CLEAR)827			reg = APDS9306_CLEAR_DATA_0_REG;828		else829			reg = APDS9306_ALS_DATA_0_REG;830		/*831		 * Changing device parameters during adc operation, resets832		 * the ADC which has to avoided.833		 */834		ret = iio_device_claim_direct_mode(indio_dev);835		if (ret)836			return ret;837		ret = apds9306_read_data(data, val, reg);838		iio_device_release_direct_mode(indio_dev);839		if (ret)840			return ret;841 842		return IIO_VAL_INT;843	case IIO_CHAN_INFO_INT_TIME:844		ret = apds9306_intg_time_get(data, val2);845		if (ret)846			return ret;847		*val = 0;848 849		return IIO_VAL_INT_PLUS_MICRO;850	case IIO_CHAN_INFO_SAMP_FREQ:851		ret = apds9306_sampling_freq_get(data, val, val2);852		if (ret)853			return ret;854 855		return IIO_VAL_INT_PLUS_MICRO;856	case IIO_CHAN_INFO_SCALE:857		ret = apds9306_scale_get(data, val, val2);858		if (ret)859			return ret;860 861		return IIO_VAL_INT_PLUS_NANO;862	default:863		return -EINVAL;864	}865};866 867static int apds9306_read_avail(struct iio_dev *indio_dev,868			       struct iio_chan_spec const *chan,869			       const int **vals, int *type, int *length,870			       long mask)871{872	struct apds9306_data *data = iio_priv(indio_dev);873 874	switch (mask) {875	case IIO_CHAN_INFO_INT_TIME:876		return iio_gts_avail_times(&data->gts, vals, type, length);877	case IIO_CHAN_INFO_SCALE:878		return iio_gts_all_avail_scales(&data->gts, vals, type, length);879	case IIO_CHAN_INFO_SAMP_FREQ:880		*length = ARRAY_SIZE(apds9306_repeat_rate_freq) * 2;881		*vals = (const int *)apds9306_repeat_rate_freq;882		*type = IIO_VAL_INT_PLUS_MICRO;883 884		return IIO_AVAIL_LIST;885	default:886		return -EINVAL;887	}888}889 890static int apds9306_write_raw_get_fmt(struct iio_dev *indio_dev,891				      struct iio_chan_spec const *chan,892				      long mask)893{894	switch (mask) {895	case IIO_CHAN_INFO_SCALE:896		return IIO_VAL_INT_PLUS_NANO;897	case IIO_CHAN_INFO_INT_TIME:898		return IIO_VAL_INT_PLUS_MICRO;899	case IIO_CHAN_INFO_SAMP_FREQ:900		return IIO_VAL_INT_PLUS_MICRO;901	default:902		return -EINVAL;903	}904}905 906static int apds9306_write_raw(struct iio_dev *indio_dev,907			      struct iio_chan_spec const *chan, int val,908			      int val2, long mask)909{910	struct apds9306_data *data = iio_priv(indio_dev);911 912	guard(mutex)(&data->mutex);913 914	switch (mask) {915	case IIO_CHAN_INFO_INT_TIME:916		if (val)917			return -EINVAL;918		return apds9306_intg_time_set(data, val2);919	case IIO_CHAN_INFO_SCALE:920		return apds9306_scale_set(data, val, val2);921	case IIO_CHAN_INFO_SAMP_FREQ:922		return apds9306_sampling_freq_set(data, val, val2);923	default:924		return -EINVAL;925	}926}927 928static irqreturn_t apds9306_irq_handler(int irq, void *priv)929{930	struct iio_dev *indio_dev = priv;931	struct apds9306_data *data = iio_priv(indio_dev);932	struct apds9306_regfields *rf = &data->rf;933	u64 ev_code;934	int ret, status, int_src;935 936	/*937	 * The interrupt line is released and the interrupt flag is938	 * cleared as a result of reading the status register. All the939	 * status flags are cleared as a result of this read.940	 */941	ret = regmap_read(data->regmap, APDS9306_MAIN_STATUS_REG, &status);942	if (ret < 0) {943		dev_err_ratelimited(data->dev, "status reg read failed\n");944		return IRQ_HANDLED;945	}946 947	ret = regmap_field_read(rf->int_src, &int_src);948	if (ret)949		return ret;950 951	if ((status & APDS9306_ALS_INT_STAT_MASK)) {952		if (int_src == APDS9306_INT_SRC_ALS)953			ev_code = IIO_UNMOD_EVENT_CODE(IIO_LIGHT, 0,954						       IIO_EV_TYPE_THRESH,955						       IIO_EV_DIR_EITHER);956		else957			ev_code = IIO_MOD_EVENT_CODE(IIO_INTENSITY, 0,958						     IIO_MOD_LIGHT_CLEAR,959						     IIO_EV_TYPE_THRESH,960						     IIO_EV_DIR_EITHER);961 962		iio_push_event(indio_dev, ev_code, iio_get_time_ns(indio_dev));963	}964 965	/*966	 * If a one-shot read through sysfs is underway at the same time967	 * as this interrupt handler is executing and a read data available968	 * flag was set, this flag is set to inform read_poll_timeout()969	 * to exit.970	 */971	if ((status & APDS9306_ALS_DATA_STAT_MASK))972		data->read_data_available = 1;973 974	return IRQ_HANDLED;975}976 977static int apds9306_read_event(struct iio_dev *indio_dev,978			       const struct iio_chan_spec *chan,979			       enum iio_event_type type,980			       enum iio_event_direction dir,981			       enum iio_event_info info,982			       int *val, int *val2)983{984	struct apds9306_data *data = iio_priv(indio_dev);985	int ret;986 987	switch (type) {988	case IIO_EV_TYPE_THRESH:989		if (dir == IIO_EV_DIR_EITHER && info == IIO_EV_INFO_PERIOD)990			ret = apds9306_event_period_get(data, val);991		else992			ret = apds9306_event_thresh_get(data, dir, val);993		if (ret)994			return ret;995 996		return IIO_VAL_INT;997	case IIO_EV_TYPE_THRESH_ADAPTIVE:998		ret = apds9306_event_thresh_adaptive_get(data, val);999		if (ret)1000			return ret;1001 1002		return IIO_VAL_INT;1003	default:1004		return -EINVAL;1005	}1006}1007 1008static int apds9306_write_event(struct iio_dev *indio_dev,1009				const struct iio_chan_spec *chan,1010				enum iio_event_type type,1011				enum iio_event_direction dir,1012				enum iio_event_info info,1013				int val, int val2)1014{1015	struct apds9306_data *data = iio_priv(indio_dev);1016 1017	switch (type) {1018	case IIO_EV_TYPE_THRESH:1019		if (dir == IIO_EV_DIR_EITHER && info == IIO_EV_INFO_PERIOD)1020			return apds9306_event_period_set(data, val);1021 1022		return apds9306_event_thresh_set(data, dir, val);1023	case IIO_EV_TYPE_THRESH_ADAPTIVE:1024		return apds9306_event_thresh_adaptive_set(data, val);1025	default:1026		return -EINVAL;1027	}1028}1029 1030static int apds9306_read_event_config(struct iio_dev *indio_dev,1031				      const struct iio_chan_spec *chan,1032				      enum iio_event_type type,1033				      enum iio_event_direction dir)1034{1035	struct apds9306_data *data = iio_priv(indio_dev);1036	struct apds9306_regfields *rf = &data->rf;1037	int int_en, int_src, ret;1038 1039	switch (type) {1040	case IIO_EV_TYPE_THRESH: {1041		guard(mutex)(&data->mutex);1042 1043		ret = regmap_field_read(rf->int_src, &int_src);1044		if (ret)1045			return ret;1046 1047		ret = regmap_field_read(rf->int_en, &int_en);1048		if (ret)1049			return ret;1050 1051		if (chan->type == IIO_LIGHT)1052			return int_en && (int_src == APDS9306_INT_SRC_ALS);1053 1054		if (chan->type == IIO_INTENSITY)1055			return int_en && (int_src == APDS9306_INT_SRC_CLEAR);1056 1057		return -EINVAL;1058	}1059	case IIO_EV_TYPE_THRESH_ADAPTIVE:1060		ret = regmap_field_read(rf->int_thresh_var_en, &int_en);1061		if (ret)1062			return ret;1063 1064		return int_en;1065	default:1066		return -EINVAL;1067	}1068}1069 1070static int apds9306_write_event_config(struct iio_dev *indio_dev,1071				       const struct iio_chan_spec *chan,1072				       enum iio_event_type type,1073				       enum iio_event_direction dir,1074				       int state)1075{1076	struct apds9306_data *data = iio_priv(indio_dev);1077	struct apds9306_regfields *rf = &data->rf;1078	int ret, enabled;1079 1080	switch (type) {1081	case IIO_EV_TYPE_THRESH: {1082		guard(mutex)(&data->mutex);1083 1084		ret = regmap_field_read(rf->int_en, &enabled);1085		if (ret)1086			return ret;1087 1088		/*1089		 * If interrupt is enabled, the channel is set before enabling1090		 * the interrupt. In case of disable, no need to switch1091		 * channels. In case of different channel is selected while1092		 * interrupt in on, just change the channel.1093		 */1094		if (state) {1095			if (chan->type == IIO_LIGHT)1096				ret = regmap_field_write(rf->int_src, 1);1097			else if (chan->type == IIO_INTENSITY)1098				ret = regmap_field_write(rf->int_src, 0);1099			else1100				return -EINVAL;1101 1102			if (ret)1103				return ret;1104 1105			if (enabled)1106				return 0;1107 1108			ret = regmap_field_write(rf->int_en, 1);1109			if (ret)1110				return ret;1111 1112			return pm_runtime_resume_and_get(data->dev);1113		} else {1114			if (!enabled)1115				return 0;1116 1117			ret = regmap_field_write(rf->int_en, 0);1118			if (ret)1119				return ret;1120 1121			pm_runtime_mark_last_busy(data->dev);1122			pm_runtime_put_autosuspend(data->dev);1123 1124			return 0;1125		}1126	}1127	case IIO_EV_TYPE_THRESH_ADAPTIVE:1128		if (state)1129			return regmap_field_write(rf->int_thresh_var_en, 1);1130		else1131			return regmap_field_write(rf->int_thresh_var_en, 0);1132	default:1133		return -EINVAL;1134	}1135}1136 1137static const struct iio_info apds9306_info_no_events = {1138	.read_avail = apds9306_read_avail,1139	.read_raw = apds9306_read_raw,1140	.write_raw = apds9306_write_raw,1141	.write_raw_get_fmt = apds9306_write_raw_get_fmt,1142};1143 1144static const struct iio_info apds9306_info = {1145	.read_avail = apds9306_read_avail,1146	.read_raw = apds9306_read_raw,1147	.write_raw = apds9306_write_raw,1148	.write_raw_get_fmt = apds9306_write_raw_get_fmt,1149	.read_event_value = apds9306_read_event,1150	.write_event_value = apds9306_write_event,1151	.read_event_config = apds9306_read_event_config,1152	.write_event_config = apds9306_write_event_config,1153	.event_attrs = &apds9306_event_attr_group,1154};1155 1156static int apds9306_init_iio_gts(struct apds9306_data *data)1157{1158	int i, ret, part_id;1159 1160	ret = regmap_read(data->regmap, APDS9306_PART_ID_REG, &part_id);1161	if (ret)1162		return ret;1163 1164	for (i = 0; i < ARRAY_SIZE(apds9306_gts_mul); i++)1165		if (part_id == apds9306_gts_mul[i].part_id)1166			break;1167 1168	if (i == ARRAY_SIZE(apds9306_gts_mul))1169		return -ENOENT;1170 1171	return devm_iio_init_iio_gts(data->dev,1172				     apds9306_gts_mul[i].max_scale_int,1173				     apds9306_gts_mul[i].max_scale_nano,1174				     apds9306_gains, ARRAY_SIZE(apds9306_gains),1175				     apds9306_itimes, ARRAY_SIZE(apds9306_itimes),1176				     &data->gts);1177}1178 1179static void apds9306_powerdown(void *ptr)1180{1181	struct apds9306_data *data = (struct apds9306_data *)ptr;1182	struct apds9306_regfields *rf = &data->rf;1183	int ret;1184 1185	ret = regmap_field_write(rf->int_thresh_var_en, 0);1186	if (ret)1187		return;1188 1189	ret = regmap_field_write(rf->int_en, 0);1190	if (ret)1191		return;1192 1193	apds9306_power_state(data, false);1194}1195 1196static int apds9306_device_init(struct apds9306_data *data)1197{1198	struct apds9306_regfields *rf = &data->rf;1199	int ret;1200 1201	ret = apds9306_init_iio_gts(data);1202	if (ret)1203		return ret;1204 1205	ret = regmap_field_write(rf->intg_time, APDS9306_MEAS_MODE_100MS);1206	if (ret)1207		return ret;1208 1209	ret = regmap_field_write(rf->repeat_rate, APDS9306_SAMP_FREQ_10HZ);1210	if (ret)1211		return ret;1212 1213	ret = regmap_field_write(rf->gain, APDS9306_GSEL_3X);1214	if (ret)1215		return ret;1216 1217	ret = regmap_field_write(rf->int_src, APDS9306_INT_SRC_ALS);1218	if (ret)1219		return ret;1220 1221	ret = regmap_field_write(rf->int_en, 0);1222	if (ret)1223		return ret;1224 1225	return regmap_field_write(rf->int_thresh_var_en, 0);1226}1227 1228static int apds9306_pm_init(struct apds9306_data *data)1229{1230	struct device *dev = data->dev;1231	int ret;1232 1233	ret = apds9306_power_state(data, true);1234	if (ret)1235		return ret;1236 1237	ret = pm_runtime_set_active(dev);1238	if (ret)1239		return ret;1240 1241	ret = devm_pm_runtime_enable(dev);1242	if (ret)1243		return ret;1244 1245	pm_runtime_set_autosuspend_delay(dev, 5000);1246	pm_runtime_use_autosuspend(dev);1247	pm_runtime_get(dev);1248 1249	return 0;1250}1251 1252static int apds9306_probe(struct i2c_client *client)1253{1254	struct device *dev = &client->dev;1255	struct apds9306_data *data;1256	struct iio_dev *indio_dev;1257	int ret;1258 1259	indio_dev = devm_iio_device_alloc(dev, sizeof(*data));1260	if (!indio_dev)1261		return -ENOMEM;1262 1263	data = iio_priv(indio_dev);1264 1265	mutex_init(&data->mutex);1266 1267	data->regmap = devm_regmap_init_i2c(client, &apds9306_regmap);1268	if (IS_ERR(data->regmap))1269		return dev_err_probe(dev, PTR_ERR(data->regmap),1270				     "regmap initialization failed\n");1271 1272	data->dev = dev;1273	i2c_set_clientdata(client, indio_dev);1274 1275	ret = apds9306_regfield_init(data);1276	if (ret)1277		return dev_err_probe(dev, ret, "regfield initialization failed\n");1278 1279	ret = devm_regulator_get_enable(dev, "vdd");1280	if (ret)1281		return dev_err_probe(dev, ret, "Failed to enable regulator\n");1282 1283	indio_dev->name = "apds9306";1284	indio_dev->modes = INDIO_DIRECT_MODE;1285	if (client->irq) {1286		indio_dev->info = &apds9306_info;1287		indio_dev->channels = apds9306_channels_with_events;1288		indio_dev->num_channels = ARRAY_SIZE(apds9306_channels_with_events);1289		ret = devm_request_threaded_irq(dev, client->irq, NULL,1290						apds9306_irq_handler, IRQF_ONESHOT,1291						"apds9306_event", indio_dev);1292		if (ret)1293			return dev_err_probe(dev, ret,1294					     "failed to assign interrupt.\n");1295	} else {1296		indio_dev->info = &apds9306_info_no_events;1297		indio_dev->channels = apds9306_channels_without_events;1298		indio_dev->num_channels =1299				ARRAY_SIZE(apds9306_channels_without_events);1300	}1301 1302	ret = apds9306_pm_init(data);1303	if (ret)1304		return dev_err_probe(dev, ret, "failed pm init\n");1305 1306	ret = apds9306_device_init(data);1307	if (ret)1308		return dev_err_probe(dev, ret, "failed to init device\n");1309 1310	ret = devm_add_action_or_reset(dev, apds9306_powerdown, data);1311	if (ret)1312		return dev_err_probe(dev, ret, "failed to add action or reset\n");1313 1314	ret = devm_iio_device_register(dev, indio_dev);1315	if (ret)1316		return dev_err_probe(dev, ret, "failed iio device registration\n");1317 1318	pm_runtime_put_autosuspend(dev);1319 1320	return 0;1321}1322 1323static int apds9306_runtime_suspend(struct device *dev)1324{1325	struct apds9306_data *data = iio_priv(dev_get_drvdata(dev));1326 1327	return apds9306_power_state(data, false);1328}1329 1330static int apds9306_runtime_resume(struct device *dev)1331{1332	struct apds9306_data *data = iio_priv(dev_get_drvdata(dev));1333 1334	return apds9306_power_state(data, true);1335}1336 1337static DEFINE_RUNTIME_DEV_PM_OPS(apds9306_pm_ops,1338				 apds9306_runtime_suspend,1339				 apds9306_runtime_resume,1340				 NULL);1341 1342static const struct of_device_id apds9306_of_match[] = {1343	{ .compatible = "avago,apds9306" },1344	{ }1345};1346MODULE_DEVICE_TABLE(of, apds9306_of_match);1347 1348static struct i2c_driver apds9306_driver = {1349	.driver = {1350		.name = "apds9306",1351		.pm = pm_ptr(&apds9306_pm_ops),1352		.of_match_table = apds9306_of_match,1353	},1354	.probe = apds9306_probe,1355};1356module_i2c_driver(apds9306_driver);1357 1358MODULE_AUTHOR("Subhajit Ghosh <subhajit.ghosh@tweaklogic.com>");1359MODULE_DESCRIPTION("APDS9306 Ambient Light Sensor driver");1360MODULE_LICENSE("GPL");1361MODULE_IMPORT_NS(IIO_GTS_HELPER);1362