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, ®val);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, ®val);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, ®val);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, ®val);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, ®val);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, ®val);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