brintos

brintos / linux-shallow public Read only

0
0
Text · 29.8 KiB · 427c934 Raw
1033 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Copyright 2018 Google LLC.4 *5 * Driver for Semtech's SX9310/SX9311 capacitive proximity/button solution.6 * Based on SX9500 driver and Semtech driver using the input framework7 * <https://my.syncplicity.com/share/teouwsim8niiaud/8 *          linux-driver-SX9310_NoSmartHSensing>.9 * Reworked in April 2019 by Evan Green <evgreen@chromium.org>10 * and in January 2020 by Daniel Campello <campello@chromium.org>.11 */12 13#include <linux/bitfield.h>14#include <linux/delay.h>15#include <linux/i2c.h>16#include <linux/interrupt.h>17#include <linux/kernel.h>18#include <linux/log2.h>19#include <linux/mod_devicetable.h>20#include <linux/module.h>21#include <linux/pm.h>22#include <linux/property.h>23#include <linux/regmap.h>24#include <linux/iio/iio.h>25 26#include "sx_common.h"27 28/* Register definitions. */29#define SX9310_REG_IRQ_SRC				SX_COMMON_REG_IRQ_SRC30#define SX9310_REG_STAT0				0x0131#define SX9310_REG_STAT1				0x0232#define SX9310_REG_STAT1_COMPSTAT_MASK			GENMASK(3, 0)33#define SX9310_REG_IRQ_MSK				0x0334#define   SX9310_CONVDONE_IRQ				BIT(3)35#define   SX9310_FAR_IRQ				BIT(5)36#define   SX9310_CLOSE_IRQ				BIT(6)37#define SX9310_REG_IRQ_FUNC				0x0438 39#define SX9310_REG_PROX_CTRL0				0x1040#define   SX9310_REG_PROX_CTRL0_SENSOREN_MASK		GENMASK(3, 0)41#define   SX9310_REG_PROX_CTRL0_SCANPERIOD_MASK		GENMASK(7, 4)42#define   SX9310_REG_PROX_CTRL0_SCANPERIOD_15MS		0x0143#define SX9310_REG_PROX_CTRL1				0x1144#define SX9310_REG_PROX_CTRL2				0x1245#define   SX9310_REG_PROX_CTRL2_COMBMODE_MASK		GENMASK(7, 6)46#define   SX9310_REG_PROX_CTRL2_COMBMODE_CS0_CS1_CS2_CS3 (0x03 << 6)47#define   SX9310_REG_PROX_CTRL2_COMBMODE_CS1_CS2	(0x02 << 6)48#define   SX9310_REG_PROX_CTRL2_COMBMODE_CS0_CS1	(0x01 << 6)49#define   SX9310_REG_PROX_CTRL2_COMBMODE_CS3		(0x00 << 6)50#define   SX9310_REG_PROX_CTRL2_SHIELDEN_MASK		GENMASK(3, 2)51#define   SX9310_REG_PROX_CTRL2_SHIELDEN_DYNAMIC	(0x01 << 2)52#define   SX9310_REG_PROX_CTRL2_SHIELDEN_GROUND		(0x02 << 2)53#define SX9310_REG_PROX_CTRL3				0x1354#define   SX9310_REG_PROX_CTRL3_GAIN0_MASK		GENMASK(3, 2)55#define   SX9310_REG_PROX_CTRL3_GAIN0_X8		(0x03 << 2)56#define   SX9310_REG_PROX_CTRL3_GAIN12_MASK		GENMASK(1, 0)57#define   SX9310_REG_PROX_CTRL3_GAIN12_X4		0x0258#define SX9310_REG_PROX_CTRL4				0x1459#define   SX9310_REG_PROX_CTRL4_RESOLUTION_MASK		GENMASK(2, 0)60#define   SX9310_REG_PROX_CTRL4_RESOLUTION_FINEST	0x0761#define   SX9310_REG_PROX_CTRL4_RESOLUTION_VERY_FINE	0x0662#define   SX9310_REG_PROX_CTRL4_RESOLUTION_FINE		0x0563#define   SX9310_REG_PROX_CTRL4_RESOLUTION_MEDIUM	0x0464#define   SX9310_REG_PROX_CTRL4_RESOLUTION_MEDIUM_COARSE 0x0365#define   SX9310_REG_PROX_CTRL4_RESOLUTION_COARSE	0x0266#define   SX9310_REG_PROX_CTRL4_RESOLUTION_VERY_COARSE	0x0167#define   SX9310_REG_PROX_CTRL4_RESOLUTION_COARSEST	0x0068#define SX9310_REG_PROX_CTRL5				0x1569#define   SX9310_REG_PROX_CTRL5_RANGE_SMALL		(0x03 << 6)70#define   SX9310_REG_PROX_CTRL5_STARTUPSENS_MASK	GENMASK(3, 2)71#define   SX9310_REG_PROX_CTRL5_STARTUPSENS_CS1		(0x01 << 2)72#define   SX9310_REG_PROX_CTRL5_RAWFILT_MASK		GENMASK(1, 0)73#define   SX9310_REG_PROX_CTRL5_RAWFILT_SHIFT		074#define   SX9310_REG_PROX_CTRL5_RAWFILT_1P25		0x0275#define SX9310_REG_PROX_CTRL6				0x1676#define   SX9310_REG_PROX_CTRL6_AVGTHRESH_DEFAULT	0x2077#define SX9310_REG_PROX_CTRL7				0x1778#define   SX9310_REG_PROX_CTRL7_AVGNEGFILT_2		(0x01 << 3)79#define   SX9310_REG_PROX_CTRL7_AVGPOSFILT_MASK		GENMASK(2, 0)80#define   SX9310_REG_PROX_CTRL7_AVGPOSFILT_SHIFT	081#define   SX9310_REG_PROX_CTRL7_AVGPOSFILT_512		0x0582#define SX9310_REG_PROX_CTRL8				0x1883#define   SX9310_REG_PROX_CTRL8_9_PTHRESH_MASK		GENMASK(7, 3)84#define SX9310_REG_PROX_CTRL9				0x1985#define   SX9310_REG_PROX_CTRL8_9_PTHRESH_28		(0x08 << 3)86#define   SX9310_REG_PROX_CTRL8_9_PTHRESH_96		(0x11 << 3)87#define   SX9310_REG_PROX_CTRL8_9_BODYTHRESH_900	0x0388#define   SX9310_REG_PROX_CTRL8_9_BODYTHRESH_1500	0x0589#define SX9310_REG_PROX_CTRL10				0x1a90#define   SX9310_REG_PROX_CTRL10_HYST_MASK		GENMASK(5, 4)91#define   SX9310_REG_PROX_CTRL10_HYST_6PCT		(0x01 << 4)92#define   SX9310_REG_PROX_CTRL10_CLOSE_DEBOUNCE_MASK	GENMASK(3, 2)93#define   SX9310_REG_PROX_CTRL10_FAR_DEBOUNCE_MASK	GENMASK(1, 0)94#define   SX9310_REG_PROX_CTRL10_FAR_DEBOUNCE_2		0x0195#define SX9310_REG_PROX_CTRL11				0x1b96#define SX9310_REG_PROX_CTRL12				0x1c97#define SX9310_REG_PROX_CTRL13				0x1d98#define SX9310_REG_PROX_CTRL14				0x1e99#define SX9310_REG_PROX_CTRL15				0x1f100#define SX9310_REG_PROX_CTRL16				0x20101#define SX9310_REG_PROX_CTRL17				0x21102#define SX9310_REG_PROX_CTRL18				0x22103#define SX9310_REG_PROX_CTRL19				0x23104#define SX9310_REG_SAR_CTRL0				0x2a105#define   SX9310_REG_SAR_CTRL0_SARDEB_4_SAMPLES		(0x02 << 5)106#define   SX9310_REG_SAR_CTRL0_SARHYST_8		(0x02 << 3)107#define SX9310_REG_SAR_CTRL1				0x2b108/* Each increment of the slope register is 0.0078125. */109#define   SX9310_REG_SAR_CTRL1_SLOPE(_hnslope)		(_hnslope / 78125)110#define SX9310_REG_SAR_CTRL2				0x2c111#define   SX9310_REG_SAR_CTRL2_SAROFFSET_DEFAULT	0x3c112 113#define SX9310_REG_SENSOR_SEL				0x30114#define SX9310_REG_USE_MSB				0x31115#define SX9310_REG_USE_LSB				0x32116#define SX9310_REG_AVG_MSB				0x33117#define SX9310_REG_AVG_LSB				0x34118#define SX9310_REG_DIFF_MSB				0x35119#define SX9310_REG_DIFF_LSB				0x36120#define SX9310_REG_OFFSET_MSB				0x37121#define SX9310_REG_OFFSET_LSB				0x38122#define SX9310_REG_SAR_MSB				0x39123#define SX9310_REG_SAR_LSB				0x3a124#define SX9310_REG_I2C_ADDR				0x40125#define SX9310_REG_PAUSE				0x41126#define SX9310_REG_WHOAMI				0x42127#define   SX9310_WHOAMI_VALUE				0x01128#define   SX9311_WHOAMI_VALUE				0x02129#define SX9310_REG_RESET				0x7f130 131 132/* 4 hardware channels, as defined in STAT0: COMB, CS2, CS1 and CS0. */133#define SX9310_NUM_CHANNELS				4134static_assert(SX9310_NUM_CHANNELS <= SX_COMMON_MAX_NUM_CHANNELS);135 136#define SX9310_NAMED_CHANNEL(idx, name)				 \137{								 \138	.type = IIO_PROXIMITY,					 \139	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |		 \140			      BIT(IIO_CHAN_INFO_HARDWAREGAIN),   \141	.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \142	.info_mask_separate_available =				 \143		BIT(IIO_CHAN_INFO_HARDWAREGAIN),		 \144	.info_mask_shared_by_all_available =			 \145		BIT(IIO_CHAN_INFO_SAMP_FREQ),			 \146	.indexed = 1,						 \147	.channel = idx,						 \148	.extend_name = name,					 \149	.address = SX9310_REG_DIFF_MSB,				 \150	.event_spec = sx_common_events,				 \151	.num_event_specs = ARRAY_SIZE(sx_common_events),	 \152	.scan_index = idx,					 \153	.scan_type = {						 \154		.sign = 's',					 \155		.realbits = 12,					 \156		.storagebits = 16,				 \157		.endianness = IIO_BE,				 \158	},							 \159}160#define SX9310_CHANNEL(idx) SX9310_NAMED_CHANNEL(idx, NULL)161 162struct sx931x_info {163	const char *name;164	unsigned int whoami;165};166 167static const struct iio_chan_spec sx9310_channels[] = {168	SX9310_CHANNEL(0),			/* CS0 */169	SX9310_CHANNEL(1),			/* CS1 */170	SX9310_CHANNEL(2),			/* CS2 */171	SX9310_NAMED_CHANNEL(3, "comb"),	/* COMB */172 173	IIO_CHAN_SOFT_TIMESTAMP(4),174};175 176/*177 * Each entry contains the integer part (val) and the fractional part, in micro178 * seconds. It conforms to the IIO output IIO_VAL_INT_PLUS_MICRO.179 */180static const struct {181	int val;182	int val2;183} sx9310_samp_freq_table[] = {184	{ 500, 0 }, /* 0000: Min (no idle time) */185	{ 66, 666666 }, /* 0001: 15 ms */186	{ 33, 333333 }, /* 0010: 30 ms (Typ.) */187	{ 22, 222222 }, /* 0011: 45 ms */188	{ 16, 666666 }, /* 0100: 60 ms */189	{ 11, 111111 }, /* 0101: 90 ms */190	{ 8, 333333 }, /* 0110: 120 ms */191	{ 5, 0 }, /* 0111: 200 ms */192	{ 2, 500000 }, /* 1000: 400 ms */193	{ 1, 666666 }, /* 1001: 600 ms */194	{ 1, 250000 }, /* 1010: 800 ms */195	{ 1, 0 }, /* 1011: 1 s */196	{ 0, 500000 }, /* 1100: 2 s */197	{ 0, 333333 }, /* 1101: 3 s */198	{ 0, 250000 }, /* 1110: 4 s */199	{ 0, 200000 }, /* 1111: 5 s */200};201static const unsigned int sx9310_scan_period_table[] = {202	2,   15,  30,  45,   60,   90,	 120,  200,203	400, 600, 800, 1000, 2000, 3000, 4000, 5000,204};205 206static const struct regmap_range sx9310_writable_reg_ranges[] = {207	regmap_reg_range(SX9310_REG_IRQ_MSK, SX9310_REG_IRQ_FUNC),208	regmap_reg_range(SX9310_REG_PROX_CTRL0, SX9310_REG_PROX_CTRL19),209	regmap_reg_range(SX9310_REG_SAR_CTRL0, SX9310_REG_SAR_CTRL2),210	regmap_reg_range(SX9310_REG_SENSOR_SEL, SX9310_REG_SENSOR_SEL),211	regmap_reg_range(SX9310_REG_OFFSET_MSB, SX9310_REG_OFFSET_LSB),212	regmap_reg_range(SX9310_REG_PAUSE, SX9310_REG_PAUSE),213	regmap_reg_range(SX9310_REG_RESET, SX9310_REG_RESET),214};215 216static const struct regmap_access_table sx9310_writeable_regs = {217	.yes_ranges = sx9310_writable_reg_ranges,218	.n_yes_ranges = ARRAY_SIZE(sx9310_writable_reg_ranges),219};220 221static const struct regmap_range sx9310_readable_reg_ranges[] = {222	regmap_reg_range(SX9310_REG_IRQ_SRC, SX9310_REG_IRQ_FUNC),223	regmap_reg_range(SX9310_REG_PROX_CTRL0, SX9310_REG_PROX_CTRL19),224	regmap_reg_range(SX9310_REG_SAR_CTRL0, SX9310_REG_SAR_CTRL2),225	regmap_reg_range(SX9310_REG_SENSOR_SEL, SX9310_REG_SAR_LSB),226	regmap_reg_range(SX9310_REG_I2C_ADDR, SX9310_REG_WHOAMI),227	regmap_reg_range(SX9310_REG_RESET, SX9310_REG_RESET),228};229 230static const struct regmap_access_table sx9310_readable_regs = {231	.yes_ranges = sx9310_readable_reg_ranges,232	.n_yes_ranges = ARRAY_SIZE(sx9310_readable_reg_ranges),233};234 235static const struct regmap_range sx9310_volatile_reg_ranges[] = {236	regmap_reg_range(SX9310_REG_IRQ_SRC, SX9310_REG_STAT1),237	regmap_reg_range(SX9310_REG_USE_MSB, SX9310_REG_DIFF_LSB),238	regmap_reg_range(SX9310_REG_SAR_MSB, SX9310_REG_SAR_LSB),239	regmap_reg_range(SX9310_REG_RESET, SX9310_REG_RESET),240};241 242static const struct regmap_access_table sx9310_volatile_regs = {243	.yes_ranges = sx9310_volatile_reg_ranges,244	.n_yes_ranges = ARRAY_SIZE(sx9310_volatile_reg_ranges),245};246 247static const struct regmap_config sx9310_regmap_config = {248	.reg_bits = 8,249	.val_bits = 8,250 251	.max_register = SX9310_REG_RESET,252	.cache_type = REGCACHE_RBTREE,253 254	.wr_table = &sx9310_writeable_regs,255	.rd_table = &sx9310_readable_regs,256	.volatile_table = &sx9310_volatile_regs,257};258 259static int sx9310_read_prox_data(struct sx_common_data *data,260				 const struct iio_chan_spec *chan, __be16 *val)261{262	int ret;263 264	ret = regmap_write(data->regmap, SX9310_REG_SENSOR_SEL, chan->channel);265	if (ret)266		return ret;267 268	return regmap_bulk_read(data->regmap, chan->address, val, sizeof(*val));269}270 271/*272 * If we have no interrupt support, we have to wait for a scan period273 * after enabling a channel to get a result.274 */275static int sx9310_wait_for_sample(struct sx_common_data *data)276{277	int ret;278	unsigned int val;279 280	ret = regmap_read(data->regmap, SX9310_REG_PROX_CTRL0, &val);281	if (ret)282		return ret;283 284	val = FIELD_GET(SX9310_REG_PROX_CTRL0_SCANPERIOD_MASK, val);285 286	msleep(sx9310_scan_period_table[val]);287 288	return 0;289}290 291static int sx9310_read_gain(struct sx_common_data *data,292			    const struct iio_chan_spec *chan, int *val)293{294	unsigned int regval, gain;295	int ret;296 297	ret = regmap_read(data->regmap, SX9310_REG_PROX_CTRL3, &regval);298	if (ret)299		return ret;300 301	switch (chan->channel) {302	case 0:303	case 3:304		gain = FIELD_GET(SX9310_REG_PROX_CTRL3_GAIN0_MASK, regval);305		break;306	case 1:307	case 2:308		gain = FIELD_GET(SX9310_REG_PROX_CTRL3_GAIN12_MASK, regval);309		break;310	default:311		return -EINVAL;312	}313 314	*val = 1 << gain;315 316	return IIO_VAL_INT;317}318 319static int sx9310_read_samp_freq(struct sx_common_data *data, int *val, int *val2)320{321	unsigned int regval;322	int ret;323 324	ret = regmap_read(data->regmap, SX9310_REG_PROX_CTRL0, &regval);325	if (ret)326		return ret;327 328	regval = FIELD_GET(SX9310_REG_PROX_CTRL0_SCANPERIOD_MASK, regval);329	*val = sx9310_samp_freq_table[regval].val;330	*val2 = sx9310_samp_freq_table[regval].val2;331 332	return IIO_VAL_INT_PLUS_MICRO;333}334 335static int sx9310_read_raw(struct iio_dev *indio_dev,336			   const struct iio_chan_spec *chan, int *val,337			   int *val2, long mask)338{339	struct sx_common_data *data = iio_priv(indio_dev);340 341	if (chan->type != IIO_PROXIMITY)342		return -EINVAL;343 344	switch (mask) {345	case IIO_CHAN_INFO_RAW:346		iio_device_claim_direct_scoped(return -EBUSY, indio_dev)347			return sx_common_read_proximity(data, chan, val);348		unreachable();349	case IIO_CHAN_INFO_HARDWAREGAIN:350		iio_device_claim_direct_scoped(return -EBUSY, indio_dev)351			return sx9310_read_gain(data, chan, val);352		unreachable();353	case IIO_CHAN_INFO_SAMP_FREQ:354		return sx9310_read_samp_freq(data, val, val2);355	default:356		return -EINVAL;357	}358}359 360static const int sx9310_gain_vals[] = { 1, 2, 4, 8 };361 362static int sx9310_read_avail(struct iio_dev *indio_dev,363			     struct iio_chan_spec const *chan,364			     const int **vals, int *type, int *length,365			     long mask)366{367	if (chan->type != IIO_PROXIMITY)368		return -EINVAL;369 370	switch (mask) {371	case IIO_CHAN_INFO_HARDWAREGAIN:372		*type = IIO_VAL_INT;373		*length = ARRAY_SIZE(sx9310_gain_vals);374		*vals = sx9310_gain_vals;375		return IIO_AVAIL_LIST;376	case IIO_CHAN_INFO_SAMP_FREQ:377		*type = IIO_VAL_INT_PLUS_MICRO;378		*length = ARRAY_SIZE(sx9310_samp_freq_table) * 2;379		*vals = (int *)sx9310_samp_freq_table;380		return IIO_AVAIL_LIST;381	default:382		return -EINVAL;383	}384}385 386static const unsigned int sx9310_pthresh_codes[] = {387	2, 4, 6, 8, 12, 16, 20, 24, 28, 32, 40, 48, 56, 64, 72, 80, 88, 96, 112,388	128, 144, 160, 192, 224, 256, 320, 384, 512, 640, 768, 1024, 1536389};390 391static int sx9310_get_thresh_reg(unsigned int channel)392{393	switch (channel) {394	case 0:395	case 3:396		return SX9310_REG_PROX_CTRL8;397	case 1:398	case 2:399		return SX9310_REG_PROX_CTRL9;400	default:401		return -EINVAL;402	}403}404 405static int sx9310_read_thresh(struct sx_common_data *data,406			      const struct iio_chan_spec *chan, int *val)407{408	unsigned int reg;409	unsigned int regval;410	int ret;411 412	reg = ret = sx9310_get_thresh_reg(chan->channel);413	if (ret < 0)414		return ret;415 416	ret = regmap_read(data->regmap, reg, &regval);417	if (ret)418		return ret;419 420	regval = FIELD_GET(SX9310_REG_PROX_CTRL8_9_PTHRESH_MASK, regval);421	if (regval >= ARRAY_SIZE(sx9310_pthresh_codes))422		return -EINVAL;423 424	*val = sx9310_pthresh_codes[regval];425	return IIO_VAL_INT;426}427 428static int sx9310_read_hysteresis(struct sx_common_data *data,429				  const struct iio_chan_spec *chan, int *val)430{431	unsigned int regval, pthresh;432	int ret;433 434	ret = sx9310_read_thresh(data, chan, &pthresh);435	if (ret < 0)436		return ret;437 438	ret = regmap_read(data->regmap, SX9310_REG_PROX_CTRL10, &regval);439	if (ret)440		return ret;441 442	regval = FIELD_GET(SX9310_REG_PROX_CTRL10_HYST_MASK, regval);443	if (!regval)444		regval = 5;445 446	/* regval is at most 5 */447	*val = pthresh >> (5 - regval);448 449	return IIO_VAL_INT;450}451 452static int sx9310_read_far_debounce(struct sx_common_data *data, int *val)453{454	unsigned int regval;455	int ret;456 457	ret = regmap_read(data->regmap, SX9310_REG_PROX_CTRL10, &regval);458	if (ret)459		return ret;460 461	regval = FIELD_GET(SX9310_REG_PROX_CTRL10_FAR_DEBOUNCE_MASK, regval);462	if (regval)463		*val = 1 << regval;464	else465		*val = 0;466 467	return IIO_VAL_INT;468}469 470static int sx9310_read_close_debounce(struct sx_common_data *data, int *val)471{472	unsigned int regval;473	int ret;474 475	ret = regmap_read(data->regmap, SX9310_REG_PROX_CTRL10, &regval);476	if (ret)477		return ret;478 479	regval = FIELD_GET(SX9310_REG_PROX_CTRL10_CLOSE_DEBOUNCE_MASK, regval);480	if (regval)481		*val = 1 << regval;482	else483		*val = 0;484 485	return IIO_VAL_INT;486}487 488static int sx9310_read_event_val(struct iio_dev *indio_dev,489				 const struct iio_chan_spec *chan,490				 enum iio_event_type type,491				 enum iio_event_direction dir,492				 enum iio_event_info info, int *val, int *val2)493{494	struct sx_common_data *data = iio_priv(indio_dev);495 496	if (chan->type != IIO_PROXIMITY)497		return -EINVAL;498 499	switch (info) {500	case IIO_EV_INFO_VALUE:501		return sx9310_read_thresh(data, chan, val);502	case IIO_EV_INFO_PERIOD:503		switch (dir) {504		case IIO_EV_DIR_RISING:505			return sx9310_read_far_debounce(data, val);506		case IIO_EV_DIR_FALLING:507			return sx9310_read_close_debounce(data, val);508		default:509			return -EINVAL;510		}511	case IIO_EV_INFO_HYSTERESIS:512		return sx9310_read_hysteresis(data, chan, val);513	default:514		return -EINVAL;515	}516}517 518static int sx9310_write_thresh(struct sx_common_data *data,519			       const struct iio_chan_spec *chan, int val)520{521	unsigned int reg;522	unsigned int regval;523	int ret, i;524 525	reg = ret = sx9310_get_thresh_reg(chan->channel);526	if (ret < 0)527		return ret;528 529	for (i = 0; i < ARRAY_SIZE(sx9310_pthresh_codes); i++) {530		if (sx9310_pthresh_codes[i] == val) {531			regval = i;532			break;533		}534	}535 536	if (i == ARRAY_SIZE(sx9310_pthresh_codes))537		return -EINVAL;538 539	regval = FIELD_PREP(SX9310_REG_PROX_CTRL8_9_PTHRESH_MASK, regval);540 541	guard(mutex)(&data->mutex);542	return regmap_update_bits(data->regmap, reg,543				  SX9310_REG_PROX_CTRL8_9_PTHRESH_MASK, regval);544}545 546static int sx9310_write_hysteresis(struct sx_common_data *data,547				   const struct iio_chan_spec *chan, int _val)548{549	unsigned int hyst, val = _val;550	int ret, pthresh;551 552	ret = sx9310_read_thresh(data, chan, &pthresh);553	if (ret < 0)554		return ret;555 556	if (val == 0)557		hyst = 0;558	else if (val == pthresh >> 2)559		hyst = 3;560	else if (val == pthresh >> 3)561		hyst = 2;562	else if (val == pthresh >> 4)563		hyst = 1;564	else565		return -EINVAL;566 567	hyst = FIELD_PREP(SX9310_REG_PROX_CTRL10_HYST_MASK, hyst);568 569	guard(mutex)(&data->mutex);570	return regmap_update_bits(data->regmap, SX9310_REG_PROX_CTRL10,571				  SX9310_REG_PROX_CTRL10_HYST_MASK, hyst);572}573 574static int sx9310_write_far_debounce(struct sx_common_data *data, int val)575{576	unsigned int regval;577 578	if (val > 0)579		val = ilog2(val);580	if (!FIELD_FIT(SX9310_REG_PROX_CTRL10_FAR_DEBOUNCE_MASK, val))581		return -EINVAL;582 583	regval = FIELD_PREP(SX9310_REG_PROX_CTRL10_FAR_DEBOUNCE_MASK, val);584 585	guard(mutex)(&data->mutex);586	return regmap_update_bits(data->regmap, SX9310_REG_PROX_CTRL10,587				  SX9310_REG_PROX_CTRL10_FAR_DEBOUNCE_MASK,588				  regval);589}590 591static int sx9310_write_close_debounce(struct sx_common_data *data, int val)592{593	unsigned int regval;594 595	if (val > 0)596		val = ilog2(val);597	if (!FIELD_FIT(SX9310_REG_PROX_CTRL10_CLOSE_DEBOUNCE_MASK, val))598		return -EINVAL;599 600	regval = FIELD_PREP(SX9310_REG_PROX_CTRL10_CLOSE_DEBOUNCE_MASK, val);601 602	guard(mutex)(&data->mutex);603	return regmap_update_bits(data->regmap, SX9310_REG_PROX_CTRL10,604				  SX9310_REG_PROX_CTRL10_CLOSE_DEBOUNCE_MASK,605				  regval);606}607 608static int sx9310_write_event_val(struct iio_dev *indio_dev,609				  const struct iio_chan_spec *chan,610				  enum iio_event_type type,611				  enum iio_event_direction dir,612				  enum iio_event_info info, int val, int val2)613{614	struct sx_common_data *data = iio_priv(indio_dev);615 616	if (chan->type != IIO_PROXIMITY)617		return -EINVAL;618 619	switch (info) {620	case IIO_EV_INFO_VALUE:621		return sx9310_write_thresh(data, chan, val);622	case IIO_EV_INFO_PERIOD:623		switch (dir) {624		case IIO_EV_DIR_RISING:625			return sx9310_write_far_debounce(data, val);626		case IIO_EV_DIR_FALLING:627			return sx9310_write_close_debounce(data, val);628		default:629			return -EINVAL;630		}631	case IIO_EV_INFO_HYSTERESIS:632		return sx9310_write_hysteresis(data, chan, val);633	default:634		return -EINVAL;635	}636}637 638static int sx9310_set_samp_freq(struct sx_common_data *data, int val, int val2)639{640	int i;641 642	for (i = 0; i < ARRAY_SIZE(sx9310_samp_freq_table); i++)643		if (val == sx9310_samp_freq_table[i].val &&644		    val2 == sx9310_samp_freq_table[i].val2)645			break;646 647	if (i == ARRAY_SIZE(sx9310_samp_freq_table))648		return -EINVAL;649 650	guard(mutex)(&data->mutex);651	return regmap_update_bits(652		data->regmap, SX9310_REG_PROX_CTRL0,653		SX9310_REG_PROX_CTRL0_SCANPERIOD_MASK,654		FIELD_PREP(SX9310_REG_PROX_CTRL0_SCANPERIOD_MASK, i));655}656 657static int sx9310_write_gain(struct sx_common_data *data,658			     const struct iio_chan_spec *chan, int val)659{660	unsigned int gain, mask;661 662	gain = ilog2(val);663 664	switch (chan->channel) {665	case 0:666	case 3:667		mask = SX9310_REG_PROX_CTRL3_GAIN0_MASK;668		gain = FIELD_PREP(SX9310_REG_PROX_CTRL3_GAIN0_MASK, gain);669		break;670	case 1:671	case 2:672		mask = SX9310_REG_PROX_CTRL3_GAIN12_MASK;673		gain = FIELD_PREP(SX9310_REG_PROX_CTRL3_GAIN12_MASK, gain);674		break;675	default:676		return -EINVAL;677	}678 679	guard(mutex)(&data->mutex);680	return regmap_update_bits(data->regmap, SX9310_REG_PROX_CTRL3, mask,681				  gain);682}683 684static int sx9310_write_raw(struct iio_dev *indio_dev,685			    const struct iio_chan_spec *chan, int val, int val2,686			    long mask)687{688	struct sx_common_data *data = iio_priv(indio_dev);689 690	if (chan->type != IIO_PROXIMITY)691		return -EINVAL;692 693	switch (mask) {694	case IIO_CHAN_INFO_SAMP_FREQ:695		return sx9310_set_samp_freq(data, val, val2);696	case IIO_CHAN_INFO_HARDWAREGAIN:697		return sx9310_write_gain(data, chan, val);698	default:699		return -EINVAL;700	}701}702 703static const struct sx_common_reg_default sx9310_default_regs[] = {704	{ SX9310_REG_IRQ_MSK, 0x00 },705	{ SX9310_REG_IRQ_FUNC, 0x00 },706	/*707	 * The lower 4 bits should not be set as it enable sensors measurements.708	 * Turning the detection on before the configuration values are set to709	 * good values can cause the device to return erroneous readings.710	 */711	{ SX9310_REG_PROX_CTRL0, SX9310_REG_PROX_CTRL0_SCANPERIOD_15MS },712	{ SX9310_REG_PROX_CTRL1, 0x00 },713	{ SX9310_REG_PROX_CTRL2, SX9310_REG_PROX_CTRL2_COMBMODE_CS1_CS2 |714				 SX9310_REG_PROX_CTRL2_SHIELDEN_DYNAMIC },715	{ SX9310_REG_PROX_CTRL3, SX9310_REG_PROX_CTRL3_GAIN0_X8 |716				 SX9310_REG_PROX_CTRL3_GAIN12_X4 },717	{ SX9310_REG_PROX_CTRL4, SX9310_REG_PROX_CTRL4_RESOLUTION_FINEST },718	{ SX9310_REG_PROX_CTRL5, SX9310_REG_PROX_CTRL5_RANGE_SMALL |719				 SX9310_REG_PROX_CTRL5_STARTUPSENS_CS1 |720				 SX9310_REG_PROX_CTRL5_RAWFILT_1P25 },721	{ SX9310_REG_PROX_CTRL6, SX9310_REG_PROX_CTRL6_AVGTHRESH_DEFAULT },722	{ SX9310_REG_PROX_CTRL7, SX9310_REG_PROX_CTRL7_AVGNEGFILT_2 |723				 SX9310_REG_PROX_CTRL7_AVGPOSFILT_512 },724	{ SX9310_REG_PROX_CTRL8, SX9310_REG_PROX_CTRL8_9_PTHRESH_96 |725				 SX9310_REG_PROX_CTRL8_9_BODYTHRESH_1500 },726	{ SX9310_REG_PROX_CTRL9, SX9310_REG_PROX_CTRL8_9_PTHRESH_28 |727				 SX9310_REG_PROX_CTRL8_9_BODYTHRESH_900 },728	{ SX9310_REG_PROX_CTRL10, SX9310_REG_PROX_CTRL10_HYST_6PCT |729				  SX9310_REG_PROX_CTRL10_FAR_DEBOUNCE_2 },730	{ SX9310_REG_PROX_CTRL11, 0x00 },731	{ SX9310_REG_PROX_CTRL12, 0x00 },732	{ SX9310_REG_PROX_CTRL13, 0x00 },733	{ SX9310_REG_PROX_CTRL14, 0x00 },734	{ SX9310_REG_PROX_CTRL15, 0x00 },735	{ SX9310_REG_PROX_CTRL16, 0x00 },736	{ SX9310_REG_PROX_CTRL17, 0x00 },737	{ SX9310_REG_PROX_CTRL18, 0x00 },738	{ SX9310_REG_PROX_CTRL19, 0x00 },739	{ SX9310_REG_SAR_CTRL0, SX9310_REG_SAR_CTRL0_SARDEB_4_SAMPLES |740				SX9310_REG_SAR_CTRL0_SARHYST_8 },741	{ SX9310_REG_SAR_CTRL1, SX9310_REG_SAR_CTRL1_SLOPE(10781250) },742	{ SX9310_REG_SAR_CTRL2, SX9310_REG_SAR_CTRL2_SAROFFSET_DEFAULT },743};744 745/* Activate all channels and perform an initial compensation. */746static int sx9310_init_compensation(struct iio_dev *indio_dev)747{748	struct sx_common_data *data = iio_priv(indio_dev);749	int ret;750	unsigned int val;751	unsigned int ctrl0;752 753	ret = regmap_read(data->regmap, SX9310_REG_PROX_CTRL0, &ctrl0);754	if (ret)755		return ret;756 757	/* run the compensation phase on all channels */758	ret = regmap_write(data->regmap, SX9310_REG_PROX_CTRL0,759			   ctrl0 | SX9310_REG_PROX_CTRL0_SENSOREN_MASK);760	if (ret)761		return ret;762 763	ret = regmap_read_poll_timeout(data->regmap, SX9310_REG_STAT1, val,764				       !(val & SX9310_REG_STAT1_COMPSTAT_MASK),765				       20000, 2000000);766	if (ret)767		return ret;768 769	regmap_write(data->regmap, SX9310_REG_PROX_CTRL0, ctrl0);770	return ret;771}772 773static const struct sx_common_reg_default *774sx9310_get_default_reg(struct device *dev, int idx,775		       struct sx_common_reg_default *reg_def)776{777	u32 combined[SX9310_NUM_CHANNELS];778	u32 start = 0, raw = 0, pos = 0;779	unsigned long comb_mask = 0;780	int ret, i, count;781	const char *res;782 783	memcpy(reg_def, &sx9310_default_regs[idx], sizeof(*reg_def));784	switch (reg_def->reg) {785	case SX9310_REG_PROX_CTRL2:786		if (device_property_read_bool(dev, "semtech,cs0-ground")) {787			reg_def->def &= ~SX9310_REG_PROX_CTRL2_SHIELDEN_MASK;788			reg_def->def |= SX9310_REG_PROX_CTRL2_SHIELDEN_GROUND;789		}790 791		count = device_property_count_u32(dev, "semtech,combined-sensors");792		if (count < 0 || count > ARRAY_SIZE(combined))793			break;794		ret = device_property_read_u32_array(dev, "semtech,combined-sensors",795				combined, count);796		if (ret)797			break;798 799		for (i = 0; i < count; i++)800			comb_mask |= BIT(combined[i]);801 802		reg_def->def &= ~SX9310_REG_PROX_CTRL2_COMBMODE_MASK;803		if (comb_mask == (BIT(3) | BIT(2) | BIT(1) | BIT(0)))804			reg_def->def |= SX9310_REG_PROX_CTRL2_COMBMODE_CS0_CS1_CS2_CS3;805		else if (comb_mask == (BIT(1) | BIT(2)))806			reg_def->def |= SX9310_REG_PROX_CTRL2_COMBMODE_CS1_CS2;807		else if (comb_mask == (BIT(0) | BIT(1)))808			reg_def->def |= SX9310_REG_PROX_CTRL2_COMBMODE_CS0_CS1;809		else if (comb_mask == BIT(3))810			reg_def->def |= SX9310_REG_PROX_CTRL2_COMBMODE_CS3;811 812		break;813	case SX9310_REG_PROX_CTRL4:814		ret = device_property_read_string(dev, "semtech,resolution", &res);815		if (ret)816			break;817 818		reg_def->def &= ~SX9310_REG_PROX_CTRL4_RESOLUTION_MASK;819		if (!strcmp(res, "coarsest"))820			reg_def->def |= SX9310_REG_PROX_CTRL4_RESOLUTION_COARSEST;821		else if (!strcmp(res, "very-coarse"))822			reg_def->def |= SX9310_REG_PROX_CTRL4_RESOLUTION_VERY_COARSE;823		else if (!strcmp(res, "coarse"))824			reg_def->def |= SX9310_REG_PROX_CTRL4_RESOLUTION_COARSE;825		else if (!strcmp(res, "medium-coarse"))826			reg_def->def |= SX9310_REG_PROX_CTRL4_RESOLUTION_MEDIUM_COARSE;827		else if (!strcmp(res, "medium"))828			reg_def->def |= SX9310_REG_PROX_CTRL4_RESOLUTION_MEDIUM;829		else if (!strcmp(res, "fine"))830			reg_def->def |= SX9310_REG_PROX_CTRL4_RESOLUTION_FINE;831		else if (!strcmp(res, "very-fine"))832			reg_def->def |= SX9310_REG_PROX_CTRL4_RESOLUTION_VERY_FINE;833		else if (!strcmp(res, "finest"))834			reg_def->def |= SX9310_REG_PROX_CTRL4_RESOLUTION_FINEST;835 836		break;837	case SX9310_REG_PROX_CTRL5:838		ret = device_property_read_u32(dev, "semtech,startup-sensor", &start);839		if (ret) {840			start = FIELD_GET(SX9310_REG_PROX_CTRL5_STARTUPSENS_MASK,841					  reg_def->def);842		}843 844		reg_def->def &= ~SX9310_REG_PROX_CTRL5_STARTUPSENS_MASK;845		reg_def->def |= FIELD_PREP(SX9310_REG_PROX_CTRL5_STARTUPSENS_MASK,846					   start);847 848		ret = device_property_read_u32(dev, "semtech,proxraw-strength", &raw);849		if (ret) {850			raw = FIELD_GET(SX9310_REG_PROX_CTRL5_RAWFILT_MASK,851					reg_def->def);852		} else {853			raw = ilog2(raw);854		}855 856		reg_def->def &= ~SX9310_REG_PROX_CTRL5_RAWFILT_MASK;857		reg_def->def |= FIELD_PREP(SX9310_REG_PROX_CTRL5_RAWFILT_MASK,858					   raw);859		break;860	case SX9310_REG_PROX_CTRL7:861		ret = device_property_read_u32(dev, "semtech,avg-pos-strength", &pos);862		if (ret)863			break;864 865		/* Powers of 2, except for a gap between 16 and 64 */866		pos = clamp(ilog2(pos), 3, 11) - (pos >= 32 ? 4 : 3);867		reg_def->def &= ~SX9310_REG_PROX_CTRL7_AVGPOSFILT_MASK;868		reg_def->def |= FIELD_PREP(SX9310_REG_PROX_CTRL7_AVGPOSFILT_MASK,869					   pos);870		break;871	}872 873	return reg_def;874}875 876static int sx9310_check_whoami(struct device *dev,877			       struct iio_dev *indio_dev)878{879	struct sx_common_data *data = iio_priv(indio_dev);880	const struct sx931x_info *ddata;881	unsigned int whoami;882	int ret;883 884	ret = regmap_read(data->regmap, SX9310_REG_WHOAMI, &whoami);885	if (ret)886		return ret;887 888	ddata = device_get_match_data(dev);889	if (ddata->whoami != whoami)890		return -ENODEV;891 892	indio_dev->name = ddata->name;893 894	return 0;895}896 897static const struct sx_common_chip_info sx9310_chip_info = {898	.reg_stat = SX9310_REG_STAT0,899	.reg_irq_msk = SX9310_REG_IRQ_MSK,900	.reg_enable_chan = SX9310_REG_PROX_CTRL0,901	.reg_reset = SX9310_REG_RESET,902 903	.mask_enable_chan = SX9310_REG_STAT1_COMPSTAT_MASK,904	.irq_msk_offset = 3,905	.num_channels = SX9310_NUM_CHANNELS,906	.num_default_regs = ARRAY_SIZE(sx9310_default_regs),907 908	.ops = {909		.read_prox_data = sx9310_read_prox_data,910		.check_whoami = sx9310_check_whoami,911		.init_compensation = sx9310_init_compensation,912		.wait_for_sample = sx9310_wait_for_sample,913		.get_default_reg = sx9310_get_default_reg,914	},915 916	.iio_channels = sx9310_channels,917	.num_iio_channels = ARRAY_SIZE(sx9310_channels),918	.iio_info =  {919		.read_raw = sx9310_read_raw,920		.read_avail = sx9310_read_avail,921		.read_event_value = sx9310_read_event_val,922		.write_event_value = sx9310_write_event_val,923		.write_raw = sx9310_write_raw,924		.read_event_config = sx_common_read_event_config,925		.write_event_config = sx_common_write_event_config,926	},927};928 929static int sx9310_probe(struct i2c_client *client)930{931	return sx_common_probe(client, &sx9310_chip_info, &sx9310_regmap_config);932}933 934static int sx9310_suspend(struct device *dev)935{936	struct sx_common_data *data = iio_priv(dev_get_drvdata(dev));937	u8 ctrl0;938	int ret;939 940	disable_irq_nosync(data->client->irq);941 942	guard(mutex)(&data->mutex);943	ret = regmap_read(data->regmap, SX9310_REG_PROX_CTRL0,944			  &data->suspend_ctrl);945	if (ret)946		return ret;947 948	ctrl0 = data->suspend_ctrl & ~SX9310_REG_PROX_CTRL0_SENSOREN_MASK;949	ret = regmap_write(data->regmap, SX9310_REG_PROX_CTRL0, ctrl0);950	if (ret)951		return ret;952 953	return regmap_write(data->regmap, SX9310_REG_PAUSE, 0);954}955 956static int sx9310_resume(struct device *dev)957{958	struct sx_common_data *data = iio_priv(dev_get_drvdata(dev));959	int ret;960 961	scoped_guard(mutex, &data->mutex) {962		ret = regmap_write(data->regmap, SX9310_REG_PAUSE, 1);963		if (ret)964			return ret;965 966		ret = regmap_write(data->regmap, SX9310_REG_PROX_CTRL0,967				   data->suspend_ctrl);968		if (ret)969			return ret;970	}971 972	enable_irq(data->client->irq);973	return 0;974}975 976static DEFINE_SIMPLE_DEV_PM_OPS(sx9310_pm_ops, sx9310_suspend, sx9310_resume);977 978static const struct sx931x_info sx9310_info = {979	.name = "sx9310",980	.whoami = SX9310_WHOAMI_VALUE,981};982 983static const struct sx931x_info sx9311_info = {984	.name = "sx9311",985	.whoami = SX9311_WHOAMI_VALUE,986};987 988static const struct acpi_device_id sx9310_acpi_match[] = {989	{ "STH9310", (kernel_ulong_t)&sx9310_info },990	{ "STH9311", (kernel_ulong_t)&sx9311_info },991	{}992};993MODULE_DEVICE_TABLE(acpi, sx9310_acpi_match);994 995static const struct of_device_id sx9310_of_match[] = {996	{ .compatible = "semtech,sx9310", &sx9310_info },997	{ .compatible = "semtech,sx9311", &sx9311_info },998	{}999};1000MODULE_DEVICE_TABLE(of, sx9310_of_match);1001 1002static const struct i2c_device_id sx9310_id[] = {1003	{ "sx9310", (kernel_ulong_t)&sx9310_info },1004	{ "sx9311", (kernel_ulong_t)&sx9311_info },1005	{}1006};1007MODULE_DEVICE_TABLE(i2c, sx9310_id);1008 1009static struct i2c_driver sx9310_driver = {1010	.driver = {1011		.name	= "sx9310",1012		.acpi_match_table = sx9310_acpi_match,1013		.of_match_table = sx9310_of_match,1014		.pm = pm_sleep_ptr(&sx9310_pm_ops),1015 1016		/*1017		 * Lots of i2c transfers in probe + over 200 ms waiting in1018		 * sx9310_init_compensation() mean a slow probe; prefer async1019		 * so we don't delay boot if we're builtin to the kernel.1020		 */1021		.probe_type = PROBE_PREFER_ASYNCHRONOUS,1022	},1023	.probe		= sx9310_probe,1024	.id_table	= sx9310_id,1025};1026module_i2c_driver(sx9310_driver);1027 1028MODULE_AUTHOR("Gwendal Grignou <gwendal@chromium.org>");1029MODULE_AUTHOR("Daniel Campello <campello@chromium.org>");1030MODULE_DESCRIPTION("Driver for Semtech SX9310/SX9311 proximity sensor");1031MODULE_LICENSE("GPL v2");1032MODULE_IMPORT_NS(SEMTECH_PROX);1033