18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (c) 2014 Intel Corporation 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Driver for Semtech's SX9500 capacitive proximity/button solution. 68c2ecf20Sopenharmony_ci * Datasheet available at 78c2ecf20Sopenharmony_ci * <http://www.semtech.com/images/datasheet/sx9500.pdf>. 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/kernel.h> 118c2ecf20Sopenharmony_ci#include <linux/slab.h> 128c2ecf20Sopenharmony_ci#include <linux/module.h> 138c2ecf20Sopenharmony_ci#include <linux/i2c.h> 148c2ecf20Sopenharmony_ci#include <linux/irq.h> 158c2ecf20Sopenharmony_ci#include <linux/acpi.h> 168c2ecf20Sopenharmony_ci#include <linux/gpio/consumer.h> 178c2ecf20Sopenharmony_ci#include <linux/regmap.h> 188c2ecf20Sopenharmony_ci#include <linux/pm.h> 198c2ecf20Sopenharmony_ci#include <linux/delay.h> 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#include <linux/iio/iio.h> 228c2ecf20Sopenharmony_ci#include <linux/iio/buffer.h> 238c2ecf20Sopenharmony_ci#include <linux/iio/sysfs.h> 248c2ecf20Sopenharmony_ci#include <linux/iio/events.h> 258c2ecf20Sopenharmony_ci#include <linux/iio/trigger.h> 268c2ecf20Sopenharmony_ci#include <linux/iio/triggered_buffer.h> 278c2ecf20Sopenharmony_ci#include <linux/iio/trigger_consumer.h> 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci#define SX9500_DRIVER_NAME "sx9500" 308c2ecf20Sopenharmony_ci#define SX9500_IRQ_NAME "sx9500_event" 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci/* Register definitions. */ 338c2ecf20Sopenharmony_ci#define SX9500_REG_IRQ_SRC 0x00 348c2ecf20Sopenharmony_ci#define SX9500_REG_STAT 0x01 358c2ecf20Sopenharmony_ci#define SX9500_REG_IRQ_MSK 0x03 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci#define SX9500_REG_PROX_CTRL0 0x06 388c2ecf20Sopenharmony_ci#define SX9500_REG_PROX_CTRL1 0x07 398c2ecf20Sopenharmony_ci#define SX9500_REG_PROX_CTRL2 0x08 408c2ecf20Sopenharmony_ci#define SX9500_REG_PROX_CTRL3 0x09 418c2ecf20Sopenharmony_ci#define SX9500_REG_PROX_CTRL4 0x0a 428c2ecf20Sopenharmony_ci#define SX9500_REG_PROX_CTRL5 0x0b 438c2ecf20Sopenharmony_ci#define SX9500_REG_PROX_CTRL6 0x0c 448c2ecf20Sopenharmony_ci#define SX9500_REG_PROX_CTRL7 0x0d 458c2ecf20Sopenharmony_ci#define SX9500_REG_PROX_CTRL8 0x0e 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci#define SX9500_REG_SENSOR_SEL 0x20 488c2ecf20Sopenharmony_ci#define SX9500_REG_USE_MSB 0x21 498c2ecf20Sopenharmony_ci#define SX9500_REG_USE_LSB 0x22 508c2ecf20Sopenharmony_ci#define SX9500_REG_AVG_MSB 0x23 518c2ecf20Sopenharmony_ci#define SX9500_REG_AVG_LSB 0x24 528c2ecf20Sopenharmony_ci#define SX9500_REG_DIFF_MSB 0x25 538c2ecf20Sopenharmony_ci#define SX9500_REG_DIFF_LSB 0x26 548c2ecf20Sopenharmony_ci#define SX9500_REG_OFFSET_MSB 0x27 558c2ecf20Sopenharmony_ci#define SX9500_REG_OFFSET_LSB 0x28 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci#define SX9500_REG_RESET 0x7f 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci/* Write this to REG_RESET to do a soft reset. */ 608c2ecf20Sopenharmony_ci#define SX9500_SOFT_RESET 0xde 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci#define SX9500_SCAN_PERIOD_MASK GENMASK(6, 4) 638c2ecf20Sopenharmony_ci#define SX9500_SCAN_PERIOD_SHIFT 4 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci/* 668c2ecf20Sopenharmony_ci * These serve for identifying IRQ source in the IRQ_SRC register, and 678c2ecf20Sopenharmony_ci * also for masking the IRQs in the IRQ_MSK register. 688c2ecf20Sopenharmony_ci */ 698c2ecf20Sopenharmony_ci#define SX9500_CLOSE_IRQ BIT(6) 708c2ecf20Sopenharmony_ci#define SX9500_FAR_IRQ BIT(5) 718c2ecf20Sopenharmony_ci#define SX9500_CONVDONE_IRQ BIT(3) 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci#define SX9500_PROXSTAT_SHIFT 4 748c2ecf20Sopenharmony_ci#define SX9500_COMPSTAT_MASK GENMASK(3, 0) 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci#define SX9500_NUM_CHANNELS 4 778c2ecf20Sopenharmony_ci#define SX9500_CHAN_MASK GENMASK(SX9500_NUM_CHANNELS - 1, 0) 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_cistruct sx9500_data { 808c2ecf20Sopenharmony_ci struct mutex mutex; 818c2ecf20Sopenharmony_ci struct i2c_client *client; 828c2ecf20Sopenharmony_ci struct iio_trigger *trig; 838c2ecf20Sopenharmony_ci struct regmap *regmap; 848c2ecf20Sopenharmony_ci struct gpio_desc *gpiod_rst; 858c2ecf20Sopenharmony_ci /* 868c2ecf20Sopenharmony_ci * Last reading of the proximity status for each channel. We 878c2ecf20Sopenharmony_ci * only send an event to user space when this changes. 888c2ecf20Sopenharmony_ci */ 898c2ecf20Sopenharmony_ci bool prox_stat[SX9500_NUM_CHANNELS]; 908c2ecf20Sopenharmony_ci bool event_enabled[SX9500_NUM_CHANNELS]; 918c2ecf20Sopenharmony_ci bool trigger_enabled; 928c2ecf20Sopenharmony_ci u16 *buffer; 938c2ecf20Sopenharmony_ci /* Remember enabled channels and sample rate during suspend. */ 948c2ecf20Sopenharmony_ci unsigned int suspend_ctrl0; 958c2ecf20Sopenharmony_ci struct completion completion; 968c2ecf20Sopenharmony_ci int data_rdy_users, close_far_users; 978c2ecf20Sopenharmony_ci int channel_users[SX9500_NUM_CHANNELS]; 988c2ecf20Sopenharmony_ci}; 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_cistatic const struct iio_event_spec sx9500_events[] = { 1018c2ecf20Sopenharmony_ci { 1028c2ecf20Sopenharmony_ci .type = IIO_EV_TYPE_THRESH, 1038c2ecf20Sopenharmony_ci .dir = IIO_EV_DIR_EITHER, 1048c2ecf20Sopenharmony_ci .mask_separate = BIT(IIO_EV_INFO_ENABLE), 1058c2ecf20Sopenharmony_ci }, 1068c2ecf20Sopenharmony_ci}; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci#define SX9500_CHANNEL(idx) \ 1098c2ecf20Sopenharmony_ci { \ 1108c2ecf20Sopenharmony_ci .type = IIO_PROXIMITY, \ 1118c2ecf20Sopenharmony_ci .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ 1128c2ecf20Sopenharmony_ci .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \ 1138c2ecf20Sopenharmony_ci .indexed = 1, \ 1148c2ecf20Sopenharmony_ci .channel = idx, \ 1158c2ecf20Sopenharmony_ci .event_spec = sx9500_events, \ 1168c2ecf20Sopenharmony_ci .num_event_specs = ARRAY_SIZE(sx9500_events), \ 1178c2ecf20Sopenharmony_ci .scan_index = idx, \ 1188c2ecf20Sopenharmony_ci .scan_type = { \ 1198c2ecf20Sopenharmony_ci .sign = 'u', \ 1208c2ecf20Sopenharmony_ci .realbits = 16, \ 1218c2ecf20Sopenharmony_ci .storagebits = 16, \ 1228c2ecf20Sopenharmony_ci .shift = 0, \ 1238c2ecf20Sopenharmony_ci }, \ 1248c2ecf20Sopenharmony_ci } 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_cistatic const struct iio_chan_spec sx9500_channels[] = { 1278c2ecf20Sopenharmony_ci SX9500_CHANNEL(0), 1288c2ecf20Sopenharmony_ci SX9500_CHANNEL(1), 1298c2ecf20Sopenharmony_ci SX9500_CHANNEL(2), 1308c2ecf20Sopenharmony_ci SX9500_CHANNEL(3), 1318c2ecf20Sopenharmony_ci IIO_CHAN_SOFT_TIMESTAMP(4), 1328c2ecf20Sopenharmony_ci}; 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_cistatic const struct { 1358c2ecf20Sopenharmony_ci int val; 1368c2ecf20Sopenharmony_ci int val2; 1378c2ecf20Sopenharmony_ci} sx9500_samp_freq_table[] = { 1388c2ecf20Sopenharmony_ci {33, 333333}, 1398c2ecf20Sopenharmony_ci {16, 666666}, 1408c2ecf20Sopenharmony_ci {11, 111111}, 1418c2ecf20Sopenharmony_ci {8, 333333}, 1428c2ecf20Sopenharmony_ci {6, 666666}, 1438c2ecf20Sopenharmony_ci {5, 0}, 1448c2ecf20Sopenharmony_ci {3, 333333}, 1458c2ecf20Sopenharmony_ci {2, 500000}, 1468c2ecf20Sopenharmony_ci}; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_cistatic const unsigned int sx9500_scan_period_table[] = { 1498c2ecf20Sopenharmony_ci 30, 60, 90, 120, 150, 200, 300, 400, 1508c2ecf20Sopenharmony_ci}; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_cistatic const struct regmap_range sx9500_writable_reg_ranges[] = { 1538c2ecf20Sopenharmony_ci regmap_reg_range(SX9500_REG_IRQ_MSK, SX9500_REG_IRQ_MSK), 1548c2ecf20Sopenharmony_ci regmap_reg_range(SX9500_REG_PROX_CTRL0, SX9500_REG_PROX_CTRL8), 1558c2ecf20Sopenharmony_ci regmap_reg_range(SX9500_REG_SENSOR_SEL, SX9500_REG_SENSOR_SEL), 1568c2ecf20Sopenharmony_ci regmap_reg_range(SX9500_REG_OFFSET_MSB, SX9500_REG_OFFSET_LSB), 1578c2ecf20Sopenharmony_ci regmap_reg_range(SX9500_REG_RESET, SX9500_REG_RESET), 1588c2ecf20Sopenharmony_ci}; 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_cistatic const struct regmap_access_table sx9500_writeable_regs = { 1618c2ecf20Sopenharmony_ci .yes_ranges = sx9500_writable_reg_ranges, 1628c2ecf20Sopenharmony_ci .n_yes_ranges = ARRAY_SIZE(sx9500_writable_reg_ranges), 1638c2ecf20Sopenharmony_ci}; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci/* 1668c2ecf20Sopenharmony_ci * All allocated registers are readable, so we just list unallocated 1678c2ecf20Sopenharmony_ci * ones. 1688c2ecf20Sopenharmony_ci */ 1698c2ecf20Sopenharmony_cistatic const struct regmap_range sx9500_non_readable_reg_ranges[] = { 1708c2ecf20Sopenharmony_ci regmap_reg_range(SX9500_REG_STAT + 1, SX9500_REG_STAT + 1), 1718c2ecf20Sopenharmony_ci regmap_reg_range(SX9500_REG_IRQ_MSK + 1, SX9500_REG_PROX_CTRL0 - 1), 1728c2ecf20Sopenharmony_ci regmap_reg_range(SX9500_REG_PROX_CTRL8 + 1, SX9500_REG_SENSOR_SEL - 1), 1738c2ecf20Sopenharmony_ci regmap_reg_range(SX9500_REG_OFFSET_LSB + 1, SX9500_REG_RESET - 1), 1748c2ecf20Sopenharmony_ci}; 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_cistatic const struct regmap_access_table sx9500_readable_regs = { 1778c2ecf20Sopenharmony_ci .no_ranges = sx9500_non_readable_reg_ranges, 1788c2ecf20Sopenharmony_ci .n_no_ranges = ARRAY_SIZE(sx9500_non_readable_reg_ranges), 1798c2ecf20Sopenharmony_ci}; 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_cistatic const struct regmap_range sx9500_volatile_reg_ranges[] = { 1828c2ecf20Sopenharmony_ci regmap_reg_range(SX9500_REG_IRQ_SRC, SX9500_REG_STAT), 1838c2ecf20Sopenharmony_ci regmap_reg_range(SX9500_REG_USE_MSB, SX9500_REG_OFFSET_LSB), 1848c2ecf20Sopenharmony_ci regmap_reg_range(SX9500_REG_RESET, SX9500_REG_RESET), 1858c2ecf20Sopenharmony_ci}; 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_cistatic const struct regmap_access_table sx9500_volatile_regs = { 1888c2ecf20Sopenharmony_ci .yes_ranges = sx9500_volatile_reg_ranges, 1898c2ecf20Sopenharmony_ci .n_yes_ranges = ARRAY_SIZE(sx9500_volatile_reg_ranges), 1908c2ecf20Sopenharmony_ci}; 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_cistatic const struct regmap_config sx9500_regmap_config = { 1938c2ecf20Sopenharmony_ci .reg_bits = 8, 1948c2ecf20Sopenharmony_ci .val_bits = 8, 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci .max_register = SX9500_REG_RESET, 1978c2ecf20Sopenharmony_ci .cache_type = REGCACHE_RBTREE, 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci .wr_table = &sx9500_writeable_regs, 2008c2ecf20Sopenharmony_ci .rd_table = &sx9500_readable_regs, 2018c2ecf20Sopenharmony_ci .volatile_table = &sx9500_volatile_regs, 2028c2ecf20Sopenharmony_ci}; 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_cistatic int sx9500_inc_users(struct sx9500_data *data, int *counter, 2058c2ecf20Sopenharmony_ci unsigned int reg, unsigned int bitmask) 2068c2ecf20Sopenharmony_ci{ 2078c2ecf20Sopenharmony_ci (*counter)++; 2088c2ecf20Sopenharmony_ci if (*counter != 1) 2098c2ecf20Sopenharmony_ci /* Bit is already active, nothing to do. */ 2108c2ecf20Sopenharmony_ci return 0; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci return regmap_update_bits(data->regmap, reg, bitmask, bitmask); 2138c2ecf20Sopenharmony_ci} 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_cistatic int sx9500_dec_users(struct sx9500_data *data, int *counter, 2168c2ecf20Sopenharmony_ci unsigned int reg, unsigned int bitmask) 2178c2ecf20Sopenharmony_ci{ 2188c2ecf20Sopenharmony_ci (*counter)--; 2198c2ecf20Sopenharmony_ci if (*counter != 0) 2208c2ecf20Sopenharmony_ci /* There are more users, do not deactivate. */ 2218c2ecf20Sopenharmony_ci return 0; 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci return regmap_update_bits(data->regmap, reg, bitmask, 0); 2248c2ecf20Sopenharmony_ci} 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_cistatic int sx9500_inc_chan_users(struct sx9500_data *data, int chan) 2278c2ecf20Sopenharmony_ci{ 2288c2ecf20Sopenharmony_ci return sx9500_inc_users(data, &data->channel_users[chan], 2298c2ecf20Sopenharmony_ci SX9500_REG_PROX_CTRL0, BIT(chan)); 2308c2ecf20Sopenharmony_ci} 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_cistatic int sx9500_dec_chan_users(struct sx9500_data *data, int chan) 2338c2ecf20Sopenharmony_ci{ 2348c2ecf20Sopenharmony_ci return sx9500_dec_users(data, &data->channel_users[chan], 2358c2ecf20Sopenharmony_ci SX9500_REG_PROX_CTRL0, BIT(chan)); 2368c2ecf20Sopenharmony_ci} 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_cistatic int sx9500_inc_data_rdy_users(struct sx9500_data *data) 2398c2ecf20Sopenharmony_ci{ 2408c2ecf20Sopenharmony_ci return sx9500_inc_users(data, &data->data_rdy_users, 2418c2ecf20Sopenharmony_ci SX9500_REG_IRQ_MSK, SX9500_CONVDONE_IRQ); 2428c2ecf20Sopenharmony_ci} 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_cistatic int sx9500_dec_data_rdy_users(struct sx9500_data *data) 2458c2ecf20Sopenharmony_ci{ 2468c2ecf20Sopenharmony_ci return sx9500_dec_users(data, &data->data_rdy_users, 2478c2ecf20Sopenharmony_ci SX9500_REG_IRQ_MSK, SX9500_CONVDONE_IRQ); 2488c2ecf20Sopenharmony_ci} 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_cistatic int sx9500_inc_close_far_users(struct sx9500_data *data) 2518c2ecf20Sopenharmony_ci{ 2528c2ecf20Sopenharmony_ci return sx9500_inc_users(data, &data->close_far_users, 2538c2ecf20Sopenharmony_ci SX9500_REG_IRQ_MSK, 2548c2ecf20Sopenharmony_ci SX9500_CLOSE_IRQ | SX9500_FAR_IRQ); 2558c2ecf20Sopenharmony_ci} 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_cistatic int sx9500_dec_close_far_users(struct sx9500_data *data) 2588c2ecf20Sopenharmony_ci{ 2598c2ecf20Sopenharmony_ci return sx9500_dec_users(data, &data->close_far_users, 2608c2ecf20Sopenharmony_ci SX9500_REG_IRQ_MSK, 2618c2ecf20Sopenharmony_ci SX9500_CLOSE_IRQ | SX9500_FAR_IRQ); 2628c2ecf20Sopenharmony_ci} 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_cistatic int sx9500_read_prox_data(struct sx9500_data *data, 2658c2ecf20Sopenharmony_ci const struct iio_chan_spec *chan, 2668c2ecf20Sopenharmony_ci int *val) 2678c2ecf20Sopenharmony_ci{ 2688c2ecf20Sopenharmony_ci int ret; 2698c2ecf20Sopenharmony_ci __be16 regval; 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci ret = regmap_write(data->regmap, SX9500_REG_SENSOR_SEL, chan->channel); 2728c2ecf20Sopenharmony_ci if (ret < 0) 2738c2ecf20Sopenharmony_ci return ret; 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci ret = regmap_bulk_read(data->regmap, SX9500_REG_USE_MSB, ®val, 2); 2768c2ecf20Sopenharmony_ci if (ret < 0) 2778c2ecf20Sopenharmony_ci return ret; 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci *val = be16_to_cpu(regval); 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci return IIO_VAL_INT; 2828c2ecf20Sopenharmony_ci} 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci/* 2858c2ecf20Sopenharmony_ci * If we have no interrupt support, we have to wait for a scan period 2868c2ecf20Sopenharmony_ci * after enabling a channel to get a result. 2878c2ecf20Sopenharmony_ci */ 2888c2ecf20Sopenharmony_cistatic int sx9500_wait_for_sample(struct sx9500_data *data) 2898c2ecf20Sopenharmony_ci{ 2908c2ecf20Sopenharmony_ci int ret; 2918c2ecf20Sopenharmony_ci unsigned int val; 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci ret = regmap_read(data->regmap, SX9500_REG_PROX_CTRL0, &val); 2948c2ecf20Sopenharmony_ci if (ret < 0) 2958c2ecf20Sopenharmony_ci return ret; 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci val = (val & SX9500_SCAN_PERIOD_MASK) >> SX9500_SCAN_PERIOD_SHIFT; 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci msleep(sx9500_scan_period_table[val]); 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci return 0; 3028c2ecf20Sopenharmony_ci} 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_cistatic int sx9500_read_proximity(struct sx9500_data *data, 3058c2ecf20Sopenharmony_ci const struct iio_chan_spec *chan, 3068c2ecf20Sopenharmony_ci int *val) 3078c2ecf20Sopenharmony_ci{ 3088c2ecf20Sopenharmony_ci int ret; 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci mutex_lock(&data->mutex); 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci ret = sx9500_inc_chan_users(data, chan->channel); 3138c2ecf20Sopenharmony_ci if (ret < 0) 3148c2ecf20Sopenharmony_ci goto out; 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci ret = sx9500_inc_data_rdy_users(data); 3178c2ecf20Sopenharmony_ci if (ret < 0) 3188c2ecf20Sopenharmony_ci goto out_dec_chan; 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci mutex_unlock(&data->mutex); 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci if (data->client->irq > 0) 3238c2ecf20Sopenharmony_ci ret = wait_for_completion_interruptible(&data->completion); 3248c2ecf20Sopenharmony_ci else 3258c2ecf20Sopenharmony_ci ret = sx9500_wait_for_sample(data); 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci mutex_lock(&data->mutex); 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci if (ret < 0) 3308c2ecf20Sopenharmony_ci goto out_dec_data_rdy; 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci ret = sx9500_read_prox_data(data, chan, val); 3338c2ecf20Sopenharmony_ci if (ret < 0) 3348c2ecf20Sopenharmony_ci goto out_dec_data_rdy; 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci ret = sx9500_dec_data_rdy_users(data); 3378c2ecf20Sopenharmony_ci if (ret < 0) 3388c2ecf20Sopenharmony_ci goto out_dec_chan; 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci ret = sx9500_dec_chan_users(data, chan->channel); 3418c2ecf20Sopenharmony_ci if (ret < 0) 3428c2ecf20Sopenharmony_ci goto out; 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci ret = IIO_VAL_INT; 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci goto out; 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ciout_dec_data_rdy: 3498c2ecf20Sopenharmony_ci sx9500_dec_data_rdy_users(data); 3508c2ecf20Sopenharmony_ciout_dec_chan: 3518c2ecf20Sopenharmony_ci sx9500_dec_chan_users(data, chan->channel); 3528c2ecf20Sopenharmony_ciout: 3538c2ecf20Sopenharmony_ci mutex_unlock(&data->mutex); 3548c2ecf20Sopenharmony_ci reinit_completion(&data->completion); 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci return ret; 3578c2ecf20Sopenharmony_ci} 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_cistatic int sx9500_read_samp_freq(struct sx9500_data *data, 3608c2ecf20Sopenharmony_ci int *val, int *val2) 3618c2ecf20Sopenharmony_ci{ 3628c2ecf20Sopenharmony_ci int ret; 3638c2ecf20Sopenharmony_ci unsigned int regval; 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci mutex_lock(&data->mutex); 3668c2ecf20Sopenharmony_ci ret = regmap_read(data->regmap, SX9500_REG_PROX_CTRL0, ®val); 3678c2ecf20Sopenharmony_ci mutex_unlock(&data->mutex); 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci if (ret < 0) 3708c2ecf20Sopenharmony_ci return ret; 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci regval = (regval & SX9500_SCAN_PERIOD_MASK) >> SX9500_SCAN_PERIOD_SHIFT; 3738c2ecf20Sopenharmony_ci *val = sx9500_samp_freq_table[regval].val; 3748c2ecf20Sopenharmony_ci *val2 = sx9500_samp_freq_table[regval].val2; 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci return IIO_VAL_INT_PLUS_MICRO; 3778c2ecf20Sopenharmony_ci} 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_cistatic int sx9500_read_raw(struct iio_dev *indio_dev, 3808c2ecf20Sopenharmony_ci const struct iio_chan_spec *chan, 3818c2ecf20Sopenharmony_ci int *val, int *val2, long mask) 3828c2ecf20Sopenharmony_ci{ 3838c2ecf20Sopenharmony_ci struct sx9500_data *data = iio_priv(indio_dev); 3848c2ecf20Sopenharmony_ci int ret; 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci switch (chan->type) { 3878c2ecf20Sopenharmony_ci case IIO_PROXIMITY: 3888c2ecf20Sopenharmony_ci switch (mask) { 3898c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_RAW: 3908c2ecf20Sopenharmony_ci ret = iio_device_claim_direct_mode(indio_dev); 3918c2ecf20Sopenharmony_ci if (ret) 3928c2ecf20Sopenharmony_ci return ret; 3938c2ecf20Sopenharmony_ci ret = sx9500_read_proximity(data, chan, val); 3948c2ecf20Sopenharmony_ci iio_device_release_direct_mode(indio_dev); 3958c2ecf20Sopenharmony_ci return ret; 3968c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_SAMP_FREQ: 3978c2ecf20Sopenharmony_ci return sx9500_read_samp_freq(data, val, val2); 3988c2ecf20Sopenharmony_ci default: 3998c2ecf20Sopenharmony_ci return -EINVAL; 4008c2ecf20Sopenharmony_ci } 4018c2ecf20Sopenharmony_ci default: 4028c2ecf20Sopenharmony_ci return -EINVAL; 4038c2ecf20Sopenharmony_ci } 4048c2ecf20Sopenharmony_ci} 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_cistatic int sx9500_set_samp_freq(struct sx9500_data *data, 4078c2ecf20Sopenharmony_ci int val, int val2) 4088c2ecf20Sopenharmony_ci{ 4098c2ecf20Sopenharmony_ci int i, ret; 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(sx9500_samp_freq_table); i++) 4128c2ecf20Sopenharmony_ci if (val == sx9500_samp_freq_table[i].val && 4138c2ecf20Sopenharmony_ci val2 == sx9500_samp_freq_table[i].val2) 4148c2ecf20Sopenharmony_ci break; 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci if (i == ARRAY_SIZE(sx9500_samp_freq_table)) 4178c2ecf20Sopenharmony_ci return -EINVAL; 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci mutex_lock(&data->mutex); 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci ret = regmap_update_bits(data->regmap, SX9500_REG_PROX_CTRL0, 4228c2ecf20Sopenharmony_ci SX9500_SCAN_PERIOD_MASK, 4238c2ecf20Sopenharmony_ci i << SX9500_SCAN_PERIOD_SHIFT); 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci mutex_unlock(&data->mutex); 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci return ret; 4288c2ecf20Sopenharmony_ci} 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_cistatic int sx9500_write_raw(struct iio_dev *indio_dev, 4318c2ecf20Sopenharmony_ci const struct iio_chan_spec *chan, 4328c2ecf20Sopenharmony_ci int val, int val2, long mask) 4338c2ecf20Sopenharmony_ci{ 4348c2ecf20Sopenharmony_ci struct sx9500_data *data = iio_priv(indio_dev); 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci switch (chan->type) { 4378c2ecf20Sopenharmony_ci case IIO_PROXIMITY: 4388c2ecf20Sopenharmony_ci switch (mask) { 4398c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_SAMP_FREQ: 4408c2ecf20Sopenharmony_ci return sx9500_set_samp_freq(data, val, val2); 4418c2ecf20Sopenharmony_ci default: 4428c2ecf20Sopenharmony_ci return -EINVAL; 4438c2ecf20Sopenharmony_ci } 4448c2ecf20Sopenharmony_ci default: 4458c2ecf20Sopenharmony_ci return -EINVAL; 4468c2ecf20Sopenharmony_ci } 4478c2ecf20Sopenharmony_ci} 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_cistatic irqreturn_t sx9500_irq_handler(int irq, void *private) 4508c2ecf20Sopenharmony_ci{ 4518c2ecf20Sopenharmony_ci struct iio_dev *indio_dev = private; 4528c2ecf20Sopenharmony_ci struct sx9500_data *data = iio_priv(indio_dev); 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci if (data->trigger_enabled) 4558c2ecf20Sopenharmony_ci iio_trigger_poll(data->trig); 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci /* 4588c2ecf20Sopenharmony_ci * Even if no event is enabled, we need to wake the thread to 4598c2ecf20Sopenharmony_ci * clear the interrupt state by reading SX9500_REG_IRQ_SRC. It 4608c2ecf20Sopenharmony_ci * is not possible to do that here because regmap_read takes a 4618c2ecf20Sopenharmony_ci * mutex. 4628c2ecf20Sopenharmony_ci */ 4638c2ecf20Sopenharmony_ci return IRQ_WAKE_THREAD; 4648c2ecf20Sopenharmony_ci} 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_cistatic void sx9500_push_events(struct iio_dev *indio_dev) 4678c2ecf20Sopenharmony_ci{ 4688c2ecf20Sopenharmony_ci int ret; 4698c2ecf20Sopenharmony_ci unsigned int val, chan; 4708c2ecf20Sopenharmony_ci struct sx9500_data *data = iio_priv(indio_dev); 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci ret = regmap_read(data->regmap, SX9500_REG_STAT, &val); 4738c2ecf20Sopenharmony_ci if (ret < 0) { 4748c2ecf20Sopenharmony_ci dev_err(&data->client->dev, "i2c transfer error in irq\n"); 4758c2ecf20Sopenharmony_ci return; 4768c2ecf20Sopenharmony_ci } 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci val >>= SX9500_PROXSTAT_SHIFT; 4798c2ecf20Sopenharmony_ci for (chan = 0; chan < SX9500_NUM_CHANNELS; chan++) { 4808c2ecf20Sopenharmony_ci int dir; 4818c2ecf20Sopenharmony_ci u64 ev; 4828c2ecf20Sopenharmony_ci bool new_prox = val & BIT(chan); 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci if (!data->event_enabled[chan]) 4858c2ecf20Sopenharmony_ci continue; 4868c2ecf20Sopenharmony_ci if (new_prox == data->prox_stat[chan]) 4878c2ecf20Sopenharmony_ci /* No change on this channel. */ 4888c2ecf20Sopenharmony_ci continue; 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci dir = new_prox ? IIO_EV_DIR_FALLING : IIO_EV_DIR_RISING; 4918c2ecf20Sopenharmony_ci ev = IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, chan, 4928c2ecf20Sopenharmony_ci IIO_EV_TYPE_THRESH, dir); 4938c2ecf20Sopenharmony_ci iio_push_event(indio_dev, ev, iio_get_time_ns(indio_dev)); 4948c2ecf20Sopenharmony_ci data->prox_stat[chan] = new_prox; 4958c2ecf20Sopenharmony_ci } 4968c2ecf20Sopenharmony_ci} 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_cistatic irqreturn_t sx9500_irq_thread_handler(int irq, void *private) 4998c2ecf20Sopenharmony_ci{ 5008c2ecf20Sopenharmony_ci struct iio_dev *indio_dev = private; 5018c2ecf20Sopenharmony_ci struct sx9500_data *data = iio_priv(indio_dev); 5028c2ecf20Sopenharmony_ci int ret; 5038c2ecf20Sopenharmony_ci unsigned int val; 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci mutex_lock(&data->mutex); 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci ret = regmap_read(data->regmap, SX9500_REG_IRQ_SRC, &val); 5088c2ecf20Sopenharmony_ci if (ret < 0) { 5098c2ecf20Sopenharmony_ci dev_err(&data->client->dev, "i2c transfer error in irq\n"); 5108c2ecf20Sopenharmony_ci goto out; 5118c2ecf20Sopenharmony_ci } 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci if (val & (SX9500_CLOSE_IRQ | SX9500_FAR_IRQ)) 5148c2ecf20Sopenharmony_ci sx9500_push_events(indio_dev); 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci if (val & SX9500_CONVDONE_IRQ) 5178c2ecf20Sopenharmony_ci complete(&data->completion); 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ciout: 5208c2ecf20Sopenharmony_ci mutex_unlock(&data->mutex); 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci return IRQ_HANDLED; 5238c2ecf20Sopenharmony_ci} 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_cistatic int sx9500_read_event_config(struct iio_dev *indio_dev, 5268c2ecf20Sopenharmony_ci const struct iio_chan_spec *chan, 5278c2ecf20Sopenharmony_ci enum iio_event_type type, 5288c2ecf20Sopenharmony_ci enum iio_event_direction dir) 5298c2ecf20Sopenharmony_ci{ 5308c2ecf20Sopenharmony_ci struct sx9500_data *data = iio_priv(indio_dev); 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci if (chan->type != IIO_PROXIMITY || type != IIO_EV_TYPE_THRESH || 5338c2ecf20Sopenharmony_ci dir != IIO_EV_DIR_EITHER) 5348c2ecf20Sopenharmony_ci return -EINVAL; 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ci return data->event_enabled[chan->channel]; 5378c2ecf20Sopenharmony_ci} 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_cistatic int sx9500_write_event_config(struct iio_dev *indio_dev, 5408c2ecf20Sopenharmony_ci const struct iio_chan_spec *chan, 5418c2ecf20Sopenharmony_ci enum iio_event_type type, 5428c2ecf20Sopenharmony_ci enum iio_event_direction dir, 5438c2ecf20Sopenharmony_ci int state) 5448c2ecf20Sopenharmony_ci{ 5458c2ecf20Sopenharmony_ci struct sx9500_data *data = iio_priv(indio_dev); 5468c2ecf20Sopenharmony_ci int ret; 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci if (chan->type != IIO_PROXIMITY || type != IIO_EV_TYPE_THRESH || 5498c2ecf20Sopenharmony_ci dir != IIO_EV_DIR_EITHER) 5508c2ecf20Sopenharmony_ci return -EINVAL; 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci mutex_lock(&data->mutex); 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci if (state == 1) { 5558c2ecf20Sopenharmony_ci ret = sx9500_inc_chan_users(data, chan->channel); 5568c2ecf20Sopenharmony_ci if (ret < 0) 5578c2ecf20Sopenharmony_ci goto out_unlock; 5588c2ecf20Sopenharmony_ci ret = sx9500_inc_close_far_users(data); 5598c2ecf20Sopenharmony_ci if (ret < 0) 5608c2ecf20Sopenharmony_ci goto out_undo_chan; 5618c2ecf20Sopenharmony_ci } else { 5628c2ecf20Sopenharmony_ci ret = sx9500_dec_chan_users(data, chan->channel); 5638c2ecf20Sopenharmony_ci if (ret < 0) 5648c2ecf20Sopenharmony_ci goto out_unlock; 5658c2ecf20Sopenharmony_ci ret = sx9500_dec_close_far_users(data); 5668c2ecf20Sopenharmony_ci if (ret < 0) 5678c2ecf20Sopenharmony_ci goto out_undo_chan; 5688c2ecf20Sopenharmony_ci } 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci data->event_enabled[chan->channel] = state; 5718c2ecf20Sopenharmony_ci goto out_unlock; 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ciout_undo_chan: 5748c2ecf20Sopenharmony_ci if (state == 1) 5758c2ecf20Sopenharmony_ci sx9500_dec_chan_users(data, chan->channel); 5768c2ecf20Sopenharmony_ci else 5778c2ecf20Sopenharmony_ci sx9500_inc_chan_users(data, chan->channel); 5788c2ecf20Sopenharmony_ciout_unlock: 5798c2ecf20Sopenharmony_ci mutex_unlock(&data->mutex); 5808c2ecf20Sopenharmony_ci return ret; 5818c2ecf20Sopenharmony_ci} 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_cistatic int sx9500_update_scan_mode(struct iio_dev *indio_dev, 5848c2ecf20Sopenharmony_ci const unsigned long *scan_mask) 5858c2ecf20Sopenharmony_ci{ 5868c2ecf20Sopenharmony_ci struct sx9500_data *data = iio_priv(indio_dev); 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci mutex_lock(&data->mutex); 5898c2ecf20Sopenharmony_ci kfree(data->buffer); 5908c2ecf20Sopenharmony_ci data->buffer = kzalloc(indio_dev->scan_bytes, GFP_KERNEL); 5918c2ecf20Sopenharmony_ci mutex_unlock(&data->mutex); 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci if (data->buffer == NULL) 5948c2ecf20Sopenharmony_ci return -ENOMEM; 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci return 0; 5978c2ecf20Sopenharmony_ci} 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_cistatic IIO_CONST_ATTR_SAMP_FREQ_AVAIL( 6008c2ecf20Sopenharmony_ci "2.500000 3.333333 5 6.666666 8.333333 11.111111 16.666666 33.333333"); 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_cistatic struct attribute *sx9500_attributes[] = { 6038c2ecf20Sopenharmony_ci &iio_const_attr_sampling_frequency_available.dev_attr.attr, 6048c2ecf20Sopenharmony_ci NULL, 6058c2ecf20Sopenharmony_ci}; 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_cistatic const struct attribute_group sx9500_attribute_group = { 6088c2ecf20Sopenharmony_ci .attrs = sx9500_attributes, 6098c2ecf20Sopenharmony_ci}; 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_cistatic const struct iio_info sx9500_info = { 6128c2ecf20Sopenharmony_ci .attrs = &sx9500_attribute_group, 6138c2ecf20Sopenharmony_ci .read_raw = &sx9500_read_raw, 6148c2ecf20Sopenharmony_ci .write_raw = &sx9500_write_raw, 6158c2ecf20Sopenharmony_ci .read_event_config = &sx9500_read_event_config, 6168c2ecf20Sopenharmony_ci .write_event_config = &sx9500_write_event_config, 6178c2ecf20Sopenharmony_ci .update_scan_mode = &sx9500_update_scan_mode, 6188c2ecf20Sopenharmony_ci}; 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_cistatic int sx9500_set_trigger_state(struct iio_trigger *trig, 6218c2ecf20Sopenharmony_ci bool state) 6228c2ecf20Sopenharmony_ci{ 6238c2ecf20Sopenharmony_ci struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig); 6248c2ecf20Sopenharmony_ci struct sx9500_data *data = iio_priv(indio_dev); 6258c2ecf20Sopenharmony_ci int ret; 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci mutex_lock(&data->mutex); 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ci if (state) 6308c2ecf20Sopenharmony_ci ret = sx9500_inc_data_rdy_users(data); 6318c2ecf20Sopenharmony_ci else 6328c2ecf20Sopenharmony_ci ret = sx9500_dec_data_rdy_users(data); 6338c2ecf20Sopenharmony_ci if (ret < 0) 6348c2ecf20Sopenharmony_ci goto out; 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_ci data->trigger_enabled = state; 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ciout: 6398c2ecf20Sopenharmony_ci mutex_unlock(&data->mutex); 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ci return ret; 6428c2ecf20Sopenharmony_ci} 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_cistatic const struct iio_trigger_ops sx9500_trigger_ops = { 6458c2ecf20Sopenharmony_ci .set_trigger_state = sx9500_set_trigger_state, 6468c2ecf20Sopenharmony_ci}; 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_cistatic irqreturn_t sx9500_trigger_handler(int irq, void *private) 6498c2ecf20Sopenharmony_ci{ 6508c2ecf20Sopenharmony_ci struct iio_poll_func *pf = private; 6518c2ecf20Sopenharmony_ci struct iio_dev *indio_dev = pf->indio_dev; 6528c2ecf20Sopenharmony_ci struct sx9500_data *data = iio_priv(indio_dev); 6538c2ecf20Sopenharmony_ci int val, bit, ret, i = 0; 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci mutex_lock(&data->mutex); 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci for_each_set_bit(bit, indio_dev->active_scan_mask, 6588c2ecf20Sopenharmony_ci indio_dev->masklength) { 6598c2ecf20Sopenharmony_ci ret = sx9500_read_prox_data(data, &indio_dev->channels[bit], 6608c2ecf20Sopenharmony_ci &val); 6618c2ecf20Sopenharmony_ci if (ret < 0) 6628c2ecf20Sopenharmony_ci goto out; 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_ci data->buffer[i++] = val; 6658c2ecf20Sopenharmony_ci } 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_ci iio_push_to_buffers_with_timestamp(indio_dev, data->buffer, 6688c2ecf20Sopenharmony_ci iio_get_time_ns(indio_dev)); 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ciout: 6718c2ecf20Sopenharmony_ci mutex_unlock(&data->mutex); 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ci iio_trigger_notify_done(indio_dev->trig); 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_ci return IRQ_HANDLED; 6768c2ecf20Sopenharmony_ci} 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_cistatic int sx9500_buffer_postenable(struct iio_dev *indio_dev) 6798c2ecf20Sopenharmony_ci{ 6808c2ecf20Sopenharmony_ci struct sx9500_data *data = iio_priv(indio_dev); 6818c2ecf20Sopenharmony_ci int ret = 0, i; 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_ci mutex_lock(&data->mutex); 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_ci for (i = 0; i < SX9500_NUM_CHANNELS; i++) 6868c2ecf20Sopenharmony_ci if (test_bit(i, indio_dev->active_scan_mask)) { 6878c2ecf20Sopenharmony_ci ret = sx9500_inc_chan_users(data, i); 6888c2ecf20Sopenharmony_ci if (ret) 6898c2ecf20Sopenharmony_ci break; 6908c2ecf20Sopenharmony_ci } 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_ci if (ret) 6938c2ecf20Sopenharmony_ci for (i = i - 1; i >= 0; i--) 6948c2ecf20Sopenharmony_ci if (test_bit(i, indio_dev->active_scan_mask)) 6958c2ecf20Sopenharmony_ci sx9500_dec_chan_users(data, i); 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci mutex_unlock(&data->mutex); 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ci return ret; 7008c2ecf20Sopenharmony_ci} 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_cistatic int sx9500_buffer_predisable(struct iio_dev *indio_dev) 7038c2ecf20Sopenharmony_ci{ 7048c2ecf20Sopenharmony_ci struct sx9500_data *data = iio_priv(indio_dev); 7058c2ecf20Sopenharmony_ci int ret = 0, i; 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_ci mutex_lock(&data->mutex); 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_ci for (i = 0; i < SX9500_NUM_CHANNELS; i++) 7108c2ecf20Sopenharmony_ci if (test_bit(i, indio_dev->active_scan_mask)) { 7118c2ecf20Sopenharmony_ci ret = sx9500_dec_chan_users(data, i); 7128c2ecf20Sopenharmony_ci if (ret) 7138c2ecf20Sopenharmony_ci break; 7148c2ecf20Sopenharmony_ci } 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_ci if (ret) 7178c2ecf20Sopenharmony_ci for (i = i - 1; i >= 0; i--) 7188c2ecf20Sopenharmony_ci if (test_bit(i, indio_dev->active_scan_mask)) 7198c2ecf20Sopenharmony_ci sx9500_inc_chan_users(data, i); 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_ci mutex_unlock(&data->mutex); 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_ci return ret; 7248c2ecf20Sopenharmony_ci} 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_cistatic const struct iio_buffer_setup_ops sx9500_buffer_setup_ops = { 7278c2ecf20Sopenharmony_ci .postenable = sx9500_buffer_postenable, 7288c2ecf20Sopenharmony_ci .predisable = sx9500_buffer_predisable, 7298c2ecf20Sopenharmony_ci}; 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_cistruct sx9500_reg_default { 7328c2ecf20Sopenharmony_ci u8 reg; 7338c2ecf20Sopenharmony_ci u8 def; 7348c2ecf20Sopenharmony_ci}; 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_cistatic const struct sx9500_reg_default sx9500_default_regs[] = { 7378c2ecf20Sopenharmony_ci { 7388c2ecf20Sopenharmony_ci .reg = SX9500_REG_PROX_CTRL1, 7398c2ecf20Sopenharmony_ci /* Shield enabled, small range. */ 7408c2ecf20Sopenharmony_ci .def = 0x43, 7418c2ecf20Sopenharmony_ci }, 7428c2ecf20Sopenharmony_ci { 7438c2ecf20Sopenharmony_ci .reg = SX9500_REG_PROX_CTRL2, 7448c2ecf20Sopenharmony_ci /* x8 gain, 167kHz frequency, finest resolution. */ 7458c2ecf20Sopenharmony_ci .def = 0x77, 7468c2ecf20Sopenharmony_ci }, 7478c2ecf20Sopenharmony_ci { 7488c2ecf20Sopenharmony_ci .reg = SX9500_REG_PROX_CTRL3, 7498c2ecf20Sopenharmony_ci /* Doze enabled, 2x scan period doze, no raw filter. */ 7508c2ecf20Sopenharmony_ci .def = 0x40, 7518c2ecf20Sopenharmony_ci }, 7528c2ecf20Sopenharmony_ci { 7538c2ecf20Sopenharmony_ci .reg = SX9500_REG_PROX_CTRL4, 7548c2ecf20Sopenharmony_ci /* Average threshold. */ 7558c2ecf20Sopenharmony_ci .def = 0x30, 7568c2ecf20Sopenharmony_ci }, 7578c2ecf20Sopenharmony_ci { 7588c2ecf20Sopenharmony_ci .reg = SX9500_REG_PROX_CTRL5, 7598c2ecf20Sopenharmony_ci /* 7608c2ecf20Sopenharmony_ci * Debouncer off, lowest average negative filter, 7618c2ecf20Sopenharmony_ci * highest average postive filter. 7628c2ecf20Sopenharmony_ci */ 7638c2ecf20Sopenharmony_ci .def = 0x0f, 7648c2ecf20Sopenharmony_ci }, 7658c2ecf20Sopenharmony_ci { 7668c2ecf20Sopenharmony_ci .reg = SX9500_REG_PROX_CTRL6, 7678c2ecf20Sopenharmony_ci /* Proximity detection threshold: 280 */ 7688c2ecf20Sopenharmony_ci .def = 0x0e, 7698c2ecf20Sopenharmony_ci }, 7708c2ecf20Sopenharmony_ci { 7718c2ecf20Sopenharmony_ci .reg = SX9500_REG_PROX_CTRL7, 7728c2ecf20Sopenharmony_ci /* 7738c2ecf20Sopenharmony_ci * No automatic compensation, compensate each pin 7748c2ecf20Sopenharmony_ci * independently, proximity hysteresis: 32, close 7758c2ecf20Sopenharmony_ci * debouncer off, far debouncer off. 7768c2ecf20Sopenharmony_ci */ 7778c2ecf20Sopenharmony_ci .def = 0x00, 7788c2ecf20Sopenharmony_ci }, 7798c2ecf20Sopenharmony_ci { 7808c2ecf20Sopenharmony_ci .reg = SX9500_REG_PROX_CTRL8, 7818c2ecf20Sopenharmony_ci /* No stuck timeout, no periodic compensation. */ 7828c2ecf20Sopenharmony_ci .def = 0x00, 7838c2ecf20Sopenharmony_ci }, 7848c2ecf20Sopenharmony_ci { 7858c2ecf20Sopenharmony_ci .reg = SX9500_REG_PROX_CTRL0, 7868c2ecf20Sopenharmony_ci /* Scan period: 30ms, all sensors disabled. */ 7878c2ecf20Sopenharmony_ci .def = 0x00, 7888c2ecf20Sopenharmony_ci }, 7898c2ecf20Sopenharmony_ci}; 7908c2ecf20Sopenharmony_ci 7918c2ecf20Sopenharmony_ci/* Activate all channels and perform an initial compensation. */ 7928c2ecf20Sopenharmony_cistatic int sx9500_init_compensation(struct iio_dev *indio_dev) 7938c2ecf20Sopenharmony_ci{ 7948c2ecf20Sopenharmony_ci struct sx9500_data *data = iio_priv(indio_dev); 7958c2ecf20Sopenharmony_ci int i, ret; 7968c2ecf20Sopenharmony_ci unsigned int val; 7978c2ecf20Sopenharmony_ci 7988c2ecf20Sopenharmony_ci ret = regmap_update_bits(data->regmap, SX9500_REG_PROX_CTRL0, 7998c2ecf20Sopenharmony_ci SX9500_CHAN_MASK, SX9500_CHAN_MASK); 8008c2ecf20Sopenharmony_ci if (ret < 0) 8018c2ecf20Sopenharmony_ci return ret; 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_ci for (i = 10; i >= 0; i--) { 8048c2ecf20Sopenharmony_ci usleep_range(10000, 20000); 8058c2ecf20Sopenharmony_ci ret = regmap_read(data->regmap, SX9500_REG_STAT, &val); 8068c2ecf20Sopenharmony_ci if (ret < 0) 8078c2ecf20Sopenharmony_ci goto out; 8088c2ecf20Sopenharmony_ci if (!(val & SX9500_COMPSTAT_MASK)) 8098c2ecf20Sopenharmony_ci break; 8108c2ecf20Sopenharmony_ci } 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_ci if (i < 0) { 8138c2ecf20Sopenharmony_ci dev_err(&data->client->dev, "initial compensation timed out"); 8148c2ecf20Sopenharmony_ci ret = -ETIMEDOUT; 8158c2ecf20Sopenharmony_ci } 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_ciout: 8188c2ecf20Sopenharmony_ci regmap_update_bits(data->regmap, SX9500_REG_PROX_CTRL0, 8198c2ecf20Sopenharmony_ci SX9500_CHAN_MASK, 0); 8208c2ecf20Sopenharmony_ci return ret; 8218c2ecf20Sopenharmony_ci} 8228c2ecf20Sopenharmony_ci 8238c2ecf20Sopenharmony_cistatic int sx9500_init_device(struct iio_dev *indio_dev) 8248c2ecf20Sopenharmony_ci{ 8258c2ecf20Sopenharmony_ci struct sx9500_data *data = iio_priv(indio_dev); 8268c2ecf20Sopenharmony_ci int ret, i; 8278c2ecf20Sopenharmony_ci unsigned int val; 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ci if (data->gpiod_rst) { 8308c2ecf20Sopenharmony_ci gpiod_set_value_cansleep(data->gpiod_rst, 0); 8318c2ecf20Sopenharmony_ci usleep_range(1000, 2000); 8328c2ecf20Sopenharmony_ci gpiod_set_value_cansleep(data->gpiod_rst, 1); 8338c2ecf20Sopenharmony_ci usleep_range(1000, 2000); 8348c2ecf20Sopenharmony_ci } 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_ci ret = regmap_write(data->regmap, SX9500_REG_IRQ_MSK, 0); 8378c2ecf20Sopenharmony_ci if (ret < 0) 8388c2ecf20Sopenharmony_ci return ret; 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_ci ret = regmap_write(data->regmap, SX9500_REG_RESET, 8418c2ecf20Sopenharmony_ci SX9500_SOFT_RESET); 8428c2ecf20Sopenharmony_ci if (ret < 0) 8438c2ecf20Sopenharmony_ci return ret; 8448c2ecf20Sopenharmony_ci 8458c2ecf20Sopenharmony_ci ret = regmap_read(data->regmap, SX9500_REG_IRQ_SRC, &val); 8468c2ecf20Sopenharmony_ci if (ret < 0) 8478c2ecf20Sopenharmony_ci return ret; 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(sx9500_default_regs); i++) { 8508c2ecf20Sopenharmony_ci ret = regmap_write(data->regmap, 8518c2ecf20Sopenharmony_ci sx9500_default_regs[i].reg, 8528c2ecf20Sopenharmony_ci sx9500_default_regs[i].def); 8538c2ecf20Sopenharmony_ci if (ret < 0) 8548c2ecf20Sopenharmony_ci return ret; 8558c2ecf20Sopenharmony_ci } 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_ci return sx9500_init_compensation(indio_dev); 8588c2ecf20Sopenharmony_ci} 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_cistatic const struct acpi_gpio_params reset_gpios = { 0, 0, false }; 8618c2ecf20Sopenharmony_cistatic const struct acpi_gpio_params interrupt_gpios = { 2, 0, false }; 8628c2ecf20Sopenharmony_ci 8638c2ecf20Sopenharmony_cistatic const struct acpi_gpio_mapping acpi_sx9500_gpios[] = { 8648c2ecf20Sopenharmony_ci { "reset-gpios", &reset_gpios, 1 }, 8658c2ecf20Sopenharmony_ci /* 8668c2ecf20Sopenharmony_ci * Some platforms have a bug in ACPI GPIO description making IRQ 8678c2ecf20Sopenharmony_ci * GPIO to be output only. Ask the GPIO core to ignore this limit. 8688c2ecf20Sopenharmony_ci */ 8698c2ecf20Sopenharmony_ci { "interrupt-gpios", &interrupt_gpios, 1, ACPI_GPIO_QUIRK_NO_IO_RESTRICTION }, 8708c2ecf20Sopenharmony_ci { }, 8718c2ecf20Sopenharmony_ci}; 8728c2ecf20Sopenharmony_ci 8738c2ecf20Sopenharmony_cistatic void sx9500_gpio_probe(struct i2c_client *client, 8748c2ecf20Sopenharmony_ci struct sx9500_data *data) 8758c2ecf20Sopenharmony_ci{ 8768c2ecf20Sopenharmony_ci struct gpio_desc *gpiod_int; 8778c2ecf20Sopenharmony_ci struct device *dev; 8788c2ecf20Sopenharmony_ci int ret; 8798c2ecf20Sopenharmony_ci 8808c2ecf20Sopenharmony_ci if (!client) 8818c2ecf20Sopenharmony_ci return; 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_ci dev = &client->dev; 8848c2ecf20Sopenharmony_ci 8858c2ecf20Sopenharmony_ci ret = devm_acpi_dev_add_driver_gpios(dev, acpi_sx9500_gpios); 8868c2ecf20Sopenharmony_ci if (ret) 8878c2ecf20Sopenharmony_ci dev_dbg(dev, "Unable to add GPIO mapping table\n"); 8888c2ecf20Sopenharmony_ci 8898c2ecf20Sopenharmony_ci if (client->irq <= 0) { 8908c2ecf20Sopenharmony_ci gpiod_int = devm_gpiod_get(dev, "interrupt", GPIOD_IN); 8918c2ecf20Sopenharmony_ci if (IS_ERR(gpiod_int)) 8928c2ecf20Sopenharmony_ci dev_err(dev, "gpio get irq failed\n"); 8938c2ecf20Sopenharmony_ci else 8948c2ecf20Sopenharmony_ci client->irq = gpiod_to_irq(gpiod_int); 8958c2ecf20Sopenharmony_ci } 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_ci data->gpiod_rst = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); 8988c2ecf20Sopenharmony_ci if (IS_ERR(data->gpiod_rst)) { 8998c2ecf20Sopenharmony_ci dev_warn(dev, "gpio get reset pin failed\n"); 9008c2ecf20Sopenharmony_ci data->gpiod_rst = NULL; 9018c2ecf20Sopenharmony_ci } 9028c2ecf20Sopenharmony_ci} 9038c2ecf20Sopenharmony_ci 9048c2ecf20Sopenharmony_cistatic int sx9500_probe(struct i2c_client *client, 9058c2ecf20Sopenharmony_ci const struct i2c_device_id *id) 9068c2ecf20Sopenharmony_ci{ 9078c2ecf20Sopenharmony_ci int ret; 9088c2ecf20Sopenharmony_ci struct iio_dev *indio_dev; 9098c2ecf20Sopenharmony_ci struct sx9500_data *data; 9108c2ecf20Sopenharmony_ci 9118c2ecf20Sopenharmony_ci indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); 9128c2ecf20Sopenharmony_ci if (indio_dev == NULL) 9138c2ecf20Sopenharmony_ci return -ENOMEM; 9148c2ecf20Sopenharmony_ci 9158c2ecf20Sopenharmony_ci data = iio_priv(indio_dev); 9168c2ecf20Sopenharmony_ci data->client = client; 9178c2ecf20Sopenharmony_ci mutex_init(&data->mutex); 9188c2ecf20Sopenharmony_ci init_completion(&data->completion); 9198c2ecf20Sopenharmony_ci data->trigger_enabled = false; 9208c2ecf20Sopenharmony_ci 9218c2ecf20Sopenharmony_ci data->regmap = devm_regmap_init_i2c(client, &sx9500_regmap_config); 9228c2ecf20Sopenharmony_ci if (IS_ERR(data->regmap)) 9238c2ecf20Sopenharmony_ci return PTR_ERR(data->regmap); 9248c2ecf20Sopenharmony_ci 9258c2ecf20Sopenharmony_ci indio_dev->name = SX9500_DRIVER_NAME; 9268c2ecf20Sopenharmony_ci indio_dev->channels = sx9500_channels; 9278c2ecf20Sopenharmony_ci indio_dev->num_channels = ARRAY_SIZE(sx9500_channels); 9288c2ecf20Sopenharmony_ci indio_dev->info = &sx9500_info; 9298c2ecf20Sopenharmony_ci indio_dev->modes = INDIO_DIRECT_MODE; 9308c2ecf20Sopenharmony_ci i2c_set_clientdata(client, indio_dev); 9318c2ecf20Sopenharmony_ci 9328c2ecf20Sopenharmony_ci sx9500_gpio_probe(client, data); 9338c2ecf20Sopenharmony_ci 9348c2ecf20Sopenharmony_ci ret = sx9500_init_device(indio_dev); 9358c2ecf20Sopenharmony_ci if (ret < 0) 9368c2ecf20Sopenharmony_ci return ret; 9378c2ecf20Sopenharmony_ci 9388c2ecf20Sopenharmony_ci if (client->irq <= 0) 9398c2ecf20Sopenharmony_ci dev_warn(&client->dev, "no valid irq found\n"); 9408c2ecf20Sopenharmony_ci else { 9418c2ecf20Sopenharmony_ci ret = devm_request_threaded_irq(&client->dev, client->irq, 9428c2ecf20Sopenharmony_ci sx9500_irq_handler, sx9500_irq_thread_handler, 9438c2ecf20Sopenharmony_ci IRQF_TRIGGER_FALLING | IRQF_ONESHOT, 9448c2ecf20Sopenharmony_ci SX9500_IRQ_NAME, indio_dev); 9458c2ecf20Sopenharmony_ci if (ret < 0) 9468c2ecf20Sopenharmony_ci return ret; 9478c2ecf20Sopenharmony_ci 9488c2ecf20Sopenharmony_ci data->trig = devm_iio_trigger_alloc(&client->dev, 9498c2ecf20Sopenharmony_ci "%s-dev%d", indio_dev->name, indio_dev->id); 9508c2ecf20Sopenharmony_ci if (!data->trig) 9518c2ecf20Sopenharmony_ci return -ENOMEM; 9528c2ecf20Sopenharmony_ci 9538c2ecf20Sopenharmony_ci data->trig->dev.parent = &client->dev; 9548c2ecf20Sopenharmony_ci data->trig->ops = &sx9500_trigger_ops; 9558c2ecf20Sopenharmony_ci iio_trigger_set_drvdata(data->trig, indio_dev); 9568c2ecf20Sopenharmony_ci 9578c2ecf20Sopenharmony_ci ret = iio_trigger_register(data->trig); 9588c2ecf20Sopenharmony_ci if (ret) 9598c2ecf20Sopenharmony_ci return ret; 9608c2ecf20Sopenharmony_ci } 9618c2ecf20Sopenharmony_ci 9628c2ecf20Sopenharmony_ci ret = iio_triggered_buffer_setup(indio_dev, NULL, 9638c2ecf20Sopenharmony_ci sx9500_trigger_handler, 9648c2ecf20Sopenharmony_ci &sx9500_buffer_setup_ops); 9658c2ecf20Sopenharmony_ci if (ret < 0) 9668c2ecf20Sopenharmony_ci goto out_trigger_unregister; 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_ci ret = iio_device_register(indio_dev); 9698c2ecf20Sopenharmony_ci if (ret < 0) 9708c2ecf20Sopenharmony_ci goto out_buffer_cleanup; 9718c2ecf20Sopenharmony_ci 9728c2ecf20Sopenharmony_ci return 0; 9738c2ecf20Sopenharmony_ci 9748c2ecf20Sopenharmony_ciout_buffer_cleanup: 9758c2ecf20Sopenharmony_ci iio_triggered_buffer_cleanup(indio_dev); 9768c2ecf20Sopenharmony_ciout_trigger_unregister: 9778c2ecf20Sopenharmony_ci if (client->irq > 0) 9788c2ecf20Sopenharmony_ci iio_trigger_unregister(data->trig); 9798c2ecf20Sopenharmony_ci 9808c2ecf20Sopenharmony_ci return ret; 9818c2ecf20Sopenharmony_ci} 9828c2ecf20Sopenharmony_ci 9838c2ecf20Sopenharmony_cistatic int sx9500_remove(struct i2c_client *client) 9848c2ecf20Sopenharmony_ci{ 9858c2ecf20Sopenharmony_ci struct iio_dev *indio_dev = i2c_get_clientdata(client); 9868c2ecf20Sopenharmony_ci struct sx9500_data *data = iio_priv(indio_dev); 9878c2ecf20Sopenharmony_ci 9888c2ecf20Sopenharmony_ci iio_device_unregister(indio_dev); 9898c2ecf20Sopenharmony_ci iio_triggered_buffer_cleanup(indio_dev); 9908c2ecf20Sopenharmony_ci if (client->irq > 0) 9918c2ecf20Sopenharmony_ci iio_trigger_unregister(data->trig); 9928c2ecf20Sopenharmony_ci kfree(data->buffer); 9938c2ecf20Sopenharmony_ci 9948c2ecf20Sopenharmony_ci return 0; 9958c2ecf20Sopenharmony_ci} 9968c2ecf20Sopenharmony_ci 9978c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 9988c2ecf20Sopenharmony_cistatic int sx9500_suspend(struct device *dev) 9998c2ecf20Sopenharmony_ci{ 10008c2ecf20Sopenharmony_ci struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); 10018c2ecf20Sopenharmony_ci struct sx9500_data *data = iio_priv(indio_dev); 10028c2ecf20Sopenharmony_ci int ret; 10038c2ecf20Sopenharmony_ci 10048c2ecf20Sopenharmony_ci mutex_lock(&data->mutex); 10058c2ecf20Sopenharmony_ci ret = regmap_read(data->regmap, SX9500_REG_PROX_CTRL0, 10068c2ecf20Sopenharmony_ci &data->suspend_ctrl0); 10078c2ecf20Sopenharmony_ci if (ret < 0) 10088c2ecf20Sopenharmony_ci goto out; 10098c2ecf20Sopenharmony_ci 10108c2ecf20Sopenharmony_ci /* 10118c2ecf20Sopenharmony_ci * Scan period doesn't matter because when all the sensors are 10128c2ecf20Sopenharmony_ci * deactivated the device is in sleep mode. 10138c2ecf20Sopenharmony_ci */ 10148c2ecf20Sopenharmony_ci ret = regmap_write(data->regmap, SX9500_REG_PROX_CTRL0, 0); 10158c2ecf20Sopenharmony_ci 10168c2ecf20Sopenharmony_ciout: 10178c2ecf20Sopenharmony_ci mutex_unlock(&data->mutex); 10188c2ecf20Sopenharmony_ci return ret; 10198c2ecf20Sopenharmony_ci} 10208c2ecf20Sopenharmony_ci 10218c2ecf20Sopenharmony_cistatic int sx9500_resume(struct device *dev) 10228c2ecf20Sopenharmony_ci{ 10238c2ecf20Sopenharmony_ci struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); 10248c2ecf20Sopenharmony_ci struct sx9500_data *data = iio_priv(indio_dev); 10258c2ecf20Sopenharmony_ci int ret; 10268c2ecf20Sopenharmony_ci 10278c2ecf20Sopenharmony_ci mutex_lock(&data->mutex); 10288c2ecf20Sopenharmony_ci ret = regmap_write(data->regmap, SX9500_REG_PROX_CTRL0, 10298c2ecf20Sopenharmony_ci data->suspend_ctrl0); 10308c2ecf20Sopenharmony_ci mutex_unlock(&data->mutex); 10318c2ecf20Sopenharmony_ci 10328c2ecf20Sopenharmony_ci return ret; 10338c2ecf20Sopenharmony_ci} 10348c2ecf20Sopenharmony_ci#endif /* CONFIG_PM_SLEEP */ 10358c2ecf20Sopenharmony_ci 10368c2ecf20Sopenharmony_cistatic const struct dev_pm_ops sx9500_pm_ops = { 10378c2ecf20Sopenharmony_ci SET_SYSTEM_SLEEP_PM_OPS(sx9500_suspend, sx9500_resume) 10388c2ecf20Sopenharmony_ci}; 10398c2ecf20Sopenharmony_ci 10408c2ecf20Sopenharmony_cistatic const struct acpi_device_id sx9500_acpi_match[] = { 10418c2ecf20Sopenharmony_ci {"SSX9500", 0}, 10428c2ecf20Sopenharmony_ci {"SASX9500", 0}, 10438c2ecf20Sopenharmony_ci { }, 10448c2ecf20Sopenharmony_ci}; 10458c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(acpi, sx9500_acpi_match); 10468c2ecf20Sopenharmony_ci 10478c2ecf20Sopenharmony_cistatic const struct of_device_id sx9500_of_match[] = { 10488c2ecf20Sopenharmony_ci { .compatible = "semtech,sx9500", }, 10498c2ecf20Sopenharmony_ci { } 10508c2ecf20Sopenharmony_ci}; 10518c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, sx9500_of_match); 10528c2ecf20Sopenharmony_ci 10538c2ecf20Sopenharmony_cistatic const struct i2c_device_id sx9500_id[] = { 10548c2ecf20Sopenharmony_ci {"sx9500", 0}, 10558c2ecf20Sopenharmony_ci { }, 10568c2ecf20Sopenharmony_ci}; 10578c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, sx9500_id); 10588c2ecf20Sopenharmony_ci 10598c2ecf20Sopenharmony_cistatic struct i2c_driver sx9500_driver = { 10608c2ecf20Sopenharmony_ci .driver = { 10618c2ecf20Sopenharmony_ci .name = SX9500_DRIVER_NAME, 10628c2ecf20Sopenharmony_ci .acpi_match_table = ACPI_PTR(sx9500_acpi_match), 10638c2ecf20Sopenharmony_ci .of_match_table = of_match_ptr(sx9500_of_match), 10648c2ecf20Sopenharmony_ci .pm = &sx9500_pm_ops, 10658c2ecf20Sopenharmony_ci }, 10668c2ecf20Sopenharmony_ci .probe = sx9500_probe, 10678c2ecf20Sopenharmony_ci .remove = sx9500_remove, 10688c2ecf20Sopenharmony_ci .id_table = sx9500_id, 10698c2ecf20Sopenharmony_ci}; 10708c2ecf20Sopenharmony_cimodule_i2c_driver(sx9500_driver); 10718c2ecf20Sopenharmony_ci 10728c2ecf20Sopenharmony_ciMODULE_AUTHOR("Vlad Dogaru <vlad.dogaru@intel.com>"); 10738c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Driver for Semtech SX9500 proximity sensor"); 10748c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 1075