brintos

brintos / linux-shallow public Read only

0
0
Text · 24.3 KiB · 2b90bf4 Raw
870 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Copyright 2021 Google LLC.4 *5 * Driver for Semtech's SX9360 capacitive proximity/button solution.6 * Based on SX9360 driver and copy of datasheet at:7 * https://edit.wpgdadawant.com/uploads/news_file/program/2019/30184/tech_files/program_30184_suggest_other_file.pdf8 */9 10#include <linux/acpi.h>11#include <linux/bits.h>12#include <linux/bitfield.h>13#include <linux/delay.h>14#include <linux/i2c.h>15#include <linux/interrupt.h>16#include <linux/kernel.h>17#include <linux/log2.h>18#include <linux/mod_devicetable.h>19#include <linux/module.h>20#include <linux/pm.h>21#include <linux/property.h>22#include <linux/regmap.h>23 24#include <linux/iio/iio.h>25 26#include "sx_common.h"27 28/* Nominal Oscillator Frequency. */29#define SX9360_FOSC_MHZ			430#define SX9360_FOSC_HZ			(SX9360_FOSC_MHZ * 1000000)31 32/* Register definitions. */33#define SX9360_REG_IRQ_SRC		SX_COMMON_REG_IRQ_SRC34#define SX9360_REG_STAT		0x0135#define SX9360_REG_STAT_COMPSTAT_MASK	GENMASK(2, 1)36#define SX9360_REG_IRQ_MSK		0x0237#define SX9360_CONVDONE_IRQ		BIT(0)38#define SX9360_FAR_IRQ			BIT(2)39#define SX9360_CLOSE_IRQ		BIT(3)40#define SX9360_REG_IRQ_CFG		0x0341 42#define SX9360_REG_GNRL_CTRL0		0x1043#define SX9360_REG_GNRL_CTRL0_PHEN_MASK GENMASK(1, 0)44#define SX9360_REG_GNRL_CTRL1		0x1145#define SX9360_REG_GNRL_CTRL1_SCANPERIOD_MASK GENMASK(2, 0)46#define SX9360_REG_GNRL_CTRL2		0x1247#define SX9360_REG_GNRL_CTRL2_PERIOD_102MS	0x3248#define SX9360_REG_GNRL_REG_2_PERIOD_MS(_r)	\49	(((_r) * 8192) / (SX9360_FOSC_HZ / 1000))50#define SX9360_REG_GNRL_FREQ_2_REG(_f)  (((_f) * 8192) / SX9360_FOSC_HZ)51#define SX9360_REG_GNRL_REG_2_FREQ(_r)  (SX9360_FOSC_HZ / ((_r) * 8192))52 53#define SX9360_REG_AFE_CTRL1		0x2154#define SX9360_REG_AFE_CTRL1_RESFILTIN_MASK GENMASK(3, 0)55#define SX9360_REG_AFE_CTRL1_RESFILTIN_0OHMS 056#define SX9360_REG_AFE_PARAM0_PHR	0x2257#define SX9360_REG_AFE_PARAM1_PHR	0x2358#define SX9360_REG_AFE_PARAM0_PHM	0x2459#define SX9360_REG_AFE_PARAM0_RSVD		0x0860#define SX9360_REG_AFE_PARAM0_RESOLUTION_MASK	GENMASK(2, 0)61#define SX9360_REG_AFE_PARAM0_RESOLUTION_128	0x0262#define SX9360_REG_AFE_PARAM1_PHM	0x2563#define SX9360_REG_AFE_PARAM1_AGAIN_PHM_6PF	0x4064#define SX9360_REG_AFE_PARAM1_FREQ_83_33HZ	0x0665 66#define SX9360_REG_PROX_CTRL0_PHR	0x4067#define SX9360_REG_PROX_CTRL0_PHM	0x4168#define SX9360_REG_PROX_CTRL0_GAIN_MASK	GENMASK(5, 3)69#define SX9360_REG_PROX_CTRL0_GAIN_1		0x8070#define SX9360_REG_PROX_CTRL0_RAWFILT_MASK	GENMASK(2, 0)71#define SX9360_REG_PROX_CTRL0_RAWFILT_1P50	0x0172#define SX9360_REG_PROX_CTRL1		0x4273#define SX9360_REG_PROX_CTRL1_AVGNEG_THRESH_MASK	GENMASK(5, 3)74#define SX9360_REG_PROX_CTRL1_AVGNEG_THRESH_16K 0x2075#define SX9360_REG_PROX_CTRL2		0x4376#define SX9360_REG_PROX_CTRL2_AVGDEB_MASK	GENMASK(7, 6)77#define SX9360_REG_PROX_CTRL2_AVGDEB_2SAMPLES	0x4078#define SX9360_REG_PROX_CTRL2_AVGPOS_THRESH_16K	0x2079#define SX9360_REG_PROX_CTRL3		0x4480#define SX9360_REG_PROX_CTRL3_AVGNEG_FILT_MASK	GENMASK(5, 3)81#define SX9360_REG_PROX_CTRL3_AVGNEG_FILT_2	0x0882#define SX9360_REG_PROX_CTRL3_AVGPOS_FILT_MASK	GENMASK(2, 0)83#define SX9360_REG_PROX_CTRL3_AVGPOS_FILT_256	0x0484#define SX9360_REG_PROX_CTRL4		0x4585#define SX9360_REG_PROX_CTRL4_HYST_MASK			GENMASK(5, 4)86#define SX9360_REG_PROX_CTRL4_CLOSE_DEBOUNCE_MASK	GENMASK(3, 2)87#define SX9360_REG_PROX_CTRL4_FAR_DEBOUNCE_MASK		GENMASK(1, 0)88#define SX9360_REG_PROX_CTRL5		0x4689#define SX9360_REG_PROX_CTRL5_PROXTHRESH_32	0x0890 91#define SX9360_REG_REF_CORR0		0x6092#define SX9360_REG_REF_CORR1		0x6193 94#define SX9360_REG_USEFUL_PHR_MSB		0x9095#define SX9360_REG_USEFUL_PHR_LSB		0x9196 97#define SX9360_REG_OFFSET_PMR_MSB		0x9298#define SX9360_REG_OFFSET_PMR_LSB		0x9399 100#define SX9360_REG_USEFUL_PHM_MSB		0x94101#define SX9360_REG_USEFUL_PHM_LSB		0x95102 103#define SX9360_REG_AVG_PHM_MSB		0x96104#define SX9360_REG_AVG_PHM_LSB		0x97105 106#define SX9360_REG_DIFF_PHM_MSB		0x98107#define SX9360_REG_DIFF_PHM_LSB		0x99108 109#define SX9360_REG_OFFSET_PHM_MSB		0x9a110#define SX9360_REG_OFFSET_PHM_LSB		0x9b111 112#define SX9360_REG_USE_FILTER_MSB		0x9a113#define SX9360_REG_USE_FILTER_LSB		0x9b114 115#define SX9360_REG_RESET		0xcf116/* Write this to REG_RESET to do a soft reset. */117#define SX9360_SOFT_RESET		0xde118 119#define SX9360_REG_WHOAMI		0xfa120#define   SX9360_WHOAMI_VALUE				0x60121 122#define SX9360_REG_REVISION		0xfe123 124/* 2 channels, Phase Reference and Measurement. */125#define SX9360_NUM_CHANNELS		2126 127static const struct iio_chan_spec sx9360_channels[] = {128	{129		.type = IIO_PROXIMITY,130		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |131				      BIT(IIO_CHAN_INFO_HARDWAREGAIN),132		.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),133		.info_mask_separate_available =134			BIT(IIO_CHAN_INFO_HARDWAREGAIN),135		.info_mask_shared_by_all_available =136			BIT(IIO_CHAN_INFO_SAMP_FREQ),137		.indexed = 1,138		.address = SX9360_REG_USEFUL_PHR_MSB,139		.channel = 0,140		.scan_index = 0,141		.scan_type = {142			.sign = 's',143			.realbits = 12,144			.storagebits = 16,145			.endianness = IIO_BE,146		},147	},148	{149		.type = IIO_PROXIMITY,150		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |151				      BIT(IIO_CHAN_INFO_HARDWAREGAIN),152		.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),153		.info_mask_separate_available =154			BIT(IIO_CHAN_INFO_HARDWAREGAIN),155		.info_mask_shared_by_all_available =156			BIT(IIO_CHAN_INFO_SAMP_FREQ),157		.indexed = 1,158		.address = SX9360_REG_USEFUL_PHM_MSB,159		.event_spec = sx_common_events,160		.num_event_specs = ARRAY_SIZE(sx_common_events),161		.channel = 1,162		.scan_index = 1,163		.scan_type = {164			.sign = 's',165			.realbits = 12,166			.storagebits = 16,167			.endianness = IIO_BE,168		},169	},170	IIO_CHAN_SOFT_TIMESTAMP(2),171};172 173/*174 * Each entry contains the integer part (val) and the fractional part, in micro175 * seconds. It conforms to the IIO output IIO_VAL_INT_PLUS_MICRO.176 *177 * The frequency control register holds the period, with a ~2ms increment.178 * Therefore the smallest frequency is 4MHz / (2047 * 8192),179 * The fastest is 4MHz / 8192.180 * The interval is not linear, but given there is 2047 possible value,181 * Returns the fake increment of (Max-Min)/2047182 */183static const struct {184	int val;185	int val2;186} sx9360_samp_freq_interval[] = {187	{ 0, 281250 },  /* 4MHz / (8192 * 2047) */188	{ 0, 281250 },189	{ 448, 281250 },  /* 4MHz / 8192 */190};191 192static const struct regmap_range sx9360_writable_reg_ranges[] = {193	/*194	 * To set COMPSTAT for compensation, even if datasheet says register is195	 * RO.196	 */197	regmap_reg_range(SX9360_REG_STAT, SX9360_REG_IRQ_CFG),198	regmap_reg_range(SX9360_REG_GNRL_CTRL0, SX9360_REG_GNRL_CTRL2),199	regmap_reg_range(SX9360_REG_AFE_CTRL1, SX9360_REG_AFE_PARAM1_PHM),200	regmap_reg_range(SX9360_REG_PROX_CTRL0_PHR, SX9360_REG_PROX_CTRL5),201	regmap_reg_range(SX9360_REG_REF_CORR0, SX9360_REG_REF_CORR1),202	regmap_reg_range(SX9360_REG_OFFSET_PMR_MSB, SX9360_REG_OFFSET_PMR_LSB),203	regmap_reg_range(SX9360_REG_RESET, SX9360_REG_RESET),204};205 206static const struct regmap_access_table sx9360_writeable_regs = {207	.yes_ranges = sx9360_writable_reg_ranges,208	.n_yes_ranges = ARRAY_SIZE(sx9360_writable_reg_ranges),209};210 211/*212 * All allocated registers are readable, so we just list unallocated213 * ones.214 */215static const struct regmap_range sx9360_non_readable_reg_ranges[] = {216	regmap_reg_range(SX9360_REG_IRQ_CFG + 1, SX9360_REG_GNRL_CTRL0 - 1),217	regmap_reg_range(SX9360_REG_GNRL_CTRL2 + 1, SX9360_REG_AFE_CTRL1 - 1),218	regmap_reg_range(SX9360_REG_AFE_PARAM1_PHM + 1,219			 SX9360_REG_PROX_CTRL0_PHR - 1),220	regmap_reg_range(SX9360_REG_PROX_CTRL5 + 1, SX9360_REG_REF_CORR0 - 1),221	regmap_reg_range(SX9360_REG_REF_CORR1 + 1,222			 SX9360_REG_USEFUL_PHR_MSB - 1),223	regmap_reg_range(SX9360_REG_USE_FILTER_LSB + 1, SX9360_REG_RESET - 1),224	regmap_reg_range(SX9360_REG_RESET + 1, SX9360_REG_WHOAMI - 1),225	regmap_reg_range(SX9360_REG_WHOAMI + 1, SX9360_REG_REVISION - 1),226};227 228static const struct regmap_access_table sx9360_readable_regs = {229	.no_ranges = sx9360_non_readable_reg_ranges,230	.n_no_ranges = ARRAY_SIZE(sx9360_non_readable_reg_ranges),231};232 233static const struct regmap_range sx9360_volatile_reg_ranges[] = {234	regmap_reg_range(SX9360_REG_IRQ_SRC, SX9360_REG_STAT),235	regmap_reg_range(SX9360_REG_USEFUL_PHR_MSB, SX9360_REG_USE_FILTER_LSB),236	regmap_reg_range(SX9360_REG_WHOAMI, SX9360_REG_WHOAMI),237	regmap_reg_range(SX9360_REG_REVISION, SX9360_REG_REVISION),238};239 240static const struct regmap_access_table sx9360_volatile_regs = {241	.yes_ranges = sx9360_volatile_reg_ranges,242	.n_yes_ranges = ARRAY_SIZE(sx9360_volatile_reg_ranges),243};244 245static const struct regmap_config sx9360_regmap_config = {246	.reg_bits = 8,247	.val_bits = 8,248 249	.max_register = SX9360_REG_REVISION,250	.cache_type = REGCACHE_RBTREE,251 252	.wr_table = &sx9360_writeable_regs,253	.rd_table = &sx9360_readable_regs,254	.volatile_table = &sx9360_volatile_regs,255};256 257static int sx9360_read_prox_data(struct sx_common_data *data,258				 const struct iio_chan_spec *chan,259				 __be16 *val)260{261	return regmap_bulk_read(data->regmap, chan->address, val, sizeof(*val));262}263 264/*265 * If we have no interrupt support, we have to wait for a scan period266 * after enabling a channel to get a result.267 */268static int sx9360_wait_for_sample(struct sx_common_data *data)269{270	int ret;271	__be16 buf;272 273	ret = regmap_bulk_read(data->regmap, SX9360_REG_GNRL_CTRL1,274			       &buf, sizeof(buf));275	if (ret < 0)276		return ret;277	msleep(SX9360_REG_GNRL_REG_2_PERIOD_MS(be16_to_cpu(buf)));278 279	return 0;280}281 282static int sx9360_read_gain(struct sx_common_data *data,283			    const struct iio_chan_spec *chan, int *val)284{285	unsigned int reg, regval;286	int ret;287 288	reg = SX9360_REG_PROX_CTRL0_PHR + chan->channel;289	ret = regmap_read(data->regmap, reg, &regval);290	if (ret)291		return ret;292 293	*val = 1 << FIELD_GET(SX9360_REG_PROX_CTRL0_GAIN_MASK, regval);294 295	return IIO_VAL_INT;296}297 298static int sx9360_read_samp_freq(struct sx_common_data *data,299				 int *val, int *val2)300{301	int ret, divisor;302	__be16 buf;303 304	ret = regmap_bulk_read(data->regmap, SX9360_REG_GNRL_CTRL1,305			       &buf, sizeof(buf));306	if (ret < 0)307		return ret;308	divisor = be16_to_cpu(buf);309	if (divisor == 0) {310		*val = 0;311		return IIO_VAL_INT;312	}313 314	*val = SX9360_FOSC_HZ;315	*val2 = divisor * 8192;316 317	return IIO_VAL_FRACTIONAL;318}319 320static int sx9360_read_raw(struct iio_dev *indio_dev,321			   const struct iio_chan_spec *chan,322			   int *val, int *val2, long mask)323{324	struct sx_common_data *data = iio_priv(indio_dev);325 326	switch (mask) {327	case IIO_CHAN_INFO_RAW:328		iio_device_claim_direct_scoped(return -EBUSY, indio_dev)329			return sx_common_read_proximity(data, chan, val);330		unreachable();331	case IIO_CHAN_INFO_HARDWAREGAIN:332		iio_device_claim_direct_scoped(return -EBUSY, indio_dev)333			return sx9360_read_gain(data, chan, val);334		unreachable();335	case IIO_CHAN_INFO_SAMP_FREQ:336		return sx9360_read_samp_freq(data, val, val2);337	default:338		return -EINVAL;339	}340}341 342static const char *sx9360_channel_labels[SX9360_NUM_CHANNELS] = {343	"reference", "main",344};345 346static int sx9360_read_label(struct iio_dev *iio_dev, const struct iio_chan_spec *chan,347			     char *label)348{349	return sysfs_emit(label, "%s\n", sx9360_channel_labels[chan->channel]);350}351 352static const int sx9360_gain_vals[] = { 1, 2, 4, 8 };353 354static int sx9360_read_avail(struct iio_dev *indio_dev,355			     struct iio_chan_spec const *chan,356			     const int **vals, int *type, int *length,357			     long mask)358{359	if (chan->type != IIO_PROXIMITY)360		return -EINVAL;361 362	switch (mask) {363	case IIO_CHAN_INFO_HARDWAREGAIN:364		*type = IIO_VAL_INT;365		*length = ARRAY_SIZE(sx9360_gain_vals);366		*vals = sx9360_gain_vals;367		return IIO_AVAIL_LIST;368	case IIO_CHAN_INFO_SAMP_FREQ:369		*type = IIO_VAL_INT_PLUS_MICRO;370		*length = ARRAY_SIZE(sx9360_samp_freq_interval) * 2;371		*vals = (int *)sx9360_samp_freq_interval;372		return IIO_AVAIL_RANGE;373	default:374		return -EINVAL;375	}376}377 378static int sx9360_set_samp_freq(struct sx_common_data *data,379				int val, int val2)380{381	int reg;382	__be16 buf;383 384	reg = val * 8192 / SX9360_FOSC_HZ + val2 * 8192 / (SX9360_FOSC_MHZ);385	buf = cpu_to_be16(reg);386	guard(mutex)(&data->mutex);387 388	return regmap_bulk_write(data->regmap, SX9360_REG_GNRL_CTRL1, &buf,389				 sizeof(buf));390}391 392static int sx9360_read_thresh(struct sx_common_data *data, int *val)393{394	unsigned int regval;395	int ret;396 397	ret = regmap_read(data->regmap, SX9360_REG_PROX_CTRL5, &regval);398	if (ret)399		return ret;400 401	if (regval <= 1)402		*val = regval;403	else404		*val = (regval * regval) / 2;405 406	return IIO_VAL_INT;407}408 409static int sx9360_read_hysteresis(struct sx_common_data *data, int *val)410{411	unsigned int regval, pthresh;412	int ret;413 414	ret = sx9360_read_thresh(data, &pthresh);415	if (ret < 0)416		return ret;417 418	ret = regmap_read(data->regmap, SX9360_REG_PROX_CTRL4, &regval);419	if (ret)420		return ret;421 422	regval = FIELD_GET(SX9360_REG_PROX_CTRL4_HYST_MASK, regval);423	if (!regval)424		*val = 0;425	else426		*val = pthresh >> (5 - regval);427 428	return IIO_VAL_INT;429}430 431static int sx9360_read_far_debounce(struct sx_common_data *data, int *val)432{433	unsigned int regval;434	int ret;435 436	ret = regmap_read(data->regmap, SX9360_REG_PROX_CTRL4, &regval);437	if (ret)438		return ret;439 440	regval = FIELD_GET(SX9360_REG_PROX_CTRL4_FAR_DEBOUNCE_MASK, regval);441	if (regval)442		*val = 1 << regval;443	else444		*val = 0;445 446	return IIO_VAL_INT;447}448 449static int sx9360_read_close_debounce(struct sx_common_data *data, int *val)450{451	unsigned int regval;452	int ret;453 454	ret = regmap_read(data->regmap, SX9360_REG_PROX_CTRL4, &regval);455	if (ret)456		return ret;457 458	regval = FIELD_GET(SX9360_REG_PROX_CTRL4_CLOSE_DEBOUNCE_MASK, regval);459	if (regval)460		*val = 1 << regval;461	else462		*val = 0;463 464	return IIO_VAL_INT;465}466 467static int sx9360_read_event_val(struct iio_dev *indio_dev,468				 const struct iio_chan_spec *chan,469				 enum iio_event_type type,470				 enum iio_event_direction dir,471				 enum iio_event_info info, int *val, int *val2)472{473	struct sx_common_data *data = iio_priv(indio_dev);474 475	if (chan->type != IIO_PROXIMITY)476		return -EINVAL;477 478	switch (info) {479	case IIO_EV_INFO_VALUE:480		return sx9360_read_thresh(data, val);481	case IIO_EV_INFO_PERIOD:482		switch (dir) {483		case IIO_EV_DIR_RISING:484			return sx9360_read_far_debounce(data, val);485		case IIO_EV_DIR_FALLING:486			return sx9360_read_close_debounce(data, val);487		default:488			return -EINVAL;489		}490	case IIO_EV_INFO_HYSTERESIS:491		return sx9360_read_hysteresis(data, val);492	default:493		return -EINVAL;494	}495}496 497static int sx9360_write_thresh(struct sx_common_data *data, int _val)498{499	unsigned int val = _val;500 501	if (val >= 1)502		val = int_sqrt(2 * val);503 504	if (val > 0xff)505		return -EINVAL;506 507	guard(mutex)(&data->mutex);508	return regmap_write(data->regmap, SX9360_REG_PROX_CTRL5, val);509}510 511static int sx9360_write_hysteresis(struct sx_common_data *data, int _val)512{513	unsigned int hyst, val = _val;514	int ret, pthresh;515 516	ret = sx9360_read_thresh(data, &pthresh);517	if (ret < 0)518		return ret;519 520	if (val == 0)521		hyst = 0;522	else if (val >= pthresh >> 2)523		hyst = 3;524	else if (val >= pthresh >> 3)525		hyst = 2;526	else if (val >= pthresh >> 4)527		hyst = 1;528	else529		return -EINVAL;530 531	hyst = FIELD_PREP(SX9360_REG_PROX_CTRL4_HYST_MASK, hyst);532	guard(mutex)(&data->mutex);533	return regmap_update_bits(data->regmap, SX9360_REG_PROX_CTRL4,534				  SX9360_REG_PROX_CTRL4_HYST_MASK, hyst);535}536 537static int sx9360_write_far_debounce(struct sx_common_data *data, int _val)538{539	unsigned int regval, val = _val;540 541	if (val > 0)542		val = ilog2(val);543	if (!FIELD_FIT(SX9360_REG_PROX_CTRL4_FAR_DEBOUNCE_MASK, val))544		return -EINVAL;545 546	regval = FIELD_PREP(SX9360_REG_PROX_CTRL4_FAR_DEBOUNCE_MASK, val);547 548	guard(mutex)(&data->mutex);549	return regmap_update_bits(data->regmap, SX9360_REG_PROX_CTRL4,550				  SX9360_REG_PROX_CTRL4_FAR_DEBOUNCE_MASK,551				  regval);552}553 554static int sx9360_write_close_debounce(struct sx_common_data *data, int _val)555{556	unsigned int regval, val = _val;557 558	if (val > 0)559		val = ilog2(val);560	if (!FIELD_FIT(SX9360_REG_PROX_CTRL4_CLOSE_DEBOUNCE_MASK, val))561		return -EINVAL;562 563	regval = FIELD_PREP(SX9360_REG_PROX_CTRL4_CLOSE_DEBOUNCE_MASK, val);564 565	guard(mutex)(&data->mutex);566	return regmap_update_bits(data->regmap, SX9360_REG_PROX_CTRL4,567				  SX9360_REG_PROX_CTRL4_CLOSE_DEBOUNCE_MASK,568				  regval);569}570 571static int sx9360_write_event_val(struct iio_dev *indio_dev,572				  const struct iio_chan_spec *chan,573				  enum iio_event_type type,574				  enum iio_event_direction dir,575				  enum iio_event_info info, int val, int val2)576{577	struct sx_common_data *data = iio_priv(indio_dev);578 579	if (chan->type != IIO_PROXIMITY)580		return -EINVAL;581 582	switch (info) {583	case IIO_EV_INFO_VALUE:584		return sx9360_write_thresh(data, val);585	case IIO_EV_INFO_PERIOD:586		switch (dir) {587		case IIO_EV_DIR_RISING:588			return sx9360_write_far_debounce(data, val);589		case IIO_EV_DIR_FALLING:590			return sx9360_write_close_debounce(data, val);591		default:592			return -EINVAL;593		}594	case IIO_EV_INFO_HYSTERESIS:595		return sx9360_write_hysteresis(data, val);596	default:597		return -EINVAL;598	}599}600 601static int sx9360_write_gain(struct sx_common_data *data,602			     const struct iio_chan_spec *chan, int val)603{604	unsigned int gain, reg;605 606	gain = ilog2(val);607	reg = SX9360_REG_PROX_CTRL0_PHR + chan->channel;608	gain = FIELD_PREP(SX9360_REG_PROX_CTRL0_GAIN_MASK, gain);609 610	guard(mutex)(&data->mutex);611	return regmap_update_bits(data->regmap, reg,612				  SX9360_REG_PROX_CTRL0_GAIN_MASK,613				  gain);614}615 616static int sx9360_write_raw(struct iio_dev *indio_dev,617			    const struct iio_chan_spec *chan, int val, int val2,618			    long mask)619{620	struct sx_common_data *data = iio_priv(indio_dev);621 622	switch (mask) {623	case IIO_CHAN_INFO_SAMP_FREQ:624		return sx9360_set_samp_freq(data, val, val2);625	case IIO_CHAN_INFO_HARDWAREGAIN:626		return sx9360_write_gain(data, chan, val);627	default:628		return -EINVAL;629	}630}631 632static const struct sx_common_reg_default sx9360_default_regs[] = {633	{ SX9360_REG_IRQ_MSK, 0x00 },634	{ SX9360_REG_IRQ_CFG, 0x00, "irq_cfg" },635	/*636	 * The lower 2 bits should not be set as it enable sensors measurements.637	 * Turning the detection on before the configuration values are set to638	 * good values can cause the device to return erroneous readings.639	 */640	{ SX9360_REG_GNRL_CTRL0, 0x00, "gnrl_ctrl0" },641	{ SX9360_REG_GNRL_CTRL1, 0x00, "gnrl_ctrl1" },642	{ SX9360_REG_GNRL_CTRL2, SX9360_REG_GNRL_CTRL2_PERIOD_102MS, "gnrl_ctrl2" },643 644	{ SX9360_REG_AFE_CTRL1, SX9360_REG_AFE_CTRL1_RESFILTIN_0OHMS, "afe_ctrl0" },645	{ SX9360_REG_AFE_PARAM0_PHR, SX9360_REG_AFE_PARAM0_RSVD |646		SX9360_REG_AFE_PARAM0_RESOLUTION_128, "afe_param0_phr" },647	{ SX9360_REG_AFE_PARAM1_PHR, SX9360_REG_AFE_PARAM1_AGAIN_PHM_6PF |648		SX9360_REG_AFE_PARAM1_FREQ_83_33HZ, "afe_param1_phr" },649	{ SX9360_REG_AFE_PARAM0_PHM, SX9360_REG_AFE_PARAM0_RSVD |650		SX9360_REG_AFE_PARAM0_RESOLUTION_128, "afe_param0_phm" },651	{ SX9360_REG_AFE_PARAM1_PHM, SX9360_REG_AFE_PARAM1_AGAIN_PHM_6PF |652		SX9360_REG_AFE_PARAM1_FREQ_83_33HZ, "afe_param1_phm" },653 654	{ SX9360_REG_PROX_CTRL0_PHR, SX9360_REG_PROX_CTRL0_GAIN_1 |655		SX9360_REG_PROX_CTRL0_RAWFILT_1P50, "prox_ctrl0_phr" },656	{ SX9360_REG_PROX_CTRL0_PHM, SX9360_REG_PROX_CTRL0_GAIN_1 |657		SX9360_REG_PROX_CTRL0_RAWFILT_1P50, "prox_ctrl0_phm" },658	{ SX9360_REG_PROX_CTRL1, SX9360_REG_PROX_CTRL1_AVGNEG_THRESH_16K, "prox_ctrl1" },659	{ SX9360_REG_PROX_CTRL2, SX9360_REG_PROX_CTRL2_AVGDEB_2SAMPLES |660		SX9360_REG_PROX_CTRL2_AVGPOS_THRESH_16K, "prox_ctrl2" },661	{ SX9360_REG_PROX_CTRL3, SX9360_REG_PROX_CTRL3_AVGNEG_FILT_2 |662		SX9360_REG_PROX_CTRL3_AVGPOS_FILT_256, "prox_ctrl3" },663	{ SX9360_REG_PROX_CTRL4, 0x00, "prox_ctrl4" },664	{ SX9360_REG_PROX_CTRL5, SX9360_REG_PROX_CTRL5_PROXTHRESH_32, "prox_ctrl5" },665};666 667/* Activate all channels and perform an initial compensation. */668static int sx9360_init_compensation(struct iio_dev *indio_dev)669{670	struct sx_common_data *data = iio_priv(indio_dev);671	unsigned int val;672	int ret;673 674	/* run the compensation phase on all channels */675	ret = regmap_set_bits(data->regmap, SX9360_REG_STAT,676			      SX9360_REG_STAT_COMPSTAT_MASK);677	if (ret)678		return ret;679 680	return regmap_read_poll_timeout(data->regmap, SX9360_REG_STAT, val,681				       !(val & SX9360_REG_STAT_COMPSTAT_MASK),682				       20000, 2000000);683}684 685static const struct sx_common_reg_default *686sx9360_get_default_reg(struct device *dev, int idx,687		       struct sx_common_reg_default *reg_def)688{689	u32 raw = 0, pos = 0;690	int ret;691 692	memcpy(reg_def, &sx9360_default_regs[idx], sizeof(*reg_def));693	switch (reg_def->reg) {694	case SX9360_REG_AFE_CTRL1:695		ret = device_property_read_u32(dev,696				"semtech,input-precharge-resistor-ohms",697				&raw);698		if (ret)699			break;700 701		reg_def->def &= ~SX9360_REG_AFE_CTRL1_RESFILTIN_MASK;702		reg_def->def |= FIELD_PREP(SX9360_REG_AFE_CTRL1_RESFILTIN_MASK,703					   raw / 2000);704		break;705	case SX9360_REG_AFE_PARAM0_PHR:706	case SX9360_REG_AFE_PARAM0_PHM:707		ret = device_property_read_u32(dev, "semtech,resolution", &raw);708		if (ret)709			break;710 711		raw = ilog2(raw) - 3;712 713		reg_def->def &= ~SX9360_REG_AFE_PARAM0_RESOLUTION_MASK;714		reg_def->def |= FIELD_PREP(SX9360_REG_AFE_PARAM0_RESOLUTION_MASK, raw);715		break;716	case SX9360_REG_PROX_CTRL0_PHR:717	case SX9360_REG_PROX_CTRL0_PHM:718		ret = device_property_read_u32(dev, "semtech,proxraw-strength", &raw);719		if (ret)720			break;721 722		reg_def->def &= ~SX9360_REG_PROX_CTRL0_RAWFILT_MASK;723		reg_def->def |= FIELD_PREP(SX9360_REG_PROX_CTRL0_RAWFILT_MASK, raw);724		break;725	case SX9360_REG_PROX_CTRL3:726		ret = device_property_read_u32(dev, "semtech,avg-pos-strength",727					       &pos);728		if (ret)729			break;730 731		/* Powers of 2, except for a gap between 16 and 64 */732		raw = clamp(ilog2(pos), 3, 11) - (pos >= 32 ? 4 : 3);733		reg_def->def &= ~SX9360_REG_PROX_CTRL3_AVGPOS_FILT_MASK;734		reg_def->def |= FIELD_PREP(SX9360_REG_PROX_CTRL3_AVGPOS_FILT_MASK, raw);735		break;736	}737 738	return reg_def;739}740 741static int sx9360_check_whoami(struct device *dev, struct iio_dev *indio_dev)742{743	/*744	 * Only one sensor for this driver. Assuming the device tree745	 * is correct, just set the sensor name.746	 */747	indio_dev->name = "sx9360";748	return 0;749}750 751static const struct sx_common_chip_info sx9360_chip_info = {752	.reg_stat = SX9360_REG_STAT,753	.reg_irq_msk = SX9360_REG_IRQ_MSK,754	.reg_enable_chan = SX9360_REG_GNRL_CTRL0,755	.reg_reset = SX9360_REG_RESET,756 757	.mask_enable_chan = SX9360_REG_GNRL_CTRL0_PHEN_MASK,758	.stat_offset = 2,759	.num_channels = SX9360_NUM_CHANNELS,760	.num_default_regs = ARRAY_SIZE(sx9360_default_regs),761 762	.ops = {763		.read_prox_data = sx9360_read_prox_data,764		.check_whoami = sx9360_check_whoami,765		.init_compensation = sx9360_init_compensation,766		.wait_for_sample = sx9360_wait_for_sample,767		.get_default_reg = sx9360_get_default_reg,768	},769 770	.iio_channels = sx9360_channels,771	.num_iio_channels = ARRAY_SIZE(sx9360_channels),772	.iio_info =  {773		.read_raw = sx9360_read_raw,774		.read_avail = sx9360_read_avail,775		.read_label = sx9360_read_label,776		.read_event_value = sx9360_read_event_val,777		.write_event_value = sx9360_write_event_val,778		.write_raw = sx9360_write_raw,779		.read_event_config = sx_common_read_event_config,780		.write_event_config = sx_common_write_event_config,781	},782};783 784static int sx9360_probe(struct i2c_client *client)785{786	return sx_common_probe(client, &sx9360_chip_info, &sx9360_regmap_config);787}788 789static int sx9360_suspend(struct device *dev)790{791	struct sx_common_data *data = iio_priv(dev_get_drvdata(dev));792	unsigned int regval;793	int ret;794 795	disable_irq_nosync(data->client->irq);796 797	guard(mutex)(&data->mutex);798	ret = regmap_read(data->regmap, SX9360_REG_GNRL_CTRL0, &regval);799	if (ret < 0)800		return ret;801 802	data->suspend_ctrl =803		FIELD_GET(SX9360_REG_GNRL_CTRL0_PHEN_MASK, regval);804 805 806	/* Disable all phases, send the device to sleep. */807	return regmap_write(data->regmap, SX9360_REG_GNRL_CTRL0, 0);808}809 810static int sx9360_resume(struct device *dev)811{812	struct sx_common_data *data = iio_priv(dev_get_drvdata(dev));813 814	scoped_guard(mutex, &data->mutex) {815		int ret = regmap_update_bits(data->regmap,816					     SX9360_REG_GNRL_CTRL0,817					     SX9360_REG_GNRL_CTRL0_PHEN_MASK,818					     data->suspend_ctrl);819		if (ret)820			return ret;821	}822	enable_irq(data->client->irq);823	return 0;824}825 826static DEFINE_SIMPLE_DEV_PM_OPS(sx9360_pm_ops, sx9360_suspend, sx9360_resume);827 828static const struct acpi_device_id sx9360_acpi_match[] = {829	{ "STH9360", SX9360_WHOAMI_VALUE },830	{ "SAMM0208", SX9360_WHOAMI_VALUE },831	{ }832};833MODULE_DEVICE_TABLE(acpi, sx9360_acpi_match);834 835static const struct of_device_id sx9360_of_match[] = {836	{ .compatible = "semtech,sx9360", (void *)SX9360_WHOAMI_VALUE },837	{ }838};839MODULE_DEVICE_TABLE(of, sx9360_of_match);840 841static const struct i2c_device_id sx9360_id[] = {842	{"sx9360", SX9360_WHOAMI_VALUE },843	{ }844};845MODULE_DEVICE_TABLE(i2c, sx9360_id);846 847static struct i2c_driver sx9360_driver = {848	.driver = {849		.name	= "sx9360",850		.acpi_match_table = sx9360_acpi_match,851		.of_match_table = sx9360_of_match,852		.pm = pm_sleep_ptr(&sx9360_pm_ops),853 854		/*855		 * Lots of i2c transfers in probe + over 200 ms waiting in856		 * sx9360_init_compensation() mean a slow probe; prefer async857		 * so we don't delay boot if we're builtin to the kernel.858		 */859		.probe_type = PROBE_PREFER_ASYNCHRONOUS,860	},861	.probe		= sx9360_probe,862	.id_table	= sx9360_id,863};864module_i2c_driver(sx9360_driver);865 866MODULE_AUTHOR("Gwendal Grignou <gwendal@chromium.org>");867MODULE_DESCRIPTION("Driver for Semtech SX9360 proximity sensor");868MODULE_LICENSE("GPL v2");869MODULE_IMPORT_NS(SEMTECH_PROX);870