From fc5d805e12230021de34a072c1d52efbe33cc794 Mon Sep 17 00:00:00 2001 From: Gwendal Grignou Date: Sat, 1 Jan 2022 12:38:13 -0800 Subject: iio:proximity:sx9310: Add frequency in read_avail Instead of using IIO_DEV_ATTR_SAMP_FREQ_AVAIL sysfs attribute, add a _FREQ case in read_avail() to display the frequency table. No change to |sampling_frequency_available| was observed. Signed-off-by: Gwendal Grignou Reviewed-by: Stephen Boyd Link: https://lore.kernel.org/r/20220101203817.290512-2-gwendal@chromium.org Signed-off-by: Jonathan Cameron --- drivers/iio/proximity/sx9310.c | 33 +++++++-------------------------- 1 file changed, 7 insertions(+), 26 deletions(-) diff --git a/drivers/iio/proximity/sx9310.c b/drivers/iio/proximity/sx9310.c index a3fdb59b06d2..1647268b6471 100644 --- a/drivers/iio/proximity/sx9310.c +++ b/drivers/iio/proximity/sx9310.c @@ -196,6 +196,8 @@ static const struct iio_event_spec sx9310_events[] = { .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \ .info_mask_separate_available = \ BIT(IIO_CHAN_INFO_HARDWAREGAIN), \ + .info_mask_shared_by_all_available = \ + BIT(IIO_CHAN_INFO_SAMP_FREQ), \ .indexed = 1, \ .channel = idx, \ .extend_name = name, \ @@ -251,22 +253,6 @@ static const unsigned int sx9310_scan_period_table[] = { 400, 600, 800, 1000, 2000, 3000, 4000, 5000, }; -static ssize_t sx9310_show_samp_freq_avail(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - size_t len = 0; - int i; - - for (i = 0; i < ARRAY_SIZE(sx9310_samp_freq_table); i++) - len += scnprintf(buf + len, PAGE_SIZE - len, "%d.%d ", - sx9310_samp_freq_table[i].val, - sx9310_samp_freq_table[i].val2); - buf[len - 1] = '\n'; - return len; -} -static IIO_DEV_ATTR_SAMP_FREQ_AVAIL(sx9310_show_samp_freq_avail); - static const struct regmap_range sx9310_writable_reg_ranges[] = { regmap_reg_range(SX9310_REG_IRQ_MSK, SX9310_REG_IRQ_FUNC), regmap_reg_range(SX9310_REG_PROX_CTRL0, SX9310_REG_PROX_CTRL19), @@ -562,6 +548,11 @@ static int sx9310_read_avail(struct iio_dev *indio_dev, *length = ARRAY_SIZE(sx9310_gain_vals); *vals = sx9310_gain_vals; return IIO_AVAIL_LIST; + case IIO_CHAN_INFO_SAMP_FREQ: + *type = IIO_VAL_INT_PLUS_MICRO; + *length = ARRAY_SIZE(sx9310_samp_freq_table) * 2; + *vals = (int *)sx9310_samp_freq_table; + return IIO_AVAIL_LIST; } return -EINVAL; @@ -1031,17 +1022,7 @@ out_unlock: return ret; } -static struct attribute *sx9310_attributes[] = { - &iio_dev_attr_sampling_frequency_available.dev_attr.attr, - NULL -}; - -static const struct attribute_group sx9310_attribute_group = { - .attrs = sx9310_attributes, -}; - static const struct iio_info sx9310_info = { - .attrs = &sx9310_attribute_group, .read_raw = sx9310_read_raw, .read_avail = sx9310_read_avail, .read_event_value = sx9310_read_event_val, -- cgit v1.2.3 From caa8ce7f6149576efc3a1af06d2c03e41cb6c46e Mon Sep 17 00:00:00 2001 From: Gwendal Grignou Date: Sat, 1 Jan 2022 12:38:14 -0800 Subject: iio:proximity:sx9310: Extract common Semtech sensor logic Before adding new Semtech sensors, move common logic to all Semtech SAR sensor in its own file: - interface with IIO subsystem, - interrupt management, - channel access conrol, - event processing. The change adds a bidirectional interface between sx93xx and sx_common. The change is quite mechanical, as the impacted functions are moved and renamed. Signed-off-by: Gwendal Grignou Reviewed-by: Stephen Boyd Link: https://lore.kernel.org/r/20220101203817.290512-3-gwendal@chromium.org Signed-off-by: Jonathan Cameron --- drivers/iio/proximity/Kconfig | 6 + drivers/iio/proximity/Makefile | 1 + drivers/iio/proximity/sx9310.c | 712 ++++++-------------------------------- drivers/iio/proximity/sx_common.c | 572 ++++++++++++++++++++++++++++++ drivers/iio/proximity/sx_common.h | 157 +++++++++ 5 files changed, 843 insertions(+), 605 deletions(-) create mode 100644 drivers/iio/proximity/sx_common.c create mode 100644 drivers/iio/proximity/sx_common.h diff --git a/drivers/iio/proximity/Kconfig b/drivers/iio/proximity/Kconfig index 7c7203ca3ac6..027712684835 100644 --- a/drivers/iio/proximity/Kconfig +++ b/drivers/iio/proximity/Kconfig @@ -112,11 +112,17 @@ config SRF04 To compile this driver as a module, choose M here: the module will be called srf04. +config SX_COMMON + tristate + help + Common Semtech proximity sensor code. + config SX9310 tristate "SX9310/SX9311 Semtech proximity sensor" select IIO_BUFFER select IIO_TRIGGERED_BUFFER select REGMAP_I2C + select SX_COMMON depends on I2C help Say Y here to build a driver for Semtech's SX9310/SX9311 capacitive diff --git a/drivers/iio/proximity/Makefile b/drivers/iio/proximity/Makefile index cbdac09433eb..2577fbce4144 100644 --- a/drivers/iio/proximity/Makefile +++ b/drivers/iio/proximity/Makefile @@ -14,6 +14,7 @@ obj-$(CONFIG_RFD77402) += rfd77402.o obj-$(CONFIG_SRF04) += srf04.o obj-$(CONFIG_SRF08) += srf08.o obj-$(CONFIG_SX9310) += sx9310.o +obj-$(CONFIG_SX_COMMON) += sx_common.o obj-$(CONFIG_SX9500) += sx9500.o obj-$(CONFIG_VCNL3020) += vcnl3020.o obj-$(CONFIG_VL53L0X_I2C) += vl53l0x-i2c.o diff --git a/drivers/iio/proximity/sx9310.c b/drivers/iio/proximity/sx9310.c index 1647268b6471..ea7318b508ea 100644 --- a/drivers/iio/proximity/sx9310.c +++ b/drivers/iio/proximity/sx9310.c @@ -10,11 +10,10 @@ * and in January 2020 by Daniel Campello . */ -#include #include #include #include -#include +#include #include #include #include @@ -22,19 +21,12 @@ #include #include #include -#include -#include - -#include -#include #include -#include -#include -#include -#include + +#include "sx_common.h" /* Register definitions. */ -#define SX9310_REG_IRQ_SRC 0x00 +#define SX9310_REG_IRQ_SRC SX_COMMON_REG_IRQ_SRC #define SX9310_REG_STAT0 0x01 #define SX9310_REG_STAT1 0x02 #define SX9310_REG_STAT1_COMPSTAT_MASK GENMASK(3, 0) @@ -135,83 +127,36 @@ #define SX9310_WHOAMI_VALUE 0x01 #define SX9311_WHOAMI_VALUE 0x02 #define SX9310_REG_RESET 0x7f -#define SX9310_SOFT_RESET 0xde /* 4 hardware channels, as defined in STAT0: COMB, CS2, CS1 and CS0. */ #define SX9310_NUM_CHANNELS 4 -static_assert(SX9310_NUM_CHANNELS < BITS_PER_LONG); - -struct sx9310_data { - /* Serialize access to registers and channel configuration */ - struct mutex mutex; - struct i2c_client *client; - struct iio_trigger *trig; - struct regmap *regmap; - struct regulator_bulk_data supplies[2]; - /* - * Last reading of the proximity status for each channel. - * We only send an event to user space when this changes. - */ - unsigned long chan_prox_stat; - bool trigger_enabled; - /* Ensure correct alignment of timestamp when present. */ - struct { - __be16 channels[SX9310_NUM_CHANNELS]; - s64 ts __aligned(8); - } buffer; - /* Remember enabled channels and sample rate during suspend. */ - unsigned int suspend_ctrl0; - struct completion completion; - unsigned long chan_read; - unsigned long chan_event; - unsigned int whoami; -}; - -static const struct iio_event_spec sx9310_events[] = { - { - .type = IIO_EV_TYPE_THRESH, - .dir = IIO_EV_DIR_RISING, - .mask_shared_by_all = BIT(IIO_EV_INFO_PERIOD), - }, - { - .type = IIO_EV_TYPE_THRESH, - .dir = IIO_EV_DIR_FALLING, - .mask_shared_by_all = BIT(IIO_EV_INFO_PERIOD), - }, - { - .type = IIO_EV_TYPE_THRESH, - .dir = IIO_EV_DIR_EITHER, - .mask_separate = BIT(IIO_EV_INFO_ENABLE) | - BIT(IIO_EV_INFO_HYSTERESIS) | - BIT(IIO_EV_INFO_VALUE), - }, -}; - -#define SX9310_NAMED_CHANNEL(idx, name) \ - { \ - .type = IIO_PROXIMITY, \ - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ - BIT(IIO_CHAN_INFO_HARDWAREGAIN), \ - .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \ - .info_mask_separate_available = \ - BIT(IIO_CHAN_INFO_HARDWAREGAIN), \ - .info_mask_shared_by_all_available = \ - BIT(IIO_CHAN_INFO_SAMP_FREQ), \ - .indexed = 1, \ - .channel = idx, \ - .extend_name = name, \ - .address = SX9310_REG_DIFF_MSB, \ - .event_spec = sx9310_events, \ - .num_event_specs = ARRAY_SIZE(sx9310_events), \ - .scan_index = idx, \ - .scan_type = { \ - .sign = 's', \ - .realbits = 12, \ - .storagebits = 16, \ - .endianness = IIO_BE, \ - }, \ - } +static_assert(SX9310_NUM_CHANNELS <= SX_COMMON_MAX_NUM_CHANNELS); + +#define SX9310_NAMED_CHANNEL(idx, name) \ +{ \ + .type = IIO_PROXIMITY, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_HARDWAREGAIN), \ + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \ + .info_mask_separate_available = \ + BIT(IIO_CHAN_INFO_HARDWAREGAIN), \ + .info_mask_shared_by_all_available = \ + BIT(IIO_CHAN_INFO_SAMP_FREQ), \ + .indexed = 1, \ + .channel = idx, \ + .extend_name = name, \ + .address = SX9310_REG_DIFF_MSB, \ + .event_spec = sx_common_events, \ + .num_event_specs = ARRAY_SIZE(sx_common_events), \ + .scan_index = idx, \ + .scan_type = { \ + .sign = 's', \ + .realbits = 12, \ + .storagebits = 16, \ + .endianness = IIO_BE, \ + }, \ +} #define SX9310_CHANNEL(idx) SX9310_NAMED_CHANNEL(idx, NULL) static const struct iio_chan_spec sx9310_channels[] = { @@ -306,64 +251,7 @@ static const struct regmap_config sx9310_regmap_config = { .volatile_table = &sx9310_volatile_regs, }; -static int sx9310_update_chan_en(struct sx9310_data *data, - unsigned long chan_read, - unsigned long chan_event) -{ - int ret; - unsigned long channels = chan_read | chan_event; - - if ((data->chan_read | data->chan_event) != channels) { - ret = regmap_update_bits(data->regmap, SX9310_REG_PROX_CTRL0, - SX9310_REG_PROX_CTRL0_SENSOREN_MASK, - channels); - if (ret) - return ret; - } - data->chan_read = chan_read; - data->chan_event = chan_event; - return 0; -} - -static int sx9310_get_read_channel(struct sx9310_data *data, int channel) -{ - return sx9310_update_chan_en(data, data->chan_read | BIT(channel), - data->chan_event); -} - -static int sx9310_put_read_channel(struct sx9310_data *data, int channel) -{ - return sx9310_update_chan_en(data, data->chan_read & ~BIT(channel), - data->chan_event); -} - -static int sx9310_get_event_channel(struct sx9310_data *data, int channel) -{ - return sx9310_update_chan_en(data, data->chan_read, - data->chan_event | BIT(channel)); -} - -static int sx9310_put_event_channel(struct sx9310_data *data, int channel) -{ - return sx9310_update_chan_en(data, data->chan_read, - data->chan_event & ~BIT(channel)); -} - -static int sx9310_enable_irq(struct sx9310_data *data, unsigned int irq) -{ - if (!data->client->irq) - return 0; - return regmap_update_bits(data->regmap, SX9310_REG_IRQ_MSK, irq, irq); -} - -static int sx9310_disable_irq(struct sx9310_data *data, unsigned int irq) -{ - if (!data->client->irq) - return 0; - return regmap_update_bits(data->regmap, SX9310_REG_IRQ_MSK, irq, 0); -} - -static int sx9310_read_prox_data(struct sx9310_data *data, +static int sx9310_read_prox_data(struct sx_common_data *data, const struct iio_chan_spec *chan, __be16 *val) { int ret; @@ -379,7 +267,7 @@ static int sx9310_read_prox_data(struct sx9310_data *data, * If we have no interrupt support, we have to wait for a scan period * after enabling a channel to get a result. */ -static int sx9310_wait_for_sample(struct sx9310_data *data) +static int sx9310_wait_for_sample(struct sx_common_data *data) { int ret; unsigned int val; @@ -395,66 +283,7 @@ static int sx9310_wait_for_sample(struct sx9310_data *data) return 0; } -static int sx9310_read_proximity(struct sx9310_data *data, - const struct iio_chan_spec *chan, int *val) -{ - int ret; - __be16 rawval; - - mutex_lock(&data->mutex); - - ret = sx9310_get_read_channel(data, chan->channel); - if (ret) - goto out; - - ret = sx9310_enable_irq(data, SX9310_CONVDONE_IRQ); - if (ret) - goto out_put_channel; - - mutex_unlock(&data->mutex); - - if (data->client->irq) { - ret = wait_for_completion_interruptible(&data->completion); - reinit_completion(&data->completion); - } else { - ret = sx9310_wait_for_sample(data); - } - - mutex_lock(&data->mutex); - - if (ret) - goto out_disable_irq; - - ret = sx9310_read_prox_data(data, chan, &rawval); - if (ret) - goto out_disable_irq; - - *val = sign_extend32(be16_to_cpu(rawval), - chan->address == SX9310_REG_DIFF_MSB ? 11 : 15); - - ret = sx9310_disable_irq(data, SX9310_CONVDONE_IRQ); - if (ret) - goto out_put_channel; - - ret = sx9310_put_read_channel(data, chan->channel); - if (ret) - goto out; - - mutex_unlock(&data->mutex); - - return IIO_VAL_INT; - -out_disable_irq: - sx9310_disable_irq(data, SX9310_CONVDONE_IRQ); -out_put_channel: - sx9310_put_read_channel(data, chan->channel); -out: - mutex_unlock(&data->mutex); - - return ret; -} - -static int sx9310_read_gain(struct sx9310_data *data, +static int sx9310_read_gain(struct sx_common_data *data, const struct iio_chan_spec *chan, int *val) { unsigned int regval, gain; @@ -482,7 +311,7 @@ static int sx9310_read_gain(struct sx9310_data *data, return IIO_VAL_INT; } -static int sx9310_read_samp_freq(struct sx9310_data *data, int *val, int *val2) +static int sx9310_read_samp_freq(struct sx_common_data *data, int *val, int *val2) { unsigned int regval; int ret; @@ -502,7 +331,7 @@ static int sx9310_read_raw(struct iio_dev *indio_dev, const struct iio_chan_spec *chan, int *val, int *val2, long mask) { - struct sx9310_data *data = iio_priv(indio_dev); + struct sx_common_data *data = iio_priv(indio_dev); int ret; if (chan->type != IIO_PROXIMITY) @@ -514,7 +343,7 @@ static int sx9310_read_raw(struct iio_dev *indio_dev, if (ret) return ret; - ret = sx9310_read_proximity(data, chan, val); + ret = sx_common_read_proximity(data, chan, val); iio_device_release_direct_mode(indio_dev); return ret; case IIO_CHAN_INFO_HARDWAREGAIN: @@ -553,9 +382,9 @@ static int sx9310_read_avail(struct iio_dev *indio_dev, *length = ARRAY_SIZE(sx9310_samp_freq_table) * 2; *vals = (int *)sx9310_samp_freq_table; return IIO_AVAIL_LIST; + default: + return -EINVAL; } - - return -EINVAL; } static const unsigned int sx9310_pthresh_codes[] = { @@ -572,12 +401,12 @@ static int sx9310_get_thresh_reg(unsigned int channel) case 1: case 2: return SX9310_REG_PROX_CTRL9; + default: + return -EINVAL; } - - return -EINVAL; } -static int sx9310_read_thresh(struct sx9310_data *data, +static int sx9310_read_thresh(struct sx_common_data *data, const struct iio_chan_spec *chan, int *val) { unsigned int reg; @@ -600,7 +429,7 @@ static int sx9310_read_thresh(struct sx9310_data *data, return IIO_VAL_INT; } -static int sx9310_read_hysteresis(struct sx9310_data *data, +static int sx9310_read_hysteresis(struct sx_common_data *data, const struct iio_chan_spec *chan, int *val) { unsigned int regval, pthresh; @@ -624,7 +453,7 @@ static int sx9310_read_hysteresis(struct sx9310_data *data, return IIO_VAL_INT; } -static int sx9310_read_far_debounce(struct sx9310_data *data, int *val) +static int sx9310_read_far_debounce(struct sx_common_data *data, int *val) { unsigned int regval; int ret; @@ -642,7 +471,7 @@ static int sx9310_read_far_debounce(struct sx9310_data *data, int *val) return IIO_VAL_INT; } -static int sx9310_read_close_debounce(struct sx9310_data *data, int *val) +static int sx9310_read_close_debounce(struct sx_common_data *data, int *val) { unsigned int regval; int ret; @@ -666,7 +495,7 @@ static int sx9310_read_event_val(struct iio_dev *indio_dev, enum iio_event_direction dir, enum iio_event_info info, int *val, int *val2) { - struct sx9310_data *data = iio_priv(indio_dev); + struct sx_common_data *data = iio_priv(indio_dev); if (chan->type != IIO_PROXIMITY) return -EINVAL; @@ -690,7 +519,7 @@ static int sx9310_read_event_val(struct iio_dev *indio_dev, } } -static int sx9310_write_thresh(struct sx9310_data *data, +static int sx9310_write_thresh(struct sx_common_data *data, const struct iio_chan_spec *chan, int val) { unsigned int reg; @@ -720,7 +549,7 @@ static int sx9310_write_thresh(struct sx9310_data *data, return ret; } -static int sx9310_write_hysteresis(struct sx9310_data *data, +static int sx9310_write_hysteresis(struct sx_common_data *data, const struct iio_chan_spec *chan, int _val) { unsigned int hyst, val = _val; @@ -750,7 +579,7 @@ static int sx9310_write_hysteresis(struct sx9310_data *data, return ret; } -static int sx9310_write_far_debounce(struct sx9310_data *data, int val) +static int sx9310_write_far_debounce(struct sx_common_data *data, int val) { int ret; unsigned int regval; @@ -771,7 +600,7 @@ static int sx9310_write_far_debounce(struct sx9310_data *data, int val) return ret; } -static int sx9310_write_close_debounce(struct sx9310_data *data, int val) +static int sx9310_write_close_debounce(struct sx_common_data *data, int val) { int ret; unsigned int regval; @@ -798,7 +627,7 @@ static int sx9310_write_event_val(struct iio_dev *indio_dev, enum iio_event_direction dir, enum iio_event_info info, int val, int val2) { - struct sx9310_data *data = iio_priv(indio_dev); + struct sx_common_data *data = iio_priv(indio_dev); if (chan->type != IIO_PROXIMITY) return -EINVAL; @@ -822,7 +651,7 @@ static int sx9310_write_event_val(struct iio_dev *indio_dev, } } -static int sx9310_set_samp_freq(struct sx9310_data *data, int val, int val2) +static int sx9310_set_samp_freq(struct sx_common_data *data, int val, int val2) { int i, ret; @@ -846,8 +675,8 @@ static int sx9310_set_samp_freq(struct sx9310_data *data, int val, int val2) return ret; } -static int sx9310_write_gain(struct sx9310_data *data, - const struct iio_chan_spec *chan, int val) +static int sx9310_write_gain(struct sx_common_data *data, + const struct iio_chan_spec *chan, int val) { unsigned int gain, mask; int ret; @@ -881,7 +710,7 @@ static int sx9310_write_raw(struct iio_dev *indio_dev, const struct iio_chan_spec *chan, int val, int val2, long mask) { - struct sx9310_data *data = iio_priv(indio_dev); + struct sx_common_data *data = iio_priv(indio_dev); if (chan->type != IIO_PROXIMITY) return -EINVAL; @@ -891,243 +720,12 @@ static int sx9310_write_raw(struct iio_dev *indio_dev, return sx9310_set_samp_freq(data, val, val2); case IIO_CHAN_INFO_HARDWAREGAIN: return sx9310_write_gain(data, chan, val); + default: + return -EINVAL; } - - return -EINVAL; -} - -static irqreturn_t sx9310_irq_handler(int irq, void *private) -{ - struct iio_dev *indio_dev = private; - struct sx9310_data *data = iio_priv(indio_dev); - - if (data->trigger_enabled) - iio_trigger_poll(data->trig); - - /* - * Even if no event is enabled, we need to wake the thread to clear the - * interrupt state by reading SX9310_REG_IRQ_SRC. - * It is not possible to do that here because regmap_read takes a mutex. - */ - return IRQ_WAKE_THREAD; -} - -static void sx9310_push_events(struct iio_dev *indio_dev) -{ - int ret; - unsigned int val, chan; - struct sx9310_data *data = iio_priv(indio_dev); - s64 timestamp = iio_get_time_ns(indio_dev); - unsigned long prox_changed; - - /* Read proximity state on all channels */ - ret = regmap_read(data->regmap, SX9310_REG_STAT0, &val); - if (ret) { - dev_err(&data->client->dev, "i2c transfer error in irq\n"); - return; - } - - /* - * Only iterate over channels with changes on proximity status that have - * events enabled. - */ - prox_changed = (data->chan_prox_stat ^ val) & data->chan_event; - - for_each_set_bit(chan, &prox_changed, SX9310_NUM_CHANNELS) { - int dir; - u64 ev; - - dir = (val & BIT(chan)) ? IIO_EV_DIR_FALLING : IIO_EV_DIR_RISING; - ev = IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, chan, - IIO_EV_TYPE_THRESH, dir); - - iio_push_event(indio_dev, ev, timestamp); - } - data->chan_prox_stat = val; -} - -static irqreturn_t sx9310_irq_thread_handler(int irq, void *private) -{ - struct iio_dev *indio_dev = private; - struct sx9310_data *data = iio_priv(indio_dev); - int ret; - unsigned int val; - - mutex_lock(&data->mutex); - - ret = regmap_read(data->regmap, SX9310_REG_IRQ_SRC, &val); - if (ret) { - dev_err(&data->client->dev, "i2c transfer error in irq\n"); - goto out; - } - - if (val & (SX9310_FAR_IRQ | SX9310_CLOSE_IRQ)) - sx9310_push_events(indio_dev); - - if (val & SX9310_CONVDONE_IRQ) - complete(&data->completion); - -out: - mutex_unlock(&data->mutex); - - return IRQ_HANDLED; -} - -static int sx9310_read_event_config(struct iio_dev *indio_dev, - const struct iio_chan_spec *chan, - enum iio_event_type type, - enum iio_event_direction dir) -{ - struct sx9310_data *data = iio_priv(indio_dev); - - return !!(data->chan_event & BIT(chan->channel)); -} - -static int sx9310_write_event_config(struct iio_dev *indio_dev, - const struct iio_chan_spec *chan, - enum iio_event_type type, - enum iio_event_direction dir, int state) -{ - struct sx9310_data *data = iio_priv(indio_dev); - unsigned int eventirq = SX9310_FAR_IRQ | SX9310_CLOSE_IRQ; - int ret; - - /* If the state hasn't changed, there's nothing to do. */ - if (!!(data->chan_event & BIT(chan->channel)) == state) - return 0; - - mutex_lock(&data->mutex); - if (state) { - ret = sx9310_get_event_channel(data, chan->channel); - if (ret) - goto out_unlock; - if (!(data->chan_event & ~BIT(chan->channel))) { - ret = sx9310_enable_irq(data, eventirq); - if (ret) - sx9310_put_event_channel(data, chan->channel); - } - } else { - ret = sx9310_put_event_channel(data, chan->channel); - if (ret) - goto out_unlock; - if (!data->chan_event) { - ret = sx9310_disable_irq(data, eventirq); - if (ret) - sx9310_get_event_channel(data, chan->channel); - } - } - -out_unlock: - mutex_unlock(&data->mutex); - return ret; -} - -static const struct iio_info sx9310_info = { - .read_raw = sx9310_read_raw, - .read_avail = sx9310_read_avail, - .read_event_value = sx9310_read_event_val, - .write_event_value = sx9310_write_event_val, - .write_raw = sx9310_write_raw, - .read_event_config = sx9310_read_event_config, - .write_event_config = sx9310_write_event_config, -}; - -static int sx9310_set_trigger_state(struct iio_trigger *trig, bool state) -{ - struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig); - struct sx9310_data *data = iio_priv(indio_dev); - int ret = 0; - - mutex_lock(&data->mutex); - - if (state) - ret = sx9310_enable_irq(data, SX9310_CONVDONE_IRQ); - else if (!data->chan_read) - ret = sx9310_disable_irq(data, SX9310_CONVDONE_IRQ); - if (ret) - goto out; - - data->trigger_enabled = state; - -out: - mutex_unlock(&data->mutex); - - return ret; -} - -static const struct iio_trigger_ops sx9310_trigger_ops = { - .set_trigger_state = sx9310_set_trigger_state, -}; - -static irqreturn_t sx9310_trigger_handler(int irq, void *private) -{ - struct iio_poll_func *pf = private; - struct iio_dev *indio_dev = pf->indio_dev; - struct sx9310_data *data = iio_priv(indio_dev); - __be16 val; - int bit, ret, i = 0; - - mutex_lock(&data->mutex); - - for_each_set_bit(bit, indio_dev->active_scan_mask, - indio_dev->masklength) { - ret = sx9310_read_prox_data(data, &indio_dev->channels[bit], - &val); - if (ret) - goto out; - - data->buffer.channels[i++] = val; - } - - iio_push_to_buffers_with_timestamp(indio_dev, &data->buffer, - pf->timestamp); - -out: - mutex_unlock(&data->mutex); - - iio_trigger_notify_done(indio_dev->trig); - - return IRQ_HANDLED; -} - -static int sx9310_buffer_preenable(struct iio_dev *indio_dev) -{ - struct sx9310_data *data = iio_priv(indio_dev); - unsigned long channels = 0; - int bit, ret; - - mutex_lock(&data->mutex); - for_each_set_bit(bit, indio_dev->active_scan_mask, - indio_dev->masklength) - __set_bit(indio_dev->channels[bit].channel, &channels); - - ret = sx9310_update_chan_en(data, channels, data->chan_event); - mutex_unlock(&data->mutex); - return ret; -} - -static int sx9310_buffer_postdisable(struct iio_dev *indio_dev) -{ - struct sx9310_data *data = iio_priv(indio_dev); - int ret; - - mutex_lock(&data->mutex); - ret = sx9310_update_chan_en(data, 0, data->chan_event); - mutex_unlock(&data->mutex); - return ret; } -static const struct iio_buffer_setup_ops sx9310_buffer_setup_ops = { - .preenable = sx9310_buffer_preenable, - .postdisable = sx9310_buffer_postdisable, -}; - -struct sx9310_reg_default { - u8 reg; - u8 def; -}; - -static const struct sx9310_reg_default sx9310_default_regs[] = { +static const struct sx_common_reg_default sx9310_default_regs[] = { { SX9310_REG_IRQ_MSK, 0x00 }, { SX9310_REG_IRQ_FUNC, 0x00 }, /* @@ -1172,7 +770,7 @@ static const struct sx9310_reg_default sx9310_default_regs[] = { /* Activate all channels and perform an initial compensation. */ static int sx9310_init_compensation(struct iio_dev *indio_dev) { - struct sx9310_data *data = iio_priv(indio_dev); + struct sx_common_data *data = iio_priv(indio_dev); int ret; unsigned int val; unsigned int ctrl0; @@ -1190,21 +788,16 @@ static int sx9310_init_compensation(struct iio_dev *indio_dev) ret = regmap_read_poll_timeout(data->regmap, SX9310_REG_STAT1, val, !(val & SX9310_REG_STAT1_COMPSTAT_MASK), 20000, 2000000); - if (ret) { - if (ret == -ETIMEDOUT) - dev_err(&data->client->dev, - "initial compensation timed out: 0x%02x\n", - val); + if (ret) return ret; - } regmap_write(data->regmap, SX9310_REG_PROX_CTRL0, ctrl0); return ret; } -static const struct sx9310_reg_default * +static const struct sx_common_reg_default * sx9310_get_default_reg(struct device *dev, int idx, - struct sx9310_reg_default *reg_def) + struct sx_common_reg_default *reg_def) { u32 combined[SX9310_NUM_CHANNELS]; u32 start = 0, raw = 0, pos = 0; @@ -1305,47 +898,21 @@ sx9310_get_default_reg(struct device *dev, int idx, return reg_def; } -static int sx9310_init_device(struct iio_dev *indio_dev) +static int sx9310_check_whoami(struct device *dev, + struct iio_dev *indio_dev) { - struct sx9310_data *data = iio_priv(indio_dev); - struct sx9310_reg_default tmp; - const struct sx9310_reg_default *initval; + struct sx_common_data *data = iio_priv(indio_dev); + unsigned int long ddata; + unsigned int whoami; int ret; - unsigned int i, val; - ret = regmap_write(data->regmap, SX9310_REG_RESET, SX9310_SOFT_RESET); + ret = regmap_read(data->regmap, SX9310_REG_WHOAMI, &whoami); if (ret) return ret; - usleep_range(1000, 2000); /* power-up time is ~1ms. */ - - /* Clear reset interrupt state by reading SX9310_REG_IRQ_SRC. */ - ret = regmap_read(data->regmap, SX9310_REG_IRQ_SRC, &val); - if (ret) - return ret; - - /* Program some sane defaults. */ - for (i = 0; i < ARRAY_SIZE(sx9310_default_regs); i++) { - initval = sx9310_get_default_reg(&indio_dev->dev, i, &tmp); - ret = regmap_write(data->regmap, initval->reg, initval->def); - if (ret) - return ret; - } - - return sx9310_init_compensation(indio_dev); -} - -static int sx9310_set_indio_dev_name(struct device *dev, - struct iio_dev *indio_dev, - unsigned int whoami) -{ - unsigned int long ddata; - ddata = (uintptr_t)device_get_match_data(dev); - if (ddata != whoami) { - dev_err(dev, "WHOAMI does not match device data: %u\n", whoami); - return -ENODEV; - } + if (ddata != whoami) + return -EINVAL; switch (whoami) { case SX9310_WHOAMI_VALUE: @@ -1355,115 +922,52 @@ static int sx9310_set_indio_dev_name(struct device *dev, indio_dev->name = "sx9311"; break; default: - dev_err(dev, "unexpected WHOAMI response: %u\n", whoami); return -ENODEV; } return 0; } -static void sx9310_regulator_disable(void *_data) -{ - struct sx9310_data *data = _data; +static const struct sx_common_chip_info sx9310_chip_info = { + .reg_stat = SX9310_REG_STAT0, + .reg_irq_msk = SX9310_REG_IRQ_MSK, + .reg_enable_chan = SX9310_REG_PROX_CTRL0, + .reg_reset = SX9310_REG_RESET, + + .mask_enable_chan = SX9310_REG_STAT1_COMPSTAT_MASK, + .irq_msk_offset = 3, + .num_channels = SX9310_NUM_CHANNELS, + .num_default_regs = ARRAY_SIZE(sx9310_default_regs), + + .ops = { + .read_prox_data = sx9310_read_prox_data, + .check_whoami = sx9310_check_whoami, + .init_compensation = sx9310_init_compensation, + .wait_for_sample = sx9310_wait_for_sample, + .get_default_reg = sx9310_get_default_reg, + }, - regulator_bulk_disable(ARRAY_SIZE(data->supplies), data->supplies); -} + .iio_channels = sx9310_channels, + .num_iio_channels = ARRAY_SIZE(sx9310_channels), + .iio_info = { + .read_raw = sx9310_read_raw, + .read_avail = sx9310_read_avail, + .read_event_value = sx9310_read_event_val, + .write_event_value = sx9310_write_event_val, + .write_raw = sx9310_write_raw, + .read_event_config = sx_common_read_event_config, + .write_event_config = sx_common_write_event_config, + }, +}; static int sx9310_probe(struct i2c_client *client) { - int ret; - struct device *dev = &client->dev; - struct iio_dev *indio_dev; - struct sx9310_data *data; - - indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); - if (!indio_dev) - return -ENOMEM; - - data = iio_priv(indio_dev); - data->client = client; - data->supplies[0].supply = "vdd"; - data->supplies[1].supply = "svdd"; - mutex_init(&data->mutex); - init_completion(&data->completion); - - data->regmap = devm_regmap_init_i2c(client, &sx9310_regmap_config); - if (IS_ERR(data->regmap)) - return PTR_ERR(data->regmap); - - ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(data->supplies), - data->supplies); - if (ret) - return ret; - - ret = regulator_bulk_enable(ARRAY_SIZE(data->supplies), data->supplies); - if (ret) - return ret; - /* Must wait for Tpor time after initial power up */ - usleep_range(1000, 1100); - - ret = devm_add_action_or_reset(dev, sx9310_regulator_disable, data); - if (ret) - return ret; - - ret = regmap_read(data->regmap, SX9310_REG_WHOAMI, &data->whoami); - if (ret) { - dev_err(dev, "error in reading WHOAMI register: %d", ret); - return ret; - } - - ret = sx9310_set_indio_dev_name(dev, indio_dev, data->whoami); - if (ret) - return ret; - - ACPI_COMPANION_SET(&indio_dev->dev, ACPI_COMPANION(dev)); - indio_dev->channels = sx9310_channels; - indio_dev->num_channels = ARRAY_SIZE(sx9310_channels); - indio_dev->info = &sx9310_info; - indio_dev->modes = INDIO_DIRECT_MODE; - i2c_set_clientdata(client, indio_dev); - - ret = sx9310_init_device(indio_dev); - if (ret) - return ret; - - if (client->irq) { - ret = devm_request_threaded_irq(dev, client->irq, - sx9310_irq_handler, - sx9310_irq_thread_handler, - IRQF_ONESHOT, - "sx9310_event", indio_dev); - if (ret) - return ret; - - data->trig = devm_iio_trigger_alloc(dev, "%s-dev%d", - indio_dev->name, - iio_device_id(indio_dev)); - if (!data->trig) - return -ENOMEM; - - data->trig->ops = &sx9310_trigger_ops; - iio_trigger_set_drvdata(data->trig, indio_dev); - - ret = devm_iio_trigger_register(dev, data->trig); - if (ret) - return ret; - } - - ret = devm_iio_triggered_buffer_setup(dev, indio_dev, - iio_pollfunc_store_time, - sx9310_trigger_handler, - &sx9310_buffer_setup_ops); - if (ret) - return ret; - - return devm_iio_device_register(dev, indio_dev); + return sx_common_probe(client, &sx9310_chip_info, &sx9310_regmap_config); } static int __maybe_unused sx9310_suspend(struct device *dev) { - struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); - struct sx9310_data *data = iio_priv(indio_dev); + struct sx_common_data *data = iio_priv(dev_get_drvdata(dev)); u8 ctrl0; int ret; @@ -1471,11 +975,11 @@ static int __maybe_unused sx9310_suspend(struct device *dev) mutex_lock(&data->mutex); ret = regmap_read(data->regmap, SX9310_REG_PROX_CTRL0, - &data->suspend_ctrl0); + &data->suspend_ctrl); if (ret) goto out; - ctrl0 = data->suspend_ctrl0 & ~SX9310_REG_PROX_CTRL0_SENSOREN_MASK; + ctrl0 = data->suspend_ctrl & ~SX9310_REG_PROX_CTRL0_SENSOREN_MASK; ret = regmap_write(data->regmap, SX9310_REG_PROX_CTRL0, ctrl0); if (ret) goto out; @@ -1489,8 +993,7 @@ out: static int __maybe_unused sx9310_resume(struct device *dev) { - struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); - struct sx9310_data *data = iio_priv(indio_dev); + struct sx_common_data *data = iio_priv(dev_get_drvdata(dev)); int ret; mutex_lock(&data->mutex); @@ -1499,7 +1002,7 @@ static int __maybe_unused sx9310_resume(struct device *dev) goto out; ret = regmap_write(data->regmap, SX9310_REG_PROX_CTRL0, - data->suspend_ctrl0); + data->suspend_ctrl); out: mutex_unlock(&data->mutex); @@ -1510,9 +1013,7 @@ out: return 0; } -static const struct dev_pm_ops sx9310_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(sx9310_suspend, sx9310_resume) -}; +static SIMPLE_DEV_PM_OPS(sx9310_pm_ops, sx9310_suspend, sx9310_resume); static const struct acpi_device_id sx9310_acpi_match[] = { { "STH9310", SX9310_WHOAMI_VALUE }, @@ -1558,3 +1059,4 @@ MODULE_AUTHOR("Gwendal Grignou "); MODULE_AUTHOR("Daniel Campello "); MODULE_DESCRIPTION("Driver for Semtech SX9310/SX9311 proximity sensor"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS(SEMTECH_PROX); diff --git a/drivers/iio/proximity/sx_common.c b/drivers/iio/proximity/sx_common.c new file mode 100644 index 000000000000..ac8fd5920481 --- /dev/null +++ b/drivers/iio/proximity/sx_common.c @@ -0,0 +1,572 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2021 Google LLC. + * + * Common part of most Semtech SAR sensor. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "sx_common.h" + +/* All Semtech SAR sensors have IRQ bit in the same order. */ +#define SX_COMMON_CONVDONE_IRQ BIT(0) +#define SX_COMMON_FAR_IRQ BIT(2) +#define SX_COMMON_CLOSE_IRQ BIT(3) + +const struct iio_event_spec sx_common_events[3] = { + { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_RISING, + .mask_shared_by_all = BIT(IIO_EV_INFO_PERIOD), + }, + { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_FALLING, + .mask_shared_by_all = BIT(IIO_EV_INFO_PERIOD), + }, + { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_EITHER, + .mask_separate = BIT(IIO_EV_INFO_ENABLE) | + BIT(IIO_EV_INFO_HYSTERESIS) | + BIT(IIO_EV_INFO_VALUE), + }, +}; +EXPORT_SYMBOL_NS_GPL(sx_common_events, SEMTECH_PROX); + +static irqreturn_t sx_common_irq_handler(int irq, void *private) +{ + struct iio_dev *indio_dev = private; + struct sx_common_data *data = iio_priv(indio_dev); + + if (data->trigger_enabled) + iio_trigger_poll(data->trig); + + /* + * Even if no event is enabled, we need to wake the thread to clear the + * interrupt state by reading SX_COMMON_REG_IRQ_SRC. + * It is not possible to do that here because regmap_read takes a mutex. + */ + return IRQ_WAKE_THREAD; +} + +static void sx_common_push_events(struct iio_dev *indio_dev) +{ + int ret; + unsigned int val, chan; + struct sx_common_data *data = iio_priv(indio_dev); + s64 timestamp = iio_get_time_ns(indio_dev); + unsigned long prox_changed; + + /* Read proximity state on all channels */ + ret = regmap_read(data->regmap, data->chip_info->reg_stat, &val); + if (ret) { + dev_err(&data->client->dev, "i2c transfer error in irq\n"); + return; + } + + val <<= data->chip_info->stat_offset; + + /* + * Only iterate over channels with changes on proximity status that have + * events enabled. + */ + prox_changed = (data->chan_prox_stat ^ val) & data->chan_event; + + for_each_set_bit(chan, &prox_changed, data->chip_info->num_channels) { + int dir; + u64 ev; + + dir = (val & BIT(chan)) ? IIO_EV_DIR_FALLING : IIO_EV_DIR_RISING; + ev = IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, chan, + IIO_EV_TYPE_THRESH, dir); + + iio_push_event(indio_dev, ev, timestamp); + } + data->chan_prox_stat = val; +} + +static int sx_common_enable_irq(struct sx_common_data *data, unsigned int irq) +{ + if (!data->client->irq) + return 0; + return regmap_update_bits(data->regmap, data->chip_info->reg_irq_msk, + irq << data->chip_info->irq_msk_offset, + irq << data->chip_info->irq_msk_offset); +} + +static int sx_common_disable_irq(struct sx_common_data *data, unsigned int irq) +{ + if (!data->client->irq) + return 0; + return regmap_update_bits(data->regmap, data->chip_info->reg_irq_msk, + irq << data->chip_info->irq_msk_offset, 0); +} + +static int sx_common_update_chan_en(struct sx_common_data *data, + unsigned long chan_read, + unsigned long chan_event) +{ + int ret; + unsigned long channels = chan_read | chan_event; + + if ((data->chan_read | data->chan_event) != channels) { + ret = regmap_update_bits(data->regmap, + data->chip_info->reg_enable_chan, + data->chip_info->mask_enable_chan, + channels); + if (ret) + return ret; + } + data->chan_read = chan_read; + data->chan_event = chan_event; + return 0; +} + +static int sx_common_get_read_channel(struct sx_common_data *data, int channel) +{ + return sx_common_update_chan_en(data, data->chan_read | BIT(channel), + data->chan_event); +} + +static int sx_common_put_read_channel(struct sx_common_data *data, int channel) +{ + return sx_common_update_chan_en(data, data->chan_read & ~BIT(channel), + data->chan_event); +} + +static int sx_common_get_event_channel(struct sx_common_data *data, int channel) +{ + return sx_common_update_chan_en(data, data->chan_read, + data->chan_event | BIT(channel)); +} + +static int sx_common_put_event_channel(struct sx_common_data *data, int channel) +{ + return sx_common_update_chan_en(data, data->chan_read, + data->chan_event & ~BIT(channel)); +} + +/** + * sx_common_read_proximity() - Read raw proximity value. + * @data: Internal data + * @chan: Channel to read + * @val: pointer to return read value. + * + * Request a conversion, wait for the sensor to be ready and + * return the raw proximity value. + */ +int sx_common_read_proximity(struct sx_common_data *data, + const struct iio_chan_spec *chan, int *val) +{ + int ret; + __be16 rawval; + + mutex_lock(&data->mutex); + + ret = sx_common_get_read_channel(data, chan->channel); + if (ret) + goto out; + + ret = sx_common_enable_irq(data, SX_COMMON_CONVDONE_IRQ); + if (ret) + goto out_put_channel; + + mutex_unlock(&data->mutex); + + if (data->client->irq) { + ret = wait_for_completion_interruptible(&data->completion); + reinit_completion(&data->completion); + } else { + ret = data->chip_info->ops.wait_for_sample(data); + } + + mutex_lock(&data->mutex); + + if (ret) + goto out_disable_irq; + + ret = data->chip_info->ops.read_prox_data(data, chan, &rawval); + if (ret) + goto out_disable_irq; + + *val = sign_extend32(be16_to_cpu(rawval), chan->scan_type.realbits - 1); + + ret = sx_common_disable_irq(data, SX_COMMON_CONVDONE_IRQ); + if (ret) + goto out_put_channel; + + ret = sx_common_put_read_channel(data, chan->channel); + if (ret) + goto out; + + mutex_unlock(&data->mutex); + + return IIO_VAL_INT; + +out_disable_irq: + sx_common_disable_irq(data, SX_COMMON_CONVDONE_IRQ); +out_put_channel: + sx_common_put_read_channel(data, chan->channel); +out: + mutex_unlock(&data->mutex); + + return ret; +} +EXPORT_SYMBOL_NS_GPL(sx_common_read_proximity, SEMTECH_PROX); + +/** + * sx_common_read_event_config() - Configure event setting. + * @indio_dev: iio device object + * @chan: Channel to read + * @type: Type of event (unused) + * @dir: Direction of event (unused) + * + * return if the given channel is used for event gathering. + */ +int sx_common_read_event_config(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir) +{ + struct sx_common_data *data = iio_priv(indio_dev); + + return !!(data->chan_event & BIT(chan->channel)); +} +EXPORT_SYMBOL_NS_GPL(sx_common_read_event_config, SEMTECH_PROX); + +/** + * sx_common_write_event_config() - Configure event setting. + * @indio_dev: iio device object + * @chan: Channel to enable + * @type: Type of event (unused) + * @dir: Direction of event (unused) + * @state: State of the event. + * + * Enable/Disable event on a given channel. + */ +int sx_common_write_event_config(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, int state) +{ + struct sx_common_data *data = iio_priv(indio_dev); + unsigned int eventirq = SX_COMMON_FAR_IRQ | SX_COMMON_CLOSE_IRQ; + int ret; + + /* If the state hasn't changed, there's nothing to do. */ + if (!!(data->chan_event & BIT(chan->channel)) == state) + return 0; + + mutex_lock(&data->mutex); + if (state) { + ret = sx_common_get_event_channel(data, chan->channel); + if (ret) + goto out_unlock; + if (!(data->chan_event & ~BIT(chan->channel))) { + ret = sx_common_enable_irq(data, eventirq); + if (ret) + sx_common_put_event_channel(data, chan->channel); + } + } else { + ret = sx_common_put_event_channel(data, chan->channel); + if (ret) + goto out_unlock; + if (!data->chan_event) { + ret = sx_common_disable_irq(data, eventirq); + if (ret) + sx_common_get_event_channel(data, chan->channel); + } + } + +out_unlock: + mutex_unlock(&data->mutex); + return ret; +} +EXPORT_SYMBOL_NS_GPL(sx_common_write_event_config, SEMTECH_PROX); + +static int sx_common_set_trigger_state(struct iio_trigger *trig, bool state) +{ + struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig); + struct sx_common_data *data = iio_priv(indio_dev); + int ret = 0; + + mutex_lock(&data->mutex); + + if (state) + ret = sx_common_enable_irq(data, SX_COMMON_CONVDONE_IRQ); + else if (!data->chan_read) + ret = sx_common_disable_irq(data, SX_COMMON_CONVDONE_IRQ); + if (ret) + goto out; + + data->trigger_enabled = state; + +out: + mutex_unlock(&data->mutex); + + return ret; +} + +static const struct iio_trigger_ops sx_common_trigger_ops = { + .set_trigger_state = sx_common_set_trigger_state, +}; + +static irqreturn_t sx_common_irq_thread_handler(int irq, void *private) +{ + struct iio_dev *indio_dev = private; + struct sx_common_data *data = iio_priv(indio_dev); + int ret; + unsigned int val; + + mutex_lock(&data->mutex); + + ret = regmap_read(data->regmap, SX_COMMON_REG_IRQ_SRC, &val); + if (ret) { + dev_err(&data->client->dev, "i2c transfer error in irq\n"); + goto out; + } + + if (val & ((SX_COMMON_FAR_IRQ | SX_COMMON_CLOSE_IRQ) << data->chip_info->irq_msk_offset)) + sx_common_push_events(indio_dev); + + if (val & (SX_COMMON_CONVDONE_IRQ << data->chip_info->irq_msk_offset)) + complete(&data->completion); + +out: + mutex_unlock(&data->mutex); + + return IRQ_HANDLED; +} + +static irqreturn_t sx_common_trigger_handler(int irq, void *private) +{ + struct iio_poll_func *pf = private; + struct iio_dev *indio_dev = pf->indio_dev; + struct sx_common_data *data = iio_priv(indio_dev); + __be16 val; + int bit, ret, i = 0; + + mutex_lock(&data->mutex); + + for_each_set_bit(bit, indio_dev->active_scan_mask, + indio_dev->masklength) { + ret = data->chip_info->ops.read_prox_data(data, + &indio_dev->channels[bit], + &val); + if (ret) + goto out; + + data->buffer.channels[i++] = val; + } + + iio_push_to_buffers_with_timestamp(indio_dev, &data->buffer, + pf->timestamp); + +out: + mutex_unlock(&data->mutex); + + iio_trigger_notify_done(indio_dev->trig); + + return IRQ_HANDLED; +} + +static int sx_common_buffer_preenable(struct iio_dev *indio_dev) +{ + struct sx_common_data *data = iio_priv(indio_dev); + unsigned long channels = 0; + int bit, ret; + + mutex_lock(&data->mutex); + for_each_set_bit(bit, indio_dev->active_scan_mask, + indio_dev->masklength) + __set_bit(indio_dev->channels[bit].channel, &channels); + + ret = sx_common_update_chan_en(data, channels, data->chan_event); + mutex_unlock(&data->mutex); + return ret; +} + +static int sx_common_buffer_postdisable(struct iio_dev *indio_dev) +{ + struct sx_common_data *data = iio_priv(indio_dev); + int ret; + + mutex_lock(&data->mutex); + ret = sx_common_update_chan_en(data, 0, data->chan_event); + mutex_unlock(&data->mutex); + return ret; +} + +static const struct iio_buffer_setup_ops sx_common_buffer_setup_ops = { + .preenable = sx_common_buffer_preenable, + .postdisable = sx_common_buffer_postdisable, +}; + +static void sx_common_regulator_disable(void *_data) +{ + struct sx_common_data *data = _data; + + regulator_bulk_disable(ARRAY_SIZE(data->supplies), data->supplies); +} + +#define SX_COMMON_SOFT_RESET 0xde + +static int sx_common_init_device(struct iio_dev *indio_dev) +{ + struct sx_common_data *data = iio_priv(indio_dev); + struct sx_common_reg_default tmp; + const struct sx_common_reg_default *initval; + int ret; + unsigned int i, val; + + ret = regmap_write(data->regmap, data->chip_info->reg_reset, + SX_COMMON_SOFT_RESET); + if (ret) + return ret; + + usleep_range(1000, 2000); /* power-up time is ~1ms. */ + + /* Clear reset interrupt state by reading SX_COMMON_REG_IRQ_SRC. */ + ret = regmap_read(data->regmap, SX_COMMON_REG_IRQ_SRC, &val); + if (ret) + return ret; + + /* Program defaults from constant or BIOS. */ + for (i = 0; i < data->chip_info->num_default_regs; i++) { + initval = data->chip_info->ops.get_default_reg(&indio_dev->dev, + i, &tmp); + ret = regmap_write(data->regmap, initval->reg, initval->def); + if (ret) + return ret; + } + + return data->chip_info->ops.init_compensation(indio_dev); +} + +/** + * sx_common_probe() - Common setup for Semtech SAR sensor + * @client: I2C client object + * @chip_info: Semtech sensor chip information. + * @regmap_config: Sensor registers map configuration. + */ +int sx_common_probe(struct i2c_client *client, + const struct sx_common_chip_info *chip_info, + const struct regmap_config *regmap_config) +{ + struct device *dev = &client->dev; + struct iio_dev *indio_dev; + struct sx_common_data *data; + int ret; + + indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); + if (!indio_dev) + return -ENOMEM; + + data = iio_priv(indio_dev); + + data->chip_info = chip_info; + data->client = client; + data->supplies[0].supply = "vdd"; + data->supplies[1].supply = "svdd"; + mutex_init(&data->mutex); + init_completion(&data->completion); + + data->regmap = devm_regmap_init_i2c(client, regmap_config); + if (IS_ERR(data->regmap)) + return dev_err_probe(dev, PTR_ERR(data->regmap), + "Could init register map\n"); + + ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(data->supplies), + data->supplies); + if (ret) + return dev_err_probe(dev, ret, "Unable to get regulators\n"); + + ret = regulator_bulk_enable(ARRAY_SIZE(data->supplies), data->supplies); + if (ret) + return dev_err_probe(dev, ret, "Unable to enable regulators\n"); + + /* Must wait for Tpor time after initial power up */ + usleep_range(1000, 1100); + + ret = devm_add_action_or_reset(dev, sx_common_regulator_disable, data); + if (ret) + return dev_err_probe(dev, ret, + "Unable to register regulators deleter\n"); + + ret = data->chip_info->ops.check_whoami(dev, indio_dev); + if (ret) + return dev_err_probe(dev, ret, "error reading WHOAMI\n"); + + ACPI_COMPANION_SET(&indio_dev->dev, ACPI_COMPANION(dev)); + indio_dev->modes = INDIO_DIRECT_MODE; + + indio_dev->channels = data->chip_info->iio_channels; + indio_dev->num_channels = data->chip_info->num_iio_channels; + indio_dev->info = &data->chip_info->iio_info; + + i2c_set_clientdata(client, indio_dev); + + ret = sx_common_init_device(indio_dev); + if (ret) + return dev_err_probe(dev, ret, "Unable to initialize sensor\n"); + + if (client->irq) { + ret = devm_request_threaded_irq(dev, client->irq, + sx_common_irq_handler, + sx_common_irq_thread_handler, + IRQF_ONESHOT, + "sx_event", indio_dev); + if (ret) + return dev_err_probe(dev, ret, "No IRQ\n"); + + data->trig = devm_iio_trigger_alloc(dev, "%s-dev%d", + indio_dev->name, + iio_device_id(indio_dev)); + if (!data->trig) + return -ENOMEM; + + data->trig->ops = &sx_common_trigger_ops; + iio_trigger_set_drvdata(data->trig, indio_dev); + + ret = devm_iio_trigger_register(dev, data->trig); + if (ret) + return ret; + } + + ret = devm_iio_triggered_buffer_setup(dev, indio_dev, + iio_pollfunc_store_time, + sx_common_trigger_handler, + &sx_common_buffer_setup_ops); + if (ret) + return ret; + + return devm_iio_device_register(dev, indio_dev); +} +EXPORT_SYMBOL_NS_GPL(sx_common_probe, SEMTECH_PROX); + +MODULE_AUTHOR("Gwendal Grignou "); +MODULE_DESCRIPTION("Common functions and structures for Semtech sensor"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/proximity/sx_common.h b/drivers/iio/proximity/sx_common.h new file mode 100644 index 000000000000..5d3edeb75f4e --- /dev/null +++ b/drivers/iio/proximity/sx_common.h @@ -0,0 +1,157 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright 2021 Google LLC. + * + * Code shared between most Semtech SAR sensor driver. + */ + +#ifndef IIO_SX_COMMON_H +#define IIO_SX_COMMON_H + +#include +#include +#include +#include + +struct device; +struct i2c_client; +struct regmap_config; +struct sx_common_data; + +#define SX_COMMON_REG_IRQ_SRC 0x00 + +#define SX_COMMON_MAX_NUM_CHANNELS 4 +static_assert(SX_COMMON_MAX_NUM_CHANNELS < BITS_PER_LONG); + +struct sx_common_reg_default { + u8 reg; + u8 def; +}; + +/** + * struct sx_common_ops: function pointers needed by common code + * + * List functions needed by common code to gather information or configure + * the sensor. + * + * @read_prox_data: Function to read raw proximity data. + * @check_whoami: Set device name based on whoami register. + * @init_compensation: Function to set initial compensation. + * @wait_for_sample: When there are no physical IRQ, function to wait for a + * sample to be ready. + * @get_default_reg: Populate the initial value for a given register. + */ +struct sx_common_ops { + int (*read_prox_data)(struct sx_common_data *data, + const struct iio_chan_spec *chan, __be16 *val); + int (*check_whoami)(struct device *dev, struct iio_dev *indio_dev); + int (*init_compensation)(struct iio_dev *indio_dev); + int (*wait_for_sample)(struct sx_common_data *data); + const struct sx_common_reg_default * + (*get_default_reg)(struct device *dev, int idx, + struct sx_common_reg_default *reg_def); +}; + +/** + * struct sx_common_chip_info: Semtech Sensor private chip information + * + * @reg_stat: Main status register address. + * @reg_irq_msk: IRQ mask register address. + * @reg_enable_chan: Address to enable/disable channels. + * Each phase presented by the sensor is an IIO channel.. + * @reg_reset: Reset register address. + * @mask_enable_chan: Mask over the channels bits in the enable channel + * register. + * @stat_offset: Offset to check phase status. + * @irq_msk_offset: Offset to enable interrupt in the IRQ mask + * register. + * @num_channels: Number of channels. + * @num_default_regs: Number of internal registers that can be configured. + * + * @ops: Private functions pointers. + * @iio_channels: Description of exposed iio channels. + * @num_iio_channels: Number of iio_channels. + * @iio_info: iio_info structure for this driver. + */ +struct sx_common_chip_info { + unsigned int reg_stat; + unsigned int reg_irq_msk; + unsigned int reg_enable_chan; + unsigned int reg_reset; + + unsigned int mask_enable_chan; + unsigned int stat_offset; + unsigned int irq_msk_offset; + unsigned int num_channels; + int num_default_regs; + + struct sx_common_ops ops; + + const struct iio_chan_spec *iio_channels; + int num_iio_channels; + struct iio_info iio_info; +}; + +/** + * struct sx_common_data: Semtech Sensor private data structure. + * + * @chip_info: Structure defining sensor internals. + * @mutex: Serialize access to registers and channel configuration. + * @completion: completion object to wait for data acquisition. + * @client: I2C client structure. + * @trig: IIO trigger object. + * @regmap: Register map. + * @num_default_regs: Number of default registers to set at init. + * @supplies: Power supplies object. + * @chan_prox_stat: Last reading of the proximity status for each channel. + * We only send an event to user space when this changes. + * @trigger_enabled: True when the device trigger is enabled. + * @buffer: Buffer to store raw samples. + * @suspend_ctrl: Remember enabled channels and sample rate during suspend. + * @chan_read: Bit field for each raw channel enabled. + * @chan_event: Bit field for each event enabled. + */ +struct sx_common_data { + const struct sx_common_chip_info *chip_info; + + struct mutex mutex; + struct completion completion; + struct i2c_client *client; + struct iio_trigger *trig; + struct regmap *regmap; + + struct regulator_bulk_data supplies[2]; + unsigned long chan_prox_stat; + bool trigger_enabled; + + /* Ensure correct alignment of timestamp when present. */ + struct { + __be16 channels[SX_COMMON_MAX_NUM_CHANNELS]; + s64 ts __aligned(8); + } buffer; + + unsigned int suspend_ctrl; + unsigned long chan_read; + unsigned long chan_event; +}; + +int sx_common_read_proximity(struct sx_common_data *data, + const struct iio_chan_spec *chan, int *val); + +int sx_common_read_event_config(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir); +int sx_common_write_event_config(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, int state); + +int sx_common_probe(struct i2c_client *client, + const struct sx_common_chip_info *chip_info, + const struct regmap_config *regmap_config); + +/* 3 is the number of events defined by a single phase. */ +extern const struct iio_event_spec sx_common_events[3]; + +#endif /* IIO_SX_COMMON_H */ -- cgit v1.2.3 From 4c18a890dff8d95ca234d184773910383a978d45 Mon Sep 17 00:00:00 2001 From: Gwendal Grignou Date: Sat, 1 Jan 2022 12:38:15 -0800 Subject: iio:proximity:sx9324: Add SX9324 support Semtech SAR sensor SX9324 is an evolution of the SX9310: It has 4 phases that can be configured to capture and process data from any of 3 CS pins and provide independent detection: proximity, table proximity or body proximity. Gather antenna data: echo sx9324-dev3 > trigger/current_trigger echo 1 > scan_elements/in_proximity0_en echo 1 > buffer/enable od -v -An --endian=big -t d2 -w2 /dev/iio\:device3 (at 10Hz, the default). Trigger events: Setting: thresh_falling_period: 2 (events) thresh_rising_period: 2 (events) in_proximity0_thresh_either_value: 300 in_proximity0_thresh_either_hysteresis: 72 using iio_event_monitor /dev/iio\:deviceX, approaching my hand to the antenna pad, I see: ... Event: time: 1634763907532035297, type: proximity, channel: 0, evtype: thresh, direction: falling Event: time: 1634763910138104640, type: proximity, channel: 0, evtype: thresh, direction: rising ... Datasheet: https://edit.wpgdadawant.com/uploads/news_file/program/2019/30184/tech_files/program_30184_suggest_other_file.pdf Signed-off-by: Gwendal Grignou Reviewed-by: Stephen Boyd Link: https://lore.kernel.org/r/20220101203817.290512-4-gwendal@chromium.org Signed-off-by: Jonathan Cameron --- Documentation/ABI/testing/sysfs-bus-iio-sx9324 | 28 + drivers/iio/proximity/Kconfig | 14 + drivers/iio/proximity/Makefile | 1 + drivers/iio/proximity/sx9324.c | 904 +++++++++++++++++++++++++ 4 files changed, 947 insertions(+) create mode 100644 Documentation/ABI/testing/sysfs-bus-iio-sx9324 create mode 100644 drivers/iio/proximity/sx9324.c diff --git a/Documentation/ABI/testing/sysfs-bus-iio-sx9324 b/Documentation/ABI/testing/sysfs-bus-iio-sx9324 new file mode 100644 index 000000000000..632e3321f5a3 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-bus-iio-sx9324 @@ -0,0 +1,28 @@ +What: /sys/bus/iio/devices/iio:deviceX/in_proximity_setup +Date: November 2021 +KernelVersion: 5.17 +Contact: Gwendal Grignou +Description: + SX9324 has 3 inputs, CS0, CS1 and CS2. Hardware layout + defines if the input is + + not connected (HZ), + + grounded (GD), + + connected to an antenna where it can act as a base + (DS - data shield), or measured input (MI). + + The sensor rotates measurement across 4 phases + (PH0, PH1, PH2, PH3), where the inputs are configured + and then measured. + + By default, during the first phase, [PH0], CS0 is measured, + while CS1 and CS2 are used as shields. + `cat in_proximity0_setup` returns "MI,DS,DS". + [PH1], CS1 is measured, CS0 and CS2 are shield: + `cat in_proximity1_setup` returns "DS,MI,DS". + [PH2], CS2 is measured, CS0 and CS1 are shield: + `cat in_proximity1_setup` returns "DS,DS,MI". + [PH3], CS1 and CS2 are measured (combo mode): + `cat in_proximity1_setup` returns "DS,MI,MI". + + Note, these are the chip default. Hardware layout will most + likely dictate different output. The entry is read-only. diff --git a/drivers/iio/proximity/Kconfig b/drivers/iio/proximity/Kconfig index 027712684835..dc66f339e5b1 100644 --- a/drivers/iio/proximity/Kconfig +++ b/drivers/iio/proximity/Kconfig @@ -131,6 +131,20 @@ config SX9310 To compile this driver as a module, choose M here: the module will be called sx9310. +config SX9324 + tristate "SX9324 Semtech proximity sensor" + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER + select REGMAP_I2C + select SX_COMMON + depends on I2C + help + Say Y here to build a driver for Semtech's SX9324 + proximity/button sensor. + + To compile this driver as a module, choose M here: the + module will be called sx9324. + config SX9500 tristate "SX9500 Semtech proximity sensor" select IIO_BUFFER diff --git a/drivers/iio/proximity/Makefile b/drivers/iio/proximity/Makefile index 2577fbce4144..cffe962b3527 100644 --- a/drivers/iio/proximity/Makefile +++ b/drivers/iio/proximity/Makefile @@ -14,6 +14,7 @@ obj-$(CONFIG_RFD77402) += rfd77402.o obj-$(CONFIG_SRF04) += srf04.o obj-$(CONFIG_SRF08) += srf08.o obj-$(CONFIG_SX9310) += sx9310.o +obj-$(CONFIG_SX9324) += sx9324.o obj-$(CONFIG_SX_COMMON) += sx_common.o obj-$(CONFIG_SX9500) += sx9500.o obj-$(CONFIG_VCNL3020) += vcnl3020.o diff --git a/drivers/iio/proximity/sx9324.c b/drivers/iio/proximity/sx9324.c new file mode 100644 index 000000000000..3aeb34b39acb --- /dev/null +++ b/drivers/iio/proximity/sx9324.c @@ -0,0 +1,904 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2021 Google LLC. + * + * Driver for Semtech's SX9324 capacitive proximity/button solution. + * Based on SX9324 driver and copy of datasheet at: + * https://edit.wpgdadawant.com/uploads/news_file/program/2019/30184/tech_files/program_30184_suggest_other_file.pdf + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "sx_common.h" + +/* Register definitions. */ +#define SX9324_REG_IRQ_SRC SX_COMMON_REG_IRQ_SRC +#define SX9324_REG_STAT0 0x01 +#define SX9324_REG_STAT1 0x02 +#define SX9324_REG_STAT2 0x03 +#define SX9324_REG_STAT2_COMPSTAT_MASK GENMASK(3, 0) +#define SX9324_REG_STAT3 0x04 +#define SX9324_REG_IRQ_MSK 0x05 +#define SX9324_CONVDONE_IRQ BIT(3) +#define SX9324_FAR_IRQ BIT(5) +#define SX9324_CLOSE_IRQ BIT(6) +#define SX9324_REG_IRQ_CFG0 0x06 +#define SX9324_REG_IRQ_CFG1 0x07 +#define SX9324_REG_IRQ_CFG1_FAILCOND 0x80 +#define SX9324_REG_IRQ_CFG2 0x08 + +#define SX9324_REG_GNRL_CTRL0 0x10 +#define SX9324_REG_GNRL_CTRL0_SCANPERIOD_MASK GENMASK(4, 0) +#define SX9324_REG_GNRL_CTRL0_SCANPERIOD_100MS 0x16 +#define SX9324_REG_GNRL_CTRL1 0x11 +#define SX9324_REG_GNRL_CTRL1_PHEN_MASK GENMASK(3, 0) +#define SX9324_REG_GNRL_CTRL1_PAUSECTRL 0x20 + +#define SX9324_REG_I2C_ADDR 0x14 +#define SX9324_REG_CLK_SPRD 0x15 + +#define SX9324_REG_AFE_CTRL0 0x20 +#define SX9324_REG_AFE_CTRL1 0x21 +#define SX9324_REG_AFE_CTRL2 0x22 +#define SX9324_REG_AFE_CTRL3 0x23 +#define SX9324_REG_AFE_CTRL4 0x24 +#define SX9324_REG_AFE_CTRL4_FREQ_83_33HZ 0x40 +#define SX9324_REG_AFE_CTRL4_RESOLUTION_MASK GENMASK(2, 0) +#define SX9324_REG_AFE_CTRL4_RES_100 0x04 +#define SX9324_REG_AFE_CTRL5 0x25 +#define SX9324_REG_AFE_CTRL6 0x26 +#define SX9324_REG_AFE_CTRL7 0x27 +#define SX9324_REG_AFE_PH0 0x28 +#define SX9324_REG_AFE_PH0_PIN_MASK(_pin) \ + GENMASK(2 * (_pin) + 1, 2 * (_pin)) + +#define SX9324_REG_AFE_PH1 0x29 +#define SX9324_REG_AFE_PH2 0x2a +#define SX9324_REG_AFE_PH3 0x2b +#define SX9324_REG_AFE_CTRL8 0x2c +#define SX9324_REG_AFE_CTRL8_RESFILTN_4KOHM 0x02 +#define SX9324_REG_AFE_CTRL9 0x2d +#define SX9324_REG_AFE_CTRL9_AGAIN_1 0x08 + +#define SX9324_REG_PROX_CTRL0 0x30 +#define SX9324_REG_PROX_CTRL0_GAIN_MASK GENMASK(5, 3) +#define SX9324_REG_PROX_CTRL0_GAIN_1 0x80 +#define SX9324_REG_PROX_CTRL0_RAWFILT_1P50 0x01 +#define SX9324_REG_PROX_CTRL1 0x31 +#define SX9324_REG_PROX_CTRL2 0x32 +#define SX9324_REG_PROX_CTRL2_AVGNEG_THRESH_16K 0x20 +#define SX9324_REG_PROX_CTRL3 0x33 +#define SX9324_REG_PROX_CTRL3_AVGDEB_2SAMPLES 0x40 +#define SX9324_REG_PROX_CTRL3_AVGPOS_THRESH_16K 0x20 +#define SX9324_REG_PROX_CTRL4 0x34 +#define SX9324_REG_PROX_CTRL4_AVGNEGFILT_MASK GENMASK(5, 3) +#define SX9324_REG_PROX_CTRL4_AVGNEG_FILT_2 0x08 +#define SX9324_REG_PROX_CTRL4_AVGPOSFILT_MASK GENMASK(2, 0) +#define SX9324_REG_PROX_CTRL3_AVGPOS_FILT_256 0x04 +#define SX9324_REG_PROX_CTRL5 0x35 +#define SX9324_REG_PROX_CTRL5_HYST_MASK GENMASK(5, 4) +#define SX9324_REG_PROX_CTRL5_CLOSE_DEBOUNCE_MASK GENMASK(3, 2) +#define SX9324_REG_PROX_CTRL5_FAR_DEBOUNCE_MASK GENMASK(1, 0) +#define SX9324_REG_PROX_CTRL6 0x36 +#define SX9324_REG_PROX_CTRL6_PROXTHRESH_32 0x08 +#define SX9324_REG_PROX_CTRL7 0x37 + +#define SX9324_REG_ADV_CTRL0 0x40 +#define SX9324_REG_ADV_CTRL1 0x41 +#define SX9324_REG_ADV_CTRL2 0x42 +#define SX9324_REG_ADV_CTRL3 0x43 +#define SX9324_REG_ADV_CTRL4 0x44 +#define SX9324_REG_ADV_CTRL5 0x45 +#define SX9324_REG_ADV_CTRL5_STARTUPSENS_MASK GENMASK(3, 2) +#define SX9324_REG_ADV_CTRL5_STARTUP_SENSOR_1 0x04 +#define SX9324_REG_ADV_CTRL5_STARTUP_METHOD_1 0x01 +#define SX9324_REG_ADV_CTRL6 0x46 +#define SX9324_REG_ADV_CTRL7 0x47 +#define SX9324_REG_ADV_CTRL8 0x48 +#define SX9324_REG_ADV_CTRL9 0x49 +#define SX9324_REG_ADV_CTRL10 0x4a +#define SX9324_REG_ADV_CTRL11 0x4b +#define SX9324_REG_ADV_CTRL12 0x4c +#define SX9324_REG_ADV_CTRL13 0x4d +#define SX9324_REG_ADV_CTRL14 0x4e +#define SX9324_REG_ADV_CTRL15 0x4f +#define SX9324_REG_ADV_CTRL16 0x50 +#define SX9324_REG_ADV_CTRL17 0x51 +#define SX9324_REG_ADV_CTRL18 0x52 +#define SX9324_REG_ADV_CTRL19 0x53 +#define SX9324_REG_ADV_CTRL20 0x54 +#define SX9324_REG_ADV_CTRL19_HIGHT_FAILURE_THRESH_SATURATION 0xf0 + +#define SX9324_REG_PHASE_SEL 0x60 + +#define SX9324_REG_USEFUL_MSB 0x61 +#define SX9324_REG_USEFUL_LSB 0x62 + +#define SX9324_REG_AVG_MSB 0x63 +#define SX9324_REG_AVG_LSB 0x64 + +#define SX9324_REG_DIFF_MSB 0x65 +#define SX9324_REG_DIFF_LSB 0x66 + +#define SX9324_REG_OFFSET_MSB 0x67 +#define SX9324_REG_OFFSET_LSB 0x68 + +#define SX9324_REG_SAR_MSB 0x69 +#define SX9324_REG_SAR_LSB 0x6a + +#define SX9324_REG_RESET 0x9f +/* Write this to REG_RESET to do a soft reset. */ +#define SX9324_SOFT_RESET 0xde + +#define SX9324_REG_WHOAMI 0xfa +#define SX9324_WHOAMI_VALUE 0x23 + +#define SX9324_REG_REVISION 0xfe + +/* 4 channels, as defined in STAT0: PH0, PH1, PH2 and PH3. */ +#define SX9324_NUM_CHANNELS 4 +/* 3 CS pins: CS0, CS1, CS2. */ +#define SX9324_NUM_PINS 3 + +static const char * const sx9324_cs_pin_usage[] = { "HZ", "MI", "DS", "GD" }; + +static ssize_t sx9324_phase_configuration_show(struct iio_dev *indio_dev, + uintptr_t private, + const struct iio_chan_spec *chan, + char *buf) +{ + struct sx_common_data *data = iio_priv(indio_dev); + unsigned int val; + int i, ret, pin_idx; + size_t len = 0; + + ret = regmap_read(data->regmap, SX9324_REG_AFE_PH0 + chan->channel, &val); + if (ret < 0) + return ret; + + for (i = 0; i < SX9324_NUM_PINS; i++) { + pin_idx = (val & SX9324_REG_AFE_PH0_PIN_MASK(i)) >> (2 * i); + len += sysfs_emit_at(buf, len, "%s,", + sx9324_cs_pin_usage[pin_idx]); + } + buf[len - 1] = '\n'; + return len; +} + +static const struct iio_chan_spec_ext_info sx9324_channel_ext_info[] = { + { + .name = "setup", + .shared = IIO_SEPARATE, + .read = sx9324_phase_configuration_show, + }, + {} +}; + +#define SX9324_CHANNEL(idx) \ +{ \ + .type = IIO_PROXIMITY, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_HARDWAREGAIN), \ + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \ + .info_mask_separate_available = \ + BIT(IIO_CHAN_INFO_HARDWAREGAIN), \ + .info_mask_shared_by_all_available = \ + BIT(IIO_CHAN_INFO_SAMP_FREQ), \ + .indexed = 1, \ + .channel = idx, \ + .address = SX9324_REG_DIFF_MSB, \ + .event_spec = sx_common_events, \ + .num_event_specs = ARRAY_SIZE(sx_common_events), \ + .scan_index = idx, \ + .scan_type = { \ + .sign = 's', \ + .realbits = 12, \ + .storagebits = 16, \ + .endianness = IIO_BE, \ + }, \ + .ext_info = sx9324_channel_ext_info, \ +} + +static const struct iio_chan_spec sx9324_channels[] = { + SX9324_CHANNEL(0), /* Phase 0 */ + SX9324_CHANNEL(1), /* Phase 1 */ + SX9324_CHANNEL(2), /* Phase 2 */ + SX9324_CHANNEL(3), /* Phase 3 */ + IIO_CHAN_SOFT_TIMESTAMP(4), +}; + +/* + * Each entry contains the integer part (val) and the fractional part, in micro + * seconds. It conforms to the IIO output IIO_VAL_INT_PLUS_MICRO. + */ +static const struct { + int val; + int val2; +} sx9324_samp_freq_table[] = { + { 1000, 0 }, /* 00000: Min (no idle time) */ + { 500, 0 }, /* 00001: 2 ms */ + { 250, 0 }, /* 00010: 4 ms */ + { 166, 666666 }, /* 00011: 6 ms */ + { 125, 0 }, /* 00100: 8 ms */ + { 100, 0 }, /* 00101: 10 ms */ + { 71, 428571 }, /* 00110: 14 ms */ + { 55, 555556 }, /* 00111: 18 ms */ + { 45, 454545 }, /* 01000: 22 ms */ + { 38, 461538 }, /* 01001: 26 ms */ + { 33, 333333 }, /* 01010: 30 ms */ + { 29, 411765 }, /* 01011: 34 ms */ + { 26, 315789 }, /* 01100: 38 ms */ + { 23, 809524 }, /* 01101: 42 ms */ + { 21, 739130 }, /* 01110: 46 ms */ + { 20, 0 }, /* 01111: 50 ms */ + { 17, 857143 }, /* 10000: 56 ms */ + { 16, 129032 }, /* 10001: 62 ms */ + { 14, 705882 }, /* 10010: 68 ms */ + { 13, 513514 }, /* 10011: 74 ms */ + { 12, 500000 }, /* 10100: 80 ms */ + { 11, 111111 }, /* 10101: 90 ms */ + { 10, 0 }, /* 10110: 100 ms (Typ.) */ + { 5, 0 }, /* 10111: 200 ms */ + { 3, 333333 }, /* 11000: 300 ms */ + { 2, 500000 }, /* 11001: 400 ms */ + { 1, 666667 }, /* 11010: 600 ms */ + { 1, 250000 }, /* 11011: 800 ms */ + { 1, 0 }, /* 11100: 1 s */ + { 0, 500000 }, /* 11101: 2 s */ + { 0, 333333 }, /* 11110: 3 s */ + { 0, 250000 }, /* 11111: 4 s */ +}; + +static const unsigned int sx9324_scan_period_table[] = { + 2, 15, 30, 45, 60, 90, 120, 200, + 400, 600, 800, 1000, 2000, 3000, 4000, 5000, +}; + +static const struct regmap_range sx9324_writable_reg_ranges[] = { + /* + * To set COMPSTAT for compensation, even if datasheet says register is + * RO. + */ + regmap_reg_range(SX9324_REG_STAT2, SX9324_REG_STAT2), + regmap_reg_range(SX9324_REG_IRQ_MSK, SX9324_REG_IRQ_CFG2), + regmap_reg_range(SX9324_REG_GNRL_CTRL0, SX9324_REG_GNRL_CTRL1), + /* Leave i2c and clock spreading as unavailable */ + regmap_reg_range(SX9324_REG_AFE_CTRL0, SX9324_REG_AFE_CTRL9), + regmap_reg_range(SX9324_REG_PROX_CTRL0, SX9324_REG_PROX_CTRL7), + regmap_reg_range(SX9324_REG_ADV_CTRL0, SX9324_REG_ADV_CTRL20), + regmap_reg_range(SX9324_REG_PHASE_SEL, SX9324_REG_PHASE_SEL), + regmap_reg_range(SX9324_REG_OFFSET_MSB, SX9324_REG_OFFSET_LSB), + regmap_reg_range(SX9324_REG_RESET, SX9324_REG_RESET), +}; + +static const struct regmap_access_table sx9324_writeable_regs = { + .yes_ranges = sx9324_writable_reg_ranges, + .n_yes_ranges = ARRAY_SIZE(sx9324_writable_reg_ranges), +}; + +/* + * All allocated registers are readable, so we just list unallocated + * ones. + */ +static const struct regmap_range sx9324_non_readable_reg_ranges[] = { + regmap_reg_range(SX9324_REG_IRQ_CFG2 + 1, SX9324_REG_GNRL_CTRL0 - 1), + regmap_reg_range(SX9324_REG_GNRL_CTRL1 + 1, SX9324_REG_AFE_CTRL0 - 1), + regmap_reg_range(SX9324_REG_AFE_CTRL9 + 1, SX9324_REG_PROX_CTRL0 - 1), + regmap_reg_range(SX9324_REG_PROX_CTRL7 + 1, SX9324_REG_ADV_CTRL0 - 1), + regmap_reg_range(SX9324_REG_ADV_CTRL20 + 1, SX9324_REG_PHASE_SEL - 1), + regmap_reg_range(SX9324_REG_SAR_LSB + 1, SX9324_REG_RESET - 1), + regmap_reg_range(SX9324_REG_RESET + 1, SX9324_REG_WHOAMI - 1), + regmap_reg_range(SX9324_REG_WHOAMI + 1, SX9324_REG_REVISION - 1), +}; + +static const struct regmap_access_table sx9324_readable_regs = { + .no_ranges = sx9324_non_readable_reg_ranges, + .n_no_ranges = ARRAY_SIZE(sx9324_non_readable_reg_ranges), +}; + +static const struct regmap_range sx9324_volatile_reg_ranges[] = { + regmap_reg_range(SX9324_REG_IRQ_SRC, SX9324_REG_STAT3), + regmap_reg_range(SX9324_REG_USEFUL_MSB, SX9324_REG_DIFF_LSB), + regmap_reg_range(SX9324_REG_SAR_MSB, SX9324_REG_SAR_LSB), + regmap_reg_range(SX9324_REG_WHOAMI, SX9324_REG_WHOAMI), + regmap_reg_range(SX9324_REG_REVISION, SX9324_REG_REVISION), +}; + +static const struct regmap_access_table sx9324_volatile_regs = { + .yes_ranges = sx9324_volatile_reg_ranges, + .n_yes_ranges = ARRAY_SIZE(sx9324_volatile_reg_ranges), +}; + +static const struct regmap_config sx9324_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + + .max_register = SX9324_REG_REVISION, + .cache_type = REGCACHE_RBTREE, + + .wr_table = &sx9324_writeable_regs, + .rd_table = &sx9324_readable_regs, + .volatile_table = &sx9324_volatile_regs, +}; + +static int sx9324_read_prox_data(struct sx_common_data *data, + const struct iio_chan_spec *chan, + __be16 *val) +{ + int ret; + + ret = regmap_write(data->regmap, SX9324_REG_PHASE_SEL, chan->channel); + if (ret < 0) + return ret; + + return regmap_bulk_read(data->regmap, chan->address, val, sizeof(*val)); +} + +/* + * If we have no interrupt support, we have to wait for a scan period + * after enabling a channel to get a result. + */ +static int sx9324_wait_for_sample(struct sx_common_data *data) +{ + int ret; + unsigned int val; + + ret = regmap_read(data->regmap, SX9324_REG_GNRL_CTRL0, &val); + if (ret < 0) + return ret; + val = FIELD_GET(SX9324_REG_GNRL_CTRL0_SCANPERIOD_MASK, val); + + msleep(sx9324_scan_period_table[val]); + + return 0; +} + +static int sx9324_read_gain(struct sx_common_data *data, + const struct iio_chan_spec *chan, int *val) +{ + unsigned int reg, regval; + int ret; + + reg = SX9324_REG_PROX_CTRL0 + chan->channel / 2; + ret = regmap_read(data->regmap, reg, ®val); + if (ret) + return ret; + + *val = 1 << FIELD_GET(SX9324_REG_PROX_CTRL0_GAIN_MASK, regval); + + return IIO_VAL_INT; +} + +static int sx9324_read_samp_freq(struct sx_common_data *data, + int *val, int *val2) +{ + int ret; + unsigned int regval; + + ret = regmap_read(data->regmap, SX9324_REG_GNRL_CTRL0, ®val); + if (ret) + return ret; + + regval = FIELD_GET(SX9324_REG_GNRL_CTRL0_SCANPERIOD_MASK, regval); + *val = sx9324_samp_freq_table[regval].val; + *val2 = sx9324_samp_freq_table[regval].val2; + + return IIO_VAL_INT_PLUS_MICRO; +} + +static int sx9324_read_raw(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + int *val, int *val2, long mask) +{ + struct sx_common_data *data = iio_priv(indio_dev); + int ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + ret = iio_device_claim_direct_mode(indio_dev); + if (ret) + return ret; + + ret = sx_common_read_proximity(data, chan, val); + iio_device_release_direct_mode(indio_dev); + return ret; + case IIO_CHAN_INFO_HARDWAREGAIN: + ret = iio_device_claim_direct_mode(indio_dev); + if (ret) + return ret; + + ret = sx9324_read_gain(data, chan, val); + iio_device_release_direct_mode(indio_dev); + return ret; + case IIO_CHAN_INFO_SAMP_FREQ: + return sx9324_read_samp_freq(data, val, val2); + default: + return -EINVAL; + } +} + +static const int sx9324_gain_vals[] = { 1, 2, 4, 8 }; + +static int sx9324_read_avail(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + const int **vals, int *type, int *length, + long mask) +{ + if (chan->type != IIO_PROXIMITY) + return -EINVAL; + + switch (mask) { + case IIO_CHAN_INFO_HARDWAREGAIN: + *type = IIO_VAL_INT; + *length = ARRAY_SIZE(sx9324_gain_vals); + *vals = sx9324_gain_vals; + return IIO_AVAIL_LIST; + case IIO_CHAN_INFO_SAMP_FREQ: + *type = IIO_VAL_INT_PLUS_MICRO; + *length = ARRAY_SIZE(sx9324_samp_freq_table) * 2; + *vals = (int *)sx9324_samp_freq_table; + return IIO_AVAIL_LIST; + default: + return -EINVAL; + } +} + +static int sx9324_set_samp_freq(struct sx_common_data *data, + int val, int val2) +{ + int i, ret; + + for (i = 0; i < ARRAY_SIZE(sx9324_samp_freq_table); i++) + if (val == sx9324_samp_freq_table[i].val && + val2 == sx9324_samp_freq_table[i].val2) + break; + + if (i == ARRAY_SIZE(sx9324_samp_freq_table)) + return -EINVAL; + + mutex_lock(&data->mutex); + + ret = regmap_update_bits(data->regmap, + SX9324_REG_GNRL_CTRL0, + SX9324_REG_GNRL_CTRL0_SCANPERIOD_MASK, i); + + mutex_unlock(&data->mutex); + + return ret; +} + +static int sx9324_read_thresh(struct sx_common_data *data, + const struct iio_chan_spec *chan, int *val) +{ + unsigned int regval; + unsigned int reg; + int ret; + + /* + * TODO(gwendal): Depending on the phase function + * (proximity/table/body), retrieve the right threshold. + * For now, return the proximity threshold. + */ + reg = SX9324_REG_PROX_CTRL6 + chan->channel / 2; + ret = regmap_read(data->regmap, reg, ®val); + if (ret) + return ret; + + if (regval <= 1) + *val = regval; + else + *val = (regval * regval) / 2; + + return IIO_VAL_INT; +} + +static int sx9324_read_hysteresis(struct sx_common_data *data, + const struct iio_chan_spec *chan, int *val) +{ + unsigned int regval, pthresh; + int ret; + + ret = sx9324_read_thresh(data, chan, &pthresh); + if (ret < 0) + return ret; + + ret = regmap_read(data->regmap, SX9324_REG_PROX_CTRL5, ®val); + if (ret) + return ret; + + regval = FIELD_GET(SX9324_REG_PROX_CTRL5_HYST_MASK, regval); + if (!regval) + *val = 0; + else + *val = pthresh >> (5 - regval); + + return IIO_VAL_INT; +} + +static int sx9324_read_far_debounce(struct sx_common_data *data, int *val) +{ + unsigned int regval; + int ret; + + ret = regmap_read(data->regmap, SX9324_REG_PROX_CTRL5, ®val); + if (ret) + return ret; + + regval = FIELD_GET(SX9324_REG_PROX_CTRL5_FAR_DEBOUNCE_MASK, regval); + if (regval) + *val = 1 << regval; + else + *val = 0; + + return IIO_VAL_INT; +} + +static int sx9324_read_close_debounce(struct sx_common_data *data, int *val) +{ + unsigned int regval; + int ret; + + ret = regmap_read(data->regmap, SX9324_REG_PROX_CTRL5, ®val); + if (ret) + return ret; + + regval = FIELD_GET(SX9324_REG_PROX_CTRL5_CLOSE_DEBOUNCE_MASK, regval); + if (regval) + *val = 1 << regval; + else + *val = 0; + + return IIO_VAL_INT; +} + +static int sx9324_read_event_val(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, int *val, int *val2) +{ + struct sx_common_data *data = iio_priv(indio_dev); + + if (chan->type != IIO_PROXIMITY) + return -EINVAL; + + switch (info) { + case IIO_EV_INFO_VALUE: + return sx9324_read_thresh(data, chan, val); + case IIO_EV_INFO_PERIOD: + switch (dir) { + case IIO_EV_DIR_RISING: + return sx9324_read_far_debounce(data, val); + case IIO_EV_DIR_FALLING: + return sx9324_read_close_debounce(data, val); + default: + return -EINVAL; + } + case IIO_EV_INFO_HYSTERESIS: + return sx9324_read_hysteresis(data, chan, val); + default: + return -EINVAL; + } +} + +static int sx9324_write_thresh(struct sx_common_data *data, + const struct iio_chan_spec *chan, int _val) +{ + unsigned int reg, val = _val; + int ret; + + reg = SX9324_REG_PROX_CTRL6 + chan->channel / 2; + + if (val >= 1) + val = int_sqrt(2 * val); + + if (val > 0xff) + return -EINVAL; + + mutex_lock(&data->mutex); + ret = regmap_write(data->regmap, reg, val); + mutex_unlock(&data->mutex); + + return ret; +} + +static int sx9324_write_hysteresis(struct sx_common_data *data, + const struct iio_chan_spec *chan, int _val) +{ + unsigned int hyst, val = _val; + int ret, pthresh; + + ret = sx9324_read_thresh(data, chan, &pthresh); + if (ret < 0) + return ret; + + if (val == 0) + hyst = 0; + else if (val >= pthresh >> 2) + hyst = 3; + else if (val >= pthresh >> 3) + hyst = 2; + else if (val >= pthresh >> 4) + hyst = 1; + else + return -EINVAL; + + hyst = FIELD_PREP(SX9324_REG_PROX_CTRL5_HYST_MASK, hyst); + mutex_lock(&data->mutex); + ret = regmap_update_bits(data->regmap, SX9324_REG_PROX_CTRL5, + SX9324_REG_PROX_CTRL5_HYST_MASK, hyst); + mutex_unlock(&data->mutex); + + return ret; +} + +static int sx9324_write_far_debounce(struct sx_common_data *data, int _val) +{ + unsigned int regval, val = _val; + int ret; + + if (val > 0) + val = ilog2(val); + if (!FIELD_FIT(SX9324_REG_PROX_CTRL5_FAR_DEBOUNCE_MASK, val)) + return -EINVAL; + + regval = FIELD_PREP(SX9324_REG_PROX_CTRL5_FAR_DEBOUNCE_MASK, val); + + mutex_lock(&data->mutex); + ret = regmap_update_bits(data->regmap, SX9324_REG_PROX_CTRL5, + SX9324_REG_PROX_CTRL5_FAR_DEBOUNCE_MASK, + regval); + mutex_unlock(&data->mutex); + + return ret; +} + +static int sx9324_write_close_debounce(struct sx_common_data *data, int _val) +{ + unsigned int regval, val = _val; + int ret; + + if (val > 0) + val = ilog2(val); + if (!FIELD_FIT(SX9324_REG_PROX_CTRL5_CLOSE_DEBOUNCE_MASK, val)) + return -EINVAL; + + regval = FIELD_PREP(SX9324_REG_PROX_CTRL5_CLOSE_DEBOUNCE_MASK, val); + + mutex_lock(&data->mutex); + ret = regmap_update_bits(data->regmap, SX9324_REG_PROX_CTRL5, + SX9324_REG_PROX_CTRL5_CLOSE_DEBOUNCE_MASK, + regval); + mutex_unlock(&data->mutex); + + return ret; +} + +static int sx9324_write_event_val(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, int val, int val2) +{ + struct sx_common_data *data = iio_priv(indio_dev); + + if (chan->type != IIO_PROXIMITY) + return -EINVAL; + + switch (info) { + case IIO_EV_INFO_VALUE: + return sx9324_write_thresh(data, chan, val); + case IIO_EV_INFO_PERIOD: + switch (dir) { + case IIO_EV_DIR_RISING: + return sx9324_write_far_debounce(data, val); + case IIO_EV_DIR_FALLING: + return sx9324_write_close_debounce(data, val); + default: + return -EINVAL; + } + case IIO_EV_INFO_HYSTERESIS: + return sx9324_write_hysteresis(data, chan, val); + default: + return -EINVAL; + } +} + +static int sx9324_write_gain(struct sx_common_data *data, + const struct iio_chan_spec *chan, int val) +{ + unsigned int gain, reg; + int ret; + + gain = ilog2(val); + reg = SX9324_REG_PROX_CTRL0 + chan->channel / 2; + gain = FIELD_PREP(SX9324_REG_PROX_CTRL0_GAIN_MASK, gain); + + mutex_lock(&data->mutex); + ret = regmap_update_bits(data->regmap, reg, + SX9324_REG_PROX_CTRL0_GAIN_MASK, + gain); + mutex_unlock(&data->mutex); + + return ret; +} + +static int sx9324_write_raw(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, int val, int val2, + long mask) +{ + struct sx_common_data *data = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_SAMP_FREQ: + return sx9324_set_samp_freq(data, val, val2); + case IIO_CHAN_INFO_HARDWAREGAIN: + return sx9324_write_gain(data, chan, val); + default: + return -EINVAL; + } +} + +/* Activate all channels and perform an initial compensation. */ +static int sx9324_init_compensation(struct iio_dev *indio_dev) +{ + struct sx_common_data *data = iio_priv(indio_dev); + unsigned int val; + int ret; + + /* run the compensation phase on all channels */ + ret = regmap_update_bits(data->regmap, SX9324_REG_STAT2, + SX9324_REG_STAT2_COMPSTAT_MASK, + SX9324_REG_STAT2_COMPSTAT_MASK); + if (ret) + return ret; + + return regmap_read_poll_timeout(data->regmap, SX9324_REG_STAT2, val, + !(val & SX9324_REG_STAT2_COMPSTAT_MASK), + 20000, 2000000); +} + +static int sx9324_check_whoami(struct device *dev, + struct iio_dev *indio_dev) +{ + /* + * Only one sensor for this driver. Assuming the device tree + * is correct, just set the sensor name. + */ + indio_dev->name = "sx9324"; + return 0; +} + +static const struct sx_common_chip_info sx9324_chip_info = { + .reg_stat = SX9324_REG_STAT0, + .reg_irq_msk = SX9324_REG_IRQ_MSK, + .reg_enable_chan = SX9324_REG_GNRL_CTRL1, + .reg_reset = SX9324_REG_RESET, + + .mask_enable_chan = SX9324_REG_GNRL_CTRL1_PHEN_MASK, + .irq_msk_offset = 3, + .num_channels = SX9324_NUM_CHANNELS, + + .ops = { + .read_prox_data = sx9324_read_prox_data, + .check_whoami = sx9324_check_whoami, + .init_compensation = sx9324_init_compensation, + .wait_for_sample = sx9324_wait_for_sample, + }, + + .iio_channels = sx9324_channels, + .num_iio_channels = ARRAY_SIZE(sx9324_channels), + .iio_info = { + .read_raw = sx9324_read_raw, + .read_avail = sx9324_read_avail, + .read_event_value = sx9324_read_event_val, + .write_event_value = sx9324_write_event_val, + .write_raw = sx9324_write_raw, + .read_event_config = sx_common_read_event_config, + .write_event_config = sx_common_write_event_config, + }, +}; + +static int sx9324_probe(struct i2c_client *client) +{ + return sx_common_probe(client, &sx9324_chip_info, &sx9324_regmap_config); +} + +static int __maybe_unused sx9324_suspend(struct device *dev) +{ + struct sx_common_data *data = iio_priv(dev_get_drvdata(dev)); + unsigned int regval; + int ret; + + disable_irq_nosync(data->client->irq); + + mutex_lock(&data->mutex); + ret = regmap_read(data->regmap, SX9324_REG_GNRL_CTRL1, ®val); + + data->suspend_ctrl = + FIELD_GET(SX9324_REG_GNRL_CTRL1_PHEN_MASK, regval); + + if (ret < 0) + goto out; + + /* Disable all phases, send the device to sleep. */ + ret = regmap_write(data->regmap, SX9324_REG_GNRL_CTRL1, 0); + +out: + mutex_unlock(&data->mutex); + return ret; +} + +static int __maybe_unused sx9324_resume(struct device *dev) +{ + struct sx_common_data *data = iio_priv(dev_get_drvdata(dev)); + int ret; + + mutex_lock(&data->mutex); + ret = regmap_write(data->regmap, SX9324_REG_GNRL_CTRL1, + data->suspend_ctrl | SX9324_REG_GNRL_CTRL1_PAUSECTRL); + mutex_unlock(&data->mutex); + if (ret) + return ret; + + enable_irq(data->client->irq); + return 0; +} + +static SIMPLE_DEV_PM_OPS(sx9324_pm_ops, sx9324_suspend, sx9324_resume); + +static const struct acpi_device_id sx9324_acpi_match[] = { + { "STH9324", SX9324_WHOAMI_VALUE }, + { } +}; +MODULE_DEVICE_TABLE(acpi, sx9324_acpi_match); + +static const struct of_device_id sx9324_of_match[] = { + { .compatible = "semtech,sx9324", (void *)SX9324_WHOAMI_VALUE }, + { } +}; +MODULE_DEVICE_TABLE(of, sx9324_of_match); + +static const struct i2c_device_id sx9324_id[] = { + { "sx9324", SX9324_WHOAMI_VALUE }, + { } +}; +MODULE_DEVICE_TABLE(i2c, sx9324_id); + +static struct i2c_driver sx9324_driver = { + .driver = { + .name = "sx9324", + .acpi_match_table = sx9324_acpi_match, + .of_match_table = sx9324_of_match, + .pm = &sx9324_pm_ops, + + /* + * Lots of i2c transfers in probe + over 200 ms waiting in + * sx9324_init_compensation() mean a slow probe; prefer async + * so we don't delay boot if we're builtin to the kernel. + */ + .probe_type = PROBE_PREFER_ASYNCHRONOUS, + }, + .probe_new = sx9324_probe, + .id_table = sx9324_id, +}; +module_i2c_driver(sx9324_driver); + +MODULE_AUTHOR("Gwendal Grignou "); +MODULE_DESCRIPTION("Driver for Semtech SX9324 proximity sensor"); +MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS(SEMTECH_PROX); -- cgit v1.2.3 From 656f807086deef48aeb0e2884a434e7a573675fc Mon Sep 17 00:00:00 2001 From: Gwendal Grignou Date: Sat, 1 Jan 2022 12:38:16 -0800 Subject: dt-bindings:iio:proximity: Add sx9324 binding Similar to SX9310, add biddings to setup sx9324 hardware properties. SX9324 is a little different, introduce 4 phases to be configured in 2 pairs over 3 antennas. Signed-off-by: Gwendal Grignou Reviewed-by: Rob Herring Reviewed-by: Stephen Boyd Link: https://lore.kernel.org/r/20220101203817.290512-5-gwendal@chromium.org Signed-off-by: Jonathan Cameron --- .../bindings/iio/proximity/semtech,sx9324.yaml | 161 +++++++++++++++++++++ 1 file changed, 161 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/proximity/semtech,sx9324.yaml diff --git a/Documentation/devicetree/bindings/iio/proximity/semtech,sx9324.yaml b/Documentation/devicetree/bindings/iio/proximity/semtech,sx9324.yaml new file mode 100644 index 000000000000..b8a6ee16854f --- /dev/null +++ b/Documentation/devicetree/bindings/iio/proximity/semtech,sx9324.yaml @@ -0,0 +1,161 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/proximity/semtech,sx9324.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Semtech's SX9324 capacitive proximity sensor + +maintainers: + - Gwendal Grignou + - Daniel Campello + +description: | + Semtech's SX9324 proximity sensor. + +properties: + compatible: + const: semtech,sx9324 + + reg: + maxItems: 1 + + interrupts: + description: + Generated by device to announce preceding read request has finished + and data is available or that a close/far proximity event has happened. + maxItems: 1 + + vdd-supply: + description: Main power supply + + svdd-supply: + description: Host interface power supply + + "#io-channel-cells": + const: 1 + + semtech,ph0-pin: + $ref: /schemas/types.yaml#/definitions/uint32-array + description: | + Array of 3 entries. Index represent the id of the CS pin. + Value indicates how each CS pin is used during phase 0. + Each of the 3 pins have the following value - + 0 : unused (high impedance) + 1 : measured input + 2 : dynamic shield + 3 : grounded. + For instance, CS0 measured, CS1 shield and CS2 ground is [1, 2, 3] + items: + enum: [ 0, 1, 2, 3 ] + minItems: 3 + maxItems: 3 + + semtech,ph1-pin: + $ref: /schemas/types.yaml#/definitions/uint32-array + description: Same as ph0-pin for phase 1. + items: + enum: [ 0, 1, 2, 3 ] + minItems: 3 + maxItems: 3 + + semtech,ph2-pin: + $ref: /schemas/types.yaml#/definitions/uint32-array + description: Same as ph0-pin for phase 2. + items: + enum: [ 0, 1, 2, 3 ] + minItems: 3 + maxItems: 3 + + semtech,ph3-pin: + $ref: /schemas/types.yaml#/definitions/uint32-array + description: Same as ph0-pin for phase 3. + items: + enum: [ 0, 1, 2, 3 ] + minItems: 3 + maxItems: 3 + + + semtech,ph01-resolution: + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [8, 16, 32, 64, 128, 256, 512, 1024] + description: + Capacitance measurement resolution. For phase 0 and 1. + Higher the number, higher the resolution. + default: 128 + + semtech,ph23-resolution: + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [8, 16, 32, 64, 128, 256, 512, 1024] + description: + Capacitance measurement resolution. For phase 2 and 3 + default: 128 + + semtech,startup-sensor: + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [0, 1, 2, 3] + default: 0 + description: | + Phase used for start-up proximity detection. + It is used when we enable a phase to remove static offset and measure + only capacitance changes introduced by the user. + + semtech,ph01-proxraw-strength: + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0 + maximum: 7 + default: 1 + description: + PROXRAW filter strength for phase 0 and 1. A value of 0 represents off, + and other values represent 1-1/2^N. + + semtech,ph23-proxraw-strength: + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0 + maximum: 7 + default: 1 + description: + Same as proxraw-strength01, for phase 2 and 3. + + semtech,avg-pos-strength: + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [0, 16, 64, 128, 256, 512, 1024, 4294967295] + default: 16 + description: | + Average positive filter strength. A value of 0 represents off and + UINT_MAX (4294967295) represents infinite. Other values + represent 1-1/N. + +required: + - compatible + - reg + - "#io-channel-cells" + +additionalProperties: false + +examples: + - | + #include + i2c { + #address-cells = <1>; + #size-cells = <0>; + proximity@28 { + compatible = "semtech,sx9324"; + reg = <0x28>; + interrupt-parent = <&pio>; + interrupts = <5 IRQ_TYPE_LEVEL_LOW 5>; + vdd-supply = <&pp3300_a>; + svdd-supply = <&pp1800_prox>; + #io-channel-cells = <1>; + semtech,ph0-pin = <1 2 3>; + semtech,ph1-pin = <3 2 1>; + semtech,ph2-pin = <1 2 3>; + semtech,ph3-pin = <3 2 1>; + semtech,ph01-resolution = <256>; + semtech,ph23-resolution = <256>; + semtech,startup-sensor = <1>; + semtech,ph01-proxraw-strength = <2>; + semtech,ph23-proxraw-strength = <2>; + semtech,avg-pos-strength = <64>; + }; + }; -- cgit v1.2.3 From a8ee3b32f5da6c77a5ccc0e42c2250d61ba54fe0 Mon Sep 17 00:00:00 2001 From: Gwendal Grignou Date: Sat, 1 Jan 2022 12:38:17 -0800 Subject: iio:proximity:sx9324: Add dt_binding support Based on bindings/iio/proximity/semtech,sx9324.yaml, implement retrieving sensor hardware property and alter default values. Signed-off-by: Gwendal Grignou Reviewed-by: Stephen Boyd Link: https://lore.kernel.org/r/20220101203817.290512-6-gwendal@chromium.org Signed-off-by: Jonathan Cameron --- drivers/iio/proximity/sx9324.c | 164 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 164 insertions(+) diff --git a/drivers/iio/proximity/sx9324.c b/drivers/iio/proximity/sx9324.c index 3aeb34b39acb..0d9bbbb50cb4 100644 --- a/drivers/iio/proximity/sx9324.c +++ b/drivers/iio/proximity/sx9324.c @@ -77,6 +77,7 @@ #define SX9324_REG_PROX_CTRL0 0x30 #define SX9324_REG_PROX_CTRL0_GAIN_MASK GENMASK(5, 3) #define SX9324_REG_PROX_CTRL0_GAIN_1 0x80 +#define SX9324_REG_PROX_CTRL0_RAWFILT_MASK GENMASK(2, 0) #define SX9324_REG_PROX_CTRL0_RAWFILT_1P50 0x01 #define SX9324_REG_PROX_CTRL1 0x31 #define SX9324_REG_PROX_CTRL2 0x32 @@ -753,6 +754,74 @@ static int sx9324_write_raw(struct iio_dev *indio_dev, } } +static const struct sx_common_reg_default sx9324_default_regs[] = { + { SX9324_REG_IRQ_MSK, 0x00 }, + { SX9324_REG_IRQ_CFG0, 0x00 }, + { SX9324_REG_IRQ_CFG1, SX9324_REG_IRQ_CFG1_FAILCOND }, + { SX9324_REG_IRQ_CFG2, 0x00 }, + { SX9324_REG_GNRL_CTRL0, SX9324_REG_GNRL_CTRL0_SCANPERIOD_100MS }, + /* + * The lower 4 bits should not be set as it enable sensors measurements. + * Turning the detection on before the configuration values are set to + * good values can cause the device to return erroneous readings. + */ + { SX9324_REG_GNRL_CTRL1, SX9324_REG_GNRL_CTRL1_PAUSECTRL }, + + { SX9324_REG_AFE_CTRL0, 0x00 }, + { SX9324_REG_AFE_CTRL3, 0x00 }, + { SX9324_REG_AFE_CTRL4, SX9324_REG_AFE_CTRL4_FREQ_83_33HZ | + SX9324_REG_AFE_CTRL4_RES_100 }, + { SX9324_REG_AFE_CTRL6, 0x00 }, + { SX9324_REG_AFE_CTRL7, SX9324_REG_AFE_CTRL4_FREQ_83_33HZ | + SX9324_REG_AFE_CTRL4_RES_100 }, + + /* TODO(gwendal): PHx use chip default or all grounded? */ + { SX9324_REG_AFE_PH0, 0x29 }, + { SX9324_REG_AFE_PH1, 0x26 }, + { SX9324_REG_AFE_PH2, 0x1a }, + { SX9324_REG_AFE_PH3, 0x16 }, + + { SX9324_REG_AFE_CTRL8, SX9324_REG_AFE_CTRL8_RESFILTN_4KOHM }, + { SX9324_REG_AFE_CTRL9, SX9324_REG_AFE_CTRL9_AGAIN_1 }, + + { SX9324_REG_PROX_CTRL0, SX9324_REG_PROX_CTRL0_GAIN_1 | + SX9324_REG_PROX_CTRL0_RAWFILT_1P50 }, + { SX9324_REG_PROX_CTRL1, SX9324_REG_PROX_CTRL0_GAIN_1 | + SX9324_REG_PROX_CTRL0_RAWFILT_1P50 }, + { SX9324_REG_PROX_CTRL2, SX9324_REG_PROX_CTRL2_AVGNEG_THRESH_16K }, + { SX9324_REG_PROX_CTRL3, SX9324_REG_PROX_CTRL3_AVGDEB_2SAMPLES | + SX9324_REG_PROX_CTRL3_AVGPOS_THRESH_16K }, + { SX9324_REG_PROX_CTRL4, SX9324_REG_PROX_CTRL4_AVGNEG_FILT_2 | + SX9324_REG_PROX_CTRL3_AVGPOS_FILT_256 }, + { SX9324_REG_PROX_CTRL5, 0x00 }, + { SX9324_REG_PROX_CTRL6, SX9324_REG_PROX_CTRL6_PROXTHRESH_32 }, + { SX9324_REG_PROX_CTRL7, SX9324_REG_PROX_CTRL6_PROXTHRESH_32 }, + { SX9324_REG_ADV_CTRL0, 0x00 }, + { SX9324_REG_ADV_CTRL1, 0x00 }, + { SX9324_REG_ADV_CTRL2, 0x00 }, + { SX9324_REG_ADV_CTRL3, 0x00 }, + { SX9324_REG_ADV_CTRL4, 0x00 }, + { SX9324_REG_ADV_CTRL5, SX9324_REG_ADV_CTRL5_STARTUP_SENSOR_1 | + SX9324_REG_ADV_CTRL5_STARTUP_METHOD_1 }, + { SX9324_REG_ADV_CTRL6, 0x00 }, + { SX9324_REG_ADV_CTRL7, 0x00 }, + { SX9324_REG_ADV_CTRL8, 0x00 }, + { SX9324_REG_ADV_CTRL9, 0x00 }, + /* Body/Table threshold */ + { SX9324_REG_ADV_CTRL10, 0x00 }, + { SX9324_REG_ADV_CTRL11, 0x00 }, + { SX9324_REG_ADV_CTRL12, 0x00 }, + /* TODO(gwendal): SAR currenly disabled */ + { SX9324_REG_ADV_CTRL13, 0x00 }, + { SX9324_REG_ADV_CTRL14, 0x00 }, + { SX9324_REG_ADV_CTRL15, 0x00 }, + { SX9324_REG_ADV_CTRL16, 0x00 }, + { SX9324_REG_ADV_CTRL17, 0x00 }, + { SX9324_REG_ADV_CTRL18, 0x00 }, + { SX9324_REG_ADV_CTRL19, SX9324_REG_ADV_CTRL19_HIGHT_FAILURE_THRESH_SATURATION }, + { SX9324_REG_ADV_CTRL20, SX9324_REG_ADV_CTRL19_HIGHT_FAILURE_THRESH_SATURATION }, +}; + /* Activate all channels and perform an initial compensation. */ static int sx9324_init_compensation(struct iio_dev *indio_dev) { @@ -772,6 +841,99 @@ static int sx9324_init_compensation(struct iio_dev *indio_dev) 20000, 2000000); } +static const struct sx_common_reg_default * +sx9324_get_default_reg(struct device *dev, int idx, + struct sx_common_reg_default *reg_def) +{ +#define SX9324_PIN_DEF "semtech,ph0-pin" +#define SX9324_RESOLUTION_DEF "semtech,ph01-resolution" +#define SX9324_PROXRAW_DEF "semtech,ph01-proxraw-strength" + unsigned int pin_defs[SX9324_NUM_PINS]; + char prop[] = SX9324_PROXRAW_DEF; + u32 start = 0, raw = 0, pos = 0; + int ret, count, ph, pin; + + memcpy(reg_def, &sx9324_default_regs[idx], sizeof(*reg_def)); + switch (reg_def->reg) { + case SX9324_REG_AFE_PH0: + case SX9324_REG_AFE_PH1: + case SX9324_REG_AFE_PH2: + case SX9324_REG_AFE_PH3: + ph = reg_def->reg - SX9324_REG_AFE_PH0; + scnprintf(prop, ARRAY_SIZE(prop), "semtech,ph%d-pin", ph); + + count = device_property_count_u32(dev, prop); + if (count != ARRAY_SIZE(pin_defs)) + break; + ret = device_property_read_u32_array(dev, prop, pin_defs, + ARRAY_SIZE(pin_defs)); + for (pin = 0; pin < SX9324_NUM_PINS; pin++) + raw |= (pin_defs[pin] << (2 * pin)) & + SX9324_REG_AFE_PH0_PIN_MASK(pin); + reg_def->def = raw; + break; + case SX9324_REG_AFE_CTRL4: + case SX9324_REG_AFE_CTRL7: + if (reg_def->reg == SX9324_REG_AFE_CTRL4) + strncpy(prop, "semtech,ph01-resolution", + ARRAY_SIZE(prop)); + else + strncpy(prop, "semtech,ph23-resolution", + ARRAY_SIZE(prop)); + + ret = device_property_read_u32(dev, prop, &raw); + if (ret) + break; + + raw = ilog2(raw) - 3; + + reg_def->def &= ~SX9324_REG_AFE_CTRL4_RESOLUTION_MASK; + reg_def->def |= FIELD_PREP(SX9324_REG_AFE_CTRL4_RESOLUTION_MASK, + raw); + break; + case SX9324_REG_ADV_CTRL5: + ret = device_property_read_u32(dev, "semtech,startup-sensor", + &start); + if (ret) + break; + + reg_def->def &= ~SX9324_REG_ADV_CTRL5_STARTUPSENS_MASK; + reg_def->def |= FIELD_PREP(SX9324_REG_ADV_CTRL5_STARTUPSENS_MASK, + start); + break; + case SX9324_REG_PROX_CTRL4: + ret = device_property_read_u32(dev, "semtech,avg-pos-strength", + &pos); + if (ret) + break; + + /* Powers of 2, except for a gap between 16 and 64 */ + raw = clamp(ilog2(pos), 3, 11) - (pos >= 32 ? 4 : 3); + + reg_def->def &= ~SX9324_REG_PROX_CTRL4_AVGPOSFILT_MASK; + reg_def->def |= FIELD_PREP(SX9324_REG_PROX_CTRL4_AVGPOSFILT_MASK, + raw); + break; + case SX9324_REG_PROX_CTRL0: + case SX9324_REG_PROX_CTRL1: + if (reg_def->reg == SX9324_REG_PROX_CTRL0) + strncpy(prop, "semtech,ph01-proxraw-strength", + ARRAY_SIZE(prop)); + else + strncpy(prop, "semtech,ph23-proxraw-strength", + ARRAY_SIZE(prop)); + ret = device_property_read_u32(dev, prop, &raw); + if (ret) + break; + + reg_def->def &= ~SX9324_REG_PROX_CTRL0_RAWFILT_MASK; + reg_def->def |= FIELD_PREP(SX9324_REG_PROX_CTRL0_RAWFILT_MASK, + raw); + break; + } + return reg_def; +} + static int sx9324_check_whoami(struct device *dev, struct iio_dev *indio_dev) { @@ -792,12 +954,14 @@ static const struct sx_common_chip_info sx9324_chip_info = { .mask_enable_chan = SX9324_REG_GNRL_CTRL1_PHEN_MASK, .irq_msk_offset = 3, .num_channels = SX9324_NUM_CHANNELS, + .num_default_regs = ARRAY_SIZE(sx9324_default_regs), .ops = { .read_prox_data = sx9324_read_prox_data, .check_whoami = sx9324_check_whoami, .init_compensation = sx9324_init_compensation, .wait_for_sample = sx9324_wait_for_sample, + .get_default_reg = sx9324_get_default_reg, }, .iio_channels = sx9324_channels, -- cgit v1.2.3 From 1cdb4c47f7f501e51006fdb4d36c528ed30de9a8 Mon Sep 17 00:00:00 2001 From: Gwendal Grignou Date: Sat, 1 Jan 2022 12:37:58 -0800 Subject: iio:proximity:sx9360: Add sx9360 support A simplified version of SX9324, it only have one pin and 2 phases (aka channels). Only one event is presented. Signed-off-by: Gwendal Grignou Reviewed-by: Stephen Boyd Link: https://lore.kernel.org/r/20220101203800.290387-2-gwendal@chromium.org Signed-off-by: Jonathan Cameron --- drivers/iio/proximity/Kconfig | 14 + drivers/iio/proximity/Makefile | 1 + drivers/iio/proximity/sx9360.c | 809 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 824 insertions(+) create mode 100644 drivers/iio/proximity/sx9360.c diff --git a/drivers/iio/proximity/Kconfig b/drivers/iio/proximity/Kconfig index dc66f339e5b1..0e5c17530b8b 100644 --- a/drivers/iio/proximity/Kconfig +++ b/drivers/iio/proximity/Kconfig @@ -145,6 +145,20 @@ config SX9324 To compile this driver as a module, choose M here: the module will be called sx9324. +config SX9360 + tristate "SX9360 Semtech proximity sensor" + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER + select REGMAP_I2C + select SX_COMMON + depends on I2C + help + Say Y here to build a driver for Semtech's SX9360 + proximity/button sensor, a simplified SX9324. + + To compile this driver as a module, choose M here: the + module will be called sx9360. + config SX9500 tristate "SX9500 Semtech proximity sensor" select IIO_BUFFER diff --git a/drivers/iio/proximity/Makefile b/drivers/iio/proximity/Makefile index cffe962b3527..cc838bb5408a 100644 --- a/drivers/iio/proximity/Makefile +++ b/drivers/iio/proximity/Makefile @@ -15,6 +15,7 @@ obj-$(CONFIG_SRF04) += srf04.o obj-$(CONFIG_SRF08) += srf08.o obj-$(CONFIG_SX9310) += sx9310.o obj-$(CONFIG_SX9324) += sx9324.o +obj-$(CONFIG_SX9360) += sx9360.o obj-$(CONFIG_SX_COMMON) += sx_common.o obj-$(CONFIG_SX9500) += sx9500.o obj-$(CONFIG_VCNL3020) += vcnl3020.o diff --git a/drivers/iio/proximity/sx9360.c b/drivers/iio/proximity/sx9360.c new file mode 100644 index 000000000000..4c977a801b81 --- /dev/null +++ b/drivers/iio/proximity/sx9360.c @@ -0,0 +1,809 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2021 Google LLC. + * + * Driver for Semtech's SX9360 capacitive proximity/button solution. + * Based on SX9360 driver and copy of datasheet at: + * https://edit.wpgdadawant.com/uploads/news_file/program/2019/30184/tech_files/program_30184_suggest_other_file.pdf + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "sx_common.h" + +/* Nominal Oscillator Frequency. */ +#define SX9360_FOSC_MHZ 4 +#define SX9360_FOSC_HZ (SX9360_FOSC_MHZ * 1000000) + +/* Register definitions. */ +#define SX9360_REG_IRQ_SRC SX_COMMON_REG_IRQ_SRC +#define SX9360_REG_STAT 0x01 +#define SX9360_REG_STAT_COMPSTAT_MASK GENMASK(2, 1) +#define SX9360_REG_IRQ_MSK 0x02 +#define SX9360_CONVDONE_IRQ BIT(0) +#define SX9360_FAR_IRQ BIT(2) +#define SX9360_CLOSE_IRQ BIT(3) +#define SX9360_REG_IRQ_CFG 0x03 + +#define SX9360_REG_GNRL_CTRL0 0x10 +#define SX9360_REG_GNRL_CTRL0_PHEN_MASK GENMASK(1, 0) +#define SX9360_REG_GNRL_CTRL1 0x11 +#define SX9360_REG_GNRL_CTRL1_SCANPERIOD_MASK GENMASK(2, 0) +#define SX9360_REG_GNRL_CTRL2 0x12 +#define SX9360_REG_GNRL_CTRL2_PERIOD_102MS 0x32 +#define SX9360_REG_GNRL_REG_2_PERIOD_MS(_r) \ + (((_r) * 8192) / (SX9360_FOSC_HZ / 1000)) +#define SX9360_REG_GNRL_FREQ_2_REG(_f) (((_f) * 8192) / SX9360_FOSC_HZ) +#define SX9360_REG_GNRL_REG_2_FREQ(_r) (SX9360_FOSC_HZ / ((_r) * 8192)) + +#define SX9360_REG_AFE_CTRL1 0x21 +#define SX9360_REG_AFE_PARAM0_PHR 0x22 +#define SX9360_REG_AFE_PARAM1_PHR 0x23 +#define SX9360_REG_AFE_PARAM0_PHM 0x24 +#define SX9360_REG_AFE_PARAM0_RSVD 0x08 +#define SX9360_REG_AFE_PARAM0_RESOLUTION_MASK GENMASK(2, 0) +#define SX9360_REG_AFE_PARAM0_RESOLUTION_128 0x02 +#define SX9360_REG_AFE_PARAM1_PHM 0x25 +#define SX9360_REG_AFE_PARAM1_AGAIN_PHM_6PF 0x40 +#define SX9360_REG_AFE_PARAM1_FREQ_83_33HZ 0x06 + +#define SX9360_REG_PROX_CTRL0_PHR 0x40 +#define SX9360_REG_PROX_CTRL0_PHM 0x41 +#define SX9360_REG_PROX_CTRL0_GAIN_MASK GENMASK(5, 3) +#define SX9360_REG_PROX_CTRL0_GAIN_1 0x80 +#define SX9360_REG_PROX_CTRL0_RAWFILT_1P50 0x01 +#define SX9360_REG_PROX_CTRL1 0x42 +#define SX9360_REG_PROX_CTRL1_AVGNEG_THRESH_MASK GENMASK(5, 3) +#define SX9360_REG_PROX_CTRL1_AVGNEG_THRESH_16K 0x20 +#define SX9360_REG_PROX_CTRL2 0x43 +#define SX9360_REG_PROX_CTRL2_AVGDEB_MASK GENMASK(7, 6) +#define SX9360_REG_PROX_CTRL2_AVGDEB_2SAMPLES 0x40 +#define SX9360_REG_PROX_CTRL2_AVGPOS_THRESH_16K 0x20 +#define SX9360_REG_PROX_CTRL3 0x44 +#define SX9360_REG_PROX_CTRL3_AVGNEG_FILT_MASK GENMASK(5, 3) +#define SX9360_REG_PROX_CTRL3_AVGNEG_FILT_2 0x08 +#define SX9360_REG_PROX_CTRL3_AVGPOS_FILT_MASK GENMASK(2, 0) +#define SX9360_REG_PROX_CTRL3_AVGPOS_FILT_256 0x04 +#define SX9360_REG_PROX_CTRL4 0x45 +#define SX9360_REG_PROX_CTRL4_HYST_MASK GENMASK(5, 4) +#define SX9360_REG_PROX_CTRL4_CLOSE_DEBOUNCE_MASK GENMASK(3, 2) +#define SX9360_REG_PROX_CTRL4_FAR_DEBOUNCE_MASK GENMASK(1, 0) +#define SX9360_REG_PROX_CTRL5 0x46 +#define SX9360_REG_PROX_CTRL5_PROXTHRESH_32 0x08 + +#define SX9360_REG_REF_CORR0 0x60 +#define SX9360_REG_REF_CORR1 0x61 + +#define SX9360_REG_USEFUL_PHR_MSB 0x90 +#define SX9360_REG_USEFUL_PHR_LSB 0x91 + +#define SX9360_REG_OFFSET_PMR_MSB 0x92 +#define SX9360_REG_OFFSET_PMR_LSB 0x93 + +#define SX9360_REG_USEFUL_PHM_MSB 0x94 +#define SX9360_REG_USEFUL_PHM_LSB 0x95 + +#define SX9360_REG_AVG_PHM_MSB 0x96 +#define SX9360_REG_AVG_PHM_LSB 0x97 + +#define SX9360_REG_DIFF_PHM_MSB 0x98 +#define SX9360_REG_DIFF_PHM_LSB 0x99 + +#define SX9360_REG_OFFSET_PHM_MSB 0x9a +#define SX9360_REG_OFFSET_PHM_LSB 0x9b + +#define SX9360_REG_USE_FILTER_MSB 0x9a +#define SX9360_REG_USE_FILTER_LSB 0x9b + +#define SX9360_REG_RESET 0xcf +/* Write this to REG_RESET to do a soft reset. */ +#define SX9360_SOFT_RESET 0xde + +#define SX9360_REG_WHOAMI 0xfa +#define SX9360_WHOAMI_VALUE 0x60 + +#define SX9360_REG_REVISION 0xfe + +/* 2 channels, Phase Reference and Measurement. */ +#define SX9360_NUM_CHANNELS 2 + +static const struct iio_chan_spec sx9360_channels[] = { + { + .type = IIO_PROXIMITY, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_HARDWAREGAIN), + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), + .info_mask_separate_available = + BIT(IIO_CHAN_INFO_HARDWAREGAIN), + .info_mask_shared_by_all_available = + BIT(IIO_CHAN_INFO_SAMP_FREQ), + .indexed = 1, + .address = SX9360_REG_USEFUL_PHR_MSB, + .channel = 0, + .scan_index = 0, + .scan_type = { + .sign = 's', + .realbits = 12, + .storagebits = 16, + .endianness = IIO_BE, + }, + }, + { + .type = IIO_PROXIMITY, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_HARDWAREGAIN), + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), + .info_mask_separate_available = + BIT(IIO_CHAN_INFO_HARDWAREGAIN), + .info_mask_shared_by_all_available = + BIT(IIO_CHAN_INFO_SAMP_FREQ), + .indexed = 1, + .address = SX9360_REG_USEFUL_PHM_MSB, + .event_spec = sx_common_events, + .num_event_specs = ARRAY_SIZE(sx_common_events), + .channel = 1, + .scan_index = 1, + .scan_type = { + .sign = 's', + .realbits = 12, + .storagebits = 16, + .endianness = IIO_BE, + }, + }, + IIO_CHAN_SOFT_TIMESTAMP(2), +}; + +/* + * Each entry contains the integer part (val) and the fractional part, in micro + * seconds. It conforms to the IIO output IIO_VAL_INT_PLUS_MICRO. + * + * The frequency control register holds the period, with a ~2ms increment. + * Therefore the smallest frequency is 4MHz / (2047 * 8192), + * The fastest is 4MHz / 8192. + * The interval is not linear, but given there is 2047 possible value, + * Returns the fake increment of (Max-Min)/2047 + */ +static const struct { + int val; + int val2; +} sx9360_samp_freq_interval[] = { + { 0, 281250 }, /* 4MHz / (8192 * 2047) */ + { 0, 281250 }, + { 448, 281250 }, /* 4MHz / 8192 */ +}; + +static const struct regmap_range sx9360_writable_reg_ranges[] = { + /* + * To set COMPSTAT for compensation, even if datasheet says register is + * RO. + */ + regmap_reg_range(SX9360_REG_STAT, SX9360_REG_IRQ_CFG), + regmap_reg_range(SX9360_REG_GNRL_CTRL0, SX9360_REG_GNRL_CTRL2), + regmap_reg_range(SX9360_REG_AFE_CTRL1, SX9360_REG_AFE_PARAM1_PHM), + regmap_reg_range(SX9360_REG_PROX_CTRL0_PHR, SX9360_REG_PROX_CTRL5), + regmap_reg_range(SX9360_REG_REF_CORR0, SX9360_REG_REF_CORR1), + regmap_reg_range(SX9360_REG_OFFSET_PMR_MSB, SX9360_REG_OFFSET_PMR_LSB), + regmap_reg_range(SX9360_REG_RESET, SX9360_REG_RESET), +}; + +static const struct regmap_access_table sx9360_writeable_regs = { + .yes_ranges = sx9360_writable_reg_ranges, + .n_yes_ranges = ARRAY_SIZE(sx9360_writable_reg_ranges), +}; + +/* + * All allocated registers are readable, so we just list unallocated + * ones. + */ +static const struct regmap_range sx9360_non_readable_reg_ranges[] = { + regmap_reg_range(SX9360_REG_IRQ_CFG + 1, SX9360_REG_GNRL_CTRL0 - 1), + regmap_reg_range(SX9360_REG_GNRL_CTRL2 + 1, SX9360_REG_AFE_CTRL1 - 1), + regmap_reg_range(SX9360_REG_AFE_PARAM1_PHM + 1, + SX9360_REG_PROX_CTRL0_PHR - 1), + regmap_reg_range(SX9360_REG_PROX_CTRL5 + 1, SX9360_REG_REF_CORR0 - 1), + regmap_reg_range(SX9360_REG_REF_CORR1 + 1, + SX9360_REG_USEFUL_PHR_MSB - 1), + regmap_reg_range(SX9360_REG_USE_FILTER_LSB + 1, SX9360_REG_RESET - 1), + regmap_reg_range(SX9360_REG_RESET + 1, SX9360_REG_WHOAMI - 1), + regmap_reg_range(SX9360_REG_WHOAMI + 1, SX9360_REG_REVISION - 1), +}; + +static const struct regmap_access_table sx9360_readable_regs = { + .no_ranges = sx9360_non_readable_reg_ranges, + .n_no_ranges = ARRAY_SIZE(sx9360_non_readable_reg_ranges), +}; + +static const struct regmap_range sx9360_volatile_reg_ranges[] = { + regmap_reg_range(SX9360_REG_IRQ_SRC, SX9360_REG_STAT), + regmap_reg_range(SX9360_REG_USEFUL_PHR_MSB, SX9360_REG_USE_FILTER_LSB), + regmap_reg_range(SX9360_REG_WHOAMI, SX9360_REG_WHOAMI), + regmap_reg_range(SX9360_REG_REVISION, SX9360_REG_REVISION), +}; + +static const struct regmap_access_table sx9360_volatile_regs = { + .yes_ranges = sx9360_volatile_reg_ranges, + .n_yes_ranges = ARRAY_SIZE(sx9360_volatile_reg_ranges), +}; + +static const struct regmap_config sx9360_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + + .max_register = SX9360_REG_REVISION, + .cache_type = REGCACHE_RBTREE, + + .wr_table = &sx9360_writeable_regs, + .rd_table = &sx9360_readable_regs, + .volatile_table = &sx9360_volatile_regs, +}; + +static int sx9360_read_prox_data(struct sx_common_data *data, + const struct iio_chan_spec *chan, + __be16 *val) +{ + return regmap_bulk_read(data->regmap, chan->address, val, sizeof(*val)); +} + +/* + * If we have no interrupt support, we have to wait for a scan period + * after enabling a channel to get a result. + */ +static int sx9360_wait_for_sample(struct sx_common_data *data) +{ + int ret; + __be16 buf; + + ret = regmap_bulk_read(data->regmap, SX9360_REG_GNRL_CTRL1, + &buf, sizeof(buf)); + if (ret < 0) + return ret; + msleep(SX9360_REG_GNRL_REG_2_PERIOD_MS(be16_to_cpu(buf))); + + return 0; +} + +static int sx9360_read_gain(struct sx_common_data *data, + const struct iio_chan_spec *chan, int *val) +{ + unsigned int reg, regval; + int ret; + + reg = SX9360_REG_PROX_CTRL0_PHR + chan->channel; + ret = regmap_read(data->regmap, reg, ®val); + if (ret) + return ret; + + *val = 1 << FIELD_GET(SX9360_REG_PROX_CTRL0_GAIN_MASK, regval); + + return IIO_VAL_INT; +} + +static int sx9360_read_samp_freq(struct sx_common_data *data, + int *val, int *val2) +{ + int ret, divisor; + __be16 buf; + + ret = regmap_bulk_read(data->regmap, SX9360_REG_GNRL_CTRL1, + &buf, sizeof(buf)); + if (ret < 0) + return ret; + divisor = be16_to_cpu(buf); + if (divisor == 0) { + *val = 0; + return IIO_VAL_INT; + } + + *val = SX9360_FOSC_HZ; + *val2 = divisor * 8192; + + return IIO_VAL_FRACTIONAL; +} + +static int sx9360_read_raw(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + int *val, int *val2, long mask) +{ + struct sx_common_data *data = iio_priv(indio_dev); + int ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + ret = iio_device_claim_direct_mode(indio_dev); + if (ret) + return ret; + + ret = sx_common_read_proximity(data, chan, val); + iio_device_release_direct_mode(indio_dev); + return ret; + case IIO_CHAN_INFO_HARDWAREGAIN: + ret = iio_device_claim_direct_mode(indio_dev); + if (ret) + return ret; + + ret = sx9360_read_gain(data, chan, val); + iio_device_release_direct_mode(indio_dev); + return ret; + case IIO_CHAN_INFO_SAMP_FREQ: + return sx9360_read_samp_freq(data, val, val2); + default: + return -EINVAL; + } +} + +static const char *sx9360_channel_labels[SX9360_NUM_CHANNELS] = { + "reference", "main", +}; + +static int sx9360_read_label(struct iio_dev *iio_dev, const struct iio_chan_spec *chan, + char *label) +{ + return sysfs_emit(label, "%s\n", sx9360_channel_labels[chan->channel]); +} + +static const int sx9360_gain_vals[] = { 1, 2, 4, 8 }; + +static int sx9360_read_avail(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + const int **vals, int *type, int *length, + long mask) +{ + if (chan->type != IIO_PROXIMITY) + return -EINVAL; + + switch (mask) { + case IIO_CHAN_INFO_HARDWAREGAIN: + *type = IIO_VAL_INT; + *length = ARRAY_SIZE(sx9360_gain_vals); + *vals = sx9360_gain_vals; + return IIO_AVAIL_LIST; + case IIO_CHAN_INFO_SAMP_FREQ: + *type = IIO_VAL_INT_PLUS_MICRO; + *length = ARRAY_SIZE(sx9360_samp_freq_interval) * 2; + *vals = (int *)sx9360_samp_freq_interval; + return IIO_AVAIL_RANGE; + default: + return -EINVAL; + } +} + +static int sx9360_set_samp_freq(struct sx_common_data *data, + int val, int val2) +{ + int ret, reg; + __be16 buf; + + reg = val * 8192 / SX9360_FOSC_HZ + val2 * 8192 / (SX9360_FOSC_MHZ); + buf = cpu_to_be16(reg); + mutex_lock(&data->mutex); + + ret = regmap_bulk_write(data->regmap, SX9360_REG_GNRL_CTRL1, &buf, + sizeof(buf)); + + mutex_unlock(&data->mutex); + + return ret; +} + +static int sx9360_read_thresh(struct sx_common_data *data, int *val) +{ + unsigned int regval; + int ret; + + ret = regmap_read(data->regmap, SX9360_REG_PROX_CTRL5, ®val); + if (ret) + return ret; + + if (regval <= 1) + *val = regval; + else + *val = (regval * regval) / 2; + + return IIO_VAL_INT; +} + +static int sx9360_read_hysteresis(struct sx_common_data *data, int *val) +{ + unsigned int regval, pthresh; + int ret; + + ret = sx9360_read_thresh(data, &pthresh); + if (ret < 0) + return ret; + + ret = regmap_read(data->regmap, SX9360_REG_PROX_CTRL4, ®val); + if (ret) + return ret; + + regval = FIELD_GET(SX9360_REG_PROX_CTRL4_HYST_MASK, regval); + if (!regval) + *val = 0; + else + *val = pthresh >> (5 - regval); + + return IIO_VAL_INT; +} + +static int sx9360_read_far_debounce(struct sx_common_data *data, int *val) +{ + unsigned int regval; + int ret; + + ret = regmap_read(data->regmap, SX9360_REG_PROX_CTRL4, ®val); + if (ret) + return ret; + + regval = FIELD_GET(SX9360_REG_PROX_CTRL4_FAR_DEBOUNCE_MASK, regval); + if (regval) + *val = 1 << regval; + else + *val = 0; + + return IIO_VAL_INT; +} + +static int sx9360_read_close_debounce(struct sx_common_data *data, int *val) +{ + unsigned int regval; + int ret; + + ret = regmap_read(data->regmap, SX9360_REG_PROX_CTRL4, ®val); + if (ret) + return ret; + + regval = FIELD_GET(SX9360_REG_PROX_CTRL4_CLOSE_DEBOUNCE_MASK, regval); + if (regval) + *val = 1 << regval; + else + *val = 0; + + return IIO_VAL_INT; +} + +static int sx9360_read_event_val(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, int *val, int *val2) +{ + struct sx_common_data *data = iio_priv(indio_dev); + + if (chan->type != IIO_PROXIMITY) + return -EINVAL; + + switch (info) { + case IIO_EV_INFO_VALUE: + return sx9360_read_thresh(data, val); + case IIO_EV_INFO_PERIOD: + switch (dir) { + case IIO_EV_DIR_RISING: + return sx9360_read_far_debounce(data, val); + case IIO_EV_DIR_FALLING: + return sx9360_read_close_debounce(data, val); + default: + return -EINVAL; + } + case IIO_EV_INFO_HYSTERESIS: + return sx9360_read_hysteresis(data, val); + default: + return -EINVAL; + } +} + +static int sx9360_write_thresh(struct sx_common_data *data, int _val) +{ + unsigned int val = _val; + int ret; + + if (val >= 1) + val = int_sqrt(2 * val); + + if (val > 0xff) + return -EINVAL; + + mutex_lock(&data->mutex); + ret = regmap_write(data->regmap, SX9360_REG_PROX_CTRL5, val); + mutex_unlock(&data->mutex); + + return ret; +} + +static int sx9360_write_hysteresis(struct sx_common_data *data, int _val) +{ + unsigned int hyst, val = _val; + int ret, pthresh; + + ret = sx9360_read_thresh(data, &pthresh); + if (ret < 0) + return ret; + + if (val == 0) + hyst = 0; + else if (val >= pthresh >> 2) + hyst = 3; + else if (val >= pthresh >> 3) + hyst = 2; + else if (val >= pthresh >> 4) + hyst = 1; + else + return -EINVAL; + + hyst = FIELD_PREP(SX9360_REG_PROX_CTRL4_HYST_MASK, hyst); + mutex_lock(&data->mutex); + ret = regmap_update_bits(data->regmap, SX9360_REG_PROX_CTRL4, + SX9360_REG_PROX_CTRL4_HYST_MASK, hyst); + mutex_unlock(&data->mutex); + + return ret; +} + +static int sx9360_write_far_debounce(struct sx_common_data *data, int _val) +{ + unsigned int regval, val = _val; + int ret; + + if (val > 0) + val = ilog2(val); + if (!FIELD_FIT(SX9360_REG_PROX_CTRL4_FAR_DEBOUNCE_MASK, val)) + return -EINVAL; + + regval = FIELD_PREP(SX9360_REG_PROX_CTRL4_FAR_DEBOUNCE_MASK, val); + + mutex_lock(&data->mutex); + ret = regmap_update_bits(data->regmap, SX9360_REG_PROX_CTRL4, + SX9360_REG_PROX_CTRL4_FAR_DEBOUNCE_MASK, + regval); + mutex_unlock(&data->mutex); + + return ret; +} + +static int sx9360_write_close_debounce(struct sx_common_data *data, int _val) +{ + unsigned int regval, val = _val; + int ret; + + if (val > 0) + val = ilog2(val); + if (!FIELD_FIT(SX9360_REG_PROX_CTRL4_CLOSE_DEBOUNCE_MASK, val)) + return -EINVAL; + + regval = FIELD_PREP(SX9360_REG_PROX_CTRL4_CLOSE_DEBOUNCE_MASK, val); + + mutex_lock(&data->mutex); + ret = regmap_update_bits(data->regmap, SX9360_REG_PROX_CTRL4, + SX9360_REG_PROX_CTRL4_CLOSE_DEBOUNCE_MASK, + regval); + mutex_unlock(&data->mutex); + + return ret; +} + +static int sx9360_write_event_val(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, int val, int val2) +{ + struct sx_common_data *data = iio_priv(indio_dev); + + if (chan->type != IIO_PROXIMITY) + return -EINVAL; + + switch (info) { + case IIO_EV_INFO_VALUE: + return sx9360_write_thresh(data, val); + case IIO_EV_INFO_PERIOD: + switch (dir) { + case IIO_EV_DIR_RISING: + return sx9360_write_far_debounce(data, val); + case IIO_EV_DIR_FALLING: + return sx9360_write_close_debounce(data, val); + default: + return -EINVAL; + } + case IIO_EV_INFO_HYSTERESIS: + return sx9360_write_hysteresis(data, val); + default: + return -EINVAL; + } +} + +static int sx9360_write_gain(struct sx_common_data *data, + const struct iio_chan_spec *chan, int val) +{ + unsigned int gain, reg; + int ret; + + gain = ilog2(val); + reg = SX9360_REG_PROX_CTRL0_PHR + chan->channel; + gain = FIELD_PREP(SX9360_REG_PROX_CTRL0_GAIN_MASK, gain); + + mutex_lock(&data->mutex); + ret = regmap_update_bits(data->regmap, reg, + SX9360_REG_PROX_CTRL0_GAIN_MASK, + gain); + mutex_unlock(&data->mutex); + + return ret; +} + +static int sx9360_write_raw(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, int val, int val2, + long mask) +{ + struct sx_common_data *data = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_SAMP_FREQ: + return sx9360_set_samp_freq(data, val, val2); + case IIO_CHAN_INFO_HARDWAREGAIN: + return sx9360_write_gain(data, chan, val); + default: + return -EINVAL; + } +} + +/* Activate all channels and perform an initial compensation. */ +static int sx9360_init_compensation(struct iio_dev *indio_dev) +{ + struct sx_common_data *data = iio_priv(indio_dev); + unsigned int val; + int ret; + + /* run the compensation phase on all channels */ + ret = regmap_update_bits(data->regmap, SX9360_REG_STAT, + SX9360_REG_STAT_COMPSTAT_MASK, + SX9360_REG_STAT_COMPSTAT_MASK); + if (ret) + return ret; + + return regmap_read_poll_timeout(data->regmap, SX9360_REG_STAT, val, + !(val & SX9360_REG_STAT_COMPSTAT_MASK), + 20000, 2000000); +} + +static int sx9360_check_whoami(struct device *dev, struct iio_dev *indio_dev) +{ + /* + * Only one sensor for this driver. Assuming the device tree + * is correct, just set the sensor name. + */ + indio_dev->name = "sx9360"; + return 0; +} + +static const struct sx_common_chip_info sx9360_chip_info = { + .reg_stat = SX9360_REG_STAT, + .reg_irq_msk = SX9360_REG_IRQ_MSK, + .reg_enable_chan = SX9360_REG_GNRL_CTRL0, + .reg_reset = SX9360_REG_RESET, + + .mask_enable_chan = SX9360_REG_GNRL_CTRL0_PHEN_MASK, + .stat_offset = 3, + .num_channels = SX9360_NUM_CHANNELS, + + .ops = { + .read_prox_data = sx9360_read_prox_data, + .check_whoami = sx9360_check_whoami, + .init_compensation = sx9360_init_compensation, + .wait_for_sample = sx9360_wait_for_sample, + }, + + .iio_channels = sx9360_channels, + .num_iio_channels = ARRAY_SIZE(sx9360_channels), + .iio_info = { + .read_raw = sx9360_read_raw, + .read_avail = sx9360_read_avail, + .read_label = sx9360_read_label, + .read_event_value = sx9360_read_event_val, + .write_event_value = sx9360_write_event_val, + .write_raw = sx9360_write_raw, + .read_event_config = sx_common_read_event_config, + .write_event_config = sx_common_write_event_config, + }, +}; + +static int sx9360_probe(struct i2c_client *client) +{ + return sx_common_probe(client, &sx9360_chip_info, &sx9360_regmap_config); +} + +static int __maybe_unused sx9360_suspend(struct device *dev) +{ + struct sx_common_data *data = iio_priv(dev_get_drvdata(dev)); + unsigned int regval; + int ret; + + disable_irq_nosync(data->client->irq); + + mutex_lock(&data->mutex); + ret = regmap_read(data->regmap, SX9360_REG_GNRL_CTRL0, ®val); + + data->suspend_ctrl = + FIELD_GET(SX9360_REG_GNRL_CTRL0_PHEN_MASK, regval); + + if (ret < 0) + goto out; + + /* Disable all phases, send the device to sleep. */ + ret = regmap_write(data->regmap, SX9360_REG_GNRL_CTRL0, 0); + +out: + mutex_unlock(&data->mutex); + return ret; +} + +static int __maybe_unused sx9360_resume(struct device *dev) +{ + struct sx_common_data *data = iio_priv(dev_get_drvdata(dev)); + int ret; + + mutex_lock(&data->mutex); + ret = regmap_update_bits(data->regmap, SX9360_REG_GNRL_CTRL0, + SX9360_REG_GNRL_CTRL0_PHEN_MASK, + data->suspend_ctrl); + mutex_unlock(&data->mutex); + if (ret) + return ret; + + enable_irq(data->client->irq); + return 0; +} + +static SIMPLE_DEV_PM_OPS(sx9360_pm_ops, sx9360_suspend, sx9360_resume); + +static const struct acpi_device_id sx9360_acpi_match[] = { + { "STH9360", SX9360_WHOAMI_VALUE }, + { } +}; +MODULE_DEVICE_TABLE(acpi, sx9360_acpi_match); + +static const struct of_device_id sx9360_of_match[] = { + { .compatible = "semtech,sx9360", (void *)SX9360_WHOAMI_VALUE }, + { } +}; +MODULE_DEVICE_TABLE(of, sx9360_of_match); + +static const struct i2c_device_id sx9360_id[] = { + {"sx9360", SX9360_WHOAMI_VALUE }, + { } +}; +MODULE_DEVICE_TABLE(i2c, sx9360_id); + +static struct i2c_driver sx9360_driver = { + .driver = { + .name = "sx9360", + .acpi_match_table = sx9360_acpi_match, + .of_match_table = sx9360_of_match, + .pm = &sx9360_pm_ops, + + /* + * Lots of i2c transfers in probe + over 200 ms waiting in + * sx9360_init_compensation() mean a slow probe; prefer async + * so we don't delay boot if we're builtin to the kernel. + */ + .probe_type = PROBE_PREFER_ASYNCHRONOUS, + }, + .probe_new = sx9360_probe, + .id_table = sx9360_id, +}; +module_i2c_driver(sx9360_driver); + +MODULE_AUTHOR("Gwendal Grignou "); +MODULE_DESCRIPTION("Driver for Semtech SX9360 proximity sensor"); +MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS(SEMTECH_PROX); -- cgit v1.2.3 From 1412b8cfc7e73b22047a7762529578bbfae9d202 Mon Sep 17 00:00:00 2001 From: Gwendal Grignou Date: Sat, 1 Jan 2022 12:37:59 -0800 Subject: dt-bindings:iio:proximity: Add sx9360 binding Add binding to configure Semtech sx9360 sensor. It is a simpler version of sx9324. Signed-off-by: Gwendal Grignou Reviewed-by: Stephen Boyd Link: https://lore.kernel.org/r/20220101203800.290387-3-gwendal@chromium.org Signed-off-by: Jonathan Cameron --- .../bindings/iio/proximity/semtech,sx9360.yaml | 89 ++++++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/proximity/semtech,sx9360.yaml diff --git a/Documentation/devicetree/bindings/iio/proximity/semtech,sx9360.yaml b/Documentation/devicetree/bindings/iio/proximity/semtech,sx9360.yaml new file mode 100644 index 000000000000..63e1a1fd00d4 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/proximity/semtech,sx9360.yaml @@ -0,0 +1,89 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/proximity/semtech,sx9360.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Semtech's SX9360 capacitive proximity sensor + +maintainers: + - Gwendal Grignou + - Daniel Campello + +description: | + Semtech's SX9360 proximity sensor. + +properties: + compatible: + const: semtech,sx9360 + + reg: + maxItems: 1 + + interrupts: + description: + Generated by device to announce preceding read request has finished + and data is available or that a close/far proximity event has happened. + maxItems: 1 + + vdd-supply: + description: Main power supply + + svdd-supply: + description: Host interface power supply + + "#io-channel-cells": + const: 1 + + semtech,resolution: + $ref: /schemas/types.yaml#/definitions/uint32-array + enum: [8, 16, 32, 64, 128, 256, 512, 1024] + description: + Capacitance measurement resolution. For both phases, "reference" and + "measurement". Higher the number, higher the resolution. + default: 128 + + semtech,proxraw-strength: + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0 + maximum: 7 + default: 1 + description: + PROXRAW filter strength for both phases. A value of 0 represents off, + and other values represent 1-1/2^N. + + semtech,avg-pos-strength: + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [0, 16, 64, 128, 256, 512, 1024, 4294967295] + default: 16 + description: | + Average positive filter strength. A value of 0 represents off and + UINT_MAX (4294967295) represents infinite. Other values + represent 1-1/N. + +required: + - compatible + - reg + - "#io-channel-cells" + +additionalProperties: false + +examples: + - | + #include + i2c { + #address-cells = <1>; + #size-cells = <0>; + proximity@28 { + compatible = "semtech,sx9360"; + reg = <0x28>; + interrupt-parent = <&pio>; + interrupts = <5 IRQ_TYPE_LEVEL_LOW 5>; + vdd-supply = <&pp3300_a>; + svdd-supply = <&pp1800_prox>; + #io-channel-cells = <1>; + semtech,resolution = <256>; + semtech,proxraw-strength = <2>; + semtech,avg-pos-strength = <64>; + }; + }; -- cgit v1.2.3 From 02d83fa6393a83151db0793e15e4e21208c3a432 Mon Sep 17 00:00:00 2001 From: Gwendal Grignou Date: Sat, 1 Jan 2022 12:38:00 -0800 Subject: iio:proximity:sx9360: Add dt-binding support Add support to configure sx9360 from dt-binding, to match device hardware setup. Signed-off-by: Gwendal Grignou Reviewed-by: Stephen Boyd Link: https://lore.kernel.org/r/20220101203800.290387-4-gwendal@chromium.org Signed-off-by: Jonathan Cameron --- drivers/iio/proximity/sx9360.c | 84 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/drivers/iio/proximity/sx9360.c b/drivers/iio/proximity/sx9360.c index 4c977a801b81..6fd6561bb6f5 100644 --- a/drivers/iio/proximity/sx9360.c +++ b/drivers/iio/proximity/sx9360.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -64,6 +65,7 @@ #define SX9360_REG_PROX_CTRL0_PHM 0x41 #define SX9360_REG_PROX_CTRL0_GAIN_MASK GENMASK(5, 3) #define SX9360_REG_PROX_CTRL0_GAIN_1 0x80 +#define SX9360_REG_PROX_CTRL0_RAWFILT_MASK GENMASK(2, 0) #define SX9360_REG_PROX_CTRL0_RAWFILT_1P50 0x01 #define SX9360_REG_PROX_CTRL1 0x42 #define SX9360_REG_PROX_CTRL1_AVGNEG_THRESH_MASK GENMASK(5, 3) @@ -657,6 +659,41 @@ static int sx9360_write_raw(struct iio_dev *indio_dev, } } +static const struct sx_common_reg_default sx9360_default_regs[] = { + { SX9360_REG_IRQ_MSK, 0x00 }, + { SX9360_REG_IRQ_CFG, 0x00 }, + /* + * The lower 2 bits should not be set as it enable sensors measurements. + * Turning the detection on before the configuration values are set to + * good values can cause the device to return erroneous readings. + */ + { SX9360_REG_GNRL_CTRL0, 0x00 }, + { SX9360_REG_GNRL_CTRL1, 0x00 }, + { SX9360_REG_GNRL_CTRL2, SX9360_REG_GNRL_CTRL2_PERIOD_102MS }, + + { SX9360_REG_AFE_CTRL1, 0x00 }, + { SX9360_REG_AFE_PARAM0_PHR, SX9360_REG_AFE_PARAM0_RSVD | + SX9360_REG_AFE_PARAM0_RESOLUTION_128 }, + { SX9360_REG_AFE_PARAM1_PHR, SX9360_REG_AFE_PARAM1_AGAIN_PHM_6PF | + SX9360_REG_AFE_PARAM1_FREQ_83_33HZ }, + { SX9360_REG_AFE_PARAM0_PHM, SX9360_REG_AFE_PARAM0_RSVD | + SX9360_REG_AFE_PARAM0_RESOLUTION_128 }, + { SX9360_REG_AFE_PARAM1_PHM, SX9360_REG_AFE_PARAM1_AGAIN_PHM_6PF | + SX9360_REG_AFE_PARAM1_FREQ_83_33HZ }, + + { SX9360_REG_PROX_CTRL0_PHR, SX9360_REG_PROX_CTRL0_GAIN_1 | + SX9360_REG_PROX_CTRL0_RAWFILT_1P50 }, + { SX9360_REG_PROX_CTRL0_PHM, SX9360_REG_PROX_CTRL0_GAIN_1 | + SX9360_REG_PROX_CTRL0_RAWFILT_1P50 }, + { SX9360_REG_PROX_CTRL1, SX9360_REG_PROX_CTRL1_AVGNEG_THRESH_16K }, + { SX9360_REG_PROX_CTRL2, SX9360_REG_PROX_CTRL2_AVGDEB_2SAMPLES | + SX9360_REG_PROX_CTRL2_AVGPOS_THRESH_16K }, + { SX9360_REG_PROX_CTRL3, SX9360_REG_PROX_CTRL3_AVGNEG_FILT_2 | + SX9360_REG_PROX_CTRL3_AVGPOS_FILT_256 }, + { SX9360_REG_PROX_CTRL4, 0x00 }, + { SX9360_REG_PROX_CTRL5, SX9360_REG_PROX_CTRL5_PROXTHRESH_32 }, +}; + /* Activate all channels and perform an initial compensation. */ static int sx9360_init_compensation(struct iio_dev *indio_dev) { @@ -676,6 +713,51 @@ static int sx9360_init_compensation(struct iio_dev *indio_dev) 20000, 2000000); } +static const struct sx_common_reg_default * +sx9360_get_default_reg(struct device *dev, int idx, + struct sx_common_reg_default *reg_def) +{ + u32 raw = 0, pos = 0; + int ret; + + memcpy(reg_def, &sx9360_default_regs[idx], sizeof(*reg_def)); + switch (reg_def->reg) { + case SX9360_REG_AFE_PARAM0_PHR: + case SX9360_REG_AFE_PARAM0_PHM: + ret = device_property_read_u32(dev, "semtech,resolution", &raw); + if (ret) + break; + + raw = ilog2(raw) - 3; + + reg_def->def &= ~SX9360_REG_AFE_PARAM0_RESOLUTION_MASK; + reg_def->def |= FIELD_PREP(SX9360_REG_AFE_PARAM0_RESOLUTION_MASK, raw); + break; + case SX9360_REG_PROX_CTRL0_PHR: + case SX9360_REG_PROX_CTRL0_PHM: + ret = device_property_read_u32(dev, "semtech,proxraw-strength", &raw); + if (ret) + break; + + reg_def->def &= ~SX9360_REG_PROX_CTRL0_RAWFILT_MASK; + reg_def->def |= FIELD_PREP(SX9360_REG_PROX_CTRL0_RAWFILT_MASK, raw); + break; + case SX9360_REG_PROX_CTRL3: + ret = device_property_read_u32(dev, "semtech,avg-pos-strength", + &pos); + if (ret) + break; + + /* Powers of 2, except for a gap between 16 and 64 */ + raw = clamp(ilog2(pos), 3, 11) - (pos >= 32 ? 4 : 3); + reg_def->def &= ~SX9360_REG_PROX_CTRL3_AVGPOS_FILT_MASK; + reg_def->def |= FIELD_PREP(SX9360_REG_PROX_CTRL3_AVGPOS_FILT_MASK, raw); + break; + } + + return reg_def; +} + static int sx9360_check_whoami(struct device *dev, struct iio_dev *indio_dev) { /* @@ -695,12 +777,14 @@ static const struct sx_common_chip_info sx9360_chip_info = { .mask_enable_chan = SX9360_REG_GNRL_CTRL0_PHEN_MASK, .stat_offset = 3, .num_channels = SX9360_NUM_CHANNELS, + .num_default_regs = ARRAY_SIZE(sx9360_default_regs), .ops = { .read_prox_data = sx9360_read_prox_data, .check_whoami = sx9360_check_whoami, .init_compensation = sx9360_init_compensation, .wait_for_sample = sx9360_wait_for_sample, + .get_default_reg = sx9360_get_default_reg, }, .iio_channels = sx9360_channels, -- cgit v1.2.3 From 09bdf14fb59dc7147378e3ccc2419e14097e0565 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Thu, 30 Dec 2021 17:48:56 +0000 Subject: iio:chemical:atlas: Trivial white space cleanup to add space before } Having a space after the { and not one before the } is inconsistent and good to remove examples that might get copied into new drivers. Signed-off-by: Jonathan Cameron Cc: Matt Ranostay Reviewed-by: Gwendal Grignou Link: https://lore.kernel.org/r/20211230174911.78291-2-jic23@kernel.org --- drivers/iio/chemical/atlas-sensor.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/iio/chemical/atlas-sensor.c b/drivers/iio/chemical/atlas-sensor.c index 04b44a327614..a8211dd20b35 100644 --- a/drivers/iio/chemical/atlas-sensor.c +++ b/drivers/iio/chemical/atlas-sensor.c @@ -589,11 +589,11 @@ static const struct iio_info atlas_info = { }; static const struct i2c_device_id atlas_id[] = { - { "atlas-ph-sm", ATLAS_PH_SM}, - { "atlas-ec-sm", ATLAS_EC_SM}, - { "atlas-orp-sm", ATLAS_ORP_SM}, - { "atlas-do-sm", ATLAS_DO_SM}, - { "atlas-rtd-sm", ATLAS_RTD_SM}, + { "atlas-ph-sm", ATLAS_PH_SM }, + { "atlas-ec-sm", ATLAS_EC_SM }, + { "atlas-orp-sm", ATLAS_ORP_SM }, + { "atlas-do-sm", ATLAS_DO_SM }, + { "atlas-rtd-sm", ATLAS_RTD_SM }, {} }; MODULE_DEVICE_TABLE(i2c, atlas_id); -- cgit v1.2.3 From 6e757756122cd70123330bd77dd9aa8846a2e98a Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Thu, 30 Dec 2021 17:48:57 +0000 Subject: iio:light:pa12203001: Tidy up white space change to add spaces after { and before } One case in here was inconsistent and was main focus of this patch. In that case there was a space after the { and none before the }. The second case was then inconsistent in having now spaces. Change makes sure there are spaces. Signed-off-by: Jonathan Cameron Reviewed-by: Gwendal Grignou Link: https://lore.kernel.org/r/20211230174911.78291-3-jic23@kernel.org --- drivers/iio/light/pa12203001.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/iio/light/pa12203001.c b/drivers/iio/light/pa12203001.c index a52b2c788540..528fa5dd2b13 100644 --- a/drivers/iio/light/pa12203001.c +++ b/drivers/iio/light/pa12203001.c @@ -452,14 +452,14 @@ static const struct dev_pm_ops pa12203001_pm_ops = { }; static const struct acpi_device_id pa12203001_acpi_match[] = { - { "TXCPA122", 0}, + { "TXCPA122", 0 }, {} }; MODULE_DEVICE_TABLE(acpi, pa12203001_acpi_match); static const struct i2c_device_id pa12203001_id[] = { - {"txcpa122", 0}, + { "txcpa122", 0 }, {} }; -- cgit v1.2.3 From 2ba83c80527eeb85291a8bd2e629e13dc89c27cf Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Thu, 30 Dec 2021 17:48:58 +0000 Subject: iio:light:vcnl4035: Trivial whitespace cleanup to add space before } Having a space after the { and not one before the } is inconsistent and I'd rather not have examples of this that get copied into new drivers. Signed-off-by: Jonathan Cameron Cc: Parthiban Nallathambi Reviewed-by: Gwendal Grignou Link: https://lore.kernel.org/r/20211230174911.78291-4-jic23@kernel.org --- drivers/iio/light/vcnl4035.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/light/vcnl4035.c b/drivers/iio/light/vcnl4035.c index 0db306ee910e..da2bf622a67b 100644 --- a/drivers/iio/light/vcnl4035.c +++ b/drivers/iio/light/vcnl4035.c @@ -651,7 +651,7 @@ static const struct dev_pm_ops vcnl4035_pm_ops = { }; static const struct i2c_device_id vcnl4035_id[] = { - { "vcnl4035", 0}, + { "vcnl4035", 0 }, { } }; MODULE_DEVICE_TABLE(i2c, vcnl4035_id); -- cgit v1.2.3 From 77f8767627c0c6b3ccfd0bee96cbec097426244a Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Thu, 30 Dec 2021 17:48:59 +0000 Subject: iio:light:us5182: White space cleanup of spacing around {} in id tables The spacing in this driver was inconsistent so make sure we have a space after { and before } for the two id tables. Signed-off-by: Jonathan Cameron Reviewed-by: Gwendal Grignou Link: https://lore.kernel.org/r/20211230174911.78291-5-jic23@kernel.org --- drivers/iio/light/us5182d.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/iio/light/us5182d.c b/drivers/iio/light/us5182d.c index 96e4a66ddf28..1492aaf8d84c 100644 --- a/drivers/iio/light/us5182d.c +++ b/drivers/iio/light/us5182d.c @@ -947,15 +947,15 @@ static const struct dev_pm_ops us5182d_pm_ops = { }; static const struct acpi_device_id us5182d_acpi_match[] = { - { "USD5182", 0}, + { "USD5182", 0 }, {} }; MODULE_DEVICE_TABLE(acpi, us5182d_acpi_match); static const struct i2c_device_id us5182d_id[] = { - {"usd5182", 0}, - {} + { "usd5182", 0 }, + {} }; MODULE_DEVICE_TABLE(i2c, us5182d_id); -- cgit v1.2.3 From 8877af25a2605e8b51a8f6948684c427a6a871b7 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Thu, 30 Dec 2021 17:49:00 +0000 Subject: iio:light:ltr501: White space cleanup of spacing around {} in id tables The spacing in this driver was inconsistent so make sure we have a space after { and before } for the two id tables. Part of aim is to avoid providing examples of this inconsistency that get copied into new drivers. Signed-off-by: Jonathan Cameron Cc: Nikita Travkin Cc: Maslov Dmitry Reviewed-by: Gwendal Grignou Link: https://lore.kernel.org/r/20211230174911.78291-6-jic23@kernel.org --- drivers/iio/light/ltr501.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/iio/light/ltr501.c b/drivers/iio/light/ltr501.c index 47d61ec2bb50..d1532ef5f08b 100644 --- a/drivers/iio/light/ltr501.c +++ b/drivers/iio/light/ltr501.c @@ -1632,18 +1632,18 @@ static int ltr501_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(ltr501_pm_ops, ltr501_suspend, ltr501_resume); static const struct acpi_device_id ltr_acpi_match[] = { - {"LTER0501", ltr501}, - {"LTER0559", ltr559}, - {"LTER0301", ltr301}, + { "LTER0501", ltr501 }, + { "LTER0559", ltr559 }, + { "LTER0301", ltr301 }, { }, }; MODULE_DEVICE_TABLE(acpi, ltr_acpi_match); static const struct i2c_device_id ltr501_id[] = { - { "ltr501", ltr501}, - { "ltr559", ltr559}, - { "ltr301", ltr301}, - { "ltr303", ltr303}, + { "ltr501", ltr501 }, + { "ltr559", ltr559 }, + { "ltr301", ltr301 }, + { "ltr303", ltr303 }, { } }; MODULE_DEVICE_TABLE(i2c, ltr501_id); -- cgit v1.2.3 From 07d6484f4998f826dae3d79f315731fa1573f139 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Thu, 30 Dec 2021 17:49:01 +0000 Subject: iio:proximity:ping: White space cleanup of spacing around {} in id tables The spacing in this driver was inconsistent so make sure we have a space after { and before } for the two id tables. Avoid providing examples of this inconsistency that get copied into new drivers. Signed-off-by: Jonathan Cameron Cc: Andreas Klinger Reviewed-by: Gwendal Grignou Link: https://lore.kernel.org/r/20211230174911.78291-7-jic23@kernel.org --- drivers/iio/proximity/ping.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/iio/proximity/ping.c b/drivers/iio/proximity/ping.c index 1283ac1c2e03..24a97d41e115 100644 --- a/drivers/iio/proximity/ping.c +++ b/drivers/iio/proximity/ping.c @@ -267,8 +267,8 @@ static const struct iio_chan_spec ping_chan_spec[] = { }; static const struct of_device_id of_ping_match[] = { - { .compatible = "parallax,ping", .data = &pa_ping_cfg}, - { .compatible = "parallax,laserping", .data = &pa_laser_ping_cfg}, + { .compatible = "parallax,ping", .data = &pa_ping_cfg }, + { .compatible = "parallax,laserping", .data = &pa_laser_ping_cfg }, {}, }; -- cgit v1.2.3 From 40b9a914676dea3a1f7044fd6bc67d0cdafbd51c Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Thu, 30 Dec 2021 17:49:02 +0000 Subject: iio:proximity:rfd77402: White space cleanup of spacing around {} in id tables The spacing in this driver was inconsistent with a space after the { but not before the }. Tidy this up to avoid providing a bad example to copy into new drivers. Signed-off-by: Jonathan Cameron Reviewed-by: Gwendal Grignou Link: https://lore.kernel.org/r/20211230174911.78291-8-jic23@kernel.org --- drivers/iio/proximity/rfd77402.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/proximity/rfd77402.c b/drivers/iio/proximity/rfd77402.c index 8c06d02139b6..0ae91963b570 100644 --- a/drivers/iio/proximity/rfd77402.c +++ b/drivers/iio/proximity/rfd77402.c @@ -310,7 +310,7 @@ static int rfd77402_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(rfd77402_pm_ops, rfd77402_suspend, rfd77402_resume); static const struct i2c_device_id rfd77402_id[] = { - { "rfd77402", 0}, + { "rfd77402", 0 }, { } }; MODULE_DEVICE_TABLE(i2c, rfd77402_id); -- cgit v1.2.3 From d9d46abc61a672c01275f8d1a143ceebb88042cd Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Thu, 30 Dec 2021 17:49:03 +0000 Subject: iio:proximity:srf04: White space cleanup of spacing around {} in id tables The spacing in this driver was inconsistent with a space after the { but not before the }. Tidy this up to avoid providing a bad example to copy into new drivers. Signed-off-by: Jonathan Cameron Cc: Andreas Klinger Reviewed-by: Gwendal Grignou Link: https://lore.kernel.org/r/20211230174911.78291-9-jic23@kernel.org --- drivers/iio/proximity/srf04.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/iio/proximity/srf04.c b/drivers/iio/proximity/srf04.c index fe88b2bb60bc..4e6286765f01 100644 --- a/drivers/iio/proximity/srf04.c +++ b/drivers/iio/proximity/srf04.c @@ -235,12 +235,12 @@ static const struct iio_chan_spec srf04_chan_spec[] = { }; static const struct of_device_id of_srf04_match[] = { - { .compatible = "devantech,srf04", .data = &srf04_cfg}, - { .compatible = "maxbotix,mb1000", .data = &mb_lv_cfg}, - { .compatible = "maxbotix,mb1010", .data = &mb_lv_cfg}, - { .compatible = "maxbotix,mb1020", .data = &mb_lv_cfg}, - { .compatible = "maxbotix,mb1030", .data = &mb_lv_cfg}, - { .compatible = "maxbotix,mb1040", .data = &mb_lv_cfg}, + { .compatible = "devantech,srf04", .data = &srf04_cfg }, + { .compatible = "maxbotix,mb1000", .data = &mb_lv_cfg }, + { .compatible = "maxbotix,mb1010", .data = &mb_lv_cfg }, + { .compatible = "maxbotix,mb1020", .data = &mb_lv_cfg }, + { .compatible = "maxbotix,mb1030", .data = &mb_lv_cfg }, + { .compatible = "maxbotix,mb1040", .data = &mb_lv_cfg }, {}, }; -- cgit v1.2.3 From 086fe53fd1a593c15525e611624ab6e03c9d9a2a Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Thu, 30 Dec 2021 17:49:04 +0000 Subject: iio:proximity:srf08: White space cleanup of spacing around {} in id tables The spacing in this driver was inconsistent with a space after the { but not before the }. Tidy this up to avoid providing a bad example to copy into new drivers. Signed-off-by: Jonathan Cameron Cc: Andreas Klinger Reviewed-by: Gwendal Grignou Link: https://lore.kernel.org/r/20211230174911.78291-10-jic23@kernel.org --- drivers/iio/proximity/srf08.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/iio/proximity/srf08.c b/drivers/iio/proximity/srf08.c index 9b0886760f76..ac1ab7e89d4e 100644 --- a/drivers/iio/proximity/srf08.c +++ b/drivers/iio/proximity/srf08.c @@ -528,9 +528,9 @@ static int srf08_probe(struct i2c_client *client, } static const struct of_device_id of_srf08_match[] = { - { .compatible = "devantech,srf02", (void *)SRF02}, - { .compatible = "devantech,srf08", (void *)SRF08}, - { .compatible = "devantech,srf10", (void *)SRF10}, + { .compatible = "devantech,srf02", (void *)SRF02 }, + { .compatible = "devantech,srf08", (void *)SRF08 }, + { .compatible = "devantech,srf10", (void *)SRF10 }, {}, }; -- cgit v1.2.3 From 9ccac0d047ea4d9be48c742e23e82ce18783afea Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Thu, 30 Dec 2021 17:49:05 +0000 Subject: iio:frequency:admv1013: White space cleanup of spacing around {} in id tables The spacing was inconsistent with a space after the { but not before the }. Tidy this up to avoid providing a bad example to copy into new drivers. Signed-off-by: Jonathan Cameron Cc: Antoniu Miclaus Reviewed-by: Gwendal Grignou Link: https://lore.kernel.org/r/20211230174911.78291-11-jic23@kernel.org --- drivers/iio/frequency/admv1013.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/frequency/admv1013.c b/drivers/iio/frequency/admv1013.c index 6cdeb50143af..849a9ea7ebe5 100644 --- a/drivers/iio/frequency/admv1013.c +++ b/drivers/iio/frequency/admv1013.c @@ -630,7 +630,7 @@ static int admv1013_probe(struct spi_device *spi) } static const struct spi_device_id admv1013_id[] = { - { "admv1013", 0}, + { "admv1013", 0 }, {} }; MODULE_DEVICE_TABLE(spi, admv1013_id); -- cgit v1.2.3 From be82553d02540e4140f4d96d29675062b47a976b Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Thu, 30 Dec 2021 17:49:06 +0000 Subject: iio:adc:mt6577_auxadc: Tidy up white space around {} in id tables Previously inconsistent with space after { and not before }. Tidy that up to avoid providing a bad example to copy into new drivers. Signed-off-by: Jonathan Cameron Cc: Zhiyong Tao Cc: Hui Liu Reviewed-by: Gwendal Grignou Link: https://lore.kernel.org/r/20211230174911.78291-12-jic23@kernel.org --- drivers/iio/adc/mt6577_auxadc.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/iio/adc/mt6577_auxadc.c b/drivers/iio/adc/mt6577_auxadc.c index d4fccd52ef08..327fff96c6c8 100644 --- a/drivers/iio/adc/mt6577_auxadc.c +++ b/drivers/iio/adc/mt6577_auxadc.c @@ -330,11 +330,11 @@ static SIMPLE_DEV_PM_OPS(mt6577_auxadc_pm_ops, mt6577_auxadc_resume); static const struct of_device_id mt6577_auxadc_of_match[] = { - { .compatible = "mediatek,mt2701-auxadc", .data = &mt8173_compat}, - { .compatible = "mediatek,mt2712-auxadc", .data = &mt8173_compat}, - { .compatible = "mediatek,mt7622-auxadc", .data = &mt8173_compat}, - { .compatible = "mediatek,mt8173-auxadc", .data = &mt8173_compat}, - { .compatible = "mediatek,mt6765-auxadc", .data = &mt6765_compat}, + { .compatible = "mediatek,mt2701-auxadc", .data = &mt8173_compat }, + { .compatible = "mediatek,mt2712-auxadc", .data = &mt8173_compat }, + { .compatible = "mediatek,mt7622-auxadc", .data = &mt8173_compat }, + { .compatible = "mediatek,mt8173-auxadc", .data = &mt8173_compat }, + { .compatible = "mediatek,mt6765-auxadc", .data = &mt6765_compat }, { } }; MODULE_DEVICE_TABLE(of, mt6577_auxadc_of_match); -- cgit v1.2.3 From 988078cfdb3e56ba11203ccfcfb2f8b350a1844f Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Thu, 30 Dec 2021 17:49:07 +0000 Subject: iio:adc:hi8435: Tidy up white space around {} in id tables Previously inconsistent with space after { but not before }. Tidy that up to avoid providing a bad example to copy into new drivers. Signed-off-by: Jonathan Cameron Reviewed-by: Gwendal Grignou Link: https://lore.kernel.org/r/20211230174911.78291-13-jic23@kernel.org --- drivers/iio/adc/hi8435.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/adc/hi8435.c b/drivers/iio/adc/hi8435.c index e665e14c6e54..8eb0140df133 100644 --- a/drivers/iio/adc/hi8435.c +++ b/drivers/iio/adc/hi8435.c @@ -529,7 +529,7 @@ static const struct of_device_id hi8435_dt_ids[] = { MODULE_DEVICE_TABLE(of, hi8435_dt_ids); static const struct spi_device_id hi8435_id[] = { - { "hi8435", 0}, + { "hi8435", 0 }, { } }; MODULE_DEVICE_TABLE(spi, hi8435_id); -- cgit v1.2.3 From 04e543086c1339afd07ca6ce8fea0ea3816b1b53 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Thu, 30 Dec 2021 17:49:08 +0000 Subject: iio:adc:ti-adc084s021: Tidy up white space around {} Previously inconsistent with a space after { but not before }. Tidy that up to avoid providing an example to copy into new drivers. Signed-off-by: Jonathan Cameron Cc: Gwendal Grignou Reviewed-by: Gwendal Grignou Link: https://lore.kernel.org/r/20211230174911.78291-14-jic23@kernel.org --- drivers/iio/adc/ti-adc084s021.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/adc/ti-adc084s021.c b/drivers/iio/adc/ti-adc084s021.c index ce3f5a3814f9..c9b5d9aec3dc 100644 --- a/drivers/iio/adc/ti-adc084s021.c +++ b/drivers/iio/adc/ti-adc084s021.c @@ -248,7 +248,7 @@ static const struct of_device_id adc084s021_of_match[] = { MODULE_DEVICE_TABLE(of, adc084s021_of_match); static const struct spi_device_id adc084s021_id[] = { - { ADC084S021_DRIVER_NAME, 0}, + { ADC084S021_DRIVER_NAME, 0 }, {} }; MODULE_DEVICE_TABLE(spi, adc084s021_id); -- cgit v1.2.3 From 2d77524b07267318faa5d06a51665872ad9aa5a1 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Thu, 30 Dec 2021 17:49:09 +0000 Subject: iio:light:tsl2722: Fix inconsistent spacing before } in id table The final entry was missing a space. Tidy that up. Signed-off-by: Jonathan Cameron Reviewed-by: Gwendal Grignou Link: https://lore.kernel.org/r/20211230174911.78291-15-jic23@kernel.org --- drivers/iio/light/tsl2772.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/light/tsl2772.c b/drivers/iio/light/tsl2772.c index d79205361dfa..729f14d9f2a4 100644 --- a/drivers/iio/light/tsl2772.c +++ b/drivers/iio/light/tsl2772.c @@ -1902,7 +1902,7 @@ static const struct i2c_device_id tsl2772_idtable[] = { { "tmd2672", tmd2672 }, { "tsl2772", tsl2772 }, { "tmd2772", tmd2772 }, - { "apds9930", apds9930}, + { "apds9930", apds9930 }, {} }; -- cgit v1.2.3 From 86eae303c0d67be23a06cb51dbeca5edef0d575c Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Thu, 30 Dec 2021 17:49:10 +0000 Subject: iio:proximity:vl53l0x: Tidy up white space around {} in id tables Previously inconsistent with a space after { but not before }. Tidy that up to avoid providing a bad example that might get copied into other drivers. Signed-off-by: Jonathan Cameron Cc: Ivan Drobyshevskyi Reviewed-by: Gwendal Grignou Link: https://lore.kernel.org/r/20211230174911.78291-16-jic23@kernel.org --- drivers/iio/proximity/vl53l0x-i2c.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/proximity/vl53l0x-i2c.c b/drivers/iio/proximity/vl53l0x-i2c.c index cf38144b6f95..661a79ea200d 100644 --- a/drivers/iio/proximity/vl53l0x-i2c.c +++ b/drivers/iio/proximity/vl53l0x-i2c.c @@ -226,7 +226,7 @@ static int vl53l0x_probe(struct i2c_client *client) } static const struct i2c_device_id vl53l0x_id[] = { - { "vl53l0x", 0}, + { "vl53l0x", 0 }, { } }; MODULE_DEVICE_TABLE(i2c, vl53l0x_id); -- cgit v1.2.3 From 8c7b323a5573fae03b1902f09503f7fb559bfd77 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Thu, 30 Dec 2021 17:49:11 +0000 Subject: iio:accel:dmard09: Tidy up white space around {} in id table Previously inconsistent with a space after { but not before }. Tidy that up to avoid providing a bad example that might get copied into other drivers. Signed-off-by: Jonathan Cameron Reviewed-by: Gwendal Grignou Link: https://lore.kernel.org/r/20211230174911.78291-17-jic23@kernel.org --- drivers/iio/accel/dmard09.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/accel/dmard09.c b/drivers/iio/accel/dmard09.c index e6e28c964777..53ab6078cb7f 100644 --- a/drivers/iio/accel/dmard09.c +++ b/drivers/iio/accel/dmard09.c @@ -126,7 +126,7 @@ static int dmard09_probe(struct i2c_client *client, } static const struct i2c_device_id dmard09_id[] = { - { "dmard09", 0}, + { "dmard09", 0 }, { }, }; -- cgit v1.2.3 From 1f69d222242c190f54ebf86eb7b9ba7b3f2d7630 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 6 Jan 2022 12:25:11 -0600 Subject: dt-bindings: iio/adc: ti,palmas-gpadc: Split interrupt fields in example Best practice for multi-cell property values is to bracket each multi-cell value. Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/20220106182518.1435497-3-robh@kernel.org Signed-off-by: Jonathan Cameron --- Documentation/devicetree/bindings/iio/adc/ti,palmas-gpadc.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/iio/adc/ti,palmas-gpadc.yaml b/Documentation/devicetree/bindings/iio/adc/ti,palmas-gpadc.yaml index 7b895784e008..57a31356082e 100644 --- a/Documentation/devicetree/bindings/iio/adc/ti,palmas-gpadc.yaml +++ b/Documentation/devicetree/bindings/iio/adc/ti,palmas-gpadc.yaml @@ -74,9 +74,9 @@ examples: compatible = "ti,twl6035-pmic", "ti,palmas-pmic"; adc { compatible = "ti,palmas-gpadc"; - interrupts = <18 0 - 16 0 - 17 0>; + interrupts = <18 0>, + <16 0>, + <17 0>; #io-channel-cells = <1>; ti,channel0-current-microamp = <5>; ti,channel3-current-microamp = <10>; -- cgit v1.2.3 From 2553340bd208cc2e54a9e6a27d948a2b51dbf3a1 Mon Sep 17 00:00:00 2001 From: Lad Prabhakar Date: Fri, 7 Jan 2022 17:25:29 +0000 Subject: iio: adc: rzg2l_adc: Fix typo Fix typo RZG2L_ADSMP_DEFUALT_SAMPLING -> RZG2L_ADSMP_DEFAULT_SAMPLING. Reported-by: Pavel Machek Signed-off-by: Lad Prabhakar Reviewed-by: Pavel Machek Link: https://lore.kernel.org/r/20220107172529.12361-1-prabhakar.mahadev-lad.rj@bp.renesas.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/rzg2l_adc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/iio/adc/rzg2l_adc.c b/drivers/iio/adc/rzg2l_adc.c index 9d5be52bd948..7585144b9715 100644 --- a/drivers/iio/adc/rzg2l_adc.c +++ b/drivers/iio/adc/rzg2l_adc.c @@ -55,7 +55,7 @@ #define RZG2L_ADCR(n) (0x30 + ((n) * 0x4)) #define RZG2L_ADCR_AD_MASK GENMASK(11, 0) -#define RZG2L_ADSMP_DEFUALT_SAMPLING 0x578 +#define RZG2L_ADSMP_DEFAULT_SAMPLING 0x578 #define RZG2L_ADC_MAX_CHANNELS 8 #define RZG2L_ADC_CHN_MASK 0x7 @@ -395,7 +395,7 @@ static int rzg2l_adc_hw_init(struct rzg2l_adc *adc) reg &= ~RZG2L_ADM3_ADIL_MASK; reg &= ~RZG2L_ADM3_ADCMP_MASK; reg &= ~RZG2L_ADM3_ADSMP_MASK; - reg |= (RZG2L_ADM3_ADCMP_E | RZG2L_ADSMP_DEFUALT_SAMPLING); + reg |= (RZG2L_ADM3_ADCMP_E | RZG2L_ADSMP_DEFAULT_SAMPLING); rzg2l_adc_writel(adc, RZG2L_ADM(3), reg); exit_hw_init: -- cgit v1.2.3 From 26b2ec2e9a27f881998b830fd5158f8a30de82a1 Mon Sep 17 00:00:00 2001 From: Nikita Yushchenko Date: Mon, 10 Jan 2022 18:24:32 +0300 Subject: iio: st_sensors: don't always auto-enable I2C and SPI interface drivers This patch makes I2C and SPI interface drivers for STMicroelectronics sensor chips individually selectable via Kconfig. The default is kept unchanged - I2C and SPI interface drivers are still selected by default if the corresponding bus support is available. However, the patch makes it possible to explicitly disable drivers that are not needed for a particular target. Signed-off-by: Nikita Yushchenko Acked-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220110152432.3799227-1-nikita.yoush@cogentembedded.com Signed-off-by: Jonathan Cameron --- drivers/iio/accel/Kconfig | 35 +++++++++++++++++++-------------- drivers/iio/common/st_sensors/Kconfig | 2 -- drivers/iio/gyro/Kconfig | 37 +++++++++++++++++++++-------------- drivers/iio/imu/st_lsm9ds0/Kconfig | 28 ++++++++++++++++++++------ drivers/iio/magnetometer/Kconfig | 35 +++++++++++++++++++-------------- drivers/iio/pressure/Kconfig | 35 +++++++++++++++++++-------------- 6 files changed, 104 insertions(+), 68 deletions(-) diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig index 49587c992a6d..eb17ca40e08a 100644 --- a/drivers/iio/accel/Kconfig +++ b/drivers/iio/accel/Kconfig @@ -349,8 +349,6 @@ config IIO_ST_ACCEL_3AXIS depends on !SENSORS_LIS3_I2C depends on !SENSORS_LIS3_SPI select IIO_ST_SENSORS_CORE - select IIO_ST_ACCEL_I2C_3AXIS if (I2C) - select IIO_ST_ACCEL_SPI_3AXIS if (SPI_MASTER) select IIO_TRIGGERED_BUFFER if (IIO_BUFFER) help Say yes here to build support for STMicroelectronics accelerometers: @@ -358,23 +356,30 @@ config IIO_ST_ACCEL_3AXIS LIS331DLH, LSM303DL, LSM303DLM, LSM330, LIS2DH12, H3LIS331DL, LNG2DM, LIS3DE, LIS2DE12, LIS2HH12 - This driver can also be built as a module. If so, these modules - will be created: - - st_accel (core functions for the driver [it is mandatory]); - - st_accel_i2c (necessary for the I2C devices [optional*]); - - st_accel_spi (necessary for the SPI devices [optional*]); - - (*) one of these is necessary to do something. + Also need to enable at least one of I2C and SPI interface drivers + below. config IIO_ST_ACCEL_I2C_3AXIS - tristate - depends on IIO_ST_ACCEL_3AXIS - depends on IIO_ST_SENSORS_I2C + tristate "STMicroelectronics accelerometers 3-Axis I2C Interface" + depends on I2C && IIO_ST_ACCEL_3AXIS + default I2C && IIO_ST_ACCEL_3AXIS + select IIO_ST_SENSORS_I2C + help + Build support for STMicroelectronics accelerometers I2C interface. + + To compile this driver as a module, choose M here. The module + will be called st_accel_i2c. config IIO_ST_ACCEL_SPI_3AXIS - tristate - depends on IIO_ST_ACCEL_3AXIS - depends on IIO_ST_SENSORS_SPI + tristate "STMicroelectronics accelerometers 3-Axis SPI Interface" + depends on SPI_MASTER && IIO_ST_ACCEL_3AXIS + default SPI_MASTER && IIO_ST_ACCEL_3AXIS + select IIO_ST_SENSORS_SPI + help + Build support for STMicroelectronics accelerometers SPI interface. + + To compile this driver as a module, choose M here. The module + will be called st_accel_spi. config KXSD9 tristate "Kionix KXSD9 Accelerometer Driver" diff --git a/drivers/iio/common/st_sensors/Kconfig b/drivers/iio/common/st_sensors/Kconfig index 9364ec7a811f..eda8f347fda5 100644 --- a/drivers/iio/common/st_sensors/Kconfig +++ b/drivers/iio/common/st_sensors/Kconfig @@ -13,5 +13,3 @@ config IIO_ST_SENSORS_SPI config IIO_ST_SENSORS_CORE tristate - select IIO_ST_SENSORS_I2C if I2C - select IIO_ST_SENSORS_SPI if SPI_MASTER diff --git a/drivers/iio/gyro/Kconfig b/drivers/iio/gyro/Kconfig index a672f7d12bbb..97b86c4a53a6 100644 --- a/drivers/iio/gyro/Kconfig +++ b/drivers/iio/gyro/Kconfig @@ -139,30 +139,37 @@ config IIO_ST_GYRO_3AXIS tristate "STMicroelectronics gyroscopes 3-Axis Driver" depends on (I2C || SPI_MASTER) && SYSFS select IIO_ST_SENSORS_CORE - select IIO_ST_GYRO_I2C_3AXIS if (I2C) - select IIO_ST_GYRO_SPI_3AXIS if (SPI_MASTER) select IIO_TRIGGERED_BUFFER if (IIO_BUFFER) help Say yes here to build support for STMicroelectronics gyroscopes: L3G4200D, LSM330DL, L3GD20, LSM330DLC, L3G4IS, LSM330, LSM9DS0. - This driver can also be built as a module. If so, these modules - will be created: - - st_gyro (core functions for the driver [it is mandatory]); - - st_gyro_i2c (necessary for the I2C devices [optional*]); - - st_gyro_spi (necessary for the SPI devices [optional*]); - - (*) one of these is necessary to do something. + Also need to enable at least one of I2C and SPI interface drivers + below. config IIO_ST_GYRO_I2C_3AXIS - tristate - depends on IIO_ST_GYRO_3AXIS - depends on IIO_ST_SENSORS_I2C + tristate "STMicroelectronics gyroscopes 3-Axis I2C Interface" + depends on I2C && IIO_ST_GYRO_3AXIS + default I2C && IIO_ST_GYRO_3AXIS + select IIO_ST_SENSORS_I2C + help + Build support for STMicroelectronics gyroscopes I2C interface. + + To compile this driver as a module, choose M here. The module + will be called st_gyro_i2c. + config IIO_ST_GYRO_SPI_3AXIS - tristate - depends on IIO_ST_GYRO_3AXIS - depends on IIO_ST_SENSORS_SPI + tristate "STMicroelectronics gyroscopes 3-Axis SPI Interface" + depends on SPI_MASTER && IIO_ST_GYRO_3AXIS + default SPI_MASTER && IIO_ST_GYRO_3AXIS + select IIO_ST_SENSORS_SPI + help + Build support for STMicroelectronics gyroscopes SPI interface. + + To compile this driver as a module, choose M here. The module + will be called st_gyro_spi. + config ITG3200 tristate "InvenSense ITG3200 Digital 3-Axis Gyroscope I2C driver" diff --git a/drivers/iio/imu/st_lsm9ds0/Kconfig b/drivers/iio/imu/st_lsm9ds0/Kconfig index 53b7017014f8..d29558edee60 100644 --- a/drivers/iio/imu/st_lsm9ds0/Kconfig +++ b/drivers/iio/imu/st_lsm9ds0/Kconfig @@ -5,8 +5,6 @@ config IIO_ST_LSM9DS0 depends on (I2C || SPI_MASTER) && SYSFS depends on !SENSORS_LIS3_I2C depends on !SENSORS_LIS3_SPI - select IIO_ST_LSM9DS0_I2C if I2C - select IIO_ST_LSM9DS0_SPI if SPI_MASTER select IIO_ST_ACCEL_3AXIS select IIO_ST_MAGN_3AXIS @@ -17,12 +15,30 @@ config IIO_ST_LSM9DS0 To compile this driver as a module, choose M here: the module will be called st_lsm9ds0. + Also need to enable at least one of I2C and SPI interface drivers + config IIO_ST_LSM9DS0_I2C - tristate - depends on IIO_ST_LSM9DS0 + tristate "STMicroelectronics LSM9DS0 IMU I2C interface" + depends on I2C && IIO_ST_LSM9DS0 + default I2C && IIO_ST_LSM9DS0 + select IIO_ST_ACCEL_I2C_3AXIS + select IIO_ST_MAGN_I2C_3AXIS select REGMAP_I2C + help + Build support for STMicroelectronics LSM9DS0 IMU I2C interface. + + To compile this driver as a module, choose M here. The module + will be called st_lsm9ds0_i2c. config IIO_ST_LSM9DS0_SPI - tristate - depends on IIO_ST_LSM9DS0 + tristate "STMicroelectronics LSM9DS0 IMU SPI interface" + depends on SPI_MASTER && IIO_ST_LSM9DS0 + default SPI_MASTER && IIO_ST_LSM9DS0 + select IIO_ST_ACCEL_SPI_3AXIS + select IIO_ST_MAGN_SPI_3AXIS select REGMAP_SPI + help + Build support for STMicroelectronics LSM9DS0 IMU I2C interface. + + To compile this driver as a module, choose M here. The module + will be called st_lsm9ds0_spi. diff --git a/drivers/iio/magnetometer/Kconfig b/drivers/iio/magnetometer/Kconfig index 565ee41ccb3a..54445365c4bc 100644 --- a/drivers/iio/magnetometer/Kconfig +++ b/drivers/iio/magnetometer/Kconfig @@ -117,30 +117,35 @@ config IIO_ST_MAGN_3AXIS tristate "STMicroelectronics magnetometers 3-Axis Driver" depends on (I2C || SPI_MASTER) && SYSFS select IIO_ST_SENSORS_CORE - select IIO_ST_MAGN_I2C_3AXIS if (I2C) - select IIO_ST_MAGN_SPI_3AXIS if (SPI_MASTER) select IIO_TRIGGERED_BUFFER if (IIO_BUFFER) help Say yes here to build support for STMicroelectronics magnetometers: LSM303DLHC, LSM303DLM, LIS3MDL. - This driver can also be built as a module. If so, these modules - will be created: - - st_magn (core functions for the driver [it is mandatory]); - - st_magn_i2c (necessary for the I2C devices [optional*]); - - st_magn_spi (necessary for the SPI devices [optional*]); - - (*) one of these is necessary to do something. + Also need to enable at least one of I2C and SPI interface drivers + below. config IIO_ST_MAGN_I2C_3AXIS - tristate - depends on IIO_ST_MAGN_3AXIS - depends on IIO_ST_SENSORS_I2C + tristate "STMicroelectronics magnetometers 3-Axis I2C Interface" + depends on I2C && IIO_ST_MAGN_3AXIS + default I2C && IIO_ST_MAGN_3AXIS + select IIO_ST_SENSORS_I2C + help + Build support for STMicroelectronics magnetometers I2C interface. + + To compile this driver as a module, choose M here. The module + will be called st_magn_i2c. config IIO_ST_MAGN_SPI_3AXIS - tristate - depends on IIO_ST_MAGN_3AXIS - depends on IIO_ST_SENSORS_SPI + tristate "STMicroelectronics magnetometers 3-Axis SPI Interface" + depends on SPI_MASTER && IIO_ST_MAGN_3AXIS + default SPI_MASTER && IIO_ST_MAGN_3AXIS + select IIO_ST_SENSORS_SPI + help + Build support for STMicroelectronics magnetometers SPI interface. + + To compile this driver as a module, choose M here. The module + will be called st_magn_spi. config SENSORS_HMC5843 tristate diff --git a/drivers/iio/pressure/Kconfig b/drivers/iio/pressure/Kconfig index fc0d3cfca418..0ff756cea63a 100644 --- a/drivers/iio/pressure/Kconfig +++ b/drivers/iio/pressure/Kconfig @@ -194,30 +194,35 @@ config IIO_ST_PRESS tristate "STMicroelectronics pressure sensor Driver" depends on (I2C || SPI_MASTER) && SYSFS select IIO_ST_SENSORS_CORE - select IIO_ST_PRESS_I2C if (I2C) - select IIO_ST_PRESS_SPI if (SPI_MASTER) select IIO_TRIGGERED_BUFFER if (IIO_BUFFER) help Say yes here to build support for STMicroelectronics pressure sensors: LPS001WP, LPS25H, LPS331AP, LPS22HB, LPS22HH. - This driver can also be built as a module. If so, these modules - will be created: - - st_pressure (core functions for the driver [it is mandatory]); - - st_pressure_i2c (necessary for the I2C devices [optional*]); - - st_pressure_spi (necessary for the SPI devices [optional*]); - - (*) one of these is necessary to do something. + Also need to enable at least one of I2C and SPI interface drivers + below. config IIO_ST_PRESS_I2C - tristate - depends on IIO_ST_PRESS - depends on IIO_ST_SENSORS_I2C + tristate "STMicroelectronics pressure sensor I2C Interface" + depends on I2C && IIO_ST_PRESS + default I2C && IIO_ST_PRESS + select IIO_ST_SENSORS_I2C + help + Build support for STMicroelectronics pressure sensor I2C interface. + + To compile this driver as a module, choose M here. The module + will be called st_pressure_i2c. config IIO_ST_PRESS_SPI - tristate - depends on IIO_ST_PRESS - depends on IIO_ST_SENSORS_SPI + tristate "STMicroelectronics pressure sensor SPI Interface" + depends on SPI_MASTER && IIO_ST_PRESS + default SPI_MASTER && IIO_ST_PRESS + select IIO_ST_SENSORS_SPI + help + Build support for STMicroelectronics pressure sensor SPI interface. + + To compile this driver as a module, choose M here. The module + will be called st_pressure_spi. config T5403 tristate "EPCOS T5403 digital barometric pressure sensor driver" -- cgit v1.2.3 From f247d58efbce7eb017b32ed713f4770ef635eb30 Mon Sep 17 00:00:00 2001 From: Guodong Liu Date: Mon, 10 Jan 2022 16:48:40 +0800 Subject: dt-bindings: iio: adc: Add compatible for Mediatek MT8186 This commit adds dt-binding documentation of auxadc for Mediatek MT8186 SoC Platform. Signed-off-by: Guodong Liu Acked-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20220110084841.575-1-guodong.liu@mediatek.com Signed-off-by: Jonathan Cameron --- Documentation/devicetree/bindings/iio/adc/mediatek,mt2701-auxadc.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/iio/adc/mediatek,mt2701-auxadc.yaml b/Documentation/devicetree/bindings/iio/adc/mediatek,mt2701-auxadc.yaml index b939f9652e3a..65581ad4b816 100644 --- a/Documentation/devicetree/bindings/iio/adc/mediatek,mt2701-auxadc.yaml +++ b/Documentation/devicetree/bindings/iio/adc/mediatek,mt2701-auxadc.yaml @@ -34,6 +34,7 @@ properties: - items: - enum: - mediatek,mt8183-auxadc + - mediatek,mt8186-auxadc - mediatek,mt8195-auxadc - mediatek,mt8516-auxadc - const: mediatek,mt8173-auxadc -- cgit v1.2.3 From ff04eb478658743c43d8ca0d3fa949b6d3fe03b4 Mon Sep 17 00:00:00 2001 From: Guodong Liu Date: Mon, 10 Jan 2022 16:48:41 +0800 Subject: iio: adc: mt8186: Add compatible node for mt8186 This commit adds mt8186 compatible node. Signed-off-by: Guodong Liu Acked-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20220110084841.575-2-guodong.liu@mediatek.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/mt6577_auxadc.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/iio/adc/mt6577_auxadc.c b/drivers/iio/adc/mt6577_auxadc.c index 327fff96c6c8..e78c96a185db 100644 --- a/drivers/iio/adc/mt6577_auxadc.c +++ b/drivers/iio/adc/mt6577_auxadc.c @@ -46,6 +46,11 @@ struct mt6577_auxadc_device { const struct mtk_auxadc_compatible *dev_comp; }; +static const struct mtk_auxadc_compatible mt8186_compat = { + .sample_data_cali = false, + .check_global_idle = false, +}; + static const struct mtk_auxadc_compatible mt8173_compat = { .sample_data_cali = false, .check_global_idle = true, @@ -334,6 +339,7 @@ static const struct of_device_id mt6577_auxadc_of_match[] = { { .compatible = "mediatek,mt2712-auxadc", .data = &mt8173_compat }, { .compatible = "mediatek,mt7622-auxadc", .data = &mt8173_compat }, { .compatible = "mediatek,mt8173-auxadc", .data = &mt8173_compat }, + { .compatible = "mediatek,mt8186-auxadc", .data = &mt8186_compat }, { .compatible = "mediatek,mt6765-auxadc", .data = &mt6765_compat }, { } }; -- cgit v1.2.3 From 1e73d7f689c7a8fa13f78fe8d6be908fdceef17a Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Wed, 15 Dec 2021 16:13:35 +0100 Subject: iio: core: Fix the kernel doc regarding the currentmode iio_dev entry This is an internal variable, which should be accessed in a very sporadic way and in no case changed by any device driver. Signed-off-by: Miquel Raynal Reviewed-by: Alexandru Ardelean Link: https://lore.kernel.org/r/20211215151344.163036-2-miquel.raynal@bootlin.com Signed-off-by: Jonathan Cameron --- include/linux/iio/iio.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h index 07025d6b3de1..faf00f2c0be6 100644 --- a/include/linux/iio/iio.h +++ b/include/linux/iio/iio.h @@ -489,7 +489,7 @@ struct iio_buffer_setup_ops { /** * struct iio_dev - industrial I/O device * @modes: [DRIVER] operating modes supported by device - * @currentmode: [DRIVER] current operating mode + * @currentmode: [INTERN] current operating mode * @dev: [DRIVER] device structure, should be assigned a parent * and owner * @buffer: [DRIVER] any buffer present -- cgit v1.2.3 From 008cc058a4ff54d0e88d4dcabeb94ae4c83ed299 Mon Sep 17 00:00:00 2001 From: Antoniu Miclaus Date: Mon, 3 Jan 2022 12:44:12 +0200 Subject: MAINTAINERS: fix Analog Devices links The forum link for the Analog Devices linux drivers has changed. Fix the links to redirect to the correct forum subsection. Signed-off-by: Antoniu Miclaus Link: https://lore.kernel.org/r/20220103104412.81247-1-antoniu.miclaus@analog.com Signed-off-by: Jonathan Cameron --- MAINTAINERS | 56 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index ea3e6c914384..530616d4001c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -460,35 +460,35 @@ AD525X ANALOG DEVICES DIGITAL POTENTIOMETERS DRIVER M: Michael Hennerich S: Supported W: http://wiki.analog.com/AD5254 -W: http://ez.analog.com/community/linux-device-drivers +W: https://ez.analog.com/linux-software-drivers F: drivers/misc/ad525x_dpot.c AD5398 CURRENT REGULATOR DRIVER (AD5398/AD5821) M: Michael Hennerich S: Supported W: http://wiki.analog.com/AD5398 -W: http://ez.analog.com/community/linux-device-drivers +W: https://ez.analog.com/linux-software-drivers F: drivers/regulator/ad5398.c AD714X CAPACITANCE TOUCH SENSOR DRIVER (AD7142/3/7/8/7A) M: Michael Hennerich S: Supported W: http://wiki.analog.com/AD7142 -W: http://ez.analog.com/community/linux-device-drivers +W: https://ez.analog.com/linux-software-drivers F: drivers/input/misc/ad714x.c AD7877 TOUCHSCREEN DRIVER M: Michael Hennerich S: Supported W: http://wiki.analog.com/AD7877 -W: http://ez.analog.com/community/linux-device-drivers +W: https://ez.analog.com/linux-software-drivers F: drivers/input/touchscreen/ad7877.c AD7879 TOUCHSCREEN DRIVER (AD7879/AD7889) M: Michael Hennerich S: Supported W: http://wiki.analog.com/AD7879 -W: http://ez.analog.com/community/linux-device-drivers +W: https://ez.analog.com/linux-software-drivers F: drivers/input/touchscreen/ad7879.c ADDRESS SPACE LAYOUT RANDOMIZATION (ASLR) @@ -500,7 +500,7 @@ M: Michael Hennerich L: linux-wpan@vger.kernel.org S: Supported W: https://wiki.analog.com/ADF7242 -W: http://ez.analog.com/community/linux-device-drivers +W: https://ez.analog.com/linux-software-drivers F: Documentation/devicetree/bindings/net/ieee802154/adf7242.txt F: drivers/net/ieee802154/adf7242.c @@ -534,7 +534,7 @@ ADP5520 BACKLIGHT DRIVER WITH IO EXPANDER (ADP5520/ADP5501) M: Michael Hennerich S: Supported W: http://wiki.analog.com/ADP5520 -W: http://ez.analog.com/community/linux-device-drivers +W: https://ez.analog.com/linux-software-drivers F: drivers/gpio/gpio-adp5520.c F: drivers/input/keyboard/adp5520-keys.c F: drivers/leds/leds-adp5520.c @@ -545,7 +545,7 @@ ADP5588 QWERTY KEYPAD AND IO EXPANDER DRIVER (ADP5588/ADP5587) M: Michael Hennerich S: Supported W: http://wiki.analog.com/ADP5588 -W: http://ez.analog.com/community/linux-device-drivers +W: https://ez.analog.com/linux-software-drivers F: drivers/gpio/gpio-adp5588.c F: drivers/input/keyboard/adp5588-keys.c @@ -553,7 +553,7 @@ ADP8860 BACKLIGHT DRIVER (ADP8860/ADP8861/ADP8863) M: Michael Hennerich S: Supported W: http://wiki.analog.com/ADP8860 -W: http://ez.analog.com/community/linux-device-drivers +W: https://ez.analog.com/linux-software-drivers F: drivers/video/backlight/adp8860_bl.c ADT746X FAN DRIVER @@ -592,7 +592,7 @@ ADXL34X THREE-AXIS DIGITAL ACCELEROMETER DRIVER (ADXL345/ADXL346) M: Michael Hennerich S: Supported W: http://wiki.analog.com/ADXL345 -W: http://ez.analog.com/community/linux-device-drivers +W: https://ez.analog.com/linux-software-drivers F: Documentation/devicetree/bindings/iio/accel/adi,adxl345.yaml F: drivers/input/misc/adxl34x.c @@ -609,7 +609,7 @@ F: drivers/iio/accel/adxl355_spi.c ADXL372 THREE-AXIS DIGITAL ACCELEROMETER DRIVER M: Michael Hennerich S: Supported -W: http://ez.analog.com/community/linux-device-drivers +W: https://ez.analog.com/linux-software-drivers F: Documentation/devicetree/bindings/iio/accel/adi,adxl372.yaml F: drivers/iio/accel/adxl372.c F: drivers/iio/accel/adxl372_i2c.c @@ -1049,7 +1049,7 @@ ANALOG DEVICES INC AD7192 DRIVER M: Alexandru Tachici L: linux-iio@vger.kernel.org S: Supported -W: http://ez.analog.com/community/linux-device-drivers +W: https://ez.analog.com/linux-software-drivers F: Documentation/devicetree/bindings/iio/adc/adi,ad7192.yaml F: drivers/iio/adc/ad7192.c @@ -1057,7 +1057,7 @@ ANALOG DEVICES INC AD7292 DRIVER M: Marcelo Schmitt L: linux-iio@vger.kernel.org S: Supported -W: http://ez.analog.com/community/linux-device-drivers +W: https://ez.analog.com/linux-software-drivers F: Documentation/devicetree/bindings/iio/adc/adi,ad7292.yaml F: drivers/iio/adc/ad7292.c @@ -1065,7 +1065,7 @@ ANALOG DEVICES INC AD7768-1 DRIVER M: Michael Hennerich L: linux-iio@vger.kernel.org S: Supported -W: http://ez.analog.com/community/linux-device-drivers +W: https://ez.analog.com/linux-software-drivers F: Documentation/devicetree/bindings/iio/adc/adi,ad7768-1.yaml F: drivers/iio/adc/ad7768-1.c @@ -1074,7 +1074,7 @@ M: Michael Hennerich M: Renato Lui Geh L: linux-iio@vger.kernel.org S: Supported -W: http://ez.analog.com/community/linux-device-drivers +W: https://ez.analog.com/linux-software-drivers F: Documentation/devicetree/bindings/iio/adc/adi,ad7780.yaml F: drivers/iio/adc/ad7780.c @@ -1103,7 +1103,7 @@ ANALOG DEVICES INC ADIN DRIVER M: Michael Hennerich L: netdev@vger.kernel.org S: Supported -W: http://ez.analog.com/community/linux-device-drivers +W: https://ez.analog.com/linux-software-drivers F: Documentation/devicetree/bindings/net/adi,adin.yaml F: drivers/net/phy/adin.c @@ -1118,14 +1118,14 @@ ANALOG DEVICES INC ADIS16460 DRIVER M: Dragos Bogdan L: linux-iio@vger.kernel.org S: Supported -W: http://ez.analog.com/community/linux-device-drivers +W: https://ez.analog.com/linux-software-drivers F: Documentation/devicetree/bindings/iio/imu/adi,adis16460.yaml F: drivers/iio/imu/adis16460.c ANALOG DEVICES INC ADIS16475 DRIVER M: Nuno Sa L: linux-iio@vger.kernel.org -W: http://ez.analog.com/community/linux-device-drivers +W: https://ez.analog.com/linux-software-drivers S: Supported F: drivers/iio/imu/adis16475.c F: Documentation/devicetree/bindings/iio/imu/adi,adis16475.yaml @@ -1134,7 +1134,7 @@ ANALOG DEVICES INC ADM1177 DRIVER M: Michael Hennerich L: linux-hwmon@vger.kernel.org S: Supported -W: http://ez.analog.com/community/linux-device-drivers +W: https://ez.analog.com/linux-software-drivers F: Documentation/devicetree/bindings/hwmon/adi,adm1177.yaml F: drivers/hwmon/adm1177.c @@ -1142,14 +1142,14 @@ ANALOG DEVICES INC ADP5061 DRIVER M: Michael Hennerich L: linux-pm@vger.kernel.org S: Supported -W: http://ez.analog.com/community/linux-device-drivers +W: https://ez.analog.com/linux-software-drivers F: drivers/power/supply/adp5061.c ANALOG DEVICES INC ADV7180 DRIVER M: Lars-Peter Clausen L: linux-media@vger.kernel.org S: Supported -W: http://ez.analog.com/community/linux-device-drivers +W: https://ez.analog.com/linux-software-drivers F: drivers/media/i2c/adv7180.c F: Documentation/devicetree/bindings/media/i2c/adv7180.yaml @@ -1192,7 +1192,7 @@ M: Nuno Sá L: alsa-devel@alsa-project.org (moderated for non-subscribers) S: Supported W: http://wiki.analog.com/ -W: http://ez.analog.com/community/linux-device-drivers +W: https://ez.analog.com/linux-software-drivers F: sound/soc/codecs/ad1* F: sound/soc/codecs/ad7* F: sound/soc/codecs/adau* @@ -1203,7 +1203,7 @@ F: sound/soc/codecs/ssm* ANALOG DEVICES INC DMA DRIVERS M: Lars-Peter Clausen S: Supported -W: http://ez.analog.com/community/linux-device-drivers +W: https://ez.analog.com/linux-software-drivers F: drivers/dma/dma-axi-dmac.c ANALOG DEVICES INC IIO DRIVERS @@ -1211,7 +1211,7 @@ M: Lars-Peter Clausen M: Michael Hennerich S: Supported W: http://wiki.analog.com/ -W: http://ez.analog.com/community/linux-device-drivers +W: https://ez.analog.com/linux-software-drivers F: Documentation/ABI/testing/sysfs-bus-iio-frequency-ad9523 F: Documentation/ABI/testing/sysfs-bus-iio-frequency-adf4350 F: Documentation/devicetree/bindings/iio/*/adi,* @@ -3273,7 +3273,7 @@ AXI-FAN-CONTROL HARDWARE MONITOR DRIVER M: Nuno Sá L: linux-hwmon@vger.kernel.org S: Supported -W: http://ez.analog.com/community/linux-device-drivers +W: https://ez.analog.com/linux-software-drivers F: Documentation/devicetree/bindings/hwmon/adi,axi-fan-control.yaml F: drivers/hwmon/axi-fan-control.c @@ -11263,7 +11263,7 @@ LTC2947 HARDWARE MONITOR DRIVER M: Nuno Sá L: linux-hwmon@vger.kernel.org S: Supported -W: http://ez.analog.com/community/linux-device-drivers +W: https://ez.analog.com/linux-software-drivers F: Documentation/devicetree/bindings/hwmon/adi,ltc2947.yaml F: drivers/hwmon/ltc2947-core.c F: drivers/hwmon/ltc2947-i2c.c @@ -11274,7 +11274,7 @@ LTC2983 IIO TEMPERATURE DRIVER M: Nuno Sá L: linux-iio@vger.kernel.org S: Supported -W: http://ez.analog.com/community/linux-device-drivers +W: https://ez.analog.com/linux-software-drivers F: Documentation/devicetree/bindings/iio/temperature/adi,ltc2983.yaml F: drivers/iio/temperature/ltc2983.c @@ -11289,7 +11289,7 @@ LTC4306 I2C MULTIPLEXER DRIVER M: Michael Hennerich L: linux-i2c@vger.kernel.org S: Supported -W: http://ez.analog.com/community/linux-device-drivers +W: https://ez.analog.com/linux-software-drivers F: Documentation/devicetree/bindings/i2c/i2c-mux-ltc4306.txt F: drivers/i2c/muxes/i2c-mux-ltc4306.c -- cgit v1.2.3 From 0f66edfb0722bc424c5d8300e5a938b1b7c5c78f Mon Sep 17 00:00:00 2001 From: Antoniu Miclaus Date: Mon, 3 Jan 2022 13:16:24 +0200 Subject: MAINTAINERS: add maintainer for ADRF6780 driver Add myself as maintainer for the ADRF6780 driver. Signed-off-by: Antoniu Miclaus Link: https://lore.kernel.org/r/20220103111624.82262-1-antoniu.miclaus@analog.com Signed-off-by: Jonathan Cameron --- MAINTAINERS | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 530616d4001c..ac36cebde659 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1145,6 +1145,14 @@ S: Supported W: https://ez.analog.com/linux-software-drivers F: drivers/power/supply/adp5061.c +ANALOG DEVICES INC ADRF6780 DRIVER +M: Antoniu Miclaus +L: linux-iio@vger.kernel.org +S: Supported +W: https://ez.analog.com/linux-software-drivers +F: Documentation/devicetree/bindings/iio/frequency/adi,adrf6780.yaml +F: drivers/iio/frequency/adrf6780.c + ANALOG DEVICES INC ADV7180 DRIVER M: Lars-Peter Clausen L: linux-media@vger.kernel.org -- cgit v1.2.3 From 84e5d88953d765e5da14f96dd30b0b1cc215c157 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Tue, 11 Jan 2022 14:04:02 +0100 Subject: iio: adc: tsc2046: rework the trigger state machine Initially this was designed to: | Fix sleeping in atomic context warning and a deadlock after iio_trigger_poll() | call | | If iio_trigger_poll() is called after IRQ was disabled, we will call | reenable_trigger() directly from hard IRQ or hrtimer context instead of | IRQ thread. In this case we will run in to multiple issue as sleeping in atomic | context and a deadlock. | | To avoid this issue, rework the trigger to use state machine. All state | changes are done over the hrtimer, so it allows us to drop fsleep() and | avoid the deadlock. Since this issue was fixed by: 9020ef659885 ("iio: trigger: Fix a scheduling whilst atomic issue seen on tsc2046"). This patch is a cleanup to make state machine easier to follow. Signed-off-by: Oleksij Rempel Link: https://lore.kernel.org/r/20220111130402.3404769-1-o.rempel@pengutronix.de Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ti-tsc2046.c | 145 +++++++++++++++++++++++++++++-------------- 1 file changed, 99 insertions(+), 46 deletions(-) diff --git a/drivers/iio/adc/ti-tsc2046.c b/drivers/iio/adc/ti-tsc2046.c index d84ae6b008c1..098dbca49176 100644 --- a/drivers/iio/adc/ti-tsc2046.c +++ b/drivers/iio/adc/ti-tsc2046.c @@ -82,6 +82,10 @@ #define TI_TSC2046_DATA_12BIT GENMASK(14, 3) #define TI_TSC2046_MAX_CHAN 8 +#define TI_TSC2046_MIN_POLL_CNT 3 +#define TI_TSC2046_EXT_POLL_CNT 3 +#define TI_TSC2046_POLL_CNT \ + (TI_TSC2046_MIN_POLL_CNT + TI_TSC2046_EXT_POLL_CNT) /* Represents a HW sample */ struct tsc2046_adc_atom { @@ -123,14 +127,23 @@ struct tsc2046_adc_ch_cfg { unsigned int oversampling_ratio; }; +enum tsc2046_state { + TSC2046_STATE_SHUTDOWN, + TSC2046_STATE_STANDBY, + TSC2046_STATE_POLL, + TSC2046_STATE_POLL_IRQ_DISABLE, + TSC2046_STATE_ENABLE_IRQ, +}; + struct tsc2046_adc_priv { struct spi_device *spi; const struct tsc2046_adc_dcfg *dcfg; struct iio_trigger *trig; struct hrtimer trig_timer; - spinlock_t trig_lock; - unsigned int trig_more_count; + enum tsc2046_state state; + int poll_cnt; + spinlock_t state_lock; struct spi_transfer xfer; struct spi_message msg; @@ -411,21 +424,63 @@ static const struct iio_info tsc2046_adc_info = { .update_scan_mode = tsc2046_adc_update_scan_mode, }; -static enum hrtimer_restart tsc2046_adc_trig_more(struct hrtimer *hrtimer) +static enum hrtimer_restart tsc2046_adc_timer(struct hrtimer *hrtimer) { struct tsc2046_adc_priv *priv = container_of(hrtimer, struct tsc2046_adc_priv, trig_timer); unsigned long flags; - spin_lock_irqsave(&priv->trig_lock, flags); - - disable_irq_nosync(priv->spi->irq); - - priv->trig_more_count++; - iio_trigger_poll(priv->trig); + /* + * This state machine should address following challenges : + * - the interrupt source is based on level shifter attached to the X + * channel of ADC. It will change the state every time we switch + * between channels. So, we need to disable IRQ if we do + * iio_trigger_poll(). + * - we should do iio_trigger_poll() at some reduced sample rate + * - we should still trigger for some amount of time after last + * interrupt with enabled IRQ was processed. + */ - spin_unlock_irqrestore(&priv->trig_lock, flags); + spin_lock_irqsave(&priv->state_lock, flags); + switch (priv->state) { + case TSC2046_STATE_ENABLE_IRQ: + if (priv->poll_cnt < TI_TSC2046_POLL_CNT) { + priv->poll_cnt++; + hrtimer_start(&priv->trig_timer, + ns_to_ktime(priv->scan_interval_us * + NSEC_PER_USEC), + HRTIMER_MODE_REL_SOFT); + + if (priv->poll_cnt >= TI_TSC2046_MIN_POLL_CNT) { + priv->state = TSC2046_STATE_POLL_IRQ_DISABLE; + enable_irq(priv->spi->irq); + } else { + priv->state = TSC2046_STATE_POLL; + } + } else { + priv->state = TSC2046_STATE_STANDBY; + enable_irq(priv->spi->irq); + } + break; + case TSC2046_STATE_POLL_IRQ_DISABLE: + disable_irq_nosync(priv->spi->irq); + fallthrough; + case TSC2046_STATE_POLL: + priv->state = TSC2046_STATE_ENABLE_IRQ; + /* iio_trigger_poll() starts hrtimer */ + iio_trigger_poll(priv->trig); + break; + case TSC2046_STATE_SHUTDOWN: + break; + case TSC2046_STATE_STANDBY: + fallthrough; + default: + dev_warn(&priv->spi->dev, "Got unexpected state: %i\n", + priv->state); + break; + } + spin_unlock_irqrestore(&priv->state_lock, flags); return HRTIMER_NORESTART; } @@ -434,16 +489,20 @@ static irqreturn_t tsc2046_adc_irq(int irq, void *dev_id) { struct iio_dev *indio_dev = dev_id; struct tsc2046_adc_priv *priv = iio_priv(indio_dev); - - spin_lock(&priv->trig_lock); + unsigned long flags; hrtimer_try_to_cancel(&priv->trig_timer); - priv->trig_more_count = 0; - disable_irq_nosync(priv->spi->irq); - iio_trigger_poll(priv->trig); + spin_lock_irqsave(&priv->state_lock, flags); + if (priv->state != TSC2046_STATE_SHUTDOWN) { + priv->state = TSC2046_STATE_ENABLE_IRQ; + priv->poll_cnt = 0; - spin_unlock(&priv->trig_lock); + /* iio_trigger_poll() starts hrtimer */ + disable_irq_nosync(priv->spi->irq); + iio_trigger_poll(priv->trig); + } + spin_unlock_irqrestore(&priv->state_lock, flags); return IRQ_HANDLED; } @@ -452,49 +511,42 @@ static void tsc2046_adc_reenable_trigger(struct iio_trigger *trig) { struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig); struct tsc2046_adc_priv *priv = iio_priv(indio_dev); - unsigned long flags; - int delta; + ktime_t tim; /* * We can sample it as fast as we can, but usually we do not need so * many samples. Reduce the sample rate for default (touchscreen) use * case. - * Currently we do not need a highly precise sample rate. It is enough - * to have calculated numbers. */ - delta = priv->scan_interval_us - priv->time_per_scan_us; - if (delta > 0) - fsleep(delta); - - spin_lock_irqsave(&priv->trig_lock, flags); - - /* - * We need to trigger at least one extra sample to detect state - * difference on ADC side. - */ - if (!priv->trig_more_count) { - int timeout_ms = DIV_ROUND_UP(priv->scan_interval_us, - USEC_PER_MSEC); - - hrtimer_start(&priv->trig_timer, ms_to_ktime(timeout_ms), - HRTIMER_MODE_REL_SOFT); - } - - enable_irq(priv->spi->irq); - - spin_unlock_irqrestore(&priv->trig_lock, flags); + tim = ns_to_ktime((priv->scan_interval_us - priv->time_per_scan_us) * + NSEC_PER_USEC); + hrtimer_start(&priv->trig_timer, tim, HRTIMER_MODE_REL_SOFT); } static int tsc2046_adc_set_trigger_state(struct iio_trigger *trig, bool enable) { struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig); struct tsc2046_adc_priv *priv = iio_priv(indio_dev); + unsigned long flags; if (enable) { - enable_irq(priv->spi->irq); + spin_lock_irqsave(&priv->state_lock, flags); + if (priv->state == TSC2046_STATE_SHUTDOWN) { + priv->state = TSC2046_STATE_STANDBY; + enable_irq(priv->spi->irq); + } + spin_unlock_irqrestore(&priv->state_lock, flags); } else { - disable_irq(priv->spi->irq); - hrtimer_try_to_cancel(&priv->trig_timer); + spin_lock_irqsave(&priv->state_lock, flags); + + if (priv->state == TSC2046_STATE_STANDBY || + priv->state == TSC2046_STATE_POLL_IRQ_DISABLE) + disable_irq_nosync(priv->spi->irq); + + priv->state = TSC2046_STATE_SHUTDOWN; + spin_unlock_irqrestore(&priv->state_lock, flags); + + hrtimer_cancel(&priv->trig_timer); } return 0; @@ -668,10 +720,11 @@ static int tsc2046_adc_probe(struct spi_device *spi) iio_trigger_set_drvdata(trig, indio_dev); trig->ops = &tsc2046_adc_trigger_ops; - spin_lock_init(&priv->trig_lock); + spin_lock_init(&priv->state_lock); + priv->state = TSC2046_STATE_SHUTDOWN; hrtimer_init(&priv->trig_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL_SOFT); - priv->trig_timer.function = tsc2046_adc_trig_more; + priv->trig_timer.function = tsc2046_adc_timer; ret = devm_iio_trigger_register(dev, trig); if (ret) { -- cgit v1.2.3 From c3154def82fc6b6fb59fd4520cbc2f92211c109d Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 16 Dec 2021 19:52:05 +0100 Subject: iio: core: Use sysfs_emit() sysfs_emit() is preferred over raw s*printf() for sysfs attributes since it knows about the sysfs buffer specifics and has some built-in checks for size and alignment. This patch converts the places in the IIO core that follow the pattern of return s*printf(...) to return sysfs_emit(...) This covers the new places that have been introduced where sprintf() is used for formatting sysfs output since the last time this was done in commit 83ca56b663cf ("iio: core: Use sysfs_emit() (trivial bits)"). Signed-off-by: Lars-Peter Clausen Link: https://lore.kernel.org/r/20211216185217.1054495-2-lars@metafoo.de Signed-off-by: Jonathan Cameron --- drivers/iio/industrialio-buffer.c | 4 ++-- drivers/iio/industrialio-core.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c index 94eb9f6cf128..f7721553a938 100644 --- a/drivers/iio/industrialio-buffer.c +++ b/drivers/iio/industrialio-buffer.c @@ -1383,9 +1383,9 @@ static ssize_t direction_show(struct device *dev, switch (buffer->direction) { case IIO_BUFFER_DIRECTION_IN: - return sprintf(buf, "in\n"); + return sysfs_emit(buf, "in\n"); case IIO_BUFFER_DIRECTION_OUT: - return sprintf(buf, "out\n"); + return sysfs_emit(buf, "out\n"); default: return -EINVAL; } diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index 409c278a4c2c..e1ed44dec2ab 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -747,7 +747,7 @@ static ssize_t iio_read_channel_label(struct device *dev, return indio_dev->info->read_label(indio_dev, this_attr->c, buf); if (this_attr->c->extend_name) - return sprintf(buf, "%s\n", this_attr->c->extend_name); + return sysfs_emit(buf, "%s\n", this_attr->c->extend_name); return -EINVAL; } -- cgit v1.2.3 From 0ce1a30cd7efa1d8f13fd5dd2a1e460ad49bfa41 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 16 Dec 2021 19:52:06 +0100 Subject: iio: dmaengine-buffer: Use sysfs_emit() sysfs_emit() is preferred over raw s*printf() for sysfs attributes since it knows about the sysfs buffer specifics and has some built-in checks for size and alignment. Use sysfs_emit() for the `length_align_bytes` buffer attribute. Signed-off-by: Lars-Peter Clausen Link: https://lore.kernel.org/r/20211216185217.1054495-3-lars@metafoo.de Signed-off-by: Jonathan Cameron --- drivers/iio/buffer/industrialio-buffer-dmaengine.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/buffer/industrialio-buffer-dmaengine.c b/drivers/iio/buffer/industrialio-buffer-dmaengine.c index f8ce26a24c57..f744b62a636a 100644 --- a/drivers/iio/buffer/industrialio-buffer-dmaengine.c +++ b/drivers/iio/buffer/industrialio-buffer-dmaengine.c @@ -136,7 +136,7 @@ static ssize_t iio_dmaengine_buffer_get_length_align(struct device *dev, struct dmaengine_buffer *dmaengine_buffer = iio_buffer_to_dmaengine_buffer(buffer); - return sprintf(buf, "%zu\n", dmaengine_buffer->align); + return sysfs_emit(buf, "%zu\n", dmaengine_buffer->align); } static IIO_DEVICE_ATTR(length_align_bytes, 0444, -- cgit v1.2.3 From 9d5fcb8ffa69428d57761b43675407ce7f652fd0 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 16 Dec 2021 19:52:07 +0100 Subject: iio: ad7192: Use sysfs_emit() sysfs_emit() is preferred over raw s*printf() for sysfs attributes since it knows about the sysfs buffer specifics and has some built-in checks for size and alignment. Use sysfs_emit() to format the custom `ac_excitation` and `bridge_swtich` attributes of the ad7192 driver. Signed-off-by: Lars-Peter Clausen Link: https://lore.kernel.org/r/20211216185217.1054495-4-lars@metafoo.de Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7192.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/iio/adc/ad7192.c b/drivers/iio/adc/ad7192.c index cc990205f306..47d3f56edcbc 100644 --- a/drivers/iio/adc/ad7192.c +++ b/drivers/iio/adc/ad7192.c @@ -433,7 +433,7 @@ static ssize_t ad7192_show_ac_excitation(struct device *dev, struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ad7192_state *st = iio_priv(indio_dev); - return sprintf(buf, "%d\n", !!(st->mode & AD7192_MODE_ACX)); + return sysfs_emit(buf, "%d\n", !!(st->mode & AD7192_MODE_ACX)); } static ssize_t ad7192_show_bridge_switch(struct device *dev, @@ -443,7 +443,7 @@ static ssize_t ad7192_show_bridge_switch(struct device *dev, struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ad7192_state *st = iio_priv(indio_dev); - return sprintf(buf, "%d\n", !!(st->gpocon & AD7192_GPOCON_BPDSW)); + return sysfs_emit(buf, "%d\n", !!(st->gpocon & AD7192_GPOCON_BPDSW)); } static ssize_t ad7192_set(struct device *dev, -- cgit v1.2.3 From 48788715ac8ed610a3d30ef1fb8d7fd38bdc1f81 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 16 Dec 2021 19:52:08 +0100 Subject: iio: ad9523: Use sysfs_emit() sysfs_emit() is preferred over raw s*printf() for sysfs attributes since it knows about the sysfs buffer specifics and has some built-in checks for size and alignment. Use sysfs_emit() to format the custom device attributes of the ad9523 driver. Signed-off-by: Lars-Peter Clausen Link: https://lore.kernel.org/r/20211216185217.1054495-5-lars@metafoo.de Signed-off-by: Jonathan Cameron --- drivers/iio/frequency/ad9523.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/frequency/ad9523.c b/drivers/iio/frequency/ad9523.c index bdb0bc3b12dd..a0f92c336fc4 100644 --- a/drivers/iio/frequency/ad9523.c +++ b/drivers/iio/frequency/ad9523.c @@ -551,7 +551,7 @@ static ssize_t ad9523_show(struct device *dev, mutex_lock(&st->lock); ret = ad9523_read(indio_dev, AD9523_READBACK_0); if (ret >= 0) { - ret = sprintf(buf, "%d\n", !!(ret & (1 << + ret = sysfs_emit(buf, "%d\n", !!(ret & (1 << (u32)this_attr->address))); } mutex_unlock(&st->lock); -- cgit v1.2.3 From 2fd52124b5979bdddcc6bdf5dbe49198c735cbaa Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 16 Dec 2021 19:52:09 +0100 Subject: iio: as3935: Use sysfs_emit() sysfs_emit() is preferred over raw s*printf() for sysfs attributes since it knows about the sysfs buffer specifics and has some built-in checks for size and alignment. Use sysfs_emit() to format the custom `noise_level_tripped` device attribute of the as3935 driver. Signed-off-by: Lars-Peter Clausen Link: https://lore.kernel.org/r/20211216185217.1054495-6-lars@metafoo.de Signed-off-by: Jonathan Cameron --- drivers/iio/proximity/as3935.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/iio/proximity/as3935.c b/drivers/iio/proximity/as3935.c index 51f4f92ae84a..bd7595db31d4 100644 --- a/drivers/iio/proximity/as3935.c +++ b/drivers/iio/proximity/as3935.c @@ -122,7 +122,7 @@ static ssize_t as3935_sensor_sensitivity_show(struct device *dev, return ret; val = (val & AS3935_AFE_MASK) >> 1; - return sprintf(buf, "%d\n", val); + return sysfs_emit(buf, "%d\n", val); } static ssize_t as3935_sensor_sensitivity_store(struct device *dev, @@ -153,7 +153,7 @@ static ssize_t as3935_noise_level_tripped_show(struct device *dev, int ret; mutex_lock(&st->lock); - ret = sprintf(buf, "%d\n", !time_after(jiffies, st->noise_tripped + HZ)); + ret = sysfs_emit(buf, "%d\n", !time_after(jiffies, st->noise_tripped + HZ)); mutex_unlock(&st->lock); return ret; -- cgit v1.2.3 From e9d4397a1627ea4e30c1f1fe9f2889bb31d658f2 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 16 Dec 2021 19:52:10 +0100 Subject: iio: ina2xx-adc: sysfs_emit() sysfs_emit() is preferred over raw s*printf() for sysfs attributes since it knows about the sysfs buffer specifics and has some built-in checks for size and alignment. Use sysfs_emit() to format the custom `in_allow_async_readout` device attribute of the ina2xx-adc driver. Signed-off-by: Lars-Peter Clausen Link: https://lore.kernel.org/r/20211216185217.1054495-7-lars@metafoo.de Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ina2xx-adc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/adc/ina2xx-adc.c b/drivers/iio/adc/ina2xx-adc.c index 4f9992a51e64..8d902a32a0fd 100644 --- a/drivers/iio/adc/ina2xx-adc.c +++ b/drivers/iio/adc/ina2xx-adc.c @@ -539,7 +539,7 @@ static ssize_t ina2xx_allow_async_readout_show(struct device *dev, { struct ina2xx_chip_info *chip = iio_priv(dev_to_iio_dev(dev)); - return sprintf(buf, "%d\n", chip->allow_async_readout); + return sysfs_emit(buf, "%d\n", chip->allow_async_readout); } static ssize_t ina2xx_allow_async_readout_store(struct device *dev, -- cgit v1.2.3 From 0ad4c227fb6000a4e53c393e19c16a49940992c0 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 16 Dec 2021 19:52:11 +0100 Subject: iio: lm3533: Use sysfs_emit() sysfs_emit() is preferred over raw s*printf() for sysfs attributes since it knows about the sysfs buffer specifics and has some built-in checks for size and alignment. Use sysfs_emit() to format the custom device attributes of the lm3533 driver. Note this driver was using scnprintf correctly so this change is about ensuring examples of code that might get cut and paste into new drivers are using current best practice. Signed-off-by: Lars-Peter Clausen Reviewed-by: Johan Hovold Link: https://lore.kernel.org/r/20211216185217.1054495-8-lars@metafoo.de Signed-off-by: Jonathan Cameron --- drivers/iio/light/lm3533-als.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/iio/light/lm3533-als.c b/drivers/iio/light/lm3533-als.c index 8a621244dd01..827bc25269e9 100644 --- a/drivers/iio/light/lm3533-als.c +++ b/drivers/iio/light/lm3533-als.c @@ -417,7 +417,7 @@ static ssize_t show_thresh_either_en(struct device *dev, enable = 0; } - return scnprintf(buf, PAGE_SIZE, "%u\n", enable); + return sysfs_emit(buf, "%u\n", enable); } static ssize_t store_thresh_either_en(struct device *dev, @@ -474,7 +474,7 @@ static ssize_t show_zone(struct device *dev, if (ret) return ret; - return scnprintf(buf, PAGE_SIZE, "%u\n", zone); + return sysfs_emit(buf, "%u\n", zone); } enum lm3533_als_attribute_type { @@ -530,7 +530,7 @@ static ssize_t show_als_attr(struct device *dev, if (ret) return ret; - return scnprintf(buf, PAGE_SIZE, "%u\n", val); + return sysfs_emit(buf, "%u\n", val); } static ssize_t store_als_attr(struct device *dev, -- cgit v1.2.3 From 9df24867d8e8fd83a4727e17c89c988e0e4be7ff Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 16 Dec 2021 19:52:12 +0100 Subject: iio: max31856: Use sysfs_emit() sysfs_emit() is preferred over raw s*printf() for sysfs attributes since it knows about the sysfs buffer specifics and has some built-in checks for size and alignment. Use sysfs_emit() to format the custom `fault_ovuv`, `fault_oc` and `in_temp_filter_notch_center_frequency` device attributes of the max31856 driver. Signed-off-by: Lars-Peter Clausen Link: https://lore.kernel.org/r/20211216185217.1054495-9-lars@metafoo.de Signed-off-by: Jonathan Cameron --- drivers/iio/temperature/max31856.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/iio/temperature/max31856.c b/drivers/iio/temperature/max31856.c index 1954322e43be..54840881259a 100644 --- a/drivers/iio/temperature/max31856.c +++ b/drivers/iio/temperature/max31856.c @@ -320,7 +320,7 @@ static ssize_t show_fault(struct device *dev, u8 faultbit, char *buf) fault = reg_val & faultbit; - return sprintf(buf, "%d\n", fault); + return sysfs_emit(buf, "%d\n", fault); } static ssize_t show_fault_ovuv(struct device *dev, @@ -344,7 +344,7 @@ static ssize_t show_filter(struct device *dev, struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct max31856_data *data = iio_priv(indio_dev); - return sprintf(buf, "%d\n", data->filter_50hz ? 50 : 60); + return sysfs_emit(buf, "%d\n", data->filter_50hz ? 50 : 60); } static ssize_t set_filter(struct device *dev, -- cgit v1.2.3 From 3c1d2fdd8096a08927ef3c5180208a136ac1a82b Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 16 Dec 2021 19:52:13 +0100 Subject: iio: max31865: Use sysfs_emit() sysfs_emit() is preferred over raw s*printf() for sysfs attributes since it knows about the sysfs buffer specifics and has some built-in checks for size and alignment. Use sysfs_emit() to format the custom ``in_filter_notch_center_frequency` and fault_ovuv` device attributes of the max31865 driver. Signed-off-by: Lars-Peter Clausen Link: https://lore.kernel.org/r/20211216185217.1054495-10-lars@metafoo.de Signed-off-by: Jonathan Cameron --- drivers/iio/temperature/max31865.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/iio/temperature/max31865.c b/drivers/iio/temperature/max31865.c index 4c8d6e6cf677..86c3f3509a26 100644 --- a/drivers/iio/temperature/max31865.c +++ b/drivers/iio/temperature/max31865.c @@ -208,7 +208,7 @@ static ssize_t show_fault(struct device *dev, u8 faultbit, char *buf) fault = data->buf[0] & faultbit; - return sprintf(buf, "%d\n", fault); + return sysfs_emit(buf, "%d\n", fault); } static ssize_t show_fault_ovuv(struct device *dev, @@ -225,7 +225,7 @@ static ssize_t show_filter(struct device *dev, struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct max31865_data *data = iio_priv(indio_dev); - return sprintf(buf, "%d\n", data->filter_50hz ? 50 : 60); + return sysfs_emit(buf, "%d\n", data->filter_50hz ? 50 : 60); } static ssize_t set_filter(struct device *dev, -- cgit v1.2.3 From d42b626d54ae05b754c14be18edd090540c2666e Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 16 Dec 2021 19:52:14 +0100 Subject: iio: max9611: Use sysfs_emit() sysfs_emit() is preferred over raw s*printf() for sysfs attributes since it knows about the sysfs buffer specifics and has some built-in checks for size and alignment. Use sysfs_emit() to format the custom `in_power_shunt_resistor` and `in_current_shunt_resistor` device attributes of the max9611 driver. Signed-off-by: Lars-Peter Clausen Reviewed-by: Jacopo Mondi Link: https://lore.kernel.org/r/20211216185217.1054495-11-lars@metafoo.de Signed-off-by: Jonathan Cameron --- drivers/iio/adc/max9611.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/adc/max9611.c b/drivers/iio/adc/max9611.c index 01a4275e9c46..f982f00303dc 100644 --- a/drivers/iio/adc/max9611.c +++ b/drivers/iio/adc/max9611.c @@ -429,7 +429,7 @@ static ssize_t max9611_shunt_resistor_show(struct device *dev, i = max9611->shunt_resistor_uohm / 1000000; r = max9611->shunt_resistor_uohm % 1000000; - return sprintf(buf, "%u.%06u\n", i, r); + return sysfs_emit(buf, "%u.%06u\n", i, r); } static IIO_DEVICE_ATTR(in_power_shunt_resistor, 0444, -- cgit v1.2.3 From 6ab56c467593b422079cf119beb4e7c44f5417a9 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 16 Dec 2021 19:52:15 +0100 Subject: iio: ms_sensors: Use sysfs_emit() sysfs_emit() is preferred over raw s*printf() for sysfs attributes since it knows about the sysfs buffer specifics and has some built-in checks for size and alignment. Use sysfs_emit() to format the custom `battery_low` and `heater_enable` device attributes of the ms_sensors driver shared code. Signed-off-by: Lars-Peter Clausen Link: https://lore.kernel.org/r/20211216185217.1054495-12-lars@metafoo.de Signed-off-by: Jonathan Cameron --- drivers/iio/common/ms_sensors/ms_sensors_i2c.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/iio/common/ms_sensors/ms_sensors_i2c.c b/drivers/iio/common/ms_sensors/ms_sensors_i2c.c index 16ea697e945c..3eb790aec4b2 100644 --- a/drivers/iio/common/ms_sensors/ms_sensors_i2c.c +++ b/drivers/iio/common/ms_sensors/ms_sensors_i2c.c @@ -324,7 +324,7 @@ ssize_t ms_sensors_show_battery_low(struct ms_ht_dev *dev_data, if (ret) return ret; - return sprintf(buf, "%d\n", (config_reg & 0x40) >> 6); + return sysfs_emit(buf, "%d\n", (config_reg & 0x40) >> 6); } EXPORT_SYMBOL(ms_sensors_show_battery_low); @@ -351,7 +351,7 @@ ssize_t ms_sensors_show_heater(struct ms_ht_dev *dev_data, if (ret) return ret; - return sprintf(buf, "%d\n", (config_reg & 0x4) >> 2); + return sysfs_emit(buf, "%d\n", (config_reg & 0x4) >> 2); } EXPORT_SYMBOL(ms_sensors_show_heater); -- cgit v1.2.3 From 1acdaa34ad17e304d39d83fc9affc2d71c550a13 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 16 Dec 2021 19:52:16 +0100 Subject: iio: scd4x: Use sysfs_emit() sysfs_emit() is preferred over raw s*printf() for sysfs attributes since it knows about the sysfs buffer specifics and has some built-in checks for size and alignment. Use sysfs_emit() to format the custom `calibration_auto_enable` device attribute of the scd4x driver. Signed-off-by: Lars-Peter Clausen Link: https://lore.kernel.org/r/20211216185217.1054495-13-lars@metafoo.de Signed-off-by: Jonathan Cameron --- drivers/iio/chemical/scd4x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/chemical/scd4x.c b/drivers/iio/chemical/scd4x.c index 267bc3c05338..20d4e7584e92 100644 --- a/drivers/iio/chemical/scd4x.c +++ b/drivers/iio/chemical/scd4x.c @@ -423,7 +423,7 @@ static ssize_t calibration_auto_enable_show(struct device *dev, val = (be16_to_cpu(bval) & SCD4X_READY_MASK) ? 1 : 0; - return sprintf(buf, "%d\n", val); + return sysfs_emit(buf, "%d\n", val); } static ssize_t calibration_auto_enable_store(struct device *dev, -- cgit v1.2.3 From f22ab91ae3029a68d45b1892effb0a1115d6926b Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 16 Dec 2021 19:52:17 +0100 Subject: iio: sps30: Use sysfs_emit() sysfs_emit() is preferred over raw s*printf() for sysfs attributes since it knows about the sysfs buffer specifics and has some built-in checks for size and alignment. Use sysfs_emit() to format the custom `cleaning_period` device attribute of the sps30 driver. Signed-off-by: Lars-Peter Clausen Link: https://lore.kernel.org/r/20211216185217.1054495-14-lars@metafoo.de Signed-off-by: Jonathan Cameron --- drivers/iio/chemical/sps30.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/chemical/sps30.c b/drivers/iio/chemical/sps30.c index d51314505115..abd67559e451 100644 --- a/drivers/iio/chemical/sps30.c +++ b/drivers/iio/chemical/sps30.c @@ -221,7 +221,7 @@ static ssize_t cleaning_period_show(struct device *dev, if (ret) return ret; - return sprintf(buf, "%d\n", be32_to_cpu(val)); + return sysfs_emit(buf, "%d\n", be32_to_cpu(val)); } static ssize_t cleaning_period_store(struct device *dev, struct device_attribute *attr, -- cgit v1.2.3 From 1bdd962bbdff60e6194acb497caddb9c8b4c61b4 Mon Sep 17 00:00:00 2001 From: Antoniu Miclaus Date: Mon, 17 Jan 2022 09:00:37 +0200 Subject: MAINTAINERS: add maintainer for AD7293 driver Add myself as maintainer for the AD7293 driver. Signed-off-by: Antoniu Miclaus Link: https://lore.kernel.org/r/20220117070039.6139-1-antoniu.miclaus@analog.com Signed-off-by: Jonathan Cameron --- MAINTAINERS | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index ac36cebde659..a16d9272ab89 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1061,6 +1061,14 @@ W: https://ez.analog.com/linux-software-drivers F: Documentation/devicetree/bindings/iio/adc/adi,ad7292.yaml F: drivers/iio/adc/ad7292.c +ANALOG DEVICES INC AD7293 DRIVER +M: Antoniu Miclaus +L: linux-iio@vger.kernel.org +S: Supported +W: https://ez.analog.com/linux-software-drivers +F: Documentation/devicetree/bindings/iio/dac/adi,ad7293.yaml +F: drivers/iio/dac/ad7293.c + ANALOG DEVICES INC AD7768-1 DRIVER M: Michael Hennerich L: linux-iio@vger.kernel.org -- cgit v1.2.3 From 712173762fcf8ee1168c5584f18e3f581e0651bb Mon Sep 17 00:00:00 2001 From: Antoniu Miclaus Date: Mon, 17 Jan 2022 09:00:38 +0200 Subject: MAINTAINERS: add maintainer for ADMV1013 driver Add myself as maintainer for the ADMV1013 driver. Signed-off-by: Antoniu Miclaus Link: https://lore.kernel.org/r/20220117070039.6139-2-antoniu.miclaus@analog.com Signed-off-by: Jonathan Cameron --- MAINTAINERS | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index a16d9272ab89..36f92966174a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1146,6 +1146,14 @@ W: https://ez.analog.com/linux-software-drivers F: Documentation/devicetree/bindings/hwmon/adi,adm1177.yaml F: drivers/hwmon/adm1177.c +ANALOG DEVICES INC ADMV1013 DRIVER +M: Antoniu Miclaus +L: linux-iio@vger.kernel.org +S: Supported +W: https://ez.analog.com/linux-software-drivers +F: Documentation/devicetree/bindings/iio/frequency/adi,admv1013.yaml +F: drivers/iio/frequency/admv1013.c + ANALOG DEVICES INC ADP5061 DRIVER M: Michael Hennerich L: linux-pm@vger.kernel.org -- cgit v1.2.3 From f3c7b621e9bf049194340bfc6f3ba0f8f360461c Mon Sep 17 00:00:00 2001 From: Antoniu Miclaus Date: Mon, 17 Jan 2022 09:00:39 +0200 Subject: MAINTAINERS: add maintainer for ADMV8818 driver Add myself as maintainer for the ADMV8818 driver. Signed-off-by: Antoniu Miclaus Link: https://lore.kernel.org/r/20220117070039.6139-3-antoniu.miclaus@analog.com Signed-off-by: Jonathan Cameron --- MAINTAINERS | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 36f92966174a..b27a61f6ba5b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1154,6 +1154,14 @@ W: https://ez.analog.com/linux-software-drivers F: Documentation/devicetree/bindings/iio/frequency/adi,admv1013.yaml F: drivers/iio/frequency/admv1013.c +ANALOG DEVICES INC ADMV8818 DRIVER +M: Antoniu Miclaus +L: linux-iio@vger.kernel.org +S: Supported +W: https://ez.analog.com/linux-software-drivers +F: Documentation/devicetree/bindings/iio/filter/adi,admv8818.yaml +F: drivers/iio/filter/admv8818.c + ANALOG DEVICES INC ADP5061 DRIVER M: Michael Hennerich L: linux-pm@vger.kernel.org -- cgit v1.2.3 From 90e33e1b3d96e537938c16ed802a5c4b4e147a65 Mon Sep 17 00:00:00 2001 From: Nuno Sá Date: Sat, 22 Jan 2022 14:09:03 +0100 Subject: MAINTAINERS: add missing files to the adis lib MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The triggered buffer support was missing in the MAINTAINERS file. Add them. Signed-off-by: Nuno Sá Link: https://lore.kernel.org/r/20220122130905.99-1-nuno.sa@analog.com Signed-off-by: Jonathan Cameron --- MAINTAINERS | 2 ++ 1 file changed, 2 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index b27a61f6ba5b..a2c8699e9e41 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1120,6 +1120,8 @@ M: Nuno Sa L: linux-iio@vger.kernel.org S: Supported F: drivers/iio/imu/adis.c +F: drivers/iio/imu/adis_buffer.c +F: drivers/iio/imu/adis_trigger.c F: include/linux/iio/imu/adis.h ANALOG DEVICES INC ADIS16460 DRIVER -- cgit v1.2.3 From da5936770517aef8b28888f1123fa654c78cc2f9 Mon Sep 17 00:00:00 2001 From: Nuno Sá Date: Sat, 22 Jan 2022 14:09:04 +0100 Subject: adis: simplify 'adis_update_bits' macros MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There's no need to use '__builtin_choose_expr' to choose the right call to 'adis_update_bits_base()'. We can change the 'BUILD_BUG_ON()' condition so that it makes sure only the supported sizes are passed in. With that, we can just use 'sizeof(val)' as the size argument of 'adis_update_bits_base()'. Signed-off-by: Nuno Sá Link: https://lore.kernel.org/r/20220122130905.99-2-nuno.sa@analog.com Signed-off-by: Jonathan Cameron --- include/linux/iio/imu/adis.h | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/include/linux/iio/imu/adis.h b/include/linux/iio/imu/adis.h index 7c02f5292eea..11754f97d8bb 100644 --- a/include/linux/iio/imu/adis.h +++ b/include/linux/iio/imu/adis.h @@ -381,10 +381,8 @@ static inline int adis_update_bits_base(struct adis *adis, unsigned int reg, * @val can lead to undesired behavior if the register to update is 16bit. */ #define adis_update_bits(adis, reg, mask, val) ({ \ - BUILD_BUG_ON(sizeof(val) == 1 || sizeof(val) == 8); \ - __builtin_choose_expr(sizeof(val) == 4, \ - adis_update_bits_base(adis, reg, mask, val, 4), \ - adis_update_bits_base(adis, reg, mask, val, 2)); \ + BUILD_BUG_ON(sizeof(val) != 2 && sizeof(val) != 4); \ + adis_update_bits_base(adis, reg, mask, val, sizeof(val)); \ }) /** @@ -399,10 +397,8 @@ static inline int adis_update_bits_base(struct adis *adis, unsigned int reg, * @val can lead to undesired behavior if the register to update is 16bit. */ #define __adis_update_bits(adis, reg, mask, val) ({ \ - BUILD_BUG_ON(sizeof(val) == 1 || sizeof(val) == 8); \ - __builtin_choose_expr(sizeof(val) == 4, \ - __adis_update_bits_base(adis, reg, mask, val, 4), \ - __adis_update_bits_base(adis, reg, mask, val, 2)); \ + BUILD_BUG_ON(sizeof(val) != 2 && sizeof(val) != 4); \ + __adis_update_bits_base(adis, reg, mask, val, sizeof(val)); \ }) int adis_enable_irq(struct adis *adis, bool enable); -- cgit v1.2.3 From c39010ea6ba13bdf0003bd353e1d4c663aaac0a8 Mon Sep 17 00:00:00 2001 From: Nuno Sá Date: Sat, 22 Jan 2022 14:09:05 +0100 Subject: iio: adis: stylistic changes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Minor stylistic changes to address checkptach complains when called with '--strict'. Signed-off-by: Nuno Sá Link: https://lore.kernel.org/r/20220122130905.99-3-nuno.sa@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/imu/adis.c | 47 ++++++++++++++++++++++------------------- drivers/iio/imu/adis_buffer.c | 6 +++--- drivers/iio/imu/adis_trigger.c | 3 +-- include/linux/iio/imu/adis.h | 48 ++++++++++++++++++++++-------------------- 4 files changed, 54 insertions(+), 50 deletions(-) diff --git a/drivers/iio/imu/adis.c b/drivers/iio/imu/adis.c index cb0d66bf6561..638957001653 100644 --- a/drivers/iio/imu/adis.c +++ b/drivers/iio/imu/adis.c @@ -30,8 +30,8 @@ * @value: The value to write to device (up to 4 bytes) * @size: The size of the @value (in bytes) */ -int __adis_write_reg(struct adis *adis, unsigned int reg, - unsigned int value, unsigned int size) +int __adis_write_reg(struct adis *adis, unsigned int reg, unsigned int value, + unsigned int size) { unsigned int page = reg / ADIS_PAGE_SIZE; int ret, i; @@ -114,7 +114,7 @@ int __adis_write_reg(struct adis *adis, unsigned int reg, ret = spi_sync(adis->spi, &msg); if (ret) { dev_err(&adis->spi->dev, "Failed to write register 0x%02X: %d\n", - reg, ret); + reg, ret); } else { adis->current_page = page; } @@ -130,8 +130,8 @@ EXPORT_SYMBOL_GPL(__adis_write_reg); * @val: The value read back from the device * @size: The size of the @val buffer */ -int __adis_read_reg(struct adis *adis, unsigned int reg, - unsigned int *val, unsigned int size) +int __adis_read_reg(struct adis *adis, unsigned int reg, unsigned int *val, + unsigned int size) { unsigned int page = reg / ADIS_PAGE_SIZE; struct spi_message msg; @@ -201,12 +201,12 @@ int __adis_read_reg(struct adis *adis, unsigned int reg, ret = spi_sync(adis->spi, &msg); if (ret) { dev_err(&adis->spi->dev, "Failed to read register 0x%02X: %d\n", - reg, ret); + reg, ret); return ret; - } else { - adis->current_page = page; } + adis->current_page = page; + switch (size) { case 4: *val = get_unaligned_be32(adis->rx); @@ -247,13 +247,13 @@ EXPORT_SYMBOL_GPL(__adis_update_bits_base); #ifdef CONFIG_DEBUG_FS -int adis_debugfs_reg_access(struct iio_dev *indio_dev, - unsigned int reg, unsigned int writeval, unsigned int *readval) +int adis_debugfs_reg_access(struct iio_dev *indio_dev, unsigned int reg, + unsigned int writeval, unsigned int *readval) { struct adis *adis = iio_device_get_drvdata(indio_dev); if (readval) { - uint16_t val16; + u16 val16; int ret; ret = adis_read_reg_16(adis, reg, &val16); @@ -261,9 +261,9 @@ int adis_debugfs_reg_access(struct iio_dev *indio_dev, *readval = val16; return ret; - } else { - return adis_write_reg_16(adis, reg, writeval); } + + return adis_write_reg_16(adis, reg, writeval); } EXPORT_SYMBOL(adis_debugfs_reg_access); @@ -279,14 +279,16 @@ EXPORT_SYMBOL(adis_debugfs_reg_access); int adis_enable_irq(struct adis *adis, bool enable) { int ret = 0; - uint16_t msc; + u16 msc; mutex_lock(&adis->state_lock); if (adis->data->enable_irq) { ret = adis->data->enable_irq(adis, enable); goto out_unlock; - } else if (adis->data->unmasked_drdy) { + } + + if (adis->data->unmasked_drdy) { if (enable) enable_irq(adis->spi->irq); else @@ -322,7 +324,7 @@ EXPORT_SYMBOL(adis_enable_irq); */ int __adis_check_status(struct adis *adis) { - uint16_t status; + u16 status; int ret; int i; @@ -358,7 +360,7 @@ int __adis_reset(struct adis *adis) const struct adis_timeout *timeouts = adis->data->timeouts; ret = __adis_write_reg_8(adis, adis->data->glob_cmd_reg, - ADIS_GLOB_CMD_SW_RESET); + ADIS_GLOB_CMD_SW_RESET); if (ret) { dev_err(&adis->spi->dev, "Failed to reset device: %d\n", ret); return ret; @@ -414,7 +416,7 @@ int __adis_initial_startup(struct adis *adis) { const struct adis_timeout *timeouts = adis->data->timeouts; struct gpio_desc *gpio; - uint16_t prod_id; + u16 prod_id; int ret; /* check if the device has rst pin low */ @@ -423,7 +425,7 @@ int __adis_initial_startup(struct adis *adis) return PTR_ERR(gpio); if (gpio) { - msleep(10); + usleep_range(10, 12); /* bring device out of reset */ gpiod_set_value_cansleep(gpio, 0); msleep(timeouts->reset_ms); @@ -477,7 +479,8 @@ EXPORT_SYMBOL_GPL(__adis_initial_startup); * a error bit in the channels raw value set error_mask to 0. */ int adis_single_conversion(struct iio_dev *indio_dev, - const struct iio_chan_spec *chan, unsigned int error_mask, int *val) + const struct iio_chan_spec *chan, + unsigned int error_mask, int *val) { struct adis *adis = iio_device_get_drvdata(indio_dev); unsigned int uval; @@ -486,7 +489,7 @@ int adis_single_conversion(struct iio_dev *indio_dev, mutex_lock(&adis->state_lock); ret = __adis_read_reg(adis, chan->address, &uval, - chan->scan_type.storagebits / 8); + chan->scan_type.storagebits / 8); if (ret) goto err_unlock; @@ -521,7 +524,7 @@ EXPORT_SYMBOL_GPL(adis_single_conversion); * called. */ int adis_init(struct adis *adis, struct iio_dev *indio_dev, - struct spi_device *spi, const struct adis_data *data) + struct spi_device *spi, const struct adis_data *data) { if (!data || !data->timeouts) { dev_err(&spi->dev, "No config data or timeouts not defined!\n"); diff --git a/drivers/iio/imu/adis_buffer.c b/drivers/iio/imu/adis_buffer.c index 351c303c8a8c..d3527cf5ed37 100644 --- a/drivers/iio/imu/adis_buffer.c +++ b/drivers/iio/imu/adis_buffer.c @@ -20,7 +20,7 @@ #include static int adis_update_scan_mode_burst(struct iio_dev *indio_dev, - const unsigned long *scan_mask) + const unsigned long *scan_mask) { struct adis *adis = iio_device_get_drvdata(indio_dev); unsigned int burst_length, burst_max_length; @@ -67,7 +67,7 @@ static int adis_update_scan_mode_burst(struct iio_dev *indio_dev, } int adis_update_scan_mode(struct iio_dev *indio_dev, - const unsigned long *scan_mask) + const unsigned long *scan_mask) { struct adis *adis = iio_device_get_drvdata(indio_dev); const struct iio_chan_spec *chan; @@ -158,7 +158,7 @@ static irqreturn_t adis_trigger_handler(int irq, void *p) } iio_push_to_buffers_with_timestamp(indio_dev, adis->buffer, - pf->timestamp); + pf->timestamp); irq_done: iio_trigger_notify_done(indio_dev->trig); diff --git a/drivers/iio/imu/adis_trigger.c b/drivers/iio/imu/adis_trigger.c index c461bd1e8e69..0e7fb00ba241 100644 --- a/drivers/iio/imu/adis_trigger.c +++ b/drivers/iio/imu/adis_trigger.c @@ -15,8 +15,7 @@ #include #include -static int adis_data_rdy_trigger_set_state(struct iio_trigger *trig, - bool state) +static int adis_data_rdy_trigger_set_state(struct iio_trigger *trig, bool state) { struct adis *adis = iio_trigger_get_drvdata(trig); diff --git a/include/linux/iio/imu/adis.h b/include/linux/iio/imu/adis.h index 11754f97d8bb..515ca09764fe 100644 --- a/include/linux/iio/imu/adis.h +++ b/include/linux/iio/imu/adis.h @@ -32,6 +32,7 @@ struct adis_timeout { u16 sw_reset_ms; u16 self_test_ms; }; + /** * struct adis_data - ADIS chip variant specific data * @read_delay: SPI delay for read operations in us @@ -45,7 +46,7 @@ struct adis_timeout { * @self_test_mask: Bitmask of supported self-test operations * @self_test_reg: Register address to request self test command * @self_test_no_autoclear: True if device's self-test needs clear of ctrl reg - * @status_error_msgs: Array of error messgaes + * @status_error_msgs: Array of error messages * @status_error_mask: Bitmask of errors supported by the device * @timeouts: Chip specific delays * @enable_irq: Hook for ADIS devices that have a special IRQ enable/disable @@ -130,12 +131,12 @@ struct adis { unsigned long irq_flag; void *buffer; - uint8_t tx[10] ____cacheline_aligned; - uint8_t rx[4]; + u8 tx[10] ____cacheline_aligned; + u8 rx[4]; }; int adis_init(struct adis *adis, struct iio_dev *indio_dev, - struct spi_device *spi, const struct adis_data *data); + struct spi_device *spi, const struct adis_data *data); int __adis_reset(struct adis *adis); /** @@ -156,9 +157,9 @@ static inline int adis_reset(struct adis *adis) } int __adis_write_reg(struct adis *adis, unsigned int reg, - unsigned int val, unsigned int size); + unsigned int val, unsigned int size); int __adis_read_reg(struct adis *adis, unsigned int reg, - unsigned int *val, unsigned int size); + unsigned int *val, unsigned int size); /** * __adis_write_reg_8() - Write single byte to a register (unlocked) @@ -167,7 +168,7 @@ int __adis_read_reg(struct adis *adis, unsigned int reg, * @value: The value to write */ static inline int __adis_write_reg_8(struct adis *adis, unsigned int reg, - uint8_t val) + u8 val) { return __adis_write_reg(adis, reg, val, 1); } @@ -179,7 +180,7 @@ static inline int __adis_write_reg_8(struct adis *adis, unsigned int reg, * @value: Value to be written */ static inline int __adis_write_reg_16(struct adis *adis, unsigned int reg, - uint16_t val) + u16 val) { return __adis_write_reg(adis, reg, val, 2); } @@ -191,7 +192,7 @@ static inline int __adis_write_reg_16(struct adis *adis, unsigned int reg, * @value: Value to be written */ static inline int __adis_write_reg_32(struct adis *adis, unsigned int reg, - uint32_t val) + u32 val) { return __adis_write_reg(adis, reg, val, 4); } @@ -203,7 +204,7 @@ static inline int __adis_write_reg_32(struct adis *adis, unsigned int reg, * @val: The value read back from the device */ static inline int __adis_read_reg_16(struct adis *adis, unsigned int reg, - uint16_t *val) + u16 *val) { unsigned int tmp; int ret; @@ -222,7 +223,7 @@ static inline int __adis_read_reg_16(struct adis *adis, unsigned int reg, * @val: The value read back from the device */ static inline int __adis_read_reg_32(struct adis *adis, unsigned int reg, - uint32_t *val) + u32 *val) { unsigned int tmp; int ret; @@ -242,7 +243,7 @@ static inline int __adis_read_reg_32(struct adis *adis, unsigned int reg, * @size: The size of the @value (in bytes) */ static inline int adis_write_reg(struct adis *adis, unsigned int reg, - unsigned int val, unsigned int size) + unsigned int val, unsigned int size) { int ret; @@ -261,7 +262,7 @@ static inline int adis_write_reg(struct adis *adis, unsigned int reg, * @size: The size of the @val buffer */ static int adis_read_reg(struct adis *adis, unsigned int reg, - unsigned int *val, unsigned int size) + unsigned int *val, unsigned int size) { int ret; @@ -279,7 +280,7 @@ static int adis_read_reg(struct adis *adis, unsigned int reg, * @value: The value to write */ static inline int adis_write_reg_8(struct adis *adis, unsigned int reg, - uint8_t val) + u8 val) { return adis_write_reg(adis, reg, val, 1); } @@ -291,7 +292,7 @@ static inline int adis_write_reg_8(struct adis *adis, unsigned int reg, * @value: Value to be written */ static inline int adis_write_reg_16(struct adis *adis, unsigned int reg, - uint16_t val) + u16 val) { return adis_write_reg(adis, reg, val, 2); } @@ -303,7 +304,7 @@ static inline int adis_write_reg_16(struct adis *adis, unsigned int reg, * @value: Value to be written */ static inline int adis_write_reg_32(struct adis *adis, unsigned int reg, - uint32_t val) + u32 val) { return adis_write_reg(adis, reg, val, 4); } @@ -315,7 +316,7 @@ static inline int adis_write_reg_32(struct adis *adis, unsigned int reg, * @val: The value read back from the device */ static inline int adis_read_reg_16(struct adis *adis, unsigned int reg, - uint16_t *val) + u16 *val) { unsigned int tmp; int ret; @@ -334,7 +335,7 @@ static inline int adis_read_reg_16(struct adis *adis, unsigned int reg, * @val: The value read back from the device */ static inline int adis_read_reg_32(struct adis *adis, unsigned int reg, - uint32_t *val) + u32 *val) { unsigned int tmp; int ret; @@ -439,8 +440,8 @@ static inline void adis_dev_unlock(struct adis *adis) } int adis_single_conversion(struct iio_dev *indio_dev, - const struct iio_chan_spec *chan, unsigned int error_mask, - int *val); + const struct iio_chan_spec *chan, + unsigned int error_mask, int *val); #define ADIS_VOLTAGE_CHAN(addr, si, chan, name, info_all, bits) { \ .type = IIO_VOLTAGE, \ @@ -489,7 +490,7 @@ int adis_single_conversion(struct iio_dev *indio_dev, .modified = 1, \ .channel2 = IIO_MOD_ ## mod, \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ - info_sep, \ + (info_sep), \ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ .info_mask_shared_by_all = info_all, \ .address = (addr), \ @@ -523,7 +524,7 @@ devm_adis_setup_buffer_and_trigger(struct adis *adis, struct iio_dev *indio_dev, int devm_adis_probe_trigger(struct adis *adis, struct iio_dev *indio_dev); int adis_update_scan_mode(struct iio_dev *indio_dev, - const unsigned long *scan_mask); + const unsigned long *scan_mask); #else /* CONFIG_IIO_BUFFER */ @@ -547,7 +548,8 @@ static inline int devm_adis_probe_trigger(struct adis *adis, #ifdef CONFIG_DEBUG_FS int adis_debugfs_reg_access(struct iio_dev *indio_dev, - unsigned int reg, unsigned int writeval, unsigned int *readval); + unsigned int reg, unsigned int writeval, + unsigned int *readval); #else -- cgit v1.2.3 From 2d255ec5100570559550ed61dd4c9c57d593e9a9 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Thu, 20 Jan 2022 16:52:43 -0600 Subject: iio: hw_consumer: Use struct_size() helper in kzalloc() Make use of the struct_size() helper instead of an open-coded version, in order to avoid any potential type mistakes or integer overflows that, in the worst scenario, could lead to heap overflows. Also, address the following sparse warnings: drivers/iio/buffer/industrialio-hw-consumer.c:63:23: warning: using sizeof on a flexible structure when using CF='-Wflexible-array-sizeof' Link: https://github.com/KSPP/linux/issues/174 Signed-off-by: Gustavo A. R. Silva Reviewed-by: Kees Cook Link: https://lore.kernel.org/r/20220120225243.GA37225@embeddedor Signed-off-by: Jonathan Cameron --- drivers/iio/buffer/industrialio-hw-consumer.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/iio/buffer/industrialio-hw-consumer.c b/drivers/iio/buffer/industrialio-hw-consumer.c index 87d9aabd20c7..fb58f599a80b 100644 --- a/drivers/iio/buffer/industrialio-hw-consumer.c +++ b/drivers/iio/buffer/industrialio-hw-consumer.c @@ -52,7 +52,6 @@ static const struct iio_buffer_access_funcs iio_hw_buf_access = { static struct hw_consumer_buffer *iio_hw_consumer_get_buffer( struct iio_hw_consumer *hwc, struct iio_dev *indio_dev) { - size_t mask_size = BITS_TO_LONGS(indio_dev->masklength) * sizeof(long); struct hw_consumer_buffer *buf; list_for_each_entry(buf, &hwc->buffers, head) { @@ -60,7 +59,8 @@ static struct hw_consumer_buffer *iio_hw_consumer_get_buffer( return buf; } - buf = kzalloc(sizeof(*buf) + mask_size, GFP_KERNEL); + buf = kzalloc(struct_size(buf, scan_mask, BITS_TO_LONGS(indio_dev->masklength)), + GFP_KERNEL); if (!buf) return NULL; -- cgit v1.2.3 From b617693a5d139dec0a3a19a909d687d2d95d78bc Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Mon, 17 Jan 2022 09:28:51 +0100 Subject: iio: adc: tsc2046: add .read_raw support Add read_raw() support to make use of iio_hwmon and other iio clients. Signed-off-by: Oleksij Rempel Link: https://lore.kernel.org/r/20220117082852.3370869-1-o.rempel@pengutronix.de Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ti-tsc2046.c | 118 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 97 insertions(+), 21 deletions(-) diff --git a/drivers/iio/adc/ti-tsc2046.c b/drivers/iio/adc/ti-tsc2046.c index 098dbca49176..eb219ff3d610 100644 --- a/drivers/iio/adc/ti-tsc2046.c +++ b/drivers/iio/adc/ti-tsc2046.c @@ -86,6 +86,7 @@ #define TI_TSC2046_EXT_POLL_CNT 3 #define TI_TSC2046_POLL_CNT \ (TI_TSC2046_MIN_POLL_CNT + TI_TSC2046_EXT_POLL_CNT) +#define TI_TSC2046_INT_VREF 2500 /* Represents a HW sample */ struct tsc2046_adc_atom { @@ -166,9 +167,6 @@ struct tsc2046_adc_priv { struct tsc2046_adc_atom *rx; struct tsc2046_adc_atom *tx; - struct tsc2046_adc_atom *rx_one; - struct tsc2046_adc_atom *tx_one; - unsigned int count; unsigned int groups; u32 effective_speed_hz; @@ -184,6 +182,8 @@ struct tsc2046_adc_priv { .type = IIO_VOLTAGE, \ .indexed = 1, \ .channel = index, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ .datasheet_name = "#name", \ .scan_index = index, \ .scan_type = { \ @@ -247,6 +247,14 @@ static u8 tsc2046_adc_get_cmd(struct tsc2046_adc_priv *priv, int ch_idx, else pd = 0; + switch (ch_idx) { + case TI_TSC2046_ADDR_TEMP1: + case TI_TSC2046_ADDR_AUX: + case TI_TSC2046_ADDR_VBAT: + case TI_TSC2046_ADDR_TEMP0: + pd |= TI_TSC2046_SER | TI_TSC2046_PD1_VREF_ON; + } + return TI_TSC2046_START | FIELD_PREP(TI_TSC2046_ADDR, ch_idx) | pd; } @@ -258,16 +266,50 @@ static u16 tsc2046_adc_get_value(struct tsc2046_adc_atom *buf) static int tsc2046_adc_read_one(struct tsc2046_adc_priv *priv, int ch_idx, u32 *effective_speed_hz) { + struct tsc2046_adc_ch_cfg *ch = &priv->ch_cfg[ch_idx]; + struct tsc2046_adc_atom *rx_buf, *tx_buf; + unsigned int val, val_normalized = 0; + int ret, i, count_skip = 0, max_count; struct spi_transfer xfer; struct spi_message msg; - int ret; + u8 cmd; + + if (!effective_speed_hz) { + count_skip = tsc2046_adc_time_to_count(priv, ch->settling_time_us); + max_count = count_skip + ch->oversampling_ratio; + } else { + max_count = 1; + } + + if (sizeof(*tx_buf) * max_count > PAGE_SIZE) + return -ENOSPC; + + tx_buf = kcalloc(max_count, sizeof(*tx_buf), GFP_KERNEL); + if (!tx_buf) + return -ENOMEM; + + rx_buf = kcalloc(max_count, sizeof(*rx_buf), GFP_KERNEL); + if (!rx_buf) { + ret = -ENOMEM; + goto free_tx; + } + + /* + * Do not enable automatic power down on working samples. Otherwise the + * plates will never be completely charged. + */ + cmd = tsc2046_adc_get_cmd(priv, ch_idx, true); + + for (i = 0; i < max_count - 1; i++) + tx_buf[i].cmd = cmd; + + /* automatically power down on last sample */ + tx_buf[i].cmd = tsc2046_adc_get_cmd(priv, ch_idx, false); memset(&xfer, 0, sizeof(xfer)); - priv->tx_one->cmd = tsc2046_adc_get_cmd(priv, ch_idx, false); - priv->tx_one->data = 0; - xfer.tx_buf = priv->tx_one; - xfer.rx_buf = priv->rx_one; - xfer.len = sizeof(*priv->tx_one); + xfer.tx_buf = tx_buf; + xfer.rx_buf = rx_buf; + xfer.len = sizeof(*tx_buf) * max_count; spi_message_init_with_transfers(&msg, &xfer, 1); /* @@ -278,13 +320,25 @@ static int tsc2046_adc_read_one(struct tsc2046_adc_priv *priv, int ch_idx, if (ret) { dev_err_ratelimited(&priv->spi->dev, "SPI transfer failed %pe\n", ERR_PTR(ret)); - return ret; + goto free_bufs; } if (effective_speed_hz) *effective_speed_hz = xfer.effective_speed_hz; - return tsc2046_adc_get_value(priv->rx_one); + for (i = 0; i < max_count - count_skip; i++) { + val = tsc2046_adc_get_value(&rx_buf[count_skip + i]); + val_normalized += val; + } + + ret = DIV_ROUND_UP(val_normalized, max_count - count_skip); + +free_bufs: + kfree(rx_buf); +free_tx: + kfree(tx_buf); + + return ret; } static size_t tsc2046_adc_group_set_layout(struct tsc2046_adc_priv *priv, @@ -391,6 +445,37 @@ static irqreturn_t tsc2046_adc_trigger_handler(int irq, void *p) return IRQ_HANDLED; } +static int tsc2046_adc_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long m) +{ + struct tsc2046_adc_priv *priv = iio_priv(indio_dev); + int ret; + + switch (m) { + case IIO_CHAN_INFO_RAW: + ret = tsc2046_adc_read_one(priv, chan->channel, NULL); + if (ret < 0) + return ret; + + *val = ret; + + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + /* + * Note: the TSC2046 has internal voltage divider on the VBAT + * line. This divider can be influenced by external divider. + * So, it is better to use external voltage-divider driver + * instead, which is calculating complete chain. + */ + *val = TI_TSC2046_INT_VREF; + *val2 = chan->scan_type.realbits; + return IIO_VAL_FRACTIONAL_LOG2; + } + + return -EINVAL; +} + static int tsc2046_adc_update_scan_mode(struct iio_dev *indio_dev, const unsigned long *active_scan_mask) { @@ -421,6 +506,7 @@ static int tsc2046_adc_update_scan_mode(struct iio_dev *indio_dev, } static const struct iio_info tsc2046_adc_info = { + .read_raw = tsc2046_adc_read_raw, .update_scan_mode = tsc2046_adc_update_scan_mode, }; @@ -563,16 +649,6 @@ static int tsc2046_adc_setup_spi_msg(struct tsc2046_adc_priv *priv) size_t size; int ret; - priv->tx_one = devm_kzalloc(&priv->spi->dev, sizeof(*priv->tx_one), - GFP_KERNEL); - if (!priv->tx_one) - return -ENOMEM; - - priv->rx_one = devm_kzalloc(&priv->spi->dev, sizeof(*priv->rx_one), - GFP_KERNEL); - if (!priv->rx_one) - return -ENOMEM; - /* * Make dummy read to set initial power state and get real SPI clock * freq. It seems to be not important which channel is used for this -- cgit v1.2.3 From 576434fd93b91d36cb62d531888e88dac5e52540 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Mon, 17 Jan 2022 09:28:52 +0100 Subject: iio: adc: tsc2046: add sanity check to avoid to big allocations To avoid problematic devicetree configurations. Set allocation limit with error message and suggestion on what can be done to solve this issue. Signed-off-by: Oleksij Rempel Link: https://lore.kernel.org/r/20220117082852.3370869-2-o.rempel@pengutronix.de Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ti-tsc2046.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/iio/adc/ti-tsc2046.c b/drivers/iio/adc/ti-tsc2046.c index eb219ff3d610..2b87f39f377a 100644 --- a/drivers/iio/adc/ti-tsc2046.c +++ b/drivers/iio/adc/ti-tsc2046.c @@ -679,6 +679,12 @@ static int tsc2046_adc_setup_spi_msg(struct tsc2046_adc_priv *priv) for (ch_idx = 0; ch_idx < priv->dcfg->num_channels; ch_idx++) size += tsc2046_adc_group_set_layout(priv, ch_idx, ch_idx); + if (size > PAGE_SIZE) { + dev_err(&priv->spi->dev, + "Calculated scan buffer is too big. Try to reduce spi-max-frequency, settling-time-us or oversampling-ratio\n"); + return -ENOSPC; + } + priv->tx = devm_kzalloc(&priv->spi->dev, size, GFP_KERNEL); if (!priv->tx) return -ENOMEM; -- cgit v1.2.3 From de645b279144b7d036ef672227af76739365f3ae Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 26 Jan 2022 17:12:17 -0600 Subject: dt-bindings: iio/adc: qcom,spmi-iadc: Fix 'reg' property in example The QCom SPMI PMIC child nodes are defined to have a single address cell, but the example has an erroneous size cell. Remove it. Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/20220126231217.1633935-1-robh@kernel.org Signed-off-by: Jonathan Cameron --- Documentation/devicetree/bindings/iio/adc/qcom,spmi-iadc.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/iio/adc/qcom,spmi-iadc.yaml b/Documentation/devicetree/bindings/iio/adc/qcom,spmi-iadc.yaml index 27e3108661c0..2a94db688830 100644 --- a/Documentation/devicetree/bindings/iio/adc/qcom,spmi-iadc.yaml +++ b/Documentation/devicetree/bindings/iio/adc/qcom,spmi-iadc.yaml @@ -51,7 +51,7 @@ examples: #size-cells = <0>; pmic_iadc: adc@3600 { compatible = "qcom,spmi-iadc"; - reg = <0x3600 0x100>; + reg = <0x3600>; interrupts = <0x0 0x36 0x0 IRQ_TYPE_EDGE_RISING>; qcom,external-resistor-micro-ohms = <10000>; #io-channel-cells = <1>; -- cgit v1.2.3 From e820a33748b5e22cecafddf919a7d8679949deb1 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 26 Jan 2022 15:53:50 +0200 Subject: math.h: Introduce data types for fractional numbers Introduce a macro to produce data types like struct TYPE_fract { __TYPE numerator; __TYPE denominator; }; to be used in the code wherever it's needed. In the following changes convert some users to it. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220126135353.24007-1-andriy.shevchenko@linux.intel.com Signed-off-by: Jonathan Cameron --- include/linux/math.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/include/linux/math.h b/include/linux/math.h index 53674a327e39..439b8f0b9ebd 100644 --- a/include/linux/math.h +++ b/include/linux/math.h @@ -2,6 +2,7 @@ #ifndef _LINUX_MATH_H #define _LINUX_MATH_H +#include #include #include @@ -106,6 +107,17 @@ } \ ) +#define __STRUCT_FRACT(type) \ +struct type##_fract { \ + __##type numerator; \ + __##type denominator; \ +}; +__STRUCT_FRACT(s16) +__STRUCT_FRACT(u16) +__STRUCT_FRACT(s32) +__STRUCT_FRACT(u32) +#undef __STRUCT_FRACT + /* * Multiplies an integer by a fraction, while avoiding unnecessary * overflow or loss of precision. -- cgit v1.2.3 From 84cd574e2eb9711ecb933d6a57b585df343be272 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 26 Jan 2022 15:53:51 +0200 Subject: iio: adc: rn5t618: Re-use generic struct u16_fract Instead of custom data type re-use generic struct u16_fract. No changes intended. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220126135353.24007-2-andriy.shevchenko@linux.intel.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/rn5t618-adc.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/iio/adc/rn5t618-adc.c b/drivers/iio/adc/rn5t618-adc.c index 7d891b4ea461..6bf32907f01d 100644 --- a/drivers/iio/adc/rn5t618-adc.c +++ b/drivers/iio/adc/rn5t618-adc.c @@ -42,11 +42,6 @@ struct rn5t618_adc_data { int irq; }; -struct rn5t618_channel_ratios { - u16 numerator; - u16 denominator; -}; - enum rn5t618_channels { LIMMON = 0, VBAT, @@ -58,7 +53,7 @@ enum rn5t618_channels { AIN0 }; -static const struct rn5t618_channel_ratios rn5t618_ratios[8] = { +static const struct u16_fract rn5t618_ratios[8] = { [LIMMON] = {50, 32}, /* measured across 20mOhm, amplified by 32 */ [VBAT] = {2, 1}, [VADP] = {3, 1}, -- cgit v1.2.3 From 8f2abd48b528931a35bc7a71e77bdf614e826f45 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 26 Jan 2022 15:53:52 +0200 Subject: iio: adc: twl4030-madc: Re-use generic struct s16_fract Instead of custom data type re-use generic struct s16_fract. No changes intended. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220126135353.24007-3-andriy.shevchenko@linux.intel.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/twl4030-madc.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/drivers/iio/adc/twl4030-madc.c b/drivers/iio/adc/twl4030-madc.c index 6ce40cc4568a..f8f8aea15612 100644 --- a/drivers/iio/adc/twl4030-madc.c +++ b/drivers/iio/adc/twl4030-madc.c @@ -231,13 +231,7 @@ static const struct iio_chan_spec twl4030_madc_iio_channels[] = { static struct twl4030_madc_data *twl4030_madc; -struct twl4030_prescale_divider_ratios { - s16 numerator; - s16 denominator; -}; - -static const struct twl4030_prescale_divider_ratios -twl4030_divider_ratios[16] = { +static const struct s16_fract twl4030_divider_ratios[16] = { {1, 1}, /* CHANNEL 0 No Prescaler */ {1, 1}, /* CHANNEL 1 No Prescaler */ {6, 10}, /* CHANNEL 2 */ @@ -256,7 +250,6 @@ twl4030_divider_ratios[16] = { {5, 11}, /* CHANNEL 15 */ }; - /* Conversion table from -3 to 55 degrees Celcius */ static int twl4030_therm_tbl[] = { 30800, 29500, 28300, 27100, -- cgit v1.2.3 From a5e9b2ddbbc789f34be2333263232435d8edf57c Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 26 Jan 2022 15:53:53 +0200 Subject: iio: adc: qcom-vadc-common: Re-use generic struct u32_fract Instead of custom data type re-use generic struct u32_fract. No changes intended. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220126135353.24007-4-andriy.shevchenko@linux.intel.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/qcom-pm8xxx-xoadc.c | 15 +++--- drivers/iio/adc/qcom-spmi-vadc.c | 24 ++++----- drivers/iio/adc/qcom-vadc-common.c | 92 ++++++++++++++++---------------- include/linux/iio/adc/qcom-vadc-common.h | 15 ++---- 4 files changed, 69 insertions(+), 77 deletions(-) diff --git a/drivers/iio/adc/qcom-pm8xxx-xoadc.c b/drivers/iio/adc/qcom-pm8xxx-xoadc.c index 21d7eff645c3..5e9e56821075 100644 --- a/drivers/iio/adc/qcom-pm8xxx-xoadc.c +++ b/drivers/iio/adc/qcom-pm8xxx-xoadc.c @@ -175,7 +175,7 @@ struct xoadc_channel { const char *datasheet_name; u8 pre_scale_mux:2; u8 amux_channel:4; - const struct vadc_prescale_ratio prescale; + const struct u32_fract prescale; enum iio_chan_type type; enum vadc_scale_fn_type scale_fn_type; u8 amux_ip_rsv:3; @@ -218,7 +218,9 @@ struct xoadc_variant { .datasheet_name = __stringify(_dname), \ .pre_scale_mux = _presmux, \ .amux_channel = _amux, \ - .prescale = { .num = _prenum, .den = _preden }, \ + .prescale = { \ + .numerator = _prenum, .denominator = _preden, \ + }, \ .type = _type, \ .scale_fn_type = _scale, \ .amux_ip_rsv = _amip, \ @@ -809,12 +811,11 @@ static int pm8xxx_xoadc_parse_channel(struct device *dev, BIT(IIO_CHAN_INFO_PROCESSED); iio_chan->indexed = 1; - dev_dbg(dev, "channel [PRESCALE/MUX: %02x AMUX: %02x] \"%s\" " - "ref voltage: %d, decimation %d " - "prescale %d/%d, scale function %d\n", + dev_dbg(dev, + "channel [PRESCALE/MUX: %02x AMUX: %02x] \"%s\" ref voltage: %d, decimation %d prescale %d/%d, scale function %d\n", hwchan->pre_scale_mux, hwchan->amux_channel, ch->name, - ch->amux_ip_rsv, ch->decimation, hwchan->prescale.num, - hwchan->prescale.den, hwchan->scale_fn_type); + ch->amux_ip_rsv, ch->decimation, hwchan->prescale.numerator, + hwchan->prescale.denominator, hwchan->scale_fn_type); return 0; } diff --git a/drivers/iio/adc/qcom-spmi-vadc.c b/drivers/iio/adc/qcom-spmi-vadc.c index 07b1a99381d9..34202ba52469 100644 --- a/drivers/iio/adc/qcom-spmi-vadc.c +++ b/drivers/iio/adc/qcom-spmi-vadc.c @@ -122,15 +122,15 @@ struct vadc_priv { struct mutex lock; }; -static const struct vadc_prescale_ratio vadc_prescale_ratios[] = { - {.num = 1, .den = 1}, - {.num = 1, .den = 3}, - {.num = 1, .den = 4}, - {.num = 1, .den = 6}, - {.num = 1, .den = 20}, - {.num = 1, .den = 8}, - {.num = 10, .den = 81}, - {.num = 1, .den = 10} +static const struct u32_fract vadc_prescale_ratios[] = { + { .numerator = 1, .denominator = 1 }, + { .numerator = 1, .denominator = 3 }, + { .numerator = 1, .denominator = 4 }, + { .numerator = 1, .denominator = 6 }, + { .numerator = 1, .denominator = 20 }, + { .numerator = 1, .denominator = 8 }, + { .numerator = 10, .denominator = 81 }, + { .numerator = 1, .denominator = 10 }, }; static int vadc_read(struct vadc_priv *vadc, u16 offset, u8 *data) @@ -404,13 +404,13 @@ err: return ret; } -static int vadc_prescaling_from_dt(u32 num, u32 den) +static int vadc_prescaling_from_dt(u32 numerator, u32 denominator) { unsigned int pre; for (pre = 0; pre < ARRAY_SIZE(vadc_prescale_ratios); pre++) - if (vadc_prescale_ratios[pre].num == num && - vadc_prescale_ratios[pre].den == den) + if (vadc_prescale_ratios[pre].numerator == numerator && + vadc_prescale_ratios[pre].denominator == denominator) break; if (pre == ARRAY_SIZE(vadc_prescale_ratios)) diff --git a/drivers/iio/adc/qcom-vadc-common.c b/drivers/iio/adc/qcom-vadc-common.c index 14723896aab2..6c6aec848f98 100644 --- a/drivers/iio/adc/qcom-vadc-common.c +++ b/drivers/iio/adc/qcom-vadc-common.c @@ -289,44 +289,44 @@ static const struct vadc_map_pt adcmap7_100k[] = { { 2420, 130048 } }; -static const struct vadc_prescale_ratio adc5_prescale_ratios[] = { - {.num = 1, .den = 1}, - {.num = 1, .den = 3}, - {.num = 1, .den = 4}, - {.num = 1, .den = 6}, - {.num = 1, .den = 20}, - {.num = 1, .den = 8}, - {.num = 10, .den = 81}, - {.num = 1, .den = 10}, - {.num = 1, .den = 16} +static const struct u32_fract adc5_prescale_ratios[] = { + { .numerator = 1, .denominator = 1 }, + { .numerator = 1, .denominator = 3 }, + { .numerator = 1, .denominator = 4 }, + { .numerator = 1, .denominator = 6 }, + { .numerator = 1, .denominator = 20 }, + { .numerator = 1, .denominator = 8 }, + { .numerator = 10, .denominator = 81 }, + { .numerator = 1, .denominator = 10 }, + { .numerator = 1, .denominator = 16 }, }; static int qcom_vadc_scale_hw_calib_volt( - const struct vadc_prescale_ratio *prescale, + const struct u32_fract *prescale, const struct adc5_data *data, u16 adc_code, int *result_uv); static int qcom_vadc_scale_hw_calib_therm( - const struct vadc_prescale_ratio *prescale, + const struct u32_fract *prescale, const struct adc5_data *data, u16 adc_code, int *result_mdec); static int qcom_vadc7_scale_hw_calib_therm( - const struct vadc_prescale_ratio *prescale, + const struct u32_fract *prescale, const struct adc5_data *data, u16 adc_code, int *result_mdec); static int qcom_vadc_scale_hw_smb_temp( - const struct vadc_prescale_ratio *prescale, + const struct u32_fract *prescale, const struct adc5_data *data, u16 adc_code, int *result_mdec); static int qcom_vadc_scale_hw_chg5_temp( - const struct vadc_prescale_ratio *prescale, + const struct u32_fract *prescale, const struct adc5_data *data, u16 adc_code, int *result_mdec); static int qcom_vadc_scale_hw_calib_die_temp( - const struct vadc_prescale_ratio *prescale, + const struct u32_fract *prescale, const struct adc5_data *data, u16 adc_code, int *result_mdec); static int qcom_vadc7_scale_hw_calib_die_temp( - const struct vadc_prescale_ratio *prescale, + const struct u32_fract *prescale, const struct adc5_data *data, u16 adc_code, int *result_mdec); @@ -406,7 +406,7 @@ static void qcom_vadc_scale_calib(const struct vadc_linear_graph *calib_graph, } static int qcom_vadc_scale_volt(const struct vadc_linear_graph *calib_graph, - const struct vadc_prescale_ratio *prescale, + const struct u32_fract *prescale, bool absolute, u16 adc_code, int *result_uv) { @@ -414,15 +414,15 @@ static int qcom_vadc_scale_volt(const struct vadc_linear_graph *calib_graph, qcom_vadc_scale_calib(calib_graph, adc_code, absolute, &voltage); - voltage = voltage * prescale->den; - result = div64_s64(voltage, prescale->num); + voltage *= prescale->denominator; + result = div64_s64(voltage, prescale->numerator); *result_uv = result; return 0; } static int qcom_vadc_scale_therm(const struct vadc_linear_graph *calib_graph, - const struct vadc_prescale_ratio *prescale, + const struct u32_fract *prescale, bool absolute, u16 adc_code, int *result_mdec) { @@ -444,7 +444,7 @@ static int qcom_vadc_scale_therm(const struct vadc_linear_graph *calib_graph, } static int qcom_vadc_scale_die_temp(const struct vadc_linear_graph *calib_graph, - const struct vadc_prescale_ratio *prescale, + const struct u32_fract *prescale, bool absolute, u16 adc_code, int *result_mdec) { @@ -454,8 +454,8 @@ static int qcom_vadc_scale_die_temp(const struct vadc_linear_graph *calib_graph, qcom_vadc_scale_calib(calib_graph, adc_code, absolute, &voltage); if (voltage > 0) { - temp = voltage * prescale->den; - do_div(temp, prescale->num * 2); + temp = voltage * prescale->denominator; + do_div(temp, prescale->numerator * 2); voltage = temp; } else { voltage = 0; @@ -467,7 +467,7 @@ static int qcom_vadc_scale_die_temp(const struct vadc_linear_graph *calib_graph, } static int qcom_vadc_scale_chg_temp(const struct vadc_linear_graph *calib_graph, - const struct vadc_prescale_ratio *prescale, + const struct u32_fract *prescale, bool absolute, u16 adc_code, int *result_mdec) { @@ -475,8 +475,8 @@ static int qcom_vadc_scale_chg_temp(const struct vadc_linear_graph *calib_graph, qcom_vadc_scale_calib(calib_graph, adc_code, absolute, &voltage); - voltage = voltage * prescale->den; - voltage = div64_s64(voltage, prescale->num); + voltage *= prescale->denominator; + voltage = div64_s64(voltage, prescale->numerator); voltage = ((PMI_CHG_SCALE_1) * (voltage * 2)); voltage = (voltage + PMI_CHG_SCALE_2); result = div64_s64(voltage, 1000000); @@ -487,21 +487,21 @@ static int qcom_vadc_scale_chg_temp(const struct vadc_linear_graph *calib_graph, /* convert voltage to ADC code, using 1.875V reference */ static u16 qcom_vadc_scale_voltage_code(s32 voltage, - const struct vadc_prescale_ratio *prescale, + const struct u32_fract *prescale, const u32 full_scale_code_volt, unsigned int factor) { s64 volt = voltage; s64 adc_vdd_ref_mv = 1875; /* reference voltage */ - volt *= prescale->num * factor * full_scale_code_volt; - volt = div64_s64(volt, (s64)prescale->den * adc_vdd_ref_mv * 1000); + volt *= prescale->numerator * factor * full_scale_code_volt; + volt = div64_s64(volt, (s64)prescale->denominator * adc_vdd_ref_mv * 1000); return volt; } static int qcom_vadc_scale_code_voltage_factor(u16 adc_code, - const struct vadc_prescale_ratio *prescale, + const struct u32_fract *prescale, const struct adc5_data *data, unsigned int factor) { @@ -520,8 +520,8 @@ static int qcom_vadc_scale_code_voltage_factor(u16 adc_code, voltage = (s64) adc_code * adc_vdd_ref_mv * 1000; voltage = div64_s64(voltage, data->full_scale_code_volt); if (voltage > 0) { - voltage *= prescale->den; - temp = prescale->num * factor; + voltage *= prescale->denominator; + temp = prescale->numerator * factor; voltage = div64_s64(voltage, temp); } else { voltage = 0; @@ -531,7 +531,7 @@ static int qcom_vadc_scale_code_voltage_factor(u16 adc_code, } static int qcom_vadc7_scale_hw_calib_therm( - const struct vadc_prescale_ratio *prescale, + const struct u32_fract *prescale, const struct adc5_data *data, u16 adc_code, int *result_mdec) { @@ -557,7 +557,7 @@ static int qcom_vadc7_scale_hw_calib_therm( } static int qcom_vadc_scale_hw_calib_volt( - const struct vadc_prescale_ratio *prescale, + const struct u32_fract *prescale, const struct adc5_data *data, u16 adc_code, int *result_uv) { @@ -568,7 +568,7 @@ static int qcom_vadc_scale_hw_calib_volt( } static int qcom_vadc_scale_hw_calib_therm( - const struct vadc_prescale_ratio *prescale, + const struct u32_fract *prescale, const struct adc5_data *data, u16 adc_code, int *result_mdec) { @@ -584,7 +584,7 @@ static int qcom_vadc_scale_hw_calib_therm( } static int qcom_vadc_scale_hw_calib_die_temp( - const struct vadc_prescale_ratio *prescale, + const struct u32_fract *prescale, const struct adc5_data *data, u16 adc_code, int *result_mdec) { @@ -596,7 +596,7 @@ static int qcom_vadc_scale_hw_calib_die_temp( } static int qcom_vadc7_scale_hw_calib_die_temp( - const struct vadc_prescale_ratio *prescale, + const struct u32_fract *prescale, const struct adc5_data *data, u16 adc_code, int *result_mdec) { @@ -611,7 +611,7 @@ static int qcom_vadc7_scale_hw_calib_die_temp( } static int qcom_vadc_scale_hw_smb_temp( - const struct vadc_prescale_ratio *prescale, + const struct u32_fract *prescale, const struct adc5_data *data, u16 adc_code, int *result_mdec) { @@ -623,7 +623,7 @@ static int qcom_vadc_scale_hw_smb_temp( } static int qcom_vadc_scale_hw_chg5_temp( - const struct vadc_prescale_ratio *prescale, + const struct u32_fract *prescale, const struct adc5_data *data, u16 adc_code, int *result_mdec) { @@ -636,7 +636,7 @@ static int qcom_vadc_scale_hw_chg5_temp( int qcom_vadc_scale(enum vadc_scale_fn_type scaletype, const struct vadc_linear_graph *calib_graph, - const struct vadc_prescale_ratio *prescale, + const struct u32_fract *prescale, bool absolute, u16 adc_code, int *result) { @@ -667,7 +667,7 @@ EXPORT_SYMBOL(qcom_vadc_scale); u16 qcom_adc_tm5_temp_volt_scale(unsigned int prescale_ratio, u32 full_scale_code_volt, int temp) { - const struct vadc_prescale_ratio *prescale = &adc5_prescale_ratios[prescale_ratio]; + const struct u32_fract *prescale = &adc5_prescale_ratios[prescale_ratio]; s32 voltage; voltage = qcom_vadc_map_temp_voltage(adcmap_100k_104ef_104fb_1875_vref, @@ -682,7 +682,7 @@ int qcom_adc5_hw_scale(enum vadc_scale_fn_type scaletype, const struct adc5_data *data, u16 adc_code, int *result) { - const struct vadc_prescale_ratio *prescale = &adc5_prescale_ratios[prescale_ratio]; + const struct u32_fract *prescale = &adc5_prescale_ratios[prescale_ratio]; if (!(scaletype >= SCALE_HW_CALIB_DEFAULT && scaletype < SCALE_HW_CALIB_INVALID)) { @@ -695,13 +695,13 @@ int qcom_adc5_hw_scale(enum vadc_scale_fn_type scaletype, } EXPORT_SYMBOL(qcom_adc5_hw_scale); -int qcom_adc5_prescaling_from_dt(u32 num, u32 den) +int qcom_adc5_prescaling_from_dt(u32 numerator, u32 denominator) { unsigned int pre; for (pre = 0; pre < ARRAY_SIZE(adc5_prescale_ratios); pre++) - if (adc5_prescale_ratios[pre].num == num && - adc5_prescale_ratios[pre].den == den) + if (adc5_prescale_ratios[pre].numerator == numerator && + adc5_prescale_ratios[pre].denominator == denominator) break; if (pre == ARRAY_SIZE(adc5_prescale_ratios)) diff --git a/include/linux/iio/adc/qcom-vadc-common.h b/include/linux/iio/adc/qcom-vadc-common.h index 33f60f43e1aa..ce78d4804994 100644 --- a/include/linux/iio/adc/qcom-vadc-common.h +++ b/include/linux/iio/adc/qcom-vadc-common.h @@ -6,6 +6,7 @@ #ifndef QCOM_VADC_COMMON_H #define QCOM_VADC_COMMON_H +#include #include #define VADC_CONV_TIME_MIN_US 2000 @@ -79,16 +80,6 @@ struct vadc_linear_graph { s32 gnd; }; -/** - * struct vadc_prescale_ratio - Represent scaling ratio for ADC input. - * @num: the inverse numerator of the gain applied to the input channel. - * @den: the inverse denominator of the gain applied to the input channel. - */ -struct vadc_prescale_ratio { - u32 num; - u32 den; -}; - /** * enum vadc_scale_fn_type - Scaling function to convert ADC code to * physical scaled units for the channel. @@ -144,12 +135,12 @@ struct adc5_data { int qcom_vadc_scale(enum vadc_scale_fn_type scaletype, const struct vadc_linear_graph *calib_graph, - const struct vadc_prescale_ratio *prescale, + const struct u32_fract *prescale, bool absolute, u16 adc_code, int *result_mdec); struct qcom_adc5_scale_type { - int (*scale_fn)(const struct vadc_prescale_ratio *prescale, + int (*scale_fn)(const struct u32_fract *prescale, const struct adc5_data *data, u16 adc_code, int *result); }; -- cgit v1.2.3 From 19d32860dc7826ef48ea3fb80d9f1b082c4a2cf8 Mon Sep 17 00:00:00 2001 From: Jongpil Jung Date: Sat, 22 Jan 2022 13:34:44 -0800 Subject: iio: sx9360: fix iio event generation To convert SX9360 status register ["REG_STAT"], into a channel index, we need to right shift by |stat_offset|, not left shift. Also the PROXSTAT bit (3) is for channel 1 (PHM, Phase Measured), not (PHR, Phase Reference, channel 0), so the offset is 2 instead of 3. Fixes: 1cdb4c47f7f5 ("iio:proximity:sx9360: Add sx9360 support") Signed-off-by: Jongpil Jung Signed-off-by: Gwendal Grignou Link: https://lore.kernel.org/r/20220122213444.745152-1-gwendal@chromium.org Signed-off-by: Jonathan Cameron --- drivers/iio/proximity/sx9360.c | 2 +- drivers/iio/proximity/sx_common.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/iio/proximity/sx9360.c b/drivers/iio/proximity/sx9360.c index 6fd6561bb6f5..3ebb30c8a4f6 100644 --- a/drivers/iio/proximity/sx9360.c +++ b/drivers/iio/proximity/sx9360.c @@ -775,7 +775,7 @@ static const struct sx_common_chip_info sx9360_chip_info = { .reg_reset = SX9360_REG_RESET, .mask_enable_chan = SX9360_REG_GNRL_CTRL0_PHEN_MASK, - .stat_offset = 3, + .stat_offset = 2, .num_channels = SX9360_NUM_CHANNELS, .num_default_regs = ARRAY_SIZE(sx9360_default_regs), diff --git a/drivers/iio/proximity/sx_common.c b/drivers/iio/proximity/sx_common.c index ac8fd5920481..a7c07316a0a9 100644 --- a/drivers/iio/proximity/sx_common.c +++ b/drivers/iio/proximity/sx_common.c @@ -87,7 +87,7 @@ static void sx_common_push_events(struct iio_dev *indio_dev) return; } - val <<= data->chip_info->stat_offset; + val >>= data->chip_info->stat_offset; /* * Only iterate over channels with changes on proximity status that have -- cgit v1.2.3 From 72ff282819d0526d3e4417c2a61414557981b5af Mon Sep 17 00:00:00 2001 From: Kai-Heng Feng Date: Fri, 28 Jan 2022 10:31:44 +0800 Subject: iio: pressure: dps310: Add ACPI HID table x86 boards may use ACPI HID "IFX3100" for the dps310 device. Vendor told us feel free to add the ID and contact "Saumitra.Chafekar@infineon.com" for further questions. So add an ACPI match table for that accordingly. Reviewed-by: Andy Shevchenko Signed-off-by: Kai-Heng Feng Link: https://lore.kernel.org/r/20220128023144.2050615-1-kai.heng.feng@canonical.com Signed-off-by: Jonathan Cameron --- drivers/iio/pressure/dps310.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/iio/pressure/dps310.c b/drivers/iio/pressure/dps310.c index 0730380ceb69..36fb7ae0d0a9 100644 --- a/drivers/iio/pressure/dps310.c +++ b/drivers/iio/pressure/dps310.c @@ -812,9 +812,16 @@ static const struct i2c_device_id dps310_id[] = { }; MODULE_DEVICE_TABLE(i2c, dps310_id); +static const struct acpi_device_id dps310_acpi_match[] = { + { "IFX3100" }, + {} +}; +MODULE_DEVICE_TABLE(acpi, dps310_acpi_match); + static struct i2c_driver dps310_driver = { .driver = { .name = DPS310_DEV_NAME, + .acpi_match_table = dps310_acpi_match, }, .probe = dps310_probe, .id_table = dps310_id, -- cgit v1.2.3 From 711b6a3f4af137c4a7f759136ccd50d455095b95 Mon Sep 17 00:00:00 2001 From: Kai-Heng Feng Date: Fri, 28 Jan 2022 12:20:51 +0800 Subject: iio: humidity: hdc100x: Add ACPI HID table x86 boards may use ACPI HID "TXNW1010" for the hdc100x device. TI told us "The ACPI ID for TI is: https://uefi.org/node/1028 (TXNW), therefore it would most likely be appropriate to use TXNW1010." So add an ACPI match table for that accordingly. Signed-off-by: Kai-Heng Feng Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220128042054.2062060-1-kai.heng.feng@canonical.com Signed-off-by: Jonathan Cameron --- drivers/iio/humidity/hdc100x.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/iio/humidity/hdc100x.c b/drivers/iio/humidity/hdc100x.c index 9e0fce917ce4..47f8e8ef56d6 100644 --- a/drivers/iio/humidity/hdc100x.c +++ b/drivers/iio/humidity/hdc100x.c @@ -417,10 +417,17 @@ static const struct of_device_id hdc100x_dt_ids[] = { }; MODULE_DEVICE_TABLE(of, hdc100x_dt_ids); +static const struct acpi_device_id hdc100x_acpi_match[] = { + { "TXNW1010" }, + { } +}; +MODULE_DEVICE_TABLE(acpi, hdc100x_acpi_match); + static struct i2c_driver hdc100x_driver = { .driver = { .name = "hdc100x", .of_match_table = hdc100x_dt_ids, + .acpi_match_table = hdc100x_acpi_match, }, .probe = hdc100x_probe, .id_table = hdc100x_id, -- cgit v1.2.3 From 1bca97ff95c732a516ebb68da72814194980e0a5 Mon Sep 17 00:00:00 2001 From: Liam Beguin Date: Sat, 8 Jan 2022 15:53:04 -0500 Subject: iio: inkern: apply consumer scale on IIO_VAL_INT cases When a consumer calls iio_read_channel_processed() and the channel has an integer scale, the scale channel scale is applied and the processed value is returned as expected. On the other hand, if the consumer calls iio_convert_raw_to_processed() the scaling factor requested by the consumer is not applied. This for example causes the consumer to process mV when expecting uV. Make sure to always apply the scaling factor requested by the consumer. Fixes: 48e44ce0f881 ("iio:inkern: Add function to read the processed value") Signed-off-by: Liam Beguin Reviewed-by: Peter Rosin Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220108205319.2046348-2-liambeguin@gmail.com Cc: Signed-off-by: Jonathan Cameron --- drivers/iio/inkern.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/inkern.c b/drivers/iio/inkern.c index 0222885b334c..021e1397ffc5 100644 --- a/drivers/iio/inkern.c +++ b/drivers/iio/inkern.c @@ -616,7 +616,7 @@ static int iio_convert_raw_to_processed_unlocked(struct iio_channel *chan, switch (scale_type) { case IIO_VAL_INT: - *processed = raw64 * scale_val; + *processed = raw64 * scale_val * scale; break; case IIO_VAL_INT_PLUS_MICRO: if (scale_val2 < 0) -- cgit v1.2.3 From 14b457fdde38de594a4bc4bd9075019319d978da Mon Sep 17 00:00:00 2001 From: Liam Beguin Date: Sat, 8 Jan 2022 15:53:05 -0500 Subject: iio: inkern: apply consumer scale when no channel scale is available When a consumer calls iio_read_channel_processed() and no channel scale is available, it's assumed that the scale is one and the raw value is returned as expected. On the other hand, if the consumer calls iio_convert_raw_to_processed() the scaling factor requested by the consumer is not applied. This for example causes the consumer to process mV when expecting uV. Make sure to always apply the scaling factor requested by the consumer. Fixes: adc8ec5ff183 ("iio: inkern: pass through raw values if no scaling") Signed-off-by: Liam Beguin Reviewed-by: Peter Rosin Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220108205319.2046348-3-liambeguin@gmail.com Cc: Signed-off-by: Jonathan Cameron --- drivers/iio/inkern.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/iio/inkern.c b/drivers/iio/inkern.c index 021e1397ffc5..dbe13fad3cbb 100644 --- a/drivers/iio/inkern.c +++ b/drivers/iio/inkern.c @@ -607,10 +607,10 @@ static int iio_convert_raw_to_processed_unlocked(struct iio_channel *chan, IIO_CHAN_INFO_SCALE); if (scale_type < 0) { /* - * Just pass raw values as processed if no scaling is - * available. + * If no channel scaling is available apply consumer scale to + * raw value and return. */ - *processed = raw; + *processed = raw * scale; return 0; } -- cgit v1.2.3 From ca85123354e1a65a22170286387b4791997fe864 Mon Sep 17 00:00:00 2001 From: Liam Beguin Date: Sat, 8 Jan 2022 15:53:06 -0500 Subject: iio: inkern: make a best effort on offset calculation iio_convert_raw_to_processed_unlocked() assumes the offset is an integer. Make a best effort to get a valid offset value for fractional cases without breaking implicit truncations. Fixes: 48e44ce0f881 ("iio:inkern: Add function to read the processed value") Signed-off-by: Liam Beguin Reviewed-by: Peter Rosin Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220108205319.2046348-4-liambeguin@gmail.com Cc: Signed-off-by: Jonathan Cameron --- drivers/iio/inkern.c | 32 +++++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/drivers/iio/inkern.c b/drivers/iio/inkern.c index dbe13fad3cbb..df74765d33dc 100644 --- a/drivers/iio/inkern.c +++ b/drivers/iio/inkern.c @@ -595,13 +595,35 @@ EXPORT_SYMBOL_GPL(iio_read_channel_average_raw); static int iio_convert_raw_to_processed_unlocked(struct iio_channel *chan, int raw, int *processed, unsigned int scale) { - int scale_type, scale_val, scale_val2, offset; + int scale_type, scale_val, scale_val2; + int offset_type, offset_val, offset_val2; s64 raw64 = raw; - int ret; - ret = iio_channel_read(chan, &offset, NULL, IIO_CHAN_INFO_OFFSET); - if (ret >= 0) - raw64 += offset; + offset_type = iio_channel_read(chan, &offset_val, &offset_val2, + IIO_CHAN_INFO_OFFSET); + if (offset_type >= 0) { + switch (offset_type) { + case IIO_VAL_INT: + break; + case IIO_VAL_INT_PLUS_MICRO: + case IIO_VAL_INT_PLUS_NANO: + /* + * Both IIO_VAL_INT_PLUS_MICRO and IIO_VAL_INT_PLUS_NANO + * implicitely truncate the offset to it's integer form. + */ + break; + case IIO_VAL_FRACTIONAL: + offset_val /= offset_val2; + break; + case IIO_VAL_FRACTIONAL_LOG2: + offset_val >>= offset_val2; + break; + default: + return -EINVAL; + } + + raw64 += offset_val; + } scale_type = iio_channel_read(chan, &scale_val, &scale_val2, IIO_CHAN_INFO_SCALE); -- cgit v1.2.3 From 51593106b608ae4247cc8da928813347da16d025 Mon Sep 17 00:00:00 2001 From: Liam Beguin Date: Sat, 8 Jan 2022 15:53:07 -0500 Subject: iio: afe: rescale: use s64 for temporary scale calculations All four scaling coefficients can take signed values. Make tmp a signed 64-bit integer and switch to div_s64() to preserve signs during 64-bit divisions. Fixes: 8b74816b5a9a ("iio: afe: rescale: new driver") Signed-off-by: Liam Beguin Reviewed-by: Peter Rosin Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220108205319.2046348-5-liambeguin@gmail.com Cc: Signed-off-by: Jonathan Cameron --- drivers/iio/afe/iio-rescale.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/iio/afe/iio-rescale.c b/drivers/iio/afe/iio-rescale.c index 774eb3044edd..271d73e420c4 100644 --- a/drivers/iio/afe/iio-rescale.c +++ b/drivers/iio/afe/iio-rescale.c @@ -39,7 +39,7 @@ static int rescale_read_raw(struct iio_dev *indio_dev, int *val, int *val2, long mask) { struct rescale *rescale = iio_priv(indio_dev); - unsigned long long tmp; + s64 tmp; int ret; switch (mask) { @@ -77,10 +77,10 @@ static int rescale_read_raw(struct iio_dev *indio_dev, *val2 = rescale->denominator; return IIO_VAL_FRACTIONAL; case IIO_VAL_FRACTIONAL_LOG2: - tmp = *val * 1000000000LL; - do_div(tmp, rescale->denominator); + tmp = (s64)*val * 1000000000LL; + tmp = div_s64(tmp, rescale->denominator); tmp *= rescale->numerator; - do_div(tmp, 1000000000LL); + tmp = div_s64(tmp, 1000000000LL); *val = tmp; return ret; default: -- cgit v1.2.3 From cd717ac6f69db4953ca701c6220c7cb58e17f35a Mon Sep 17 00:00:00 2001 From: Liam Beguin Date: Sat, 8 Jan 2022 15:53:08 -0500 Subject: iio: afe: rescale: reorder includes Includes should be ordered alphabetically which is already the case, but follow what is done in other drivers by separation IIO specific headers with a blank line. Signed-off-by: Liam Beguin Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220108205319.2046348-6-liambeguin@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/afe/iio-rescale.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/iio/afe/iio-rescale.c b/drivers/iio/afe/iio-rescale.c index 271d73e420c4..69710c481376 100644 --- a/drivers/iio/afe/iio-rescale.c +++ b/drivers/iio/afe/iio-rescale.c @@ -9,14 +9,15 @@ #include #include -#include -#include #include #include #include #include #include +#include +#include + struct rescale; struct rescale_cfg { -- cgit v1.2.3 From f89ff2b356f01e6789d48f1f58cf537d670303b7 Mon Sep 17 00:00:00 2001 From: Eugen Hristev Date: Fri, 17 Dec 2021 11:54:01 +0200 Subject: dt-bindings: iio: adc: atmel,sama5d2-adc: make atmel,trigger-edge-type non-mandatory The atmel,trigger-edge-type was never imposed by the driver. Make things right and remove this property from the mandatory list. This will not break existing nodes because according to the binding they should have this property. However, the driver does not impose it and it works without it, the property selects the trigger type, and without it, the driver will have no trigger available, which is the case on some boards which do not have access to the trigger pin. This will avoid generating this warning for example: */arch/arm/boot/dts/at91-sama7g5ek.dt.yaml: adc@e1000000: 'atmel,trigger-edge-type' is a required property From schema: */Documentation/devicetree/bindings/iio/adc/atmel,sama5d2-adc.yaml Signed-off-by: Eugen Hristev Acked-by: Rob Herring Link: https://lore.kernel.org/r/20211217095401.583821-1-eugen.hristev@microchip.com Signed-off-by: Jonathan Cameron --- Documentation/devicetree/bindings/iio/adc/atmel,sama5d2-adc.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/Documentation/devicetree/bindings/iio/adc/atmel,sama5d2-adc.yaml b/Documentation/devicetree/bindings/iio/adc/atmel,sama5d2-adc.yaml index efed361215b4..482d80dd43b5 100644 --- a/Documentation/devicetree/bindings/iio/adc/atmel,sama5d2-adc.yaml +++ b/Documentation/devicetree/bindings/iio/adc/atmel,sama5d2-adc.yaml @@ -72,7 +72,6 @@ required: - atmel,min-sample-rate-hz - atmel,max-sample-rate-hz - atmel,startup-time-ms - - atmel,trigger-edge-type examples: - | -- cgit v1.2.3 From f3366f8e646451aed5594400d54b75361f0f2109 Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Mon, 6 Dec 2021 10:50:34 +0800 Subject: mailmap: Update email address for Cai Huoqing The caihuoqing@baidu.com would be deprecated and use cai.huoqing@linux.dev as the main email address. Signed-off-by: Cai Huoqing Link: https://lore.kernel.org/r/20211206025034.2729-1-caihuoqing@baidu.com Signed-off-by: Jonathan Cameron --- .mailmap | 1 + 1 file changed, 1 insertion(+) diff --git a/.mailmap b/.mailmap index b157f88ce26a..76dd303c7eac 100644 --- a/.mailmap +++ b/.mailmap @@ -70,6 +70,7 @@ Boris Brezillon Boris Brezillon Brian Avery Brian King +Cai Huoqing Changbin Du Changbin Du Chao Yu -- cgit v1.2.3 From 7b9c8e1a0ca18a62565ee0e28b23baf7b176e96f Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Sun, 30 Jan 2022 15:50:08 +0100 Subject: dt-bindings: iio: adc: at91-sama5d2: update maintainers entry Update the maintainers entry to match the changes made back in mid-2020 with 853fa48717c2 ("MAINTAINERS: adc: at91-sama5d2_adc: remove myself as co-maintainer"). Signed-off-by: Nicolas Ferre Link: https://lore.kernel.org/r/6acdb66592baf395a77a431c0cb9a37b0f178097.1643554065.git.nicolas.ferre@microchip.com Signed-off-by: Jonathan Cameron --- Documentation/devicetree/bindings/iio/adc/atmel,sama5d2-adc.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/Documentation/devicetree/bindings/iio/adc/atmel,sama5d2-adc.yaml b/Documentation/devicetree/bindings/iio/adc/atmel,sama5d2-adc.yaml index 482d80dd43b5..31f840d59303 100644 --- a/Documentation/devicetree/bindings/iio/adc/atmel,sama5d2-adc.yaml +++ b/Documentation/devicetree/bindings/iio/adc/atmel,sama5d2-adc.yaml @@ -7,7 +7,6 @@ $schema: http://devicetree.org/meta-schemas/core.yaml# title: AT91 SAMA5D2 Analog to Digital Converter (ADC) maintainers: - - Ludovic Desroches - Eugen Hristev properties: -- cgit v1.2.3 From 0216208088c7d16f466988010d58c60d62c324b7 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 3 Feb 2022 14:33:54 +0200 Subject: iio: dac: ad5592r: Drop leftover header inclusion There is no use of of.h in the module, drop it. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220203123354.76573-1-andriy.shevchenko@linux.intel.com Signed-off-by: Jonathan Cameron --- drivers/iio/dac/ad5592r-base.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/iio/dac/ad5592r-base.c b/drivers/iio/dac/ad5592r-base.c index 2fcc59728fd6..a9c654b614a4 100644 --- a/drivers/iio/dac/ad5592r-base.c +++ b/drivers/iio/dac/ad5592r-base.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include -- cgit v1.2.3 From 200da7ef7cf0d29e67cb9630f72d91839ded8d0a Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 3 Feb 2022 14:27:25 +0200 Subject: iio: chemical: bme680: Switch from of headers to mod_devicetable.h There is nothing directly using of specific interfaces in this driver, so lets not include the headers. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220203122725.75939-1-andriy.shevchenko@linux.intel.com Signed-off-by: Jonathan Cameron --- drivers/iio/chemical/bme680_spi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/chemical/bme680_spi.c b/drivers/iio/chemical/bme680_spi.c index cc579a7ac5ce..0a064a395178 100644 --- a/drivers/iio/chemical/bme680_spi.c +++ b/drivers/iio/chemical/bme680_spi.c @@ -4,8 +4,8 @@ * * Copyright (C) 2018 Himanshu Jha */ +#include #include -#include #include #include -- cgit v1.2.3 From 201d11c5082a9265ad4cc4b9e7695ac68e8c4bd3 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 3 Feb 2022 14:16:24 +0200 Subject: iio: amplifiers: hmc425a: Make use of device properties Convert the module to be property provider agnostic and allow it to be used on non-OF platforms. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220203121624.75515-1-andriy.shevchenko@linux.intel.com Signed-off-by: Jonathan Cameron --- drivers/iio/amplifiers/hmc425a.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/iio/amplifiers/hmc425a.c b/drivers/iio/amplifiers/hmc425a.c index 16c0a77f6a1c..ce80e0c916f4 100644 --- a/drivers/iio/amplifiers/hmc425a.c +++ b/drivers/iio/amplifiers/hmc425a.c @@ -11,10 +11,10 @@ #include #include #include +#include #include -#include -#include #include +#include #include #include #include @@ -192,7 +192,7 @@ static int hmc425a_probe(struct platform_device *pdev) return -ENOMEM; st = iio_priv(indio_dev); - st->type = (uintptr_t)of_device_get_match_data(&pdev->dev); + st->type = (uintptr_t)device_get_match_data(&pdev->dev); st->chip_info = &hmc425a_chip_info_tbl[st->type]; indio_dev->num_channels = st->chip_info->num_channels; -- cgit v1.2.3 From 130650e8360fa39919b61eab048c6a724da243d8 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 3 Feb 2022 13:00:06 +0200 Subject: iio: frequency: adf4350: Make use of device properties Convert the module to be property provider agnostic and allow it to be used on non-OF platforms. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220203110006.4291-1-andriy.shevchenko@linux.intel.com Signed-off-by: Jonathan Cameron --- drivers/iio/frequency/adf4350.c | 103 ++++++++++++++++------------------------ 1 file changed, 42 insertions(+), 61 deletions(-) diff --git a/drivers/iio/frequency/adf4350.c b/drivers/iio/frequency/adf4350.c index 3d9eba716b69..9af20a51540d 100644 --- a/drivers/iio/frequency/adf4350.c +++ b/drivers/iio/frequency/adf4350.c @@ -7,17 +7,18 @@ #include #include +#include +#include +#include #include #include #include #include #include -#include #include #include #include #include -#include #include #include @@ -381,10 +382,8 @@ static const struct iio_info adf4350_info = { .debugfs_reg_access = &adf4350_reg_access, }; -#ifdef CONFIG_OF static struct adf4350_platform_data *adf4350_parse_dt(struct device *dev) { - struct device_node *np = dev->of_node; struct adf4350_platform_data *pdata; unsigned int tmp; @@ -392,101 +391,83 @@ static struct adf4350_platform_data *adf4350_parse_dt(struct device *dev) if (!pdata) return NULL; - snprintf(&pdata->name[0], SPI_NAME_SIZE - 1, "%pOFn", np); + snprintf(pdata->name, sizeof(pdata->name), "%pfw", dev_fwnode(dev)); tmp = 10000; - of_property_read_u32(np, "adi,channel-spacing", &tmp); + device_property_read_u32(dev, "adi,channel-spacing", &tmp); pdata->channel_spacing = tmp; tmp = 0; - of_property_read_u32(np, "adi,power-up-frequency", &tmp); + device_property_read_u32(dev, "adi,power-up-frequency", &tmp); pdata->power_up_frequency = tmp; tmp = 0; - of_property_read_u32(np, "adi,reference-div-factor", &tmp); + device_property_read_u32(dev, "adi,reference-div-factor", &tmp); pdata->ref_div_factor = tmp; - pdata->ref_doubler_en = of_property_read_bool(np, - "adi,reference-doubler-enable"); - pdata->ref_div2_en = of_property_read_bool(np, - "adi,reference-div2-enable"); + pdata->ref_doubler_en = device_property_read_bool(dev, "adi,reference-doubler-enable"); + pdata->ref_div2_en = device_property_read_bool(dev, "adi,reference-div2-enable"); /* r2_user_settings */ - pdata->r2_user_settings = of_property_read_bool(np, - "adi,phase-detector-polarity-positive-enable") ? - ADF4350_REG2_PD_POLARITY_POS : 0; - pdata->r2_user_settings |= of_property_read_bool(np, - "adi,lock-detect-precision-6ns-enable") ? - ADF4350_REG2_LDP_6ns : 0; - pdata->r2_user_settings |= of_property_read_bool(np, - "adi,lock-detect-function-integer-n-enable") ? - ADF4350_REG2_LDF_INT_N : 0; + pdata->r2_user_settings = 0; + if (device_property_read_bool(dev, "adi,phase-detector-polarity-positive-enable")) + pdata->r2_user_settings |= ADF4350_REG2_PD_POLARITY_POS; + if (device_property_read_bool(dev, "adi,lock-detect-precision-6ns-enable")) + pdata->r2_user_settings |= ADF4350_REG2_LDP_6ns; + if (device_property_read_bool(dev, "adi,lock-detect-function-integer-n-enable")) + pdata->r2_user_settings |= ADF4350_REG2_LDF_INT_N; tmp = 2500; - of_property_read_u32(np, "adi,charge-pump-current", &tmp); + device_property_read_u32(dev, "adi,charge-pump-current", &tmp); pdata->r2_user_settings |= ADF4350_REG2_CHARGE_PUMP_CURR_uA(tmp); tmp = 0; - of_property_read_u32(np, "adi,muxout-select", &tmp); + device_property_read_u32(dev, "adi,muxout-select", &tmp); pdata->r2_user_settings |= ADF4350_REG2_MUXOUT(tmp); - pdata->r2_user_settings |= of_property_read_bool(np, - "adi,low-spur-mode-enable") ? - ADF4350_REG2_NOISE_MODE(0x3) : 0; + if (device_property_read_bool(dev, "adi,low-spur-mode-enable")) + pdata->r2_user_settings |= ADF4350_REG2_NOISE_MODE(0x3); /* r3_user_settings */ - pdata->r3_user_settings = of_property_read_bool(np, - "adi,cycle-slip-reduction-enable") ? - ADF4350_REG3_12BIT_CSR_EN : 0; - pdata->r3_user_settings |= of_property_read_bool(np, - "adi,charge-cancellation-enable") ? - ADF4351_REG3_CHARGE_CANCELLATION_EN : 0; - - pdata->r3_user_settings |= of_property_read_bool(np, - "adi,anti-backlash-3ns-enable") ? - ADF4351_REG3_ANTI_BACKLASH_3ns_EN : 0; - pdata->r3_user_settings |= of_property_read_bool(np, - "adi,band-select-clock-mode-high-enable") ? - ADF4351_REG3_BAND_SEL_CLOCK_MODE_HIGH : 0; + pdata->r3_user_settings = 0; + if (device_property_read_bool(dev, "adi,cycle-slip-reduction-enable")) + pdata->r3_user_settings |= ADF4350_REG3_12BIT_CSR_EN; + if (device_property_read_bool(dev, "adi,charge-cancellation-enable")) + pdata->r3_user_settings |= ADF4351_REG3_CHARGE_CANCELLATION_EN; + if (device_property_read_bool(dev, "adi,anti-backlash-3ns-enable")) + pdata->r3_user_settings |= ADF4351_REG3_ANTI_BACKLASH_3ns_EN; + if (device_property_read_bool(dev, "adi,band-select-clock-mode-high-enable")) + pdata->r3_user_settings |= ADF4351_REG3_BAND_SEL_CLOCK_MODE_HIGH; tmp = 0; - of_property_read_u32(np, "adi,12bit-clk-divider", &tmp); + device_property_read_u32(dev, "adi,12bit-clk-divider", &tmp); pdata->r3_user_settings |= ADF4350_REG3_12BIT_CLKDIV(tmp); tmp = 0; - of_property_read_u32(np, "adi,clk-divider-mode", &tmp); + device_property_read_u32(dev, "adi,clk-divider-mode", &tmp); pdata->r3_user_settings |= ADF4350_REG3_12BIT_CLKDIV_MODE(tmp); /* r4_user_settings */ - pdata->r4_user_settings = of_property_read_bool(np, - "adi,aux-output-enable") ? - ADF4350_REG4_AUX_OUTPUT_EN : 0; - pdata->r4_user_settings |= of_property_read_bool(np, - "adi,aux-output-fundamental-enable") ? - ADF4350_REG4_AUX_OUTPUT_FUND : 0; - pdata->r4_user_settings |= of_property_read_bool(np, - "adi,mute-till-lock-enable") ? - ADF4350_REG4_MUTE_TILL_LOCK_EN : 0; + pdata->r4_user_settings = 0; + if (device_property_read_bool(dev, "adi,aux-output-enable")) + pdata->r4_user_settings |= ADF4350_REG4_AUX_OUTPUT_EN; + if (device_property_read_bool(dev, "adi,aux-output-fundamental-enable")) + pdata->r4_user_settings |= ADF4350_REG4_AUX_OUTPUT_FUND; + if (device_property_read_bool(dev, "adi,mute-till-lock-enable")) + pdata->r4_user_settings |= ADF4350_REG4_MUTE_TILL_LOCK_EN; tmp = 0; - of_property_read_u32(np, "adi,output-power", &tmp); + device_property_read_u32(dev, "adi,output-power", &tmp); pdata->r4_user_settings |= ADF4350_REG4_OUTPUT_PWR(tmp); tmp = 0; - of_property_read_u32(np, "adi,aux-output-power", &tmp); + device_property_read_u32(dev, "adi,aux-output-power", &tmp); pdata->r4_user_settings |= ADF4350_REG4_AUX_OUTPUT_PWR(tmp); return pdata; } -#else -static -struct adf4350_platform_data *adf4350_parse_dt(struct device *dev) -{ - return NULL; -} -#endif static int adf4350_probe(struct spi_device *spi) { @@ -496,7 +477,7 @@ static int adf4350_probe(struct spi_device *spi) struct clk *clk = NULL; int ret; - if (spi->dev.of_node) { + if (dev_fwnode(&spi->dev)) { pdata = adf4350_parse_dt(&spi->dev); if (pdata == NULL) return -EINVAL; @@ -625,7 +606,7 @@ MODULE_DEVICE_TABLE(spi, adf4350_id); static struct spi_driver adf4350_driver = { .driver = { .name = "adf4350", - .of_match_table = of_match_ptr(adf4350_of_match), + .of_match_table = adf4350_of_match, }, .probe = adf4350_probe, .remove = adf4350_remove, -- cgit v1.2.3 From d2fdbccd809605a0813cd119ba20f84536b7c95b Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 2 Feb 2022 22:34:20 +0200 Subject: iio: humidity: dht11: Switch from of headers to mod_devicetable.h There is nothing directly using of specific interfaces in this driver, so lets not include the headers. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220202203420.56654-1-andriy.shevchenko@linux.intel.com Signed-off-by: Jonathan Cameron --- drivers/iio/humidity/dht11.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/iio/humidity/dht11.c b/drivers/iio/humidity/dht11.c index 9a7819817488..c97e25448772 100644 --- a/drivers/iio/humidity/dht11.c +++ b/drivers/iio/humidity/dht11.c @@ -11,10 +11,9 @@ #include #include #include -#include -#include #include #include +#include #include #include #include -- cgit v1.2.3 From 2314e7ed67d22af2864fae5586d5e20b793f4909 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 2 Feb 2022 22:55:31 +0200 Subject: iio: temperature: mlx90632: Switch from of headers to mod_devicetable.h There is nothing directly using of specific interfaces in this driver, so lets not include the headers. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220202205531.57966-1-andriy.shevchenko@linux.intel.com Signed-off-by: Jonathan Cameron --- drivers/iio/temperature/mlx90632.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/temperature/mlx90632.c b/drivers/iio/temperature/mlx90632.c index 608ccb1d8bc8..7ee7ff8047a4 100644 --- a/drivers/iio/temperature/mlx90632.c +++ b/drivers/iio/temperature/mlx90632.c @@ -13,9 +13,9 @@ #include #include #include +#include #include #include -#include #include #include -- cgit v1.2.3 From 0bb77dcea7fae1b5f692fa4679f5cfa0e6c58df8 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 2 Feb 2022 22:53:28 +0200 Subject: iio: temperature: maxim_thermocouple: Switch from of headers to mod_devicetable.h There is nothing directly using of specific interfaces in this driver, so lets not include the headers. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220202205328.57837-1-andriy.shevchenko@linux.intel.com Signed-off-by: Jonathan Cameron --- drivers/iio/temperature/maxim_thermocouple.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/iio/temperature/maxim_thermocouple.c b/drivers/iio/temperature/maxim_thermocouple.c index 0297e215b61a..98c41cddc6f0 100644 --- a/drivers/iio/temperature/maxim_thermocouple.c +++ b/drivers/iio/temperature/maxim_thermocouple.c @@ -6,12 +6,11 @@ * Author: */ -#include #include +#include +#include #include #include -#include -#include #include #include #include -- cgit v1.2.3 From 08f5fbf030ecb2c0c54fb3072ab76a8ceae75cf9 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 2 Feb 2022 19:37:23 +0200 Subject: iio: accel: adxl355: Replace custom definitions with generic from units.h The units.h provides MEGA and TERA. Replace custom ones. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220202173723.8678-1-andriy.shevchenko@linux.intel.com Signed-off-by: Jonathan Cameron --- drivers/iio/accel/adxl355_core.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/iio/accel/adxl355_core.c b/drivers/iio/accel/adxl355_core.c index 4f485909f459..7023de888835 100644 --- a/drivers/iio/accel/adxl355_core.c +++ b/drivers/iio/accel/adxl355_core.c @@ -20,6 +20,8 @@ #include #include #include +#include + #include #include "adxl355.h" @@ -60,9 +62,6 @@ #define ADXL355_PARTID_VAL 0xED #define ADXL355_RESET_CODE 0x52 -#define MEGA 1000000UL -#define TERA 1000000000000ULL - static const struct regmap_range adxl355_read_reg_range[] = { regmap_reg_range(ADXL355_DEVID_AD_REG, ADXL355_FIFO_DATA_REG), regmap_reg_range(ADXL355_OFFSET_X_H_REG, ADXL355_SELF_TEST_REG), -- cgit v1.2.3 From c53c7740bdbd976f868ddcfaf73f63797617ed99 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 3 Feb 2022 17:59:18 +0200 Subject: iio: imu: inv_mpu6050: Drop wrong use of ACPI_PTR() ACPI_PTR() is more harmful than helpful. For example, in this case if CONFIG_ACPI=n, the ID table left unused which is not what we want. Instead of adding ifdeffery or attribute here and there, drop ACPI_PTR(). Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220203155920.18586-1-andriy.shevchenko@linux.intel.com Signed-off-by: Jonathan Cameron --- drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c | 7 +++---- drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c | 4 ++-- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c index fe03707ec2d3..ccb06d9af760 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c @@ -3,11 +3,11 @@ * Copyright (C) 2012 Invensense, Inc. */ -#include #include #include #include #include +#include #include #include #include @@ -249,11 +249,10 @@ static const struct of_device_id inv_of_match[] = { }; MODULE_DEVICE_TABLE(of, inv_of_match); -static const struct acpi_device_id __maybe_unused inv_acpi_match[] = { +static const struct acpi_device_id inv_acpi_match[] = { {"INVN6500", INV_MPU6500}, { }, }; - MODULE_DEVICE_TABLE(acpi, inv_acpi_match); static struct i2c_driver inv_mpu_driver = { @@ -262,7 +261,7 @@ static struct i2c_driver inv_mpu_driver = { .id_table = inv_mpu_id, .driver = { .of_match_table = inv_of_match, - .acpi_match_table = ACPI_PTR(inv_acpi_match), + .acpi_match_table = inv_acpi_match, .name = "inv-mpu6050-i2c", .pm = &inv_mpu_pmops, }, diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c index 6800356b25fb..44b4f74b9256 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c @@ -2,8 +2,8 @@ /* * Copyright (C) 2015 Intel Corporation Inc. */ +#include #include -#include #include #include #include @@ -148,7 +148,7 @@ static struct spi_driver inv_mpu_driver = { .id_table = inv_mpu_id, .driver = { .of_match_table = inv_of_match, - .acpi_match_table = ACPI_PTR(inv_acpi_match), + .acpi_match_table = inv_acpi_match, .name = "inv-mpu6000-spi", .pm = &inv_mpu_pmops, }, -- cgit v1.2.3 From 1ef6ff6ef8d581ceb1512581f47be3f99f4f8571 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 3 Feb 2022 17:59:19 +0200 Subject: iio: imu: inv_mpu6050: Check ACPI companion directly Instead of checking for ACPI handle followed by extracting a companion device, do the latter first and use it for checks. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220203155920.18586-2-andriy.shevchenko@linux.intel.com Signed-off-by: Jonathan Cameron --- drivers/iio/imu/inv_mpu6050/inv_mpu_acpi.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_acpi.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_acpi.c index f8f0cf716bc6..9b4298095d3f 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_acpi.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_acpi.c @@ -127,15 +127,14 @@ static int inv_mpu_process_acpi_config(struct i2c_client *client, int inv_mpu_acpi_create_mux_client(struct i2c_client *client) { struct inv_mpu6050_state *st = iio_priv(dev_get_drvdata(&client->dev)); + struct acpi_device *adev = ACPI_COMPANION(&client->dev); st->mux_client = NULL; - if (ACPI_HANDLE(&client->dev)) { + if (adev) { struct i2c_board_info info; struct i2c_client *mux_client; - struct acpi_device *adev; int ret = -1; - adev = ACPI_COMPANION(&client->dev); memset(&info, 0, sizeof(info)); dmi_check_system(inv_mpu_dev_list); -- cgit v1.2.3 From 889bdfc336392b904f7da441908d833556eaf438 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 3 Feb 2022 17:59:20 +0200 Subject: iio: imu: inv_mpu6050: Make use of device properties Convert the module to be property provider agnostic and allow it to be used on non-OF platforms. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220203155920.18586-3-andriy.shevchenko@linux.intel.com Signed-off-by: Jonathan Cameron --- drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c | 8 ++++---- drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c | 1 - 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c index ccb06d9af760..55cffb5fa115 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c @@ -9,8 +9,8 @@ #include #include #include -#include #include + #include "inv_mpu_iio.h" static const struct regmap_config inv_mpu_regmap_config = { @@ -51,7 +51,7 @@ static int inv_mpu_i2c_aux_setup(struct iio_dev *indio_dev) { struct inv_mpu6050_state *st = iio_priv(indio_dev); struct device *dev = indio_dev->dev.parent; - struct device_node *mux_node; + struct fwnode_handle *mux_node; int ret; /* @@ -65,12 +65,12 @@ static int inv_mpu_i2c_aux_setup(struct iio_dev *indio_dev) case INV_MPU9150: case INV_MPU9250: case INV_MPU9255: - mux_node = of_get_child_by_name(dev->of_node, "i2c-gate"); + mux_node = device_get_named_child_node(dev, "i2c-gate"); if (mux_node != NULL) { st->magn_disabled = true; dev_warn(dev, "disable internal use of magnetometer\n"); } - of_node_put(mux_node); + fwnode_handle_put(mux_node); break; default: break; diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c index 44b4f74b9256..26a7c2521dc4 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c @@ -4,7 +4,6 @@ */ #include #include -#include #include #include #include -- cgit v1.2.3 From 342c6c5e2260875e0716a9f798dd89da431e679f Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Mon, 7 Feb 2022 13:59:43 +0000 Subject: iio: adc: cpcap-adc: remove redundant assignment to variable cal_data_diff The variable cal_data_diff is being assigned a value that is never read, it is being re-assigned later on with a new value in both paths of an if statement. The assignment is redundant, so remove it. Signed-off-by: Colin Ian King Link: https://lore.kernel.org/r/20220207135943.340629-1-colin.i.king@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/cpcap-adc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/adc/cpcap-adc.c b/drivers/iio/adc/cpcap-adc.c index 40e59f4c95bc..b6c4ef70484e 100644 --- a/drivers/iio/adc/cpcap-adc.c +++ b/drivers/iio/adc/cpcap-adc.c @@ -474,7 +474,7 @@ static int cpcap_adc_calibrate_one(struct cpcap_adc *ddata, for (i = 0; i < CPCAP_ADC_MAX_RETRIES; i++) { calibration_data[0] = 0; calibration_data[1] = 0; - cal_data_diff = 0; + cpcap_adc_setup_calibrate(ddata, channel); error = regmap_read(ddata->reg, calibration_register, &calibration_data[0]); -- cgit v1.2.3 From 261ecd47b4d17c186aa17202f8ee325f380610e0 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sun, 13 Feb 2022 13:30:11 +0100 Subject: iio: as3935: Use devm_delayed_work_autocancel() Use devm_delayed_work_autocancel() instead of hand writing it. It saves a few lines of code. Signed-off-by: Christophe JAILLET Link: https://lore.kernel.org/r/8d5c50f191bd8f751849d72127f83b14a7636d64.1644755396.git.christophe.jaillet@wanadoo.fr Signed-off-by: Jonathan Cameron --- drivers/iio/proximity/as3935.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/drivers/iio/proximity/as3935.c b/drivers/iio/proximity/as3935.c index bd7595db31d4..00e06491b188 100644 --- a/drivers/iio/proximity/as3935.c +++ b/drivers/iio/proximity/as3935.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -344,14 +345,6 @@ static SIMPLE_DEV_PM_OPS(as3935_pm_ops, as3935_suspend, as3935_resume); #define AS3935_PM_OPS NULL #endif -static void as3935_stop_work(void *data) -{ - struct iio_dev *indio_dev = data; - struct as3935_state *st = iio_priv(indio_dev); - - cancel_delayed_work_sync(&st->work); -} - static int as3935_probe(struct spi_device *spi) { struct device *dev = &spi->dev; @@ -432,8 +425,7 @@ static int as3935_probe(struct spi_device *spi) calibrate_as3935(st); - INIT_DELAYED_WORK(&st->work, as3935_event_work); - ret = devm_add_action(dev, as3935_stop_work, indio_dev); + ret = devm_delayed_work_autocancel(dev, &st->work, as3935_event_work); if (ret) return ret; -- cgit v1.2.3 From b946e9491a048755aa9261e7d9f0d012ba52c740 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 10 Feb 2022 15:57:24 +0200 Subject: iio: ssp_sensors: Make use of device properties Convert the module to be property provider agnostic and allow it to be used on non-OF platforms. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220210135724.26660-1-andriy.shevchenko@linux.intel.com Signed-off-by: Jonathan Cameron --- drivers/iio/common/ssp_sensors/ssp_dev.c | 22 +++++----------------- 1 file changed, 5 insertions(+), 17 deletions(-) diff --git a/drivers/iio/common/ssp_sensors/ssp_dev.c b/drivers/iio/common/ssp_sensors/ssp_dev.c index 1aee87100038..a2b91a7504bc 100644 --- a/drivers/iio/common/ssp_sensors/ssp_dev.c +++ b/drivers/iio/common/ssp_sensors/ssp_dev.c @@ -7,9 +7,10 @@ #include #include #include +#include #include -#include -#include +#include + #include "ssp.h" #define SSP_WDT_TIME 10000 @@ -425,7 +426,6 @@ int ssp_queue_ssp_refresh_task(struct ssp_data *data, unsigned int delay) msecs_to_jiffies(delay)); } -#ifdef CONFIG_OF static const struct of_device_id ssp_of_match[] = { { .compatible = "samsung,sensorhub-rinato", @@ -441,8 +441,6 @@ MODULE_DEVICE_TABLE(of, ssp_of_match); static struct ssp_data *ssp_parse_dt(struct device *dev) { struct ssp_data *data; - struct device_node *node = dev->of_node; - const struct of_device_id *match; data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); if (!data) @@ -461,22 +459,12 @@ static struct ssp_data *ssp_parse_dt(struct device *dev) if (IS_ERR(data->mcu_reset_gpiod)) return NULL; - match = of_match_node(ssp_of_match, node); - if (!match) - return NULL; - - data->sensorhub_info = match->data; + data->sensorhub_info = device_get_match_data(dev); dev_set_drvdata(dev, data); return data; } -#else -static struct ssp_data *ssp_parse_dt(struct device *pdev) -{ - return NULL; -} -#endif /** * ssp_register_consumer() - registers iio consumer in ssp framework @@ -672,7 +660,7 @@ static struct spi_driver ssp_driver = { .remove = ssp_remove, .driver = { .pm = &ssp_pm_ops, - .of_match_table = of_match_ptr(ssp_of_match), + .of_match_table = ssp_of_match, .name = "sensorhub" }, }; -- cgit v1.2.3 From 15ea6bc03bd9e6256053d12a5ee88755ac3e21d5 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 7 Feb 2022 14:42:04 +0200 Subject: iio: chemical: atlas-ezo-sensor: Make use of device properties Convert the module to be property provider agnostic and allow it to be used on non-OF platforms. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220207124204.11658-1-andriy.shevchenko@linux.intel.com Signed-off-by: Jonathan Cameron --- drivers/iio/chemical/atlas-ezo-sensor.c | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/drivers/iio/chemical/atlas-ezo-sensor.c b/drivers/iio/chemical/atlas-ezo-sensor.c index b1bacfe3c3ce..bbcf5a59c1f4 100644 --- a/drivers/iio/chemical/atlas-ezo-sensor.c +++ b/drivers/iio/chemical/atlas-ezo-sensor.c @@ -6,13 +6,15 @@ * Author: Matt Ranostay */ -#include #include #include +#include +#include #include +#include #include #include -#include + #include #define ATLAS_EZO_DRV_NAME "atlas-ezo-sensor" @@ -33,7 +35,7 @@ struct atlas_ezo_device { struct atlas_ezo_data { struct i2c_client *client; - struct atlas_ezo_device *chip; + const struct atlas_ezo_device *chip; /* lock to avoid multiple concurrent read calls */ struct mutex lock; @@ -184,17 +186,17 @@ static const struct iio_info atlas_info = { }; static const struct i2c_device_id atlas_ezo_id[] = { - { "atlas-co2-ezo", ATLAS_CO2_EZO }, - { "atlas-o2-ezo", ATLAS_O2_EZO }, - { "atlas-hum-ezo", ATLAS_HUM_EZO }, + { "atlas-co2-ezo", (kernel_ulong_t)&atlas_ezo_devices[ATLAS_CO2_EZO] }, + { "atlas-o2-ezo", (kernel_ulong_t)&atlas_ezo_devices[ATLAS_O2_EZO] }, + { "atlas-hum-ezo", (kernel_ulong_t)&atlas_ezo_devices[ATLAS_HUM_EZO] }, {} }; MODULE_DEVICE_TABLE(i2c, atlas_ezo_id); static const struct of_device_id atlas_ezo_dt_ids[] = { - { .compatible = "atlas,co2-ezo", .data = (void *)ATLAS_CO2_EZO, }, - { .compatible = "atlas,o2-ezo", .data = (void *)ATLAS_O2_EZO, }, - { .compatible = "atlas,hum-ezo", .data = (void *)ATLAS_HUM_EZO, }, + { .compatible = "atlas,co2-ezo", .data = &atlas_ezo_devices[ATLAS_CO2_EZO], }, + { .compatible = "atlas,o2-ezo", .data = &atlas_ezo_devices[ATLAS_O2_EZO], }, + { .compatible = "atlas,hum-ezo", .data = &atlas_ezo_devices[ATLAS_HUM_EZO], }, {} }; MODULE_DEVICE_TABLE(of, atlas_ezo_dt_ids); @@ -202,20 +204,20 @@ MODULE_DEVICE_TABLE(of, atlas_ezo_dt_ids); static int atlas_ezo_probe(struct i2c_client *client, const struct i2c_device_id *id) { + const struct atlas_ezo_device *chip; struct atlas_ezo_data *data; - struct atlas_ezo_device *chip; - const struct of_device_id *of_id; struct iio_dev *indio_dev; indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); if (!indio_dev) return -ENOMEM; - of_id = of_match_device(atlas_ezo_dt_ids, &client->dev); - if (!of_id) - chip = &atlas_ezo_devices[id->driver_data]; + if (dev_fwnode(&client->dev)) + chip = device_get_match_data(&client->dev); else - chip = &atlas_ezo_devices[(unsigned long)of_id->data]; + chip = (const struct atlas_ezo_device *)id->driver_data; + if (!chip) + return -EINVAL; indio_dev->info = &atlas_info; indio_dev->name = ATLAS_EZO_DRV_NAME; -- cgit v1.2.3 From a47ac019e7e8129b93a0b991e04b2a59872e053d Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Tue, 8 Feb 2022 13:43:35 +0100 Subject: iio: mma8452: Fix probe failing when an i2c_device_id is used The mma8452_driver declares both of_match_table and i2c_driver.id_table match-tables, but its probe() function only checked for of matches. Add support for i2c_device_id matches. This fixes the driver not loading on some x86 tablets (e.g. the Nextbook Ares 8) where the i2c_client is instantiated by platform code using an i2c_device_id. Drop of_match_ptr() protection to avoid unused warning. Fixes: c3cdd6e48e35 ("iio: mma8452: refactor for seperating chip specific data") Signed-off-by: Hans de Goede Link: https://lore.kernel.org/r/20220208124336.511884-1-hdegoede@redhat.com Signed-off-by: Jonathan Cameron --- drivers/iio/accel/mma8452.c | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/drivers/iio/accel/mma8452.c b/drivers/iio/accel/mma8452.c index 64b82b4503ad..09c82abd2354 100644 --- a/drivers/iio/accel/mma8452.c +++ b/drivers/iio/accel/mma8452.c @@ -176,6 +176,7 @@ static const struct mma8452_event_regs trans_ev_regs = { * @enabled_events: event flags enabled and handled by this driver */ struct mma_chip_info { + const char *name; u8 chip_id; const struct iio_chan_spec *channels; int num_channels; @@ -1301,6 +1302,7 @@ enum { static const struct mma_chip_info mma_chip_info_table[] = { [mma8451] = { + .name = "mma8451", .chip_id = MMA8451_DEVICE_ID, .channels = mma8451_channels, .num_channels = ARRAY_SIZE(mma8451_channels), @@ -1325,6 +1327,7 @@ static const struct mma_chip_info mma_chip_info_table[] = { MMA8452_INT_FF_MT, }, [mma8452] = { + .name = "mma8452", .chip_id = MMA8452_DEVICE_ID, .channels = mma8452_channels, .num_channels = ARRAY_SIZE(mma8452_channels), @@ -1341,6 +1344,7 @@ static const struct mma_chip_info mma_chip_info_table[] = { MMA8452_INT_FF_MT, }, [mma8453] = { + .name = "mma8453", .chip_id = MMA8453_DEVICE_ID, .channels = mma8453_channels, .num_channels = ARRAY_SIZE(mma8453_channels), @@ -1357,6 +1361,7 @@ static const struct mma_chip_info mma_chip_info_table[] = { MMA8452_INT_FF_MT, }, [mma8652] = { + .name = "mma8652", .chip_id = MMA8652_DEVICE_ID, .channels = mma8652_channels, .num_channels = ARRAY_SIZE(mma8652_channels), @@ -1366,6 +1371,7 @@ static const struct mma_chip_info mma_chip_info_table[] = { .enabled_events = MMA8452_INT_FF_MT, }, [mma8653] = { + .name = "mma8653", .chip_id = MMA8653_DEVICE_ID, .channels = mma8653_channels, .num_channels = ARRAY_SIZE(mma8653_channels), @@ -1380,6 +1386,7 @@ static const struct mma_chip_info mma_chip_info_table[] = { .enabled_events = MMA8452_INT_FF_MT, }, [fxls8471] = { + .name = "fxls8471", .chip_id = FXLS8471_DEVICE_ID, .channels = mma8451_channels, .num_channels = ARRAY_SIZE(mma8451_channels), @@ -1522,13 +1529,6 @@ static int mma8452_probe(struct i2c_client *client, struct mma8452_data *data; struct iio_dev *indio_dev; int ret; - const struct of_device_id *match; - - match = of_match_device(mma8452_dt_ids, &client->dev); - if (!match) { - dev_err(&client->dev, "unknown device model\n"); - return -ENODEV; - } indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); if (!indio_dev) @@ -1537,7 +1537,14 @@ static int mma8452_probe(struct i2c_client *client, data = iio_priv(indio_dev); data->client = client; mutex_init(&data->lock); - data->chip_info = match->data; + + data->chip_info = device_get_match_data(&client->dev); + if (!data->chip_info && id) { + data->chip_info = &mma_chip_info_table[id->driver_data]; + } else { + dev_err(&client->dev, "unknown device model\n"); + return -ENODEV; + } data->vdd_reg = devm_regulator_get(&client->dev, "vdd"); if (IS_ERR(data->vdd_reg)) @@ -1581,11 +1588,11 @@ static int mma8452_probe(struct i2c_client *client, } dev_info(&client->dev, "registering %s accelerometer; ID 0x%x\n", - match->compatible, data->chip_info->chip_id); + data->chip_info->name, data->chip_info->chip_id); i2c_set_clientdata(client, indio_dev); indio_dev->info = &mma8452_info; - indio_dev->name = id->name; + indio_dev->name = data->chip_info->name; indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->channels = data->chip_info->channels; indio_dev->num_channels = data->chip_info->num_channels; @@ -1810,7 +1817,7 @@ MODULE_DEVICE_TABLE(i2c, mma8452_id); static struct i2c_driver mma8452_driver = { .driver = { .name = "mma8452", - .of_match_table = of_match_ptr(mma8452_dt_ids), + .of_match_table = mma8452_dt_ids, .pm = &mma8452_pm_ops, }, .probe = mma8452_probe, -- cgit v1.2.3 From b863f2e3a83f990752410851ab02a36c8c740008 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Tue, 8 Feb 2022 13:43:36 +0100 Subject: iio: mma8452: Add support for the "mount-matrix" device property Add support for the standard "mount-matrix" device property to the mma8452 driver. Signed-off-by: Hans de Goede Link: https://lore.kernel.org/r/20220208124336.511884-2-hdegoede@redhat.com Signed-off-by: Jonathan Cameron --- drivers/iio/accel/mma8452.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/drivers/iio/accel/mma8452.c b/drivers/iio/accel/mma8452.c index 09c82abd2354..6ea10700d048 100644 --- a/drivers/iio/accel/mma8452.c +++ b/drivers/iio/accel/mma8452.c @@ -104,6 +104,7 @@ struct mma8452_data { struct i2c_client *client; struct mutex lock; + struct iio_mount_matrix orientation; u8 ctrl_reg1; u8 data_cfg; const struct mma_chip_info *chip_info; @@ -1190,6 +1191,20 @@ static const struct attribute_group mma8452_event_attribute_group = { .attrs = mma8452_event_attributes, }; +static const struct iio_mount_matrix * +mma8452_get_mount_matrix(const struct iio_dev *indio_dev, + const struct iio_chan_spec *chan) +{ + struct mma8452_data *data = iio_priv(indio_dev); + + return &data->orientation; +} + +static const struct iio_chan_spec_ext_info mma8452_ext_info[] = { + IIO_MOUNT_MATRIX(IIO_SHARED_BY_TYPE, mma8452_get_mount_matrix), + { } +}; + #define MMA8452_FREEFALL_CHANNEL(modifier) { \ .type = IIO_ACCEL, \ .modified = 1, \ @@ -1228,6 +1243,7 @@ static const struct attribute_group mma8452_event_attribute_group = { }, \ .event_spec = mma8452_transient_event, \ .num_event_specs = ARRAY_SIZE(mma8452_transient_event), \ + .ext_info = mma8452_ext_info, \ } #define MMA8652_CHANNEL(axis, idx, bits) { \ @@ -1249,6 +1265,7 @@ static const struct attribute_group mma8452_event_attribute_group = { }, \ .event_spec = mma8452_motion_event, \ .num_event_specs = ARRAY_SIZE(mma8452_motion_event), \ + .ext_info = mma8452_ext_info, \ } static const struct iio_chan_spec mma8451_channels[] = { @@ -1546,6 +1563,10 @@ static int mma8452_probe(struct i2c_client *client, return -ENODEV; } + ret = iio_read_mount_matrix(&client->dev, &data->orientation); + if (ret) + return ret; + data->vdd_reg = devm_regulator_get(&client->dev, "vdd"); if (IS_ERR(data->vdd_reg)) return dev_err_probe(&client->dev, PTR_ERR(data->vdd_reg), -- cgit v1.2.3 From 150ba97f1cb9eb867bba6d5e1861be6fd5580adf Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 2 Feb 2022 22:41:12 +0200 Subject: iio: trigger: stm32-timer: Make use of device properties Convert the module to be property provider agnostic and allow it to be used on non-OF platforms. Signed-off-by: Andy Shevchenko Reviewed-by: Fabrice Gasnier Link: https://lore.kernel.org/r/20220202204112.57095-1-andriy.shevchenko@linux.intel.com Signed-off-by: Jonathan Cameron --- drivers/iio/trigger/Kconfig | 2 +- drivers/iio/trigger/stm32-timer-trigger.c | 11 ++++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/iio/trigger/Kconfig b/drivers/iio/trigger/Kconfig index 8cef2f7452e8..7ecb69725b1d 100644 --- a/drivers/iio/trigger/Kconfig +++ b/drivers/iio/trigger/Kconfig @@ -38,7 +38,7 @@ config IIO_STM32_LPTIMER_TRIGGER config IIO_STM32_TIMER_TRIGGER tristate "STM32 Timer Trigger" - depends on (ARCH_STM32 && OF && MFD_STM32_TIMERS) || COMPILE_TEST + depends on (ARCH_STM32 && MFD_STM32_TIMERS) || COMPILE_TEST help Select this option to enable STM32 Timer Trigger diff --git a/drivers/iio/trigger/stm32-timer-trigger.c b/drivers/iio/trigger/stm32-timer-trigger.c index 4f9461e1412c..5049d9ecfc1a 100644 --- a/drivers/iio/trigger/stm32-timer-trigger.c +++ b/drivers/iio/trigger/stm32-timer-trigger.c @@ -11,9 +11,10 @@ #include #include #include +#include #include #include -#include +#include #define MAX_TRIGGERS 7 #define MAX_VALIDS 5 @@ -771,11 +772,11 @@ static int stm32_timer_trigger_probe(struct platform_device *pdev) unsigned int index; int ret; - if (of_property_read_u32(dev->of_node, "reg", &index)) - return -EINVAL; + ret = device_property_read_u32(dev, "reg", &index); + if (ret) + return ret; - cfg = (const struct stm32_timer_trigger_cfg *) - of_match_device(dev->driver->of_match_table, dev)->data; + cfg = device_get_match_data(dev); if (index >= ARRAY_SIZE(triggers_table) || index >= cfg->num_valids_table) -- cgit v1.2.3 From 3ee61082b4204b50391b2aa10bfc3ae3ceac09b1 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Wed, 2 Feb 2022 17:50:46 -0600 Subject: dt-bindings: vendor-prefixes: Add silan vendor prefix Hangzhou Silan Microelectronics Co., Ltd. (http://www.silan.com.cn/) is a manufacturer of ICs, including MEMS sensors. Signed-off-by: Samuel Holland Acked-by: Rob Herring Reviewed-by: Linus Walleij Link: https://lore.kernel.org/r/20220202235049.8051-2-samuel@sholland.org Signed-off-by: Jonathan Cameron --- Documentation/devicetree/bindings/vendor-prefixes.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml index 294093d45a23..b923be2c8172 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.yaml +++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml @@ -1082,6 +1082,8 @@ patternProperties: description: Silicon Image "^silabs,.*": description: Silicon Laboratories + "^silan,.*": + description: Hangzhou Silan Microelectronics Co., Ltd. "^silead,.*": description: Silead Inc. "^silergy,.*": -- cgit v1.2.3 From cb432e7dda793bd3e1821a3bacc23fe07630e80a Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Wed, 2 Feb 2022 17:50:47 -0600 Subject: dt-bindings: iio: st: Add Silan SC7A20 accelerometer This chip is not an ST part, but it appears to be register-compatible with the LIS2DH, so it can use the same binding. Signed-off-by: Samuel Holland Acked-by: Rob Herring Reviewed-by: Linus Walleij Link: https://lore.kernel.org/r/20220202235049.8051-3-samuel@sholland.org Signed-off-by: Jonathan Cameron --- Documentation/devicetree/bindings/iio/st,st-sensors.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/devicetree/bindings/iio/st,st-sensors.yaml b/Documentation/devicetree/bindings/iio/st,st-sensors.yaml index 71de5631ebae..9735a2048255 100644 --- a/Documentation/devicetree/bindings/iio/st,st-sensors.yaml +++ b/Documentation/devicetree/bindings/iio/st,st-sensors.yaml @@ -46,6 +46,9 @@ properties: - st,lsm330d-accel - st,lsm330dl-accel - st,lsm330dlc-accel + - description: Silan Accelerometers + enum: + - silan,sc7a20 - description: STMicroelectronics Gyroscopes enum: - st,l3g4200d-gyro -- cgit v1.2.3 From c7a43b089826b17e46419d93c00c0d2f4b26735f Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Wed, 2 Feb 2022 17:50:48 -0600 Subject: iio: accel: st_accel: Add support for Silan SC7A20 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This chip appears to be register-compatible with the LIS2DH. The new description is a copy of the LIS2DH's description with a different WAI value. Datasheet: http://linux-chenxing.org/silan/SC7A20-SilanMicroelectronics.pdf Datasheet: http://www.siitek.com.cn/Upfiles/down/SC7A20说明书_0.92(智能穿戴).pdf Signed-off-by: Samuel Holland Reviewed-by: Linus Walleij Link: https://lore.kernel.org/r/20220202235049.8051-4-samuel@sholland.org Signed-off-by: Jonathan Cameron --- drivers/iio/accel/st_accel.h | 2 + drivers/iio/accel/st_accel_core.c | 83 +++++++++++++++++++++++++++++++++++++++ drivers/iio/accel/st_accel_i2c.c | 5 +++ 3 files changed, 90 insertions(+) diff --git a/drivers/iio/accel/st_accel.h b/drivers/iio/accel/st_accel.h index 8750dea56fcb..00e056c21bfc 100644 --- a/drivers/iio/accel/st_accel.h +++ b/drivers/iio/accel/st_accel.h @@ -36,6 +36,7 @@ enum st_accel_type { LIS3DHH, LIS2DE12, LIS2HH12, + SC7A20, ST_ACCEL_MAX, }; @@ -61,6 +62,7 @@ enum st_accel_type { #define LIS3DE_ACCEL_DEV_NAME "lis3de" #define LIS2DE12_ACCEL_DEV_NAME "lis2de12" #define LIS2HH12_ACCEL_DEV_NAME "lis2hh12" +#define SC7A20_ACCEL_DEV_NAME "sc7a20" #ifdef CONFIG_IIO_BUFFER int st_accel_allocate_ring(struct iio_dev *indio_dev); diff --git a/drivers/iio/accel/st_accel_core.c b/drivers/iio/accel/st_accel_core.c index 31ea19d0ba71..2ada8d6fb503 100644 --- a/drivers/iio/accel/st_accel_core.c +++ b/drivers/iio/accel/st_accel_core.c @@ -1087,6 +1087,89 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = { .multi_read_bit = true, .bootime = 2, }, + { + /* + * Not an ST part. Register-compatible with the LIS2DH, even + * though the WAI value is different. + */ + .wai = 0x11, + .wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS, + .sensors_supported = { + [0] = SC7A20_ACCEL_DEV_NAME, + }, + .ch = (struct iio_chan_spec *)st_accel_12bit_channels, + .odr = { + .addr = 0x20, + .mask = 0xf0, + .odr_avl = { + { .hz = 1, .value = 0x01, }, + { .hz = 10, .value = 0x02, }, + { .hz = 25, .value = 0x03, }, + { .hz = 50, .value = 0x04, }, + { .hz = 100, .value = 0x05, }, + { .hz = 200, .value = 0x06, }, + { .hz = 400, .value = 0x07, }, + { .hz = 1600, .value = 0x08, }, + }, + }, + .pw = { + .addr = 0x20, + .mask = 0xf0, + .value_off = ST_SENSORS_DEFAULT_POWER_OFF_VALUE, + }, + .enable_axis = { + .addr = ST_SENSORS_DEFAULT_AXIS_ADDR, + .mask = ST_SENSORS_DEFAULT_AXIS_MASK, + }, + .fs = { + .addr = 0x23, + .mask = 0x30, + .fs_avl = { + [0] = { + .num = ST_ACCEL_FS_AVL_2G, + .value = 0x00, + .gain = IIO_G_TO_M_S_2(1000), + }, + [1] = { + .num = ST_ACCEL_FS_AVL_4G, + .value = 0x01, + .gain = IIO_G_TO_M_S_2(2000), + }, + [2] = { + .num = ST_ACCEL_FS_AVL_8G, + .value = 0x02, + .gain = IIO_G_TO_M_S_2(4000), + }, + [3] = { + .num = ST_ACCEL_FS_AVL_16G, + .value = 0x03, + .gain = IIO_G_TO_M_S_2(12000), + }, + }, + }, + .bdu = { + .addr = 0x23, + .mask = 0x80, + }, + .drdy_irq = { + .int1 = { + .addr = 0x22, + .mask = 0x10, + }, + .addr_ihl = 0x25, + .mask_ihl = 0x02, + .stat_drdy = { + .addr = ST_SENSORS_DEFAULT_STAT_ADDR, + .mask = 0x07, + }, + }, + .sim = { + .addr = 0x23, + .value = BIT(0), + }, + .multi_read_bit = true, + .bootime = 2, + }, }; /* Default accel DRDY is available on INT1 pin */ diff --git a/drivers/iio/accel/st_accel_i2c.c b/drivers/iio/accel/st_accel_i2c.c index c0ce78eebad9..7f5888570e87 100644 --- a/drivers/iio/accel/st_accel_i2c.c +++ b/drivers/iio/accel/st_accel_i2c.c @@ -107,6 +107,10 @@ static const struct of_device_id st_accel_of_match[] = { .compatible = "st,lis2hh12", .data = LIS2HH12_ACCEL_DEV_NAME, }, + { + .compatible = "silan,sc7a20", + .data = SC7A20_ACCEL_DEV_NAME, + }, {}, }; MODULE_DEVICE_TABLE(of, st_accel_of_match); @@ -142,6 +146,7 @@ static const struct i2c_device_id st_accel_id_table[] = { { LIS3DE_ACCEL_DEV_NAME }, { LIS2DE12_ACCEL_DEV_NAME }, { LIS2HH12_ACCEL_DEV_NAME }, + { SC7A20_ACCEL_DEV_NAME }, {}, }; MODULE_DEVICE_TABLE(i2c, st_accel_id_table); -- cgit v1.2.3 From 4205a215803f7d9a04fcd642bca22de78ea80156 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 16 Jan 2022 18:05:23 +0000 Subject: iio:accel:mma9551_core: Move exports into IIO_MMA9551 namespace In order to avoid unnecessary pollution of the global symbol namespace move the core mma9551 functions into an mma9551 specific namespace. For more information see https://lwn.net/Articles/760045/ Signed-off-by: Jonathan Cameron Link: https://lore.kernel.org/r/20220116180535.2367780-2-jic23@kernel.org --- drivers/iio/accel/mma9551.c | 1 + drivers/iio/accel/mma9551_core.c | 36 ++++++++++++++++++------------------ drivers/iio/accel/mma9553.c | 1 + 3 files changed, 20 insertions(+), 18 deletions(-) diff --git a/drivers/iio/accel/mma9551.c b/drivers/iio/accel/mma9551.c index 4c359fb05480..8709c53fa06b 100644 --- a/drivers/iio/accel/mma9551.c +++ b/drivers/iio/accel/mma9551.c @@ -622,3 +622,4 @@ MODULE_AUTHOR("Irina Tirdea "); MODULE_AUTHOR("Vlad Dogaru "); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("MMA9551L motion-sensing platform driver"); +MODULE_IMPORT_NS(IIO_MMA9551); diff --git a/drivers/iio/accel/mma9551_core.c b/drivers/iio/accel/mma9551_core.c index fbf2e2c45678..64ca7d7a9673 100644 --- a/drivers/iio/accel/mma9551_core.c +++ b/drivers/iio/accel/mma9551_core.c @@ -219,7 +219,7 @@ int mma9551_read_config_byte(struct i2c_client *client, u8 app_id, return mma9551_transfer(client, app_id, MMA9551_CMD_READ_CONFIG, reg, NULL, 0, val, 1); } -EXPORT_SYMBOL(mma9551_read_config_byte); +EXPORT_SYMBOL_NS(mma9551_read_config_byte, IIO_MMA9551); /** * mma9551_write_config_byte() - write 1 configuration byte @@ -244,7 +244,7 @@ int mma9551_write_config_byte(struct i2c_client *client, u8 app_id, return mma9551_transfer(client, app_id, MMA9551_CMD_WRITE_CONFIG, reg, &val, 1, NULL, 0); } -EXPORT_SYMBOL(mma9551_write_config_byte); +EXPORT_SYMBOL_NS(mma9551_write_config_byte, IIO_MMA9551); /** * mma9551_read_status_byte() - read 1 status byte @@ -269,7 +269,7 @@ int mma9551_read_status_byte(struct i2c_client *client, u8 app_id, return mma9551_transfer(client, app_id, MMA9551_CMD_READ_STATUS, reg, NULL, 0, val, 1); } -EXPORT_SYMBOL(mma9551_read_status_byte); +EXPORT_SYMBOL_NS(mma9551_read_status_byte, IIO_MMA9551); /** * mma9551_read_config_word() - read 1 config word @@ -300,7 +300,7 @@ int mma9551_read_config_word(struct i2c_client *client, u8 app_id, return ret; } -EXPORT_SYMBOL(mma9551_read_config_word); +EXPORT_SYMBOL_NS(mma9551_read_config_word, IIO_MMA9551); /** * mma9551_write_config_word() - write 1 config word @@ -327,7 +327,7 @@ int mma9551_write_config_word(struct i2c_client *client, u8 app_id, return mma9551_transfer(client, app_id, MMA9551_CMD_WRITE_CONFIG, reg, (u8 *)&v, 2, NULL, 0); } -EXPORT_SYMBOL(mma9551_write_config_word); +EXPORT_SYMBOL_NS(mma9551_write_config_word, IIO_MMA9551); /** * mma9551_read_status_word() - read 1 status word @@ -358,7 +358,7 @@ int mma9551_read_status_word(struct i2c_client *client, u8 app_id, return ret; } -EXPORT_SYMBOL(mma9551_read_status_word); +EXPORT_SYMBOL_NS(mma9551_read_status_word, IIO_MMA9551); /** * mma9551_read_config_words() - read multiple config words @@ -397,7 +397,7 @@ int mma9551_read_config_words(struct i2c_client *client, u8 app_id, return 0; } -EXPORT_SYMBOL(mma9551_read_config_words); +EXPORT_SYMBOL_NS(mma9551_read_config_words, IIO_MMA9551); /** * mma9551_read_status_words() - read multiple status words @@ -436,7 +436,7 @@ int mma9551_read_status_words(struct i2c_client *client, u8 app_id, return 0; } -EXPORT_SYMBOL(mma9551_read_status_words); +EXPORT_SYMBOL_NS(mma9551_read_status_words, IIO_MMA9551); /** * mma9551_write_config_words() - write multiple config words @@ -471,7 +471,7 @@ int mma9551_write_config_words(struct i2c_client *client, u8 app_id, return mma9551_transfer(client, app_id, MMA9551_CMD_WRITE_CONFIG, reg, (u8 *)be_buf, len * sizeof(u16), NULL, 0); } -EXPORT_SYMBOL(mma9551_write_config_words); +EXPORT_SYMBOL_NS(mma9551_write_config_words, IIO_MMA9551); /** * mma9551_update_config_bits() - update bits in register @@ -507,7 +507,7 @@ int mma9551_update_config_bits(struct i2c_client *client, u8 app_id, return mma9551_write_config_byte(client, app_id, reg, tmp); } -EXPORT_SYMBOL(mma9551_update_config_bits); +EXPORT_SYMBOL_NS(mma9551_update_config_bits, IIO_MMA9551); /** * mma9551_gpio_config() - configure gpio @@ -586,7 +586,7 @@ int mma9551_gpio_config(struct i2c_client *client, enum mma9551_gpio_pin pin, return ret; } -EXPORT_SYMBOL(mma9551_gpio_config); +EXPORT_SYMBOL_NS(mma9551_gpio_config, IIO_MMA9551); /** * mma9551_read_version() - read device version information @@ -616,7 +616,7 @@ int mma9551_read_version(struct i2c_client *client) return 0; } -EXPORT_SYMBOL(mma9551_read_version); +EXPORT_SYMBOL_NS(mma9551_read_version, IIO_MMA9551); /** * mma9551_set_device_state() - sets HW power mode @@ -646,7 +646,7 @@ int mma9551_set_device_state(struct i2c_client *client, bool enable) MMA9551_SLEEP_CFG_FLEEN : MMA9551_SLEEP_CFG_SNCEN); } -EXPORT_SYMBOL(mma9551_set_device_state); +EXPORT_SYMBOL_NS(mma9551_set_device_state, IIO_MMA9551); /** * mma9551_set_power_state() - sets runtime PM state @@ -680,7 +680,7 @@ int mma9551_set_power_state(struct i2c_client *client, bool on) return 0; } -EXPORT_SYMBOL(mma9551_set_power_state); +EXPORT_SYMBOL_NS(mma9551_set_power_state, IIO_MMA9551); /** * mma9551_sleep() - sleep @@ -699,7 +699,7 @@ void mma9551_sleep(int freq) else msleep_interruptible(sleep_val); } -EXPORT_SYMBOL(mma9551_sleep); +EXPORT_SYMBOL_NS(mma9551_sleep, IIO_MMA9551); /** * mma9551_read_accel_chan() - read accelerometer channel @@ -755,7 +755,7 @@ out_poweroff: mma9551_set_power_state(client, false); return ret; } -EXPORT_SYMBOL(mma9551_read_accel_chan); +EXPORT_SYMBOL_NS(mma9551_read_accel_chan, IIO_MMA9551); /** * mma9551_read_accel_scale() - read accelerometer scale @@ -773,7 +773,7 @@ int mma9551_read_accel_scale(int *val, int *val2) return IIO_VAL_INT_PLUS_MICRO; } -EXPORT_SYMBOL(mma9551_read_accel_scale); +EXPORT_SYMBOL_NS(mma9551_read_accel_scale, IIO_MMA9551); /** * mma9551_app_reset() - reset application @@ -792,7 +792,7 @@ int mma9551_app_reset(struct i2c_client *client, u32 app_mask) MMA9551_RSC_OFFSET(app_mask), MMA9551_RSC_VAL(app_mask)); } -EXPORT_SYMBOL(mma9551_app_reset); +EXPORT_SYMBOL_NS(mma9551_app_reset, IIO_MMA9551); MODULE_AUTHOR("Irina Tirdea "); MODULE_AUTHOR("Vlad Dogaru "); diff --git a/drivers/iio/accel/mma9553.c b/drivers/iio/accel/mma9553.c index 0570ab1cc064..a836e73c3242 100644 --- a/drivers/iio/accel/mma9553.c +++ b/drivers/iio/accel/mma9553.c @@ -1260,3 +1260,4 @@ module_i2c_driver(mma9553_driver); MODULE_AUTHOR("Irina Tirdea "); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("MMA9553L pedometer platform driver"); +MODULE_IMPORT_NS(IIO_MMA9551); -- cgit v1.2.3 From eca7b25bee064575eb80a025cdee66eb2d65174d Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 16 Jan 2022 18:05:24 +0000 Subject: iio:accel:mma7455_core: Move exports into IIO_MMA7455 namespace MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In order to avoid unnecessary pollution of the global symbol namespace move the core mma7455 functions into an mma7455 specific namespace and import that into the two bus modules. For more information see https://lwn.net/Articles/760045/ Signed-off-by: Jonathan Cameron Cc: Uwe Kleine-König Link: https://lore.kernel.org/r/20220116180535.2367780-3-jic23@kernel.org --- drivers/iio/accel/mma7455_core.c | 6 +++--- drivers/iio/accel/mma7455_i2c.c | 1 + drivers/iio/accel/mma7455_spi.c | 1 + 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/iio/accel/mma7455_core.c b/drivers/iio/accel/mma7455_core.c index e6739ba74edf..a34195b3215d 100644 --- a/drivers/iio/accel/mma7455_core.c +++ b/drivers/iio/accel/mma7455_core.c @@ -238,7 +238,7 @@ const struct regmap_config mma7455_core_regmap = { .val_bits = 8, .max_register = MMA7455_REG_TW, }; -EXPORT_SYMBOL_GPL(mma7455_core_regmap); +EXPORT_SYMBOL_NS_GPL(mma7455_core_regmap, IIO_MMA7455); int mma7455_core_probe(struct device *dev, struct regmap *regmap, const char *name) @@ -293,7 +293,7 @@ int mma7455_core_probe(struct device *dev, struct regmap *regmap, return 0; } -EXPORT_SYMBOL_GPL(mma7455_core_probe); +EXPORT_SYMBOL_NS_GPL(mma7455_core_probe, IIO_MMA7455); void mma7455_core_remove(struct device *dev) { @@ -306,7 +306,7 @@ void mma7455_core_remove(struct device *dev) regmap_write(mma7455->regmap, MMA7455_REG_MCTL, MMA7455_MCTL_MODE_STANDBY); } -EXPORT_SYMBOL_GPL(mma7455_core_remove); +EXPORT_SYMBOL_NS_GPL(mma7455_core_remove, IIO_MMA7455); MODULE_AUTHOR("Joachim Eastwood "); MODULE_DESCRIPTION("Freescale MMA7455L core accelerometer driver"); diff --git a/drivers/iio/accel/mma7455_i2c.c b/drivers/iio/accel/mma7455_i2c.c index 8a5256516f9f..a3b84e8a3ea8 100644 --- a/drivers/iio/accel/mma7455_i2c.c +++ b/drivers/iio/accel/mma7455_i2c.c @@ -61,3 +61,4 @@ module_i2c_driver(mma7455_i2c_driver); MODULE_AUTHOR("Joachim Eastwood "); MODULE_DESCRIPTION("Freescale MMA7455L I2C accelerometer driver"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS(IIO_MMA7455); diff --git a/drivers/iio/accel/mma7455_spi.c b/drivers/iio/accel/mma7455_spi.c index ecf690692dcc..564a0e12cebe 100644 --- a/drivers/iio/accel/mma7455_spi.c +++ b/drivers/iio/accel/mma7455_spi.c @@ -49,3 +49,4 @@ module_spi_driver(mma7455_spi_driver); MODULE_AUTHOR("Joachim Eastwood "); MODULE_DESCRIPTION("Freescale MMA7455L SPI accelerometer driver"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS(IIO_MMA7455); -- cgit v1.2.3 From c24ef124e9448ecdfea83aecf5d53364ef88a781 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 16 Jan 2022 18:05:25 +0000 Subject: iio:accel:kxsd9: Move exports into IIO_KDSD9 namespace In order to avoid unnecessary pollution of the global symbol namespace move the core kxsd9 functions into a kxsd9 specific namespace and import that into the two bus modules. For more information see https://lwn.net/Articles/760045/ Signed-off-by: Jonathan Cameron Link: https://lore.kernel.org/r/20220116180535.2367780-4-jic23@kernel.org --- drivers/iio/accel/kxsd9-i2c.c | 1 + drivers/iio/accel/kxsd9-spi.c | 1 + drivers/iio/accel/kxsd9.c | 6 +++--- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/iio/accel/kxsd9-i2c.c b/drivers/iio/accel/kxsd9-i2c.c index 274b41a6e603..c8dc52f11037 100644 --- a/drivers/iio/accel/kxsd9-i2c.c +++ b/drivers/iio/accel/kxsd9-i2c.c @@ -65,3 +65,4 @@ module_i2c_driver(kxsd9_i2c_driver); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("KXSD9 accelerometer I2C interface"); +MODULE_IMPORT_NS(IIO_KXSD9); diff --git a/drivers/iio/accel/kxsd9-spi.c b/drivers/iio/accel/kxsd9-spi.c index 441e6b764281..a06a3a273de7 100644 --- a/drivers/iio/accel/kxsd9-spi.c +++ b/drivers/iio/accel/kxsd9-spi.c @@ -66,3 +66,4 @@ module_spi_driver(kxsd9_spi_driver); MODULE_AUTHOR("Jonathan Cameron "); MODULE_DESCRIPTION("Kionix KXSD9 SPI driver"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS(IIO_KXSD9); diff --git a/drivers/iio/accel/kxsd9.c b/drivers/iio/accel/kxsd9.c index 552eba5e8b4f..3975860331a6 100644 --- a/drivers/iio/accel/kxsd9.c +++ b/drivers/iio/accel/kxsd9.c @@ -476,7 +476,7 @@ err_power_down: return ret; } -EXPORT_SYMBOL(kxsd9_common_probe); +EXPORT_SYMBOL_NS(kxsd9_common_probe, IIO_KXSD9); void kxsd9_common_remove(struct device *dev) { @@ -490,7 +490,7 @@ void kxsd9_common_remove(struct device *dev) pm_runtime_disable(dev); kxsd9_power_down(st); } -EXPORT_SYMBOL(kxsd9_common_remove); +EXPORT_SYMBOL_NS(kxsd9_common_remove, IIO_KXSD9); #ifdef CONFIG_PM static int kxsd9_runtime_suspend(struct device *dev) @@ -516,7 +516,7 @@ const struct dev_pm_ops kxsd9_dev_pm_ops = { SET_RUNTIME_PM_OPS(kxsd9_runtime_suspend, kxsd9_runtime_resume, NULL) }; -EXPORT_SYMBOL(kxsd9_dev_pm_ops); +EXPORT_SYMBOL_NS(kxsd9_dev_pm_ops, IIO_KXSD9); MODULE_AUTHOR("Jonathan Cameron "); MODULE_DESCRIPTION("Kionix KXSD9 driver"); -- cgit v1.2.3 From f9c02c94858dd8974f82060a3f1292f4132848b0 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 16 Jan 2022 18:05:26 +0000 Subject: iio:accel:bma400: Move exports into IIO_BMA400 namespace In order to avoid unnecessary pollution of the global symbol namespace move the core bma400 functions into a bma400 specific namespace and import that into the two bus modules. Signed-off-by: Jonathan Cameron Cc: Linus Walleij Link: https://lore.kernel.org/r/20220116180535.2367780-5-jic23@kernel.org --- drivers/iio/accel/bma400_core.c | 6 +++--- drivers/iio/accel/bma400_i2c.c | 1 + drivers/iio/accel/bma400_spi.c | 1 + 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/iio/accel/bma400_core.c b/drivers/iio/accel/bma400_core.c index fd2647b728d3..043002fe6f63 100644 --- a/drivers/iio/accel/bma400_core.c +++ b/drivers/iio/accel/bma400_core.c @@ -136,7 +136,7 @@ const struct regmap_config bma400_regmap_config = { .writeable_reg = bma400_is_writable_reg, .volatile_reg = bma400_is_volatile_reg, }; -EXPORT_SYMBOL(bma400_regmap_config); +EXPORT_SYMBOL_NS(bma400_regmap_config, IIO_BMA400); static const struct iio_mount_matrix * bma400_accel_get_mount_matrix(const struct iio_dev *indio_dev, @@ -826,7 +826,7 @@ int bma400_probe(struct device *dev, struct regmap *regmap, const char *name) return iio_device_register(indio_dev); } -EXPORT_SYMBOL(bma400_probe); +EXPORT_SYMBOL_NS(bma400_probe, IIO_BMA400); void bma400_remove(struct device *dev) { @@ -846,7 +846,7 @@ void bma400_remove(struct device *dev) iio_device_unregister(indio_dev); } -EXPORT_SYMBOL(bma400_remove); +EXPORT_SYMBOL_NS(bma400_remove, IIO_BMA400); MODULE_AUTHOR("Dan Robertson "); MODULE_DESCRIPTION("Bosch BMA400 triaxial acceleration sensor core"); diff --git a/drivers/iio/accel/bma400_i2c.c b/drivers/iio/accel/bma400_i2c.c index f50df5310beb..da104ffd3fe0 100644 --- a/drivers/iio/accel/bma400_i2c.c +++ b/drivers/iio/accel/bma400_i2c.c @@ -61,3 +61,4 @@ module_i2c_driver(bma400_i2c_driver); MODULE_AUTHOR("Dan Robertson "); MODULE_DESCRIPTION("Bosch BMA400 triaxial acceleration sensor (I2C)"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(IIO_BMA400); diff --git a/drivers/iio/accel/bma400_spi.c b/drivers/iio/accel/bma400_spi.c index 9f622e37477b..23f3a8ab30bd 100644 --- a/drivers/iio/accel/bma400_spi.c +++ b/drivers/iio/accel/bma400_spi.c @@ -120,3 +120,4 @@ module_spi_driver(bma400_spi_driver); MODULE_AUTHOR("Dan Robertson "); MODULE_DESCRIPTION("Bosch BMA400 triaxial acceleration sensor (SPI)"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(IIO_BMA400); -- cgit v1.2.3 From fa4df5a9036e1a68b18a01c714c69961040d2f9b Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 16 Jan 2022 18:05:27 +0000 Subject: iio:accel:adxl313: Move exports into IIO_ADXL313 namespace In order to avoid unnecessary pollution of the global symbol namespace move the driver core exports into their own namespace and import that into the two bus modules. Signed-off-by: Jonathan Cameron Cc: Lucas Stankus Link: https://lore.kernel.org/r/20220116180535.2367780-6-jic23@kernel.org --- drivers/iio/accel/adxl313_core.c | 6 +++--- drivers/iio/accel/adxl313_i2c.c | 1 + drivers/iio/accel/adxl313_spi.c | 1 + 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/iio/accel/adxl313_core.c b/drivers/iio/accel/adxl313_core.c index 0d243341f1a7..9e4193e64765 100644 --- a/drivers/iio/accel/adxl313_core.c +++ b/drivers/iio/accel/adxl313_core.c @@ -26,7 +26,7 @@ const struct regmap_access_table adxl313_readable_regs_table = { .yes_ranges = adxl313_readable_reg_range, .n_yes_ranges = ARRAY_SIZE(adxl313_readable_reg_range), }; -EXPORT_SYMBOL_GPL(adxl313_readable_regs_table); +EXPORT_SYMBOL_NS_GPL(adxl313_readable_regs_table, IIO_ADXL313); static const struct regmap_range adxl313_writable_reg_range[] = { regmap_reg_range(ADXL313_REG_SOFT_RESET, ADXL313_REG_SOFT_RESET), @@ -41,7 +41,7 @@ const struct regmap_access_table adxl313_writable_regs_table = { .yes_ranges = adxl313_writable_reg_range, .n_yes_ranges = ARRAY_SIZE(adxl313_writable_reg_range), }; -EXPORT_SYMBOL_GPL(adxl313_writable_regs_table); +EXPORT_SYMBOL_NS_GPL(adxl313_writable_regs_table, IIO_ADXL313); struct adxl313_data { struct regmap *regmap; @@ -325,7 +325,7 @@ int adxl313_core_probe(struct device *dev, return devm_iio_device_register(dev, indio_dev); } -EXPORT_SYMBOL_GPL(adxl313_core_probe); +EXPORT_SYMBOL_NS_GPL(adxl313_core_probe, IIO_ADXL313); MODULE_AUTHOR("Lucas Stankus "); MODULE_DESCRIPTION("ADXL313 3-Axis Digital Accelerometer core driver"); diff --git a/drivers/iio/accel/adxl313_i2c.c b/drivers/iio/accel/adxl313_i2c.c index 82e9fb2db1e6..c329765dbf60 100644 --- a/drivers/iio/accel/adxl313_i2c.c +++ b/drivers/iio/accel/adxl313_i2c.c @@ -64,3 +64,4 @@ module_i2c_driver(adxl313_i2c_driver); MODULE_AUTHOR("Lucas Stankus "); MODULE_DESCRIPTION("ADXL313 3-Axis Digital Accelerometer I2C driver"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS(IIO_ADXL313); diff --git a/drivers/iio/accel/adxl313_spi.c b/drivers/iio/accel/adxl313_spi.c index a6162f36ef52..a3c6d553462d 100644 --- a/drivers/iio/accel/adxl313_spi.c +++ b/drivers/iio/accel/adxl313_spi.c @@ -90,3 +90,4 @@ module_spi_driver(adxl313_spi_driver); MODULE_AUTHOR("Lucas Stankus "); MODULE_DESCRIPTION("ADXL313 3-Axis Digital Accelerometer SPI driver"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS(IIO_ADXL313); -- cgit v1.2.3 From 0a18114d3ffd0ce0dc3a356d0c2fc7b5b8afc0ae Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 16 Jan 2022 18:05:28 +0000 Subject: iio:accel:adxl345: Move exports into IIO_ADXL345 namespace To avoid unnecessary pollution of the global symbol namespace move the driver core exports into their own namespace and import that into the two bus modules. Signed-off-by: Jonathan Cameron Link: https://lore.kernel.org/r/20220116180535.2367780-7-jic23@kernel.org --- drivers/iio/accel/adxl345_core.c | 2 +- drivers/iio/accel/adxl345_i2c.c | 1 + drivers/iio/accel/adxl345_spi.c | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/iio/accel/adxl345_core.c b/drivers/iio/accel/adxl345_core.c index 4b275051ef61..ef2240e356e0 100644 --- a/drivers/iio/accel/adxl345_core.c +++ b/drivers/iio/accel/adxl345_core.c @@ -270,7 +270,7 @@ int adxl345_core_probe(struct device *dev, struct regmap *regmap, return devm_iio_device_register(dev, indio_dev); } -EXPORT_SYMBOL_GPL(adxl345_core_probe); +EXPORT_SYMBOL_NS_GPL(adxl345_core_probe, IIO_ADXL345); MODULE_AUTHOR("Eva Rachel Retuya "); MODULE_DESCRIPTION("ADXL345 3-Axis Digital Accelerometer core driver"); diff --git a/drivers/iio/accel/adxl345_i2c.c b/drivers/iio/accel/adxl345_i2c.c index a431cba216e6..7bc8324c4f07 100644 --- a/drivers/iio/accel/adxl345_i2c.c +++ b/drivers/iio/accel/adxl345_i2c.c @@ -68,3 +68,4 @@ module_i2c_driver(adxl345_i2c_driver); MODULE_AUTHOR("Eva Rachel Retuya "); MODULE_DESCRIPTION("ADXL345 3-Axis Digital Accelerometer I2C driver"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS(IIO_ADXL345); diff --git a/drivers/iio/accel/adxl345_spi.c b/drivers/iio/accel/adxl345_spi.c index ea559ac2e87d..c752562c5d3b 100644 --- a/drivers/iio/accel/adxl345_spi.c +++ b/drivers/iio/accel/adxl345_spi.c @@ -72,3 +72,4 @@ module_spi_driver(adxl345_spi_driver); MODULE_AUTHOR("Eva Rachel Retuya "); MODULE_DESCRIPTION("ADXL345 3-Axis Digital Accelerometer SPI driver"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS(IIO_ADXL345); -- cgit v1.2.3 From fe2fe330e0d1efdf3b366f26deaf92fac7c28340 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 16 Jan 2022 18:05:29 +0000 Subject: iio:accel:adxl355: Move exports into IIO_ADXL355 namespace To avoid unnecessary pollution of the global symbol namespace move the driver core exports into their own namespace and import that into the two bus modules. For more info see https://lwn.net/Articles/760045/ Signed-off-by: Jonathan Cameron Cc: Puranjay Mohan Link: https://lore.kernel.org/r/20220116180535.2367780-8-jic23@kernel.org --- drivers/iio/accel/adxl355_core.c | 6 +++--- drivers/iio/accel/adxl355_i2c.c | 1 + drivers/iio/accel/adxl355_spi.c | 1 + 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/iio/accel/adxl355_core.c b/drivers/iio/accel/adxl355_core.c index 7023de888835..e9c10c8c32f0 100644 --- a/drivers/iio/accel/adxl355_core.c +++ b/drivers/iio/accel/adxl355_core.c @@ -71,7 +71,7 @@ const struct regmap_access_table adxl355_readable_regs_tbl = { .yes_ranges = adxl355_read_reg_range, .n_yes_ranges = ARRAY_SIZE(adxl355_read_reg_range), }; -EXPORT_SYMBOL_GPL(adxl355_readable_regs_tbl); +EXPORT_SYMBOL_NS_GPL(adxl355_readable_regs_tbl, IIO_ADXL355); static const struct regmap_range adxl355_write_reg_range[] = { regmap_reg_range(ADXL355_OFFSET_X_H_REG, ADXL355_RESET_REG), @@ -81,7 +81,7 @@ const struct regmap_access_table adxl355_writeable_regs_tbl = { .yes_ranges = adxl355_write_reg_range, .n_yes_ranges = ARRAY_SIZE(adxl355_write_reg_range), }; -EXPORT_SYMBOL_GPL(adxl355_writeable_regs_tbl); +EXPORT_SYMBOL_NS_GPL(adxl355_writeable_regs_tbl, IIO_ADXL355); enum adxl355_op_mode { ADXL355_MEASUREMENT, @@ -757,7 +757,7 @@ int adxl355_core_probe(struct device *dev, struct regmap *regmap, return devm_iio_device_register(dev, indio_dev); } -EXPORT_SYMBOL_GPL(adxl355_core_probe); +EXPORT_SYMBOL_NS_GPL(adxl355_core_probe, IIO_ADXL355); MODULE_AUTHOR("Puranjay Mohan "); MODULE_DESCRIPTION("ADXL355 3-Axis Digital Accelerometer core driver"); diff --git a/drivers/iio/accel/adxl355_i2c.c b/drivers/iio/accel/adxl355_i2c.c index 5a987bda9060..f67d57921c81 100644 --- a/drivers/iio/accel/adxl355_i2c.c +++ b/drivers/iio/accel/adxl355_i2c.c @@ -60,3 +60,4 @@ module_i2c_driver(adxl355_i2c_driver); MODULE_AUTHOR("Puranjay Mohan "); MODULE_DESCRIPTION("ADXL355 3-Axis Digital Accelerometer I2C driver"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS(IIO_ADXL355); diff --git a/drivers/iio/accel/adxl355_spi.c b/drivers/iio/accel/adxl355_spi.c index fb225aeb56e3..5fe986ae03f6 100644 --- a/drivers/iio/accel/adxl355_spi.c +++ b/drivers/iio/accel/adxl355_spi.c @@ -63,3 +63,4 @@ module_spi_driver(adxl355_spi_driver); MODULE_AUTHOR("Puranjay Mohan "); MODULE_DESCRIPTION("ADXL355 3-Axis Digital Accelerometer SPI driver"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS(IIO_ADXL355); -- cgit v1.2.3 From 489c75af0f4da1e83ba08895bdda533663faf592 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 16 Jan 2022 18:05:30 +0000 Subject: iio:accel:adxl372: Move exports into IIO_ADXL372 namespace To avoid unnecessary pollution of the global symbol namespace move the driver core exports into their own namespace and import that into the two bus modules. For more info see https://lwn.net/Articles/760045/ Signed-off-by: Jonathan Cameron Link: https://lore.kernel.org/r/20220116180535.2367780-9-jic23@kernel.org --- drivers/iio/accel/adxl372.c | 4 ++-- drivers/iio/accel/adxl372_i2c.c | 1 + drivers/iio/accel/adxl372_spi.c | 1 + 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/iio/accel/adxl372.c b/drivers/iio/accel/adxl372.c index 758952584f8c..e3ecbaee61f7 100644 --- a/drivers/iio/accel/adxl372.c +++ b/drivers/iio/accel/adxl372.c @@ -1176,7 +1176,7 @@ bool adxl372_readable_noinc_reg(struct device *dev, unsigned int reg) { return (reg == ADXL372_FIFO_DATA); } -EXPORT_SYMBOL_GPL(adxl372_readable_noinc_reg); +EXPORT_SYMBOL_NS_GPL(adxl372_readable_noinc_reg, IIO_ADXL372); int adxl372_probe(struct device *dev, struct regmap *regmap, int irq, const char *name) @@ -1260,7 +1260,7 @@ int adxl372_probe(struct device *dev, struct regmap *regmap, return devm_iio_device_register(dev, indio_dev); } -EXPORT_SYMBOL_GPL(adxl372_probe); +EXPORT_SYMBOL_NS_GPL(adxl372_probe, IIO_ADXL372); MODULE_AUTHOR("Stefan Popa "); MODULE_DESCRIPTION("Analog Devices ADXL372 3-axis accelerometer driver"); diff --git a/drivers/iio/accel/adxl372_i2c.c b/drivers/iio/accel/adxl372_i2c.c index 9a07ab3d151a..4efb70a5fe40 100644 --- a/drivers/iio/accel/adxl372_i2c.c +++ b/drivers/iio/accel/adxl372_i2c.c @@ -67,3 +67,4 @@ module_i2c_driver(adxl372_i2c_driver); MODULE_AUTHOR("Stefan Popa "); MODULE_DESCRIPTION("Analog Devices ADXL372 3-axis accelerometer I2C driver"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(IIO_ADXL372); diff --git a/drivers/iio/accel/adxl372_spi.c b/drivers/iio/accel/adxl372_spi.c index 1f1352fee99a..2bd267a22f29 100644 --- a/drivers/iio/accel/adxl372_spi.c +++ b/drivers/iio/accel/adxl372_spi.c @@ -59,3 +59,4 @@ module_spi_driver(adxl372_spi_driver); MODULE_AUTHOR("Stefan Popa "); MODULE_DESCRIPTION("Analog Devices ADXL372 3-axis accelerometer SPI driver"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(IIO_ADXL372); -- cgit v1.2.3 From 26b74d852f6c53868d88a067f497da7ebbdaae9f Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 16 Jan 2022 18:05:31 +0000 Subject: iio:accel:bmc150: Move exports into IIO_BMC150 namespace To avoid unnecessary pollution of the global symbol namespace move the driver core exports into their own namespace and import that into the two bus modules. For more info see https://lwn.net/Articles/760045/ Acked-by: Srinivas Pandruvada Signed-off-by: Jonathan Cameron Link: https://lore.kernel.org/r/20220116180535.2367780-10-jic23@kernel.org --- drivers/iio/accel/bmc150-accel-core.c | 8 ++++---- drivers/iio/accel/bmc150-accel-i2c.c | 1 + drivers/iio/accel/bmc150-accel-spi.c | 1 + 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/iio/accel/bmc150-accel-core.c b/drivers/iio/accel/bmc150-accel-core.c index e6081dd0a880..a5e0214b7be6 100644 --- a/drivers/iio/accel/bmc150-accel-core.c +++ b/drivers/iio/accel/bmc150-accel-core.c @@ -203,7 +203,7 @@ const struct regmap_config bmc150_regmap_conf = { .val_bits = 8, .max_register = 0x3f, }; -EXPORT_SYMBOL_GPL(bmc150_regmap_conf); +EXPORT_SYMBOL_NS_GPL(bmc150_regmap_conf, IIO_BMC150); static int bmc150_accel_set_mode(struct bmc150_accel_data *data, enum bmc150_power_modes mode, @@ -1798,7 +1798,7 @@ err_disable_regulators: return ret; } -EXPORT_SYMBOL_GPL(bmc150_accel_core_probe); +EXPORT_SYMBOL_NS_GPL(bmc150_accel_core_probe, IIO_BMC150); void bmc150_accel_core_remove(struct device *dev) { @@ -1821,7 +1821,7 @@ void bmc150_accel_core_remove(struct device *dev) regulator_bulk_disable(ARRAY_SIZE(data->regulators), data->regulators); } -EXPORT_SYMBOL_GPL(bmc150_accel_core_remove); +EXPORT_SYMBOL_NS_GPL(bmc150_accel_core_remove, IIO_BMC150); #ifdef CONFIG_PM_SLEEP static int bmc150_accel_suspend(struct device *dev) @@ -1896,7 +1896,7 @@ const struct dev_pm_ops bmc150_accel_pm_ops = { SET_RUNTIME_PM_OPS(bmc150_accel_runtime_suspend, bmc150_accel_runtime_resume, NULL) }; -EXPORT_SYMBOL_GPL(bmc150_accel_pm_ops); +EXPORT_SYMBOL_NS_GPL(bmc150_accel_pm_ops, IIO_BMC150); MODULE_AUTHOR("Srinivas Pandruvada "); MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/accel/bmc150-accel-i2c.c b/drivers/iio/accel/bmc150-accel-i2c.c index 9e52df9a8f07..dff4d7dd101c 100644 --- a/drivers/iio/accel/bmc150-accel-i2c.c +++ b/drivers/iio/accel/bmc150-accel-i2c.c @@ -280,3 +280,4 @@ module_i2c_driver(bmc150_accel_driver); MODULE_AUTHOR("Srinivas Pandruvada "); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("BMC150 I2C accelerometer driver"); +MODULE_IMPORT_NS(IIO_BMC150); diff --git a/drivers/iio/accel/bmc150-accel-spi.c b/drivers/iio/accel/bmc150-accel-spi.c index 11559567cb39..000632c52800 100644 --- a/drivers/iio/accel/bmc150-accel-spi.c +++ b/drivers/iio/accel/bmc150-accel-spi.c @@ -84,3 +84,4 @@ module_spi_driver(bmc150_accel_driver); MODULE_AUTHOR("Markus Pargmann "); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("BMC150 SPI accelerometer driver"); +MODULE_IMPORT_NS(IIO_BMC150); -- cgit v1.2.3 From 3bd072d118765f2fcbee3bfef19d2b7960ab0d1d Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 16 Jan 2022 18:05:32 +0000 Subject: iio:accel:bmi088: Move exports into IIO_BMI088 namespace To avoid unnecessary pollution of the global symbol namespace move the driver core exports into their own namespace and import that into the two bus modules. For more info see https://lwn.net/Articles/760045/ Signed-off-by: Jonathan Cameron Cc: Mike Looijmans Link: https://lore.kernel.org/r/20220116180535.2367780-11-jic23@kernel.org --- drivers/iio/accel/bmi088-accel-core.c | 8 ++++---- drivers/iio/accel/bmi088-accel-spi.c | 1 + 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/iio/accel/bmi088-accel-core.c b/drivers/iio/accel/bmi088-accel-core.c index d74465214feb..8b2728bbcade 100644 --- a/drivers/iio/accel/bmi088-accel-core.c +++ b/drivers/iio/accel/bmi088-accel-core.c @@ -146,7 +146,7 @@ const struct regmap_config bmi088_regmap_conf = { .volatile_table = &bmi088_volatile_table, .cache_type = REGCACHE_RBTREE, }; -EXPORT_SYMBOL_GPL(bmi088_regmap_conf); +EXPORT_SYMBOL_NS_GPL(bmi088_regmap_conf, IIO_BMI088); static int bmi088_accel_power_up(struct bmi088_accel_data *data) { @@ -533,7 +533,7 @@ int bmi088_accel_core_probe(struct device *dev, struct regmap *regmap, return ret; } -EXPORT_SYMBOL_GPL(bmi088_accel_core_probe); +EXPORT_SYMBOL_NS_GPL(bmi088_accel_core_probe, IIO_BMI088); void bmi088_accel_core_remove(struct device *dev) @@ -547,7 +547,7 @@ void bmi088_accel_core_remove(struct device *dev) pm_runtime_set_suspended(dev); bmi088_accel_power_down(data); } -EXPORT_SYMBOL_GPL(bmi088_accel_core_remove); +EXPORT_SYMBOL_NS_GPL(bmi088_accel_core_remove, IIO_BMI088); static int __maybe_unused bmi088_accel_runtime_suspend(struct device *dev) { @@ -571,7 +571,7 @@ const struct dev_pm_ops bmi088_accel_pm_ops = { SET_RUNTIME_PM_OPS(bmi088_accel_runtime_suspend, bmi088_accel_runtime_resume, NULL) }; -EXPORT_SYMBOL_GPL(bmi088_accel_pm_ops); +EXPORT_SYMBOL_NS_GPL(bmi088_accel_pm_ops, IIO_BMI088); MODULE_AUTHOR("Niek van Agt "); MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/accel/bmi088-accel-spi.c b/drivers/iio/accel/bmi088-accel-spi.c index 758ad2f12896..961e87a927c4 100644 --- a/drivers/iio/accel/bmi088-accel-spi.c +++ b/drivers/iio/accel/bmi088-accel-spi.c @@ -83,3 +83,4 @@ module_spi_driver(bmi088_accel_driver); MODULE_AUTHOR("Niek van Agt "); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("BMI088 accelerometer driver (SPI)"); +MODULE_IMPORT_NS(IIO_BMI088); -- cgit v1.2.3 From fbbd286c16a6c3b166e72af3ce17fc4037de24fa Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 16 Jan 2022 18:05:33 +0000 Subject: iio:accel:fxl8962af: Move exports into IIO_FXL8962AF namespace To avoid unnecessary pollution of the global symbol namespace move the driver core exports into their own namespace and import that into the two bus modules. For more info see https://lwn.net/Articles/760045/ Signed-off-by: Jonathan Cameron Cc: Sean Nyekjaer Reviewed-by: Sean Nyekjaer Link: https://lore.kernel.org/r/20220116180535.2367780-12-jic23@kernel.org --- drivers/iio/accel/fxls8962af-core.c | 6 +++--- drivers/iio/accel/fxls8962af-i2c.c | 1 + drivers/iio/accel/fxls8962af-spi.c | 1 + 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/iio/accel/fxls8962af-core.c b/drivers/iio/accel/fxls8962af-core.c index 32989d91b982..8e763dbf096b 100644 --- a/drivers/iio/accel/fxls8962af-core.c +++ b/drivers/iio/accel/fxls8962af-core.c @@ -178,7 +178,7 @@ const struct regmap_config fxls8962af_regmap_conf = { .val_bits = 8, .max_register = FXLS8962AF_MAX_REG, }; -EXPORT_SYMBOL_GPL(fxls8962af_regmap_conf); +EXPORT_SYMBOL_NS_GPL(fxls8962af_regmap_conf, IIO_FXLS8962AF); enum { fxls8962af_idx_x, @@ -1232,7 +1232,7 @@ int fxls8962af_core_probe(struct device *dev, struct regmap *regmap, int irq) return devm_iio_device_register(dev, indio_dev); } -EXPORT_SYMBOL_GPL(fxls8962af_core_probe); +EXPORT_SYMBOL_NS_GPL(fxls8962af_core_probe, IIO_FXLS8962AF); static int __maybe_unused fxls8962af_runtime_suspend(struct device *dev) { @@ -1298,7 +1298,7 @@ const struct dev_pm_ops fxls8962af_pm_ops = { SET_RUNTIME_PM_OPS(fxls8962af_runtime_suspend, fxls8962af_runtime_resume, NULL) }; -EXPORT_SYMBOL_GPL(fxls8962af_pm_ops); +EXPORT_SYMBOL_NS_GPL(fxls8962af_pm_ops, IIO_FXLS8962AF); MODULE_AUTHOR("Sean Nyekjaer "); MODULE_DESCRIPTION("NXP FXLS8962AF/FXLS8964AF accelerometer driver"); diff --git a/drivers/iio/accel/fxls8962af-i2c.c b/drivers/iio/accel/fxls8962af-i2c.c index cfb004b20455..7e0ecd3bf0d9 100644 --- a/drivers/iio/accel/fxls8962af-i2c.c +++ b/drivers/iio/accel/fxls8962af-i2c.c @@ -55,3 +55,4 @@ module_i2c_driver(fxls8962af_driver); MODULE_AUTHOR("Sean Nyekjaer "); MODULE_DESCRIPTION("NXP FXLS8962AF/FXLS8964AF accelerometer i2c driver"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS(IIO_FXLS8962AF); diff --git a/drivers/iio/accel/fxls8962af-spi.c b/drivers/iio/accel/fxls8962af-spi.c index 57108d3d480b..0357d54d47cc 100644 --- a/drivers/iio/accel/fxls8962af-spi.c +++ b/drivers/iio/accel/fxls8962af-spi.c @@ -55,3 +55,4 @@ module_spi_driver(fxls8962af_driver); MODULE_AUTHOR("Sean Nyekjaer "); MODULE_DESCRIPTION("NXP FXLS8962AF/FXLS8964AF accelerometer spi driver"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS(IIO_FXLS8962AF); -- cgit v1.2.3 From d4786e7df03dc26e67d706910f3089de43a4fffe Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 16 Jan 2022 18:05:34 +0000 Subject: iio:st-sensors: Remove duplicate MODULE_* The core module and type specific core modules are made up of several files. There is no benefit in duplicating the MODULE_* macros in each file so remove them. Noticed whilst adding MODULE_IMPORT_NS() as I missed some files and it still worked, making it clear not all of these blocks were needed. Signed-off-by: Jonathan Cameron Cc: Andy Shevchenko Cc: Linus Walleij Cc: Denis Ciocca Reviewed-by: Linus Walleij Link: https://lore.kernel.org/r/20220116180535.2367780-13-jic23@kernel.org --- drivers/iio/accel/st_accel_buffer.c | 5 ----- drivers/iio/common/st_sensors/st_sensors_buffer.c | 5 ----- drivers/iio/common/st_sensors/st_sensors_trigger.c | 5 ----- drivers/iio/gyro/st_gyro_buffer.c | 4 ---- drivers/iio/magnetometer/st_magn_buffer.c | 4 ---- drivers/iio/pressure/st_pressure_buffer.c | 5 ----- 6 files changed, 28 deletions(-) diff --git a/drivers/iio/accel/st_accel_buffer.c b/drivers/iio/accel/st_accel_buffer.c index fc82fa83f1fb..b2977ae19b69 100644 --- a/drivers/iio/accel/st_accel_buffer.c +++ b/drivers/iio/accel/st_accel_buffer.c @@ -7,7 +7,6 @@ * Denis Ciocca */ -#include #include #include #include @@ -65,7 +64,3 @@ int st_accel_allocate_ring(struct iio_dev *indio_dev) return devm_iio_triggered_buffer_setup(indio_dev->dev.parent, indio_dev, NULL, &st_sensors_trigger_handler, &st_accel_buffer_setup_ops); } - -MODULE_AUTHOR("Denis Ciocca "); -MODULE_DESCRIPTION("STMicroelectronics accelerometers buffer"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/common/st_sensors/st_sensors_buffer.c b/drivers/iio/common/st_sensors/st_sensors_buffer.c index dccc471e79da..5f2b1fb95fd7 100644 --- a/drivers/iio/common/st_sensors/st_sensors_buffer.c +++ b/drivers/iio/common/st_sensors/st_sensors_buffer.c @@ -8,7 +8,6 @@ */ #include -#include #include #include #include @@ -78,7 +77,3 @@ st_sensors_get_buffer_element_error: return IRQ_HANDLED; } EXPORT_SYMBOL(st_sensors_trigger_handler); - -MODULE_AUTHOR("Denis Ciocca "); -MODULE_DESCRIPTION("STMicroelectronics ST-sensors buffer"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/common/st_sensors/st_sensors_trigger.c b/drivers/iio/common/st_sensors/st_sensors_trigger.c index 392d74449886..ab7a5a24fa6e 100644 --- a/drivers/iio/common/st_sensors/st_sensors_trigger.c +++ b/drivers/iio/common/st_sensors/st_sensors_trigger.c @@ -8,7 +8,6 @@ */ #include -#include #include #include #include @@ -241,7 +240,3 @@ int st_sensors_validate_device(struct iio_trigger *trig, return 0; } EXPORT_SYMBOL(st_sensors_validate_device); - -MODULE_AUTHOR("Denis Ciocca "); -MODULE_DESCRIPTION("STMicroelectronics ST-sensors trigger"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/gyro/st_gyro_buffer.c b/drivers/iio/gyro/st_gyro_buffer.c index 4ae33ef25b9c..1ebfe7aa6c96 100644 --- a/drivers/iio/gyro/st_gyro_buffer.c +++ b/drivers/iio/gyro/st_gyro_buffer.c @@ -7,7 +7,6 @@ * Denis Ciocca */ -#include #include #include #include @@ -65,6 +64,3 @@ int st_gyro_allocate_ring(struct iio_dev *indio_dev) NULL, &st_sensors_trigger_handler, &st_gyro_buffer_setup_ops); } -MODULE_AUTHOR("Denis Ciocca "); -MODULE_DESCRIPTION("STMicroelectronics gyroscopes buffer"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/magnetometer/st_magn_buffer.c b/drivers/iio/magnetometer/st_magn_buffer.c index cb43ccda808d..79987f42e8d9 100644 --- a/drivers/iio/magnetometer/st_magn_buffer.c +++ b/drivers/iio/magnetometer/st_magn_buffer.c @@ -7,7 +7,6 @@ * Denis Ciocca */ -#include #include #include #include @@ -45,6 +44,3 @@ int st_magn_allocate_ring(struct iio_dev *indio_dev) NULL, &st_sensors_trigger_handler, &st_magn_buffer_setup_ops); } -MODULE_AUTHOR("Denis Ciocca "); -MODULE_DESCRIPTION("STMicroelectronics magnetometers buffer"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/pressure/st_pressure_buffer.c b/drivers/iio/pressure/st_pressure_buffer.c index 25dbd5476b26..0dbf357c2c22 100644 --- a/drivers/iio/pressure/st_pressure_buffer.c +++ b/drivers/iio/pressure/st_pressure_buffer.c @@ -7,7 +7,6 @@ * Denis Ciocca */ -#include #include #include #include @@ -44,7 +43,3 @@ int st_press_allocate_ring(struct iio_dev *indio_dev) return devm_iio_triggered_buffer_setup(indio_dev->dev.parent, indio_dev, NULL, &st_sensors_trigger_handler, &st_press_buffer_setup_ops); } - -MODULE_AUTHOR("Denis Ciocca "); -MODULE_DESCRIPTION("STMicroelectronics pressures buffer"); -MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 0805b5121f2933a17616b9799a33bc175d07e722 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 16 Jan 2022 18:05:35 +0000 Subject: iio:st-sensors: Move exports into IIO_ST_SENSORS namespace To avoid unnecessary pollution of the global symbol namespace move the driver core and type specific core exports into their a new namespace and import that where needed. For more info see https://lwn.net/Articles/760045/ Signed-off-by: Jonathan Cameron Cc: Andy Shevchenko Cc: Linus Walleij Cc: Denis Ciocca Link: https://lore.kernel.org/r/20220116180535.2367780-14-jic23@kernel.org --- drivers/iio/accel/st_accel_core.c | 5 ++-- drivers/iio/accel/st_accel_i2c.c | 1 + drivers/iio/accel/st_accel_spi.c | 1 + drivers/iio/common/st_sensors/st_sensors_buffer.c | 2 +- drivers/iio/common/st_sensors/st_sensors_core.c | 28 +++++++++++----------- drivers/iio/common/st_sensors/st_sensors_i2c.c | 2 +- drivers/iio/common/st_sensors/st_sensors_spi.c | 2 +- drivers/iio/common/st_sensors/st_sensors_trigger.c | 4 ++-- drivers/iio/gyro/st_gyro_core.c | 5 ++-- drivers/iio/gyro/st_gyro_i2c.c | 1 + drivers/iio/gyro/st_gyro_spi.c | 1 + drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_core.c | 3 ++- drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_i2c.c | 1 + drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_spi.c | 1 + drivers/iio/magnetometer/st_magn_core.c | 5 ++-- drivers/iio/magnetometer/st_magn_i2c.c | 1 + drivers/iio/magnetometer/st_magn_spi.c | 1 + drivers/iio/pressure/st_pressure_core.c | 5 ++-- drivers/iio/pressure/st_pressure_i2c.c | 1 + drivers/iio/pressure/st_pressure_spi.c | 1 + 20 files changed, 43 insertions(+), 28 deletions(-) diff --git a/drivers/iio/accel/st_accel_core.c b/drivers/iio/accel/st_accel_core.c index 2ada8d6fb503..5c5da6fdb490 100644 --- a/drivers/iio/accel/st_accel_core.c +++ b/drivers/iio/accel/st_accel_core.c @@ -1412,7 +1412,7 @@ const struct st_sensor_settings *st_accel_get_settings(const char *name) return &st_accel_sensors_settings[index]; } -EXPORT_SYMBOL(st_accel_get_settings); +EXPORT_SYMBOL_NS(st_accel_get_settings, IIO_ST_SENSORS); int st_accel_common_probe(struct iio_dev *indio_dev) { @@ -1466,8 +1466,9 @@ int st_accel_common_probe(struct iio_dev *indio_dev) return devm_iio_device_register(parent, indio_dev); } -EXPORT_SYMBOL(st_accel_common_probe); +EXPORT_SYMBOL_NS(st_accel_common_probe, IIO_ST_SENSORS); MODULE_AUTHOR("Denis Ciocca "); MODULE_DESCRIPTION("STMicroelectronics accelerometers driver"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS(IIO_ST_SENSORS); diff --git a/drivers/iio/accel/st_accel_i2c.c b/drivers/iio/accel/st_accel_i2c.c index 7f5888570e87..96adc4344f4a 100644 --- a/drivers/iio/accel/st_accel_i2c.c +++ b/drivers/iio/accel/st_accel_i2c.c @@ -199,3 +199,4 @@ module_i2c_driver(st_accel_driver); MODULE_AUTHOR("Denis Ciocca "); MODULE_DESCRIPTION("STMicroelectronics accelerometers i2c driver"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS(IIO_ST_SENSORS); diff --git a/drivers/iio/accel/st_accel_spi.c b/drivers/iio/accel/st_accel_spi.c index b74a1c6d03de..108b63d0146c 100644 --- a/drivers/iio/accel/st_accel_spi.c +++ b/drivers/iio/accel/st_accel_spi.c @@ -164,3 +164,4 @@ module_spi_driver(st_accel_driver); MODULE_AUTHOR("Denis Ciocca "); MODULE_DESCRIPTION("STMicroelectronics accelerometers spi driver"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS(IIO_ST_SENSORS); diff --git a/drivers/iio/common/st_sensors/st_sensors_buffer.c b/drivers/iio/common/st_sensors/st_sensors_buffer.c index 5f2b1fb95fd7..e2f108ca949c 100644 --- a/drivers/iio/common/st_sensors/st_sensors_buffer.c +++ b/drivers/iio/common/st_sensors/st_sensors_buffer.c @@ -76,4 +76,4 @@ st_sensors_get_buffer_element_error: return IRQ_HANDLED; } -EXPORT_SYMBOL(st_sensors_trigger_handler); +EXPORT_SYMBOL_NS(st_sensors_trigger_handler, IIO_ST_SENSORS); diff --git a/drivers/iio/common/st_sensors/st_sensors_core.c b/drivers/iio/common/st_sensors/st_sensors_core.c index eb452d0c423c..fa9bcdf0d190 100644 --- a/drivers/iio/common/st_sensors/st_sensors_core.c +++ b/drivers/iio/common/st_sensors/st_sensors_core.c @@ -46,7 +46,7 @@ int st_sensors_debugfs_reg_access(struct iio_dev *indio_dev, return 0; } -EXPORT_SYMBOL(st_sensors_debugfs_reg_access); +EXPORT_SYMBOL_NS(st_sensors_debugfs_reg_access, IIO_ST_SENSORS); static int st_sensors_match_odr(struct st_sensor_settings *sensor_settings, unsigned int odr, struct st_sensor_odr_avl *odr_out) @@ -106,7 +106,7 @@ int st_sensors_set_odr(struct iio_dev *indio_dev, unsigned int odr) st_sensors_match_odr_error: return err; } -EXPORT_SYMBOL(st_sensors_set_odr); +EXPORT_SYMBOL_NS(st_sensors_set_odr, IIO_ST_SENSORS); static int st_sensors_match_fs(struct st_sensor_settings *sensor_settings, unsigned int fs, int *index_fs_avl) @@ -199,7 +199,7 @@ int st_sensors_set_enable(struct iio_dev *indio_dev, bool enable) set_enable_error: return err; } -EXPORT_SYMBOL(st_sensors_set_enable); +EXPORT_SYMBOL_NS(st_sensors_set_enable, IIO_ST_SENSORS); int st_sensors_set_axis_enable(struct iio_dev *indio_dev, u8 axis_enable) { @@ -213,7 +213,7 @@ int st_sensors_set_axis_enable(struct iio_dev *indio_dev, u8 axis_enable) axis_enable); return err; } -EXPORT_SYMBOL(st_sensors_set_axis_enable); +EXPORT_SYMBOL_NS(st_sensors_set_axis_enable, IIO_ST_SENSORS); static void st_reg_disable(void *reg) { @@ -257,7 +257,7 @@ int st_sensors_power_enable(struct iio_dev *indio_dev) return devm_add_action_or_reset(parent, st_reg_disable, pdata->vdd_io); } -EXPORT_SYMBOL(st_sensors_power_enable); +EXPORT_SYMBOL_NS(st_sensors_power_enable, IIO_ST_SENSORS); static int st_sensors_set_drdy_int_pin(struct iio_dev *indio_dev, struct st_sensors_platform_data *pdata) @@ -352,7 +352,7 @@ void st_sensors_dev_name_probe(struct device *dev, char *name, int len) /* The name from the match takes precedence if present */ strlcpy(name, match, len); } -EXPORT_SYMBOL(st_sensors_dev_name_probe); +EXPORT_SYMBOL_NS(st_sensors_dev_name_probe, IIO_ST_SENSORS); int st_sensors_init_sensor(struct iio_dev *indio_dev, struct st_sensors_platform_data *pdata) @@ -437,7 +437,7 @@ int st_sensors_init_sensor(struct iio_dev *indio_dev, return err; } -EXPORT_SYMBOL(st_sensors_init_sensor); +EXPORT_SYMBOL_NS(st_sensors_init_sensor, IIO_ST_SENSORS); int st_sensors_set_dataready_irq(struct iio_dev *indio_dev, bool enable) { @@ -486,7 +486,7 @@ int st_sensors_set_dataready_irq(struct iio_dev *indio_dev, bool enable) st_accel_set_dataready_irq_error: return err; } -EXPORT_SYMBOL(st_sensors_set_dataready_irq); +EXPORT_SYMBOL_NS(st_sensors_set_dataready_irq, IIO_ST_SENSORS); int st_sensors_set_fullscale_by_gain(struct iio_dev *indio_dev, int scale) { @@ -509,7 +509,7 @@ int st_sensors_set_fullscale_by_gain(struct iio_dev *indio_dev, int scale) st_sensors_match_scale_error: return err; } -EXPORT_SYMBOL(st_sensors_set_fullscale_by_gain); +EXPORT_SYMBOL_NS(st_sensors_set_fullscale_by_gain, IIO_ST_SENSORS); static int st_sensors_read_axis_data(struct iio_dev *indio_dev, struct iio_chan_spec const *ch, int *data) @@ -572,7 +572,7 @@ out: return err; } -EXPORT_SYMBOL(st_sensors_read_info_raw); +EXPORT_SYMBOL_NS(st_sensors_read_info_raw, IIO_ST_SENSORS); /* * st_sensors_get_settings_index() - get index of the sensor settings for a @@ -599,7 +599,7 @@ int st_sensors_get_settings_index(const char *name, return -ENODEV; } -EXPORT_SYMBOL(st_sensors_get_settings_index); +EXPORT_SYMBOL_NS(st_sensors_get_settings_index, IIO_ST_SENSORS); /* * st_sensors_verify_id() - verify sensor ID (WhoAmI) is matching with the @@ -632,7 +632,7 @@ int st_sensors_verify_id(struct iio_dev *indio_dev) return 0; } -EXPORT_SYMBOL(st_sensors_verify_id); +EXPORT_SYMBOL_NS(st_sensors_verify_id, IIO_ST_SENSORS); ssize_t st_sensors_sysfs_sampling_frequency_avail(struct device *dev, struct device_attribute *attr, char *buf) @@ -654,7 +654,7 @@ ssize_t st_sensors_sysfs_sampling_frequency_avail(struct device *dev, return len; } -EXPORT_SYMBOL(st_sensors_sysfs_sampling_frequency_avail); +EXPORT_SYMBOL_NS(st_sensors_sysfs_sampling_frequency_avail, IIO_ST_SENSORS); ssize_t st_sensors_sysfs_scale_avail(struct device *dev, struct device_attribute *attr, char *buf) @@ -678,7 +678,7 @@ ssize_t st_sensors_sysfs_scale_avail(struct device *dev, return len; } -EXPORT_SYMBOL(st_sensors_sysfs_scale_avail); +EXPORT_SYMBOL_NS(st_sensors_sysfs_scale_avail, IIO_ST_SENSORS); MODULE_AUTHOR("Denis Ciocca "); MODULE_DESCRIPTION("STMicroelectronics ST-sensors core"); diff --git a/drivers/iio/common/st_sensors/st_sensors_i2c.c b/drivers/iio/common/st_sensors/st_sensors_i2c.c index 18bd3c3d99bc..ee95082c7410 100644 --- a/drivers/iio/common/st_sensors/st_sensors_i2c.c +++ b/drivers/iio/common/st_sensors/st_sensors_i2c.c @@ -61,7 +61,7 @@ int st_sensors_i2c_configure(struct iio_dev *indio_dev, return 0; } -EXPORT_SYMBOL(st_sensors_i2c_configure); +EXPORT_SYMBOL_NS(st_sensors_i2c_configure, IIO_ST_SENSORS); MODULE_AUTHOR("Denis Ciocca "); MODULE_DESCRIPTION("STMicroelectronics ST-sensors i2c driver"); diff --git a/drivers/iio/common/st_sensors/st_sensors_spi.c b/drivers/iio/common/st_sensors/st_sensors_spi.c index 7c60050e90dc..63e302c3fbaa 100644 --- a/drivers/iio/common/st_sensors/st_sensors_spi.c +++ b/drivers/iio/common/st_sensors/st_sensors_spi.c @@ -113,7 +113,7 @@ int st_sensors_spi_configure(struct iio_dev *indio_dev, return 0; } -EXPORT_SYMBOL(st_sensors_spi_configure); +EXPORT_SYMBOL_NS(st_sensors_spi_configure, IIO_ST_SENSORS); MODULE_AUTHOR("Denis Ciocca "); MODULE_DESCRIPTION("STMicroelectronics ST-sensors spi driver"); diff --git a/drivers/iio/common/st_sensors/st_sensors_trigger.c b/drivers/iio/common/st_sensors/st_sensors_trigger.c index ab7a5a24fa6e..899b640c0a70 100644 --- a/drivers/iio/common/st_sensors/st_sensors_trigger.c +++ b/drivers/iio/common/st_sensors/st_sensors_trigger.c @@ -227,7 +227,7 @@ int st_sensors_allocate_trigger(struct iio_dev *indio_dev, return 0; } -EXPORT_SYMBOL(st_sensors_allocate_trigger); +EXPORT_SYMBOL_NS(st_sensors_allocate_trigger, IIO_ST_SENSORS); int st_sensors_validate_device(struct iio_trigger *trig, struct iio_dev *indio_dev) @@ -239,4 +239,4 @@ int st_sensors_validate_device(struct iio_trigger *trig, return 0; } -EXPORT_SYMBOL(st_sensors_validate_device); +EXPORT_SYMBOL_NS(st_sensors_validate_device, IIO_ST_SENSORS); diff --git a/drivers/iio/gyro/st_gyro_core.c b/drivers/iio/gyro/st_gyro_core.c index 201050b76fe5..62172e18d0d8 100644 --- a/drivers/iio/gyro/st_gyro_core.c +++ b/drivers/iio/gyro/st_gyro_core.c @@ -472,7 +472,7 @@ const struct st_sensor_settings *st_gyro_get_settings(const char *name) return &st_gyro_sensors_settings[index]; } -EXPORT_SYMBOL(st_gyro_get_settings); +EXPORT_SYMBOL_NS(st_gyro_get_settings, IIO_ST_SENSORS); int st_gyro_common_probe(struct iio_dev *indio_dev) { @@ -518,8 +518,9 @@ int st_gyro_common_probe(struct iio_dev *indio_dev) return devm_iio_device_register(parent, indio_dev); } -EXPORT_SYMBOL(st_gyro_common_probe); +EXPORT_SYMBOL_NS(st_gyro_common_probe, IIO_ST_SENSORS); MODULE_AUTHOR("Denis Ciocca "); MODULE_DESCRIPTION("STMicroelectronics gyroscopes driver"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS(IIO_ST_SENSORS); diff --git a/drivers/iio/gyro/st_gyro_i2c.c b/drivers/iio/gyro/st_gyro_i2c.c index 163c7ba300c1..8c7af42b6558 100644 --- a/drivers/iio/gyro/st_gyro_i2c.c +++ b/drivers/iio/gyro/st_gyro_i2c.c @@ -120,3 +120,4 @@ module_i2c_driver(st_gyro_driver); MODULE_AUTHOR("Denis Ciocca "); MODULE_DESCRIPTION("STMicroelectronics gyroscopes i2c driver"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS(IIO_ST_SENSORS); diff --git a/drivers/iio/gyro/st_gyro_spi.c b/drivers/iio/gyro/st_gyro_spi.c index b0023f9b9771..22aaabe48e4a 100644 --- a/drivers/iio/gyro/st_gyro_spi.c +++ b/drivers/iio/gyro/st_gyro_spi.c @@ -124,3 +124,4 @@ module_spi_driver(st_gyro_driver); MODULE_AUTHOR("Denis Ciocca "); MODULE_DESCRIPTION("STMicroelectronics gyroscopes spi driver"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS(IIO_ST_SENSORS); diff --git a/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_core.c b/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_core.c index 9fb06b7cde3c..ae7bc815382f 100644 --- a/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_core.c +++ b/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_core.c @@ -142,8 +142,9 @@ int st_lsm9ds0_probe(struct st_lsm9ds0 *lsm9ds0, struct regmap *regmap) /* Setup magnetometer device */ return st_lsm9ds0_probe_magn(lsm9ds0, regmap); } -EXPORT_SYMBOL_GPL(st_lsm9ds0_probe); +EXPORT_SYMBOL_NS_GPL(st_lsm9ds0_probe, IIO_ST_SENSORS); MODULE_AUTHOR("Andy Shevchenko "); MODULE_DESCRIPTION("STMicroelectronics LSM9DS0 IMU core driver"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS(IIO_ST_SENSORS); diff --git a/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_i2c.c b/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_i2c.c index 8f205c477e6f..a90138d8b06a 100644 --- a/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_i2c.c +++ b/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_i2c.c @@ -77,3 +77,4 @@ module_i2c_driver(st_lsm9ds0_driver); MODULE_AUTHOR("Andy Shevchenko "); MODULE_DESCRIPTION("STMicroelectronics LSM9DS0 IMU I2C driver"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS(IIO_ST_SENSORS); diff --git a/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_spi.c b/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_spi.c index 0ddfa53166af..b743bf3546a7 100644 --- a/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_spi.c +++ b/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_spi.c @@ -76,3 +76,4 @@ module_spi_driver(st_lsm9ds0_driver); MODULE_AUTHOR("Andy Shevchenko "); MODULE_DESCRIPTION("STMicroelectronics LSM9DS0 IMU SPI driver"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS(IIO_ST_SENSORS); diff --git a/drivers/iio/magnetometer/st_magn_core.c b/drivers/iio/magnetometer/st_magn_core.c index 0806a1e65ce4..74435f4a427d 100644 --- a/drivers/iio/magnetometer/st_magn_core.c +++ b/drivers/iio/magnetometer/st_magn_core.c @@ -606,7 +606,7 @@ const struct st_sensor_settings *st_magn_get_settings(const char *name) return &st_magn_sensors_settings[index]; } -EXPORT_SYMBOL(st_magn_get_settings); +EXPORT_SYMBOL_NS(st_magn_get_settings, IIO_ST_SENSORS); int st_magn_common_probe(struct iio_dev *indio_dev) { @@ -653,8 +653,9 @@ int st_magn_common_probe(struct iio_dev *indio_dev) return devm_iio_device_register(parent, indio_dev); } -EXPORT_SYMBOL(st_magn_common_probe); +EXPORT_SYMBOL_NS(st_magn_common_probe, IIO_ST_SENSORS); MODULE_AUTHOR("Denis Ciocca "); MODULE_DESCRIPTION("STMicroelectronics magnetometers driver"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS(IIO_ST_SENSORS); diff --git a/drivers/iio/magnetometer/st_magn_i2c.c b/drivers/iio/magnetometer/st_magn_i2c.c index 7237711fc09b..c5d8c303db4e 100644 --- a/drivers/iio/magnetometer/st_magn_i2c.c +++ b/drivers/iio/magnetometer/st_magn_i2c.c @@ -115,3 +115,4 @@ module_i2c_driver(st_magn_driver); MODULE_AUTHOR("Denis Ciocca "); MODULE_DESCRIPTION("STMicroelectronics magnetometers i2c driver"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS(IIO_ST_SENSORS); diff --git a/drivers/iio/magnetometer/st_magn_spi.c b/drivers/iio/magnetometer/st_magn_spi.c index 489d4462862f..6ddc4318564a 100644 --- a/drivers/iio/magnetometer/st_magn_spi.c +++ b/drivers/iio/magnetometer/st_magn_spi.c @@ -106,3 +106,4 @@ module_spi_driver(st_magn_driver); MODULE_AUTHOR("Denis Ciocca "); MODULE_DESCRIPTION("STMicroelectronics magnetometers spi driver"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS(IIO_ST_SENSORS); diff --git a/drivers/iio/pressure/st_pressure_core.c b/drivers/iio/pressure/st_pressure_core.c index 26a1ee43d56e..5b93933a2e27 100644 --- a/drivers/iio/pressure/st_pressure_core.c +++ b/drivers/iio/pressure/st_pressure_core.c @@ -672,7 +672,7 @@ const struct st_sensor_settings *st_press_get_settings(const char *name) return &st_press_sensors_settings[index]; } -EXPORT_SYMBOL(st_press_get_settings); +EXPORT_SYMBOL_NS(st_press_get_settings, IIO_ST_SENSORS); int st_press_common_probe(struct iio_dev *indio_dev) { @@ -724,8 +724,9 @@ int st_press_common_probe(struct iio_dev *indio_dev) return devm_iio_device_register(parent, indio_dev); } -EXPORT_SYMBOL(st_press_common_probe); +EXPORT_SYMBOL_NS(st_press_common_probe, IIO_ST_SENSORS); MODULE_AUTHOR("Denis Ciocca "); MODULE_DESCRIPTION("STMicroelectronics pressures driver"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS(IIO_ST_SENSORS); diff --git a/drivers/iio/pressure/st_pressure_i2c.c b/drivers/iio/pressure/st_pressure_i2c.c index 1939e999a427..7035777fd988 100644 --- a/drivers/iio/pressure/st_pressure_i2c.c +++ b/drivers/iio/pressure/st_pressure_i2c.c @@ -120,3 +120,4 @@ module_i2c_driver(st_press_driver); MODULE_AUTHOR("Denis Ciocca "); MODULE_DESCRIPTION("STMicroelectronics pressures i2c driver"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS(IIO_ST_SENSORS); diff --git a/drivers/iio/pressure/st_pressure_spi.c b/drivers/iio/pressure/st_pressure_spi.c index d6fc954e28f8..bfab8e7fb061 100644 --- a/drivers/iio/pressure/st_pressure_spi.c +++ b/drivers/iio/pressure/st_pressure_spi.c @@ -118,3 +118,4 @@ module_spi_driver(st_press_driver); MODULE_AUTHOR("Denis Ciocca "); MODULE_DESCRIPTION("STMicroelectronics pressures spi driver"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS(IIO_ST_SENSORS); -- cgit v1.2.3 From ef807729767fb78a68de4dd00fec5ad4be0f2bc5 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 30 Jan 2022 20:56:46 +0000 Subject: iio:adc:ad_sigma_delta: Move exports into IIO_AD_SIGMA_DELTA namespace In order to avoid unnecessary pollution of the global symbol namespace move the core/library functions into a specific namespace and import that into the various specific device drivers that use them. For more information see https://lwn.net/Articles/760045/ Signed-off-by: Jonathan Cameron Cc: Renato Lui Geh Cc: Michael Hennerich Cc: Lars-Peter Clausen Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220130205701.334592-2-jic23@kernel.org --- drivers/iio/adc/ad7124.c | 1 + drivers/iio/adc/ad7192.c | 1 + drivers/iio/adc/ad7780.c | 1 + drivers/iio/adc/ad7791.c | 1 + drivers/iio/adc/ad7793.c | 1 + drivers/iio/adc/ad_sigma_delta.c | 20 ++++++++++---------- 6 files changed, 15 insertions(+), 10 deletions(-) diff --git a/drivers/iio/adc/ad7124.c b/drivers/iio/adc/ad7124.c index bc2cfa5f9592..998a342d51a6 100644 --- a/drivers/iio/adc/ad7124.c +++ b/drivers/iio/adc/ad7124.c @@ -970,3 +970,4 @@ module_spi_driver(ad71124_driver); MODULE_AUTHOR("Stefan Popa "); MODULE_DESCRIPTION("Analog Devices AD7124 SPI driver"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(IIO_AD_SIGMA_DELTA); diff --git a/drivers/iio/adc/ad7192.c b/drivers/iio/adc/ad7192.c index 47d3f56edcbc..770b4e59238f 100644 --- a/drivers/iio/adc/ad7192.c +++ b/drivers/iio/adc/ad7192.c @@ -1048,3 +1048,4 @@ module_spi_driver(ad7192_driver); MODULE_AUTHOR("Michael Hennerich "); MODULE_DESCRIPTION("Analog Devices AD7190, AD7192, AD7193, AD7195 ADC"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS(IIO_AD_SIGMA_DELTA); diff --git a/drivers/iio/adc/ad7780.c b/drivers/iio/adc/ad7780.c index b6e8c8abf6f4..a813fe04787c 100644 --- a/drivers/iio/adc/ad7780.c +++ b/drivers/iio/adc/ad7780.c @@ -375,3 +375,4 @@ module_spi_driver(ad7780_driver); MODULE_AUTHOR("Michael Hennerich "); MODULE_DESCRIPTION("Analog Devices AD7780 and similar ADCs"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS(IIO_AD_SIGMA_DELTA); diff --git a/drivers/iio/adc/ad7791.c b/drivers/iio/adc/ad7791.c index cb579aa89f39..fee8d129a5f0 100644 --- a/drivers/iio/adc/ad7791.c +++ b/drivers/iio/adc/ad7791.c @@ -474,3 +474,4 @@ module_spi_driver(ad7791_driver); MODULE_AUTHOR("Lars-Peter Clausen "); MODULE_DESCRIPTION("Analog Devices AD7787/AD7788/AD7789/AD7790/AD7791 ADC driver"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS(IIO_AD_SIGMA_DELTA); diff --git a/drivers/iio/adc/ad7793.c b/drivers/iio/adc/ad7793.c index 0e7ab3fb072a..5f8cb9aaac70 100644 --- a/drivers/iio/adc/ad7793.c +++ b/drivers/iio/adc/ad7793.c @@ -867,3 +867,4 @@ module_spi_driver(ad7793_driver); MODULE_AUTHOR("Michael Hennerich "); MODULE_DESCRIPTION("Analog Devices AD7793 and similar ADCs"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS(IIO_AD_SIGMA_DELTA); diff --git a/drivers/iio/adc/ad_sigma_delta.c b/drivers/iio/adc/ad_sigma_delta.c index cd418bd8bd87..ebcd52526cac 100644 --- a/drivers/iio/adc/ad_sigma_delta.c +++ b/drivers/iio/adc/ad_sigma_delta.c @@ -42,7 +42,7 @@ void ad_sd_set_comm(struct ad_sigma_delta *sigma_delta, uint8_t comm) * to select the channel */ sigma_delta->comm = comm & AD_SD_COMM_CHAN_MASK; } -EXPORT_SYMBOL_GPL(ad_sd_set_comm); +EXPORT_SYMBOL_NS_GPL(ad_sd_set_comm, IIO_AD_SIGMA_DELTA); /** * ad_sd_write_reg() - Write a register @@ -94,7 +94,7 @@ int ad_sd_write_reg(struct ad_sigma_delta *sigma_delta, unsigned int reg, return ret; } -EXPORT_SYMBOL_GPL(ad_sd_write_reg); +EXPORT_SYMBOL_NS_GPL(ad_sd_write_reg, IIO_AD_SIGMA_DELTA); static int ad_sd_read_reg_raw(struct ad_sigma_delta *sigma_delta, unsigned int reg, unsigned int size, uint8_t *val) @@ -171,7 +171,7 @@ int ad_sd_read_reg(struct ad_sigma_delta *sigma_delta, out: return ret; } -EXPORT_SYMBOL_GPL(ad_sd_read_reg); +EXPORT_SYMBOL_NS_GPL(ad_sd_read_reg, IIO_AD_SIGMA_DELTA); /** * ad_sd_reset() - Reset the serial interface @@ -199,7 +199,7 @@ int ad_sd_reset(struct ad_sigma_delta *sigma_delta, return ret; } -EXPORT_SYMBOL_GPL(ad_sd_reset); +EXPORT_SYMBOL_NS_GPL(ad_sd_reset, IIO_AD_SIGMA_DELTA); int ad_sd_calibrate(struct ad_sigma_delta *sigma_delta, unsigned int mode, unsigned int channel) @@ -238,7 +238,7 @@ out: return ret; } -EXPORT_SYMBOL_GPL(ad_sd_calibrate); +EXPORT_SYMBOL_NS_GPL(ad_sd_calibrate, IIO_AD_SIGMA_DELTA); /** * ad_sd_calibrate_all() - Performs channel calibration @@ -262,7 +262,7 @@ int ad_sd_calibrate_all(struct ad_sigma_delta *sigma_delta, return 0; } -EXPORT_SYMBOL_GPL(ad_sd_calibrate_all); +EXPORT_SYMBOL_NS_GPL(ad_sd_calibrate_all, IIO_AD_SIGMA_DELTA); /** * ad_sigma_delta_single_conversion() - Performs a single data conversion @@ -337,7 +337,7 @@ out: return IIO_VAL_INT; } -EXPORT_SYMBOL_GPL(ad_sigma_delta_single_conversion); +EXPORT_SYMBOL_NS_GPL(ad_sigma_delta_single_conversion, IIO_AD_SIGMA_DELTA); static int ad_sd_buffer_postenable(struct iio_dev *indio_dev) { @@ -465,7 +465,7 @@ int ad_sd_validate_trigger(struct iio_dev *indio_dev, struct iio_trigger *trig) return 0; } -EXPORT_SYMBOL_GPL(ad_sd_validate_trigger); +EXPORT_SYMBOL_NS_GPL(ad_sd_validate_trigger, IIO_AD_SIGMA_DELTA); static int devm_ad_sd_probe_trigger(struct device *dev, struct iio_dev *indio_dev) { @@ -524,7 +524,7 @@ int devm_ad_sd_setup_buffer_and_trigger(struct device *dev, struct iio_dev *indi return devm_ad_sd_probe_trigger(dev, indio_dev); } -EXPORT_SYMBOL_GPL(devm_ad_sd_setup_buffer_and_trigger); +EXPORT_SYMBOL_NS_GPL(devm_ad_sd_setup_buffer_and_trigger, IIO_AD_SIGMA_DELTA); /** * ad_sd_init() - Initializes a ad_sigma_delta struct @@ -545,7 +545,7 @@ int ad_sd_init(struct ad_sigma_delta *sigma_delta, struct iio_dev *indio_dev, return 0; } -EXPORT_SYMBOL_GPL(ad_sd_init); +EXPORT_SYMBOL_NS_GPL(ad_sd_init, IIO_AD_SIGMA_DELTA); MODULE_AUTHOR("Lars-Peter Clausen "); MODULE_DESCRIPTION("Analog Devices Sigma-Delta ADCs"); -- cgit v1.2.3 From 8a0080af84d3fb2423f0b3b55eff666f545eb097 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 30 Jan 2022 20:56:47 +0000 Subject: iio:adc:ad7091r: Move exports into IIO_AD7091R namespace. In order to avoid unnecessary pollution of the global symbol namespace move the core/library functions into a specific namespace and import that into the various specific device drivers that use them. For more information see https://lwn.net/Articles/760045/ An alternative here would be to conclude that we are unlikely to see support for the other ad7091r parts in the near future and just merge the two modules into one supporting just the i2c -5 variant. Signed-off-by: Jonathan Cameron Cc: Paul Cercueil Reviewed-by: Paul Cercueil Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220130205701.334592-3-jic23@kernel.org --- drivers/iio/adc/ad7091r-base.c | 4 ++-- drivers/iio/adc/ad7091r5.c | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/iio/adc/ad7091r-base.c b/drivers/iio/adc/ad7091r-base.c index 63b4d6ea4566..8e252cde735b 100644 --- a/drivers/iio/adc/ad7091r-base.c +++ b/drivers/iio/adc/ad7091r-base.c @@ -260,7 +260,7 @@ int ad7091r_probe(struct device *dev, const char *name, return devm_iio_device_register(dev, iio_dev); } -EXPORT_SYMBOL_GPL(ad7091r_probe); +EXPORT_SYMBOL_NS_GPL(ad7091r_probe, IIO_AD7091R); static bool ad7091r_writeable_reg(struct device *dev, unsigned int reg) { @@ -290,7 +290,7 @@ const struct regmap_config ad7091r_regmap_config = { .writeable_reg = ad7091r_writeable_reg, .volatile_reg = ad7091r_volatile_reg, }; -EXPORT_SYMBOL_GPL(ad7091r_regmap_config); +EXPORT_SYMBOL_NS_GPL(ad7091r_regmap_config, IIO_AD7091R); MODULE_AUTHOR("Beniamin Bia "); MODULE_DESCRIPTION("Analog Devices AD7091Rx multi-channel converters"); diff --git a/drivers/iio/adc/ad7091r5.c b/drivers/iio/adc/ad7091r5.c index 9665679c3ea6..47f5763023a4 100644 --- a/drivers/iio/adc/ad7091r5.c +++ b/drivers/iio/adc/ad7091r5.c @@ -111,3 +111,4 @@ module_i2c_driver(ad7091r5_driver); MODULE_AUTHOR("Beniamin Bia "); MODULE_DESCRIPTION("Analog Devices AD7091R5 multi-channel ADC driver"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS(IIO_AD7091R); -- cgit v1.2.3 From 59cea5bc7c19ac88f2300969eb35c49d91a0eeeb Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 30 Jan 2022 20:56:48 +0000 Subject: iio:adc:ad76060: Move exports into IIO_AD7606 namespace. In order to avoid unnecessary pollution of the global symbol namespace move the core/library functions into a specific namespace and import that into the various bus specific device drivers that use them. For more information see https://lwn.net/Articles/760045/ Signed-off-by: Jonathan Cameron Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220130205701.334592-4-jic23@kernel.org --- drivers/iio/adc/ad7606.c | 4 ++-- drivers/iio/adc/ad7606_par.c | 1 + drivers/iio/adc/ad7606_spi.c | 1 + 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/iio/adc/ad7606.c b/drivers/iio/adc/ad7606.c index 0a60ecc69d38..3b193dc26438 100644 --- a/drivers/iio/adc/ad7606.c +++ b/drivers/iio/adc/ad7606.c @@ -693,7 +693,7 @@ int ad7606_probe(struct device *dev, int irq, void __iomem *base_address, return devm_iio_device_register(dev, indio_dev); } -EXPORT_SYMBOL_GPL(ad7606_probe); +EXPORT_SYMBOL_NS_GPL(ad7606_probe, IIO_AD7606); #ifdef CONFIG_PM_SLEEP @@ -725,7 +725,7 @@ static int ad7606_resume(struct device *dev) } SIMPLE_DEV_PM_OPS(ad7606_pm_ops, ad7606_suspend, ad7606_resume); -EXPORT_SYMBOL_GPL(ad7606_pm_ops); +EXPORT_SYMBOL_NS_GPL(ad7606_pm_ops, IIO_AD7606); #endif diff --git a/drivers/iio/adc/ad7606_par.c b/drivers/iio/adc/ad7606_par.c index f732b3ac7878..8888e56b5e90 100644 --- a/drivers/iio/adc/ad7606_par.c +++ b/drivers/iio/adc/ad7606_par.c @@ -101,3 +101,4 @@ module_platform_driver(ad7606_driver); MODULE_AUTHOR("Michael Hennerich "); MODULE_DESCRIPTION("Analog Devices AD7606 ADC"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS(IIO_AD7606); diff --git a/drivers/iio/adc/ad7606_spi.c b/drivers/iio/adc/ad7606_spi.c index 29945ad07dca..263a778bcf25 100644 --- a/drivers/iio/adc/ad7606_spi.c +++ b/drivers/iio/adc/ad7606_spi.c @@ -362,3 +362,4 @@ module_spi_driver(ad7606_driver); MODULE_AUTHOR("Michael Hennerich "); MODULE_DESCRIPTION("Analog Devices AD7606 ADC"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS(IIO_AD7606); -- cgit v1.2.3 From a7f6cecfef9b92aabda049e476bb22305ca5df2b Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 30 Jan 2022 20:56:49 +0000 Subject: iio:common:meas-spec: Move exports into IIO_MEAS_SPEC_SENSORS The obvious choice of ms_sensors felt rather too likely to clash with other namespaces introduced in future, hence the longer abbreviation. In order to avoid unnecessary pollution of the global symbol namespace move the common/library functions into a specific namespace and import that into the various specific device drivers that use them. For more information see https://lwn.net/Articles/760045/ Signed-off-by: Jonathan Cameron Cc: Alexandre Belloni Cc: William Markezana Cc: Ludovic Tancerel Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220130205701.334592-5-jic23@kernel.org --- drivers/iio/common/ms_sensors/ms_sensors_i2c.c | 24 ++++++++++++------------ drivers/iio/humidity/htu21.c | 1 + drivers/iio/pressure/ms5637.c | 1 + drivers/iio/temperature/tsys01.c | 1 + drivers/iio/temperature/tsys02d.c | 1 + 5 files changed, 16 insertions(+), 12 deletions(-) diff --git a/drivers/iio/common/ms_sensors/ms_sensors_i2c.c b/drivers/iio/common/ms_sensors/ms_sensors_i2c.c index 3eb790aec4b2..6633b35a94e6 100644 --- a/drivers/iio/common/ms_sensors/ms_sensors_i2c.c +++ b/drivers/iio/common/ms_sensors/ms_sensors_i2c.c @@ -58,7 +58,7 @@ int ms_sensors_reset(void *cli, u8 cmd, unsigned int delay) return 0; } -EXPORT_SYMBOL(ms_sensors_reset); +EXPORT_SYMBOL_NS(ms_sensors_reset, IIO_MEAS_SPEC_SENSORS); /** * ms_sensors_read_prom_word() - PROM word read function @@ -84,7 +84,7 @@ int ms_sensors_read_prom_word(void *cli, int cmd, u16 *word) return 0; } -EXPORT_SYMBOL(ms_sensors_read_prom_word); +EXPORT_SYMBOL_NS(ms_sensors_read_prom_word, IIO_MEAS_SPEC_SENSORS); /** * ms_sensors_convert_and_read() - ADC conversion & read function @@ -130,7 +130,7 @@ err: dev_err(&client->dev, "Unable to make sensor adc conversion\n"); return ret; } -EXPORT_SYMBOL(ms_sensors_convert_and_read); +EXPORT_SYMBOL_NS(ms_sensors_convert_and_read, IIO_MEAS_SPEC_SENSORS); /** * ms_sensors_crc_valid() - CRC check function @@ -248,7 +248,7 @@ int ms_sensors_read_serial(struct i2c_client *client, u64 *sn) return 0; } -EXPORT_SYMBOL(ms_sensors_read_serial); +EXPORT_SYMBOL_NS(ms_sensors_read_serial, IIO_MEAS_SPEC_SENSORS); static int ms_sensors_read_config_reg(struct i2c_client *client, u8 *config_reg) @@ -299,7 +299,7 @@ ssize_t ms_sensors_write_resolution(struct ms_ht_dev *dev_data, MS_SENSORS_CONFIG_REG_WRITE, config_reg); } -EXPORT_SYMBOL(ms_sensors_write_resolution); +EXPORT_SYMBOL_NS(ms_sensors_write_resolution, IIO_MEAS_SPEC_SENSORS); /** * ms_sensors_show_battery_low() - Show device battery low indicator @@ -326,7 +326,7 @@ ssize_t ms_sensors_show_battery_low(struct ms_ht_dev *dev_data, return sysfs_emit(buf, "%d\n", (config_reg & 0x40) >> 6); } -EXPORT_SYMBOL(ms_sensors_show_battery_low); +EXPORT_SYMBOL_NS(ms_sensors_show_battery_low, IIO_MEAS_SPEC_SENSORS); /** * ms_sensors_show_heater() - Show device heater @@ -353,7 +353,7 @@ ssize_t ms_sensors_show_heater(struct ms_ht_dev *dev_data, return sysfs_emit(buf, "%d\n", (config_reg & 0x4) >> 2); } -EXPORT_SYMBOL(ms_sensors_show_heater); +EXPORT_SYMBOL_NS(ms_sensors_show_heater, IIO_MEAS_SPEC_SENSORS); /** * ms_sensors_write_heater() - Write device heater @@ -401,7 +401,7 @@ ssize_t ms_sensors_write_heater(struct ms_ht_dev *dev_data, return len; } -EXPORT_SYMBOL(ms_sensors_write_heater); +EXPORT_SYMBOL_NS(ms_sensors_write_heater, IIO_MEAS_SPEC_SENSORS); /** * ms_sensors_ht_read_temperature() - Read temperature @@ -442,7 +442,7 @@ int ms_sensors_ht_read_temperature(struct ms_ht_dev *dev_data, return 0; } -EXPORT_SYMBOL(ms_sensors_ht_read_temperature); +EXPORT_SYMBOL_NS(ms_sensors_ht_read_temperature, IIO_MEAS_SPEC_SENSORS); /** * ms_sensors_ht_read_humidity() - Read humidity @@ -485,7 +485,7 @@ int ms_sensors_ht_read_humidity(struct ms_ht_dev *dev_data, return 0; } -EXPORT_SYMBOL(ms_sensors_ht_read_humidity); +EXPORT_SYMBOL_NS(ms_sensors_ht_read_humidity, IIO_MEAS_SPEC_SENSORS); /** * ms_sensors_tp_crc4() - Calculate PROM CRC for @@ -602,7 +602,7 @@ int ms_sensors_tp_read_prom(struct ms_tp_dev *dev_data) return 0; } -EXPORT_SYMBOL(ms_sensors_tp_read_prom); +EXPORT_SYMBOL_NS(ms_sensors_tp_read_prom, IIO_MEAS_SPEC_SENSORS); /** * ms_sensors_read_temp_and_pressure() - read temp and pressure @@ -688,7 +688,7 @@ int ms_sensors_read_temp_and_pressure(struct ms_tp_dev *dev_data, return 0; } -EXPORT_SYMBOL(ms_sensors_read_temp_and_pressure); +EXPORT_SYMBOL_NS(ms_sensors_read_temp_and_pressure, IIO_MEAS_SPEC_SENSORS); MODULE_DESCRIPTION("Measurement-Specialties common i2c driver"); MODULE_AUTHOR("William Markezana "); diff --git a/drivers/iio/humidity/htu21.c b/drivers/iio/humidity/htu21.c index 36df2a102ca4..fd9e2565f8a2 100644 --- a/drivers/iio/humidity/htu21.c +++ b/drivers/iio/humidity/htu21.c @@ -258,3 +258,4 @@ MODULE_DESCRIPTION("Measurement-Specialties htu21 temperature and humidity drive MODULE_AUTHOR("William Markezana "); MODULE_AUTHOR("Ludovic Tancerel "); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS(IIO_MEAS_SPEC_SENSORS); diff --git a/drivers/iio/pressure/ms5637.c b/drivers/iio/pressure/ms5637.c index 81f683321b23..70c70019142a 100644 --- a/drivers/iio/pressure/ms5637.c +++ b/drivers/iio/pressure/ms5637.c @@ -252,3 +252,4 @@ MODULE_DESCRIPTION("Measurement-Specialties ms5637 temperature & pressure driver MODULE_AUTHOR("William Markezana "); MODULE_AUTHOR("Ludovic Tancerel "); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS(IIO_MEAS_SPEC_SENSORS); diff --git a/drivers/iio/temperature/tsys01.c b/drivers/iio/temperature/tsys01.c index bbfbad9a8767..60d58ec5b063 100644 --- a/drivers/iio/temperature/tsys01.c +++ b/drivers/iio/temperature/tsys01.c @@ -233,3 +233,4 @@ MODULE_DESCRIPTION("Measurement-Specialties tsys01 temperature driver"); MODULE_AUTHOR("William Markezana "); MODULE_AUTHOR("Ludovic Tancerel "); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS(IIO_MEAS_SPEC_SENSORS); diff --git a/drivers/iio/temperature/tsys02d.c b/drivers/iio/temperature/tsys02d.c index fc96e5f9d3fc..49c275e4f510 100644 --- a/drivers/iio/temperature/tsys02d.c +++ b/drivers/iio/temperature/tsys02d.c @@ -187,3 +187,4 @@ MODULE_DESCRIPTION("Measurement-Specialties tsys02d temperature driver"); MODULE_AUTHOR("William Markezana "); MODULE_AUTHOR("Ludovic Tancerel "); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS(IIO_MEAS_SPEC_SENSORS); -- cgit v1.2.3 From 0a1b56b7b3c65cb137665a9cf14a126e02123119 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 30 Jan 2022 20:56:50 +0000 Subject: iio:common:ssp_sensors: Move exports into IIO_SSP_SENSORS namespace In order to avoid unnecessary pollution of the global symbol namespace move the common/library functions into a specific namespace and import that into the various specific device drivers that use them. For more information see https://lwn.net/Articles/760045/ Both the exports used between the two common modules and the individual drivers are moved to a single namespace as greater granularity does not feel useful. Signed-off-by: Jonathan Cameron Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220130205701.334592-6-jic23@kernel.org --- drivers/iio/accel/ssp_accel_sensor.c | 1 + drivers/iio/common/ssp_sensors/ssp_dev.c | 10 +++++----- drivers/iio/common/ssp_sensors/ssp_iio.c | 7 ++++--- drivers/iio/gyro/ssp_gyro_sensor.c | 1 + 4 files changed, 11 insertions(+), 8 deletions(-) diff --git a/drivers/iio/accel/ssp_accel_sensor.c b/drivers/iio/accel/ssp_accel_sensor.c index 04dcb2b657ee..a1164b439f41 100644 --- a/drivers/iio/accel/ssp_accel_sensor.c +++ b/drivers/iio/accel/ssp_accel_sensor.c @@ -142,3 +142,4 @@ module_platform_driver(ssp_accel_driver); MODULE_AUTHOR("Karol Wrona "); MODULE_DESCRIPTION("Samsung sensorhub accelerometers driver"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(IIO_SSP_SENSORS); diff --git a/drivers/iio/common/ssp_sensors/ssp_dev.c b/drivers/iio/common/ssp_sensors/ssp_dev.c index a2b91a7504bc..a60c11481b03 100644 --- a/drivers/iio/common/ssp_sensors/ssp_dev.c +++ b/drivers/iio/common/ssp_sensors/ssp_dev.c @@ -205,7 +205,7 @@ u32 ssp_get_sensor_delay(struct ssp_data *data, enum ssp_sensor_type type) { return data->delay_buf[type]; } -EXPORT_SYMBOL(ssp_get_sensor_delay); +EXPORT_SYMBOL_NS(ssp_get_sensor_delay, IIO_SSP_SENSORS); /** * ssp_enable_sensor() - enables data acquisition for sensor @@ -267,7 +267,7 @@ int ssp_enable_sensor(struct ssp_data *data, enum ssp_sensor_type type, derror: return ret; } -EXPORT_SYMBOL(ssp_enable_sensor); +EXPORT_SYMBOL_NS(ssp_enable_sensor, IIO_SSP_SENSORS); /** * ssp_change_delay() - changes data acquisition for sensor @@ -298,7 +298,7 @@ int ssp_change_delay(struct ssp_data *data, enum ssp_sensor_type type, return 0; } -EXPORT_SYMBOL(ssp_change_delay); +EXPORT_SYMBOL_NS(ssp_change_delay, IIO_SSP_SENSORS); /** * ssp_disable_sensor() - disables sensor @@ -335,7 +335,7 @@ int ssp_disable_sensor(struct ssp_data *data, enum ssp_sensor_type type) return 0; } -EXPORT_SYMBOL(ssp_disable_sensor); +EXPORT_SYMBOL_NS(ssp_disable_sensor, IIO_SSP_SENSORS); static irqreturn_t ssp_irq_thread_fn(int irq, void *dev_id) { @@ -478,7 +478,7 @@ void ssp_register_consumer(struct iio_dev *indio_dev, enum ssp_sensor_type type) data->sensor_devs[type] = indio_dev; } -EXPORT_SYMBOL(ssp_register_consumer); +EXPORT_SYMBOL_NS(ssp_register_consumer, IIO_SSP_SENSORS); static int ssp_probe(struct spi_device *spi) { diff --git a/drivers/iio/common/ssp_sensors/ssp_iio.c b/drivers/iio/common/ssp_sensors/ssp_iio.c index 5336db81ba0a..88b8b56bfa51 100644 --- a/drivers/iio/common/ssp_sensors/ssp_iio.c +++ b/drivers/iio/common/ssp_sensors/ssp_iio.c @@ -32,7 +32,7 @@ int ssp_common_buffer_postenable(struct iio_dev *indio_dev) return ssp_enable_sensor(data, spd->type, ssp_get_sensor_delay(data, spd->type)); } -EXPORT_SYMBOL(ssp_common_buffer_postenable); +EXPORT_SYMBOL_NS(ssp_common_buffer_postenable, IIO_SSP_SENSORS); /** * ssp_common_buffer_postdisable() - generic postdisable callback for ssp buffer @@ -55,7 +55,7 @@ int ssp_common_buffer_postdisable(struct iio_dev *indio_dev) return ret; } -EXPORT_SYMBOL(ssp_common_buffer_postdisable); +EXPORT_SYMBOL_NS(ssp_common_buffer_postdisable, IIO_SSP_SENSORS); /** * ssp_common_process_data() - Common process data callback for ssp sensors @@ -91,8 +91,9 @@ int ssp_common_process_data(struct iio_dev *indio_dev, void *buf, return iio_push_to_buffers_with_timestamp(indio_dev, spd->buffer, calculated_time); } -EXPORT_SYMBOL(ssp_common_process_data); +EXPORT_SYMBOL_NS(ssp_common_process_data, IIO_SSP_SENSORS); MODULE_AUTHOR("Karol Wrona "); MODULE_DESCRIPTION("Samsung sensorhub commons"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(IIO_SSP_SENSORS); diff --git a/drivers/iio/gyro/ssp_gyro_sensor.c b/drivers/iio/gyro/ssp_gyro_sensor.c index 46ed12771d2f..5fd1bf9902ea 100644 --- a/drivers/iio/gyro/ssp_gyro_sensor.c +++ b/drivers/iio/gyro/ssp_gyro_sensor.c @@ -142,3 +142,4 @@ module_platform_driver(ssp_gyro_driver); MODULE_AUTHOR("Karol Wrona "); MODULE_DESCRIPTION("Samsung sensorhub gyroscopes driver"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(IIO_SSP_SENSORS); -- cgit v1.2.3 From 4dcd738473f211a8546eceeb466e5bc1698849c7 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 30 Jan 2022 20:56:51 +0000 Subject: iio:dac:ad5592r: Move exports into IIO_AD5592R namespace In order to avoid unnecessary pollution of the global symbol namespace move the common/library functions into a specific namespace and import that into the various specific device drivers that use them. For more information see https://lwn.net/Articles/760045/ Signed-off-by: Jonathan Cameron Cc: Paul Cercueil Reviewed-by: Paul Cercueil Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220130205701.334592-7-jic23@kernel.org --- drivers/iio/dac/ad5592r-base.c | 4 ++-- drivers/iio/dac/ad5592r.c | 1 + drivers/iio/dac/ad5593r.c | 1 + 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/iio/dac/ad5592r-base.c b/drivers/iio/dac/ad5592r-base.c index a9c654b614a4..a424b7220b61 100644 --- a/drivers/iio/dac/ad5592r-base.c +++ b/drivers/iio/dac/ad5592r-base.c @@ -660,7 +660,7 @@ error_disable_reg: return ret; } -EXPORT_SYMBOL_GPL(ad5592r_probe); +EXPORT_SYMBOL_NS_GPL(ad5592r_probe, IIO_AD5592R); void ad5592r_remove(struct device *dev) { @@ -674,7 +674,7 @@ void ad5592r_remove(struct device *dev) if (st->reg) regulator_disable(st->reg); } -EXPORT_SYMBOL_GPL(ad5592r_remove); +EXPORT_SYMBOL_NS_GPL(ad5592r_remove, IIO_AD5592R); MODULE_AUTHOR("Paul Cercueil "); MODULE_DESCRIPTION("Analog Devices AD5592R multi-channel converters"); diff --git a/drivers/iio/dac/ad5592r.c b/drivers/iio/dac/ad5592r.c index 6bfd7951e18c..1572279b04bb 100644 --- a/drivers/iio/dac/ad5592r.c +++ b/drivers/iio/dac/ad5592r.c @@ -170,3 +170,4 @@ module_spi_driver(ad5592r_spi_driver); MODULE_AUTHOR("Paul Cercueil "); MODULE_DESCRIPTION("Analog Devices AD5592R multi-channel converters"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS(IIO_AD5592R); diff --git a/drivers/iio/dac/ad5593r.c b/drivers/iio/dac/ad5593r.c index 64dd7a0bddf7..34e1319a9712 100644 --- a/drivers/iio/dac/ad5593r.c +++ b/drivers/iio/dac/ad5593r.c @@ -137,3 +137,4 @@ module_i2c_driver(ad5593r_driver); MODULE_AUTHOR("Paul Cercueil "); MODULE_DESCRIPTION("Analog Devices AD5593R multi-channel converters"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS(IIO_AD5592R); -- cgit v1.2.3 From 2ebc23b34c7faf3f7018becca0a1078e2b9405e8 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 30 Jan 2022 20:56:52 +0000 Subject: iio:dac:ad5686: Move exports into IIO_AD5686 namespace Note these are used in the related ad5696-i2c drivers as well as the more obviously connected ad5686-spi driver. In order to avoid unnecessary pollution of the global symbol namespace move the common/library functions into a specific namespace and import that into the various specific device drivers that use them. For more information see https://lwn.net/Articles/760045/ Signed-off-by: Jonathan Cameron Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220130205701.334592-8-jic23@kernel.org --- drivers/iio/dac/ad5686-spi.c | 1 + drivers/iio/dac/ad5686.c | 4 ++-- drivers/iio/dac/ad5696-i2c.c | 1 + 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/iio/dac/ad5686-spi.c b/drivers/iio/dac/ad5686-spi.c index 2628810fdbb1..75b54c5ba39f 100644 --- a/drivers/iio/dac/ad5686-spi.c +++ b/drivers/iio/dac/ad5686-spi.c @@ -137,3 +137,4 @@ module_spi_driver(ad5686_spi_driver); MODULE_AUTHOR("Stefan Popa "); MODULE_DESCRIPTION("Analog Devices AD5686 and similar multi-channel DACs"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS(IIO_AD5686); diff --git a/drivers/iio/dac/ad5686.c b/drivers/iio/dac/ad5686.c index e592a995f404..f78dd3f33199 100644 --- a/drivers/iio/dac/ad5686.c +++ b/drivers/iio/dac/ad5686.c @@ -536,7 +536,7 @@ error_disable_reg: regulator_disable(st->reg); return ret; } -EXPORT_SYMBOL_GPL(ad5686_probe); +EXPORT_SYMBOL_NS_GPL(ad5686_probe, IIO_AD5686); void ad5686_remove(struct device *dev) { @@ -547,7 +547,7 @@ void ad5686_remove(struct device *dev) if (!IS_ERR(st->reg)) regulator_disable(st->reg); } -EXPORT_SYMBOL_GPL(ad5686_remove); +EXPORT_SYMBOL_NS_GPL(ad5686_remove, IIO_AD5686); MODULE_AUTHOR("Michael Hennerich "); MODULE_DESCRIPTION("Analog Devices AD5686/85/84 DAC"); diff --git a/drivers/iio/dac/ad5696-i2c.c b/drivers/iio/dac/ad5696-i2c.c index 93f0e0e66c22..762503c1901b 100644 --- a/drivers/iio/dac/ad5696-i2c.c +++ b/drivers/iio/dac/ad5696-i2c.c @@ -125,3 +125,4 @@ module_i2c_driver(ad5686_i2c_driver); MODULE_AUTHOR("Stefan Popa "); MODULE_DESCRIPTION("Analog Devices AD5686 and similar multi-channel DACs"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS(IIO_AD5686); -- cgit v1.2.3 From 6c9304d6af122f9afea41885ad82ed627e9442a8 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 30 Jan 2022 20:56:53 +0000 Subject: iio:imu:adis: Move exports into IIO_ADISLIB namespace In order to avoid unneessary pollution of the global symbol namespace move the common/library functions into a specific namespace and import that into the various specific device drivers that use them. Signed-off-by: Jonathan Cameron Cc: Lars-Peter Clausen Cc: Song Bao Hua (Barry Song) Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220130205701.334592-9-jic23@kernel.org --- drivers/iio/accel/adis16201.c | 1 + drivers/iio/accel/adis16209.c | 1 + drivers/iio/gyro/adis16136.c | 1 + drivers/iio/gyro/adis16260.c | 1 + drivers/iio/imu/adis.c | 20 ++++++++++---------- drivers/iio/imu/adis16400.c | 1 + drivers/iio/imu/adis16460.c | 1 + drivers/iio/imu/adis16475.c | 1 + drivers/iio/imu/adis16480.c | 1 + drivers/iio/imu/adis_buffer.c | 4 ++-- drivers/iio/imu/adis_trigger.c | 2 +- drivers/staging/iio/accel/adis16203.c | 1 + drivers/staging/iio/accel/adis16240.c | 1 + 13 files changed, 23 insertions(+), 13 deletions(-) diff --git a/drivers/iio/accel/adis16201.c b/drivers/iio/accel/adis16201.c index 7a434e2884d4..dfb8e2e5bdf5 100644 --- a/drivers/iio/accel/adis16201.c +++ b/drivers/iio/accel/adis16201.c @@ -300,3 +300,4 @@ MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>"); MODULE_DESCRIPTION("Analog Devices ADIS16201 Dual-Axis Digital Inclinometer and Accelerometer"); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("spi:adis16201"); +MODULE_IMPORT_NS(IIO_ADISLIB); diff --git a/drivers/iio/accel/adis16209.c b/drivers/iio/accel/adis16209.c index ac08e866d612..5a9c6e2296f1 100644 --- a/drivers/iio/accel/adis16209.c +++ b/drivers/iio/accel/adis16209.c @@ -310,3 +310,4 @@ MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>"); MODULE_DESCRIPTION("Analog Devices ADIS16209 Dual-Axis Digital Inclinometer and Accelerometer"); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("spi:adis16209"); +MODULE_IMPORT_NS(IIO_ADISLIB); diff --git a/drivers/iio/gyro/adis16136.c b/drivers/iio/gyro/adis16136.c index 36879f01e28c..71295709f2b9 100644 --- a/drivers/iio/gyro/adis16136.c +++ b/drivers/iio/gyro/adis16136.c @@ -591,3 +591,4 @@ module_spi_driver(adis16136_driver); MODULE_AUTHOR("Lars-Peter Clausen "); MODULE_DESCRIPTION("Analog Devices ADIS16133/ADIS16135/ADIS16136 gyroscope driver"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS(IIO_ADISLIB); diff --git a/drivers/iio/gyro/adis16260.c b/drivers/iio/gyro/adis16260.c index 66b6b7bd5e1b..eaf57bd339ed 100644 --- a/drivers/iio/gyro/adis16260.c +++ b/drivers/iio/gyro/adis16260.c @@ -433,3 +433,4 @@ module_spi_driver(adis16260_driver); MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>"); MODULE_DESCRIPTION("Analog Devices ADIS16260/5 Digital Gyroscope Sensor"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS(IIO_ADISLIB); diff --git a/drivers/iio/imu/adis.c b/drivers/iio/imu/adis.c index 638957001653..f7fcfd04f659 100644 --- a/drivers/iio/imu/adis.c +++ b/drivers/iio/imu/adis.c @@ -121,7 +121,7 @@ int __adis_write_reg(struct adis *adis, unsigned int reg, unsigned int value, return ret; } -EXPORT_SYMBOL_GPL(__adis_write_reg); +EXPORT_SYMBOL_NS_GPL(__adis_write_reg, IIO_ADISLIB); /** * __adis_read_reg() - read N bytes from register (unlocked version) @@ -218,7 +218,7 @@ int __adis_read_reg(struct adis *adis, unsigned int reg, unsigned int *val, return ret; } -EXPORT_SYMBOL_GPL(__adis_read_reg); +EXPORT_SYMBOL_NS_GPL(__adis_read_reg, IIO_ADISLIB); /** * __adis_update_bits_base() - ADIS Update bits function - Unlocked version * @adis: The adis device @@ -243,7 +243,7 @@ int __adis_update_bits_base(struct adis *adis, unsigned int reg, const u32 mask, return __adis_write_reg(adis, reg, __val, size); } -EXPORT_SYMBOL_GPL(__adis_update_bits_base); +EXPORT_SYMBOL_NS_GPL(__adis_update_bits_base, IIO_ADISLIB); #ifdef CONFIG_DEBUG_FS @@ -265,7 +265,7 @@ int adis_debugfs_reg_access(struct iio_dev *indio_dev, unsigned int reg, return adis_write_reg_16(adis, reg, writeval); } -EXPORT_SYMBOL(adis_debugfs_reg_access); +EXPORT_SYMBOL_NS(adis_debugfs_reg_access, IIO_ADISLIB); #endif @@ -314,7 +314,7 @@ out_unlock: mutex_unlock(&adis->state_lock); return ret; } -EXPORT_SYMBOL(adis_enable_irq); +EXPORT_SYMBOL_NS(adis_enable_irq, IIO_ADISLIB); /** * __adis_check_status() - Check the device for error conditions (unlocked) @@ -346,7 +346,7 @@ int __adis_check_status(struct adis *adis) return -EIO; } -EXPORT_SYMBOL_GPL(__adis_check_status); +EXPORT_SYMBOL_NS_GPL(__adis_check_status, IIO_ADISLIB); /** * __adis_reset() - Reset the device (unlocked version) @@ -370,7 +370,7 @@ int __adis_reset(struct adis *adis) return 0; } -EXPORT_SYMBOL_GPL(__adis_reset); +EXPORT_SYMBOL_NS_GPL(__adis_reset, IIO_ADIS_LIB); static int adis_self_test(struct adis *adis) { @@ -461,7 +461,7 @@ int __adis_initial_startup(struct adis *adis) return 0; } -EXPORT_SYMBOL_GPL(__adis_initial_startup); +EXPORT_SYMBOL_NS_GPL(__adis_initial_startup, IIO_ADISLIB); /** * adis_single_conversion() - Performs a single sample conversion @@ -509,7 +509,7 @@ err_unlock: mutex_unlock(&adis->state_lock); return ret; } -EXPORT_SYMBOL_GPL(adis_single_conversion); +EXPORT_SYMBOL_NS_GPL(adis_single_conversion, IIO_ADISLIB); /** * adis_init() - Initialize adis device structure @@ -546,7 +546,7 @@ int adis_init(struct adis *adis, struct iio_dev *indio_dev, return 0; } -EXPORT_SYMBOL_GPL(adis_init); +EXPORT_SYMBOL_NS_GPL(adis_init, IIO_ADISLIB); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Lars-Peter Clausen "); diff --git a/drivers/iio/imu/adis16400.c b/drivers/iio/imu/adis16400.c index 9fd30e62d6e8..17bb0c40a149 100644 --- a/drivers/iio/imu/adis16400.c +++ b/drivers/iio/imu/adis16400.c @@ -1240,3 +1240,4 @@ module_spi_driver(adis16400_driver); MODULE_AUTHOR("Manuel Stahl "); MODULE_DESCRIPTION("Analog Devices ADIS16400/5 IMU SPI driver"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS(IIO_ADISLIB); diff --git a/drivers/iio/imu/adis16460.c b/drivers/iio/imu/adis16460.c index b01988170118..69facd72bd7d 100644 --- a/drivers/iio/imu/adis16460.c +++ b/drivers/iio/imu/adis16460.c @@ -428,3 +428,4 @@ module_spi_driver(adis16460_driver); MODULE_AUTHOR("Dragos Bogdan "); MODULE_DESCRIPTION("Analog Devices ADIS16460 IMU driver"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(IIO_ADISLIB); diff --git a/drivers/iio/imu/adis16475.c b/drivers/iio/imu/adis16475.c index ea91d127077d..ff2b0fab840a 100644 --- a/drivers/iio/imu/adis16475.c +++ b/drivers/iio/imu/adis16475.c @@ -1365,3 +1365,4 @@ module_spi_driver(adis16475_driver); MODULE_AUTHOR("Nuno Sa "); MODULE_DESCRIPTION("Analog Devices ADIS16475 IMU driver"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(IIO_ADISLIB); diff --git a/drivers/iio/imu/adis16480.c b/drivers/iio/imu/adis16480.c index ed129321a14d..0419cc3d5fe2 100644 --- a/drivers/iio/imu/adis16480.c +++ b/drivers/iio/imu/adis16480.c @@ -1533,3 +1533,4 @@ module_spi_driver(adis16480_driver); MODULE_AUTHOR("Lars-Peter Clausen "); MODULE_DESCRIPTION("Analog Devices ADIS16480 IMU driver"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS(IIO_ADISLIB); diff --git a/drivers/iio/imu/adis_buffer.c b/drivers/iio/imu/adis_buffer.c index d3527cf5ed37..928933027ae3 100644 --- a/drivers/iio/imu/adis_buffer.c +++ b/drivers/iio/imu/adis_buffer.c @@ -124,7 +124,7 @@ int adis_update_scan_mode(struct iio_dev *indio_dev, return 0; } -EXPORT_SYMBOL_GPL(adis_update_scan_mode); +EXPORT_SYMBOL_NS_GPL(adis_update_scan_mode, IIO_ADISLIB); static irqreturn_t adis_trigger_handler(int irq, void *p) { @@ -212,5 +212,5 @@ devm_adis_setup_buffer_and_trigger(struct adis *adis, struct iio_dev *indio_dev, return devm_add_action_or_reset(&adis->spi->dev, adis_buffer_cleanup, adis); } -EXPORT_SYMBOL_GPL(devm_adis_setup_buffer_and_trigger); +EXPORT_SYMBOL_NS_GPL(devm_adis_setup_buffer_and_trigger, IIO_ADISLIB); diff --git a/drivers/iio/imu/adis_trigger.c b/drivers/iio/imu/adis_trigger.c index 0e7fb00ba241..f890bf842db8 100644 --- a/drivers/iio/imu/adis_trigger.c +++ b/drivers/iio/imu/adis_trigger.c @@ -87,5 +87,5 @@ int devm_adis_probe_trigger(struct adis *adis, struct iio_dev *indio_dev) return devm_iio_trigger_register(&adis->spi->dev, adis->trig); } -EXPORT_SYMBOL_GPL(devm_adis_probe_trigger); +EXPORT_SYMBOL_NS_GPL(devm_adis_probe_trigger, IIO_ADISLIB); diff --git a/drivers/staging/iio/accel/adis16203.c b/drivers/staging/iio/accel/adis16203.c index 1d3026dae827..62d5397ff1f9 100644 --- a/drivers/staging/iio/accel/adis16203.c +++ b/drivers/staging/iio/accel/adis16203.c @@ -312,3 +312,4 @@ MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>"); MODULE_DESCRIPTION("Analog Devices ADIS16203 Programmable 360 Degrees Inclinometer"); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("spi:adis16203"); +MODULE_IMPORT_NS(IIO_ADISLIB); diff --git a/drivers/staging/iio/accel/adis16240.c b/drivers/staging/iio/accel/adis16240.c index 2a8aa83b8d9e..bca857eef92e 100644 --- a/drivers/staging/iio/accel/adis16240.c +++ b/drivers/staging/iio/accel/adis16240.c @@ -440,3 +440,4 @@ MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>"); MODULE_DESCRIPTION("Analog Devices Programmable Impact Sensor and Recorder"); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("spi:adis16240"); +MODULE_IMPORT_NS(IIO_ADISLIB); -- cgit v1.2.3 From c8629ec92cb2a2e24bed4509d13c88b0cf5525c4 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 30 Jan 2022 20:56:54 +0000 Subject: iio:pressure:zpa2326: Move exports into IIO_ZPA2326 namespace In order to avoid unnecessary pollution of the global symbol namespace move the common/library functions into a specific namespace and import that into the bus specific device drivers that use them. For more information see https://lwn.net/Articles/760045/ Signed-off-by: Jonathan Cameron Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220130205701.334592-10-jic23@kernel.org --- drivers/iio/pressure/zpa2326.c | 12 ++++++------ drivers/iio/pressure/zpa2326_i2c.c | 1 + drivers/iio/pressure/zpa2326_spi.c | 1 + 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/iio/pressure/zpa2326.c b/drivers/iio/pressure/zpa2326.c index 89295c90f801..67119a9b95fc 100644 --- a/drivers/iio/pressure/zpa2326.c +++ b/drivers/iio/pressure/zpa2326.c @@ -162,7 +162,7 @@ bool zpa2326_isreg_writeable(struct device *dev, unsigned int reg) return false; } } -EXPORT_SYMBOL_GPL(zpa2326_isreg_writeable); +EXPORT_SYMBOL_NS_GPL(zpa2326_isreg_writeable, IIO_ZPA2326); bool zpa2326_isreg_readable(struct device *dev, unsigned int reg) { @@ -191,7 +191,7 @@ bool zpa2326_isreg_readable(struct device *dev, unsigned int reg) return false; } } -EXPORT_SYMBOL_GPL(zpa2326_isreg_readable); +EXPORT_SYMBOL_NS_GPL(zpa2326_isreg_readable, IIO_ZPA2326); bool zpa2326_isreg_precious(struct device *dev, unsigned int reg) { @@ -204,7 +204,7 @@ bool zpa2326_isreg_precious(struct device *dev, unsigned int reg) return false; } } -EXPORT_SYMBOL_GPL(zpa2326_isreg_precious); +EXPORT_SYMBOL_NS_GPL(zpa2326_isreg_precious, IIO_ZPA2326); /** * zpa2326_enable_device() - Enable device, i.e. get out of low power mode. @@ -649,7 +649,7 @@ const struct dev_pm_ops zpa2326_pm_ops = { SET_RUNTIME_PM_OPS(zpa2326_runtime_suspend, zpa2326_runtime_resume, NULL) }; -EXPORT_SYMBOL_GPL(zpa2326_pm_ops); +EXPORT_SYMBOL_NS_GPL(zpa2326_pm_ops, IIO_ZPA2326); /** * zpa2326_resume() - Request the PM layer to power supply the device. @@ -1698,7 +1698,7 @@ poweroff: return err; } -EXPORT_SYMBOL_GPL(zpa2326_probe); +EXPORT_SYMBOL_NS_GPL(zpa2326_probe, IIO_ZPA2326); void zpa2326_remove(const struct device *parent) { @@ -1709,7 +1709,7 @@ void zpa2326_remove(const struct device *parent) zpa2326_sleep(indio_dev); zpa2326_power_off(indio_dev, iio_priv(indio_dev)); } -EXPORT_SYMBOL_GPL(zpa2326_remove); +EXPORT_SYMBOL_NS_GPL(zpa2326_remove, IIO_ZPA2326); MODULE_AUTHOR("Gregor Boirie "); MODULE_DESCRIPTION("Core driver for Murata ZPA2326 pressure sensor"); diff --git a/drivers/iio/pressure/zpa2326_i2c.c b/drivers/iio/pressure/zpa2326_i2c.c index 95d9739444c4..0db0860d386b 100644 --- a/drivers/iio/pressure/zpa2326_i2c.c +++ b/drivers/iio/pressure/zpa2326_i2c.c @@ -87,3 +87,4 @@ module_i2c_driver(zpa2326_i2c_driver); MODULE_AUTHOR("Gregor Boirie "); MODULE_DESCRIPTION("I2C driver for Murata ZPA2326 pressure sensor"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS(IIO_ZPA2326); diff --git a/drivers/iio/pressure/zpa2326_spi.c b/drivers/iio/pressure/zpa2326_spi.c index 85201a4bae44..5fbd2586c4ea 100644 --- a/drivers/iio/pressure/zpa2326_spi.c +++ b/drivers/iio/pressure/zpa2326_spi.c @@ -91,3 +91,4 @@ module_spi_driver(zpa2326_spi_driver); MODULE_AUTHOR("Gregor Boirie "); MODULE_DESCRIPTION("SPI driver for Murata ZPA2326 pressure sensor"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS(IIO_ZPA2326); -- cgit v1.2.3 From 1980d4a1bae068935da597abaacdfb26c4132e88 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 30 Jan 2022 20:56:55 +0000 Subject: iio:pressure:ms5611: Move exports into IIO_MS5611 namespace In order to avoid unnecessary pollution of the global symbol namespace move the common/library functions into a specific namespace and import that into the bus specific device drivers that use them. For more information see https://lwn.net/Articles/760045/ Signed-off-by: Jonathan Cameron Cc: Tomasz Duszynski Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220130205701.334592-11-jic23@kernel.org --- drivers/iio/pressure/ms5611_core.c | 4 ++-- drivers/iio/pressure/ms5611_i2c.c | 1 + drivers/iio/pressure/ms5611_spi.c | 1 + 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/iio/pressure/ms5611_core.c b/drivers/iio/pressure/ms5611_core.c index a4d0b54cde9b..717521de66c4 100644 --- a/drivers/iio/pressure/ms5611_core.c +++ b/drivers/iio/pressure/ms5611_core.c @@ -471,7 +471,7 @@ err_fini: ms5611_fini(indio_dev); return ret; } -EXPORT_SYMBOL(ms5611_probe); +EXPORT_SYMBOL_NS(ms5611_probe, IIO_MS5611); void ms5611_remove(struct iio_dev *indio_dev) { @@ -479,7 +479,7 @@ void ms5611_remove(struct iio_dev *indio_dev) iio_triggered_buffer_cleanup(indio_dev); ms5611_fini(indio_dev); } -EXPORT_SYMBOL(ms5611_remove); +EXPORT_SYMBOL_NS(ms5611_remove, IIO_MS5611); MODULE_AUTHOR("Tomasz Duszynski "); MODULE_DESCRIPTION("MS5611 core driver"); diff --git a/drivers/iio/pressure/ms5611_i2c.c b/drivers/iio/pressure/ms5611_i2c.c index 1047a85527a9..3b1de71e0d15 100644 --- a/drivers/iio/pressure/ms5611_i2c.c +++ b/drivers/iio/pressure/ms5611_i2c.c @@ -140,3 +140,4 @@ module_i2c_driver(ms5611_driver); MODULE_AUTHOR("Tomasz Duszynski "); MODULE_DESCRIPTION("MS5611 i2c driver"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS(IIO_MS5611); diff --git a/drivers/iio/pressure/ms5611_spi.c b/drivers/iio/pressure/ms5611_spi.c index 9fa2dcd71760..281b08398720 100644 --- a/drivers/iio/pressure/ms5611_spi.c +++ b/drivers/iio/pressure/ms5611_spi.c @@ -142,3 +142,4 @@ module_spi_driver(ms5611_driver); MODULE_AUTHOR("Tomasz Duszynski "); MODULE_DESCRIPTION("MS5611 spi driver"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS(IIO_MS5611); -- cgit v1.2.3 From c7c848b05fb86aeb7fc8019f72f0462a7406e7a3 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 30 Jan 2022 20:56:56 +0000 Subject: iio:pressure:mpl115: Move exports into IIO_MPL115 namespace In order to avoid unnecessary pollution of the global symbol namespace move the common/library functions into a specific namespace and import that into the bus specific device drivers that use them. For more information see https://lwn.net/Articles/760045/ Signed-off-by: Jonathan Cameron Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220130205701.334592-12-jic23@kernel.org --- drivers/iio/pressure/mpl115.c | 2 +- drivers/iio/pressure/mpl115_i2c.c | 1 + drivers/iio/pressure/mpl115_spi.c | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/iio/pressure/mpl115.c b/drivers/iio/pressure/mpl115.c index 81f288312a28..5bf5b9abe6f1 100644 --- a/drivers/iio/pressure/mpl115.c +++ b/drivers/iio/pressure/mpl115.c @@ -187,7 +187,7 @@ int mpl115_probe(struct device *dev, const char *name, return devm_iio_device_register(dev, indio_dev); } -EXPORT_SYMBOL_GPL(mpl115_probe); +EXPORT_SYMBOL_NS_GPL(mpl115_probe, IIO_MPL115); MODULE_AUTHOR("Peter Meerwald "); MODULE_DESCRIPTION("Freescale MPL115 pressure/temperature driver"); diff --git a/drivers/iio/pressure/mpl115_i2c.c b/drivers/iio/pressure/mpl115_i2c.c index ac1f12bcb65e..099ab1c6832c 100644 --- a/drivers/iio/pressure/mpl115_i2c.c +++ b/drivers/iio/pressure/mpl115_i2c.c @@ -62,3 +62,4 @@ module_i2c_driver(mpl115_i2c_driver); MODULE_AUTHOR("Peter Meerwald "); MODULE_DESCRIPTION("Freescale MPL115A2 pressure/temperature driver"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(IIO_MPL115); diff --git a/drivers/iio/pressure/mpl115_spi.c b/drivers/iio/pressure/mpl115_spi.c index 4d064f98f56a..7feec87e2704 100644 --- a/drivers/iio/pressure/mpl115_spi.c +++ b/drivers/iio/pressure/mpl115_spi.c @@ -101,3 +101,4 @@ module_spi_driver(mpl115_spi_driver); MODULE_AUTHOR("Akinobu Mita "); MODULE_DESCRIPTION("Freescale MPL115A1 pressure/temperature driver"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(IIO_MPL115); -- cgit v1.2.3 From 230ee6c69c8948e8d997a76daf7a1aa403fc6d5a Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 30 Jan 2022 20:56:57 +0000 Subject: iio:magnetometer:rm3100: Move exports to IIO_RM3100 namespace In order to avoid unnecessary pollution of the global symbol namespace move the common/library functions into a specific namespace and import that into the bus specific device drivers that use them. For more information see https://lwn.net/Articles/760045/ Signed-off-by: Jonathan Cameron Cc: Song Qiang Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220130205701.334592-13-jic23@kernel.org --- drivers/iio/magnetometer/rm3100-core.c | 8 ++++---- drivers/iio/magnetometer/rm3100-i2c.c | 1 + drivers/iio/magnetometer/rm3100-spi.c | 1 + 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/iio/magnetometer/rm3100-core.c b/drivers/iio/magnetometer/rm3100-core.c index 13914273c999..26195733ea3e 100644 --- a/drivers/iio/magnetometer/rm3100-core.c +++ b/drivers/iio/magnetometer/rm3100-core.c @@ -100,7 +100,7 @@ const struct regmap_access_table rm3100_readable_table = { .yes_ranges = rm3100_readable_ranges, .n_yes_ranges = ARRAY_SIZE(rm3100_readable_ranges), }; -EXPORT_SYMBOL_GPL(rm3100_readable_table); +EXPORT_SYMBOL_NS_GPL(rm3100_readable_table, IIO_RM3100); static const struct regmap_range rm3100_writable_ranges[] = { regmap_reg_range(RM3100_W_REG_START, RM3100_W_REG_END), @@ -110,7 +110,7 @@ const struct regmap_access_table rm3100_writable_table = { .yes_ranges = rm3100_writable_ranges, .n_yes_ranges = ARRAY_SIZE(rm3100_writable_ranges), }; -EXPORT_SYMBOL_GPL(rm3100_writable_table); +EXPORT_SYMBOL_NS_GPL(rm3100_writable_table, IIO_RM3100); static const struct regmap_range rm3100_volatile_ranges[] = { regmap_reg_range(RM3100_V_REG_START, RM3100_V_REG_END), @@ -120,7 +120,7 @@ const struct regmap_access_table rm3100_volatile_table = { .yes_ranges = rm3100_volatile_ranges, .n_yes_ranges = ARRAY_SIZE(rm3100_volatile_ranges), }; -EXPORT_SYMBOL_GPL(rm3100_volatile_table); +EXPORT_SYMBOL_NS_GPL(rm3100_volatile_table, IIO_RM3100); static irqreturn_t rm3100_thread_fn(int irq, void *d) { @@ -607,7 +607,7 @@ int rm3100_common_probe(struct device *dev, struct regmap *regmap, int irq) return devm_iio_device_register(dev, indio_dev); } -EXPORT_SYMBOL_GPL(rm3100_common_probe); +EXPORT_SYMBOL_NS_GPL(rm3100_common_probe, IIO_RM3100); MODULE_AUTHOR("Song Qiang "); MODULE_DESCRIPTION("PNI RM3100 3-axis magnetometer i2c driver"); diff --git a/drivers/iio/magnetometer/rm3100-i2c.c b/drivers/iio/magnetometer/rm3100-i2c.c index 1ac622c6d6c9..ba669ab7113d 100644 --- a/drivers/iio/magnetometer/rm3100-i2c.c +++ b/drivers/iio/magnetometer/rm3100-i2c.c @@ -52,3 +52,4 @@ module_i2c_driver(rm3100_driver); MODULE_AUTHOR("Song Qiang "); MODULE_DESCRIPTION("PNI RM3100 3-axis magnetometer i2c driver"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS(IIO_RM3100); diff --git a/drivers/iio/magnetometer/rm3100-spi.c b/drivers/iio/magnetometer/rm3100-spi.c index 65d5eb9e4f5e..76dc9b66cd3c 100644 --- a/drivers/iio/magnetometer/rm3100-spi.c +++ b/drivers/iio/magnetometer/rm3100-spi.c @@ -62,3 +62,4 @@ module_spi_driver(rm3100_driver); MODULE_AUTHOR("Song Qiang "); MODULE_DESCRIPTION("PNI RM3100 3-axis magnetometer spi driver"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS(IIO_RM3100); -- cgit v1.2.3 From 47d6cae0d0ea7477b5ea5f43a5b9be759052566b Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 30 Jan 2022 20:56:58 +0000 Subject: iio:magnetometer:bmc150: Move exports to IIO_BMC150_MAGN namespace In order to avoid unnecessary pollution of the global symbol namespace move the common/library functions into a specific namespace and import that into the bus specific device drivers that use them. Note the MAGN postfix here is reflecting that this driver is only responsible for part of the BMC150 device. For more information see https://lwn.net/Articles/760045/ Signed-off-by: Jonathan Cameron Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220130205701.334592-14-jic23@kernel.org --- drivers/iio/magnetometer/bmc150_magn.c | 8 ++++---- drivers/iio/magnetometer/bmc150_magn_i2c.c | 1 + drivers/iio/magnetometer/bmc150_magn_spi.c | 1 + 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/iio/magnetometer/bmc150_magn.c b/drivers/iio/magnetometer/bmc150_magn.c index f96f53175349..85f8bbf4b793 100644 --- a/drivers/iio/magnetometer/bmc150_magn.c +++ b/drivers/iio/magnetometer/bmc150_magn.c @@ -226,7 +226,7 @@ const struct regmap_config bmc150_magn_regmap_config = { .writeable_reg = bmc150_magn_is_writeable_reg, .volatile_reg = bmc150_magn_is_volatile_reg, }; -EXPORT_SYMBOL(bmc150_magn_regmap_config); +EXPORT_SYMBOL_NS(bmc150_magn_regmap_config, IIO_BMC150_MAGN); static int bmc150_magn_set_power_mode(struct bmc150_magn_data *data, enum bmc150_magn_power_modes mode, @@ -982,7 +982,7 @@ err_poweroff: bmc150_magn_set_power_mode(data, BMC150_MAGN_POWER_MODE_SUSPEND, true); return ret; } -EXPORT_SYMBOL(bmc150_magn_probe); +EXPORT_SYMBOL_NS(bmc150_magn_probe, IIO_BMC150_MAGN); int bmc150_magn_remove(struct device *dev) { @@ -1009,7 +1009,7 @@ int bmc150_magn_remove(struct device *dev) regulator_bulk_disable(ARRAY_SIZE(data->regulators), data->regulators); return 0; } -EXPORT_SYMBOL(bmc150_magn_remove); +EXPORT_SYMBOL_NS(bmc150_magn_remove, IIO_BMC150_MAGN); #ifdef CONFIG_PM static int bmc150_magn_runtime_suspend(struct device *dev) @@ -1077,7 +1077,7 @@ const struct dev_pm_ops bmc150_magn_pm_ops = { SET_RUNTIME_PM_OPS(bmc150_magn_runtime_suspend, bmc150_magn_runtime_resume, NULL) }; -EXPORT_SYMBOL(bmc150_magn_pm_ops); +EXPORT_SYMBOL_NS(bmc150_magn_pm_ops, IIO_BMC150_MAGN); MODULE_AUTHOR("Irina Tirdea "); MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/magnetometer/bmc150_magn_i2c.c b/drivers/iio/magnetometer/bmc150_magn_i2c.c index 876e96005e33..e39b89661ad1 100644 --- a/drivers/iio/magnetometer/bmc150_magn_i2c.c +++ b/drivers/iio/magnetometer/bmc150_magn_i2c.c @@ -80,3 +80,4 @@ module_i2c_driver(bmc150_magn_driver); MODULE_AUTHOR("Daniel Baluta Date: Sun, 30 Jan 2022 20:56:59 +0000 Subject: iio:magnetometer:hmc5843: Move exports to IIO_HMC5843 namespace In order to avoid unnecessary pollution of the global symbol namespace move the common/library functions into a specific namespace and import that into the bus specific device drivers that use them. For more information see https://lwn.net/Articles/760045/ Signed-off-by: Jonathan Cameron Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220130205701.334592-15-jic23@kernel.org --- drivers/iio/magnetometer/hmc5843_core.c | 8 ++++---- drivers/iio/magnetometer/hmc5843_i2c.c | 1 + drivers/iio/magnetometer/hmc5843_spi.c | 1 + 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/iio/magnetometer/hmc5843_core.c b/drivers/iio/magnetometer/hmc5843_core.c index 5a730d9bdbb0..92eb2d156ddb 100644 --- a/drivers/iio/magnetometer/hmc5843_core.c +++ b/drivers/iio/magnetometer/hmc5843_core.c @@ -608,14 +608,14 @@ int hmc5843_common_suspend(struct device *dev) return hmc5843_set_mode(iio_priv(dev_get_drvdata(dev)), HMC5843_MODE_SLEEP); } -EXPORT_SYMBOL(hmc5843_common_suspend); +EXPORT_SYMBOL_NS(hmc5843_common_suspend, IIO_HMC5843); int hmc5843_common_resume(struct device *dev) { return hmc5843_set_mode(iio_priv(dev_get_drvdata(dev)), HMC5843_MODE_CONVERSION_CONTINUOUS); } -EXPORT_SYMBOL(hmc5843_common_resume); +EXPORT_SYMBOL_NS(hmc5843_common_resume, IIO_HMC5843); int hmc5843_common_probe(struct device *dev, struct regmap *regmap, enum hmc5843_ids id, const char *name) @@ -669,7 +669,7 @@ buffer_setup_err: hmc5843_set_mode(iio_priv(indio_dev), HMC5843_MODE_SLEEP); return ret; } -EXPORT_SYMBOL(hmc5843_common_probe); +EXPORT_SYMBOL_NS(hmc5843_common_probe, IIO_HMC5843); void hmc5843_common_remove(struct device *dev) { @@ -681,7 +681,7 @@ void hmc5843_common_remove(struct device *dev) /* sleep mode to save power */ hmc5843_set_mode(iio_priv(indio_dev), HMC5843_MODE_SLEEP); } -EXPORT_SYMBOL(hmc5843_common_remove); +EXPORT_SYMBOL_NS(hmc5843_common_remove, IIO_HMC5843); MODULE_AUTHOR("Shubhrajyoti Datta "); MODULE_DESCRIPTION("HMC5843/5883/5883L/5983 core driver"); diff --git a/drivers/iio/magnetometer/hmc5843_i2c.c b/drivers/iio/magnetometer/hmc5843_i2c.c index bc6e12f1d521..8d2ff8fc204d 100644 --- a/drivers/iio/magnetometer/hmc5843_i2c.c +++ b/drivers/iio/magnetometer/hmc5843_i2c.c @@ -105,3 +105,4 @@ module_i2c_driver(hmc5843_driver); MODULE_AUTHOR("Josef Gajdusek "); MODULE_DESCRIPTION("HMC5843/5883/5883L/5983 i2c driver"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(IIO_HMC5843); diff --git a/drivers/iio/magnetometer/hmc5843_spi.c b/drivers/iio/magnetometer/hmc5843_spi.c index 89cf59a62c28..f2a8e98d8eb5 100644 --- a/drivers/iio/magnetometer/hmc5843_spi.c +++ b/drivers/iio/magnetometer/hmc5843_spi.c @@ -102,3 +102,4 @@ module_spi_driver(hmc5843_driver); MODULE_AUTHOR("Josef Gajdusek "); MODULE_DESCRIPTION("HMC5983 SPI driver"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(IIO_HMC5843); -- cgit v1.2.3 From cfaa5482b3b4e961000e13de7d572401d5d2f30d Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 30 Jan 2022 20:57:00 +0000 Subject: iio:light:st_uvis25: Move exports to IIO_UVIS25 namespace In order to avoid unnecessary pollution of the global symbol namespace move the common/library functions into a specific namespace and import that into the bus specific device drivers that use them. For more information see https://lwn.net/Articles/760045/ Signed-off-by: Jonathan Cameron Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220130205701.334592-16-jic23@kernel.org --- drivers/iio/light/st_uvis25_core.c | 4 ++-- drivers/iio/light/st_uvis25_i2c.c | 1 + drivers/iio/light/st_uvis25_spi.c | 1 + 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/iio/light/st_uvis25_core.c b/drivers/iio/light/st_uvis25_core.c index 41a2ce5a2d53..3d4cc1180b6a 100644 --- a/drivers/iio/light/st_uvis25_core.c +++ b/drivers/iio/light/st_uvis25_core.c @@ -323,7 +323,7 @@ int st_uvis25_probe(struct device *dev, int irq, struct regmap *regmap) return devm_iio_device_register(dev, iio_dev); } -EXPORT_SYMBOL(st_uvis25_probe); +EXPORT_SYMBOL_NS(st_uvis25_probe, IIO_UVIS25); static int __maybe_unused st_uvis25_suspend(struct device *dev) { @@ -349,7 +349,7 @@ static int __maybe_unused st_uvis25_resume(struct device *dev) const struct dev_pm_ops st_uvis25_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(st_uvis25_suspend, st_uvis25_resume) }; -EXPORT_SYMBOL(st_uvis25_pm_ops); +EXPORT_SYMBOL_NS(st_uvis25_pm_ops, IIO_UVIS25); MODULE_AUTHOR("Lorenzo Bianconi "); MODULE_DESCRIPTION("STMicroelectronics uvis25 sensor driver"); diff --git a/drivers/iio/light/st_uvis25_i2c.c b/drivers/iio/light/st_uvis25_i2c.c index 98cd49eefe45..b06d09af28a3 100644 --- a/drivers/iio/light/st_uvis25_i2c.c +++ b/drivers/iio/light/st_uvis25_i2c.c @@ -66,3 +66,4 @@ module_i2c_driver(st_uvis25_driver); MODULE_AUTHOR("Lorenzo Bianconi "); MODULE_DESCRIPTION("STMicroelectronics uvis25 i2c driver"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS(IIO_UVIS25); diff --git a/drivers/iio/light/st_uvis25_spi.c b/drivers/iio/light/st_uvis25_spi.c index af9d94d12787..3a4dc6d7180c 100644 --- a/drivers/iio/light/st_uvis25_spi.c +++ b/drivers/iio/light/st_uvis25_spi.c @@ -66,3 +66,4 @@ module_spi_driver(st_uvis25_driver); MODULE_AUTHOR("Lorenzo Bianconi "); MODULE_DESCRIPTION("STMicroelectronics uvis25 spi driver"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS(IIO_UVIS25); -- cgit v1.2.3 From 146b43d9f1a1bbce43ad8aef2a21f080b59ea006 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 30 Jan 2022 20:57:01 +0000 Subject: iio:chemical:bme680: Move exports to IIO_BME680 namespace In order to avoid unnecessary pollution of the global symbol namespace move the common/library functions into a specific namespace and import that into the bus specific device drivers that use them. For more information see https://lwn.net/Articles/760045/ Signed-off-by: Jonathan Cameron Cc: Himanshu Jha Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220130205701.334592-17-jic23@kernel.org --- drivers/iio/chemical/bme680_core.c | 4 ++-- drivers/iio/chemical/bme680_i2c.c | 1 + drivers/iio/chemical/bme680_spi.c | 1 + 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/iio/chemical/bme680_core.c b/drivers/iio/chemical/bme680_core.c index bf23cc7eb99e..16ff7a98c9f0 100644 --- a/drivers/iio/chemical/bme680_core.c +++ b/drivers/iio/chemical/bme680_core.c @@ -81,7 +81,7 @@ const struct regmap_config bme680_regmap_config = { .volatile_table = &bme680_volatile_table, .cache_type = REGCACHE_RBTREE, }; -EXPORT_SYMBOL(bme680_regmap_config); +EXPORT_SYMBOL_NS(bme680_regmap_config, IIO_BME680); static const struct iio_chan_spec bme680_channels[] = { { @@ -957,7 +957,7 @@ int bme680_core_probe(struct device *dev, struct regmap *regmap, return devm_iio_device_register(dev, indio_dev); } -EXPORT_SYMBOL_GPL(bme680_core_probe); +EXPORT_SYMBOL_NS_GPL(bme680_core_probe, IIO_BME680); MODULE_AUTHOR("Himanshu Jha "); MODULE_DESCRIPTION("Bosch BME680 Driver"); diff --git a/drivers/iio/chemical/bme680_i2c.c b/drivers/iio/chemical/bme680_i2c.c index 74cf89c82c0a..20f2c20b6b02 100644 --- a/drivers/iio/chemical/bme680_i2c.c +++ b/drivers/iio/chemical/bme680_i2c.c @@ -60,3 +60,4 @@ module_i2c_driver(bme680_i2c_driver); MODULE_AUTHOR("Himanshu Jha "); MODULE_DESCRIPTION("BME680 I2C driver"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS(IIO_BME680); diff --git a/drivers/iio/chemical/bme680_spi.c b/drivers/iio/chemical/bme680_spi.c index 0a064a395178..4404d42ae5ec 100644 --- a/drivers/iio/chemical/bme680_spi.c +++ b/drivers/iio/chemical/bme680_spi.c @@ -163,3 +163,4 @@ module_spi_driver(bme680_spi_driver); MODULE_AUTHOR("Himanshu Jha "); MODULE_DESCRIPTION("Bosch BME680 SPI driver"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS(IIO_BME680); -- cgit v1.2.3 From 5d0e9e22e42f796f1f382325d62fe949cdd38066 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 30 Jan 2022 19:30:58 +0000 Subject: iio:accel:da311: Switch from CONFIG_PM_SLEEP guards to pm_sleep_ptr() etc Letting the compiler remove these functions when the kernel is built without CONFIG_PM_SLEEP support is simpler and less error prone than the use of #ifdef based config guards. Removing instances of this approach from IIO also stops them being copied into new drivers. Signed-off-by: Jonathan Cameron Reviewed-by: Paul Cercueil Link: https://lore.kernel.org/r/20220130193147.279148-2-jic23@kernel.org --- drivers/iio/accel/da311.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/iio/accel/da311.c b/drivers/iio/accel/da311.c index 04e13487e706..ec4e29d260f7 100644 --- a/drivers/iio/accel/da311.c +++ b/drivers/iio/accel/da311.c @@ -256,7 +256,6 @@ static int da311_probe(struct i2c_client *client, return devm_iio_device_register(&client->dev, indio_dev); } -#ifdef CONFIG_PM_SLEEP static int da311_suspend(struct device *dev) { return da311_enable(to_i2c_client(dev), false); @@ -266,9 +265,8 @@ static int da311_resume(struct device *dev) { return da311_enable(to_i2c_client(dev), true); } -#endif -static SIMPLE_DEV_PM_OPS(da311_pm_ops, da311_suspend, da311_resume); +static DEFINE_SIMPLE_DEV_PM_OPS(da311_pm_ops, da311_suspend, da311_resume); static const struct i2c_device_id da311_i2c_id[] = { {"da311", 0}, @@ -279,7 +277,7 @@ MODULE_DEVICE_TABLE(i2c, da311_i2c_id); static struct i2c_driver da311_driver = { .driver = { .name = "da311", - .pm = &da311_pm_ops, + .pm = pm_sleep_ptr(&da311_pm_ops), }, .probe = da311_probe, .id_table = da311_i2c_id, -- cgit v1.2.3 From ff9231c7eb739c3d24ae00750e1c614aa47bbb2a Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 30 Jan 2022 19:30:59 +0000 Subject: iio:accel:da280: Switch from CONFIG_PM_SLEEP guards to pm_sleep_ptr() etc Letting the compiler remove these functions when the kernel is built without CONFIG_PM_SLEEP support is simpler and less error prone than the use of #ifdef based config guards. Removing instances of this approach from IIO also stops them being copied into new drivers. Signed-off-by: Jonathan Cameron Reviewed-by: Paul Cercueil Link: https://lore.kernel.org/r/20220130193147.279148-3-jic23@kernel.org --- drivers/iio/accel/da280.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/iio/accel/da280.c b/drivers/iio/accel/da280.c index 9633bdae5fd4..04e9c5678964 100644 --- a/drivers/iio/accel/da280.c +++ b/drivers/iio/accel/da280.c @@ -153,7 +153,6 @@ static int da280_probe(struct i2c_client *client, return devm_iio_device_register(&client->dev, indio_dev); } -#ifdef CONFIG_PM_SLEEP static int da280_suspend(struct device *dev) { return da280_enable(to_i2c_client(dev), false); @@ -163,9 +162,8 @@ static int da280_resume(struct device *dev) { return da280_enable(to_i2c_client(dev), true); } -#endif -static SIMPLE_DEV_PM_OPS(da280_pm_ops, da280_suspend, da280_resume); +static DEFINE_SIMPLE_DEV_PM_OPS(da280_pm_ops, da280_suspend, da280_resume); static const struct acpi_device_id da280_acpi_match[] = { {"MIRAACC", da280}, @@ -184,7 +182,7 @@ static struct i2c_driver da280_driver = { .driver = { .name = "da280", .acpi_match_table = ACPI_PTR(da280_acpi_match), - .pm = &da280_pm_ops, + .pm = pm_sleep_ptr(&da280_pm_ops), }, .probe = da280_probe, .id_table = da280_i2c_id, -- cgit v1.2.3 From 8aa26e20cf05c3e22a26a7b0e6a7d2252aeebf6f Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 30 Jan 2022 19:31:00 +0000 Subject: iio:accel:dmard06: Switch from CONFIG_PM_SLEEP guards to pm_sleep_ptr() etc Letting the compiler remove these functions when the kernel is built without CONFIG_PM_SLEEP support is simpler and less error prone than the use of #ifdef based config guards. Removing instances of this approach from IIO also stops them being copied into new drivers. Signed-off-by: Jonathan Cameron Reviewed-by: Paul Cercueil Link: https://lore.kernel.org/r/20220130193147.279148-4-jic23@kernel.org --- drivers/iio/accel/dmard06.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/drivers/iio/accel/dmard06.c b/drivers/iio/accel/dmard06.c index de2868c28d95..4b69c8530f5e 100644 --- a/drivers/iio/accel/dmard06.c +++ b/drivers/iio/accel/dmard06.c @@ -170,7 +170,6 @@ static int dmard06_probe(struct i2c_client *client, return devm_iio_device_register(&client->dev, indio_dev); } -#ifdef CONFIG_PM_SLEEP static int dmard06_suspend(struct device *dev) { struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); @@ -199,11 +198,8 @@ static int dmard06_resume(struct device *dev) return 0; } -static SIMPLE_DEV_PM_OPS(dmard06_pm_ops, dmard06_suspend, dmard06_resume); -#define DMARD06_PM_OPS (&dmard06_pm_ops) -#else -#define DMARD06_PM_OPS NULL -#endif +static DEFINE_SIMPLE_DEV_PM_OPS(dmard06_pm_ops, dmard06_suspend, + dmard06_resume); static const struct i2c_device_id dmard06_id[] = { { "dmard05", 0 }, @@ -227,7 +223,7 @@ static struct i2c_driver dmard06_driver = { .driver = { .name = DMARD06_DRV_NAME, .of_match_table = dmard06_of_match, - .pm = DMARD06_PM_OPS, + .pm = pm_sleep_ptr(&dmard06_pm_ops), }, }; module_i2c_driver(dmard06_driver); -- cgit v1.2.3 From 50bc5e785121305d3f5f9731dfcdf7c7f2752080 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 30 Jan 2022 19:31:01 +0000 Subject: iio:accel:dmard10: Switch from CONFIG_PM guards to pm_sleep_ptr() etc Letting the compiler remove these functions when the kernel is built without CONFIG_PM_SLEEP support is simpler and less error prone than the use of #ifdef based config guards. Removing instances of this approach from IIO also stops them being copied into new drivers. Signed-off-by: Jonathan Cameron Reviewed-by: Paul Cercueil Link: https://lore.kernel.org/r/20220130193147.279148-5-jic23@kernel.org --- drivers/iio/accel/dmard10.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/iio/accel/dmard10.c b/drivers/iio/accel/dmard10.c index f9f173eec202..8ac62ec0a04a 100644 --- a/drivers/iio/accel/dmard10.c +++ b/drivers/iio/accel/dmard10.c @@ -218,7 +218,6 @@ static int dmard10_probe(struct i2c_client *client, return devm_iio_device_register(&client->dev, indio_dev); } -#ifdef CONFIG_PM_SLEEP static int dmard10_suspend(struct device *dev) { return dmard10_shutdown(to_i2c_client(dev)); @@ -228,9 +227,9 @@ static int dmard10_resume(struct device *dev) { return dmard10_reset(to_i2c_client(dev)); } -#endif -static SIMPLE_DEV_PM_OPS(dmard10_pm_ops, dmard10_suspend, dmard10_resume); +static DEFINE_SIMPLE_DEV_PM_OPS(dmard10_pm_ops, dmard10_suspend, + dmard10_resume); static const struct i2c_device_id dmard10_i2c_id[] = { {"dmard10", 0}, @@ -241,7 +240,7 @@ MODULE_DEVICE_TABLE(i2c, dmard10_i2c_id); static struct i2c_driver dmard10_driver = { .driver = { .name = "dmard10", - .pm = &dmard10_pm_ops, + .pm = pm_sleep_ptr(&dmard10_pm_ops), }, .probe = dmard10_probe, .id_table = dmard10_i2c_id, -- cgit v1.2.3 From 4929ddd0a40d2a3443105d66568b8a6669d783a0 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 30 Jan 2022 19:31:02 +0000 Subject: iio:accel:mc3230: Switch from CONFIG_PM_SLEEP guards to pm_sleep_ptr() etc Letting the compiler remove these functions when the kernel is built without CONFIG_PM_SLEEP support is simpler and less error prone than the use of #ifdef based config guards. Removing instances of this approach from IIO also stops them being copied into new drivers. Signed-off-by: Jonathan Cameron Reviewed-by: Hans de Goede Reviewed-by: Paul Cercueil Link: https://lore.kernel.org/r/20220130193147.279148-6-jic23@kernel.org --- drivers/iio/accel/mc3230.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/iio/accel/mc3230.c b/drivers/iio/accel/mc3230.c index 735002b716f3..679e69cd7657 100644 --- a/drivers/iio/accel/mc3230.c +++ b/drivers/iio/accel/mc3230.c @@ -160,7 +160,6 @@ static int mc3230_remove(struct i2c_client *client) return mc3230_set_opcon(iio_priv(indio_dev), MC3230_MODE_OPCON_STANDBY); } -#ifdef CONFIG_PM_SLEEP static int mc3230_suspend(struct device *dev) { struct mc3230_data *data; @@ -178,9 +177,8 @@ static int mc3230_resume(struct device *dev) return mc3230_set_opcon(data, MC3230_MODE_OPCON_WAKE); } -#endif -static SIMPLE_DEV_PM_OPS(mc3230_pm_ops, mc3230_suspend, mc3230_resume); +static DEFINE_SIMPLE_DEV_PM_OPS(mc3230_pm_ops, mc3230_suspend, mc3230_resume); static const struct i2c_device_id mc3230_i2c_id[] = { {"mc3230", 0}, @@ -191,7 +189,7 @@ MODULE_DEVICE_TABLE(i2c, mc3230_i2c_id); static struct i2c_driver mc3230_driver = { .driver = { .name = "mc3230", - .pm = &mc3230_pm_ops, + .pm = pm_sleep_ptr(&mc3230_pm_ops), }, .probe = mc3230_probe, .remove = mc3230_remove, -- cgit v1.2.3 From 812c5f31b1b937d4407b16648ceb16bee16c0cf1 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 30 Jan 2022 19:31:03 +0000 Subject: iio:accel:mma7660: Switch from CONFIG_PM_SLEEP guards to pm_sleep_ptr() Letting the compiler remove these functions when the kernel is built without CONFIG_PM_SLEEP support is simpler and less error prone than the use of #ifdef based config guards. Removing instances of this approach from IIO also stops them being copied into new drivers. Signed-off-by: Jonathan Cameron Reviewed-by: Paul Cercueil Link: https://lore.kernel.org/r/20220130193147.279148-7-jic23@kernel.org --- drivers/iio/accel/mma7660.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/drivers/iio/accel/mma7660.c b/drivers/iio/accel/mma7660.c index 24b83ccdb950..112a5a33c29f 100644 --- a/drivers/iio/accel/mma7660.c +++ b/drivers/iio/accel/mma7660.c @@ -222,7 +222,6 @@ static int mma7660_remove(struct i2c_client *client) return 0; } -#ifdef CONFIG_PM_SLEEP static int mma7660_suspend(struct device *dev) { struct mma7660_data *data; @@ -241,12 +240,8 @@ static int mma7660_resume(struct device *dev) return mma7660_set_mode(data, MMA7660_MODE_ACTIVE); } -static SIMPLE_DEV_PM_OPS(mma7660_pm_ops, mma7660_suspend, mma7660_resume); - -#define MMA7660_PM_OPS (&mma7660_pm_ops) -#else -#define MMA7660_PM_OPS NULL -#endif +static DEFINE_SIMPLE_DEV_PM_OPS(mma7660_pm_ops, mma7660_suspend, + mma7660_resume); static const struct i2c_device_id mma7660_i2c_id[] = { {"mma7660", 0}, @@ -270,7 +265,7 @@ MODULE_DEVICE_TABLE(acpi, mma7660_acpi_id); static struct i2c_driver mma7660_driver = { .driver = { .name = "mma7660", - .pm = MMA7660_PM_OPS, + .pm = pm_sleep_ptr(&mma7660_pm_ops), .of_match_table = mma7660_of_match, .acpi_match_table = ACPI_PTR(mma7660_acpi_id), }, -- cgit v1.2.3 From 81e566f9c013ee12153a806b0f288527a44b7665 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 30 Jan 2022 19:31:04 +0000 Subject: iio:accel:mma9551: Switch from CONFIG_PM guards to pm_ptr() etc Letting the compiler remove these functions when the kernel is built without CONFIG_PM support is simpler and less error prone than the use of #ifdef based config guards. Removing instances of this approach from IIO also stops them being copied into new drivers. Signed-off-by: Jonathan Cameron Reviewed-by: Paul Cercueil Link: https://lore.kernel.org/r/20220130193147.279148-8-jic23@kernel.org --- drivers/iio/accel/mma9551.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/drivers/iio/accel/mma9551.c b/drivers/iio/accel/mma9551.c index 8709c53fa06b..ada0ee09547b 100644 --- a/drivers/iio/accel/mma9551.c +++ b/drivers/iio/accel/mma9551.c @@ -523,7 +523,6 @@ static int mma9551_remove(struct i2c_client *client) return 0; } -#ifdef CONFIG_PM static int mma9551_runtime_suspend(struct device *dev) { struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); @@ -555,9 +554,7 @@ static int mma9551_runtime_resume(struct device *dev) return 0; } -#endif -#ifdef CONFIG_PM_SLEEP static int mma9551_suspend(struct device *dev) { struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); @@ -583,12 +580,10 @@ static int mma9551_resume(struct device *dev) return ret; } -#endif static const struct dev_pm_ops mma9551_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(mma9551_suspend, mma9551_resume) - SET_RUNTIME_PM_OPS(mma9551_runtime_suspend, - mma9551_runtime_resume, NULL) + SYSTEM_SLEEP_PM_OPS(mma9551_suspend, mma9551_resume) + RUNTIME_PM_OPS(mma9551_runtime_suspend, mma9551_runtime_resume, NULL) }; static const struct acpi_device_id mma9551_acpi_match[] = { @@ -609,7 +604,7 @@ static struct i2c_driver mma9551_driver = { .driver = { .name = MMA9551_DRV_NAME, .acpi_match_table = ACPI_PTR(mma9551_acpi_match), - .pm = &mma9551_pm_ops, + .pm = pm_ptr(&mma9551_pm_ops), }, .probe = mma9551_probe, .remove = mma9551_remove, -- cgit v1.2.3 From abbdba86f8300df12a3a510090474bcecaabc8f1 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 30 Jan 2022 19:31:05 +0000 Subject: iio:accel:mma9553: Switch from CONFIG_PM guards to pm_ptr() etc Letting the compiler remove these functions when the kernel is built without CONFIG_PM support is simpler and less error prone than the use of #ifdef based config guards. Removing instances of this approach from IIO also stops them being copied into new drivers. Signed-off-by: Jonathan Cameron Reviewed-by: Paul Cercueil Link: https://lore.kernel.org/r/20220130193147.279148-9-jic23@kernel.org --- drivers/iio/accel/mma9553.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/drivers/iio/accel/mma9553.c b/drivers/iio/accel/mma9553.c index a836e73c3242..3e2dc8cff875 100644 --- a/drivers/iio/accel/mma9553.c +++ b/drivers/iio/accel/mma9553.c @@ -1162,7 +1162,6 @@ static int mma9553_remove(struct i2c_client *client) return 0; } -#ifdef CONFIG_PM static int mma9553_runtime_suspend(struct device *dev) { struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); @@ -1194,9 +1193,7 @@ static int mma9553_runtime_resume(struct device *dev) return 0; } -#endif -#ifdef CONFIG_PM_SLEEP static int mma9553_suspend(struct device *dev) { struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); @@ -1222,12 +1219,10 @@ static int mma9553_resume(struct device *dev) return ret; } -#endif static const struct dev_pm_ops mma9553_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(mma9553_suspend, mma9553_resume) - SET_RUNTIME_PM_OPS(mma9553_runtime_suspend, - mma9553_runtime_resume, NULL) + SYSTEM_SLEEP_PM_OPS(mma9553_suspend, mma9553_resume) + RUNTIME_PM_OPS(mma9553_runtime_suspend, mma9553_runtime_resume, NULL) }; static const struct acpi_device_id mma9553_acpi_match[] = { @@ -1248,7 +1243,7 @@ static struct i2c_driver mma9553_driver = { .driver = { .name = MMA9553_DRV_NAME, .acpi_match_table = ACPI_PTR(mma9553_acpi_match), - .pm = &mma9553_pm_ops, + .pm = pm_ptr(&mma9553_pm_ops), }, .probe = mma9553_probe, .remove = mma9553_remove, -- cgit v1.2.3 From 0c74ef35128ef11aaf44d0b0928460a3e00ae1af Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 30 Jan 2022 19:31:06 +0000 Subject: iio:accel:stk8ba50: Switch from CONFIG_PM_SLEEP guards to pm_sleep_ptr() etc Letting the compiler remove these functions when the kernel is built without CONFIG_PM_SLEEP support is simpler and less error prone than the use of #ifdef based config guards. Removing instances of this approach from IIO also stops them being copied into new drivers. Signed-off-by: Jonathan Cameron Reviewed-by: Paul Cercueil Link: https://lore.kernel.org/r/20220130193147.279148-10-jic23@kernel.org --- drivers/iio/accel/stk8ba50.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/drivers/iio/accel/stk8ba50.c b/drivers/iio/accel/stk8ba50.c index 517c57ed9e94..0067ec5cbae8 100644 --- a/drivers/iio/accel/stk8ba50.c +++ b/drivers/iio/accel/stk8ba50.c @@ -504,7 +504,6 @@ static int stk8ba50_remove(struct i2c_client *client) return stk8ba50_set_power(data, STK8BA50_MODE_SUSPEND); } -#ifdef CONFIG_PM_SLEEP static int stk8ba50_suspend(struct device *dev) { struct stk8ba50_data *data; @@ -523,12 +522,8 @@ static int stk8ba50_resume(struct device *dev) return stk8ba50_set_power(data, STK8BA50_MODE_NORMAL); } -static SIMPLE_DEV_PM_OPS(stk8ba50_pm_ops, stk8ba50_suspend, stk8ba50_resume); - -#define STK8BA50_PM_OPS (&stk8ba50_pm_ops) -#else -#define STK8BA50_PM_OPS NULL -#endif +static DEFINE_SIMPLE_DEV_PM_OPS(stk8ba50_pm_ops, stk8ba50_suspend, + stk8ba50_resume); static const struct i2c_device_id stk8ba50_i2c_id[] = { {"stk8ba50", 0}, @@ -546,7 +541,7 @@ MODULE_DEVICE_TABLE(acpi, stk8ba50_acpi_id); static struct i2c_driver stk8ba50_driver = { .driver = { .name = "stk8ba50", - .pm = STK8BA50_PM_OPS, + .pm = pm_sleep_ptr(&stk8ba50_pm_ops), .acpi_match_table = ACPI_PTR(stk8ba50_acpi_id), }, .probe = stk8ba50_probe, -- cgit v1.2.3 From 19e2ed804066054f4e49bce0f37e3ae879a0e34a Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 30 Jan 2022 19:31:07 +0000 Subject: iio:adc:at91-adc: Switch from CONFIG_PM_SLEEP guards to pm_sleep_ptr() etc Letting the compiler remove these functions when the kernel is built without CONFIG_PM_SLEEP support is simpler and less error prone than the use of ifdef based config guards. Removing instances of this approach from IIO also stops them being copied into new drivers. Reviewed-by: Alexandre Belloni Signed-off-by: Jonathan Cameron Cc: Ludovic Desroches Reviewed-by: Paul Cercueil Link: https://lore.kernel.org/r/20220130193147.279148-11-jic23@kernel.org --- drivers/iio/adc/at91_adc.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c index 5a7d3a3a5fa8..532daaa6f943 100644 --- a/drivers/iio/adc/at91_adc.c +++ b/drivers/iio/adc/at91_adc.c @@ -1234,7 +1234,6 @@ static int at91_adc_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM_SLEEP static int at91_adc_suspend(struct device *dev) { struct iio_dev *idev = dev_get_drvdata(dev); @@ -1256,9 +1255,9 @@ static int at91_adc_resume(struct device *dev) return 0; } -#endif -static SIMPLE_DEV_PM_OPS(at91_adc_pm_ops, at91_adc_suspend, at91_adc_resume); +static DEFINE_SIMPLE_DEV_PM_OPS(at91_adc_pm_ops, at91_adc_suspend, + at91_adc_resume); static const struct at91_adc_trigger at91sam9260_triggers[] = { { .name = "timer-counter-0", .value = 0x1 }, @@ -1386,7 +1385,7 @@ static struct platform_driver at91_adc_driver = { .driver = { .name = DRIVER_NAME, .of_match_table = at91_adc_dt_ids, - .pm = &at91_adc_pm_ops, + .pm = pm_sleep_ptr(&at91_adc_pm_ops), }, }; -- cgit v1.2.3 From a3c185d9ae03f7fd41c3c1f6d48058c3202e186f Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 30 Jan 2022 19:31:08 +0000 Subject: iio:adc:exynos_adc: Switch from CONFIG_PM_SLEEP guards to pm_sleep_ptr() Letting the compiler remove these functions when the kernel is built without CONFIG_PM_SLEEP support is simpler and less error prone than the use of #ifdef based config guards. Removing instances of this approach from IIO also stops them being copied into new drivers. Reviewed-by: Krzysztof Kozlowski Signed-off-by: Jonathan Cameron Reviewed-by: Paul Cercueil Link: https://lore.kernel.org/r/20220130193147.279148-12-jic23@kernel.org --- drivers/iio/adc/exynos_adc.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/iio/adc/exynos_adc.c b/drivers/iio/adc/exynos_adc.c index 3b3868aa2533..cff1ba57fb16 100644 --- a/drivers/iio/adc/exynos_adc.c +++ b/drivers/iio/adc/exynos_adc.c @@ -968,7 +968,6 @@ static int exynos_adc_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM_SLEEP static int exynos_adc_suspend(struct device *dev) { struct iio_dev *indio_dev = dev_get_drvdata(dev); @@ -1001,11 +1000,9 @@ static int exynos_adc_resume(struct device *dev) return 0; } -#endif -static SIMPLE_DEV_PM_OPS(exynos_adc_pm_ops, - exynos_adc_suspend, - exynos_adc_resume); +static DEFINE_SIMPLE_DEV_PM_OPS(exynos_adc_pm_ops, exynos_adc_suspend, + exynos_adc_resume); static struct platform_driver exynos_adc_driver = { .probe = exynos_adc_probe, @@ -1013,7 +1010,7 @@ static struct platform_driver exynos_adc_driver = { .driver = { .name = "exynos-adc", .of_match_table = exynos_adc_match, - .pm = &exynos_adc_pm_ops, + .pm = pm_sleep_ptr(&exynos_adc_pm_ops), }, }; -- cgit v1.2.3 From 3f1a9c392d6993f25bc7c0c5b2fb0aa73667e8a2 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 30 Jan 2022 19:31:09 +0000 Subject: iio:adc:palmas_gpadc: Switch from CONFIG_PM_SLEEP guards to pm_sleep_ptr() Letting the compiler remove these functions when the kernel is built without CONFIG_PM_SLEEP support is simpler and less error prone than the use of #ifdef based config guards. Removing instances of this approach from IIO also stops them being copied into new drivers. In this case SIMPLE_DEV_PM_OPS() could have been used previously. Now we have DEFINE_SIMPLE_DEV_PM_OPS() which also deals with letting the compiler remove the structure and functions so use that instead. Signed-off-by: Jonathan Cameron Reviewed-by: Paul Cercueil Link: https://lore.kernel.org/r/20220130193147.279148-13-jic23@kernel.org --- drivers/iio/adc/palmas_gpadc.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/drivers/iio/adc/palmas_gpadc.c b/drivers/iio/adc/palmas_gpadc.c index f9c8385c72d3..61e80bf3d05e 100644 --- a/drivers/iio/adc/palmas_gpadc.c +++ b/drivers/iio/adc/palmas_gpadc.c @@ -653,7 +653,6 @@ static int palmas_gpadc_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM_SLEEP static int palmas_adc_wakeup_configure(struct palmas_gpadc *adc) { int adc_period, conv; @@ -822,12 +821,9 @@ static int palmas_gpadc_resume(struct device *dev) return 0; }; -#endif -static const struct dev_pm_ops palmas_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(palmas_gpadc_suspend, - palmas_gpadc_resume) -}; +static DEFINE_SIMPLE_DEV_PM_OPS(palmas_pm_ops, palmas_gpadc_suspend, + palmas_gpadc_resume); static const struct of_device_id of_palmas_gpadc_match_tbl[] = { { .compatible = "ti,palmas-gpadc", }, @@ -840,7 +836,7 @@ static struct platform_driver palmas_gpadc_driver = { .remove = palmas_gpadc_remove, .driver = { .name = MOD_NAME, - .pm = &palmas_pm_ops, + .pm = pm_sleep_ptr(&palmas_pm_ops), .of_match_table = of_palmas_gpadc_match_tbl, }, }; -- cgit v1.2.3 From cc0595a9b6843b3cab78669830ba68c07f079d94 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 30 Jan 2022 19:31:10 +0000 Subject: iio:adc:rockchip: Switch from CONFIG_PM_SLEEP guards to pm_sleep_ptr() etc Letting the compiler remove these functions when the kernel is built without CONFIG_PM_SLEEP support is simpler and less error prone than the use of ifdef based config guards. Removing instances of this approach from IIO also stops them being copied into new drivers. Signed-off-by: Jonathan Cameron Cc: Heiko Stuebner Reviewed-by: Paul Cercueil Link: https://lore.kernel.org/r/20220130193147.279148-14-jic23@kernel.org --- drivers/iio/adc/rockchip_saradc.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/iio/adc/rockchip_saradc.c b/drivers/iio/adc/rockchip_saradc.c index 14b8df4ca9c8..b87ea7148b58 100644 --- a/drivers/iio/adc/rockchip_saradc.c +++ b/drivers/iio/adc/rockchip_saradc.c @@ -481,7 +481,6 @@ static int rockchip_saradc_probe(struct platform_device *pdev) return devm_iio_device_register(&pdev->dev, indio_dev); } -#ifdef CONFIG_PM_SLEEP static int rockchip_saradc_suspend(struct device *dev) { struct iio_dev *indio_dev = dev_get_drvdata(dev); @@ -514,17 +513,17 @@ static int rockchip_saradc_resume(struct device *dev) return ret; } -#endif -static SIMPLE_DEV_PM_OPS(rockchip_saradc_pm_ops, - rockchip_saradc_suspend, rockchip_saradc_resume); +static DEFINE_SIMPLE_DEV_PM_OPS(rockchip_saradc_pm_ops, + rockchip_saradc_suspend, + rockchip_saradc_resume); static struct platform_driver rockchip_saradc_driver = { .probe = rockchip_saradc_probe, .driver = { .name = "rockchip-saradc", .of_match_table = rockchip_saradc_match, - .pm = &rockchip_saradc_pm_ops, + .pm = pm_sleep_ptr(&rockchip_saradc_pm_ops), }, }; -- cgit v1.2.3 From d3a6c17e683b65a7e7bd8a2f4377b3c05d0f4135 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 30 Jan 2022 19:31:11 +0000 Subject: iio:adc:twl6030: Switch from CONFIG_PM_SLEEP guards to pm_sleep_ptr() etc Letting the compiler remove these functions when the kernel is built without CONFIG_PM_SLEEP support is simpler and less error prone than the use of ifdef based config guards. Removing instances of this approach from IIO also stops them being copied into new drivers. Signed-off-by: Jonathan Cameron Reviewed-by: Paul Cercueil Link: https://lore.kernel.org/r/20220130193147.279148-15-jic23@kernel.org --- drivers/iio/adc/twl6030-gpadc.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/iio/adc/twl6030-gpadc.c b/drivers/iio/adc/twl6030-gpadc.c index afdb59e0b526..4966997b5319 100644 --- a/drivers/iio/adc/twl6030-gpadc.c +++ b/drivers/iio/adc/twl6030-gpadc.c @@ -944,7 +944,6 @@ static int twl6030_gpadc_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM_SLEEP static int twl6030_gpadc_suspend(struct device *pdev) { int ret; @@ -968,17 +967,16 @@ static int twl6030_gpadc_resume(struct device *pdev) return 0; }; -#endif -static SIMPLE_DEV_PM_OPS(twl6030_gpadc_pm_ops, twl6030_gpadc_suspend, - twl6030_gpadc_resume); +static DEFINE_SIMPLE_DEV_PM_OPS(twl6030_gpadc_pm_ops, twl6030_gpadc_suspend, + twl6030_gpadc_resume); static struct platform_driver twl6030_gpadc_driver = { .probe = twl6030_gpadc_probe, .remove = twl6030_gpadc_remove, .driver = { .name = DRIVER_NAME, - .pm = &twl6030_gpadc_pm_ops, + .pm = pm_sleep_ptr(&twl6030_gpadc_pm_ops), .of_match_table = of_twl6030_match_tbl, }, }; -- cgit v1.2.3 From 9cbeee0fac7de6bbf929c1c543a94d75f1c4128d Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 30 Jan 2022 19:31:12 +0000 Subject: iio:adc:vf610: Switch from CONFIG_PM_SLEEP guards to pm_sleep_ptr() etc Letting the compiler remove these functions when the kernel is built without CONFIG_PM_SLEEP support is simpler and less error prone than the use of ifdef based config guards. Removing instances of this approach from IIO also stops them being copied into new drivers. Signed-off-by: Jonathan Cameron Cc: Stefan-Gabriel Mirea Reviewed-by: Paul Cercueil Link: https://lore.kernel.org/r/20220130193147.279148-16-jic23@kernel.org --- drivers/iio/adc/vf610_adc.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/iio/adc/vf610_adc.c b/drivers/iio/adc/vf610_adc.c index fd57fc43e8e5..c84293efc129 100644 --- a/drivers/iio/adc/vf610_adc.c +++ b/drivers/iio/adc/vf610_adc.c @@ -912,7 +912,6 @@ static int vf610_adc_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM_SLEEP static int vf610_adc_suspend(struct device *dev) { struct iio_dev *indio_dev = dev_get_drvdata(dev); @@ -952,9 +951,9 @@ disable_reg: regulator_disable(info->vref); return ret; } -#endif -static SIMPLE_DEV_PM_OPS(vf610_adc_pm_ops, vf610_adc_suspend, vf610_adc_resume); +static DEFINE_SIMPLE_DEV_PM_OPS(vf610_adc_pm_ops, vf610_adc_suspend, + vf610_adc_resume); static struct platform_driver vf610_adc_driver = { .probe = vf610_adc_probe, @@ -962,7 +961,7 @@ static struct platform_driver vf610_adc_driver = { .driver = { .name = DRIVER_NAME, .of_match_table = vf610_adc_match, - .pm = &vf610_adc_pm_ops, + .pm = pm_sleep_ptr(&vf610_adc_pm_ops), }, }; -- cgit v1.2.3 From bb08abc74037047f9d10791c66859219030184c0 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 30 Jan 2022 19:31:13 +0000 Subject: iio:common:ssp: Switch from CONFIG_PM_SLEEP guards to pm_sleep_ptr() etc Letting the compiler remove these functions when the kernel is built without CONFIG_PM_SLEEP support is simpler and less error prone than the use of ifdef based config guards. Also switch to SIMPLE_DEV_PM_OPS rather than open coding the structure. Removing instances of this approach from IIO also stops them being copied into new drivers. Signed-off-by: Jonathan Cameron Reviewed-by: Paul Cercueil Link: https://lore.kernel.org/r/20220130193147.279148-17-jic23@kernel.org --- drivers/iio/common/ssp_sensors/ssp_dev.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/iio/common/ssp_sensors/ssp_dev.c b/drivers/iio/common/ssp_sensors/ssp_dev.c index a60c11481b03..a3783ea3117a 100644 --- a/drivers/iio/common/ssp_sensors/ssp_dev.c +++ b/drivers/iio/common/ssp_sensors/ssp_dev.c @@ -600,7 +600,6 @@ static int ssp_remove(struct spi_device *spi) return 0; } -#ifdef CONFIG_PM_SLEEP static int ssp_suspend(struct device *dev) { int ret; @@ -649,17 +648,14 @@ static int ssp_resume(struct device *dev) return 0; } -#endif /* CONFIG_PM_SLEEP */ -static const struct dev_pm_ops ssp_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(ssp_suspend, ssp_resume) -}; +static DEFINE_SIMPLE_DEV_PM_OPS(ssp_pm_ops, ssp_suspend, ssp_resume); static struct spi_driver ssp_driver = { .probe = ssp_probe, .remove = ssp_remove, .driver = { - .pm = &ssp_pm_ops, + .pm = pm_sleep_ptr(&ssp_pm_ops), .of_match_table = ssp_of_match, .name = "sensorhub" }, -- cgit v1.2.3 From 90b8c2c8f9f53a980d49081798080352aca69deb Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 30 Jan 2022 19:31:14 +0000 Subject: iio:dac:vf610: Switch from CONFIG_PM_SLEEP guards to pm_sleep_ptr() etc Letting the compiler remove these functions when the kernel is built without CONFIG_PM_SLEEP support is simpler and less error prone than the use of #ifdef based config guards. Removing instances of this approach from IIO also stops them being copied into new drivers. Signed-off-by: Jonathan Cameron Reviewed-by: Paul Cercueil Link: https://lore.kernel.org/r/20220130193147.279148-18-jic23@kernel.org --- drivers/iio/dac/vf610_dac.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/iio/dac/vf610_dac.c b/drivers/iio/dac/vf610_dac.c index 636b4009f763..92429c0d2685 100644 --- a/drivers/iio/dac/vf610_dac.c +++ b/drivers/iio/dac/vf610_dac.c @@ -242,7 +242,6 @@ static int vf610_dac_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM_SLEEP static int vf610_dac_suspend(struct device *dev) { struct iio_dev *indio_dev = dev_get_drvdata(dev); @@ -268,9 +267,9 @@ static int vf610_dac_resume(struct device *dev) return 0; } -#endif -static SIMPLE_DEV_PM_OPS(vf610_dac_pm_ops, vf610_dac_suspend, vf610_dac_resume); +static DEFINE_SIMPLE_DEV_PM_OPS(vf610_dac_pm_ops, vf610_dac_suspend, + vf610_dac_resume); static struct platform_driver vf610_dac_driver = { .probe = vf610_dac_probe, @@ -278,7 +277,7 @@ static struct platform_driver vf610_dac_driver = { .driver = { .name = "vf610-dac", .of_match_table = vf610_dac_match, - .pm = &vf610_dac_pm_ops, + .pm = pm_sleep_ptr(&vf610_dac_pm_ops), }, }; module_platform_driver(vf610_dac_driver); -- cgit v1.2.3 From 2f2207a6e6aa6dd169b14765b30396f37287ecc6 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 30 Jan 2022 19:31:15 +0000 Subject: iio:light:apds9300: Switch from CONFIG_PM_SLEEP guards to pm_sleep_ptr() etc Letting the compiler remove these functions when the kernel is built without CONFIG_PM_SLEEP support is simpler and less error prone than the use of #ifdef based config guards. Removing instances of this approach from IIO also stops them being copied into new drivers. Signed-off-by: Jonathan Cameron Reviewed-by: Paul Cercueil Link: https://lore.kernel.org/r/20220130193147.279148-19-jic23@kernel.org --- drivers/iio/light/apds9300.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/drivers/iio/light/apds9300.c b/drivers/iio/light/apds9300.c index baaf202dce05..0f9d77598997 100644 --- a/drivers/iio/light/apds9300.c +++ b/drivers/iio/light/apds9300.c @@ -466,7 +466,6 @@ static int apds9300_remove(struct i2c_client *client) return 0; } -#ifdef CONFIG_PM_SLEEP static int apds9300_suspend(struct device *dev) { struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); @@ -493,11 +492,8 @@ static int apds9300_resume(struct device *dev) return ret; } -static SIMPLE_DEV_PM_OPS(apds9300_pm_ops, apds9300_suspend, apds9300_resume); -#define APDS9300_PM_OPS (&apds9300_pm_ops) -#else -#define APDS9300_PM_OPS NULL -#endif +static DEFINE_SIMPLE_DEV_PM_OPS(apds9300_pm_ops, apds9300_suspend, + apds9300_resume); static const struct i2c_device_id apds9300_id[] = { { APDS9300_DRV_NAME, 0 }, @@ -509,7 +505,7 @@ MODULE_DEVICE_TABLE(i2c, apds9300_id); static struct i2c_driver apds9300_driver = { .driver = { .name = APDS9300_DRV_NAME, - .pm = APDS9300_PM_OPS, + .pm = pm_sleep_ptr(&apds9300_pm_ops), }, .probe = apds9300_probe, .remove = apds9300_remove, -- cgit v1.2.3 From 5f3521b8ebc5cae7040348befe9edcf44fb2f808 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 30 Jan 2022 19:31:16 +0000 Subject: iio:light:cm3232: Switch from CONFIG_PM_SLEEP guards to pm_sleep_ptr() etc Letting the compiler remove these functions when the kernel is built without CONFIG_PM_SLEEP support is simpler and less error prone than the use of #ifdef based config guards. Also switch to SIMPLE_DEV_PM_OPS rather than opencoding the same. Removing instances of this approach from IIO also stops them being copied into new drivers. Signed-off-by: Jonathan Cameron Reviewed-by: Paul Cercueil Link: https://lore.kernel.org/r/20220130193147.279148-20-jic23@kernel.org --- drivers/iio/light/cm3232.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/drivers/iio/light/cm3232.c b/drivers/iio/light/cm3232.c index 18a410340dc5..2c80a0535d2c 100644 --- a/drivers/iio/light/cm3232.c +++ b/drivers/iio/light/cm3232.c @@ -374,7 +374,6 @@ static const struct i2c_device_id cm3232_id[] = { {} }; -#ifdef CONFIG_PM_SLEEP static int cm3232_suspend(struct device *dev) { struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); @@ -403,9 +402,7 @@ static int cm3232_resume(struct device *dev) return ret; } -static const struct dev_pm_ops cm3232_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(cm3232_suspend, cm3232_resume)}; -#endif +static DEFINE_SIMPLE_DEV_PM_OPS(cm3232_pm_ops, cm3232_suspend, cm3232_resume); MODULE_DEVICE_TABLE(i2c, cm3232_id); @@ -419,9 +416,7 @@ static struct i2c_driver cm3232_driver = { .driver = { .name = "cm3232", .of_match_table = cm3232_of_match, -#ifdef CONFIG_PM_SLEEP - .pm = &cm3232_pm_ops, -#endif + .pm = pm_sleep_ptr(&cm3232_pm_ops), }, .id_table = cm3232_id, .probe = cm3232_probe, -- cgit v1.2.3 From b020281dda5e4798cfbdd7a321e10964f8b0a87f Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 30 Jan 2022 19:31:17 +0000 Subject: iio:light:isl29018: Switch from CONFIG_PM_SLEEP guards to pm_sleep_ptr() Letting the compiler remove these functions when the kernel is built without CONFIG_PM_SLEEP support is simpler and less error prone than the use of #ifdef based config guards. Removing instances of this approach from IIO also stops them being copied into new drivers. Signed-off-by: Jonathan Cameron Cc: Anson Huang Cc: Brian Masney Reviewed-by: Paul Cercueil Link: https://lore.kernel.org/r/20220130193147.279148-21-jic23@kernel.org --- drivers/iio/light/isl29018.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/drivers/iio/light/isl29018.c b/drivers/iio/light/isl29018.c index 2689867467a8..b36f8b7ca68e 100644 --- a/drivers/iio/light/isl29018.c +++ b/drivers/iio/light/isl29018.c @@ -784,7 +784,6 @@ static int isl29018_probe(struct i2c_client *client, return devm_iio_device_register(&client->dev, indio_dev); } -#ifdef CONFIG_PM_SLEEP static int isl29018_suspend(struct device *dev) { struct isl29018_chip *chip = iio_priv(dev_get_drvdata(dev)); @@ -830,11 +829,8 @@ static int isl29018_resume(struct device *dev) return err; } -static SIMPLE_DEV_PM_OPS(isl29018_pm_ops, isl29018_suspend, isl29018_resume); -#define ISL29018_PM_OPS (&isl29018_pm_ops) -#else -#define ISL29018_PM_OPS NULL -#endif +static DEFINE_SIMPLE_DEV_PM_OPS(isl29018_pm_ops, isl29018_suspend, + isl29018_resume); #ifdef CONFIG_ACPI static const struct acpi_device_id isl29018_acpi_match[] = { @@ -866,7 +862,7 @@ static struct i2c_driver isl29018_driver = { .driver = { .name = "isl29018", .acpi_match_table = ACPI_PTR(isl29018_acpi_match), - .pm = ISL29018_PM_OPS, + .pm = pm_sleep_ptr(&isl29018_pm_ops), .of_match_table = isl29018_of_match, }, .probe = isl29018_probe, -- cgit v1.2.3 From e9b76712625cc7d244c5fbc800a8d4f3fa8853b8 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 30 Jan 2022 19:31:18 +0000 Subject: iio:light:isl29125: Switch from CONFIG_PM_SLEEP guards to pm_sleep_ptr() etc Letting the compiler remove these functions when the kernel is built without CONFIG_PM_SLEEP support is simpler and less error prone than the use of #ifdef based config guards. Removing instances of this approach from IIO also stops them being copied into new drivers. Signed-off-by: Jonathan Cameron Reviewed-by: Paul Cercueil Link: https://lore.kernel.org/r/20220130193147.279148-22-jic23@kernel.org --- drivers/iio/light/isl29125.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/iio/light/isl29125.c b/drivers/iio/light/isl29125.c index ba53b50d711a..eb68a52aab82 100644 --- a/drivers/iio/light/isl29125.c +++ b/drivers/iio/light/isl29125.c @@ -311,7 +311,6 @@ static int isl29125_remove(struct i2c_client *client) return 0; } -#ifdef CONFIG_PM_SLEEP static int isl29125_suspend(struct device *dev) { struct isl29125_data *data = iio_priv(i2c_get_clientdata( @@ -326,9 +325,9 @@ static int isl29125_resume(struct device *dev) return i2c_smbus_write_byte_data(data->client, ISL29125_CONF1, data->conf1); } -#endif -static SIMPLE_DEV_PM_OPS(isl29125_pm_ops, isl29125_suspend, isl29125_resume); +static DEFINE_SIMPLE_DEV_PM_OPS(isl29125_pm_ops, isl29125_suspend, + isl29125_resume); static const struct i2c_device_id isl29125_id[] = { { "isl29125", 0 }, @@ -339,7 +338,7 @@ MODULE_DEVICE_TABLE(i2c, isl29125_id); static struct i2c_driver isl29125_driver = { .driver = { .name = ISL29125_DRV_NAME, - .pm = &isl29125_pm_ops, + .pm = pm_sleep_ptr(&isl29125_pm_ops), }, .probe = isl29125_probe, .remove = isl29125_remove, -- cgit v1.2.3 From fb20995d5fb752b5076a0c53da05c2c61f47531d Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 30 Jan 2022 19:31:19 +0000 Subject: iio:light:jsa1212: Switch from CONFIG_PM_SLEEP guards to pm_sleep_ptr() etc Letting the compiler remove these functions when the kernel is built without CONFIG_PM_SLEEP support is simpler and less error prone than the use of #ifdef based config guards. Removing instances of this approach from IIO also stops them being copied into new drivers. Signed-off-by: Jonathan Cameron Reviewed-by: Paul Cercueil Link: https://lore.kernel.org/r/20220130193147.279148-23-jic23@kernel.org --- drivers/iio/light/jsa1212.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/drivers/iio/light/jsa1212.c b/drivers/iio/light/jsa1212.c index 724a0ec9f35c..a55194263d23 100644 --- a/drivers/iio/light/jsa1212.c +++ b/drivers/iio/light/jsa1212.c @@ -383,7 +383,6 @@ static int jsa1212_remove(struct i2c_client *client) return jsa1212_power_off(data); } -#ifdef CONFIG_PM_SLEEP static int jsa1212_suspend(struct device *dev) { struct jsa1212_data *data; @@ -421,12 +420,8 @@ unlock_and_ret: return ret; } -static SIMPLE_DEV_PM_OPS(jsa1212_pm_ops, jsa1212_suspend, jsa1212_resume); - -#define JSA1212_PM_OPS (&jsa1212_pm_ops) -#else -#define JSA1212_PM_OPS NULL -#endif +static DEFINE_SIMPLE_DEV_PM_OPS(jsa1212_pm_ops, jsa1212_suspend, + jsa1212_resume); static const struct acpi_device_id jsa1212_acpi_match[] = { {"JSA1212", 0}, @@ -443,7 +438,7 @@ MODULE_DEVICE_TABLE(i2c, jsa1212_id); static struct i2c_driver jsa1212_driver = { .driver = { .name = JSA1212_DRIVER_NAME, - .pm = JSA1212_PM_OPS, + .pm = pm_sleep_ptr(&jsa1212_pm_ops), .acpi_match_table = ACPI_PTR(jsa1212_acpi_match), }, .probe = jsa1212_probe, -- cgit v1.2.3 From d03da05124677adbd1d6f54ac5fa32f1ab870b98 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 30 Jan 2022 19:31:20 +0000 Subject: iio:light:ltr501: Switch from CONFIG_PM_SLEEP guards to pm_sleep_ptr() etc Letting the compiler remove these functions when the kernel is built without CONFIG_PM_SLEEP support is simpler and less error prone than the use of #ifdef based config guards. Removing instances of this approach from IIO also stops them being copied into new drivers. Signed-off-by: Jonathan Cameron Cc: Maslov Dmitry Reviewed-by: Paul Cercueil Link: https://lore.kernel.org/r/20220130193147.279148-24-jic23@kernel.org --- drivers/iio/light/ltr501.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/iio/light/ltr501.c b/drivers/iio/light/ltr501.c index d1532ef5f08b..679a1e1086ae 100644 --- a/drivers/iio/light/ltr501.c +++ b/drivers/iio/light/ltr501.c @@ -1611,7 +1611,6 @@ static int ltr501_remove(struct i2c_client *client) return 0; } -#ifdef CONFIG_PM_SLEEP static int ltr501_suspend(struct device *dev) { struct ltr501_data *data = iio_priv(i2c_get_clientdata( @@ -1627,9 +1626,8 @@ static int ltr501_resume(struct device *dev) return ltr501_write_contr(data, data->als_contr, data->ps_contr); } -#endif -static SIMPLE_DEV_PM_OPS(ltr501_pm_ops, ltr501_suspend, ltr501_resume); +static DEFINE_SIMPLE_DEV_PM_OPS(ltr501_pm_ops, ltr501_suspend, ltr501_resume); static const struct acpi_device_id ltr_acpi_match[] = { { "LTER0501", ltr501 }, @@ -1661,7 +1659,7 @@ static struct i2c_driver ltr501_driver = { .driver = { .name = LTR501_DRV_NAME, .of_match_table = ltr501_of_match, - .pm = <r501_pm_ops, + .pm = pm_sleep_ptr(<r501_pm_ops), .acpi_match_table = ACPI_PTR(ltr_acpi_match), }, .probe = ltr501_probe, -- cgit v1.2.3 From 20cadda37b1af7317ea5d064519c55ef40fb9333 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 30 Jan 2022 19:31:21 +0000 Subject: iio:light:stk3310: Switch from CONFIG_PM_SLEEP guards to pm_sleep_ptr() etc Letting the compiler remove these functions when the kernel is built without CONFIG_PM_SLEEP support is simpler and less error prone than the use of #ifdef based config guards. Removing instances of this approach from IIO also stops them being copied into new drivers. Signed-off-by: Jonathan Cameron Cc: Icenowy Zheng Cc: Luca Weiss Cc: Martijn Braam Reviewed-by: Paul Cercueil Link: https://lore.kernel.org/r/20220130193147.279148-25-jic23@kernel.org --- drivers/iio/light/stk3310.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/drivers/iio/light/stk3310.c b/drivers/iio/light/stk3310.c index fc63856ed54d..1d02dfbc29d1 100644 --- a/drivers/iio/light/stk3310.c +++ b/drivers/iio/light/stk3310.c @@ -632,7 +632,6 @@ static int stk3310_remove(struct i2c_client *client) return stk3310_set_state(iio_priv(indio_dev), STK3310_STATE_STANDBY); } -#ifdef CONFIG_PM_SLEEP static int stk3310_suspend(struct device *dev) { struct stk3310_data *data; @@ -656,12 +655,8 @@ static int stk3310_resume(struct device *dev) return stk3310_set_state(data, state); } -static SIMPLE_DEV_PM_OPS(stk3310_pm_ops, stk3310_suspend, stk3310_resume); - -#define STK3310_PM_OPS (&stk3310_pm_ops) -#else -#define STK3310_PM_OPS NULL -#endif +static DEFINE_SIMPLE_DEV_PM_OPS(stk3310_pm_ops, stk3310_suspend, + stk3310_resume); static const struct i2c_device_id stk3310_i2c_id[] = { {"STK3310", 0}, @@ -692,7 +687,7 @@ static struct i2c_driver stk3310_driver = { .driver = { .name = "stk3310", .of_match_table = stk3310_of_match, - .pm = STK3310_PM_OPS, + .pm = pm_sleep_ptr(&stk3310_pm_ops), .acpi_match_table = ACPI_PTR(stk3310_acpi_id), }, .probe = stk3310_probe, -- cgit v1.2.3 From f3ba05346600f3a79257c228c469d6c0406f4b92 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 30 Jan 2022 19:31:22 +0000 Subject: iio:light:tcs3414: Switch from CONFIG_PM_SLEEP guards to pm_sleep_ptr() etc Letting the compiler remove these functions when the kernel is built without CONFIG_PM_SLEEP support is simpler and less error prone than the use of #ifdef based config guards. Removing instances of this approach from IIO also stops them being copied into new drivers. Signed-off-by: Jonathan Cameron Reviewed-by: Paul Cercueil Link: https://lore.kernel.org/r/20220130193147.279148-26-jic23@kernel.org --- drivers/iio/light/tcs3414.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/iio/light/tcs3414.c b/drivers/iio/light/tcs3414.c index b87222141429..3951536022b3 100644 --- a/drivers/iio/light/tcs3414.c +++ b/drivers/iio/light/tcs3414.c @@ -345,7 +345,6 @@ static int tcs3414_probe(struct i2c_client *client, return devm_iio_device_register(&client->dev, indio_dev); } -#ifdef CONFIG_PM_SLEEP static int tcs3414_suspend(struct device *dev) { struct tcs3414_data *data = iio_priv(i2c_get_clientdata( @@ -360,9 +359,9 @@ static int tcs3414_resume(struct device *dev) return i2c_smbus_write_byte_data(data->client, TCS3414_CONTROL, data->control); } -#endif -static SIMPLE_DEV_PM_OPS(tcs3414_pm_ops, tcs3414_suspend, tcs3414_resume); +static DEFINE_SIMPLE_DEV_PM_OPS(tcs3414_pm_ops, tcs3414_suspend, + tcs3414_resume); static const struct i2c_device_id tcs3414_id[] = { { "tcs3414", 0 }, @@ -373,7 +372,7 @@ MODULE_DEVICE_TABLE(i2c, tcs3414_id); static struct i2c_driver tcs3414_driver = { .driver = { .name = TCS3414_DRV_NAME, - .pm = &tcs3414_pm_ops, + .pm = pm_sleep_ptr(&tcs3414_pm_ops), }, .probe = tcs3414_probe, .id_table = tcs3414_id, -- cgit v1.2.3 From 54edb876789e2c5d6d6ba3227211184190bb216f Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 30 Jan 2022 19:31:23 +0000 Subject: iio:light:tcs3472: Switch from CONFIG_PM_SLEEP guards to pm_sleep_ptr() etc Letting the compiler remove these functions when the kernel is built without CONFIG_PM_SLEEP support is simpler and less error prone than the use of #ifdef based config guards. Removing instances of this approach from IIO also stops them being copied into new drivers. Signed-off-by: Jonathan Cameron Reviewed-by: Paul Cercueil Link: https://lore.kernel.org/r/20220130193147.279148-27-jic23@kernel.org --- drivers/iio/light/tcs3472.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/iio/light/tcs3472.c b/drivers/iio/light/tcs3472.c index 371c6a39a165..823435f59bb6 100644 --- a/drivers/iio/light/tcs3472.c +++ b/drivers/iio/light/tcs3472.c @@ -572,7 +572,6 @@ static int tcs3472_remove(struct i2c_client *client) return 0; } -#ifdef CONFIG_PM_SLEEP static int tcs3472_suspend(struct device *dev) { struct tcs3472_data *data = iio_priv(i2c_get_clientdata( @@ -598,9 +597,9 @@ static int tcs3472_resume(struct device *dev) return ret; } -#endif -static SIMPLE_DEV_PM_OPS(tcs3472_pm_ops, tcs3472_suspend, tcs3472_resume); +static DEFINE_SIMPLE_DEV_PM_OPS(tcs3472_pm_ops, tcs3472_suspend, + tcs3472_resume); static const struct i2c_device_id tcs3472_id[] = { { "tcs3472", 0 }, @@ -611,7 +610,7 @@ MODULE_DEVICE_TABLE(i2c, tcs3472_id); static struct i2c_driver tcs3472_driver = { .driver = { .name = TCS3472_DRV_NAME, - .pm = &tcs3472_pm_ops, + .pm = pm_sleep_ptr(&tcs3472_pm_ops), }, .probe = tcs3472_probe, .remove = tcs3472_remove, -- cgit v1.2.3 From 854b67052ce81bd2a1b2a2ce31e49b4d90a5460c Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 30 Jan 2022 19:31:24 +0000 Subject: iio:light:tsl2563: Switch from CONFIG_PM_SLEEP guards to pm_sleep_ptr() etc Letting the compiler remove these functions when the kernel is built without CONFIG_PM_SLEEP support is simpler and less error prone than the use of #ifdef based config guards. Removing instances of this approach from IIO also stops them being copied into new drivers. Signed-off-by: Jonathan Cameron Cc: Vaishnav M A Reviewed-by: Paul Cercueil Link: https://lore.kernel.org/r/20220130193147.279148-28-jic23@kernel.org --- drivers/iio/light/tsl2563.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/drivers/iio/light/tsl2563.c b/drivers/iio/light/tsl2563.c index 5bf2bfbc5379..0a278eea36ca 100644 --- a/drivers/iio/light/tsl2563.c +++ b/drivers/iio/light/tsl2563.c @@ -814,7 +814,6 @@ static int tsl2563_remove(struct i2c_client *client) return 0; } -#ifdef CONFIG_PM_SLEEP static int tsl2563_suspend(struct device *dev) { struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); @@ -857,11 +856,8 @@ out: return ret; } -static SIMPLE_DEV_PM_OPS(tsl2563_pm_ops, tsl2563_suspend, tsl2563_resume); -#define TSL2563_PM_OPS (&tsl2563_pm_ops) -#else -#define TSL2563_PM_OPS NULL -#endif +static DEFINE_SIMPLE_DEV_PM_OPS(tsl2563_pm_ops, tsl2563_suspend, + tsl2563_resume); static const struct i2c_device_id tsl2563_id[] = { { "tsl2560", 0 }, @@ -885,7 +881,7 @@ static struct i2c_driver tsl2563_i2c_driver = { .driver = { .name = "tsl2563", .of_match_table = tsl2563_of_match, - .pm = TSL2563_PM_OPS, + .pm = pm_sleep_ptr(&tsl2563_pm_ops), }, .probe = tsl2563_probe, .remove = tsl2563_remove, -- cgit v1.2.3 From 5ad7f3c995aa1970db1c4de1a49a17b104857574 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 30 Jan 2022 19:31:25 +0000 Subject: iio:light:tsl4531: Switch from CONFIG_PM_SLEEP guards to pm_sleep_ptr() etc Letting the compiler remove these functions when the kernel is built without CONFIG_PM_SLEEP support is simpler and less error prone than the use of #ifdef based config guards. Removing instances of this approach from IIO also stops them being copied into new drivers. Signed-off-by: Jonathan Cameron Reviewed-by: Paul Cercueil Link: https://lore.kernel.org/r/20220130193147.279148-29-jic23@kernel.org --- drivers/iio/light/tsl4531.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/drivers/iio/light/tsl4531.c b/drivers/iio/light/tsl4531.c index 70505ba6d858..6ae1b27e50b6 100644 --- a/drivers/iio/light/tsl4531.c +++ b/drivers/iio/light/tsl4531.c @@ -215,7 +215,6 @@ static int tsl4531_remove(struct i2c_client *client) return 0; } -#ifdef CONFIG_PM_SLEEP static int tsl4531_suspend(struct device *dev) { return tsl4531_powerdown(to_i2c_client(dev)); @@ -227,11 +226,8 @@ static int tsl4531_resume(struct device *dev) TSL4531_MODE_NORMAL); } -static SIMPLE_DEV_PM_OPS(tsl4531_pm_ops, tsl4531_suspend, tsl4531_resume); -#define TSL4531_PM_OPS (&tsl4531_pm_ops) -#else -#define TSL4531_PM_OPS NULL -#endif +static DEFINE_SIMPLE_DEV_PM_OPS(tsl4531_pm_ops, tsl4531_suspend, + tsl4531_resume); static const struct i2c_device_id tsl4531_id[] = { { "tsl4531", 0 }, @@ -242,7 +238,7 @@ MODULE_DEVICE_TABLE(i2c, tsl4531_id); static struct i2c_driver tsl4531_driver = { .driver = { .name = TSL4531_DRV_NAME, - .pm = TSL4531_PM_OPS, + .pm = pm_sleep_ptr(&tsl4531_pm_ops), }, .probe = tsl4531_probe, .remove = tsl4531_remove, -- cgit v1.2.3 From 6c1318f225728d44f4b65befde77e7b65d8b0329 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 30 Jan 2022 19:31:26 +0000 Subject: iio:magn:ak8975: Switch from CONFIG_PM guards to pm_ptr() etc Letting the compiler remove these functions when the kernel is built without CONFIG_PM support is simpler and less error prone than the use of #ifdef based config guards. Use the new DEFINE_RUNTIME_DEV_PM_OPS() macro to reduce boilerplate. Removing instances of this approach from IIO also stops them being copied into new drivers. Acked-by: Matt Ranostay Signed-off-by: Jonathan Cameron Cc: Jonathan Albrieux Cc: Linus Walleij Reviewed-by: Paul Cercueil Link: https://lore.kernel.org/r/20220130193147.279148-30-jic23@kernel.org --- drivers/iio/magnetometer/ak8975.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/drivers/iio/magnetometer/ak8975.c b/drivers/iio/magnetometer/ak8975.c index 55879a20ae52..088f748b683e 100644 --- a/drivers/iio/magnetometer/ak8975.c +++ b/drivers/iio/magnetometer/ak8975.c @@ -1033,7 +1033,6 @@ static int ak8975_remove(struct i2c_client *client) return 0; } -#ifdef CONFIG_PM static int ak8975_runtime_suspend(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); @@ -1074,14 +1073,9 @@ static int ak8975_runtime_resume(struct device *dev) return 0; } -#endif /* CONFIG_PM */ -static const struct dev_pm_ops ak8975_dev_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, - pm_runtime_force_resume) - SET_RUNTIME_PM_OPS(ak8975_runtime_suspend, - ak8975_runtime_resume, NULL) -}; +static DEFINE_RUNTIME_DEV_PM_OPS(ak8975_dev_pm_ops, ak8975_runtime_suspend, + ak8975_runtime_resume, NULL); static const struct i2c_device_id ak8975_id[] = { {"ak8975", AK8975}, @@ -1113,7 +1107,7 @@ MODULE_DEVICE_TABLE(of, ak8975_of_match); static struct i2c_driver ak8975_driver = { .driver = { .name = "ak8975", - .pm = &ak8975_dev_pm_ops, + .pm = pm_ptr(&ak8975_dev_pm_ops), .of_match_table = ak8975_of_match, .acpi_match_table = ak_acpi_match, }, -- cgit v1.2.3 From fe7b9a3820bd111b249249a0a389980417ab8d45 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 30 Jan 2022 19:31:27 +0000 Subject: iio:magn:mag3110: Switch from CONFIG_PM_SLEEP guards to pm_sleep_ptr() etc Letting the compiler remove these functions when the kernel is built without CONFIG_PM_SLEEP support is simpler and less error prone than the use of #ifdef based config guards. Removing instances of this approach from IIO also stops them being copied into new drivers. Signed-off-by: Jonathan Cameron Reviewed-by: Paul Cercueil Link: https://lore.kernel.org/r/20220130193147.279148-31-jic23@kernel.org --- drivers/iio/magnetometer/mag3110.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/drivers/iio/magnetometer/mag3110.c b/drivers/iio/magnetometer/mag3110.c index 17c62d806218..226439d0bfb5 100644 --- a/drivers/iio/magnetometer/mag3110.c +++ b/drivers/iio/magnetometer/mag3110.c @@ -573,7 +573,6 @@ static int mag3110_remove(struct i2c_client *client) return 0; } -#ifdef CONFIG_PM_SLEEP static int mag3110_suspend(struct device *dev) { struct mag3110_data *data = iio_priv(i2c_get_clientdata( @@ -623,11 +622,8 @@ static int mag3110_resume(struct device *dev) data->ctrl_reg1); } -static SIMPLE_DEV_PM_OPS(mag3110_pm_ops, mag3110_suspend, mag3110_resume); -#define MAG3110_PM_OPS (&mag3110_pm_ops) -#else -#define MAG3110_PM_OPS NULL -#endif +static DEFINE_SIMPLE_DEV_PM_OPS(mag3110_pm_ops, mag3110_suspend, + mag3110_resume); static const struct i2c_device_id mag3110_id[] = { { "mag3110", 0 }, @@ -645,7 +641,7 @@ static struct i2c_driver mag3110_driver = { .driver = { .name = "mag3110", .of_match_table = mag3110_of_match, - .pm = MAG3110_PM_OPS, + .pm = pm_sleep_ptr(&mag3110_pm_ops), }, .probe = mag3110_probe, .remove = mag3110_remove, -- cgit v1.2.3 From c9f384b87b328379090eb1eb57773043e0320349 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 30 Jan 2022 19:31:28 +0000 Subject: iio:magn:mmc35240: Switch from CONFIG_PM_SLEEP guards to pm_sleep_ptr() etc Letting the compiler remove these functions when the kernel is built without CONFIG_PM_SLEEP support is simpler and less error prone than the use of #ifdef based config guards. Also use SIMPLE_DEV_PM_OPS instead of open-coding the equivalent. Removing instances of this approach from IIO also stops them being copied into new drivers. Signed-off-by: Jonathan Cameron Reviewed-by: Paul Cercueil Link: https://lore.kernel.org/r/20220130193147.279148-32-jic23@kernel.org --- drivers/iio/magnetometer/mmc35240.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/iio/magnetometer/mmc35240.c b/drivers/iio/magnetometer/mmc35240.c index 65f3d1ed0d59..186edfcda0b7 100644 --- a/drivers/iio/magnetometer/mmc35240.c +++ b/drivers/iio/magnetometer/mmc35240.c @@ -521,7 +521,6 @@ static int mmc35240_probe(struct i2c_client *client, return devm_iio_device_register(&client->dev, indio_dev); } -#ifdef CONFIG_PM_SLEEP static int mmc35240_suspend(struct device *dev) { struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); @@ -548,11 +547,9 @@ static int mmc35240_resume(struct device *dev) return 0; } -#endif -static const struct dev_pm_ops mmc35240_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(mmc35240_suspend, mmc35240_resume) -}; +static DEFINE_SIMPLE_DEV_PM_OPS(mmc35240_pm_ops, mmc35240_suspend, + mmc35240_resume); static const struct of_device_id mmc35240_of_match[] = { { .compatible = "memsic,mmc35240", }, @@ -576,7 +573,7 @@ static struct i2c_driver mmc35240_driver = { .driver = { .name = MMC35240_DRV_NAME, .of_match_table = mmc35240_of_match, - .pm = &mmc35240_pm_ops, + .pm = pm_sleep_ptr(&mmc35240_pm_ops), .acpi_match_table = ACPI_PTR(mmc35240_acpi_match), }, .probe = mmc35240_probe, -- cgit v1.2.3 From 902b291fc683948f908259cd0c092071d8116210 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 30 Jan 2022 19:31:29 +0000 Subject: iio:pressure:mpl3115: Switch from CONFIG_PM_SLEEP guards to pm_sleep_ptr() etc Letting the compiler remove these functions when the kernel is built without CONFIG_PM_SLEEP support is simpler and less error prone than the use of #ifdef based config guards. Removing instances of this approach from IIO also stops them being copied into new drivers. Signed-off-by: Jonathan Cameron Reviewed-by: Paul Cercueil Link: https://lore.kernel.org/r/20220130193147.279148-33-jic23@kernel.org --- drivers/iio/pressure/mpl3115.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/drivers/iio/pressure/mpl3115.c b/drivers/iio/pressure/mpl3115.c index e95b9a5475b4..d4f89e4babed 100644 --- a/drivers/iio/pressure/mpl3115.c +++ b/drivers/iio/pressure/mpl3115.c @@ -301,7 +301,6 @@ static int mpl3115_remove(struct i2c_client *client) return 0; } -#ifdef CONFIG_PM_SLEEP static int mpl3115_suspend(struct device *dev) { return mpl3115_standby(iio_priv(i2c_get_clientdata( @@ -317,11 +316,8 @@ static int mpl3115_resume(struct device *dev) data->ctrl_reg1); } -static SIMPLE_DEV_PM_OPS(mpl3115_pm_ops, mpl3115_suspend, mpl3115_resume); -#define MPL3115_PM_OPS (&mpl3115_pm_ops) -#else -#define MPL3115_PM_OPS NULL -#endif +static DEFINE_SIMPLE_DEV_PM_OPS(mpl3115_pm_ops, mpl3115_suspend, + mpl3115_resume); static const struct i2c_device_id mpl3115_id[] = { { "mpl3115", 0 }, @@ -339,7 +335,7 @@ static struct i2c_driver mpl3115_driver = { .driver = { .name = "mpl3115", .of_match_table = mpl3115_of_match, - .pm = MPL3115_PM_OPS, + .pm = pm_sleep_ptr(&mpl3115_pm_ops), }, .probe = mpl3115_probe, .remove = mpl3115_remove, -- cgit v1.2.3 From bff03d5cab0917b7f61cee335202ace23c4c6b9e Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 30 Jan 2022 19:31:30 +0000 Subject: iio:proximity:as3935: Switch from CONFIG_PM_SLEEP guards to pm_sleep_ptr() etc Letting the compiler remove these functions when the kernel is built without CONFIG_PM_SLEEP support is simpler and less error prone than the use of #ifdef based config guards. Removing instances of this approach from IIO also stops them being copied into new drivers. Reviewed-by: Gwendal Grignou Acked-by: Matt Ranostay Signed-off-by: Jonathan Cameron Reviewed-by: Paul Cercueil Link: https://lore.kernel.org/r/20220130193147.279148-34-jic23@kernel.org --- drivers/iio/proximity/as3935.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/drivers/iio/proximity/as3935.c b/drivers/iio/proximity/as3935.c index 00e06491b188..67891ce2bd09 100644 --- a/drivers/iio/proximity/as3935.c +++ b/drivers/iio/proximity/as3935.c @@ -296,7 +296,6 @@ static void calibrate_as3935(struct as3935_state *st) as3935_write(st, AS3935_NFLWDTH, st->nflwdth_reg); } -#ifdef CONFIG_PM_SLEEP static int as3935_suspend(struct device *dev) { struct iio_dev *indio_dev = dev_get_drvdata(dev); @@ -338,12 +337,7 @@ err_resume: return ret; } -static SIMPLE_DEV_PM_OPS(as3935_pm_ops, as3935_suspend, as3935_resume); -#define AS3935_PM_OPS (&as3935_pm_ops) - -#else -#define AS3935_PM_OPS NULL -#endif +static DEFINE_SIMPLE_DEV_PM_OPS(as3935_pm_ops, as3935_suspend, as3935_resume); static int as3935_probe(struct spi_device *spi) { @@ -464,7 +458,7 @@ static struct spi_driver as3935_driver = { .driver = { .name = "as3935", .of_match_table = as3935_of_match, - .pm = AS3935_PM_OPS, + .pm = pm_sleep_ptr(&as3935_pm_ops), }, .probe = as3935_probe, .id_table = as3935_id, -- cgit v1.2.3 From fe895d256022cc69184a5cc5d86e8c62ef1c769a Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 30 Jan 2022 19:31:31 +0000 Subject: iio:proximity:rfd77492: Switch from CONFIG_PM_SLEEP guards to pm_sleep_ptr() etc Letting the compiler remove these functions when the kernel is built without CONFIG_PM_SLEEP support is simpler and less error prone than the use of #ifdef based config guards. Removing instances of this approach from IIO also stops them being copied into new drivers. Signed-off-by: Jonathan Cameron Reviewed-by: Paul Cercueil Link: https://lore.kernel.org/r/20220130193147.279148-35-jic23@kernel.org --- drivers/iio/proximity/rfd77402.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/iio/proximity/rfd77402.c b/drivers/iio/proximity/rfd77402.c index 0ae91963b570..cb80b3c9d073 100644 --- a/drivers/iio/proximity/rfd77402.c +++ b/drivers/iio/proximity/rfd77402.c @@ -295,7 +295,6 @@ static int rfd77402_probe(struct i2c_client *client, return devm_iio_device_register(&client->dev, indio_dev); } -#ifdef CONFIG_PM_SLEEP static int rfd77402_suspend(struct device *dev) { return rfd77402_powerdown(to_i2c_client(dev)); @@ -305,9 +304,9 @@ static int rfd77402_resume(struct device *dev) { return rfd77402_init(to_i2c_client(dev)); } -#endif -static SIMPLE_DEV_PM_OPS(rfd77402_pm_ops, rfd77402_suspend, rfd77402_resume); +static DEFINE_SIMPLE_DEV_PM_OPS(rfd77402_pm_ops, rfd77402_suspend, + rfd77402_resume); static const struct i2c_device_id rfd77402_id[] = { { "rfd77402", 0 }, @@ -318,7 +317,7 @@ MODULE_DEVICE_TABLE(i2c, rfd77402_id); static struct i2c_driver rfd77402_driver = { .driver = { .name = RFD77402_DRV_NAME, - .pm = &rfd77402_pm_ops, + .pm = pm_sleep_ptr(&rfd77402_pm_ops), }, .probe = rfd77402_probe, .id_table = rfd77402_id, -- cgit v1.2.3 From 51e256d4b485bdbd8924aa660433228fe9254772 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 30 Jan 2022 19:31:32 +0000 Subject: iio:proximity:sx9500: Switch from CONFIG_PM_SLEEP guards to pm_sleep_ptr() etc Letting the compiler remove these functions when the kernel is built without CONFIG_PM_SLEEP support is simpler and less error prone than the use of #ifdef based config guards. Removing instances of this approach from IIO also stops them being copied into new drivers. Reviewed-by: Gwendal Grignou Signed-off-by: Jonathan Cameron Reviewed-by: Paul Cercueil Link: https://lore.kernel.org/r/20220130193147.279148-36-jic23@kernel.org --- drivers/iio/proximity/sx9500.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/iio/proximity/sx9500.c b/drivers/iio/proximity/sx9500.c index 3e4ddb2e8c2b..42589d6200ad 100644 --- a/drivers/iio/proximity/sx9500.c +++ b/drivers/iio/proximity/sx9500.c @@ -993,7 +993,6 @@ static int sx9500_remove(struct i2c_client *client) return 0; } -#ifdef CONFIG_PM_SLEEP static int sx9500_suspend(struct device *dev) { struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); @@ -1030,11 +1029,8 @@ static int sx9500_resume(struct device *dev) return ret; } -#endif /* CONFIG_PM_SLEEP */ -static const struct dev_pm_ops sx9500_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(sx9500_suspend, sx9500_resume) -}; +static DEFINE_SIMPLE_DEV_PM_OPS(sx9500_pm_ops, sx9500_suspend, sx9500_resume); static const struct acpi_device_id sx9500_acpi_match[] = { {"SSX9500", 0}, @@ -1060,7 +1056,7 @@ static struct i2c_driver sx9500_driver = { .name = SX9500_DRIVER_NAME, .acpi_match_table = ACPI_PTR(sx9500_acpi_match), .of_match_table = of_match_ptr(sx9500_of_match), - .pm = &sx9500_pm_ops, + .pm = pm_sleep_ptr(&sx9500_pm_ops), }, .probe = sx9500_probe, .remove = sx9500_remove, -- cgit v1.2.3 From 1ef7361fec0bbc7d67939f10986895cd6aec7a80 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 30 Jan 2022 19:31:33 +0000 Subject: iio:temperature:tmp006: Switch from CONFIG_PM_SLEEP guards to pm_sleep_ptr() etc Letting the compiler remove these functions when the kernel is built without CONFIG_PM_SLEEP support is simpler and less error prone than the use of #ifdef based config guards. Removing instances of this approach from IIO also stops them being copied into new drivers. Signed-off-by: Jonathan Cameron Reviewed-by: Paul Cercueil Link: https://lore.kernel.org/r/20220130193147.279148-37-jic23@kernel.org --- drivers/iio/temperature/tmp006.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/iio/temperature/tmp006.c b/drivers/iio/temperature/tmp006.c index e4943a0bc9aa..706a760f30b4 100644 --- a/drivers/iio/temperature/tmp006.c +++ b/drivers/iio/temperature/tmp006.c @@ -261,7 +261,6 @@ static int tmp006_probe(struct i2c_client *client, return devm_iio_device_register(&client->dev, indio_dev); } -#ifdef CONFIG_PM_SLEEP static int tmp006_suspend(struct device *dev) { return tmp006_power(dev, false); @@ -271,9 +270,8 @@ static int tmp006_resume(struct device *dev) { return tmp006_power(dev, true); } -#endif -static SIMPLE_DEV_PM_OPS(tmp006_pm_ops, tmp006_suspend, tmp006_resume); +static DEFINE_SIMPLE_DEV_PM_OPS(tmp006_pm_ops, tmp006_suspend, tmp006_resume); static const struct i2c_device_id tmp006_id[] = { { "tmp006", 0 }, @@ -284,7 +282,7 @@ MODULE_DEVICE_TABLE(i2c, tmp006_id); static struct i2c_driver tmp006_driver = { .driver = { .name = "tmp006", - .pm = &tmp006_pm_ops, + .pm = pm_sleep_ptr(&tmp006_pm_ops), }, .probe = tmp006_probe, .id_table = tmp006_id, -- cgit v1.2.3 From ce83415d90da4c1e55c0fd2c7a6de03ce91f1530 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 30 Jan 2022 19:31:34 +0000 Subject: iio:temperature:tmp007: Switch from CONFIG_PM_SLEEP guards to pm_sleep_ptr() etc Letting the compiler remove these functions when the kernel is built without CONFIG_PM_SLEEP support is simpler and less error prone than the use of #ifdef based config guards. Removing instances of this approach from IIO also stops them being copied into new drivers. Acked-by: Manivannan Sadhasivam Signed-off-by: Jonathan Cameron Reviewed-by: Paul Cercueil Link: https://lore.kernel.org/r/20220130193147.279148-38-jic23@kernel.org --- drivers/iio/temperature/tmp007.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/iio/temperature/tmp007.c b/drivers/iio/temperature/tmp007.c index b422371a4674..f3420d8a0e35 100644 --- a/drivers/iio/temperature/tmp007.c +++ b/drivers/iio/temperature/tmp007.c @@ -537,7 +537,6 @@ static int tmp007_probe(struct i2c_client *client, return devm_iio_device_register(&client->dev, indio_dev); } -#ifdef CONFIG_PM_SLEEP static int tmp007_suspend(struct device *dev) { struct tmp007_data *data = iio_priv(i2c_get_clientdata( @@ -554,9 +553,8 @@ static int tmp007_resume(struct device *dev) return i2c_smbus_write_word_swapped(data->client, TMP007_CONFIG, data->config | TMP007_CONFIG_CONV_EN); } -#endif -static SIMPLE_DEV_PM_OPS(tmp007_pm_ops, tmp007_suspend, tmp007_resume); +static DEFINE_SIMPLE_DEV_PM_OPS(tmp007_pm_ops, tmp007_suspend, tmp007_resume); static const struct of_device_id tmp007_of_match[] = { { .compatible = "ti,tmp007", }, @@ -574,7 +572,7 @@ static struct i2c_driver tmp007_driver = { .driver = { .name = "tmp007", .of_match_table = tmp007_of_match, - .pm = &tmp007_pm_ops, + .pm = pm_sleep_ptr(&tmp007_pm_ops), }, .probe = tmp007_probe, .id_table = tmp007_id, -- cgit v1.2.3 From c1d24fac216fa05f4bb772d84c1bb02208d99392 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 30 Jan 2022 19:31:35 +0000 Subject: iio:accel:stk8312: Switch from CONFIG_PM_SLEEP guards to pm_sleep_ptr() etc Letting the compiler remove these functions when the kernel is built without CONFIG_PM_SLEEP support is simpler and less error prone than the use of #ifdef based config guards. Removing instances of this approach from IIO also stops them being copied into new drivers. Signed-off-by: Jonathan Cameron Reviewed-by: Paul Cercueil Link: https://lore.kernel.org/r/20220130193147.279148-39-jic23@kernel.org --- drivers/iio/accel/stk8312.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/drivers/iio/accel/stk8312.c b/drivers/iio/accel/stk8312.c index de0cdf8c1f94..a71dfff3ca4a 100644 --- a/drivers/iio/accel/stk8312.c +++ b/drivers/iio/accel/stk8312.c @@ -611,7 +611,6 @@ static int stk8312_remove(struct i2c_client *client) return stk8312_set_mode(data, STK8312_MODE_STANDBY); } -#ifdef CONFIG_PM_SLEEP static int stk8312_suspend(struct device *dev) { struct stk8312_data *data; @@ -630,12 +629,8 @@ static int stk8312_resume(struct device *dev) return stk8312_set_mode(data, data->mode | STK8312_MODE_ACTIVE); } -static SIMPLE_DEV_PM_OPS(stk8312_pm_ops, stk8312_suspend, stk8312_resume); - -#define STK8312_PM_OPS (&stk8312_pm_ops) -#else -#define STK8312_PM_OPS NULL -#endif +static DEFINE_SIMPLE_DEV_PM_OPS(stk8312_pm_ops, stk8312_suspend, + stk8312_resume); static const struct i2c_device_id stk8312_i2c_id[] = { /* Deprecated in favour of lowercase form */ @@ -648,7 +643,7 @@ MODULE_DEVICE_TABLE(i2c, stk8312_i2c_id); static struct i2c_driver stk8312_driver = { .driver = { .name = STK8312_DRIVER_NAME, - .pm = STK8312_PM_OPS, + .pm = pm_sleep_ptr(&stk8312_pm_ops), }, .probe = stk8312_probe, .remove = stk8312_remove, -- cgit v1.2.3 From 195b8b24688d3d0429cd8f977abd2fb6fb1f7c4e Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 30 Jan 2022 19:31:36 +0000 Subject: iio:accel:bma180: Switch from CONFIG_PM_SLEEP guards to pm_sleep_ptr() etc Letting the compiler remove these functions when the kernel is built without CONFIG_PM_SLEEP support is simpler and less error prone than the use of #ifdef based config guards. Removing instances of this approach from IIO also stops them being copied into new drivers. Signed-off-by: Jonathan Cameron Reviewed-by: Paul Cercueil Link: https://lore.kernel.org/r/20220130193147.279148-40-jic23@kernel.org --- drivers/iio/accel/bma180.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/drivers/iio/accel/bma180.c b/drivers/iio/accel/bma180.c index d8a454c266d5..4f73bc827eec 100644 --- a/drivers/iio/accel/bma180.c +++ b/drivers/iio/accel/bma180.c @@ -1065,7 +1065,6 @@ static int bma180_remove(struct i2c_client *client) return 0; } -#ifdef CONFIG_PM_SLEEP static int bma180_suspend(struct device *dev) { struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); @@ -1092,11 +1091,7 @@ static int bma180_resume(struct device *dev) return ret; } -static SIMPLE_DEV_PM_OPS(bma180_pm_ops, bma180_suspend, bma180_resume); -#define BMA180_PM_OPS (&bma180_pm_ops) -#else -#define BMA180_PM_OPS NULL -#endif +static DEFINE_SIMPLE_DEV_PM_OPS(bma180_pm_ops, bma180_suspend, bma180_resume); static const struct i2c_device_id bma180_ids[] = { { "bma023", BMA023 }, @@ -1137,7 +1132,7 @@ MODULE_DEVICE_TABLE(of, bma180_of_match); static struct i2c_driver bma180_driver = { .driver = { .name = "bma180", - .pm = BMA180_PM_OPS, + .pm = pm_sleep_ptr(&bma180_pm_ops), .of_match_table = bma180_of_match, }, .probe = bma180_probe, -- cgit v1.2.3 From 671d2c605b7ab2af64bfde3298929ef0267e4f14 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 30 Jan 2022 19:31:37 +0000 Subject: iio:dac:m62332: Switch from CONFIG_PM_SLEEP guards to pm_sleep_ptr() etc Letting the compiler remove these functions when the kernel is built without CONFIG_PM_SLEEP support is simpler and less error prone than the use of #ifdef based config guards. Note that in this case the storage for saving state was protected by CONFIG_PM guards. The storage is very small and unlikely to make any real difference to the space allocated for state so just drop those guards. Removing instances of this approach from IIO also stops them being copied into new drivers. Signed-off-by: Jonathan Cameron Reviewed-by: Paul Cercueil Link: https://lore.kernel.org/r/20220130193147.279148-41-jic23@kernel.org --- drivers/iio/dac/m62332.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/drivers/iio/dac/m62332.c b/drivers/iio/dac/m62332.c index 225b1a374dc1..22b02f50fe41 100644 --- a/drivers/iio/dac/m62332.c +++ b/drivers/iio/dac/m62332.c @@ -25,9 +25,7 @@ struct m62332_data { struct regulator *vcc; struct mutex mutex; u8 raw[M62332_CHANNELS]; -#ifdef CONFIG_PM_SLEEP u8 save[M62332_CHANNELS]; -#endif }; static int m62332_set_value(struct iio_dev *indio_dev, u8 val, int channel) @@ -124,7 +122,6 @@ static int m62332_write_raw(struct iio_dev *indio_dev, return -EINVAL; } -#ifdef CONFIG_PM_SLEEP static int m62332_suspend(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); @@ -156,11 +153,7 @@ static int m62332_resume(struct device *dev) return m62332_set_value(indio_dev, data->save[1], 1); } -static SIMPLE_DEV_PM_OPS(m62332_pm_ops, m62332_suspend, m62332_resume); -#define M62332_PM_OPS (&m62332_pm_ops) -#else -#define M62332_PM_OPS NULL -#endif +static DEFINE_SIMPLE_DEV_PM_OPS(m62332_pm_ops, m62332_suspend, m62332_resume); static const struct iio_info m62332_info = { .read_raw = m62332_read_raw, @@ -246,7 +239,7 @@ MODULE_DEVICE_TABLE(i2c, m62332_id); static struct i2c_driver m62332_driver = { .driver = { .name = "m62332", - .pm = M62332_PM_OPS, + .pm = pm_sleep_ptr(&m62332_pm_ops), }, .probe = m62332_probe, .remove = m62332_remove, -- cgit v1.2.3 From da123e2949b467b25ca641e2573bee7a3872a9aa Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 30 Jan 2022 19:31:38 +0000 Subject: iio:imu:kmx61: Switch from CONFIG_PM* guards to pm_ptr() etc Letting the compiler remove these functions when the kernel is built without one or more of CONFIG_PM/CONFIG_PM_SLEEP support is simpler and less error prone than the use of #ifdef based config guards. Removing instances of this approach from IIO also stops them being copied into new drivers. Signed-off-by: Jonathan Cameron Reviewed-by: Paul Cercueil Link: https://lore.kernel.org/r/20220130193147.279148-42-jic23@kernel.org --- drivers/iio/imu/kmx61.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/drivers/iio/imu/kmx61.c b/drivers/iio/imu/kmx61.c index 1dabfd615dab..20ac1b4c8923 100644 --- a/drivers/iio/imu/kmx61.c +++ b/drivers/iio/imu/kmx61.c @@ -1440,7 +1440,6 @@ static int kmx61_remove(struct i2c_client *client) return 0; } -#ifdef CONFIG_PM_SLEEP static int kmx61_suspend(struct device *dev) { int ret; @@ -1466,9 +1465,7 @@ static int kmx61_resume(struct device *dev) return kmx61_set_mode(data, stby, KMX61_ACC | KMX61_MAG, true); } -#endif -#ifdef CONFIG_PM static int kmx61_runtime_suspend(struct device *dev) { struct kmx61_data *data = i2c_get_clientdata(to_i2c_client(dev)); @@ -1493,11 +1490,10 @@ static int kmx61_runtime_resume(struct device *dev) return kmx61_set_mode(data, stby, KMX61_ACC | KMX61_MAG, true); } -#endif static const struct dev_pm_ops kmx61_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(kmx61_suspend, kmx61_resume) - SET_RUNTIME_PM_OPS(kmx61_runtime_suspend, kmx61_runtime_resume, NULL) + SYSTEM_SLEEP_PM_OPS(kmx61_suspend, kmx61_resume) + RUNTIME_PM_OPS(kmx61_runtime_suspend, kmx61_runtime_resume, NULL) }; static const struct acpi_device_id kmx61_acpi_match[] = { @@ -1518,7 +1514,7 @@ static struct i2c_driver kmx61_driver = { .driver = { .name = KMX61_DRV_NAME, .acpi_match_table = ACPI_PTR(kmx61_acpi_match), - .pm = &kmx61_pm_ops, + .pm = pm_ptr(&kmx61_pm_ops), }, .probe = kmx61_probe, .remove = kmx61_remove, -- cgit v1.2.3 From 4a96b4e2fa78325eb97d76e9b22ffdfa301e366f Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 30 Jan 2022 19:31:39 +0000 Subject: iio:temperature:mlx90614: Switch from CONFIG_PM* guards to pm_ptr() etc Letting the compiler remove these functions when the kernel is built without one or more of CONFIG_PM/CONFIG_PM_SLEEP support is simpler and less error prone than the use of #ifdef based config guards. Removing instances of this approach from IIO also stops them being copied into new drivers. Signed-off-by: Jonathan Cameron Cc: Crt Mori Reviewed-by: Crt Mori Reviewed-by: Paul Cercueil Link: https://lore.kernel.org/r/20220130193147.279148-43-jic23@kernel.org --- drivers/iio/temperature/mlx90614.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/drivers/iio/temperature/mlx90614.c b/drivers/iio/temperature/mlx90614.c index afcb10ea7c44..c253a5315988 100644 --- a/drivers/iio/temperature/mlx90614.c +++ b/drivers/iio/temperature/mlx90614.c @@ -600,7 +600,6 @@ static const struct of_device_id mlx90614_of_match[] = { }; MODULE_DEVICE_TABLE(of, mlx90614_of_match); -#ifdef CONFIG_PM_SLEEP static int mlx90614_pm_suspend(struct device *dev) { struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); @@ -630,9 +629,7 @@ static int mlx90614_pm_resume(struct device *dev) return 0; } -#endif -#ifdef CONFIG_PM static int mlx90614_pm_runtime_suspend(struct device *dev) { struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); @@ -648,19 +645,18 @@ static int mlx90614_pm_runtime_resume(struct device *dev) return mlx90614_wakeup(data); } -#endif static const struct dev_pm_ops mlx90614_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(mlx90614_pm_suspend, mlx90614_pm_resume) - SET_RUNTIME_PM_OPS(mlx90614_pm_runtime_suspend, - mlx90614_pm_runtime_resume, NULL) + SYSTEM_SLEEP_PM_OPS(mlx90614_pm_suspend, mlx90614_pm_resume) + RUNTIME_PM_OPS(mlx90614_pm_runtime_suspend, + mlx90614_pm_runtime_resume, NULL) }; static struct i2c_driver mlx90614_driver = { .driver = { .name = "mlx90614", .of_match_table = mlx90614_of_match, - .pm = &mlx90614_pm_ops, + .pm = pm_ptr(&mlx90614_pm_ops), }, .probe = mlx90614_probe, .remove = mlx90614_remove, -- cgit v1.2.3 From c62433f93186352b813907b1c7a35763c8457ecc Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 30 Jan 2022 19:31:40 +0000 Subject: iio:adc:ab8500: Switch from CONFIG_PM guards to pm_ptr() etc Letting the compiler remove these functions when the kernel is built without CONFIG_PM support is simpler and less error prone than the use of #ifdef based config guards. This case uses the new DEFINE_RUNTIME_DEV_PM_OPS() to reduce boilerplate. Removing instances of this approach from IIO also stops them being copied into new drivers. Signed-off-by: Jonathan Cameron Reviewed-by: Linus Walleij Reviewed-by: Paul Cercueil Link: https://lore.kernel.org/r/20220130193147.279148-44-jic23@kernel.org --- drivers/iio/adc/ab8500-gpadc.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/drivers/iio/adc/ab8500-gpadc.c b/drivers/iio/adc/ab8500-gpadc.c index 4c46a201d4ef..930ce96e6ff5 100644 --- a/drivers/iio/adc/ab8500-gpadc.c +++ b/drivers/iio/adc/ab8500-gpadc.c @@ -942,7 +942,6 @@ static const struct iio_info ab8500_gpadc_info = { .read_raw = ab8500_gpadc_read_raw, }; -#ifdef CONFIG_PM static int ab8500_gpadc_runtime_suspend(struct device *dev) { struct iio_dev *indio_dev = dev_get_drvdata(dev); @@ -965,7 +964,6 @@ static int ab8500_gpadc_runtime_resume(struct device *dev) return ret; } -#endif /** * ab8500_gpadc_parse_channel() - process devicetree channel configuration @@ -1199,20 +1197,16 @@ static int ab8500_gpadc_remove(struct platform_device *pdev) return 0; } -static const struct dev_pm_ops ab8500_gpadc_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, - pm_runtime_force_resume) - SET_RUNTIME_PM_OPS(ab8500_gpadc_runtime_suspend, - ab8500_gpadc_runtime_resume, - NULL) -}; +static DEFINE_RUNTIME_DEV_PM_OPS(ab8500_gpadc_pm_ops, + ab8500_gpadc_runtime_suspend, + ab8500_gpadc_runtime_resume, NULL); static struct platform_driver ab8500_gpadc_driver = { .probe = ab8500_gpadc_probe, .remove = ab8500_gpadc_remove, .driver = { .name = "ab8500-gpadc", - .pm = &ab8500_gpadc_pm_ops, + .pm = pm_ptr(&ab8500_gpadc_pm_ops), }, }; builtin_platform_driver(ab8500_gpadc_driver); -- cgit v1.2.3 From d65daa79d48ed9f0532cdb57b4cde3cd25468069 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 30 Jan 2022 19:31:41 +0000 Subject: iio:adc:stm32:Switch from CONFIG_PM guards to pm_ptr() Letting the compiler remove these functions when the kernel is built without CONFIG_PM support is simpler and less error prone than the use of #ifdef based config guards. Removing instances of this approach from IIO also stops them being copied into new drivers. The new DEFINE_RUNTIME_DEV_PM_OPS() macro reduces boilerplate. Reviewed-by: Fabrice Gasnier Signed-off-by: Jonathan Cameron Cc: Olivier Moysan Reviewed-by: Paul Cercueil Link: https://lore.kernel.org/r/20220130193147.279148-45-jic23@kernel.org --- drivers/iio/adc/stm32-adc-core.c | 17 ++++++----------- drivers/iio/adc/stm32-adc.c | 12 ++++-------- 2 files changed, 10 insertions(+), 19 deletions(-) diff --git a/drivers/iio/adc/stm32-adc-core.c b/drivers/iio/adc/stm32-adc-core.c index b6e18eb101f7..142656232157 100644 --- a/drivers/iio/adc/stm32-adc-core.c +++ b/drivers/iio/adc/stm32-adc-core.c @@ -763,7 +763,6 @@ static int stm32_adc_remove(struct platform_device *pdev) return 0; } -#if defined(CONFIG_PM) static int stm32_adc_core_runtime_suspend(struct device *dev) { stm32_adc_core_hw_stop(dev); @@ -782,15 +781,11 @@ static int stm32_adc_core_runtime_idle(struct device *dev) return 0; } -#endif - -static const struct dev_pm_ops stm32_adc_core_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, - pm_runtime_force_resume) - SET_RUNTIME_PM_OPS(stm32_adc_core_runtime_suspend, - stm32_adc_core_runtime_resume, - stm32_adc_core_runtime_idle) -}; + +static DEFINE_RUNTIME_DEV_PM_OPS(stm32_adc_core_pm_ops, + stm32_adc_core_runtime_suspend, + stm32_adc_core_runtime_resume, + stm32_adc_core_runtime_idle); static const struct stm32_adc_priv_cfg stm32f4_adc_priv_cfg = { .regs = &stm32f4_adc_common_regs, @@ -836,7 +831,7 @@ static struct platform_driver stm32_adc_driver = { .driver = { .name = "stm32-adc-core", .of_match_table = stm32_adc_of_match, - .pm = &stm32_adc_core_pm_ops, + .pm = pm_ptr(&stm32_adc_core_pm_ops), }, }; module_platform_driver(stm32_adc_driver); diff --git a/drivers/iio/adc/stm32-adc.c b/drivers/iio/adc/stm32-adc.c index 897166d9e45c..a68ecbda6480 100644 --- a/drivers/iio/adc/stm32-adc.c +++ b/drivers/iio/adc/stm32-adc.c @@ -2352,7 +2352,6 @@ static int stm32_adc_remove(struct platform_device *pdev) return 0; } -#if defined(CONFIG_PM_SLEEP) static int stm32_adc_suspend(struct device *dev) { struct iio_dev *indio_dev = dev_get_drvdata(dev); @@ -2382,9 +2381,7 @@ static int stm32_adc_resume(struct device *dev) return stm32_adc_buffer_postenable(indio_dev); } -#endif -#if defined(CONFIG_PM) static int stm32_adc_runtime_suspend(struct device *dev) { return stm32_adc_hw_stop(dev); @@ -2394,12 +2391,11 @@ static int stm32_adc_runtime_resume(struct device *dev) { return stm32_adc_hw_start(dev); } -#endif static const struct dev_pm_ops stm32_adc_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(stm32_adc_suspend, stm32_adc_resume) - SET_RUNTIME_PM_OPS(stm32_adc_runtime_suspend, stm32_adc_runtime_resume, - NULL) + SYSTEM_SLEEP_PM_OPS(stm32_adc_suspend, stm32_adc_resume) + RUNTIME_PM_OPS(stm32_adc_runtime_suspend, stm32_adc_runtime_resume, + NULL) }; static const struct stm32_adc_cfg stm32f4_adc_cfg = { @@ -2453,7 +2449,7 @@ static struct platform_driver stm32_adc_driver = { .driver = { .name = "stm32-adc", .of_match_table = stm32_adc_of_match, - .pm = &stm32_adc_pm_ops, + .pm = pm_ptr(&stm32_adc_pm_ops), }, }; module_platform_driver(stm32_adc_driver); -- cgit v1.2.3 From 25d8770738db5c2e0090297e74a8447b7fc6953f Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 30 Jan 2022 19:31:42 +0000 Subject: iio:adc:rcar: Switch from CONFIG_PM guards to pm_ptr() etc Letting the compiler remove these functions when the kernel is built without CONFIG_PM support is simpler and less error prone than the use of #ifdef based config guards. Removing instances of this approach from IIO also stops them being copied into new drivers. Signed-off-by: Jonathan Cameron Reviewed-by: Paul Cercueil Link: https://lore.kernel.org/r/20220130193147.279148-46-jic23@kernel.org --- drivers/iio/adc/rcar-gyroadc.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/iio/adc/rcar-gyroadc.c b/drivers/iio/adc/rcar-gyroadc.c index 727ea6c68049..27d9e147b4b7 100644 --- a/drivers/iio/adc/rcar-gyroadc.c +++ b/drivers/iio/adc/rcar-gyroadc.c @@ -577,7 +577,6 @@ static int rcar_gyroadc_remove(struct platform_device *pdev) return 0; } -#if defined(CONFIG_PM) static int rcar_gyroadc_suspend(struct device *dev) { struct iio_dev *indio_dev = dev_get_drvdata(dev); @@ -597,10 +596,9 @@ static int rcar_gyroadc_resume(struct device *dev) return 0; } -#endif static const struct dev_pm_ops rcar_gyroadc_pm_ops = { - SET_RUNTIME_PM_OPS(rcar_gyroadc_suspend, rcar_gyroadc_resume, NULL) + RUNTIME_PM_OPS(rcar_gyroadc_suspend, rcar_gyroadc_resume, NULL) }; static struct platform_driver rcar_gyroadc_driver = { @@ -609,7 +607,7 @@ static struct platform_driver rcar_gyroadc_driver = { .driver = { .name = DRIVER_NAME, .of_match_table = rcar_gyroadc_match, - .pm = &rcar_gyroadc_pm_ops, + .pm = pm_ptr(&rcar_gyroadc_pm_ops), }, }; -- cgit v1.2.3 From ea0876120ffa4f6e83f72dae05bde189f0da20da Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 30 Jan 2022 19:31:43 +0000 Subject: iio:light:bh1780: Switch from CONFIG_PM guards to pm_ptr() etc Letting the compiler remove these functions when the kernel is built without CONFIG_PM support is simpler and less error prone than the use of #ifdef based config guards. Use the new DEFINE_RUNTIME_DEV_PM_OPS to reduce boilerplate. Removing instances of this approach from IIO also stops them being copied into new drivers. Reviewed-by: Linus Walleij Signed-off-by: Jonathan Cameron Reviewed-by: Paul Cercueil Link: https://lore.kernel.org/r/20220130193147.279148-47-jic23@kernel.org --- drivers/iio/light/bh1780.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/drivers/iio/light/bh1780.c b/drivers/iio/light/bh1780.c index abbf2e662e7d..790d3d613979 100644 --- a/drivers/iio/light/bh1780.c +++ b/drivers/iio/light/bh1780.c @@ -221,7 +221,6 @@ static int bh1780_remove(struct i2c_client *client) return 0; } -#ifdef CONFIG_PM static int bh1780_runtime_suspend(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); @@ -256,14 +255,9 @@ static int bh1780_runtime_resume(struct device *dev) return 0; } -#endif /* CONFIG_PM */ -static const struct dev_pm_ops bh1780_dev_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, - pm_runtime_force_resume) - SET_RUNTIME_PM_OPS(bh1780_runtime_suspend, - bh1780_runtime_resume, NULL) -}; +static DEFINE_RUNTIME_DEV_PM_OPS(bh1780_dev_pm_ops, bh1780_runtime_suspend, + bh1780_runtime_resume, NULL); static const struct i2c_device_id bh1780_id[] = { { "bh1780", 0 }, @@ -284,7 +278,7 @@ static struct i2c_driver bh1780_driver = { .id_table = bh1780_id, .driver = { .name = "bh1780", - .pm = &bh1780_dev_pm_ops, + .pm = pm_ptr(&bh1780_dev_pm_ops), .of_match_table = of_bh1780_match, }, }; -- cgit v1.2.3 From ae73d91e60056ef913d583f5796f9dac9ae54482 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 30 Jan 2022 19:31:44 +0000 Subject: iio:proximity:pulsedlight: Switch from CONFIG_PM guards to pm_ptr() etc Letting the compiler remove these functions when the kernel is built without CONFIG_PM support is simpler and less error prone than the use of #ifdef based config guards. Removing instances of this approach from IIO also stops them being copied into new drivers. Acked-by: Matt Ranostay Signed-off-by: Jonathan Cameron Reviewed-by: Paul Cercueil Link: https://lore.kernel.org/r/20220130193147.279148-48-jic23@kernel.org --- drivers/iio/proximity/pulsedlight-lidar-lite-v2.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c b/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c index 27026c060ab9..648ae576d6fa 100644 --- a/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c +++ b/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c @@ -338,7 +338,6 @@ static const struct of_device_id lidar_dt_ids[] = { }; MODULE_DEVICE_TABLE(of, lidar_dt_ids); -#ifdef CONFIG_PM static int lidar_pm_runtime_suspend(struct device *dev) { struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); @@ -358,18 +357,16 @@ static int lidar_pm_runtime_resume(struct device *dev) return ret; } -#endif static const struct dev_pm_ops lidar_pm_ops = { - SET_RUNTIME_PM_OPS(lidar_pm_runtime_suspend, - lidar_pm_runtime_resume, NULL) + RUNTIME_PM_OPS(lidar_pm_runtime_suspend, lidar_pm_runtime_resume, NULL) }; static struct i2c_driver lidar_driver = { .driver = { .name = LIDAR_DRV_NAME, .of_match_table = lidar_dt_ids, - .pm = &lidar_pm_ops, + .pm = pm_ptr(&lidar_pm_ops), }, .probe = lidar_probe, .remove = lidar_remove, -- cgit v1.2.3 From 05a9ddc8fc54e416939badec1cb2969917187812 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 30 Jan 2022 19:31:45 +0000 Subject: iio:chemical:atlas: Switch from CONFIG_PM guards to pm_ptr() etc Letting the compiler remove these functions when the kernel is built without CONFIG_PM support is simpler and less error prone than the use of #ifdef based config guards. Removing instances of this approach from IIO also stops them being copied into new drivers. Acked-by: Matt Ranostay Signed-off-by: Jonathan Cameron Reviewed-by: Paul Cercueil Link: https://lore.kernel.org/r/20220130193147.279148-49-jic23@kernel.org --- drivers/iio/chemical/atlas-sensor.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/iio/chemical/atlas-sensor.c b/drivers/iio/chemical/atlas-sensor.c index a8211dd20b35..56dea9734c8d 100644 --- a/drivers/iio/chemical/atlas-sensor.c +++ b/drivers/iio/chemical/atlas-sensor.c @@ -737,7 +737,6 @@ static int atlas_remove(struct i2c_client *client) return atlas_set_powermode(data, 0); } -#ifdef CONFIG_PM static int atlas_runtime_suspend(struct device *dev) { struct atlas_data *data = @@ -753,18 +752,16 @@ static int atlas_runtime_resume(struct device *dev) return atlas_set_powermode(data, 1); } -#endif static const struct dev_pm_ops atlas_pm_ops = { - SET_RUNTIME_PM_OPS(atlas_runtime_suspend, - atlas_runtime_resume, NULL) + RUNTIME_PM_OPS(atlas_runtime_suspend, atlas_runtime_resume, NULL) }; static struct i2c_driver atlas_driver = { .driver = { .name = ATLAS_DRV_NAME, .of_match_table = atlas_dt_ids, - .pm = &atlas_pm_ops, + .pm = pm_ptr(&atlas_pm_ops), }, .probe = atlas_probe, .remove = atlas_remove, -- cgit v1.2.3 From 33b0a376f9048770e3b515063a6d87feff85c83d Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 30 Jan 2022 19:31:46 +0000 Subject: iio:light:rpr0521: Switch from CONFIG_PM guards to pm_ptr() etc Letting the compiler remove these functions when the kernel is built without CONFIG_PM support is simpler and less error prone than the use of #ifdef based config guards. Removing instances of this approach from IIO also stops them being copied into new drivers. Signed-off-by: Jonathan Cameron Cc: Mikko Koivunen Reviewed-by: Paul Cercueil Link: https://lore.kernel.org/r/20220130193147.279148-50-jic23@kernel.org --- drivers/iio/light/rpr0521.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/iio/light/rpr0521.c b/drivers/iio/light/rpr0521.c index c2dd8a3d4217..dabdd05f0e2c 100644 --- a/drivers/iio/light/rpr0521.c +++ b/drivers/iio/light/rpr0521.c @@ -1055,7 +1055,6 @@ static int rpr0521_remove(struct i2c_client *client) return 0; } -#ifdef CONFIG_PM static int rpr0521_runtime_suspend(struct device *dev) { struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); @@ -1101,11 +1100,9 @@ static int rpr0521_runtime_resume(struct device *dev) return 0; } -#endif static const struct dev_pm_ops rpr0521_pm_ops = { - SET_RUNTIME_PM_OPS(rpr0521_runtime_suspend, - rpr0521_runtime_resume, NULL) + RUNTIME_PM_OPS(rpr0521_runtime_suspend, rpr0521_runtime_resume, NULL) }; static const struct acpi_device_id rpr0521_acpi_match[] = { @@ -1124,7 +1121,7 @@ MODULE_DEVICE_TABLE(i2c, rpr0521_id); static struct i2c_driver rpr0521_driver = { .driver = { .name = RPR0521_DRV_NAME, - .pm = &rpr0521_pm_ops, + .pm = pm_ptr(&rpr0521_pm_ops), .acpi_match_table = ACPI_PTR(rpr0521_acpi_match), }, .probe = rpr0521_probe, -- cgit v1.2.3 From ade59a7af270d2447b4d8b4001a6d46d464a0191 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 30 Jan 2022 19:31:47 +0000 Subject: iio:adc:stm32*: Use pm[_sleep]_ptr() etc to avoid need to make pm __maybe_unused The combinations of either * pm_sleep_ptr() and DEFINE_SIMPLE_DEV_PM_OPS() * pm_ptr() and RUNTIME_PM_OPS()/SYSTEM_SLEEP_PM_OPS Make sure the functions are always visible to the compiler and removed by it rather than requring #ifdef magic. This removes the need to mark the functions as __maybe_unused and saves additional space with some build options as the dev_pm_ops structure itself can be dropped automatically if CONFIG_PM is not enabled. Signed-off-by: Jonathan Cameron Cc: Olivier Moysan Cc: Fabrice Gasnier Reviewed-by: Fabrice Gasnier Reviewed-by: Paul Cercueil Link: https://lore.kernel.org/r/20220130193147.279148-51-jic23@kernel.org --- drivers/iio/adc/stm32-dfsdm-adc.c | 11 ++++++----- drivers/iio/adc/stm32-dfsdm-core.c | 19 +++++++++---------- drivers/iio/dac/stm32-dac-core.c | 16 ++++++++-------- drivers/iio/dac/stm32-dac.c | 9 ++++----- drivers/iio/trigger/stm32-timer-trigger.c | 12 ++++++------ 5 files changed, 33 insertions(+), 34 deletions(-) diff --git a/drivers/iio/adc/stm32-dfsdm-adc.c b/drivers/iio/adc/stm32-dfsdm-adc.c index 1cfefb3b5e56..9704cf0b9753 100644 --- a/drivers/iio/adc/stm32-dfsdm-adc.c +++ b/drivers/iio/adc/stm32-dfsdm-adc.c @@ -1632,7 +1632,7 @@ static int stm32_dfsdm_adc_remove(struct platform_device *pdev) return 0; } -static int __maybe_unused stm32_dfsdm_adc_suspend(struct device *dev) +static int stm32_dfsdm_adc_suspend(struct device *dev) { struct iio_dev *indio_dev = dev_get_drvdata(dev); @@ -1642,7 +1642,7 @@ static int __maybe_unused stm32_dfsdm_adc_suspend(struct device *dev) return 0; } -static int __maybe_unused stm32_dfsdm_adc_resume(struct device *dev) +static int stm32_dfsdm_adc_resume(struct device *dev) { struct iio_dev *indio_dev = dev_get_drvdata(dev); struct stm32_dfsdm_adc *adc = iio_priv(indio_dev); @@ -1665,14 +1665,15 @@ static int __maybe_unused stm32_dfsdm_adc_resume(struct device *dev) return 0; } -static SIMPLE_DEV_PM_OPS(stm32_dfsdm_adc_pm_ops, - stm32_dfsdm_adc_suspend, stm32_dfsdm_adc_resume); +static DEFINE_SIMPLE_DEV_PM_OPS(stm32_dfsdm_adc_pm_ops, + stm32_dfsdm_adc_suspend, + stm32_dfsdm_adc_resume); static struct platform_driver stm32_dfsdm_adc_driver = { .driver = { .name = "stm32-dfsdm-adc", .of_match_table = stm32_dfsdm_adc_match, - .pm = &stm32_dfsdm_adc_pm_ops, + .pm = pm_sleep_ptr(&stm32_dfsdm_adc_pm_ops), }, .probe = stm32_dfsdm_adc_probe, .remove = stm32_dfsdm_adc_remove, diff --git a/drivers/iio/adc/stm32-dfsdm-core.c b/drivers/iio/adc/stm32-dfsdm-core.c index a627af9a825e..a3d4de6ba4c2 100644 --- a/drivers/iio/adc/stm32-dfsdm-core.c +++ b/drivers/iio/adc/stm32-dfsdm-core.c @@ -381,7 +381,7 @@ static int stm32_dfsdm_core_remove(struct platform_device *pdev) return 0; } -static int __maybe_unused stm32_dfsdm_core_suspend(struct device *dev) +static int stm32_dfsdm_core_suspend(struct device *dev) { struct stm32_dfsdm *dfsdm = dev_get_drvdata(dev); struct dfsdm_priv *priv = to_stm32_dfsdm_priv(dfsdm); @@ -397,7 +397,7 @@ static int __maybe_unused stm32_dfsdm_core_suspend(struct device *dev) return pinctrl_pm_select_sleep_state(dev); } -static int __maybe_unused stm32_dfsdm_core_resume(struct device *dev) +static int stm32_dfsdm_core_resume(struct device *dev) { struct stm32_dfsdm *dfsdm = dev_get_drvdata(dev); struct dfsdm_priv *priv = to_stm32_dfsdm_priv(dfsdm); @@ -414,7 +414,7 @@ static int __maybe_unused stm32_dfsdm_core_resume(struct device *dev) return pm_runtime_force_resume(dev); } -static int __maybe_unused stm32_dfsdm_core_runtime_suspend(struct device *dev) +static int stm32_dfsdm_core_runtime_suspend(struct device *dev) { struct stm32_dfsdm *dfsdm = dev_get_drvdata(dev); @@ -423,7 +423,7 @@ static int __maybe_unused stm32_dfsdm_core_runtime_suspend(struct device *dev) return 0; } -static int __maybe_unused stm32_dfsdm_core_runtime_resume(struct device *dev) +static int stm32_dfsdm_core_runtime_resume(struct device *dev) { struct stm32_dfsdm *dfsdm = dev_get_drvdata(dev); @@ -431,11 +431,10 @@ static int __maybe_unused stm32_dfsdm_core_runtime_resume(struct device *dev) } static const struct dev_pm_ops stm32_dfsdm_core_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(stm32_dfsdm_core_suspend, - stm32_dfsdm_core_resume) - SET_RUNTIME_PM_OPS(stm32_dfsdm_core_runtime_suspend, - stm32_dfsdm_core_runtime_resume, - NULL) + SYSTEM_SLEEP_PM_OPS(stm32_dfsdm_core_suspend, stm32_dfsdm_core_resume) + RUNTIME_PM_OPS(stm32_dfsdm_core_runtime_suspend, + stm32_dfsdm_core_runtime_resume, + NULL) }; static struct platform_driver stm32_dfsdm_driver = { @@ -444,7 +443,7 @@ static struct platform_driver stm32_dfsdm_driver = { .driver = { .name = "stm32-dfsdm", .of_match_table = stm32_dfsdm_of_match, - .pm = &stm32_dfsdm_core_pm_ops, + .pm = pm_ptr(&stm32_dfsdm_core_pm_ops), }, }; diff --git a/drivers/iio/dac/stm32-dac-core.c b/drivers/iio/dac/stm32-dac-core.c index bd7a3b20e645..83bf184e3adc 100644 --- a/drivers/iio/dac/stm32-dac-core.c +++ b/drivers/iio/dac/stm32-dac-core.c @@ -195,7 +195,7 @@ static int stm32_dac_remove(struct platform_device *pdev) return 0; } -static int __maybe_unused stm32_dac_core_resume(struct device *dev) +static int stm32_dac_core_resume(struct device *dev) { struct stm32_dac_common *common = dev_get_drvdata(dev); struct stm32_dac_priv *priv = to_stm32_dac_priv(common); @@ -213,23 +213,23 @@ static int __maybe_unused stm32_dac_core_resume(struct device *dev) return pm_runtime_force_resume(dev); } -static int __maybe_unused stm32_dac_core_runtime_suspend(struct device *dev) +static int stm32_dac_core_runtime_suspend(struct device *dev) { stm32_dac_core_hw_stop(dev); return 0; } -static int __maybe_unused stm32_dac_core_runtime_resume(struct device *dev) +static int stm32_dac_core_runtime_resume(struct device *dev) { return stm32_dac_core_hw_start(dev); } static const struct dev_pm_ops stm32_dac_core_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, stm32_dac_core_resume) - SET_RUNTIME_PM_OPS(stm32_dac_core_runtime_suspend, - stm32_dac_core_runtime_resume, - NULL) + SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, stm32_dac_core_resume) + RUNTIME_PM_OPS(stm32_dac_core_runtime_suspend, + stm32_dac_core_runtime_resume, + NULL) }; static const struct stm32_dac_cfg stm32h7_dac_cfg = { @@ -253,7 +253,7 @@ static struct platform_driver stm32_dac_driver = { .driver = { .name = "stm32-dac-core", .of_match_table = stm32_dac_of_match, - .pm = &stm32_dac_core_pm_ops, + .pm = pm_ptr(&stm32_dac_core_pm_ops), }, }; module_platform_driver(stm32_dac_driver); diff --git a/drivers/iio/dac/stm32-dac.c b/drivers/iio/dac/stm32-dac.c index cd71cc4553a7..b20192a071cb 100644 --- a/drivers/iio/dac/stm32-dac.c +++ b/drivers/iio/dac/stm32-dac.c @@ -372,7 +372,7 @@ static int stm32_dac_remove(struct platform_device *pdev) return 0; } -static int __maybe_unused stm32_dac_suspend(struct device *dev) +static int stm32_dac_suspend(struct device *dev) { struct iio_dev *indio_dev = dev_get_drvdata(dev); int channel = indio_dev->channels[0].channel; @@ -386,9 +386,8 @@ static int __maybe_unused stm32_dac_suspend(struct device *dev) return pm_runtime_force_suspend(dev); } -static const struct dev_pm_ops stm32_dac_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(stm32_dac_suspend, pm_runtime_force_resume) -}; +static DEFINE_SIMPLE_DEV_PM_OPS(stm32_dac_pm_ops, stm32_dac_suspend, + pm_runtime_force_resume); static const struct of_device_id stm32_dac_of_match[] = { { .compatible = "st,stm32-dac", }, @@ -402,7 +401,7 @@ static struct platform_driver stm32_dac_driver = { .driver = { .name = "stm32-dac", .of_match_table = stm32_dac_of_match, - .pm = &stm32_dac_pm_ops, + .pm = pm_sleep_ptr(&stm32_dac_pm_ops), }, }; module_platform_driver(stm32_dac_driver); diff --git a/drivers/iio/trigger/stm32-timer-trigger.c b/drivers/iio/trigger/stm32-timer-trigger.c index 5049d9ecfc1a..3643c4afae67 100644 --- a/drivers/iio/trigger/stm32-timer-trigger.c +++ b/drivers/iio/trigger/stm32-timer-trigger.c @@ -828,7 +828,7 @@ static int stm32_timer_trigger_remove(struct platform_device *pdev) return 0; } -static int __maybe_unused stm32_timer_trigger_suspend(struct device *dev) +static int stm32_timer_trigger_suspend(struct device *dev) { struct stm32_timer_trigger *priv = dev_get_drvdata(dev); @@ -850,7 +850,7 @@ static int __maybe_unused stm32_timer_trigger_suspend(struct device *dev) return 0; } -static int __maybe_unused stm32_timer_trigger_resume(struct device *dev) +static int stm32_timer_trigger_resume(struct device *dev) { struct stm32_timer_trigger *priv = dev_get_drvdata(dev); int ret; @@ -876,9 +876,9 @@ static int __maybe_unused stm32_timer_trigger_resume(struct device *dev) return 0; } -static SIMPLE_DEV_PM_OPS(stm32_timer_trigger_pm_ops, - stm32_timer_trigger_suspend, - stm32_timer_trigger_resume); +static DEFINE_SIMPLE_DEV_PM_OPS(stm32_timer_trigger_pm_ops, + stm32_timer_trigger_suspend, + stm32_timer_trigger_resume); static const struct stm32_timer_trigger_cfg stm32_timer_trg_cfg = { .valids_table = valids_table, @@ -908,7 +908,7 @@ static struct platform_driver stm32_timer_trigger_driver = { .driver = { .name = "stm32-timer-trigger", .of_match_table = stm32_trig_of_match, - .pm = &stm32_timer_trigger_pm_ops, + .pm = pm_sleep_ptr(&stm32_timer_trigger_pm_ops), }, }; module_platform_driver(stm32_timer_trigger_driver); -- cgit v1.2.3 From f281e4ddbbc0b60f061bc18a2834e9363ba85f9f Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 6 Feb 2022 19:03:09 +0000 Subject: staging:iio:adc:ad7280a: Fix handing of device address bit reversing. The bit reversal was wrong for bits 1 and 3 of the 5 bits. Result is driver failure to probe if you have more than 2 daisy-chained devices. Discovered via QEMU based device emulation. Fixes tag is for when this moved from a macro to a function, but it was broken before that. Signed-off-by: Jonathan Cameron Fixes: 065a7c0b1fec ("Staging: iio: adc: ad7280a.c: Fixed Macro argument reuse") Reviewed-by: Marcelo Schmitt Link: https://lore.kernel.org/r/20220206190328.333093-2-jic23@kernel.org --- drivers/staging/iio/adc/ad7280a.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/staging/iio/adc/ad7280a.c b/drivers/staging/iio/adc/ad7280a.c index fef0055b8990..20183b2ea127 100644 --- a/drivers/staging/iio/adc/ad7280a.c +++ b/drivers/staging/iio/adc/ad7280a.c @@ -107,9 +107,9 @@ static unsigned int ad7280a_devaddr(unsigned int addr) { return ((addr & 0x1) << 4) | - ((addr & 0x2) << 3) | + ((addr & 0x2) << 2) | (addr & 0x4) | - ((addr & 0x8) >> 3) | + ((addr & 0x8) >> 2) | ((addr & 0x10) >> 4); } -- cgit v1.2.3 From 4c59aabd9a93d8f867d9f6aa0407cc6a7db47fa5 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 6 Feb 2022 19:03:10 +0000 Subject: staging:iio:adc:ad7280a: Register define cleanup. 1. Postfix register addresses with _REG to distinguish them from fields within the registers 2. Switch to using FIELD_PREP and masks to aid readability. 3. Shorten a few defines to make the lines remain a sensible length. 4. Fix an issue whether where an CTRL_LB field is set in CTRL_HB. 5. Fix wrong AUX1_3_4 which should be AUX_1_3_5 according to table 14 in the datasheet. Signed-off-by: Jonathan Cameron Reviewed-by: Marcelo Schmitt Link: https://lore.kernel.org/r/20220206190328.333093-3-jic23@kernel.org --- drivers/staging/iio/adc/ad7280a.c | 285 ++++++++++++++++++++------------------ 1 file changed, 154 insertions(+), 131 deletions(-) diff --git a/drivers/staging/iio/adc/ad7280a.c b/drivers/staging/iio/adc/ad7280a.c index 20183b2ea127..0f64b2fbfa7a 100644 --- a/drivers/staging/iio/adc/ad7280a.c +++ b/drivers/staging/iio/adc/ad7280a.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -23,78 +24,86 @@ #include "ad7280a.h" /* Registers */ -#define AD7280A_CELL_VOLTAGE_1 0x0 /* D11 to D0, Read only */ -#define AD7280A_CELL_VOLTAGE_2 0x1 /* D11 to D0, Read only */ -#define AD7280A_CELL_VOLTAGE_3 0x2 /* D11 to D0, Read only */ -#define AD7280A_CELL_VOLTAGE_4 0x3 /* D11 to D0, Read only */ -#define AD7280A_CELL_VOLTAGE_5 0x4 /* D11 to D0, Read only */ -#define AD7280A_CELL_VOLTAGE_6 0x5 /* D11 to D0, Read only */ -#define AD7280A_AUX_ADC_1 0x6 /* D11 to D0, Read only */ -#define AD7280A_AUX_ADC_2 0x7 /* D11 to D0, Read only */ -#define AD7280A_AUX_ADC_3 0x8 /* D11 to D0, Read only */ -#define AD7280A_AUX_ADC_4 0x9 /* D11 to D0, Read only */ -#define AD7280A_AUX_ADC_5 0xA /* D11 to D0, Read only */ -#define AD7280A_AUX_ADC_6 0xB /* D11 to D0, Read only */ -#define AD7280A_SELF_TEST 0xC /* D11 to D0, Read only */ -#define AD7280A_CONTROL_HB 0xD /* D15 to D8, Read/write */ -#define AD7280A_CONTROL_LB 0xE /* D7 to D0, Read/write */ -#define AD7280A_CELL_OVERVOLTAGE 0xF /* D7 to D0, Read/write */ -#define AD7280A_CELL_UNDERVOLTAGE 0x10 /* D7 to D0, Read/write */ -#define AD7280A_AUX_ADC_OVERVOLTAGE 0x11 /* D7 to D0, Read/write */ -#define AD7280A_AUX_ADC_UNDERVOLTAGE 0x12 /* D7 to D0, Read/write */ -#define AD7280A_ALERT 0x13 /* D7 to D0, Read/write */ -#define AD7280A_CELL_BALANCE 0x14 /* D7 to D0, Read/write */ -#define AD7280A_CB1_TIMER 0x15 /* D7 to D0, Read/write */ -#define AD7280A_CB2_TIMER 0x16 /* D7 to D0, Read/write */ -#define AD7280A_CB3_TIMER 0x17 /* D7 to D0, Read/write */ -#define AD7280A_CB4_TIMER 0x18 /* D7 to D0, Read/write */ -#define AD7280A_CB5_TIMER 0x19 /* D7 to D0, Read/write */ -#define AD7280A_CB6_TIMER 0x1A /* D7 to D0, Read/write */ -#define AD7280A_PD_TIMER 0x1B /* D7 to D0, Read/write */ -#define AD7280A_READ 0x1C /* D7 to D0, Read/write */ -#define AD7280A_CNVST_CONTROL 0x1D /* D7 to D0, Read/write */ - -/* Bits and Masks */ -#define AD7280A_CTRL_HB_CONV_INPUT_ALL 0 -#define AD7280A_CTRL_HB_CONV_INPUT_6CELL_AUX1_3_4 BIT(6) -#define AD7280A_CTRL_HB_CONV_INPUT_6CELL BIT(7) -#define AD7280A_CTRL_HB_CONV_INPUT_SELF_TEST (BIT(7) | BIT(6)) -#define AD7280A_CTRL_HB_CONV_RES_READ_ALL 0 -#define AD7280A_CTRL_HB_CONV_RES_READ_6CELL_AUX1_3_4 BIT(4) -#define AD7280A_CTRL_HB_CONV_RES_READ_6CELL BIT(5) -#define AD7280A_CTRL_HB_CONV_RES_READ_NO (BIT(5) | BIT(4)) -#define AD7280A_CTRL_HB_CONV_START_CNVST 0 -#define AD7280A_CTRL_HB_CONV_START_CS BIT(3) -#define AD7280A_CTRL_HB_CONV_AVG_DIS 0 -#define AD7280A_CTRL_HB_CONV_AVG_2 BIT(1) -#define AD7280A_CTRL_HB_CONV_AVG_4 BIT(2) -#define AD7280A_CTRL_HB_CONV_AVG_8 (BIT(2) | BIT(1)) -#define AD7280A_CTRL_HB_CONV_AVG(x) ((x) << 1) -#define AD7280A_CTRL_HB_PWRDN_SW BIT(0) - -#define AD7280A_CTRL_LB_SWRST BIT(7) -#define AD7280A_CTRL_LB_ACQ_TIME_400ns 0 -#define AD7280A_CTRL_LB_ACQ_TIME_800ns BIT(5) -#define AD7280A_CTRL_LB_ACQ_TIME_1200ns BIT(6) -#define AD7280A_CTRL_LB_ACQ_TIME_1600ns (BIT(6) | BIT(5)) -#define AD7280A_CTRL_LB_ACQ_TIME(x) ((x) << 5) -#define AD7280A_CTRL_LB_MUST_SET BIT(4) -#define AD7280A_CTRL_LB_THERMISTOR_EN BIT(3) -#define AD7280A_CTRL_LB_LOCK_DEV_ADDR BIT(2) -#define AD7280A_CTRL_LB_INC_DEV_ADDR BIT(1) -#define AD7280A_CTRL_LB_DAISY_CHAIN_RB_EN BIT(0) - -#define AD7280A_ALERT_GEN_STATIC_HIGH BIT(6) -#define AD7280A_ALERT_RELAY_SIG_CHAIN_DOWN (BIT(7) | BIT(6)) +#define AD7280A_CELL_VOLTAGE_1_REG 0x0 /* D11 to D0, Read only */ +#define AD7280A_CELL_VOLTAGE_2_REG 0x1 /* D11 to D0, Read only */ +#define AD7280A_CELL_VOLTAGE_3_REG 0x2 /* D11 to D0, Read only */ +#define AD7280A_CELL_VOLTAGE_4_REG 0x3 /* D11 to D0, Read only */ +#define AD7280A_CELL_VOLTAGE_5_REG 0x4 /* D11 to D0, Read only */ +#define AD7280A_CELL_VOLTAGE_6_REG 0x5 /* D11 to D0, Read only */ +#define AD7280A_AUX_ADC_1_REG 0x6 /* D11 to D0, Read only */ +#define AD7280A_AUX_ADC_2_REG 0x7 /* D11 to D0, Read only */ +#define AD7280A_AUX_ADC_3_REG 0x8 /* D11 to D0, Read only */ +#define AD7280A_AUX_ADC_4_REG 0x9 /* D11 to D0, Read only */ +#define AD7280A_AUX_ADC_5_REG 0xA /* D11 to D0, Read only */ +#define AD7280A_AUX_ADC_6_REG 0xB /* D11 to D0, Read only */ +#define AD7280A_SELF_TEST_REG 0xC /* D11 to D0, Read only */ + +#define AD7280A_CTRL_HB_REG 0xD /* D15 to D8, Read/write */ +#define AD7280A_CTRL_HB_CONV_INPUT_MSK GENMASK(7, 6) +#define AD7280A_CTRL_HB_CONV_INPUT_ALL 0 +#define AD7280A_CTRL_HB_CONV_INPUT_6CELL_AUX1_3_5 1 +#define AD7280A_CTRL_HB_CONV_INPUT_6CELL 2 +#define AD7280A_CTRL_HB_CONV_INPUT_SELF_TEST 3 +#define AD7280A_CTRL_HB_CONV_RREAD_MSK GENMASK(5, 4) +#define AD7280A_CTRL_HB_CONV_RREAD_ALL 0 +#define AD7280A_CTRL_HB_CONV_RREAD_6CELL_AUX1_3_5 1 +#define AD7280A_CTRL_HB_CONV_RREAD_6CELL 2 +#define AD7280A_CTRL_HB_CONV_RREAD_NO 3 +#define AD7280A_CTRL_HB_CONV_START_MSK BIT(3) +#define AD7280A_CTRL_HB_CONV_START_CNVST 0 +#define AD7280A_CTRL_HB_CONV_START_CS 1 +#define AD7280A_CTRL_HB_CONV_AVG_MSK GENMASK(2, 1) +#define AD7280A_CTRL_HB_CONV_AVG_DIS 0 +#define AD7280A_CTRL_HB_CONV_AVG_2 1 +#define AD7280A_CTRL_HB_CONV_AVG_4 2 +#define AD7280A_CTRL_HB_CONV_AVG_8 3 +#define AD7280A_CTRL_HB_PWRDN_SW BIT(0) + +#define AD7280A_CTRL_LB_REG 0xE /* D7 to D0, Read/write */ +#define AD7280A_CTRL_LB_SWRST_MSK BIT(7) +#define AD7280A_CTRL_LB_ACQ_TIME_MSK GENMASK(6, 5) +#define AD7280A_CTRL_LB_ACQ_TIME_400ns 0 +#define AD7280A_CTRL_LB_ACQ_TIME_800ns 1 +#define AD7280A_CTRL_LB_ACQ_TIME_1200ns 2 +#define AD7280A_CTRL_LB_ACQ_TIME_1600ns 3 +#define AD7280A_CTRL_LB_MUST_SET BIT(4) +#define AD7280A_CTRL_LB_THERMISTOR_MSK BIT(3) +#define AD7280A_CTRL_LB_LOCK_DEV_ADDR_MSK BIT(2) +#define AD7280A_CTRL_LB_INC_DEV_ADDR_MSK BIT(1) +#define AD7280A_CTRL_LB_DAISY_CHAIN_RB_MSK BIT(0) + +#define AD7280A_CELL_OVERVOLTAGE_REG 0xF /* D7 to D0, Read/write */ +#define AD7280A_CELL_UNDERVOLTAGE_REG 0x10 /* D7 to D0, Read/write */ +#define AD7280A_AUX_ADC_OVERVOLTAGE_REG 0x11 /* D7 to D0, Read/write */ +#define AD7280A_AUX_ADC_UNDERVOLTAGE_REG 0x12 /* D7 to D0, Read/write */ + +#define AD7280A_ALERT_REG 0x13 /* D7 to D0, Read/write */ +#define AD7280A_ALERT_GEN_STATIC_HIGH BIT(6) +#define AD7280A_ALERT_RELAY_SIG_CHAIN_DOWN (BIT(7) | BIT(6)) + +#define AD7280A_CELL_BALANCE_REG 0x14 /* D7 to D0, Read/write */ +#define AD7280A_CB1_TIMER_REG 0x15 /* D7 to D0, Read/write */ +#define AD7280A_CB_TIMER_VAL_MSK GENMASK(7, 3) +#define AD7280A_CB2_TIMER_REG 0x16 /* D7 to D0, Read/write */ +#define AD7280A_CB3_TIMER_REG 0x17 /* D7 to D0, Read/write */ +#define AD7280A_CB4_TIMER_REG 0x18 /* D7 to D0, Read/write */ +#define AD7280A_CB5_TIMER_REG 0x19 /* D7 to D0, Read/write */ +#define AD7280A_CB6_TIMER_REG 0x1A /* D7 to D0, Read/write */ +#define AD7280A_PD_TIMER_REG 0x1B /* D7 to D0, Read/write */ +#define AD7280A_READ_REG 0x1C /* D7 to D0, Read/write */ +#define AD7280A_READ_ADDR_MSK GENMASK(7, 2) +#define AD7280A_CNVST_CTRL_REG 0x1D /* D7 to D0, Read/write */ + +/* Magic value used to indicate this special case */ #define AD7280A_ALL_CELLS (0xAD << 16) #define AD7280A_MAX_SPI_CLK_HZ 700000 /* < 1MHz */ #define AD7280A_MAX_CHAIN 8 #define AD7280A_CELLS_PER_DEV 6 #define AD7280A_BITS 12 -#define AD7280A_NUM_CH (AD7280A_AUX_ADC_6 - \ - AD7280A_CELL_VOLTAGE_1 + 1) +#define AD7280A_NUM_CH (AD7280A_AUX_ADC_6_REG - \ + AD7280A_CELL_VOLTAGE_1_REG + 1) #define AD7280A_CALC_VOLTAGE_CHAN_NUM(d, c) (((d) * AD7280A_CELLS_PER_DEV) + \ (c)) @@ -222,23 +231,28 @@ static int ad7280_read(struct ad7280_state *st, unsigned int devaddr, unsigned int tmp; /* turns off the read operation on all parts */ - ret = ad7280_write(st, AD7280A_DEVADDR_MASTER, AD7280A_CONTROL_HB, 1, - AD7280A_CTRL_HB_CONV_INPUT_ALL | - AD7280A_CTRL_HB_CONV_RES_READ_NO | + ret = ad7280_write(st, AD7280A_DEVADDR_MASTER, AD7280A_CTRL_HB_REG, 1, + FIELD_PREP(AD7280A_CTRL_HB_CONV_INPUT_MSK, + AD7280A_CTRL_HB_CONV_INPUT_ALL) | + FIELD_PREP(AD7280A_CTRL_HB_CONV_RREAD_MSK, + AD7280A_CTRL_HB_CONV_RREAD_NO) | st->ctrl_hb); if (ret) return ret; /* turns on the read operation on the addressed part */ - ret = ad7280_write(st, devaddr, AD7280A_CONTROL_HB, 0, - AD7280A_CTRL_HB_CONV_INPUT_ALL | - AD7280A_CTRL_HB_CONV_RES_READ_ALL | + ret = ad7280_write(st, devaddr, AD7280A_CTRL_HB_REG, 0, + FIELD_PREP(AD7280A_CTRL_HB_CONV_INPUT_MSK, + AD7280A_CTRL_HB_CONV_INPUT_ALL) | + FIELD_PREP(AD7280A_CTRL_HB_CONV_RREAD_MSK, + AD7280A_CTRL_HB_CONV_RREAD_ALL) | st->ctrl_hb); if (ret) return ret; /* Set register address on the part to be read from */ - ret = ad7280_write(st, devaddr, AD7280A_READ, 0, addr << 2); + ret = ad7280_write(st, devaddr, AD7280A_READ_REG, 0, + FIELD_PREP(AD7280A_READ_ADDR_MSK, addr)); if (ret) return ret; @@ -261,21 +275,27 @@ static int ad7280_read_channel(struct ad7280_state *st, unsigned int devaddr, int ret; unsigned int tmp; - ret = ad7280_write(st, devaddr, AD7280A_READ, 0, addr << 2); + ret = ad7280_write(st, devaddr, AD7280A_READ_REG, 0, + FIELD_PREP(AD7280A_READ_ADDR_MSK, addr)); if (ret) return ret; - ret = ad7280_write(st, AD7280A_DEVADDR_MASTER, AD7280A_CONTROL_HB, 1, - AD7280A_CTRL_HB_CONV_INPUT_ALL | - AD7280A_CTRL_HB_CONV_RES_READ_NO | + ret = ad7280_write(st, AD7280A_DEVADDR_MASTER, AD7280A_CTRL_HB_REG, 1, + FIELD_PREP(AD7280A_CTRL_HB_CONV_INPUT_MSK, + AD7280A_CTRL_HB_CONV_INPUT_ALL) | + FIELD_PREP(AD7280A_CTRL_HB_CONV_RREAD_MSK, + AD7280A_CTRL_HB_CONV_RREAD_NO) | st->ctrl_hb); if (ret) return ret; - ret = ad7280_write(st, devaddr, AD7280A_CONTROL_HB, 0, - AD7280A_CTRL_HB_CONV_INPUT_ALL | - AD7280A_CTRL_HB_CONV_RES_READ_ALL | - AD7280A_CTRL_HB_CONV_START_CS | + ret = ad7280_write(st, devaddr, AD7280A_CTRL_HB_REG, 0, + FIELD_PREP(AD7280A_CTRL_HB_CONV_INPUT_MSK, + AD7280A_CTRL_HB_CONV_INPUT_ALL) | + FIELD_PREP(AD7280A_CTRL_HB_CONV_RREAD_MSK, + AD7280A_CTRL_HB_CONV_RREAD_ALL) | + FIELD_PREP(AD7280A_CTRL_HB_CONV_START_MSK, + AD7280A_CTRL_HB_CONV_START_CS) | st->ctrl_hb); if (ret) return ret; @@ -301,15 +321,18 @@ static int ad7280_read_all_channels(struct ad7280_state *st, unsigned int cnt, int i, ret; unsigned int tmp, sum = 0; - ret = ad7280_write(st, AD7280A_DEVADDR_MASTER, AD7280A_READ, 1, - AD7280A_CELL_VOLTAGE_1 << 2); + ret = ad7280_write(st, AD7280A_DEVADDR_MASTER, AD7280A_READ_REG, 1, + AD7280A_CELL_VOLTAGE_1_REG << 2); if (ret) return ret; - ret = ad7280_write(st, AD7280A_DEVADDR_MASTER, AD7280A_CONTROL_HB, 1, - AD7280A_CTRL_HB_CONV_INPUT_ALL | - AD7280A_CTRL_HB_CONV_RES_READ_ALL | - AD7280A_CTRL_HB_CONV_START_CS | + ret = ad7280_write(st, AD7280A_DEVADDR_MASTER, AD7280A_CTRL_HB_REG, 1, + FIELD_PREP(AD7280A_CTRL_HB_CONV_INPUT_MSK, + AD7280A_CTRL_HB_CONV_INPUT_ALL) | + FIELD_PREP(AD7280A_CTRL_HB_CONV_RREAD_MSK, + AD7280A_CTRL_HB_CONV_RREAD_ALL) | + FIELD_PREP(AD7280A_CTRL_HB_CONV_START_MSK, + AD7280A_CTRL_HB_CONV_START_CS) | st->ctrl_hb); if (ret) return ret; @@ -327,7 +350,7 @@ static int ad7280_read_all_channels(struct ad7280_state *st, unsigned int cnt, if (array) array[i] = tmp; /* only sum cell voltages */ - if (((tmp >> 23) & 0xF) <= AD7280A_CELL_VOLTAGE_6) + if (((tmp >> 23) & 0xF) <= AD7280A_CELL_VOLTAGE_6_REG) sum += ((tmp >> 11) & 0xFFF); } @@ -338,7 +361,7 @@ static void ad7280_sw_power_down(void *data) { struct ad7280_state *st = data; - ad7280_write(st, AD7280A_DEVADDR_MASTER, AD7280A_CONTROL_HB, 1, + ad7280_write(st, AD7280A_DEVADDR_MASTER, AD7280A_CTRL_HB_REG, 1, AD7280A_CTRL_HB_PWRDN_SW | st->ctrl_hb); } @@ -347,25 +370,26 @@ static int ad7280_chain_setup(struct ad7280_state *st) unsigned int val, n; int ret; - ret = ad7280_write(st, AD7280A_DEVADDR_MASTER, AD7280A_CONTROL_LB, 1, - AD7280A_CTRL_LB_DAISY_CHAIN_RB_EN | - AD7280A_CTRL_LB_LOCK_DEV_ADDR | + ret = ad7280_write(st, AD7280A_DEVADDR_MASTER, AD7280A_CTRL_LB_REG, 1, + FIELD_PREP(AD7280A_CTRL_LB_DAISY_CHAIN_RB_MSK, 1) | + FIELD_PREP(AD7280A_CTRL_LB_LOCK_DEV_ADDR_MSK, 1) | AD7280A_CTRL_LB_MUST_SET | - AD7280A_CTRL_LB_SWRST | + FIELD_PREP(AD7280A_CTRL_LB_SWRST_MSK, 1) | st->ctrl_lb); if (ret) return ret; - ret = ad7280_write(st, AD7280A_DEVADDR_MASTER, AD7280A_CONTROL_LB, 1, - AD7280A_CTRL_LB_DAISY_CHAIN_RB_EN | - AD7280A_CTRL_LB_LOCK_DEV_ADDR | + ret = ad7280_write(st, AD7280A_DEVADDR_MASTER, AD7280A_CTRL_LB_REG, 1, + FIELD_PREP(AD7280A_CTRL_LB_DAISY_CHAIN_RB_MSK, 1) | + FIELD_PREP(AD7280A_CTRL_LB_LOCK_DEV_ADDR_MSK, 1) | AD7280A_CTRL_LB_MUST_SET | + FIELD_PREP(AD7280A_CTRL_LB_SWRST_MSK, 0) | st->ctrl_lb); if (ret) goto error_power_down; - ret = ad7280_write(st, AD7280A_DEVADDR_MASTER, AD7280A_READ, 1, - AD7280A_CONTROL_LB << 2); + ret = ad7280_write(st, AD7280A_DEVADDR_MASTER, AD7280A_READ_REG, 1, + FIELD_PREP(AD7280A_READ_ADDR_MSK, AD7280A_CTRL_LB_REG)); if (ret) goto error_power_down; @@ -390,7 +414,7 @@ static int ad7280_chain_setup(struct ad7280_state *st) ret = -EFAULT; error_power_down: - ad7280_write(st, AD7280A_DEVADDR_MASTER, AD7280A_CONTROL_HB, 1, + ad7280_write(st, AD7280A_DEVADDR_MASTER, AD7280A_CTRL_HB_REG, 1, AD7280A_CTRL_HB_PWRDN_SW | st->ctrl_hb); return ret; @@ -434,7 +458,7 @@ static ssize_t ad7280_store_balance_sw(struct device *dev, else st->cb_mask[devaddr] &= ~(1 << (ch + 2)); - ret = ad7280_write(st, devaddr, AD7280A_CELL_BALANCE, + ret = ad7280_write(st, devaddr, AD7280A_CELL_BALANCE_REG, 0, st->cb_mask[devaddr]); mutex_unlock(&st->lock); @@ -459,7 +483,7 @@ static ssize_t ad7280_show_balance_timer(struct device *dev, if (ret < 0) return ret; - msecs = (ret >> 3) * 71500; + msecs = FIELD_GET(AD7280A_CB_TIMER_VAL_MSK, ret) * 71500; return sprintf(buf, "%u\n", msecs); } @@ -486,8 +510,8 @@ static ssize_t ad7280_store_balance_timer(struct device *dev, mutex_lock(&st->lock); ret = ad7280_write(st, this_attr->address >> 8, - this_attr->address & 0xFF, - 0, (val & 0x1F) << 3); + this_attr->address & 0xFF, 0, + FIELD_PREP(AD7280A_CB_TIMER_VAL_MSK, val)); mutex_unlock(&st->lock); return ret ? ret : len; @@ -559,10 +583,10 @@ static void ad7280_init_dev_channels(struct ad7280_state *st, int dev, int *cnt) int addr, ch, i; struct iio_chan_spec *chan; - for (ch = AD7280A_CELL_VOLTAGE_1; ch <= AD7280A_AUX_ADC_6; ch++) { + for (ch = AD7280A_CELL_VOLTAGE_1_REG; ch <= AD7280A_AUX_ADC_6_REG; ch++) { chan = &st->channels[*cnt]; - if (ch < AD7280A_AUX_ADC_1) { + if (ch < AD7280A_AUX_ADC_1_REG) { i = AD7280A_CALC_VOLTAGE_CHAN_NUM(dev, ch); ad7280_voltage_channel_init(chan, i); } else { @@ -634,7 +658,7 @@ static int ad7280_init_dev_attrs(struct ad7280_state *st, int dev, int *cnt) struct iio_dev_attr *iio_attr; struct device *sdev = &st->spi->dev; - for (ch = AD7280A_CELL_VOLTAGE_1; ch <= AD7280A_CELL_VOLTAGE_6; ch++) { + for (ch = AD7280A_CELL_VOLTAGE_1_REG; ch <= AD7280A_CELL_VOLTAGE_6_REG; ch++) { iio_attr = &st->iio_attr[*cnt]; addr = ad7280a_devaddr(dev) << 8 | ch; i = dev * AD7280A_CELLS_PER_DEV + ch; @@ -647,7 +671,7 @@ static int ad7280_init_dev_attrs(struct ad7280_state *st, int dev, int *cnt) (*cnt)++; iio_attr = &st->iio_attr[*cnt]; - addr = ad7280a_devaddr(dev) << 8 | (AD7280A_CB1_TIMER + ch); + addr = ad7280a_devaddr(dev) << 8 | (AD7280A_CB1_TIMER_REG + ch); ret = ad7280_balance_timer_attr_init(iio_attr, sdev, addr, i); if (ret < 0) @@ -691,16 +715,16 @@ static ssize_t ad7280_read_channel_config(struct device *dev, unsigned int val; switch (this_attr->address) { - case AD7280A_CELL_OVERVOLTAGE: + case AD7280A_CELL_OVERVOLTAGE_REG: val = 1000 + (st->cell_threshhigh * 1568) / 100; break; - case AD7280A_CELL_UNDERVOLTAGE: + case AD7280A_CELL_UNDERVOLTAGE_REG: val = 1000 + (st->cell_threshlow * 1568) / 100; break; - case AD7280A_AUX_ADC_OVERVOLTAGE: + case AD7280A_AUX_ADC_OVERVOLTAGE_REG: val = (st->aux_threshhigh * 196) / 10; break; - case AD7280A_AUX_ADC_UNDERVOLTAGE: + case AD7280A_AUX_ADC_UNDERVOLTAGE_REG: val = (st->aux_threshlow * 196) / 10; break; default: @@ -727,12 +751,12 @@ static ssize_t ad7280_write_channel_config(struct device *dev, return ret; switch (this_attr->address) { - case AD7280A_CELL_OVERVOLTAGE: - case AD7280A_CELL_UNDERVOLTAGE: + case AD7280A_CELL_OVERVOLTAGE_REG: + case AD7280A_CELL_UNDERVOLTAGE_REG: val = ((val - 1000) * 100) / 1568; /* LSB 15.68mV */ break; - case AD7280A_AUX_ADC_OVERVOLTAGE: - case AD7280A_AUX_ADC_UNDERVOLTAGE: + case AD7280A_AUX_ADC_OVERVOLTAGE_REG: + case AD7280A_AUX_ADC_UNDERVOLTAGE_REG: val = (val * 10) / 196; /* LSB 19.6mV */ break; default: @@ -743,16 +767,16 @@ static ssize_t ad7280_write_channel_config(struct device *dev, mutex_lock(&st->lock); switch (this_attr->address) { - case AD7280A_CELL_OVERVOLTAGE: + case AD7280A_CELL_OVERVOLTAGE_REG: st->cell_threshhigh = val; break; - case AD7280A_CELL_UNDERVOLTAGE: + case AD7280A_CELL_UNDERVOLTAGE_REG: st->cell_threshlow = val; break; - case AD7280A_AUX_ADC_OVERVOLTAGE: + case AD7280A_AUX_ADC_OVERVOLTAGE_REG: st->aux_threshhigh = val; break; - case AD7280A_AUX_ADC_UNDERVOLTAGE: + case AD7280A_AUX_ADC_UNDERVOLTAGE_REG: st->aux_threshlow = val; break; } @@ -781,7 +805,7 @@ static irqreturn_t ad7280_event_handler(int irq, void *private) goto out; for (i = 0; i < st->scan_cnt; i++) { - if (((channels[i] >> 23) & 0xF) <= AD7280A_CELL_VOLTAGE_6) { + if (((channels[i] >> 23) & 0xF) <= AD7280A_CELL_VOLTAGE_6_REG) { if (((channels[i] >> 11) & 0xFFF) >= st->cell_threshhigh) { u64 tmp = IIO_EVENT_CODE(IIO_VOLTAGE, 1, 0, @@ -801,7 +825,7 @@ static irqreturn_t ad7280_event_handler(int irq, void *private) } } else { if (((channels[i] >> 11) & 0xFFF) >= - st->aux_threshhigh) { + st->aux_threshhigh) { u64 tmp = IIO_UNMOD_EVENT_CODE(IIO_TEMP, 0, IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING); @@ -833,26 +857,26 @@ static IIO_DEVICE_ATTR_NAMED(in_thresh_low_value, 0644, ad7280_read_channel_config, ad7280_write_channel_config, - AD7280A_CELL_UNDERVOLTAGE); + AD7280A_CELL_UNDERVOLTAGE_REG); static IIO_DEVICE_ATTR_NAMED(in_thresh_high_value, in_voltage-voltage_thresh_high_value, 0644, ad7280_read_channel_config, ad7280_write_channel_config, - AD7280A_CELL_OVERVOLTAGE); + AD7280A_CELL_OVERVOLTAGE_REG); static IIO_DEVICE_ATTR(in_temp_thresh_low_value, 0644, ad7280_read_channel_config, ad7280_write_channel_config, - AD7280A_AUX_ADC_UNDERVOLTAGE); + AD7280A_AUX_ADC_UNDERVOLTAGE_REG); static IIO_DEVICE_ATTR(in_temp_thresh_high_value, 0644, ad7280_read_channel_config, ad7280_write_channel_config, - AD7280A_AUX_ADC_OVERVOLTAGE); + AD7280A_AUX_ADC_OVERVOLTAGE_REG); static struct attribute *ad7280_event_attributes[] = { &iio_dev_attr_in_thresh_low_value.dev_attr.attr, @@ -892,7 +916,7 @@ static int ad7280_read_raw(struct iio_dev *indio_dev, return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: - if ((chan->address & 0xFF) <= AD7280A_CELL_VOLTAGE_6) + if ((chan->address & 0xFF) <= AD7280A_CELL_VOLTAGE_6_REG) *val = 4000; else *val = 5000; @@ -942,10 +966,9 @@ static int ad7280_probe(struct spi_device *spi) st->spi->mode = SPI_MODE_1; spi_setup(st->spi); - st->ctrl_lb = AD7280A_CTRL_LB_ACQ_TIME(pdata->acquisition_time & 0x3); - st->ctrl_hb = AD7280A_CTRL_HB_CONV_AVG(pdata->conversion_averaging - & 0x3) | (pdata->thermistor_term_en ? - AD7280A_CTRL_LB_THERMISTOR_EN : 0); + st->ctrl_lb = FIELD_PREP(AD7280A_CTRL_LB_ACQ_TIME_MSK, pdata->acquisition_time) | + FIELD_PREP(AD7280A_CTRL_LB_THERMISTOR_MSK, pdata->thermistor_term_en); + st->ctrl_hb = FIELD_PREP(AD7280A_CTRL_HB_CONV_AVG_MSK, pdata->conversion_averaging); ret = ad7280_chain_setup(st); if (ret < 0) @@ -998,13 +1021,13 @@ static int ad7280_probe(struct spi_device *spi) if (spi->irq > 0) { ret = ad7280_write(st, AD7280A_DEVADDR_MASTER, - AD7280A_ALERT, 1, + AD7280A_ALERT_REG, 1, AD7280A_ALERT_RELAY_SIG_CHAIN_DOWN); if (ret) return ret; ret = ad7280_write(st, ad7280a_devaddr(st->slave_num), - AD7280A_ALERT, 0, + AD7280A_ALERT_REG, 0, AD7280A_ALERT_GEN_STATIC_HIGH | (pdata->chain_last_alert_ignore & 0xF)); if (ret) -- cgit v1.2.3 From dd7062fe88015beaedf479116c8aae64b103e9b8 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 6 Feb 2022 19:03:11 +0000 Subject: staging:iio:adc:ad7280a: rename _read() to _read_reg() This avoids possible confusion with read back of the channel conversions. These two types of reads are of difference sizes with resulting differences in the data layout of the response from the hardware. Signed-off-by: Jonathan Cameron Reviewed-by: Marcelo Schmitt Link: https://lore.kernel.org/r/20220206190328.333093-4-jic23@kernel.org --- drivers/staging/iio/adc/ad7280a.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/staging/iio/adc/ad7280a.c b/drivers/staging/iio/adc/ad7280a.c index 0f64b2fbfa7a..f1382666d2aa 100644 --- a/drivers/staging/iio/adc/ad7280a.c +++ b/drivers/staging/iio/adc/ad7280a.c @@ -224,8 +224,8 @@ static int ad7280_write(struct ad7280_state *st, unsigned int devaddr, return spi_write(st->spi, &st->buf[0], 4); } -static int ad7280_read(struct ad7280_state *st, unsigned int devaddr, - unsigned int addr) +static int ad7280_read_reg(struct ad7280_state *st, unsigned int devaddr, + unsigned int addr) { int ret; unsigned int tmp; @@ -476,8 +476,8 @@ static ssize_t ad7280_show_balance_timer(struct device *dev, unsigned int msecs; mutex_lock(&st->lock); - ret = ad7280_read(st, this_attr->address >> 8, - this_attr->address & 0xFF); + ret = ad7280_read_reg(st, this_attr->address >> 8, + this_attr->address & 0xFF); mutex_unlock(&st->lock); if (ret < 0) -- cgit v1.2.3 From 003f1d48de520404e8d1ed3c4e98bbed547d1bae Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 6 Feb 2022 19:03:12 +0000 Subject: staging:iio:adc:ad7280a: Split buff[2] into tx and rx parts As the __cacheline_aligned will ensure that the first of these two buffers is appropriate aligned, there is no need to keep them as a single array which is confusing given the first element is always tx and the second rx. Hence let us just have two parts and name them separately. Signed-off-by: Jonathan Cameron Reviewed-by: Marcelo Schmitt Link: https://lore.kernel.org/r/20220206190328.333093-5-jic23@kernel.org --- drivers/staging/iio/adc/ad7280a.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/drivers/staging/iio/adc/ad7280a.c b/drivers/staging/iio/adc/ad7280a.c index f1382666d2aa..b1698262cee0 100644 --- a/drivers/staging/iio/adc/ad7280a.c +++ b/drivers/staging/iio/adc/ad7280a.c @@ -153,7 +153,8 @@ struct ad7280_state { unsigned char cb_mask[AD7280A_MAX_CHAIN]; struct mutex lock; /* protect sensor state */ - __be32 buf[2] ____cacheline_aligned; + __be32 tx ____cacheline_aligned; + __be32 rx; }; static unsigned char ad7280_calc_crc8(unsigned char *crc_tab, unsigned int val) @@ -196,18 +197,18 @@ static int __ad7280_read32(struct ad7280_state *st, unsigned int *val) { int ret; struct spi_transfer t = { - .tx_buf = &st->buf[0], - .rx_buf = &st->buf[1], - .len = 4, + .tx_buf = &st->tx, + .rx_buf = &st->rx, + .len = sizeof(st->tx), }; - st->buf[0] = cpu_to_be32(AD7280A_READ_TXVAL); + st->tx = cpu_to_be32(AD7280A_READ_TXVAL); ret = spi_sync_transfer(st->spi, &t, 1); if (ret) return ret; - *val = be32_to_cpu(st->buf[1]); + *val = be32_to_cpu(st->rx); return 0; } @@ -219,9 +220,9 @@ static int ad7280_write(struct ad7280_state *st, unsigned int devaddr, (val & 0xFF) << 13 | all << 12; reg |= ad7280_calc_crc8(st->crc_tab, reg >> 11) << 3 | 0x2; - st->buf[0] = cpu_to_be32(reg); + st->tx = cpu_to_be32(reg); - return spi_write(st->spi, &st->buf[0], 4); + return spi_write(st->spi, &st->tx, sizeof(st->tx)); } static int ad7280_read_reg(struct ad7280_state *st, unsigned int devaddr, -- cgit v1.2.3 From 4915c6b3dd19fd331e3f189c92b27e14849d72fe Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 6 Feb 2022 19:03:13 +0000 Subject: staging:iio:adc:ad7280a: Use bitfield ops to managed fields in transfers. The write and two types of read transfer are sufficiently complex that they benefit from the clarity of using FIELD_PREP() and FIELD_GET(). This also applies to the handling in ad7280_event_handler() so use a similar approach there as well. Signed-off-by: Jonathan Cameron Reviewed-by: Marcelo Schmitt Link: https://lore.kernel.org/r/20220206190328.333093-6-jic23@kernel.org --- drivers/staging/iio/adc/ad7280a.c | 64 +++++++++++++++++++++++++++------------ 1 file changed, 45 insertions(+), 19 deletions(-) diff --git a/drivers/staging/iio/adc/ad7280a.c b/drivers/staging/iio/adc/ad7280a.c index b1698262cee0..0db7ac02589b 100644 --- a/drivers/staging/iio/adc/ad7280a.c +++ b/drivers/staging/iio/adc/ad7280a.c @@ -95,6 +95,23 @@ #define AD7280A_READ_ADDR_MSK GENMASK(7, 2) #define AD7280A_CNVST_CTRL_REG 0x1D /* D7 to D0, Read/write */ +/* Transfer fields */ +#define AD7280A_TRANS_WRITE_DEVADDR_MSK GENMASK(31, 27) +#define AD7280A_TRANS_WRITE_ADDR_MSK GENMASK(26, 21) +#define AD7280A_TRANS_WRITE_VAL_MSK GENMASK(20, 13) +#define AD7280A_TRANS_WRITE_ALL_MSK BIT(12) +#define AD7280A_TRANS_WRITE_CRC_MSK GENMASK(10, 3) +#define AD7280A_TRANS_WRITE_RES_PATTERN 0x2 + +/* Layouts differ for channel vs other registers */ +#define AD7280A_TRANS_READ_DEVADDR_MSK GENMASK(31, 27) +#define AD7280A_TRANS_READ_CONV_CHANADDR_MSK GENMASK(26, 23) +#define AD7280A_TRANS_READ_CONV_DATA_MSK GENMASK(22, 11) +#define AD7280A_TRANS_READ_REG_REGADDR_MSK GENMASK(26, 21) +#define AD7280A_TRANS_READ_REG_DATA_MSK GENMASK(20, 13) +#define AD7280A_TRANS_READ_WRITE_ACK_MSK BIT(10) +#define AD7280A_TRANS_READ_CRC_MSK GENMASK(9, 2) + /* Magic value used to indicate this special case */ #define AD7280A_ALL_CELLS (0xAD << 16) @@ -216,10 +233,16 @@ static int __ad7280_read32(struct ad7280_state *st, unsigned int *val) static int ad7280_write(struct ad7280_state *st, unsigned int devaddr, unsigned int addr, bool all, unsigned int val) { - unsigned int reg = devaddr << 27 | addr << 21 | - (val & 0xFF) << 13 | all << 12; + unsigned int reg = FIELD_PREP(AD7280A_TRANS_WRITE_DEVADDR_MSK, devaddr) | + FIELD_PREP(AD7280A_TRANS_WRITE_ADDR_MSK, addr) | + FIELD_PREP(AD7280A_TRANS_WRITE_VAL_MSK, val) | + FIELD_PREP(AD7280A_TRANS_WRITE_ALL_MSK, all); + + reg |= FIELD_PREP(AD7280A_TRANS_WRITE_CRC_MSK, + ad7280_calc_crc8(st->crc_tab, reg >> 11)); + /* Reserved b010 pattern not included crc calc */ + reg |= AD7280A_TRANS_WRITE_RES_PATTERN; - reg |= ad7280_calc_crc8(st->crc_tab, reg >> 11) << 3 | 0x2; st->tx = cpu_to_be32(reg); return spi_write(st->spi, &st->tx, sizeof(st->tx)); @@ -264,10 +287,11 @@ static int ad7280_read_reg(struct ad7280_state *st, unsigned int devaddr, if (ad7280_check_crc(st, tmp)) return -EIO; - if (((tmp >> 27) != devaddr) || (((tmp >> 21) & 0x3F) != addr)) + if ((FIELD_GET(AD7280A_TRANS_READ_DEVADDR_MSK, tmp) != devaddr) || + (FIELD_GET(AD7280A_TRANS_READ_REG_REGADDR_MSK, tmp) != addr)) return -EFAULT; - return (tmp >> 13) & 0xFF; + return FIELD_GET(AD7280A_TRANS_READ_REG_DATA_MSK, tmp); } static int ad7280_read_channel(struct ad7280_state *st, unsigned int devaddr, @@ -310,10 +334,11 @@ static int ad7280_read_channel(struct ad7280_state *st, unsigned int devaddr, if (ad7280_check_crc(st, tmp)) return -EIO; - if (((tmp >> 27) != devaddr) || (((tmp >> 23) & 0xF) != addr)) + if ((FIELD_GET(AD7280A_TRANS_READ_DEVADDR_MSK, tmp) != devaddr) || + (FIELD_GET(AD7280A_TRANS_READ_CONV_CHANADDR_MSK, tmp) != addr)) return -EFAULT; - return (tmp >> 11) & 0xFFF; + return FIELD_GET(AD7280A_TRANS_READ_CONV_DATA_MSK, tmp); } static int ad7280_read_all_channels(struct ad7280_state *st, unsigned int cnt, @@ -351,8 +376,9 @@ static int ad7280_read_all_channels(struct ad7280_state *st, unsigned int cnt, if (array) array[i] = tmp; /* only sum cell voltages */ - if (((tmp >> 23) & 0xF) <= AD7280A_CELL_VOLTAGE_6_REG) - sum += ((tmp >> 11) & 0xFFF); + if (FIELD_GET(AD7280A_TRANS_READ_CONV_CHANADDR_MSK, tmp) <= + AD7280A_CELL_VOLTAGE_6_REG) + sum += FIELD_GET(AD7280A_TRANS_READ_CONV_DATA_MSK, tmp); } return sum; @@ -407,7 +433,7 @@ static int ad7280_chain_setup(struct ad7280_state *st) goto error_power_down; } - if (n != ad7280a_devaddr(val >> 27)) { + if (n != ad7280a_devaddr(FIELD_GET(AD7280A_TRANS_READ_DEVADDR_MSK, val))) { ret = -EIO; goto error_power_down; } @@ -806,17 +832,19 @@ static irqreturn_t ad7280_event_handler(int irq, void *private) goto out; for (i = 0; i < st->scan_cnt; i++) { - if (((channels[i] >> 23) & 0xF) <= AD7280A_CELL_VOLTAGE_6_REG) { - if (((channels[i] >> 11) & 0xFFF) >= - st->cell_threshhigh) { + unsigned int val; + + val = FIELD_GET(AD7280A_TRANS_READ_CONV_DATA_MSK, channels[i]); + if (FIELD_GET(AD7280A_TRANS_READ_CONV_CHANADDR_MSK, channels[i]) <= + AD7280A_CELL_VOLTAGE_6_REG) { + if (val >= st->cell_threshhigh) { u64 tmp = IIO_EVENT_CODE(IIO_VOLTAGE, 1, 0, IIO_EV_DIR_RISING, IIO_EV_TYPE_THRESH, 0, 0, 0); iio_push_event(indio_dev, tmp, iio_get_time_ns(indio_dev)); - } else if (((channels[i] >> 11) & 0xFFF) <= - st->cell_threshlow) { + } else if (val <= st->cell_threshlow) { u64 tmp = IIO_EVENT_CODE(IIO_VOLTAGE, 1, 0, IIO_EV_DIR_FALLING, IIO_EV_TYPE_THRESH, @@ -825,15 +853,13 @@ static irqreturn_t ad7280_event_handler(int irq, void *private) iio_get_time_ns(indio_dev)); } } else { - if (((channels[i] >> 11) & 0xFFF) >= - st->aux_threshhigh) { + if (val >= st->aux_threshhigh) { u64 tmp = IIO_UNMOD_EVENT_CODE(IIO_TEMP, 0, IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING); iio_push_event(indio_dev, tmp, iio_get_time_ns(indio_dev)); - } else if (((channels[i] >> 11) & 0xFFF) <= - st->aux_threshlow) { + } else if (val <= st->aux_threshlow) { u64 tmp = IIO_UNMOD_EVENT_CODE(IIO_TEMP, 0, IIO_EV_TYPE_THRESH, IIO_EV_DIR_FALLING); -- cgit v1.2.3 From 112bf4aa4afb5608d77ac9208758528bcdfae70d Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 6 Feb 2022 19:03:14 +0000 Subject: staging:iio:adc:ad7280a: Switch to standard event control This driver had a slightly non standard events ABI but there seems to be no reason for not doing it with the core support for rising and falling events on the two types of channels. In theory the events on different daisy chained chips could be at different levels, but the driver has never supported this and it doesn't seem likely to be used so let us ignore that option. Includes reordering so that we only set the software cached value of the thresholds if the hardware write succeeds. Signed-off-by: Jonathan Cameron Reviewed-by: Marcelo Schmitt Link: https://lore.kernel.org/r/20220206190328.333093-7-jic23@kernel.org --- drivers/staging/iio/adc/ad7280a.c | 213 ++++++++++++++++++++------------------ 1 file changed, 110 insertions(+), 103 deletions(-) diff --git a/drivers/staging/iio/adc/ad7280a.c b/drivers/staging/iio/adc/ad7280a.c index 0db7ac02589b..34b0f826ebee 100644 --- a/drivers/staging/iio/adc/ad7280a.c +++ b/drivers/staging/iio/adc/ad7280a.c @@ -551,18 +551,34 @@ static const struct attribute_group ad7280_attrs_group = { .attrs = ad7280_attributes, }; +static const struct iio_event_spec ad7280_events[] = { + { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_RISING, + .mask_shared_by_type = BIT(IIO_EV_INFO_VALUE), + }, { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_FALLING, + .mask_shared_by_type = BIT(IIO_EV_INFO_VALUE), + }, +}; + static void ad7280_voltage_channel_init(struct iio_chan_spec *chan, int i) { chan->type = IIO_VOLTAGE; chan->differential = 1; chan->channel = i; chan->channel2 = chan->channel + 1; + chan->event_spec = ad7280_events; + chan->num_event_specs = ARRAY_SIZE(ad7280_events); } static void ad7280_temp_channel_init(struct iio_chan_spec *chan, int i) { chan->type = IIO_TEMP; chan->channel = i; + chan->event_spec = ad7280_events; + chan->num_event_specs = ARRAY_SIZE(ad7280_events); } static void ad7280_common_fields_init(struct iio_chan_spec *chan, int addr, @@ -732,88 +748,120 @@ static int ad7280_attr_init(struct ad7280_state *st) return 0; } -static ssize_t ad7280_read_channel_config(struct device *dev, - struct device_attribute *attr, - char *buf) +static int ad7280a_read_thresh(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, int *val, int *val2) { - struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ad7280_state *st = iio_priv(indio_dev); - struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); - unsigned int val; - switch (this_attr->address) { - case AD7280A_CELL_OVERVOLTAGE_REG: - val = 1000 + (st->cell_threshhigh * 1568) / 100; - break; - case AD7280A_CELL_UNDERVOLTAGE_REG: - val = 1000 + (st->cell_threshlow * 1568) / 100; - break; - case AD7280A_AUX_ADC_OVERVOLTAGE_REG: - val = (st->aux_threshhigh * 196) / 10; + switch (chan->type) { + case IIO_VOLTAGE: + switch (dir) { + case IIO_EV_DIR_RISING: + *val = 1000 + (st->cell_threshhigh * 1568L) / 100; + return IIO_VAL_INT; + case IIO_EV_DIR_FALLING: + *val = 1000 + (st->cell_threshlow * 1568L) / 100; + return IIO_VAL_INT; + default: + return -EINVAL; + } break; - case AD7280A_AUX_ADC_UNDERVOLTAGE_REG: - val = (st->aux_threshlow * 196) / 10; + case IIO_TEMP: + switch (dir) { + case IIO_EV_DIR_RISING: + *val = ((st->aux_threshhigh) * 196L) / 10; + return IIO_VAL_INT; + case IIO_EV_DIR_FALLING: + *val = (st->aux_threshlow * 196L) / 10; + return IIO_VAL_INT; + default: + return -EINVAL; + } break; default: return -EINVAL; } - - return sprintf(buf, "%u\n", val); } -static ssize_t ad7280_write_channel_config(struct device *dev, - struct device_attribute *attr, - const char *buf, - size_t len) +static int ad7280a_write_thresh(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, + int val, int val2) { - struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ad7280_state *st = iio_priv(indio_dev); - struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); - - long val; + unsigned int addr; + long value; int ret; - ret = kstrtol(buf, 10, &val); - if (ret) - return ret; - - switch (this_attr->address) { - case AD7280A_CELL_OVERVOLTAGE_REG: - case AD7280A_CELL_UNDERVOLTAGE_REG: - val = ((val - 1000) * 100) / 1568; /* LSB 15.68mV */ - break; - case AD7280A_AUX_ADC_OVERVOLTAGE_REG: - case AD7280A_AUX_ADC_UNDERVOLTAGE_REG: - val = (val * 10) / 196; /* LSB 19.6mV */ - break; - default: - return -EFAULT; - } - - val = clamp(val, 0L, 0xFFL); + if (val2 != 0) + return -EINVAL; mutex_lock(&st->lock); - switch (this_attr->address) { - case AD7280A_CELL_OVERVOLTAGE_REG: - st->cell_threshhigh = val; - break; - case AD7280A_CELL_UNDERVOLTAGE_REG: - st->cell_threshlow = val; - break; - case AD7280A_AUX_ADC_OVERVOLTAGE_REG: - st->aux_threshhigh = val; + switch (chan->type) { + case IIO_VOLTAGE: + value = ((val - 1000) * 100) / 1568; /* LSB 15.68mV */ + value = clamp(value, 0L, 0xFFL); + switch (dir) { + case IIO_EV_DIR_RISING: + addr = AD7280A_CELL_OVERVOLTAGE_REG; + ret = ad7280_write(st, AD7280A_DEVADDR_MASTER, addr, + 1, val); + if (ret) + break; + st->cell_threshhigh = value; + break; + case IIO_EV_DIR_FALLING: + addr = AD7280A_CELL_UNDERVOLTAGE_REG; + ret = ad7280_write(st, AD7280A_DEVADDR_MASTER, addr, + 1, val); + if (ret) + break; + st->cell_threshlow = value; + break; + default: + ret = -EINVAL; + goto err_unlock; + } break; - case AD7280A_AUX_ADC_UNDERVOLTAGE_REG: - st->aux_threshlow = val; + case IIO_TEMP: + value = (val * 10) / 196; /* LSB 19.6mV */ + value = clamp(value, 0L, 0xFFL); + switch (dir) { + case IIO_EV_DIR_RISING: + addr = AD7280A_AUX_ADC_OVERVOLTAGE_REG; + ret = ad7280_write(st, AD7280A_DEVADDR_MASTER, addr, + 1, val); + if (ret) + break; + st->aux_threshhigh = val; + break; + case IIO_EV_DIR_FALLING: + addr = AD7280A_AUX_ADC_UNDERVOLTAGE_REG; + ret = ad7280_write(st, AD7280A_DEVADDR_MASTER, addr, + 1, val); + if (ret) + break; + st->aux_threshlow = val; + break; + default: + ret = -EINVAL; + goto err_unlock; + } break; + default: + ret = -EINVAL; + goto err_unlock; } - ret = ad7280_write(st, AD7280A_DEVADDR_MASTER, - this_attr->address, 1, val); - +err_unlock: mutex_unlock(&st->lock); - return ret ? ret : len; + return ret; } static irqreturn_t ad7280_event_handler(int irq, void *private) @@ -875,48 +923,6 @@ out: return IRQ_HANDLED; } -/* Note: No need to fix checkpatch warning that reads: - * CHECK: spaces preferred around that '-' (ctx:VxV) - * The function argument is stringified and doesn't need a fix - */ -static IIO_DEVICE_ATTR_NAMED(in_thresh_low_value, - in_voltage-voltage_thresh_low_value, - 0644, - ad7280_read_channel_config, - ad7280_write_channel_config, - AD7280A_CELL_UNDERVOLTAGE_REG); - -static IIO_DEVICE_ATTR_NAMED(in_thresh_high_value, - in_voltage-voltage_thresh_high_value, - 0644, - ad7280_read_channel_config, - ad7280_write_channel_config, - AD7280A_CELL_OVERVOLTAGE_REG); - -static IIO_DEVICE_ATTR(in_temp_thresh_low_value, - 0644, - ad7280_read_channel_config, - ad7280_write_channel_config, - AD7280A_AUX_ADC_UNDERVOLTAGE_REG); - -static IIO_DEVICE_ATTR(in_temp_thresh_high_value, - 0644, - ad7280_read_channel_config, - ad7280_write_channel_config, - AD7280A_AUX_ADC_OVERVOLTAGE_REG); - -static struct attribute *ad7280_event_attributes[] = { - &iio_dev_attr_in_thresh_low_value.dev_attr.attr, - &iio_dev_attr_in_thresh_high_value.dev_attr.attr, - &iio_dev_attr_in_temp_thresh_low_value.dev_attr.attr, - &iio_dev_attr_in_temp_thresh_high_value.dev_attr.attr, - NULL, -}; - -static const struct attribute_group ad7280_event_attrs_group = { - .attrs = ad7280_event_attributes, -}; - static int ad7280_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, @@ -956,7 +962,8 @@ static int ad7280_read_raw(struct iio_dev *indio_dev, static const struct iio_info ad7280_info = { .read_raw = ad7280_read_raw, - .event_attrs = &ad7280_event_attrs_group, + .read_event_value = &ad7280a_read_thresh, + .write_event_value = &ad7280a_write_thresh, .attrs = &ad7280_attrs_group, }; -- cgit v1.2.3 From 96ccdbc07a742f8a7ba986a0eb96cb85ee1733df Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 6 Feb 2022 19:03:15 +0000 Subject: staging:iio:adc:ad7280a: Standardize extended ABI naming The *_balance_switch_en and *_balance_switch_timer attributes had non standard prefixes. Use the ext_info framework to automatically create then with in_voltageX-voltageY_ prefix. Documentation for these two unusual attributes to follow. Signed-off-by: Jonathan Cameron Reviewed-by: Marcelo Schmitt Link: https://lore.kernel.org/r/20220206190328.333093-8-jic23@kernel.org --- drivers/staging/iio/adc/ad7280a.c | 174 ++++++++++---------------------------- 1 file changed, 43 insertions(+), 131 deletions(-) diff --git a/drivers/staging/iio/adc/ad7280a.c b/drivers/staging/iio/adc/ad7280a.c index 34b0f826ebee..29edbda64230 100644 --- a/drivers/staging/iio/adc/ad7280a.c +++ b/drivers/staging/iio/adc/ad7280a.c @@ -156,7 +156,6 @@ static unsigned int ad7280a_devaddr(unsigned int addr) struct ad7280_state { struct spi_device *spi; struct iio_chan_spec *channels; - struct iio_dev_attr *iio_attr; int slave_num; int scan_cnt; int readback_delay_us; @@ -447,37 +446,33 @@ error_power_down: return ret; } -static ssize_t ad7280_show_balance_sw(struct device *dev, - struct device_attribute *attr, - char *buf) +static ssize_t ad7280_show_balance_sw(struct iio_dev *indio_dev, + uintptr_t private, + const struct iio_chan_spec *chan, char *buf) { - struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ad7280_state *st = iio_priv(indio_dev); - struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); - return sprintf(buf, "%d\n", - !!(st->cb_mask[this_attr->address >> 8] & - (1 << ((this_attr->address & 0xFF) + 2)))); + return sysfs_emit(buf, "%d\n", + !!(st->cb_mask[chan->address >> 8] & + (1 << ((chan->address & 0xFF) + 2)))); } -static ssize_t ad7280_store_balance_sw(struct device *dev, - struct device_attribute *attr, - const char *buf, - size_t len) +static ssize_t ad7280_store_balance_sw(struct iio_dev *indio_dev, + uintptr_t private, + const struct iio_chan_spec *chan, + const char *buf, size_t len) { - struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ad7280_state *st = iio_priv(indio_dev); - struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); + unsigned int devaddr, ch; bool readin; int ret; - unsigned int devaddr, ch; ret = strtobool(buf, &readin); if (ret) return ret; - devaddr = this_attr->address >> 8; - ch = this_attr->address & 0xFF; + devaddr = chan->address >> 8; + ch = chan->address & 0xFF; mutex_lock(&st->lock); if (readin) @@ -492,19 +487,18 @@ static ssize_t ad7280_store_balance_sw(struct device *dev, return ret ? ret : len; } -static ssize_t ad7280_show_balance_timer(struct device *dev, - struct device_attribute *attr, +static ssize_t ad7280_show_balance_timer(struct iio_dev *indio_dev, + uintptr_t private, + const struct iio_chan_spec *chan, char *buf) { - struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ad7280_state *st = iio_priv(indio_dev); - struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); - int ret; unsigned int msecs; + int ret; mutex_lock(&st->lock); - ret = ad7280_read_reg(st, this_attr->address >> 8, - this_attr->address & 0xFF); + ret = ad7280_read_reg(st, chan->address >> 8, + (chan->address & 0xFF) + AD7280A_CB1_TIMER_REG); mutex_unlock(&st->lock); if (ret < 0) @@ -512,43 +506,50 @@ static ssize_t ad7280_show_balance_timer(struct device *dev, msecs = FIELD_GET(AD7280A_CB_TIMER_VAL_MSK, ret) * 71500; - return sprintf(buf, "%u\n", msecs); + return sysfs_emit(buf, "%u.%u\n", msecs / 1000, msecs % 1000); } -static ssize_t ad7280_store_balance_timer(struct device *dev, - struct device_attribute *attr, - const char *buf, - size_t len) +static ssize_t ad7280_store_balance_timer(struct iio_dev *indio_dev, + uintptr_t private, + const struct iio_chan_spec *chan, + const char *buf, size_t len) { - struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ad7280_state *st = iio_priv(indio_dev); - struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); - unsigned long val; + int val, val2; int ret; - ret = kstrtoul(buf, 10, &val); + ret = iio_str_to_fixpoint(buf, 1000, &val, &val2); if (ret) return ret; + val = val * 1000 + val2; val /= 71500; if (val > 31) return -EINVAL; mutex_lock(&st->lock); - ret = ad7280_write(st, this_attr->address >> 8, - this_attr->address & 0xFF, 0, + ret = ad7280_write(st, chan->address >> 8, + (chan->address & 0xFF) + AD7280A_CB1_TIMER_REG, 0, FIELD_PREP(AD7280A_CB_TIMER_VAL_MSK, val)); mutex_unlock(&st->lock); return ret ? ret : len; } -static struct attribute *ad7280_attributes[AD7280A_MAX_CHAIN * - AD7280A_CELLS_PER_DEV * 2 + 1]; - -static const struct attribute_group ad7280_attrs_group = { - .attrs = ad7280_attributes, +static const struct iio_chan_spec_ext_info ad7280_cell_ext_info[] = { + { + .name = "balance_switch_en", + .read = ad7280_show_balance_sw, + .write = ad7280_store_balance_sw, + .shared = IIO_SEPARATE, + }, { + .name = "balance_switch_timer", + .read = ad7280_show_balance_timer, + .write = ad7280_store_balance_timer, + .shared = IIO_SEPARATE, + }, + {} }; static const struct iio_event_spec ad7280_events[] = { @@ -571,6 +572,7 @@ static void ad7280_voltage_channel_init(struct iio_chan_spec *chan, int i) chan->channel2 = chan->channel + 1; chan->event_spec = ad7280_events; chan->num_event_specs = ARRAY_SIZE(ad7280_events); + chan->ext_info = ad7280_cell_ext_info; } static void ad7280_temp_channel_init(struct iio_chan_spec *chan, int i) @@ -663,91 +665,6 @@ static int ad7280_channel_init(struct ad7280_state *st) return cnt + 1; } -static int ad7280_balance_switch_attr_init(struct iio_dev_attr *attr, - struct device *dev, int addr, int i) -{ - attr->address = addr; - attr->dev_attr.attr.mode = 0644; - attr->dev_attr.show = ad7280_show_balance_sw; - attr->dev_attr.store = ad7280_store_balance_sw; - attr->dev_attr.attr.name = devm_kasprintf(dev, GFP_KERNEL, - "in%d-in%d_balance_switch_en", - i, i + 1); - if (!attr->dev_attr.attr.name) - return -ENOMEM; - - return 0; -} - -static int ad7280_balance_timer_attr_init(struct iio_dev_attr *attr, - struct device *dev, int addr, int i) -{ - attr->address = addr; - attr->dev_attr.attr.mode = 0644; - attr->dev_attr.show = ad7280_show_balance_timer; - attr->dev_attr.store = ad7280_store_balance_timer; - attr->dev_attr.attr.name = devm_kasprintf(dev, GFP_KERNEL, - "in%d-in%d_balance_timer", - i, i + 1); - if (!attr->dev_attr.attr.name) - return -ENOMEM; - - return 0; -} - -static int ad7280_init_dev_attrs(struct ad7280_state *st, int dev, int *cnt) -{ - int addr, ch, i, ret; - struct iio_dev_attr *iio_attr; - struct device *sdev = &st->spi->dev; - - for (ch = AD7280A_CELL_VOLTAGE_1_REG; ch <= AD7280A_CELL_VOLTAGE_6_REG; ch++) { - iio_attr = &st->iio_attr[*cnt]; - addr = ad7280a_devaddr(dev) << 8 | ch; - i = dev * AD7280A_CELLS_PER_DEV + ch; - - ret = ad7280_balance_switch_attr_init(iio_attr, sdev, addr, i); - if (ret < 0) - return ret; - - ad7280_attributes[*cnt] = &iio_attr->dev_attr.attr; - - (*cnt)++; - iio_attr = &st->iio_attr[*cnt]; - addr = ad7280a_devaddr(dev) << 8 | (AD7280A_CB1_TIMER_REG + ch); - - ret = ad7280_balance_timer_attr_init(iio_attr, sdev, addr, i); - if (ret < 0) - return ret; - - ad7280_attributes[*cnt] = &iio_attr->dev_attr.attr; - (*cnt)++; - } - - ad7280_attributes[*cnt] = NULL; - - return 0; -} - -static int ad7280_attr_init(struct ad7280_state *st) -{ - int dev, cnt = 0, ret; - - st->iio_attr = devm_kcalloc(&st->spi->dev, 2, sizeof(*st->iio_attr) * - (st->slave_num + 1) * AD7280A_CELLS_PER_DEV, - GFP_KERNEL); - if (!st->iio_attr) - return -ENOMEM; - - for (dev = 0; dev <= st->slave_num; dev++) { - ret = ad7280_init_dev_attrs(st, dev, &cnt); - if (ret < 0) - return ret; - } - - return 0; -} - static int ad7280a_read_thresh(struct iio_dev *indio_dev, const struct iio_chan_spec *chan, enum iio_event_type type, @@ -964,7 +881,6 @@ static const struct iio_info ad7280_info = { .read_raw = ad7280_read_raw, .read_event_value = &ad7280a_read_thresh, .write_event_value = &ad7280a_write_thresh, - .attrs = &ad7280_attrs_group, }; static const struct ad7280_platform_data ad7793_default_pdata = { @@ -1045,10 +961,6 @@ static int ad7280_probe(struct spi_device *spi) indio_dev->channels = st->channels; indio_dev->info = &ad7280_info; - ret = ad7280_attr_init(st); - if (ret < 0) - return ret; - ret = devm_iio_device_register(&spi->dev, indio_dev); if (ret) return ret; -- cgit v1.2.3 From c27e1e1a2444939c1f2f8b5633083e2995692f28 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 6 Feb 2022 19:03:16 +0000 Subject: staging:iio:adc:ad7280a: Drop unused timestamp channel. The driver doesn't support buffered mode, so a timestamp channel that is entirely hidden from userspace without buffer mode is rather pointless. Drop it. Signed-off-by: Jonathan Cameron Reviewed-by: Marcelo Schmitt Link: https://lore.kernel.org/r/20220206190328.333093-9-jic23@kernel.org --- drivers/staging/iio/adc/ad7280a.c | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/drivers/staging/iio/adc/ad7280a.c b/drivers/staging/iio/adc/ad7280a.c index 29edbda64230..c1ac46a8112e 100644 --- a/drivers/staging/iio/adc/ad7280a.c +++ b/drivers/staging/iio/adc/ad7280a.c @@ -613,16 +613,6 @@ static void ad7280_total_voltage_channel_init(struct iio_chan_spec *chan, chan->scan_type.storagebits = 32; } -static void ad7280_timestamp_channel_init(struct iio_chan_spec *chan, int cnt) -{ - chan->type = IIO_TIMESTAMP; - chan->channel = -1; - chan->scan_index = cnt; - chan->scan_type.sign = 's'; - chan->scan_type.realbits = 64; - chan->scan_type.storagebits = 64; -} - static void ad7280_init_dev_channels(struct ad7280_state *st, int dev, int *cnt) { int addr, ch, i; @@ -650,7 +640,7 @@ static int ad7280_channel_init(struct ad7280_state *st) { int dev, cnt = 0; - st->channels = devm_kcalloc(&st->spi->dev, (st->slave_num + 1) * 12 + 2, + st->channels = devm_kcalloc(&st->spi->dev, (st->slave_num + 1) * 12 + 1, sizeof(*st->channels), GFP_KERNEL); if (!st->channels) return -ENOMEM; @@ -659,8 +649,6 @@ static int ad7280_channel_init(struct ad7280_state *st) ad7280_init_dev_channels(st, dev, &cnt); ad7280_total_voltage_channel_init(&st->channels[cnt], cnt, dev); - cnt++; - ad7280_timestamp_channel_init(&st->channels[cnt], cnt); return cnt + 1; } -- cgit v1.2.3 From e0a3ae8e42edd856f3119ac21dd9fb94000342c0 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 6 Feb 2022 19:03:17 +0000 Subject: staging:iio:adc:ad7280a: Trivial comment formatting cleanup IIO uses the /* * stuff * more stuff */ multi-line style, so use that here as well. Signed-off-by: Jonathan Cameron Reviewed-by: Marcelo Schmitt Link: https://lore.kernel.org/r/20220206190328.333093-10-jic23@kernel.org --- drivers/staging/iio/adc/ad7280a.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/drivers/staging/iio/adc/ad7280a.c b/drivers/staging/iio/adc/ad7280a.c index c1ac46a8112e..e32526fbed5a 100644 --- a/drivers/staging/iio/adc/ad7280a.c +++ b/drivers/staging/iio/adc/ad7280a.c @@ -139,9 +139,10 @@ static unsigned int ad7280a_devaddr(unsigned int addr) ((addr & 0x10) >> 4); } -/* During a read a valid write is mandatory. - * So writing to the highest available address (Address 0x1F) - * and setting the address all parts bit to 0 is recommended +/* + * During a read a valid write is mandatory. + * So writing to the highest available address (Address 0x1F) and setting the + * address all parts bit to 0 is recommended. * So the TXVAL is AD7280A_DEVADDR_ALL + CRC */ #define AD7280A_READ_TXVAL 0xF800030A @@ -180,7 +181,7 @@ static unsigned char ad7280_calc_crc8(unsigned char *crc_tab, unsigned int val) crc = crc_tab[val >> 16 & 0xFF]; crc = crc_tab[crc ^ (val >> 8 & 0xFF)]; - return crc ^ (val & 0xFF); + return crc ^ (val & 0xFF); } static int ad7280_check_crc(struct ad7280_state *st, unsigned int val) @@ -193,12 +194,12 @@ static int ad7280_check_crc(struct ad7280_state *st, unsigned int val) return 0; } -/* After initiating a conversion sequence we need to wait until the - * conversion is done. The delay is typically in the range of 15..30 us - * however depending an the number of devices in the daisy chain and the - * number of averages taken, conversion delays and acquisition time options - * it may take up to 250us, in this case we better sleep instead of busy - * wait. +/* + * After initiating a conversion sequence we need to wait until the conversion + * is done. The delay is typically in the range of 15..30us however depending on + * the number of devices in the daisy chain, the number of averages taken, + * conversion delays and acquisition time options it may take up to 250us, in + * this case we better sleep instead of busy wait. */ static void ad7280_delay(struct ad7280_state *st) -- cgit v1.2.3 From c5fe2f537b91e17c854135fdc0b46aa0f4f9db78 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 6 Feb 2022 19:03:18 +0000 Subject: staging:iio:adc:ad7280a: Make oversampling_ratio a runtime control Oversampling has nothing directly to do with analog circuits or similar so belongs in the control of userspace as a policy decision. The only complexity in here was that the acquisition time needs updating if this setting is changed at runtime (as oversampling is time consuming). Signed-off-by: Jonathan Cameron Reviewed-by: Marcelo Schmitt Link: https://lore.kernel.org/r/20220206190328.333093-11-jic23@kernel.org --- drivers/staging/iio/adc/ad7280a.c | 100 +++++++++++++++++++++++++++----------- drivers/staging/iio/adc/ad7280a.h | 6 --- 2 files changed, 72 insertions(+), 34 deletions(-) diff --git a/drivers/staging/iio/adc/ad7280a.c b/drivers/staging/iio/adc/ad7280a.c index e32526fbed5a..2ba9379ce0a7 100644 --- a/drivers/staging/iio/adc/ad7280a.c +++ b/drivers/staging/iio/adc/ad7280a.c @@ -129,6 +129,10 @@ #define AD7280A_DEVADDR_MASTER 0 #define AD7280A_DEVADDR_ALL 0x1F + +static const unsigned short ad7280a_n_avg[4] = {1, 2, 4, 8}; +static const unsigned short ad7280a_t_acq_ns[4] = {465, 1010, 1460, 1890}; + /* 5-bit device address is sent LSB first */ static unsigned int ad7280a_devaddr(unsigned int addr) { @@ -161,7 +165,8 @@ struct ad7280_state { int scan_cnt; int readback_delay_us; unsigned char crc_tab[CRC8_TABLE_SIZE]; - unsigned char ctrl_hb; + u8 oversampling_ratio; + u8 acquisition_time; unsigned char ctrl_lb; unsigned char cell_threshhigh; unsigned char cell_threshlow; @@ -260,7 +265,8 @@ static int ad7280_read_reg(struct ad7280_state *st, unsigned int devaddr, AD7280A_CTRL_HB_CONV_INPUT_ALL) | FIELD_PREP(AD7280A_CTRL_HB_CONV_RREAD_MSK, AD7280A_CTRL_HB_CONV_RREAD_NO) | - st->ctrl_hb); + FIELD_PREP(AD7280A_CTRL_HB_CONV_AVG_MSK, + st->oversampling_ratio)); if (ret) return ret; @@ -270,7 +276,8 @@ static int ad7280_read_reg(struct ad7280_state *st, unsigned int devaddr, AD7280A_CTRL_HB_CONV_INPUT_ALL) | FIELD_PREP(AD7280A_CTRL_HB_CONV_RREAD_MSK, AD7280A_CTRL_HB_CONV_RREAD_ALL) | - st->ctrl_hb); + FIELD_PREP(AD7280A_CTRL_HB_CONV_AVG_MSK, + st->oversampling_ratio)); if (ret) return ret; @@ -310,7 +317,8 @@ static int ad7280_read_channel(struct ad7280_state *st, unsigned int devaddr, AD7280A_CTRL_HB_CONV_INPUT_ALL) | FIELD_PREP(AD7280A_CTRL_HB_CONV_RREAD_MSK, AD7280A_CTRL_HB_CONV_RREAD_NO) | - st->ctrl_hb); + FIELD_PREP(AD7280A_CTRL_HB_CONV_AVG_MSK, + st->oversampling_ratio)); if (ret) return ret; @@ -321,7 +329,8 @@ static int ad7280_read_channel(struct ad7280_state *st, unsigned int devaddr, AD7280A_CTRL_HB_CONV_RREAD_ALL) | FIELD_PREP(AD7280A_CTRL_HB_CONV_START_MSK, AD7280A_CTRL_HB_CONV_START_CS) | - st->ctrl_hb); + FIELD_PREP(AD7280A_CTRL_HB_CONV_AVG_MSK, + st->oversampling_ratio)); if (ret) return ret; @@ -359,7 +368,8 @@ static int ad7280_read_all_channels(struct ad7280_state *st, unsigned int cnt, AD7280A_CTRL_HB_CONV_RREAD_ALL) | FIELD_PREP(AD7280A_CTRL_HB_CONV_START_MSK, AD7280A_CTRL_HB_CONV_START_CS) | - st->ctrl_hb); + FIELD_PREP(AD7280A_CTRL_HB_CONV_AVG_MSK, + st->oversampling_ratio)); if (ret) return ret; @@ -389,7 +399,8 @@ static void ad7280_sw_power_down(void *data) struct ad7280_state *st = data; ad7280_write(st, AD7280A_DEVADDR_MASTER, AD7280A_CTRL_HB_REG, 1, - AD7280A_CTRL_HB_PWRDN_SW | st->ctrl_hb); + AD7280A_CTRL_HB_PWRDN_SW | + FIELD_PREP(AD7280A_CTRL_HB_CONV_AVG_MSK, st->oversampling_ratio)); } static int ad7280_chain_setup(struct ad7280_state *st) @@ -442,7 +453,8 @@ static int ad7280_chain_setup(struct ad7280_state *st) error_power_down: ad7280_write(st, AD7280A_DEVADDR_MASTER, AD7280A_CTRL_HB_REG, 1, - AD7280A_CTRL_HB_PWRDN_SW | st->ctrl_hb); + AD7280A_CTRL_HB_PWRDN_SW | + FIELD_PREP(AD7280A_CTRL_HB_CONV_AVG_MSK, st->oversampling_ratio)); return ret; } @@ -590,6 +602,7 @@ static void ad7280_common_fields_init(struct iio_chan_spec *chan, int addr, chan->indexed = 1; chan->info_mask_separate = BIT(IIO_CHAN_INFO_RAW); chan->info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE); + chan->info_mask_shared_by_all = BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO); chan->address = addr; chan->scan_index = cnt; chan->scan_type.sign = 'u'; @@ -829,6 +842,26 @@ out: return IRQ_HANDLED; } +static void ad7280_update_delay(struct ad7280_state *st) +{ + /* + * Total Conversion Time = ((tACQ + tCONV) * + * (Number of Conversions per Part)) − + * tACQ + ((N - 1) * tDELAY) + * + * Readback Delay = Total Conversion Time + tWAIT + */ + + st->readback_delay_us = + ((ad7280a_t_acq_ns[st->acquisition_time & 0x3] + 695) * + (AD7280A_NUM_CH * ad7280a_n_avg[st->oversampling_ratio & 0x3])) - + ad7280a_t_acq_ns[st->acquisition_time & 0x3] + st->slave_num * 250; + + /* Convert to usecs */ + st->readback_delay_us = DIV_ROUND_UP(st->readback_delay_us, 1000); + st->readback_delay_us += 5; /* Add tWAIT */ +} + static int ad7280_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, @@ -862,19 +895,46 @@ static int ad7280_read_raw(struct iio_dev *indio_dev, *val2 = AD7280A_BITS; return IIO_VAL_FRACTIONAL_LOG2; + case IIO_CHAN_INFO_OVERSAMPLING_RATIO: + *val = ad7280a_n_avg[st->oversampling_ratio]; + return IIO_VAL_INT; } return -EINVAL; } +static int ad7280_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + struct ad7280_state *st = iio_priv(indio_dev); + int i; + + switch (mask) { + case IIO_CHAN_INFO_OVERSAMPLING_RATIO: + if (val2 != 0) + return -EINVAL; + for (i = 0; i < ARRAY_SIZE(ad7280a_n_avg); i++) { + if (val == ad7280a_n_avg[i]) { + st->oversampling_ratio = i; + ad7280_update_delay(st); + return 0; + } + } + return -EINVAL; + default: + return -EINVAL; + } +} + static const struct iio_info ad7280_info = { .read_raw = ad7280_read_raw, + .write_raw = ad7280_write_raw, .read_event_value = &ad7280a_read_thresh, .write_event_value = &ad7280a_write_thresh, }; static const struct ad7280_platform_data ad7793_default_pdata = { .acquisition_time = AD7280A_ACQ_TIME_400ns, - .conversion_averaging = AD7280A_CONV_AVG_DIS, .thermistor_term_en = true, }; @@ -883,8 +943,6 @@ static int ad7280_probe(struct spi_device *spi) const struct ad7280_platform_data *pdata = dev_get_platdata(&spi->dev); struct ad7280_state *st; int ret; - const unsigned short t_acq_ns[4] = {465, 1010, 1460, 1890}; - const unsigned short n_avg[4] = {1, 2, 4, 8}; struct iio_dev *indio_dev; indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); @@ -907,7 +965,7 @@ static int ad7280_probe(struct spi_device *spi) st->ctrl_lb = FIELD_PREP(AD7280A_CTRL_LB_ACQ_TIME_MSK, pdata->acquisition_time) | FIELD_PREP(AD7280A_CTRL_LB_THERMISTOR_MSK, pdata->thermistor_term_en); - st->ctrl_hb = FIELD_PREP(AD7280A_CTRL_HB_CONV_AVG_MSK, pdata->conversion_averaging); + st->oversampling_ratio = 0; /* No oversampling */ ret = ad7280_chain_setup(st); if (ret < 0) @@ -917,27 +975,13 @@ static int ad7280_probe(struct spi_device *spi) st->scan_cnt = (st->slave_num + 1) * AD7280A_NUM_CH; st->cell_threshhigh = 0xFF; st->aux_threshhigh = 0xFF; + st->acquisition_time = pdata->acquisition_time; ret = devm_add_action_or_reset(&spi->dev, ad7280_sw_power_down, st); if (ret) return ret; - /* - * Total Conversion Time = ((tACQ + tCONV) * - * (Number of Conversions per Part)) − - * tACQ + ((N - 1) * tDELAY) - * - * Readback Delay = Total Conversion Time + tWAIT - */ - - st->readback_delay_us = - ((t_acq_ns[pdata->acquisition_time & 0x3] + 695) * - (AD7280A_NUM_CH * n_avg[pdata->conversion_averaging & 0x3])) - - t_acq_ns[pdata->acquisition_time & 0x3] + st->slave_num * 250; - - /* Convert to usecs */ - st->readback_delay_us = DIV_ROUND_UP(st->readback_delay_us, 1000); - st->readback_delay_us += 5; /* Add tWAIT */ + ad7280_update_delay(st); indio_dev->name = spi_get_device_id(spi)->name; indio_dev->modes = INDIO_DIRECT_MODE; diff --git a/drivers/staging/iio/adc/ad7280a.h b/drivers/staging/iio/adc/ad7280a.h index 23f18bb9e279..99297789a46d 100644 --- a/drivers/staging/iio/adc/ad7280a.h +++ b/drivers/staging/iio/adc/ad7280a.h @@ -17,11 +17,6 @@ #define AD7280A_ACQ_TIME_1200ns 2 #define AD7280A_ACQ_TIME_1600ns 3 -#define AD7280A_CONV_AVG_DIS 0 -#define AD7280A_CONV_AVG_2 1 -#define AD7280A_CONV_AVG_4 2 -#define AD7280A_CONV_AVG_8 3 - #define AD7280A_ALERT_REMOVE_VIN5 BIT(2) #define AD7280A_ALERT_REMOVE_VIN4_VIN5 BIT(3) #define AD7280A_ALERT_REMOVE_AUX5 BIT(0) @@ -29,7 +24,6 @@ struct ad7280_platform_data { unsigned int acquisition_time; - unsigned int conversion_averaging; unsigned int chain_last_alert_ignore; bool thermistor_term_en; }; -- cgit v1.2.3 From 65ba4ab6f018c08262af98e9e83c1ebbe5c7627c Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 6 Feb 2022 19:03:19 +0000 Subject: staging:iio:adc:ad7280a: Cleanup includes Drop used includes, add a few missing ones and reorder. The include-what-you-use tool output was considered in making this change. Signed-off-by: Jonathan Cameron Reviewed-by: Marcelo Schmitt Link: https://lore.kernel.org/r/20220206190328.333093-12-jic23@kernel.org --- drivers/staging/iio/adc/ad7280a.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/drivers/staging/iio/adc/ad7280a.c b/drivers/staging/iio/adc/ad7280a.c index 2ba9379ce0a7..d408974c848c 100644 --- a/drivers/staging/iio/adc/ad7280a.c +++ b/drivers/staging/iio/adc/ad7280a.c @@ -5,21 +5,23 @@ * Copyright 2011 Analog Devices Inc. */ +#include +#include #include +#include #include +#include +#include #include +#include +#include +#include #include #include #include -#include -#include -#include -#include -#include -#include -#include #include +#include #include "ad7280a.h" -- cgit v1.2.3 From 9010ac1c7115e1edd69d955ba50098cb3341c84d Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 6 Feb 2022 19:03:20 +0000 Subject: staging:iio:ad7280a: Reflect optionality of irq in ABI Given the irq is optional, let us remove the interfaces related to events when it is not present. Signed-off-by: Jonathan Cameron Reviewed-by: Marcelo Schmitt Link: https://lore.kernel.org/r/20220206190328.333093-13-jic23@kernel.org --- drivers/staging/iio/adc/ad7280a.c | 48 +++++++++++++++++++++++---------------- 1 file changed, 29 insertions(+), 19 deletions(-) diff --git a/drivers/staging/iio/adc/ad7280a.c b/drivers/staging/iio/adc/ad7280a.c index d408974c848c..8635a12f5f84 100644 --- a/drivers/staging/iio/adc/ad7280a.c +++ b/drivers/staging/iio/adc/ad7280a.c @@ -579,23 +579,29 @@ static const struct iio_event_spec ad7280_events[] = { }, }; -static void ad7280_voltage_channel_init(struct iio_chan_spec *chan, int i) +static void ad7280_voltage_channel_init(struct iio_chan_spec *chan, int i, + bool irq_present) { chan->type = IIO_VOLTAGE; chan->differential = 1; chan->channel = i; chan->channel2 = chan->channel + 1; - chan->event_spec = ad7280_events; - chan->num_event_specs = ARRAY_SIZE(ad7280_events); + if (irq_present) { + chan->event_spec = ad7280_events; + chan->num_event_specs = ARRAY_SIZE(ad7280_events); + } chan->ext_info = ad7280_cell_ext_info; } -static void ad7280_temp_channel_init(struct iio_chan_spec *chan, int i) +static void ad7280_temp_channel_init(struct iio_chan_spec *chan, int i, + bool irq_present) { chan->type = IIO_TEMP; chan->channel = i; - chan->event_spec = ad7280_events; - chan->num_event_specs = ARRAY_SIZE(ad7280_events); + if (irq_present) { + chan->event_spec = ad7280_events; + chan->num_event_specs = ARRAY_SIZE(ad7280_events); + } } static void ad7280_common_fields_init(struct iio_chan_spec *chan, int addr, @@ -629,7 +635,8 @@ static void ad7280_total_voltage_channel_init(struct iio_chan_spec *chan, chan->scan_type.storagebits = 32; } -static void ad7280_init_dev_channels(struct ad7280_state *st, int dev, int *cnt) +static void ad7280_init_dev_channels(struct ad7280_state *st, int dev, int *cnt, + bool irq_present) { int addr, ch, i; struct iio_chan_spec *chan; @@ -639,10 +646,10 @@ static void ad7280_init_dev_channels(struct ad7280_state *st, int dev, int *cnt) if (ch < AD7280A_AUX_ADC_1_REG) { i = AD7280A_CALC_VOLTAGE_CHAN_NUM(dev, ch); - ad7280_voltage_channel_init(chan, i); + ad7280_voltage_channel_init(chan, i, irq_present); } else { i = AD7280A_CALC_TEMP_CHAN_NUM(dev, ch); - ad7280_temp_channel_init(chan, i); + ad7280_temp_channel_init(chan, i, irq_present); } addr = ad7280a_devaddr(dev) << 8 | ch; @@ -652,7 +659,7 @@ static void ad7280_init_dev_channels(struct ad7280_state *st, int dev, int *cnt) } } -static int ad7280_channel_init(struct ad7280_state *st) +static int ad7280_channel_init(struct ad7280_state *st, bool irq_present) { int dev, cnt = 0; @@ -662,7 +669,7 @@ static int ad7280_channel_init(struct ad7280_state *st) return -ENOMEM; for (dev = 0; dev <= st->slave_num; dev++) - ad7280_init_dev_channels(st, dev, &cnt); + ad7280_init_dev_channels(st, dev, &cnt, irq_present); ad7280_total_voltage_channel_init(&st->channels[cnt], cnt, dev); @@ -935,6 +942,11 @@ static const struct iio_info ad7280_info = { .write_event_value = &ad7280a_write_thresh, }; +static const struct iio_info ad7280_info_no_irq = { + .read_raw = ad7280_read_raw, + .write_raw = ad7280_write_raw, +}; + static const struct ad7280_platform_data ad7793_default_pdata = { .acquisition_time = AD7280A_ACQ_TIME_400ns, .thermistor_term_en = true, @@ -988,18 +1000,12 @@ static int ad7280_probe(struct spi_device *spi) indio_dev->name = spi_get_device_id(spi)->name; indio_dev->modes = INDIO_DIRECT_MODE; - ret = ad7280_channel_init(st); + ret = ad7280_channel_init(st, spi->irq > 0); if (ret < 0) return ret; indio_dev->num_channels = ret; indio_dev->channels = st->channels; - indio_dev->info = &ad7280_info; - - ret = devm_iio_device_register(&spi->dev, indio_dev); - if (ret) - return ret; - if (spi->irq > 0) { ret = ad7280_write(st, AD7280A_DEVADDR_MASTER, AD7280A_ALERT_REG, 1, @@ -1023,9 +1029,13 @@ static int ad7280_probe(struct spi_device *spi) indio_dev); if (ret) return ret; + + indio_dev->info = &ad7280_info; + } else { + indio_dev->info = &ad7280_info_no_irq; } - return 0; + return devm_iio_device_register(&spi->dev, indio_dev); } static const struct spi_device_id ad7280_id[] = { -- cgit v1.2.3 From dfa258c0660ed2a93d05fe9b7b3d3d652432bab7 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 6 Feb 2022 19:03:21 +0000 Subject: staging:iio:adc:ad7280a: Use a local dev pointer to avoid &spi->dev We use this a few times already and it is about to get worse, so introduce a local variable to simplify things. Signed-off-by: Jonathan Cameron Reviewed-by: Marcelo Schmitt Link: https://lore.kernel.org/r/20220206190328.333093-14-jic23@kernel.org --- drivers/staging/iio/adc/ad7280a.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/staging/iio/adc/ad7280a.c b/drivers/staging/iio/adc/ad7280a.c index 8635a12f5f84..df4a03f42c7a 100644 --- a/drivers/staging/iio/adc/ad7280a.c +++ b/drivers/staging/iio/adc/ad7280a.c @@ -955,11 +955,12 @@ static const struct ad7280_platform_data ad7793_default_pdata = { static int ad7280_probe(struct spi_device *spi) { const struct ad7280_platform_data *pdata = dev_get_platdata(&spi->dev); + struct device *dev = &spi->dev; struct ad7280_state *st; int ret; struct iio_dev *indio_dev; - indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); + indio_dev = devm_iio_device_alloc(dev, sizeof(*st)); if (!indio_dev) return -ENOMEM; @@ -991,7 +992,7 @@ static int ad7280_probe(struct spi_device *spi) st->aux_threshhigh = 0xFF; st->acquisition_time = pdata->acquisition_time; - ret = devm_add_action_or_reset(&spi->dev, ad7280_sw_power_down, st); + ret = devm_add_action_or_reset(dev, ad7280_sw_power_down, st); if (ret) return ret; @@ -1020,7 +1021,7 @@ static int ad7280_probe(struct spi_device *spi) if (ret) return ret; - ret = devm_request_threaded_irq(&spi->dev, spi->irq, + ret = devm_request_threaded_irq(dev, spi->irq, NULL, ad7280_event_handler, IRQF_TRIGGER_FALLING | @@ -1035,7 +1036,7 @@ static int ad7280_probe(struct spi_device *spi) indio_dev->info = &ad7280_info_no_irq; } - return devm_iio_device_register(&spi->dev, indio_dev); + return devm_iio_device_register(dev, indio_dev); } static const struct spi_device_id ad7280_id[] = { -- cgit v1.2.3 From 219def44752738638a13848fb04ecb388ed03507 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 6 Feb 2022 19:03:22 +0000 Subject: staging:iio:adc:ad7280a: Use device properties to replace platform data. Convert all the device specific info that was previously in platform data over to generic firmware query interfaces. dt-bindings to follow shortly. Signed-off-by: Jonathan Cameron Reviewed-by: Marcelo Schmitt Link: https://lore.kernel.org/r/20220206190328.333093-15-jic23@kernel.org --- drivers/staging/iio/adc/ad7280a.c | 100 ++++++++++++++++++++++++++++++++------ drivers/staging/iio/adc/ad7280a.h | 31 ------------ 2 files changed, 86 insertions(+), 45 deletions(-) delete mode 100644 drivers/staging/iio/adc/ad7280a.h diff --git a/drivers/staging/iio/adc/ad7280a.c b/drivers/staging/iio/adc/ad7280a.c index df4a03f42c7a..e8c9f22971cb 100644 --- a/drivers/staging/iio/adc/ad7280a.c +++ b/drivers/staging/iio/adc/ad7280a.c @@ -23,8 +23,6 @@ #include #include -#include "ad7280a.h" - /* Registers */ #define AD7280A_CELL_VOLTAGE_1_REG 0x0 /* D11 to D0, Read only */ @@ -81,6 +79,11 @@ #define AD7280A_AUX_ADC_UNDERVOLTAGE_REG 0x12 /* D7 to D0, Read/write */ #define AD7280A_ALERT_REG 0x13 /* D7 to D0, Read/write */ +#define AD7280A_ALERT_REMOVE_MSK GENMASK(3, 0) +#define AD7280A_ALERT_REMOVE_AUX5 BIT(0) +#define AD7280A_ALERT_REMOVE_AUX3_AUX5 BIT(1) +#define AD7280A_ALERT_REMOVE_VIN5 BIT(2) +#define AD7280A_ALERT_REMOVE_VIN4_VIN5 BIT(3) #define AD7280A_ALERT_GEN_STATIC_HIGH BIT(6) #define AD7280A_ALERT_RELAY_SIG_CHAIN_DOWN (BIT(7) | BIT(6)) @@ -163,6 +166,8 @@ static unsigned int ad7280a_devaddr(unsigned int addr) struct ad7280_state { struct spi_device *spi; struct iio_chan_spec *channels; + unsigned int chain_last_alert_ignore; + bool thermistor_term_en; int slave_num; int scan_cnt; int readback_delay_us; @@ -947,14 +952,8 @@ static const struct iio_info ad7280_info_no_irq = { .write_raw = ad7280_write_raw, }; -static const struct ad7280_platform_data ad7793_default_pdata = { - .acquisition_time = AD7280A_ACQ_TIME_400ns, - .thermistor_term_en = true, -}; - static int ad7280_probe(struct spi_device *spi) { - const struct ad7280_platform_data *pdata = dev_get_platdata(&spi->dev); struct device *dev = &spi->dev; struct ad7280_state *st; int ret; @@ -969,17 +968,90 @@ static int ad7280_probe(struct spi_device *spi) st->spi = spi; mutex_init(&st->lock); - if (!pdata) - pdata = &ad7793_default_pdata; + st->thermistor_term_en = + device_property_read_bool(dev, "adi,thermistor-termination"); + + if (device_property_present(dev, "adi,acquisition-time-ns")) { + u32 val; + + ret = device_property_read_u32(dev, "adi,acquisition-time-ns", &val); + if (ret) + return ret; + + switch (val) { + case 400: + st->acquisition_time = AD7280A_CTRL_LB_ACQ_TIME_400ns; + break; + case 800: + st->acquisition_time = AD7280A_CTRL_LB_ACQ_TIME_800ns; + break; + case 1200: + st->acquisition_time = AD7280A_CTRL_LB_ACQ_TIME_1200ns; + break; + case 1600: + st->acquisition_time = AD7280A_CTRL_LB_ACQ_TIME_1600ns; + break; + default: + dev_err(dev, "Firmware provided acquisition time is invalid\n"); + return -EINVAL; + } + } else { + st->acquisition_time = AD7280A_CTRL_LB_ACQ_TIME_400ns; + } + + /* Alert masks are intended for when particular inputs are not wired up */ + if (device_property_present(dev, "adi,voltage-alert-last-chan")) { + u32 val; + ret = device_property_read_u32(dev, "adi,voltage-alert-last-chan", &val); + if (ret) + return ret; + + switch (val) { + case 3: + st->chain_last_alert_ignore |= AD7280A_ALERT_REMOVE_VIN4_VIN5; + break; + case 4: + st->chain_last_alert_ignore |= AD7280A_ALERT_REMOVE_VIN5; + break; + case 5: + break; + default: + dev_err(dev, + "Firmware provided last voltage alert channel invalid\n"); + break; + } + } + if (device_property_present(dev, "adi,temp-alert-last-chan")) { + u32 val; + + ret = device_property_read_u32(dev, "adi,temp-alert-last-chan", &val); + if (ret) + return ret; + + switch (val) { + case 3: + st->chain_last_alert_ignore |= AD7280A_ALERT_REMOVE_AUX3_AUX5; + break; + case 4: + st->chain_last_alert_ignore |= AD7280A_ALERT_REMOVE_AUX5; + break; + case 5: + break; + default: + dev_err(dev, + "Firmware provided last temp alert channel invalid\n"); + break; + } + } crc8_populate_msb(st->crc_tab, POLYNOM); st->spi->max_speed_hz = AD7280A_MAX_SPI_CLK_HZ; st->spi->mode = SPI_MODE_1; spi_setup(st->spi); - st->ctrl_lb = FIELD_PREP(AD7280A_CTRL_LB_ACQ_TIME_MSK, pdata->acquisition_time) | - FIELD_PREP(AD7280A_CTRL_LB_THERMISTOR_MSK, pdata->thermistor_term_en); + st->ctrl_lb = FIELD_PREP(AD7280A_CTRL_LB_ACQ_TIME_MSK, st->acquisition_time) | + FIELD_PREP(AD7280A_CTRL_LB_THERMISTOR_MSK, st->thermistor_term_en); st->oversampling_ratio = 0; /* No oversampling */ ret = ad7280_chain_setup(st); @@ -990,7 +1062,6 @@ static int ad7280_probe(struct spi_device *spi) st->scan_cnt = (st->slave_num + 1) * AD7280A_NUM_CH; st->cell_threshhigh = 0xFF; st->aux_threshhigh = 0xFF; - st->acquisition_time = pdata->acquisition_time; ret = devm_add_action_or_reset(dev, ad7280_sw_power_down, st); if (ret) @@ -1017,7 +1088,8 @@ static int ad7280_probe(struct spi_device *spi) ret = ad7280_write(st, ad7280a_devaddr(st->slave_num), AD7280A_ALERT_REG, 0, AD7280A_ALERT_GEN_STATIC_HIGH | - (pdata->chain_last_alert_ignore & 0xF)); + FIELD_PREP(AD7280A_ALERT_REMOVE_MSK, + st->chain_last_alert_ignore)); if (ret) return ret; diff --git a/drivers/staging/iio/adc/ad7280a.h b/drivers/staging/iio/adc/ad7280a.h deleted file mode 100644 index 99297789a46d..000000000000 --- a/drivers/staging/iio/adc/ad7280a.h +++ /dev/null @@ -1,31 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * AD7280A Lithium Ion Battery Monitoring System - * - * Copyright 2011 Analog Devices Inc. - */ - -#ifndef IIO_ADC_AD7280_H_ -#define IIO_ADC_AD7280_H_ - -/* - * TODO: struct ad7280_platform_data needs to go into include/linux/iio - */ - -#define AD7280A_ACQ_TIME_400ns 0 -#define AD7280A_ACQ_TIME_800ns 1 -#define AD7280A_ACQ_TIME_1200ns 2 -#define AD7280A_ACQ_TIME_1600ns 3 - -#define AD7280A_ALERT_REMOVE_VIN5 BIT(2) -#define AD7280A_ALERT_REMOVE_VIN4_VIN5 BIT(3) -#define AD7280A_ALERT_REMOVE_AUX5 BIT(0) -#define AD7280A_ALERT_REMOVE_AUX4_AUX5 BIT(1) - -struct ad7280_platform_data { - unsigned int acquisition_time; - unsigned int chain_last_alert_ignore; - bool thermistor_term_en; -}; - -#endif /* IIO_ADC_AD7280_H_ */ -- cgit v1.2.3 From d2960145b37643970b53c60fa94fbf5c26f6eddf Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 6 Feb 2022 19:03:23 +0000 Subject: staging:iio:adc:ad7280a: Drop buggy support for early termination of AUX alert. This functionality is intended to allow for a few temperature sensors to be missing (and hence not worth reading) on the final device in a chain. The ones removed are 3 and 5 (unlike for the ADC channels where it is 4 and 5). The datasheet includes a foot note 3 to Table 12 that makes this complex to support. "(3) To remove AUX5 or AUX5 and AUX3 from the alert detection, conversions on three auxiliary ADC input channels only must be selected in the control register." This mode has never been supported by the driver. As this support would be complex to add and the rework is being done against a QEMU model developed for the purposes of verifying nothing is broken, it is better to drop this support for now. Reported-by: Marcelo Schmitt Signed-off-by: Jonathan Cameron Reviewed-by: Marcelo Schmitt Link: https://lore.kernel.org/r/20220206190328.333093-16-jic23@kernel.org --- drivers/staging/iio/adc/ad7280a.c | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/drivers/staging/iio/adc/ad7280a.c b/drivers/staging/iio/adc/ad7280a.c index e8c9f22971cb..a32c32a1226a 100644 --- a/drivers/staging/iio/adc/ad7280a.c +++ b/drivers/staging/iio/adc/ad7280a.c @@ -1022,28 +1022,6 @@ static int ad7280_probe(struct spi_device *spi) break; } } - if (device_property_present(dev, "adi,temp-alert-last-chan")) { - u32 val; - - ret = device_property_read_u32(dev, "adi,temp-alert-last-chan", &val); - if (ret) - return ret; - - switch (val) { - case 3: - st->chain_last_alert_ignore |= AD7280A_ALERT_REMOVE_AUX3_AUX5; - break; - case 4: - st->chain_last_alert_ignore |= AD7280A_ALERT_REMOVE_AUX5; - break; - case 5: - break; - default: - dev_err(dev, - "Firmware provided last temp alert channel invalid\n"); - break; - } - } crc8_populate_msb(st->crc_tab, POLYNOM); st->spi->max_speed_hz = AD7280A_MAX_SPI_CLK_HZ; -- cgit v1.2.3 From aa1b784deff3cc700b8405d7211c879ed2654203 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 6 Feb 2022 19:03:24 +0000 Subject: dt-bindings:iio:adc:ad7280a: Add binding Add a binding for this Lithium Ion Battery monitoring chip/chain of chips as it is now clean and ready to move out of staging. Signed-off-by: Jonathan Cameron Reviewed-by: Rob Herring Reviewed-by: Marcelo Schmitt Link: https://lore.kernel.org/r/20220206190328.333093-17-jic23@kernel.org --- .../devicetree/bindings/iio/adc/adi,ad7280a.yaml | 77 ++++++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/adc/adi,ad7280a.yaml diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad7280a.yaml b/Documentation/devicetree/bindings/iio/adc/adi,ad7280a.yaml new file mode 100644 index 000000000000..a694d5794d4a --- /dev/null +++ b/Documentation/devicetree/bindings/iio/adc/adi,ad7280a.yaml @@ -0,0 +1,77 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/adc/adi,ad7280a.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Analog Devices AD7280a Lithium Ion Battery Monitoring System + +maintainers: + - Michael Hennerich + - Jonathan Cameron + +description: | + Bindings for the Analog Devices AD7280a Battery Monitoring System. + Used in devices such as hybrid electric cars, battery backup and power tools. + Multiple chips can be daisy chained and accessed via a single SPI interface. + Data sheet found here: + https://www.analog.com/media/en/technical-documentation/data-sheets/AD7280A.pdf + +properties: + compatible: + const: adi,ad7280a + + reg: + maxItems: 1 + + interrupts: + description: IRQ line for the ADC + maxItems: 1 + + spi-max-frequency: true + + adi,voltage-alert-last-chan: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + Allows limiting of scope of which channels are considered for voltage + alerts, typically because not all are wired to anything. Only applies to + last device in the daisy chain. + default: 5 + enum: [3, 4, 5] + + adi,acquisition-time-ns: + description: + Additional time may be needed to charge the sampling capacitors depending + on external writing. + default: 400 + enum: [400, 800, 1200, 1600] + + adi,thermistor-termination: + type: boolean + description: + Enable the thermistor termination function. + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + spi { + #address-cells = <1>; + #size-cells = <0>; + + adc@0 { + compatible = "adi,ad7280a"; + reg = <0>; + spi-max-frequency = <700000>; + interrupt-parent = <&gpio>; + interrupts = <25 2>; + adi,thermistor-termination; + adi,acquisition-time-ns = <800>; + adi,voltage-alert-last-chan = <5>; + }; + }; +... -- cgit v1.2.3 From bc6fbf11771932732361e386c98b1c9fcc6898fe Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 6 Feb 2022 19:03:25 +0000 Subject: iio:adc:ad7280a: Document ABI for cell balance switches Very minimal ABI docs. This is unusual enough that I'd expect anyone who actually wanted to touch them to go look at the datasheet. Signed-off-by: Jonathan Cameron Reviewed-by: Marcelo Schmitt Link: https://lore.kernel.org/r/20220206190328.333093-18-jic23@kernel.org --- Documentation/ABI/testing/sysfs-bus-iio-adc-ad7280a | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 Documentation/ABI/testing/sysfs-bus-iio-adc-ad7280a diff --git a/Documentation/ABI/testing/sysfs-bus-iio-adc-ad7280a b/Documentation/ABI/testing/sysfs-bus-iio-adc-ad7280a new file mode 100644 index 000000000000..83b7efe6aa07 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-bus-iio-adc-ad7280a @@ -0,0 +1,13 @@ +What: /sys/bus/iio/devices/iio:deviceX/in_voltageY-voltageZ_balance_switch_en +KernelVersion: 5.14 +Contact: linux-iio@vger.kernel.org +Description: + Used to enable an output for balancing cells for time + controlled via in_voltage_Y-voltageZ_balance_switch_timer. + +What: /sys/bus/iio/devices/iio:deviceX/in_voltageY-voltageZ_balance_switch_timer +KernelVersion: 5.14 +Contact: linux-iio@vger.kernel.org +Description: + Time in seconds for which balance switch will be turned on. + Multiple of 71.5 seconds. -- cgit v1.2.3 From 6c6bc851d8369d00b2466a2c5ac92b5992e09ada Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 6 Feb 2022 19:03:26 +0000 Subject: staging:iio:adc:ad7280a: Remove shift from cb_mask state cache. Making the local storage of the Cell Balance mask a simple bitmap and then shifting it only at time of register write simplifies several code paths. Suggested-by: Marcelo Schmitt Signed-off-by: Jonathan Cameron Reviewed-by: Marcelo Schmitt Link: https://lore.kernel.org/r/20220206190328.333093-19-jic23@kernel.org --- drivers/staging/iio/adc/ad7280a.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/staging/iio/adc/ad7280a.c b/drivers/staging/iio/adc/ad7280a.c index a32c32a1226a..a7e16144b013 100644 --- a/drivers/staging/iio/adc/ad7280a.c +++ b/drivers/staging/iio/adc/ad7280a.c @@ -88,6 +88,7 @@ #define AD7280A_ALERT_RELAY_SIG_CHAIN_DOWN (BIT(7) | BIT(6)) #define AD7280A_CELL_BALANCE_REG 0x14 /* D7 to D0, Read/write */ +#define AD7280A_CELL_BALANCE_CHAN_BITMAP_MSK GENMASK(7, 2) #define AD7280A_CB1_TIMER_REG 0x15 /* D7 to D0, Read/write */ #define AD7280A_CB_TIMER_VAL_MSK GENMASK(7, 3) #define AD7280A_CB2_TIMER_REG 0x16 /* D7 to D0, Read/write */ @@ -474,7 +475,7 @@ static ssize_t ad7280_show_balance_sw(struct iio_dev *indio_dev, return sysfs_emit(buf, "%d\n", !!(st->cb_mask[chan->address >> 8] & - (1 << ((chan->address & 0xFF) + 2)))); + BIT(chan->address & 0xFF))); } static ssize_t ad7280_store_balance_sw(struct iio_dev *indio_dev, @@ -496,12 +497,13 @@ static ssize_t ad7280_store_balance_sw(struct iio_dev *indio_dev, mutex_lock(&st->lock); if (readin) - st->cb_mask[devaddr] |= 1 << (ch + 2); + st->cb_mask[devaddr] |= BIT(ch); else - st->cb_mask[devaddr] &= ~(1 << (ch + 2)); + st->cb_mask[devaddr] &= ~BIT(ch); - ret = ad7280_write(st, devaddr, AD7280A_CELL_BALANCE_REG, - 0, st->cb_mask[devaddr]); + ret = ad7280_write(st, devaddr, AD7280A_CELL_BALANCE_REG, 0, + FIELD_PREP(AD7280A_CELL_BALANCE_CHAN_BITMAP_MSK, + st->cb_mask[devaddr])); mutex_unlock(&st->lock); return ret ? ret : len; -- cgit v1.2.3 From 48fb57697ee620945b6deca3d688b797acd95450 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 6 Feb 2022 19:03:27 +0000 Subject: staging:iio:adc:ad7280a: Use more conservative delays to allow 105C operation. The datasheet provides timings for operating this device at up to 105 degrees centigrade. Adopt these more conservative timings. Suggested-by: Marcelo Schmitt Signed-off-by: Jonathan Cameron Reviewed-by: Marcelo Schmitt Link: https://lore.kernel.org/r/20220206190328.333093-20-jic23@kernel.org --- drivers/staging/iio/adc/ad7280a.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/staging/iio/adc/ad7280a.c b/drivers/staging/iio/adc/ad7280a.c index a7e16144b013..ef9d27759961 100644 --- a/drivers/staging/iio/adc/ad7280a.c +++ b/drivers/staging/iio/adc/ad7280a.c @@ -137,7 +137,7 @@ #define AD7280A_DEVADDR_ALL 0x1F static const unsigned short ad7280a_n_avg[4] = {1, 2, 4, 8}; -static const unsigned short ad7280a_t_acq_ns[4] = {465, 1010, 1460, 1890}; +static const unsigned short ad7280a_t_acq_ns[4] = {470, 1030, 1510, 1945}; /* 5-bit device address is sent LSB first */ static unsigned int ad7280a_devaddr(unsigned int addr) @@ -869,7 +869,7 @@ static void ad7280_update_delay(struct ad7280_state *st) */ st->readback_delay_us = - ((ad7280a_t_acq_ns[st->acquisition_time & 0x3] + 695) * + ((ad7280a_t_acq_ns[st->acquisition_time & 0x3] + 720) * (AD7280A_NUM_CH * ad7280a_n_avg[st->oversampling_ratio & 0x3])) - ad7280a_t_acq_ns[st->acquisition_time & 0x3] + st->slave_num * 250; -- cgit v1.2.3 From cf890fe8ae3641da301ce212a22ea841c9bf6296 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 6 Feb 2022 19:03:28 +0000 Subject: iio:adc:ad7280a: Move out of staging This is a rather unusual device (in IIO anyway). However, it has a near to standard userspace ABI. Note the work to move this out of staging was done against a minimal QEMU model, which doesn't model all the features of the device. I have no intention to upstream the QEMU model as it was developed just to enable this driver cleanup. https://github.com/jic23/qemu/tree/ad7280a-hacks Signed-off-by: Jonathan Cameron Reviewed-by: Marcelo Schmitt Link: https://lore.kernel.org/r/20220206190328.333093-21-jic23@kernel.org --- drivers/iio/adc/Kconfig | 11 + drivers/iio/adc/Makefile | 1 + drivers/iio/adc/ad7280a.c | 1111 +++++++++++++++++++++++++++++++++++++ drivers/staging/iio/adc/Kconfig | 11 - drivers/staging/iio/adc/Makefile | 1 - drivers/staging/iio/adc/ad7280a.c | 1111 ------------------------------------- 6 files changed, 1123 insertions(+), 1123 deletions(-) create mode 100644 drivers/iio/adc/ad7280a.c delete mode 100644 drivers/staging/iio/adc/ad7280a.c diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 4fdc8bfbb407..71ab0a06aa82 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -64,6 +64,17 @@ config AD7266 To compile this driver as a module, choose M here: the module will be called ad7266. +config AD7280 + tristate "Analog Devices AD7280A Lithium Ion Battery Monitoring System" + depends on SPI + select CRC8 + help + Say yes here to build support for Analog Devices AD7280A + Lithium Ion Battery Monitoring System. + + To compile this driver as a module, choose M here: the + module will be called ad7280a + config AD7291 tristate "Analog Devices AD7291 ADC driver" depends on I2C diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index 4a8f1833993b..39d806f6d457 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -10,6 +10,7 @@ obj-$(CONFIG_AD7091R5) += ad7091r5.o ad7091r-base.o obj-$(CONFIG_AD7124) += ad7124.o obj-$(CONFIG_AD7192) += ad7192.o obj-$(CONFIG_AD7266) += ad7266.o +obj-$(CONFIG_AD7280) += ad7280a.o obj-$(CONFIG_AD7291) += ad7291.o obj-$(CONFIG_AD7292) += ad7292.o obj-$(CONFIG_AD7298) += ad7298.o diff --git a/drivers/iio/adc/ad7280a.c b/drivers/iio/adc/ad7280a.c new file mode 100644 index 000000000000..ef9d27759961 --- /dev/null +++ b/drivers/iio/adc/ad7280a.c @@ -0,0 +1,1111 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * AD7280A Lithium Ion Battery Monitoring System + * + * Copyright 2011 Analog Devices Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/* Registers */ + +#define AD7280A_CELL_VOLTAGE_1_REG 0x0 /* D11 to D0, Read only */ +#define AD7280A_CELL_VOLTAGE_2_REG 0x1 /* D11 to D0, Read only */ +#define AD7280A_CELL_VOLTAGE_3_REG 0x2 /* D11 to D0, Read only */ +#define AD7280A_CELL_VOLTAGE_4_REG 0x3 /* D11 to D0, Read only */ +#define AD7280A_CELL_VOLTAGE_5_REG 0x4 /* D11 to D0, Read only */ +#define AD7280A_CELL_VOLTAGE_6_REG 0x5 /* D11 to D0, Read only */ +#define AD7280A_AUX_ADC_1_REG 0x6 /* D11 to D0, Read only */ +#define AD7280A_AUX_ADC_2_REG 0x7 /* D11 to D0, Read only */ +#define AD7280A_AUX_ADC_3_REG 0x8 /* D11 to D0, Read only */ +#define AD7280A_AUX_ADC_4_REG 0x9 /* D11 to D0, Read only */ +#define AD7280A_AUX_ADC_5_REG 0xA /* D11 to D0, Read only */ +#define AD7280A_AUX_ADC_6_REG 0xB /* D11 to D0, Read only */ +#define AD7280A_SELF_TEST_REG 0xC /* D11 to D0, Read only */ + +#define AD7280A_CTRL_HB_REG 0xD /* D15 to D8, Read/write */ +#define AD7280A_CTRL_HB_CONV_INPUT_MSK GENMASK(7, 6) +#define AD7280A_CTRL_HB_CONV_INPUT_ALL 0 +#define AD7280A_CTRL_HB_CONV_INPUT_6CELL_AUX1_3_5 1 +#define AD7280A_CTRL_HB_CONV_INPUT_6CELL 2 +#define AD7280A_CTRL_HB_CONV_INPUT_SELF_TEST 3 +#define AD7280A_CTRL_HB_CONV_RREAD_MSK GENMASK(5, 4) +#define AD7280A_CTRL_HB_CONV_RREAD_ALL 0 +#define AD7280A_CTRL_HB_CONV_RREAD_6CELL_AUX1_3_5 1 +#define AD7280A_CTRL_HB_CONV_RREAD_6CELL 2 +#define AD7280A_CTRL_HB_CONV_RREAD_NO 3 +#define AD7280A_CTRL_HB_CONV_START_MSK BIT(3) +#define AD7280A_CTRL_HB_CONV_START_CNVST 0 +#define AD7280A_CTRL_HB_CONV_START_CS 1 +#define AD7280A_CTRL_HB_CONV_AVG_MSK GENMASK(2, 1) +#define AD7280A_CTRL_HB_CONV_AVG_DIS 0 +#define AD7280A_CTRL_HB_CONV_AVG_2 1 +#define AD7280A_CTRL_HB_CONV_AVG_4 2 +#define AD7280A_CTRL_HB_CONV_AVG_8 3 +#define AD7280A_CTRL_HB_PWRDN_SW BIT(0) + +#define AD7280A_CTRL_LB_REG 0xE /* D7 to D0, Read/write */ +#define AD7280A_CTRL_LB_SWRST_MSK BIT(7) +#define AD7280A_CTRL_LB_ACQ_TIME_MSK GENMASK(6, 5) +#define AD7280A_CTRL_LB_ACQ_TIME_400ns 0 +#define AD7280A_CTRL_LB_ACQ_TIME_800ns 1 +#define AD7280A_CTRL_LB_ACQ_TIME_1200ns 2 +#define AD7280A_CTRL_LB_ACQ_TIME_1600ns 3 +#define AD7280A_CTRL_LB_MUST_SET BIT(4) +#define AD7280A_CTRL_LB_THERMISTOR_MSK BIT(3) +#define AD7280A_CTRL_LB_LOCK_DEV_ADDR_MSK BIT(2) +#define AD7280A_CTRL_LB_INC_DEV_ADDR_MSK BIT(1) +#define AD7280A_CTRL_LB_DAISY_CHAIN_RB_MSK BIT(0) + +#define AD7280A_CELL_OVERVOLTAGE_REG 0xF /* D7 to D0, Read/write */ +#define AD7280A_CELL_UNDERVOLTAGE_REG 0x10 /* D7 to D0, Read/write */ +#define AD7280A_AUX_ADC_OVERVOLTAGE_REG 0x11 /* D7 to D0, Read/write */ +#define AD7280A_AUX_ADC_UNDERVOLTAGE_REG 0x12 /* D7 to D0, Read/write */ + +#define AD7280A_ALERT_REG 0x13 /* D7 to D0, Read/write */ +#define AD7280A_ALERT_REMOVE_MSK GENMASK(3, 0) +#define AD7280A_ALERT_REMOVE_AUX5 BIT(0) +#define AD7280A_ALERT_REMOVE_AUX3_AUX5 BIT(1) +#define AD7280A_ALERT_REMOVE_VIN5 BIT(2) +#define AD7280A_ALERT_REMOVE_VIN4_VIN5 BIT(3) +#define AD7280A_ALERT_GEN_STATIC_HIGH BIT(6) +#define AD7280A_ALERT_RELAY_SIG_CHAIN_DOWN (BIT(7) | BIT(6)) + +#define AD7280A_CELL_BALANCE_REG 0x14 /* D7 to D0, Read/write */ +#define AD7280A_CELL_BALANCE_CHAN_BITMAP_MSK GENMASK(7, 2) +#define AD7280A_CB1_TIMER_REG 0x15 /* D7 to D0, Read/write */ +#define AD7280A_CB_TIMER_VAL_MSK GENMASK(7, 3) +#define AD7280A_CB2_TIMER_REG 0x16 /* D7 to D0, Read/write */ +#define AD7280A_CB3_TIMER_REG 0x17 /* D7 to D0, Read/write */ +#define AD7280A_CB4_TIMER_REG 0x18 /* D7 to D0, Read/write */ +#define AD7280A_CB5_TIMER_REG 0x19 /* D7 to D0, Read/write */ +#define AD7280A_CB6_TIMER_REG 0x1A /* D7 to D0, Read/write */ +#define AD7280A_PD_TIMER_REG 0x1B /* D7 to D0, Read/write */ +#define AD7280A_READ_REG 0x1C /* D7 to D0, Read/write */ +#define AD7280A_READ_ADDR_MSK GENMASK(7, 2) +#define AD7280A_CNVST_CTRL_REG 0x1D /* D7 to D0, Read/write */ + +/* Transfer fields */ +#define AD7280A_TRANS_WRITE_DEVADDR_MSK GENMASK(31, 27) +#define AD7280A_TRANS_WRITE_ADDR_MSK GENMASK(26, 21) +#define AD7280A_TRANS_WRITE_VAL_MSK GENMASK(20, 13) +#define AD7280A_TRANS_WRITE_ALL_MSK BIT(12) +#define AD7280A_TRANS_WRITE_CRC_MSK GENMASK(10, 3) +#define AD7280A_TRANS_WRITE_RES_PATTERN 0x2 + +/* Layouts differ for channel vs other registers */ +#define AD7280A_TRANS_READ_DEVADDR_MSK GENMASK(31, 27) +#define AD7280A_TRANS_READ_CONV_CHANADDR_MSK GENMASK(26, 23) +#define AD7280A_TRANS_READ_CONV_DATA_MSK GENMASK(22, 11) +#define AD7280A_TRANS_READ_REG_REGADDR_MSK GENMASK(26, 21) +#define AD7280A_TRANS_READ_REG_DATA_MSK GENMASK(20, 13) +#define AD7280A_TRANS_READ_WRITE_ACK_MSK BIT(10) +#define AD7280A_TRANS_READ_CRC_MSK GENMASK(9, 2) + +/* Magic value used to indicate this special case */ +#define AD7280A_ALL_CELLS (0xAD << 16) + +#define AD7280A_MAX_SPI_CLK_HZ 700000 /* < 1MHz */ +#define AD7280A_MAX_CHAIN 8 +#define AD7280A_CELLS_PER_DEV 6 +#define AD7280A_BITS 12 +#define AD7280A_NUM_CH (AD7280A_AUX_ADC_6_REG - \ + AD7280A_CELL_VOLTAGE_1_REG + 1) + +#define AD7280A_CALC_VOLTAGE_CHAN_NUM(d, c) (((d) * AD7280A_CELLS_PER_DEV) + \ + (c)) +#define AD7280A_CALC_TEMP_CHAN_NUM(d, c) (((d) * AD7280A_CELLS_PER_DEV) + \ + (c) - AD7280A_CELLS_PER_DEV) + +#define AD7280A_DEVADDR_MASTER 0 +#define AD7280A_DEVADDR_ALL 0x1F + +static const unsigned short ad7280a_n_avg[4] = {1, 2, 4, 8}; +static const unsigned short ad7280a_t_acq_ns[4] = {470, 1030, 1510, 1945}; + +/* 5-bit device address is sent LSB first */ +static unsigned int ad7280a_devaddr(unsigned int addr) +{ + return ((addr & 0x1) << 4) | + ((addr & 0x2) << 2) | + (addr & 0x4) | + ((addr & 0x8) >> 2) | + ((addr & 0x10) >> 4); +} + +/* + * During a read a valid write is mandatory. + * So writing to the highest available address (Address 0x1F) and setting the + * address all parts bit to 0 is recommended. + * So the TXVAL is AD7280A_DEVADDR_ALL + CRC + */ +#define AD7280A_READ_TXVAL 0xF800030A + +/* + * AD7280 CRC + * + * P(x) = x^8 + x^5 + x^3 + x^2 + x^1 + x^0 = 0b100101111 => 0x2F + */ +#define POLYNOM 0x2F + +struct ad7280_state { + struct spi_device *spi; + struct iio_chan_spec *channels; + unsigned int chain_last_alert_ignore; + bool thermistor_term_en; + int slave_num; + int scan_cnt; + int readback_delay_us; + unsigned char crc_tab[CRC8_TABLE_SIZE]; + u8 oversampling_ratio; + u8 acquisition_time; + unsigned char ctrl_lb; + unsigned char cell_threshhigh; + unsigned char cell_threshlow; + unsigned char aux_threshhigh; + unsigned char aux_threshlow; + unsigned char cb_mask[AD7280A_MAX_CHAIN]; + struct mutex lock; /* protect sensor state */ + + __be32 tx ____cacheline_aligned; + __be32 rx; +}; + +static unsigned char ad7280_calc_crc8(unsigned char *crc_tab, unsigned int val) +{ + unsigned char crc; + + crc = crc_tab[val >> 16 & 0xFF]; + crc = crc_tab[crc ^ (val >> 8 & 0xFF)]; + + return crc ^ (val & 0xFF); +} + +static int ad7280_check_crc(struct ad7280_state *st, unsigned int val) +{ + unsigned char crc = ad7280_calc_crc8(st->crc_tab, val >> 10); + + if (crc != ((val >> 2) & 0xFF)) + return -EIO; + + return 0; +} + +/* + * After initiating a conversion sequence we need to wait until the conversion + * is done. The delay is typically in the range of 15..30us however depending on + * the number of devices in the daisy chain, the number of averages taken, + * conversion delays and acquisition time options it may take up to 250us, in + * this case we better sleep instead of busy wait. + */ + +static void ad7280_delay(struct ad7280_state *st) +{ + if (st->readback_delay_us < 50) + udelay(st->readback_delay_us); + else + usleep_range(250, 500); +} + +static int __ad7280_read32(struct ad7280_state *st, unsigned int *val) +{ + int ret; + struct spi_transfer t = { + .tx_buf = &st->tx, + .rx_buf = &st->rx, + .len = sizeof(st->tx), + }; + + st->tx = cpu_to_be32(AD7280A_READ_TXVAL); + + ret = spi_sync_transfer(st->spi, &t, 1); + if (ret) + return ret; + + *val = be32_to_cpu(st->rx); + + return 0; +} + +static int ad7280_write(struct ad7280_state *st, unsigned int devaddr, + unsigned int addr, bool all, unsigned int val) +{ + unsigned int reg = FIELD_PREP(AD7280A_TRANS_WRITE_DEVADDR_MSK, devaddr) | + FIELD_PREP(AD7280A_TRANS_WRITE_ADDR_MSK, addr) | + FIELD_PREP(AD7280A_TRANS_WRITE_VAL_MSK, val) | + FIELD_PREP(AD7280A_TRANS_WRITE_ALL_MSK, all); + + reg |= FIELD_PREP(AD7280A_TRANS_WRITE_CRC_MSK, + ad7280_calc_crc8(st->crc_tab, reg >> 11)); + /* Reserved b010 pattern not included crc calc */ + reg |= AD7280A_TRANS_WRITE_RES_PATTERN; + + st->tx = cpu_to_be32(reg); + + return spi_write(st->spi, &st->tx, sizeof(st->tx)); +} + +static int ad7280_read_reg(struct ad7280_state *st, unsigned int devaddr, + unsigned int addr) +{ + int ret; + unsigned int tmp; + + /* turns off the read operation on all parts */ + ret = ad7280_write(st, AD7280A_DEVADDR_MASTER, AD7280A_CTRL_HB_REG, 1, + FIELD_PREP(AD7280A_CTRL_HB_CONV_INPUT_MSK, + AD7280A_CTRL_HB_CONV_INPUT_ALL) | + FIELD_PREP(AD7280A_CTRL_HB_CONV_RREAD_MSK, + AD7280A_CTRL_HB_CONV_RREAD_NO) | + FIELD_PREP(AD7280A_CTRL_HB_CONV_AVG_MSK, + st->oversampling_ratio)); + if (ret) + return ret; + + /* turns on the read operation on the addressed part */ + ret = ad7280_write(st, devaddr, AD7280A_CTRL_HB_REG, 0, + FIELD_PREP(AD7280A_CTRL_HB_CONV_INPUT_MSK, + AD7280A_CTRL_HB_CONV_INPUT_ALL) | + FIELD_PREP(AD7280A_CTRL_HB_CONV_RREAD_MSK, + AD7280A_CTRL_HB_CONV_RREAD_ALL) | + FIELD_PREP(AD7280A_CTRL_HB_CONV_AVG_MSK, + st->oversampling_ratio)); + if (ret) + return ret; + + /* Set register address on the part to be read from */ + ret = ad7280_write(st, devaddr, AD7280A_READ_REG, 0, + FIELD_PREP(AD7280A_READ_ADDR_MSK, addr)); + if (ret) + return ret; + + ret = __ad7280_read32(st, &tmp); + if (ret) + return ret; + + if (ad7280_check_crc(st, tmp)) + return -EIO; + + if ((FIELD_GET(AD7280A_TRANS_READ_DEVADDR_MSK, tmp) != devaddr) || + (FIELD_GET(AD7280A_TRANS_READ_REG_REGADDR_MSK, tmp) != addr)) + return -EFAULT; + + return FIELD_GET(AD7280A_TRANS_READ_REG_DATA_MSK, tmp); +} + +static int ad7280_read_channel(struct ad7280_state *st, unsigned int devaddr, + unsigned int addr) +{ + int ret; + unsigned int tmp; + + ret = ad7280_write(st, devaddr, AD7280A_READ_REG, 0, + FIELD_PREP(AD7280A_READ_ADDR_MSK, addr)); + if (ret) + return ret; + + ret = ad7280_write(st, AD7280A_DEVADDR_MASTER, AD7280A_CTRL_HB_REG, 1, + FIELD_PREP(AD7280A_CTRL_HB_CONV_INPUT_MSK, + AD7280A_CTRL_HB_CONV_INPUT_ALL) | + FIELD_PREP(AD7280A_CTRL_HB_CONV_RREAD_MSK, + AD7280A_CTRL_HB_CONV_RREAD_NO) | + FIELD_PREP(AD7280A_CTRL_HB_CONV_AVG_MSK, + st->oversampling_ratio)); + if (ret) + return ret; + + ret = ad7280_write(st, devaddr, AD7280A_CTRL_HB_REG, 0, + FIELD_PREP(AD7280A_CTRL_HB_CONV_INPUT_MSK, + AD7280A_CTRL_HB_CONV_INPUT_ALL) | + FIELD_PREP(AD7280A_CTRL_HB_CONV_RREAD_MSK, + AD7280A_CTRL_HB_CONV_RREAD_ALL) | + FIELD_PREP(AD7280A_CTRL_HB_CONV_START_MSK, + AD7280A_CTRL_HB_CONV_START_CS) | + FIELD_PREP(AD7280A_CTRL_HB_CONV_AVG_MSK, + st->oversampling_ratio)); + if (ret) + return ret; + + ad7280_delay(st); + + ret = __ad7280_read32(st, &tmp); + if (ret) + return ret; + + if (ad7280_check_crc(st, tmp)) + return -EIO; + + if ((FIELD_GET(AD7280A_TRANS_READ_DEVADDR_MSK, tmp) != devaddr) || + (FIELD_GET(AD7280A_TRANS_READ_CONV_CHANADDR_MSK, tmp) != addr)) + return -EFAULT; + + return FIELD_GET(AD7280A_TRANS_READ_CONV_DATA_MSK, tmp); +} + +static int ad7280_read_all_channels(struct ad7280_state *st, unsigned int cnt, + unsigned int *array) +{ + int i, ret; + unsigned int tmp, sum = 0; + + ret = ad7280_write(st, AD7280A_DEVADDR_MASTER, AD7280A_READ_REG, 1, + AD7280A_CELL_VOLTAGE_1_REG << 2); + if (ret) + return ret; + + ret = ad7280_write(st, AD7280A_DEVADDR_MASTER, AD7280A_CTRL_HB_REG, 1, + FIELD_PREP(AD7280A_CTRL_HB_CONV_INPUT_MSK, + AD7280A_CTRL_HB_CONV_INPUT_ALL) | + FIELD_PREP(AD7280A_CTRL_HB_CONV_RREAD_MSK, + AD7280A_CTRL_HB_CONV_RREAD_ALL) | + FIELD_PREP(AD7280A_CTRL_HB_CONV_START_MSK, + AD7280A_CTRL_HB_CONV_START_CS) | + FIELD_PREP(AD7280A_CTRL_HB_CONV_AVG_MSK, + st->oversampling_ratio)); + if (ret) + return ret; + + ad7280_delay(st); + + for (i = 0; i < cnt; i++) { + ret = __ad7280_read32(st, &tmp); + if (ret) + return ret; + + if (ad7280_check_crc(st, tmp)) + return -EIO; + + if (array) + array[i] = tmp; + /* only sum cell voltages */ + if (FIELD_GET(AD7280A_TRANS_READ_CONV_CHANADDR_MSK, tmp) <= + AD7280A_CELL_VOLTAGE_6_REG) + sum += FIELD_GET(AD7280A_TRANS_READ_CONV_DATA_MSK, tmp); + } + + return sum; +} + +static void ad7280_sw_power_down(void *data) +{ + struct ad7280_state *st = data; + + ad7280_write(st, AD7280A_DEVADDR_MASTER, AD7280A_CTRL_HB_REG, 1, + AD7280A_CTRL_HB_PWRDN_SW | + FIELD_PREP(AD7280A_CTRL_HB_CONV_AVG_MSK, st->oversampling_ratio)); +} + +static int ad7280_chain_setup(struct ad7280_state *st) +{ + unsigned int val, n; + int ret; + + ret = ad7280_write(st, AD7280A_DEVADDR_MASTER, AD7280A_CTRL_LB_REG, 1, + FIELD_PREP(AD7280A_CTRL_LB_DAISY_CHAIN_RB_MSK, 1) | + FIELD_PREP(AD7280A_CTRL_LB_LOCK_DEV_ADDR_MSK, 1) | + AD7280A_CTRL_LB_MUST_SET | + FIELD_PREP(AD7280A_CTRL_LB_SWRST_MSK, 1) | + st->ctrl_lb); + if (ret) + return ret; + + ret = ad7280_write(st, AD7280A_DEVADDR_MASTER, AD7280A_CTRL_LB_REG, 1, + FIELD_PREP(AD7280A_CTRL_LB_DAISY_CHAIN_RB_MSK, 1) | + FIELD_PREP(AD7280A_CTRL_LB_LOCK_DEV_ADDR_MSK, 1) | + AD7280A_CTRL_LB_MUST_SET | + FIELD_PREP(AD7280A_CTRL_LB_SWRST_MSK, 0) | + st->ctrl_lb); + if (ret) + goto error_power_down; + + ret = ad7280_write(st, AD7280A_DEVADDR_MASTER, AD7280A_READ_REG, 1, + FIELD_PREP(AD7280A_READ_ADDR_MSK, AD7280A_CTRL_LB_REG)); + if (ret) + goto error_power_down; + + for (n = 0; n <= AD7280A_MAX_CHAIN; n++) { + ret = __ad7280_read32(st, &val); + if (ret) + goto error_power_down; + + if (val == 0) + return n - 1; + + if (ad7280_check_crc(st, val)) { + ret = -EIO; + goto error_power_down; + } + + if (n != ad7280a_devaddr(FIELD_GET(AD7280A_TRANS_READ_DEVADDR_MSK, val))) { + ret = -EIO; + goto error_power_down; + } + } + ret = -EFAULT; + +error_power_down: + ad7280_write(st, AD7280A_DEVADDR_MASTER, AD7280A_CTRL_HB_REG, 1, + AD7280A_CTRL_HB_PWRDN_SW | + FIELD_PREP(AD7280A_CTRL_HB_CONV_AVG_MSK, st->oversampling_ratio)); + + return ret; +} + +static ssize_t ad7280_show_balance_sw(struct iio_dev *indio_dev, + uintptr_t private, + const struct iio_chan_spec *chan, char *buf) +{ + struct ad7280_state *st = iio_priv(indio_dev); + + return sysfs_emit(buf, "%d\n", + !!(st->cb_mask[chan->address >> 8] & + BIT(chan->address & 0xFF))); +} + +static ssize_t ad7280_store_balance_sw(struct iio_dev *indio_dev, + uintptr_t private, + const struct iio_chan_spec *chan, + const char *buf, size_t len) +{ + struct ad7280_state *st = iio_priv(indio_dev); + unsigned int devaddr, ch; + bool readin; + int ret; + + ret = strtobool(buf, &readin); + if (ret) + return ret; + + devaddr = chan->address >> 8; + ch = chan->address & 0xFF; + + mutex_lock(&st->lock); + if (readin) + st->cb_mask[devaddr] |= BIT(ch); + else + st->cb_mask[devaddr] &= ~BIT(ch); + + ret = ad7280_write(st, devaddr, AD7280A_CELL_BALANCE_REG, 0, + FIELD_PREP(AD7280A_CELL_BALANCE_CHAN_BITMAP_MSK, + st->cb_mask[devaddr])); + mutex_unlock(&st->lock); + + return ret ? ret : len; +} + +static ssize_t ad7280_show_balance_timer(struct iio_dev *indio_dev, + uintptr_t private, + const struct iio_chan_spec *chan, + char *buf) +{ + struct ad7280_state *st = iio_priv(indio_dev); + unsigned int msecs; + int ret; + + mutex_lock(&st->lock); + ret = ad7280_read_reg(st, chan->address >> 8, + (chan->address & 0xFF) + AD7280A_CB1_TIMER_REG); + mutex_unlock(&st->lock); + + if (ret < 0) + return ret; + + msecs = FIELD_GET(AD7280A_CB_TIMER_VAL_MSK, ret) * 71500; + + return sysfs_emit(buf, "%u.%u\n", msecs / 1000, msecs % 1000); +} + +static ssize_t ad7280_store_balance_timer(struct iio_dev *indio_dev, + uintptr_t private, + const struct iio_chan_spec *chan, + const char *buf, size_t len) +{ + struct ad7280_state *st = iio_priv(indio_dev); + int val, val2; + int ret; + + ret = iio_str_to_fixpoint(buf, 1000, &val, &val2); + if (ret) + return ret; + + val = val * 1000 + val2; + val /= 71500; + + if (val > 31) + return -EINVAL; + + mutex_lock(&st->lock); + ret = ad7280_write(st, chan->address >> 8, + (chan->address & 0xFF) + AD7280A_CB1_TIMER_REG, 0, + FIELD_PREP(AD7280A_CB_TIMER_VAL_MSK, val)); + mutex_unlock(&st->lock); + + return ret ? ret : len; +} + +static const struct iio_chan_spec_ext_info ad7280_cell_ext_info[] = { + { + .name = "balance_switch_en", + .read = ad7280_show_balance_sw, + .write = ad7280_store_balance_sw, + .shared = IIO_SEPARATE, + }, { + .name = "balance_switch_timer", + .read = ad7280_show_balance_timer, + .write = ad7280_store_balance_timer, + .shared = IIO_SEPARATE, + }, + {} +}; + +static const struct iio_event_spec ad7280_events[] = { + { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_RISING, + .mask_shared_by_type = BIT(IIO_EV_INFO_VALUE), + }, { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_FALLING, + .mask_shared_by_type = BIT(IIO_EV_INFO_VALUE), + }, +}; + +static void ad7280_voltage_channel_init(struct iio_chan_spec *chan, int i, + bool irq_present) +{ + chan->type = IIO_VOLTAGE; + chan->differential = 1; + chan->channel = i; + chan->channel2 = chan->channel + 1; + if (irq_present) { + chan->event_spec = ad7280_events; + chan->num_event_specs = ARRAY_SIZE(ad7280_events); + } + chan->ext_info = ad7280_cell_ext_info; +} + +static void ad7280_temp_channel_init(struct iio_chan_spec *chan, int i, + bool irq_present) +{ + chan->type = IIO_TEMP; + chan->channel = i; + if (irq_present) { + chan->event_spec = ad7280_events; + chan->num_event_specs = ARRAY_SIZE(ad7280_events); + } +} + +static void ad7280_common_fields_init(struct iio_chan_spec *chan, int addr, + int cnt) +{ + chan->indexed = 1; + chan->info_mask_separate = BIT(IIO_CHAN_INFO_RAW); + chan->info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE); + chan->info_mask_shared_by_all = BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO); + chan->address = addr; + chan->scan_index = cnt; + chan->scan_type.sign = 'u'; + chan->scan_type.realbits = 12; + chan->scan_type.storagebits = 32; +} + +static void ad7280_total_voltage_channel_init(struct iio_chan_spec *chan, + int cnt, int dev) +{ + chan->type = IIO_VOLTAGE; + chan->differential = 1; + chan->channel = 0; + chan->channel2 = dev * AD7280A_CELLS_PER_DEV; + chan->address = AD7280A_ALL_CELLS; + chan->indexed = 1; + chan->info_mask_separate = BIT(IIO_CHAN_INFO_RAW); + chan->info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE); + chan->scan_index = cnt; + chan->scan_type.sign = 'u'; + chan->scan_type.realbits = 32; + chan->scan_type.storagebits = 32; +} + +static void ad7280_init_dev_channels(struct ad7280_state *st, int dev, int *cnt, + bool irq_present) +{ + int addr, ch, i; + struct iio_chan_spec *chan; + + for (ch = AD7280A_CELL_VOLTAGE_1_REG; ch <= AD7280A_AUX_ADC_6_REG; ch++) { + chan = &st->channels[*cnt]; + + if (ch < AD7280A_AUX_ADC_1_REG) { + i = AD7280A_CALC_VOLTAGE_CHAN_NUM(dev, ch); + ad7280_voltage_channel_init(chan, i, irq_present); + } else { + i = AD7280A_CALC_TEMP_CHAN_NUM(dev, ch); + ad7280_temp_channel_init(chan, i, irq_present); + } + + addr = ad7280a_devaddr(dev) << 8 | ch; + ad7280_common_fields_init(chan, addr, *cnt); + + (*cnt)++; + } +} + +static int ad7280_channel_init(struct ad7280_state *st, bool irq_present) +{ + int dev, cnt = 0; + + st->channels = devm_kcalloc(&st->spi->dev, (st->slave_num + 1) * 12 + 1, + sizeof(*st->channels), GFP_KERNEL); + if (!st->channels) + return -ENOMEM; + + for (dev = 0; dev <= st->slave_num; dev++) + ad7280_init_dev_channels(st, dev, &cnt, irq_present); + + ad7280_total_voltage_channel_init(&st->channels[cnt], cnt, dev); + + return cnt + 1; +} + +static int ad7280a_read_thresh(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, int *val, int *val2) +{ + struct ad7280_state *st = iio_priv(indio_dev); + + switch (chan->type) { + case IIO_VOLTAGE: + switch (dir) { + case IIO_EV_DIR_RISING: + *val = 1000 + (st->cell_threshhigh * 1568L) / 100; + return IIO_VAL_INT; + case IIO_EV_DIR_FALLING: + *val = 1000 + (st->cell_threshlow * 1568L) / 100; + return IIO_VAL_INT; + default: + return -EINVAL; + } + break; + case IIO_TEMP: + switch (dir) { + case IIO_EV_DIR_RISING: + *val = ((st->aux_threshhigh) * 196L) / 10; + return IIO_VAL_INT; + case IIO_EV_DIR_FALLING: + *val = (st->aux_threshlow * 196L) / 10; + return IIO_VAL_INT; + default: + return -EINVAL; + } + break; + default: + return -EINVAL; + } +} + +static int ad7280a_write_thresh(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, + int val, int val2) +{ + struct ad7280_state *st = iio_priv(indio_dev); + unsigned int addr; + long value; + int ret; + + if (val2 != 0) + return -EINVAL; + + mutex_lock(&st->lock); + switch (chan->type) { + case IIO_VOLTAGE: + value = ((val - 1000) * 100) / 1568; /* LSB 15.68mV */ + value = clamp(value, 0L, 0xFFL); + switch (dir) { + case IIO_EV_DIR_RISING: + addr = AD7280A_CELL_OVERVOLTAGE_REG; + ret = ad7280_write(st, AD7280A_DEVADDR_MASTER, addr, + 1, val); + if (ret) + break; + st->cell_threshhigh = value; + break; + case IIO_EV_DIR_FALLING: + addr = AD7280A_CELL_UNDERVOLTAGE_REG; + ret = ad7280_write(st, AD7280A_DEVADDR_MASTER, addr, + 1, val); + if (ret) + break; + st->cell_threshlow = value; + break; + default: + ret = -EINVAL; + goto err_unlock; + } + break; + case IIO_TEMP: + value = (val * 10) / 196; /* LSB 19.6mV */ + value = clamp(value, 0L, 0xFFL); + switch (dir) { + case IIO_EV_DIR_RISING: + addr = AD7280A_AUX_ADC_OVERVOLTAGE_REG; + ret = ad7280_write(st, AD7280A_DEVADDR_MASTER, addr, + 1, val); + if (ret) + break; + st->aux_threshhigh = val; + break; + case IIO_EV_DIR_FALLING: + addr = AD7280A_AUX_ADC_UNDERVOLTAGE_REG; + ret = ad7280_write(st, AD7280A_DEVADDR_MASTER, addr, + 1, val); + if (ret) + break; + st->aux_threshlow = val; + break; + default: + ret = -EINVAL; + goto err_unlock; + } + break; + default: + ret = -EINVAL; + goto err_unlock; + } + +err_unlock: + mutex_unlock(&st->lock); + + return ret; +} + +static irqreturn_t ad7280_event_handler(int irq, void *private) +{ + struct iio_dev *indio_dev = private; + struct ad7280_state *st = iio_priv(indio_dev); + unsigned int *channels; + int i, ret; + + channels = kcalloc(st->scan_cnt, sizeof(*channels), GFP_KERNEL); + if (!channels) + return IRQ_HANDLED; + + ret = ad7280_read_all_channels(st, st->scan_cnt, channels); + if (ret < 0) + goto out; + + for (i = 0; i < st->scan_cnt; i++) { + unsigned int val; + + val = FIELD_GET(AD7280A_TRANS_READ_CONV_DATA_MSK, channels[i]); + if (FIELD_GET(AD7280A_TRANS_READ_CONV_CHANADDR_MSK, channels[i]) <= + AD7280A_CELL_VOLTAGE_6_REG) { + if (val >= st->cell_threshhigh) { + u64 tmp = IIO_EVENT_CODE(IIO_VOLTAGE, 1, 0, + IIO_EV_DIR_RISING, + IIO_EV_TYPE_THRESH, + 0, 0, 0); + iio_push_event(indio_dev, tmp, + iio_get_time_ns(indio_dev)); + } else if (val <= st->cell_threshlow) { + u64 tmp = IIO_EVENT_CODE(IIO_VOLTAGE, 1, 0, + IIO_EV_DIR_FALLING, + IIO_EV_TYPE_THRESH, + 0, 0, 0); + iio_push_event(indio_dev, tmp, + iio_get_time_ns(indio_dev)); + } + } else { + if (val >= st->aux_threshhigh) { + u64 tmp = IIO_UNMOD_EVENT_CODE(IIO_TEMP, 0, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_RISING); + iio_push_event(indio_dev, tmp, + iio_get_time_ns(indio_dev)); + } else if (val <= st->aux_threshlow) { + u64 tmp = IIO_UNMOD_EVENT_CODE(IIO_TEMP, 0, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_FALLING); + iio_push_event(indio_dev, tmp, + iio_get_time_ns(indio_dev)); + } + } + } + +out: + kfree(channels); + + return IRQ_HANDLED; +} + +static void ad7280_update_delay(struct ad7280_state *st) +{ + /* + * Total Conversion Time = ((tACQ + tCONV) * + * (Number of Conversions per Part)) − + * tACQ + ((N - 1) * tDELAY) + * + * Readback Delay = Total Conversion Time + tWAIT + */ + + st->readback_delay_us = + ((ad7280a_t_acq_ns[st->acquisition_time & 0x3] + 720) * + (AD7280A_NUM_CH * ad7280a_n_avg[st->oversampling_ratio & 0x3])) - + ad7280a_t_acq_ns[st->acquisition_time & 0x3] + st->slave_num * 250; + + /* Convert to usecs */ + st->readback_delay_us = DIV_ROUND_UP(st->readback_delay_us, 1000); + st->readback_delay_us += 5; /* Add tWAIT */ +} + +static int ad7280_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, + int *val2, + long m) +{ + struct ad7280_state *st = iio_priv(indio_dev); + int ret; + + switch (m) { + case IIO_CHAN_INFO_RAW: + mutex_lock(&st->lock); + if (chan->address == AD7280A_ALL_CELLS) + ret = ad7280_read_all_channels(st, st->scan_cnt, NULL); + else + ret = ad7280_read_channel(st, chan->address >> 8, + chan->address & 0xFF); + mutex_unlock(&st->lock); + + if (ret < 0) + return ret; + + *val = ret; + + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + if ((chan->address & 0xFF) <= AD7280A_CELL_VOLTAGE_6_REG) + *val = 4000; + else + *val = 5000; + + *val2 = AD7280A_BITS; + return IIO_VAL_FRACTIONAL_LOG2; + case IIO_CHAN_INFO_OVERSAMPLING_RATIO: + *val = ad7280a_n_avg[st->oversampling_ratio]; + return IIO_VAL_INT; + } + return -EINVAL; +} + +static int ad7280_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + struct ad7280_state *st = iio_priv(indio_dev); + int i; + + switch (mask) { + case IIO_CHAN_INFO_OVERSAMPLING_RATIO: + if (val2 != 0) + return -EINVAL; + for (i = 0; i < ARRAY_SIZE(ad7280a_n_avg); i++) { + if (val == ad7280a_n_avg[i]) { + st->oversampling_ratio = i; + ad7280_update_delay(st); + return 0; + } + } + return -EINVAL; + default: + return -EINVAL; + } +} + +static const struct iio_info ad7280_info = { + .read_raw = ad7280_read_raw, + .write_raw = ad7280_write_raw, + .read_event_value = &ad7280a_read_thresh, + .write_event_value = &ad7280a_write_thresh, +}; + +static const struct iio_info ad7280_info_no_irq = { + .read_raw = ad7280_read_raw, + .write_raw = ad7280_write_raw, +}; + +static int ad7280_probe(struct spi_device *spi) +{ + struct device *dev = &spi->dev; + struct ad7280_state *st; + int ret; + struct iio_dev *indio_dev; + + indio_dev = devm_iio_device_alloc(dev, sizeof(*st)); + if (!indio_dev) + return -ENOMEM; + + st = iio_priv(indio_dev); + spi_set_drvdata(spi, indio_dev); + st->spi = spi; + mutex_init(&st->lock); + + st->thermistor_term_en = + device_property_read_bool(dev, "adi,thermistor-termination"); + + if (device_property_present(dev, "adi,acquisition-time-ns")) { + u32 val; + + ret = device_property_read_u32(dev, "adi,acquisition-time-ns", &val); + if (ret) + return ret; + + switch (val) { + case 400: + st->acquisition_time = AD7280A_CTRL_LB_ACQ_TIME_400ns; + break; + case 800: + st->acquisition_time = AD7280A_CTRL_LB_ACQ_TIME_800ns; + break; + case 1200: + st->acquisition_time = AD7280A_CTRL_LB_ACQ_TIME_1200ns; + break; + case 1600: + st->acquisition_time = AD7280A_CTRL_LB_ACQ_TIME_1600ns; + break; + default: + dev_err(dev, "Firmware provided acquisition time is invalid\n"); + return -EINVAL; + } + } else { + st->acquisition_time = AD7280A_CTRL_LB_ACQ_TIME_400ns; + } + + /* Alert masks are intended for when particular inputs are not wired up */ + if (device_property_present(dev, "adi,voltage-alert-last-chan")) { + u32 val; + + ret = device_property_read_u32(dev, "adi,voltage-alert-last-chan", &val); + if (ret) + return ret; + + switch (val) { + case 3: + st->chain_last_alert_ignore |= AD7280A_ALERT_REMOVE_VIN4_VIN5; + break; + case 4: + st->chain_last_alert_ignore |= AD7280A_ALERT_REMOVE_VIN5; + break; + case 5: + break; + default: + dev_err(dev, + "Firmware provided last voltage alert channel invalid\n"); + break; + } + } + crc8_populate_msb(st->crc_tab, POLYNOM); + + st->spi->max_speed_hz = AD7280A_MAX_SPI_CLK_HZ; + st->spi->mode = SPI_MODE_1; + spi_setup(st->spi); + + st->ctrl_lb = FIELD_PREP(AD7280A_CTRL_LB_ACQ_TIME_MSK, st->acquisition_time) | + FIELD_PREP(AD7280A_CTRL_LB_THERMISTOR_MSK, st->thermistor_term_en); + st->oversampling_ratio = 0; /* No oversampling */ + + ret = ad7280_chain_setup(st); + if (ret < 0) + return ret; + + st->slave_num = ret; + st->scan_cnt = (st->slave_num + 1) * AD7280A_NUM_CH; + st->cell_threshhigh = 0xFF; + st->aux_threshhigh = 0xFF; + + ret = devm_add_action_or_reset(dev, ad7280_sw_power_down, st); + if (ret) + return ret; + + ad7280_update_delay(st); + + indio_dev->name = spi_get_device_id(spi)->name; + indio_dev->modes = INDIO_DIRECT_MODE; + + ret = ad7280_channel_init(st, spi->irq > 0); + if (ret < 0) + return ret; + + indio_dev->num_channels = ret; + indio_dev->channels = st->channels; + if (spi->irq > 0) { + ret = ad7280_write(st, AD7280A_DEVADDR_MASTER, + AD7280A_ALERT_REG, 1, + AD7280A_ALERT_RELAY_SIG_CHAIN_DOWN); + if (ret) + return ret; + + ret = ad7280_write(st, ad7280a_devaddr(st->slave_num), + AD7280A_ALERT_REG, 0, + AD7280A_ALERT_GEN_STATIC_HIGH | + FIELD_PREP(AD7280A_ALERT_REMOVE_MSK, + st->chain_last_alert_ignore)); + if (ret) + return ret; + + ret = devm_request_threaded_irq(dev, spi->irq, + NULL, + ad7280_event_handler, + IRQF_TRIGGER_FALLING | + IRQF_ONESHOT, + indio_dev->name, + indio_dev); + if (ret) + return ret; + + indio_dev->info = &ad7280_info; + } else { + indio_dev->info = &ad7280_info_no_irq; + } + + return devm_iio_device_register(dev, indio_dev); +} + +static const struct spi_device_id ad7280_id[] = { + {"ad7280a", 0}, + {} +}; +MODULE_DEVICE_TABLE(spi, ad7280_id); + +static struct spi_driver ad7280_driver = { + .driver = { + .name = "ad7280", + }, + .probe = ad7280_probe, + .id_table = ad7280_id, +}; +module_spi_driver(ad7280_driver); + +MODULE_AUTHOR("Michael Hennerich "); +MODULE_DESCRIPTION("Analog Devices AD7280A"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/iio/adc/Kconfig b/drivers/staging/iio/adc/Kconfig index b25f41053fac..2f0d6cf048d2 100644 --- a/drivers/staging/iio/adc/Kconfig +++ b/drivers/staging/iio/adc/Kconfig @@ -15,15 +15,4 @@ config AD7816 To compile this driver as a module, choose M here: the module will be called ad7816. -config AD7280 - tristate "Analog Devices AD7280A Lithium Ion Battery Monitoring System" - depends on SPI - select CRC8 - help - Say yes here to build support for Analog Devices AD7280A - Lithium Ion Battery Monitoring System. - - To compile this driver as a module, choose M here: the - module will be called ad7280a - endmenu diff --git a/drivers/staging/iio/adc/Makefile b/drivers/staging/iio/adc/Makefile index 6436a62b6278..1e2a94c4db84 100644 --- a/drivers/staging/iio/adc/Makefile +++ b/drivers/staging/iio/adc/Makefile @@ -4,4 +4,3 @@ # obj-$(CONFIG_AD7816) += ad7816.o -obj-$(CONFIG_AD7280) += ad7280a.o diff --git a/drivers/staging/iio/adc/ad7280a.c b/drivers/staging/iio/adc/ad7280a.c deleted file mode 100644 index ef9d27759961..000000000000 --- a/drivers/staging/iio/adc/ad7280a.c +++ /dev/null @@ -1,1111 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * AD7280A Lithium Ion Battery Monitoring System - * - * Copyright 2011 Analog Devices Inc. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -/* Registers */ - -#define AD7280A_CELL_VOLTAGE_1_REG 0x0 /* D11 to D0, Read only */ -#define AD7280A_CELL_VOLTAGE_2_REG 0x1 /* D11 to D0, Read only */ -#define AD7280A_CELL_VOLTAGE_3_REG 0x2 /* D11 to D0, Read only */ -#define AD7280A_CELL_VOLTAGE_4_REG 0x3 /* D11 to D0, Read only */ -#define AD7280A_CELL_VOLTAGE_5_REG 0x4 /* D11 to D0, Read only */ -#define AD7280A_CELL_VOLTAGE_6_REG 0x5 /* D11 to D0, Read only */ -#define AD7280A_AUX_ADC_1_REG 0x6 /* D11 to D0, Read only */ -#define AD7280A_AUX_ADC_2_REG 0x7 /* D11 to D0, Read only */ -#define AD7280A_AUX_ADC_3_REG 0x8 /* D11 to D0, Read only */ -#define AD7280A_AUX_ADC_4_REG 0x9 /* D11 to D0, Read only */ -#define AD7280A_AUX_ADC_5_REG 0xA /* D11 to D0, Read only */ -#define AD7280A_AUX_ADC_6_REG 0xB /* D11 to D0, Read only */ -#define AD7280A_SELF_TEST_REG 0xC /* D11 to D0, Read only */ - -#define AD7280A_CTRL_HB_REG 0xD /* D15 to D8, Read/write */ -#define AD7280A_CTRL_HB_CONV_INPUT_MSK GENMASK(7, 6) -#define AD7280A_CTRL_HB_CONV_INPUT_ALL 0 -#define AD7280A_CTRL_HB_CONV_INPUT_6CELL_AUX1_3_5 1 -#define AD7280A_CTRL_HB_CONV_INPUT_6CELL 2 -#define AD7280A_CTRL_HB_CONV_INPUT_SELF_TEST 3 -#define AD7280A_CTRL_HB_CONV_RREAD_MSK GENMASK(5, 4) -#define AD7280A_CTRL_HB_CONV_RREAD_ALL 0 -#define AD7280A_CTRL_HB_CONV_RREAD_6CELL_AUX1_3_5 1 -#define AD7280A_CTRL_HB_CONV_RREAD_6CELL 2 -#define AD7280A_CTRL_HB_CONV_RREAD_NO 3 -#define AD7280A_CTRL_HB_CONV_START_MSK BIT(3) -#define AD7280A_CTRL_HB_CONV_START_CNVST 0 -#define AD7280A_CTRL_HB_CONV_START_CS 1 -#define AD7280A_CTRL_HB_CONV_AVG_MSK GENMASK(2, 1) -#define AD7280A_CTRL_HB_CONV_AVG_DIS 0 -#define AD7280A_CTRL_HB_CONV_AVG_2 1 -#define AD7280A_CTRL_HB_CONV_AVG_4 2 -#define AD7280A_CTRL_HB_CONV_AVG_8 3 -#define AD7280A_CTRL_HB_PWRDN_SW BIT(0) - -#define AD7280A_CTRL_LB_REG 0xE /* D7 to D0, Read/write */ -#define AD7280A_CTRL_LB_SWRST_MSK BIT(7) -#define AD7280A_CTRL_LB_ACQ_TIME_MSK GENMASK(6, 5) -#define AD7280A_CTRL_LB_ACQ_TIME_400ns 0 -#define AD7280A_CTRL_LB_ACQ_TIME_800ns 1 -#define AD7280A_CTRL_LB_ACQ_TIME_1200ns 2 -#define AD7280A_CTRL_LB_ACQ_TIME_1600ns 3 -#define AD7280A_CTRL_LB_MUST_SET BIT(4) -#define AD7280A_CTRL_LB_THERMISTOR_MSK BIT(3) -#define AD7280A_CTRL_LB_LOCK_DEV_ADDR_MSK BIT(2) -#define AD7280A_CTRL_LB_INC_DEV_ADDR_MSK BIT(1) -#define AD7280A_CTRL_LB_DAISY_CHAIN_RB_MSK BIT(0) - -#define AD7280A_CELL_OVERVOLTAGE_REG 0xF /* D7 to D0, Read/write */ -#define AD7280A_CELL_UNDERVOLTAGE_REG 0x10 /* D7 to D0, Read/write */ -#define AD7280A_AUX_ADC_OVERVOLTAGE_REG 0x11 /* D7 to D0, Read/write */ -#define AD7280A_AUX_ADC_UNDERVOLTAGE_REG 0x12 /* D7 to D0, Read/write */ - -#define AD7280A_ALERT_REG 0x13 /* D7 to D0, Read/write */ -#define AD7280A_ALERT_REMOVE_MSK GENMASK(3, 0) -#define AD7280A_ALERT_REMOVE_AUX5 BIT(0) -#define AD7280A_ALERT_REMOVE_AUX3_AUX5 BIT(1) -#define AD7280A_ALERT_REMOVE_VIN5 BIT(2) -#define AD7280A_ALERT_REMOVE_VIN4_VIN5 BIT(3) -#define AD7280A_ALERT_GEN_STATIC_HIGH BIT(6) -#define AD7280A_ALERT_RELAY_SIG_CHAIN_DOWN (BIT(7) | BIT(6)) - -#define AD7280A_CELL_BALANCE_REG 0x14 /* D7 to D0, Read/write */ -#define AD7280A_CELL_BALANCE_CHAN_BITMAP_MSK GENMASK(7, 2) -#define AD7280A_CB1_TIMER_REG 0x15 /* D7 to D0, Read/write */ -#define AD7280A_CB_TIMER_VAL_MSK GENMASK(7, 3) -#define AD7280A_CB2_TIMER_REG 0x16 /* D7 to D0, Read/write */ -#define AD7280A_CB3_TIMER_REG 0x17 /* D7 to D0, Read/write */ -#define AD7280A_CB4_TIMER_REG 0x18 /* D7 to D0, Read/write */ -#define AD7280A_CB5_TIMER_REG 0x19 /* D7 to D0, Read/write */ -#define AD7280A_CB6_TIMER_REG 0x1A /* D7 to D0, Read/write */ -#define AD7280A_PD_TIMER_REG 0x1B /* D7 to D0, Read/write */ -#define AD7280A_READ_REG 0x1C /* D7 to D0, Read/write */ -#define AD7280A_READ_ADDR_MSK GENMASK(7, 2) -#define AD7280A_CNVST_CTRL_REG 0x1D /* D7 to D0, Read/write */ - -/* Transfer fields */ -#define AD7280A_TRANS_WRITE_DEVADDR_MSK GENMASK(31, 27) -#define AD7280A_TRANS_WRITE_ADDR_MSK GENMASK(26, 21) -#define AD7280A_TRANS_WRITE_VAL_MSK GENMASK(20, 13) -#define AD7280A_TRANS_WRITE_ALL_MSK BIT(12) -#define AD7280A_TRANS_WRITE_CRC_MSK GENMASK(10, 3) -#define AD7280A_TRANS_WRITE_RES_PATTERN 0x2 - -/* Layouts differ for channel vs other registers */ -#define AD7280A_TRANS_READ_DEVADDR_MSK GENMASK(31, 27) -#define AD7280A_TRANS_READ_CONV_CHANADDR_MSK GENMASK(26, 23) -#define AD7280A_TRANS_READ_CONV_DATA_MSK GENMASK(22, 11) -#define AD7280A_TRANS_READ_REG_REGADDR_MSK GENMASK(26, 21) -#define AD7280A_TRANS_READ_REG_DATA_MSK GENMASK(20, 13) -#define AD7280A_TRANS_READ_WRITE_ACK_MSK BIT(10) -#define AD7280A_TRANS_READ_CRC_MSK GENMASK(9, 2) - -/* Magic value used to indicate this special case */ -#define AD7280A_ALL_CELLS (0xAD << 16) - -#define AD7280A_MAX_SPI_CLK_HZ 700000 /* < 1MHz */ -#define AD7280A_MAX_CHAIN 8 -#define AD7280A_CELLS_PER_DEV 6 -#define AD7280A_BITS 12 -#define AD7280A_NUM_CH (AD7280A_AUX_ADC_6_REG - \ - AD7280A_CELL_VOLTAGE_1_REG + 1) - -#define AD7280A_CALC_VOLTAGE_CHAN_NUM(d, c) (((d) * AD7280A_CELLS_PER_DEV) + \ - (c)) -#define AD7280A_CALC_TEMP_CHAN_NUM(d, c) (((d) * AD7280A_CELLS_PER_DEV) + \ - (c) - AD7280A_CELLS_PER_DEV) - -#define AD7280A_DEVADDR_MASTER 0 -#define AD7280A_DEVADDR_ALL 0x1F - -static const unsigned short ad7280a_n_avg[4] = {1, 2, 4, 8}; -static const unsigned short ad7280a_t_acq_ns[4] = {470, 1030, 1510, 1945}; - -/* 5-bit device address is sent LSB first */ -static unsigned int ad7280a_devaddr(unsigned int addr) -{ - return ((addr & 0x1) << 4) | - ((addr & 0x2) << 2) | - (addr & 0x4) | - ((addr & 0x8) >> 2) | - ((addr & 0x10) >> 4); -} - -/* - * During a read a valid write is mandatory. - * So writing to the highest available address (Address 0x1F) and setting the - * address all parts bit to 0 is recommended. - * So the TXVAL is AD7280A_DEVADDR_ALL + CRC - */ -#define AD7280A_READ_TXVAL 0xF800030A - -/* - * AD7280 CRC - * - * P(x) = x^8 + x^5 + x^3 + x^2 + x^1 + x^0 = 0b100101111 => 0x2F - */ -#define POLYNOM 0x2F - -struct ad7280_state { - struct spi_device *spi; - struct iio_chan_spec *channels; - unsigned int chain_last_alert_ignore; - bool thermistor_term_en; - int slave_num; - int scan_cnt; - int readback_delay_us; - unsigned char crc_tab[CRC8_TABLE_SIZE]; - u8 oversampling_ratio; - u8 acquisition_time; - unsigned char ctrl_lb; - unsigned char cell_threshhigh; - unsigned char cell_threshlow; - unsigned char aux_threshhigh; - unsigned char aux_threshlow; - unsigned char cb_mask[AD7280A_MAX_CHAIN]; - struct mutex lock; /* protect sensor state */ - - __be32 tx ____cacheline_aligned; - __be32 rx; -}; - -static unsigned char ad7280_calc_crc8(unsigned char *crc_tab, unsigned int val) -{ - unsigned char crc; - - crc = crc_tab[val >> 16 & 0xFF]; - crc = crc_tab[crc ^ (val >> 8 & 0xFF)]; - - return crc ^ (val & 0xFF); -} - -static int ad7280_check_crc(struct ad7280_state *st, unsigned int val) -{ - unsigned char crc = ad7280_calc_crc8(st->crc_tab, val >> 10); - - if (crc != ((val >> 2) & 0xFF)) - return -EIO; - - return 0; -} - -/* - * After initiating a conversion sequence we need to wait until the conversion - * is done. The delay is typically in the range of 15..30us however depending on - * the number of devices in the daisy chain, the number of averages taken, - * conversion delays and acquisition time options it may take up to 250us, in - * this case we better sleep instead of busy wait. - */ - -static void ad7280_delay(struct ad7280_state *st) -{ - if (st->readback_delay_us < 50) - udelay(st->readback_delay_us); - else - usleep_range(250, 500); -} - -static int __ad7280_read32(struct ad7280_state *st, unsigned int *val) -{ - int ret; - struct spi_transfer t = { - .tx_buf = &st->tx, - .rx_buf = &st->rx, - .len = sizeof(st->tx), - }; - - st->tx = cpu_to_be32(AD7280A_READ_TXVAL); - - ret = spi_sync_transfer(st->spi, &t, 1); - if (ret) - return ret; - - *val = be32_to_cpu(st->rx); - - return 0; -} - -static int ad7280_write(struct ad7280_state *st, unsigned int devaddr, - unsigned int addr, bool all, unsigned int val) -{ - unsigned int reg = FIELD_PREP(AD7280A_TRANS_WRITE_DEVADDR_MSK, devaddr) | - FIELD_PREP(AD7280A_TRANS_WRITE_ADDR_MSK, addr) | - FIELD_PREP(AD7280A_TRANS_WRITE_VAL_MSK, val) | - FIELD_PREP(AD7280A_TRANS_WRITE_ALL_MSK, all); - - reg |= FIELD_PREP(AD7280A_TRANS_WRITE_CRC_MSK, - ad7280_calc_crc8(st->crc_tab, reg >> 11)); - /* Reserved b010 pattern not included crc calc */ - reg |= AD7280A_TRANS_WRITE_RES_PATTERN; - - st->tx = cpu_to_be32(reg); - - return spi_write(st->spi, &st->tx, sizeof(st->tx)); -} - -static int ad7280_read_reg(struct ad7280_state *st, unsigned int devaddr, - unsigned int addr) -{ - int ret; - unsigned int tmp; - - /* turns off the read operation on all parts */ - ret = ad7280_write(st, AD7280A_DEVADDR_MASTER, AD7280A_CTRL_HB_REG, 1, - FIELD_PREP(AD7280A_CTRL_HB_CONV_INPUT_MSK, - AD7280A_CTRL_HB_CONV_INPUT_ALL) | - FIELD_PREP(AD7280A_CTRL_HB_CONV_RREAD_MSK, - AD7280A_CTRL_HB_CONV_RREAD_NO) | - FIELD_PREP(AD7280A_CTRL_HB_CONV_AVG_MSK, - st->oversampling_ratio)); - if (ret) - return ret; - - /* turns on the read operation on the addressed part */ - ret = ad7280_write(st, devaddr, AD7280A_CTRL_HB_REG, 0, - FIELD_PREP(AD7280A_CTRL_HB_CONV_INPUT_MSK, - AD7280A_CTRL_HB_CONV_INPUT_ALL) | - FIELD_PREP(AD7280A_CTRL_HB_CONV_RREAD_MSK, - AD7280A_CTRL_HB_CONV_RREAD_ALL) | - FIELD_PREP(AD7280A_CTRL_HB_CONV_AVG_MSK, - st->oversampling_ratio)); - if (ret) - return ret; - - /* Set register address on the part to be read from */ - ret = ad7280_write(st, devaddr, AD7280A_READ_REG, 0, - FIELD_PREP(AD7280A_READ_ADDR_MSK, addr)); - if (ret) - return ret; - - ret = __ad7280_read32(st, &tmp); - if (ret) - return ret; - - if (ad7280_check_crc(st, tmp)) - return -EIO; - - if ((FIELD_GET(AD7280A_TRANS_READ_DEVADDR_MSK, tmp) != devaddr) || - (FIELD_GET(AD7280A_TRANS_READ_REG_REGADDR_MSK, tmp) != addr)) - return -EFAULT; - - return FIELD_GET(AD7280A_TRANS_READ_REG_DATA_MSK, tmp); -} - -static int ad7280_read_channel(struct ad7280_state *st, unsigned int devaddr, - unsigned int addr) -{ - int ret; - unsigned int tmp; - - ret = ad7280_write(st, devaddr, AD7280A_READ_REG, 0, - FIELD_PREP(AD7280A_READ_ADDR_MSK, addr)); - if (ret) - return ret; - - ret = ad7280_write(st, AD7280A_DEVADDR_MASTER, AD7280A_CTRL_HB_REG, 1, - FIELD_PREP(AD7280A_CTRL_HB_CONV_INPUT_MSK, - AD7280A_CTRL_HB_CONV_INPUT_ALL) | - FIELD_PREP(AD7280A_CTRL_HB_CONV_RREAD_MSK, - AD7280A_CTRL_HB_CONV_RREAD_NO) | - FIELD_PREP(AD7280A_CTRL_HB_CONV_AVG_MSK, - st->oversampling_ratio)); - if (ret) - return ret; - - ret = ad7280_write(st, devaddr, AD7280A_CTRL_HB_REG, 0, - FIELD_PREP(AD7280A_CTRL_HB_CONV_INPUT_MSK, - AD7280A_CTRL_HB_CONV_INPUT_ALL) | - FIELD_PREP(AD7280A_CTRL_HB_CONV_RREAD_MSK, - AD7280A_CTRL_HB_CONV_RREAD_ALL) | - FIELD_PREP(AD7280A_CTRL_HB_CONV_START_MSK, - AD7280A_CTRL_HB_CONV_START_CS) | - FIELD_PREP(AD7280A_CTRL_HB_CONV_AVG_MSK, - st->oversampling_ratio)); - if (ret) - return ret; - - ad7280_delay(st); - - ret = __ad7280_read32(st, &tmp); - if (ret) - return ret; - - if (ad7280_check_crc(st, tmp)) - return -EIO; - - if ((FIELD_GET(AD7280A_TRANS_READ_DEVADDR_MSK, tmp) != devaddr) || - (FIELD_GET(AD7280A_TRANS_READ_CONV_CHANADDR_MSK, tmp) != addr)) - return -EFAULT; - - return FIELD_GET(AD7280A_TRANS_READ_CONV_DATA_MSK, tmp); -} - -static int ad7280_read_all_channels(struct ad7280_state *st, unsigned int cnt, - unsigned int *array) -{ - int i, ret; - unsigned int tmp, sum = 0; - - ret = ad7280_write(st, AD7280A_DEVADDR_MASTER, AD7280A_READ_REG, 1, - AD7280A_CELL_VOLTAGE_1_REG << 2); - if (ret) - return ret; - - ret = ad7280_write(st, AD7280A_DEVADDR_MASTER, AD7280A_CTRL_HB_REG, 1, - FIELD_PREP(AD7280A_CTRL_HB_CONV_INPUT_MSK, - AD7280A_CTRL_HB_CONV_INPUT_ALL) | - FIELD_PREP(AD7280A_CTRL_HB_CONV_RREAD_MSK, - AD7280A_CTRL_HB_CONV_RREAD_ALL) | - FIELD_PREP(AD7280A_CTRL_HB_CONV_START_MSK, - AD7280A_CTRL_HB_CONV_START_CS) | - FIELD_PREP(AD7280A_CTRL_HB_CONV_AVG_MSK, - st->oversampling_ratio)); - if (ret) - return ret; - - ad7280_delay(st); - - for (i = 0; i < cnt; i++) { - ret = __ad7280_read32(st, &tmp); - if (ret) - return ret; - - if (ad7280_check_crc(st, tmp)) - return -EIO; - - if (array) - array[i] = tmp; - /* only sum cell voltages */ - if (FIELD_GET(AD7280A_TRANS_READ_CONV_CHANADDR_MSK, tmp) <= - AD7280A_CELL_VOLTAGE_6_REG) - sum += FIELD_GET(AD7280A_TRANS_READ_CONV_DATA_MSK, tmp); - } - - return sum; -} - -static void ad7280_sw_power_down(void *data) -{ - struct ad7280_state *st = data; - - ad7280_write(st, AD7280A_DEVADDR_MASTER, AD7280A_CTRL_HB_REG, 1, - AD7280A_CTRL_HB_PWRDN_SW | - FIELD_PREP(AD7280A_CTRL_HB_CONV_AVG_MSK, st->oversampling_ratio)); -} - -static int ad7280_chain_setup(struct ad7280_state *st) -{ - unsigned int val, n; - int ret; - - ret = ad7280_write(st, AD7280A_DEVADDR_MASTER, AD7280A_CTRL_LB_REG, 1, - FIELD_PREP(AD7280A_CTRL_LB_DAISY_CHAIN_RB_MSK, 1) | - FIELD_PREP(AD7280A_CTRL_LB_LOCK_DEV_ADDR_MSK, 1) | - AD7280A_CTRL_LB_MUST_SET | - FIELD_PREP(AD7280A_CTRL_LB_SWRST_MSK, 1) | - st->ctrl_lb); - if (ret) - return ret; - - ret = ad7280_write(st, AD7280A_DEVADDR_MASTER, AD7280A_CTRL_LB_REG, 1, - FIELD_PREP(AD7280A_CTRL_LB_DAISY_CHAIN_RB_MSK, 1) | - FIELD_PREP(AD7280A_CTRL_LB_LOCK_DEV_ADDR_MSK, 1) | - AD7280A_CTRL_LB_MUST_SET | - FIELD_PREP(AD7280A_CTRL_LB_SWRST_MSK, 0) | - st->ctrl_lb); - if (ret) - goto error_power_down; - - ret = ad7280_write(st, AD7280A_DEVADDR_MASTER, AD7280A_READ_REG, 1, - FIELD_PREP(AD7280A_READ_ADDR_MSK, AD7280A_CTRL_LB_REG)); - if (ret) - goto error_power_down; - - for (n = 0; n <= AD7280A_MAX_CHAIN; n++) { - ret = __ad7280_read32(st, &val); - if (ret) - goto error_power_down; - - if (val == 0) - return n - 1; - - if (ad7280_check_crc(st, val)) { - ret = -EIO; - goto error_power_down; - } - - if (n != ad7280a_devaddr(FIELD_GET(AD7280A_TRANS_READ_DEVADDR_MSK, val))) { - ret = -EIO; - goto error_power_down; - } - } - ret = -EFAULT; - -error_power_down: - ad7280_write(st, AD7280A_DEVADDR_MASTER, AD7280A_CTRL_HB_REG, 1, - AD7280A_CTRL_HB_PWRDN_SW | - FIELD_PREP(AD7280A_CTRL_HB_CONV_AVG_MSK, st->oversampling_ratio)); - - return ret; -} - -static ssize_t ad7280_show_balance_sw(struct iio_dev *indio_dev, - uintptr_t private, - const struct iio_chan_spec *chan, char *buf) -{ - struct ad7280_state *st = iio_priv(indio_dev); - - return sysfs_emit(buf, "%d\n", - !!(st->cb_mask[chan->address >> 8] & - BIT(chan->address & 0xFF))); -} - -static ssize_t ad7280_store_balance_sw(struct iio_dev *indio_dev, - uintptr_t private, - const struct iio_chan_spec *chan, - const char *buf, size_t len) -{ - struct ad7280_state *st = iio_priv(indio_dev); - unsigned int devaddr, ch; - bool readin; - int ret; - - ret = strtobool(buf, &readin); - if (ret) - return ret; - - devaddr = chan->address >> 8; - ch = chan->address & 0xFF; - - mutex_lock(&st->lock); - if (readin) - st->cb_mask[devaddr] |= BIT(ch); - else - st->cb_mask[devaddr] &= ~BIT(ch); - - ret = ad7280_write(st, devaddr, AD7280A_CELL_BALANCE_REG, 0, - FIELD_PREP(AD7280A_CELL_BALANCE_CHAN_BITMAP_MSK, - st->cb_mask[devaddr])); - mutex_unlock(&st->lock); - - return ret ? ret : len; -} - -static ssize_t ad7280_show_balance_timer(struct iio_dev *indio_dev, - uintptr_t private, - const struct iio_chan_spec *chan, - char *buf) -{ - struct ad7280_state *st = iio_priv(indio_dev); - unsigned int msecs; - int ret; - - mutex_lock(&st->lock); - ret = ad7280_read_reg(st, chan->address >> 8, - (chan->address & 0xFF) + AD7280A_CB1_TIMER_REG); - mutex_unlock(&st->lock); - - if (ret < 0) - return ret; - - msecs = FIELD_GET(AD7280A_CB_TIMER_VAL_MSK, ret) * 71500; - - return sysfs_emit(buf, "%u.%u\n", msecs / 1000, msecs % 1000); -} - -static ssize_t ad7280_store_balance_timer(struct iio_dev *indio_dev, - uintptr_t private, - const struct iio_chan_spec *chan, - const char *buf, size_t len) -{ - struct ad7280_state *st = iio_priv(indio_dev); - int val, val2; - int ret; - - ret = iio_str_to_fixpoint(buf, 1000, &val, &val2); - if (ret) - return ret; - - val = val * 1000 + val2; - val /= 71500; - - if (val > 31) - return -EINVAL; - - mutex_lock(&st->lock); - ret = ad7280_write(st, chan->address >> 8, - (chan->address & 0xFF) + AD7280A_CB1_TIMER_REG, 0, - FIELD_PREP(AD7280A_CB_TIMER_VAL_MSK, val)); - mutex_unlock(&st->lock); - - return ret ? ret : len; -} - -static const struct iio_chan_spec_ext_info ad7280_cell_ext_info[] = { - { - .name = "balance_switch_en", - .read = ad7280_show_balance_sw, - .write = ad7280_store_balance_sw, - .shared = IIO_SEPARATE, - }, { - .name = "balance_switch_timer", - .read = ad7280_show_balance_timer, - .write = ad7280_store_balance_timer, - .shared = IIO_SEPARATE, - }, - {} -}; - -static const struct iio_event_spec ad7280_events[] = { - { - .type = IIO_EV_TYPE_THRESH, - .dir = IIO_EV_DIR_RISING, - .mask_shared_by_type = BIT(IIO_EV_INFO_VALUE), - }, { - .type = IIO_EV_TYPE_THRESH, - .dir = IIO_EV_DIR_FALLING, - .mask_shared_by_type = BIT(IIO_EV_INFO_VALUE), - }, -}; - -static void ad7280_voltage_channel_init(struct iio_chan_spec *chan, int i, - bool irq_present) -{ - chan->type = IIO_VOLTAGE; - chan->differential = 1; - chan->channel = i; - chan->channel2 = chan->channel + 1; - if (irq_present) { - chan->event_spec = ad7280_events; - chan->num_event_specs = ARRAY_SIZE(ad7280_events); - } - chan->ext_info = ad7280_cell_ext_info; -} - -static void ad7280_temp_channel_init(struct iio_chan_spec *chan, int i, - bool irq_present) -{ - chan->type = IIO_TEMP; - chan->channel = i; - if (irq_present) { - chan->event_spec = ad7280_events; - chan->num_event_specs = ARRAY_SIZE(ad7280_events); - } -} - -static void ad7280_common_fields_init(struct iio_chan_spec *chan, int addr, - int cnt) -{ - chan->indexed = 1; - chan->info_mask_separate = BIT(IIO_CHAN_INFO_RAW); - chan->info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE); - chan->info_mask_shared_by_all = BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO); - chan->address = addr; - chan->scan_index = cnt; - chan->scan_type.sign = 'u'; - chan->scan_type.realbits = 12; - chan->scan_type.storagebits = 32; -} - -static void ad7280_total_voltage_channel_init(struct iio_chan_spec *chan, - int cnt, int dev) -{ - chan->type = IIO_VOLTAGE; - chan->differential = 1; - chan->channel = 0; - chan->channel2 = dev * AD7280A_CELLS_PER_DEV; - chan->address = AD7280A_ALL_CELLS; - chan->indexed = 1; - chan->info_mask_separate = BIT(IIO_CHAN_INFO_RAW); - chan->info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE); - chan->scan_index = cnt; - chan->scan_type.sign = 'u'; - chan->scan_type.realbits = 32; - chan->scan_type.storagebits = 32; -} - -static void ad7280_init_dev_channels(struct ad7280_state *st, int dev, int *cnt, - bool irq_present) -{ - int addr, ch, i; - struct iio_chan_spec *chan; - - for (ch = AD7280A_CELL_VOLTAGE_1_REG; ch <= AD7280A_AUX_ADC_6_REG; ch++) { - chan = &st->channels[*cnt]; - - if (ch < AD7280A_AUX_ADC_1_REG) { - i = AD7280A_CALC_VOLTAGE_CHAN_NUM(dev, ch); - ad7280_voltage_channel_init(chan, i, irq_present); - } else { - i = AD7280A_CALC_TEMP_CHAN_NUM(dev, ch); - ad7280_temp_channel_init(chan, i, irq_present); - } - - addr = ad7280a_devaddr(dev) << 8 | ch; - ad7280_common_fields_init(chan, addr, *cnt); - - (*cnt)++; - } -} - -static int ad7280_channel_init(struct ad7280_state *st, bool irq_present) -{ - int dev, cnt = 0; - - st->channels = devm_kcalloc(&st->spi->dev, (st->slave_num + 1) * 12 + 1, - sizeof(*st->channels), GFP_KERNEL); - if (!st->channels) - return -ENOMEM; - - for (dev = 0; dev <= st->slave_num; dev++) - ad7280_init_dev_channels(st, dev, &cnt, irq_present); - - ad7280_total_voltage_channel_init(&st->channels[cnt], cnt, dev); - - return cnt + 1; -} - -static int ad7280a_read_thresh(struct iio_dev *indio_dev, - const struct iio_chan_spec *chan, - enum iio_event_type type, - enum iio_event_direction dir, - enum iio_event_info info, int *val, int *val2) -{ - struct ad7280_state *st = iio_priv(indio_dev); - - switch (chan->type) { - case IIO_VOLTAGE: - switch (dir) { - case IIO_EV_DIR_RISING: - *val = 1000 + (st->cell_threshhigh * 1568L) / 100; - return IIO_VAL_INT; - case IIO_EV_DIR_FALLING: - *val = 1000 + (st->cell_threshlow * 1568L) / 100; - return IIO_VAL_INT; - default: - return -EINVAL; - } - break; - case IIO_TEMP: - switch (dir) { - case IIO_EV_DIR_RISING: - *val = ((st->aux_threshhigh) * 196L) / 10; - return IIO_VAL_INT; - case IIO_EV_DIR_FALLING: - *val = (st->aux_threshlow * 196L) / 10; - return IIO_VAL_INT; - default: - return -EINVAL; - } - break; - default: - return -EINVAL; - } -} - -static int ad7280a_write_thresh(struct iio_dev *indio_dev, - const struct iio_chan_spec *chan, - enum iio_event_type type, - enum iio_event_direction dir, - enum iio_event_info info, - int val, int val2) -{ - struct ad7280_state *st = iio_priv(indio_dev); - unsigned int addr; - long value; - int ret; - - if (val2 != 0) - return -EINVAL; - - mutex_lock(&st->lock); - switch (chan->type) { - case IIO_VOLTAGE: - value = ((val - 1000) * 100) / 1568; /* LSB 15.68mV */ - value = clamp(value, 0L, 0xFFL); - switch (dir) { - case IIO_EV_DIR_RISING: - addr = AD7280A_CELL_OVERVOLTAGE_REG; - ret = ad7280_write(st, AD7280A_DEVADDR_MASTER, addr, - 1, val); - if (ret) - break; - st->cell_threshhigh = value; - break; - case IIO_EV_DIR_FALLING: - addr = AD7280A_CELL_UNDERVOLTAGE_REG; - ret = ad7280_write(st, AD7280A_DEVADDR_MASTER, addr, - 1, val); - if (ret) - break; - st->cell_threshlow = value; - break; - default: - ret = -EINVAL; - goto err_unlock; - } - break; - case IIO_TEMP: - value = (val * 10) / 196; /* LSB 19.6mV */ - value = clamp(value, 0L, 0xFFL); - switch (dir) { - case IIO_EV_DIR_RISING: - addr = AD7280A_AUX_ADC_OVERVOLTAGE_REG; - ret = ad7280_write(st, AD7280A_DEVADDR_MASTER, addr, - 1, val); - if (ret) - break; - st->aux_threshhigh = val; - break; - case IIO_EV_DIR_FALLING: - addr = AD7280A_AUX_ADC_UNDERVOLTAGE_REG; - ret = ad7280_write(st, AD7280A_DEVADDR_MASTER, addr, - 1, val); - if (ret) - break; - st->aux_threshlow = val; - break; - default: - ret = -EINVAL; - goto err_unlock; - } - break; - default: - ret = -EINVAL; - goto err_unlock; - } - -err_unlock: - mutex_unlock(&st->lock); - - return ret; -} - -static irqreturn_t ad7280_event_handler(int irq, void *private) -{ - struct iio_dev *indio_dev = private; - struct ad7280_state *st = iio_priv(indio_dev); - unsigned int *channels; - int i, ret; - - channels = kcalloc(st->scan_cnt, sizeof(*channels), GFP_KERNEL); - if (!channels) - return IRQ_HANDLED; - - ret = ad7280_read_all_channels(st, st->scan_cnt, channels); - if (ret < 0) - goto out; - - for (i = 0; i < st->scan_cnt; i++) { - unsigned int val; - - val = FIELD_GET(AD7280A_TRANS_READ_CONV_DATA_MSK, channels[i]); - if (FIELD_GET(AD7280A_TRANS_READ_CONV_CHANADDR_MSK, channels[i]) <= - AD7280A_CELL_VOLTAGE_6_REG) { - if (val >= st->cell_threshhigh) { - u64 tmp = IIO_EVENT_CODE(IIO_VOLTAGE, 1, 0, - IIO_EV_DIR_RISING, - IIO_EV_TYPE_THRESH, - 0, 0, 0); - iio_push_event(indio_dev, tmp, - iio_get_time_ns(indio_dev)); - } else if (val <= st->cell_threshlow) { - u64 tmp = IIO_EVENT_CODE(IIO_VOLTAGE, 1, 0, - IIO_EV_DIR_FALLING, - IIO_EV_TYPE_THRESH, - 0, 0, 0); - iio_push_event(indio_dev, tmp, - iio_get_time_ns(indio_dev)); - } - } else { - if (val >= st->aux_threshhigh) { - u64 tmp = IIO_UNMOD_EVENT_CODE(IIO_TEMP, 0, - IIO_EV_TYPE_THRESH, - IIO_EV_DIR_RISING); - iio_push_event(indio_dev, tmp, - iio_get_time_ns(indio_dev)); - } else if (val <= st->aux_threshlow) { - u64 tmp = IIO_UNMOD_EVENT_CODE(IIO_TEMP, 0, - IIO_EV_TYPE_THRESH, - IIO_EV_DIR_FALLING); - iio_push_event(indio_dev, tmp, - iio_get_time_ns(indio_dev)); - } - } - } - -out: - kfree(channels); - - return IRQ_HANDLED; -} - -static void ad7280_update_delay(struct ad7280_state *st) -{ - /* - * Total Conversion Time = ((tACQ + tCONV) * - * (Number of Conversions per Part)) − - * tACQ + ((N - 1) * tDELAY) - * - * Readback Delay = Total Conversion Time + tWAIT - */ - - st->readback_delay_us = - ((ad7280a_t_acq_ns[st->acquisition_time & 0x3] + 720) * - (AD7280A_NUM_CH * ad7280a_n_avg[st->oversampling_ratio & 0x3])) - - ad7280a_t_acq_ns[st->acquisition_time & 0x3] + st->slave_num * 250; - - /* Convert to usecs */ - st->readback_delay_us = DIV_ROUND_UP(st->readback_delay_us, 1000); - st->readback_delay_us += 5; /* Add tWAIT */ -} - -static int ad7280_read_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int *val, - int *val2, - long m) -{ - struct ad7280_state *st = iio_priv(indio_dev); - int ret; - - switch (m) { - case IIO_CHAN_INFO_RAW: - mutex_lock(&st->lock); - if (chan->address == AD7280A_ALL_CELLS) - ret = ad7280_read_all_channels(st, st->scan_cnt, NULL); - else - ret = ad7280_read_channel(st, chan->address >> 8, - chan->address & 0xFF); - mutex_unlock(&st->lock); - - if (ret < 0) - return ret; - - *val = ret; - - return IIO_VAL_INT; - case IIO_CHAN_INFO_SCALE: - if ((chan->address & 0xFF) <= AD7280A_CELL_VOLTAGE_6_REG) - *val = 4000; - else - *val = 5000; - - *val2 = AD7280A_BITS; - return IIO_VAL_FRACTIONAL_LOG2; - case IIO_CHAN_INFO_OVERSAMPLING_RATIO: - *val = ad7280a_n_avg[st->oversampling_ratio]; - return IIO_VAL_INT; - } - return -EINVAL; -} - -static int ad7280_write_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int val, int val2, long mask) -{ - struct ad7280_state *st = iio_priv(indio_dev); - int i; - - switch (mask) { - case IIO_CHAN_INFO_OVERSAMPLING_RATIO: - if (val2 != 0) - return -EINVAL; - for (i = 0; i < ARRAY_SIZE(ad7280a_n_avg); i++) { - if (val == ad7280a_n_avg[i]) { - st->oversampling_ratio = i; - ad7280_update_delay(st); - return 0; - } - } - return -EINVAL; - default: - return -EINVAL; - } -} - -static const struct iio_info ad7280_info = { - .read_raw = ad7280_read_raw, - .write_raw = ad7280_write_raw, - .read_event_value = &ad7280a_read_thresh, - .write_event_value = &ad7280a_write_thresh, -}; - -static const struct iio_info ad7280_info_no_irq = { - .read_raw = ad7280_read_raw, - .write_raw = ad7280_write_raw, -}; - -static int ad7280_probe(struct spi_device *spi) -{ - struct device *dev = &spi->dev; - struct ad7280_state *st; - int ret; - struct iio_dev *indio_dev; - - indio_dev = devm_iio_device_alloc(dev, sizeof(*st)); - if (!indio_dev) - return -ENOMEM; - - st = iio_priv(indio_dev); - spi_set_drvdata(spi, indio_dev); - st->spi = spi; - mutex_init(&st->lock); - - st->thermistor_term_en = - device_property_read_bool(dev, "adi,thermistor-termination"); - - if (device_property_present(dev, "adi,acquisition-time-ns")) { - u32 val; - - ret = device_property_read_u32(dev, "adi,acquisition-time-ns", &val); - if (ret) - return ret; - - switch (val) { - case 400: - st->acquisition_time = AD7280A_CTRL_LB_ACQ_TIME_400ns; - break; - case 800: - st->acquisition_time = AD7280A_CTRL_LB_ACQ_TIME_800ns; - break; - case 1200: - st->acquisition_time = AD7280A_CTRL_LB_ACQ_TIME_1200ns; - break; - case 1600: - st->acquisition_time = AD7280A_CTRL_LB_ACQ_TIME_1600ns; - break; - default: - dev_err(dev, "Firmware provided acquisition time is invalid\n"); - return -EINVAL; - } - } else { - st->acquisition_time = AD7280A_CTRL_LB_ACQ_TIME_400ns; - } - - /* Alert masks are intended for when particular inputs are not wired up */ - if (device_property_present(dev, "adi,voltage-alert-last-chan")) { - u32 val; - - ret = device_property_read_u32(dev, "adi,voltage-alert-last-chan", &val); - if (ret) - return ret; - - switch (val) { - case 3: - st->chain_last_alert_ignore |= AD7280A_ALERT_REMOVE_VIN4_VIN5; - break; - case 4: - st->chain_last_alert_ignore |= AD7280A_ALERT_REMOVE_VIN5; - break; - case 5: - break; - default: - dev_err(dev, - "Firmware provided last voltage alert channel invalid\n"); - break; - } - } - crc8_populate_msb(st->crc_tab, POLYNOM); - - st->spi->max_speed_hz = AD7280A_MAX_SPI_CLK_HZ; - st->spi->mode = SPI_MODE_1; - spi_setup(st->spi); - - st->ctrl_lb = FIELD_PREP(AD7280A_CTRL_LB_ACQ_TIME_MSK, st->acquisition_time) | - FIELD_PREP(AD7280A_CTRL_LB_THERMISTOR_MSK, st->thermistor_term_en); - st->oversampling_ratio = 0; /* No oversampling */ - - ret = ad7280_chain_setup(st); - if (ret < 0) - return ret; - - st->slave_num = ret; - st->scan_cnt = (st->slave_num + 1) * AD7280A_NUM_CH; - st->cell_threshhigh = 0xFF; - st->aux_threshhigh = 0xFF; - - ret = devm_add_action_or_reset(dev, ad7280_sw_power_down, st); - if (ret) - return ret; - - ad7280_update_delay(st); - - indio_dev->name = spi_get_device_id(spi)->name; - indio_dev->modes = INDIO_DIRECT_MODE; - - ret = ad7280_channel_init(st, spi->irq > 0); - if (ret < 0) - return ret; - - indio_dev->num_channels = ret; - indio_dev->channels = st->channels; - if (spi->irq > 0) { - ret = ad7280_write(st, AD7280A_DEVADDR_MASTER, - AD7280A_ALERT_REG, 1, - AD7280A_ALERT_RELAY_SIG_CHAIN_DOWN); - if (ret) - return ret; - - ret = ad7280_write(st, ad7280a_devaddr(st->slave_num), - AD7280A_ALERT_REG, 0, - AD7280A_ALERT_GEN_STATIC_HIGH | - FIELD_PREP(AD7280A_ALERT_REMOVE_MSK, - st->chain_last_alert_ignore)); - if (ret) - return ret; - - ret = devm_request_threaded_irq(dev, spi->irq, - NULL, - ad7280_event_handler, - IRQF_TRIGGER_FALLING | - IRQF_ONESHOT, - indio_dev->name, - indio_dev); - if (ret) - return ret; - - indio_dev->info = &ad7280_info; - } else { - indio_dev->info = &ad7280_info_no_irq; - } - - return devm_iio_device_register(dev, indio_dev); -} - -static const struct spi_device_id ad7280_id[] = { - {"ad7280a", 0}, - {} -}; -MODULE_DEVICE_TABLE(spi, ad7280_id); - -static struct spi_driver ad7280_driver = { - .driver = { - .name = "ad7280", - }, - .probe = ad7280_probe, - .id_table = ad7280_id, -}; -module_spi_driver(ad7280_driver); - -MODULE_AUTHOR("Michael Hennerich "); -MODULE_DESCRIPTION("Analog Devices AD7280A"); -MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From b38da7feefb4c8080753eb5bf4e4db5eba0e119b Mon Sep 17 00:00:00 2001 From: Jan Luebbe Date: Wed, 16 Feb 2022 17:23:12 +0100 Subject: dt-bindings: iio: adc: microchip,mcp3201: fix interface type (I2C -> SPI) This family of ADCs uses SPI, not I2C. Signed-off-by: Jan Luebbe Link: https://lore.kernel.org/r/20220216162312.4064-1-jlu@pengutronix.de Signed-off-by: Jonathan Cameron --- Documentation/devicetree/bindings/iio/adc/microchip,mcp3201.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/iio/adc/microchip,mcp3201.yaml b/Documentation/devicetree/bindings/iio/adc/microchip,mcp3201.yaml index cbbac4ce56d6..fcc1ba53b20d 100644 --- a/Documentation/devicetree/bindings/iio/adc/microchip,mcp3201.yaml +++ b/Documentation/devicetree/bindings/iio/adc/microchip,mcp3201.yaml @@ -10,7 +10,7 @@ maintainers: - Oskar Andero description: | - Family of simple ADCs with an I2C inteface. + Family of simple ADCs with a SPI interface. properties: compatible: -- cgit v1.2.3 From a1a5cfe70cd29a59a9a85290dfe95ed1c8df1193 Mon Sep 17 00:00:00 2001 From: Cosmin Tanislav Date: Mon, 14 Feb 2022 09:38:06 +0200 Subject: iio: introduce mag_referenced Some accelerometers that support activity and inactivity events also support a referenced mode, in which the gravitational acceleration is taken as a point of reference before comparing the acceleration to the specified activity and inactivity magnitude. For example, in the case of the ADXL367, for activity detection, the formula is: abs(acceleration - reference) > magnitude Add a new event type that makes this behavior clear. Signed-off-by: Cosmin Tanislav Link: https://lore.kernel.org/r/20220214073810.781016-2-cosmin.tanislav@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/industrialio-event.c | 1 + include/uapi/linux/iio/types.h | 1 + tools/iio/iio_event_monitor.c | 1 + 3 files changed, 3 insertions(+) diff --git a/drivers/iio/industrialio-event.c b/drivers/iio/industrialio-event.c index d0732eac0f0a..ce8b102ce52f 100644 --- a/drivers/iio/industrialio-event.c +++ b/drivers/iio/industrialio-event.c @@ -230,6 +230,7 @@ static const char * const iio_ev_type_text[] = { [IIO_EV_TYPE_THRESH_ADAPTIVE] = "thresh_adaptive", [IIO_EV_TYPE_MAG_ADAPTIVE] = "mag_adaptive", [IIO_EV_TYPE_CHANGE] = "change", + [IIO_EV_TYPE_MAG_REFERENCED] = "mag_referenced", }; static const char * const iio_ev_dir_text[] = { diff --git a/include/uapi/linux/iio/types.h b/include/uapi/linux/iio/types.h index 48c13147c0a8..472cead10d8d 100644 --- a/include/uapi/linux/iio/types.h +++ b/include/uapi/linux/iio/types.h @@ -104,6 +104,7 @@ enum iio_event_type { IIO_EV_TYPE_THRESH_ADAPTIVE, IIO_EV_TYPE_MAG_ADAPTIVE, IIO_EV_TYPE_CHANGE, + IIO_EV_TYPE_MAG_REFERENCED, }; enum iio_event_direction { diff --git a/tools/iio/iio_event_monitor.c b/tools/iio/iio_event_monitor.c index b94a16ba5c6c..2f4581658859 100644 --- a/tools/iio/iio_event_monitor.c +++ b/tools/iio/iio_event_monitor.c @@ -68,6 +68,7 @@ static const char * const iio_ev_type_text[] = { [IIO_EV_TYPE_THRESH_ADAPTIVE] = "thresh_adaptive", [IIO_EV_TYPE_MAG_ADAPTIVE] = "mag_adaptive", [IIO_EV_TYPE_CHANGE] = "change", + [IIO_EV_TYPE_MAG_REFERENCED] = "mag_referenced", }; static const char * const iio_ev_dir_text[] = { -- cgit v1.2.3 From 89d185848633db2aa811131ac5db795d5366da78 Mon Sep 17 00:00:00 2001 From: Cosmin Tanislav Date: Mon, 14 Feb 2022 09:38:07 +0200 Subject: iio: ABI: document mag_referenced Some accelerometers that support activity and inactivity events also support a referenced mode, in which the gravitational acceleration is taken as a point of reference before comparing the acceleration to the specified activity and inactivity magnitude. For example, in the case of the ADXL367, for activity detection, the formula is: abs(acceleration - reference) > magnitude Add a new event type that makes this behavior clear. Signed-off-by: Cosmin Tanislav Link: https://lore.kernel.org/r/20220214073810.781016-3-cosmin.tanislav@analog.com Signed-off-by: Jonathan Cameron --- Documentation/ABI/testing/sysfs-bus-iio | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio index c551301b33f1..41c1e3e1bf30 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio +++ b/Documentation/ABI/testing/sysfs-bus-iio @@ -1213,6 +1213,32 @@ Description: number or direction is not specified, applies to all channels of this type. +What: /sys/.../iio:deviceX/events/in_accel_mag_referenced_en +What: /sys/.../iio:deviceX/events/in_accel_mag_referenced_rising_en +What: /sys/.../iio:deviceX/events/in_accel_mag_referenced_falling_en +What: /sys/.../iio:deviceX/events/in_accel_y_mag_referenced_en +What: /sys/.../iio:deviceX/events/in_accel_y_mag_referenced_rising_en +What: /sys/.../iio:deviceX/events/in_accel_y_mag_referenced_falling_en +KernelVersion: 5.18 +Contact: linux-iio@vger.kernel.org +Description: + Similar to in_accel_mag[_y][_rising|_falling]_en, but the event + value is relative to a reference magnitude. The reference magnitude + includes the graviational acceleration. + +What: /sys/.../iio:deviceX/events/in_accel_mag_referenced_value +What: /sys/.../iio:deviceX/events/in_accel_mag_referenced_rising_value +What: /sys/.../iio:deviceX/events/in_accel_mag_referenced_falling_value +What: /sys/.../iio:deviceX/events/in_accel_y_mag_referenced_value +What: /sys/.../iio:deviceX/events/in_accel_y_mag_referenced_rising_value +What: /sys/.../iio:deviceX/events/in_accel_y_mag_referenced_falling_value +KernelVersion: 5.18 +Contact: linux-iio@vger.kernel.org +Description: + The value to which the reference magnitude of the channel is + compared. If the axis is not specified, it applies to all channels + of this type. + What: /sys/.../events/in_steps_change_en KernelVersion: 4.0 Contact: linux-iio@vger.kernel.org -- cgit v1.2.3 From 06a4a0cf698474ce5a19eb2854edcb6af51b8055 Mon Sep 17 00:00:00 2001 From: Cosmin Tanislav Date: Mon, 14 Feb 2022 09:38:08 +0200 Subject: iio: ABI: add note about configuring other attributes during buffer capture It might be impossible to configure other attributes (e.g.: events, scale, sampling rate) if they impact the currently active buffer capture session. On ADXL367, writing to register before 0x2E requires the device to be placed in standby mode, otherwise the changes might be effective for only part of a measurement. To ensure this requirement, the configuration attributes of the IIO device try to claim direct mode before switching to standby mode. During a buffer capture, direct mode cannot be claimed, and the attribute write callback returns -EBUSY. Describe this behavior in the buffer/enable attribute description. Signed-off-by: Cosmin Tanislav Link: https://lore.kernel.org/r/20220214073810.781016-4-cosmin.tanislav@analog.com Signed-off-by: Jonathan Cameron --- Documentation/ABI/testing/sysfs-bus-iio | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio index 41c1e3e1bf30..bc98453bdade 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio +++ b/Documentation/ABI/testing/sysfs-bus-iio @@ -1278,6 +1278,10 @@ Description: Actually start the buffer capture up. Will start trigger if first device and appropriate. + Note that it might be impossible to configure other attributes, + (e.g.: events, scale, sampling rate) if they impact the currently + active buffer capture session. + What: /sys/bus/iio/devices/iio:deviceX/bufferY KernelVersion: 5.11 Contact: linux-iio@vger.kernel.org -- cgit v1.2.3 From 27ae7f9d923885b6380c60dbe45d3bb19e885c5f Mon Sep 17 00:00:00 2001 From: Cosmin Tanislav Date: Mon, 14 Feb 2022 09:38:09 +0200 Subject: dt-bindings: iio: accel: add ADXL367 The ADXL367 is an ultralow power, 3-axis MEMS accelerometer. The ADXL367 does not alias input signals to achieve ultralow power consumption, it samples the full bandwidth of the sensor at all data rates. Measurement ranges of +-2g, +-4g, and +-8g are available, with a resolution of 0.25mg/LSB on the +-2 g range. In addition to its ultralow power consumption, the ADXL367 has many features to enable true system level power reduction. It includes a deep multimode output FIFO, a built-in micropower temperature sensor, and an internal ADC for synchronous conversion of an additional analog input. Signed-off-by: Cosmin Tanislav Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20220214073810.781016-5-cosmin.tanislav@analog.com Signed-off-by: Jonathan Cameron --- .../devicetree/bindings/iio/accel/adi,adxl367.yaml | 79 ++++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/accel/adi,adxl367.yaml diff --git a/Documentation/devicetree/bindings/iio/accel/adi,adxl367.yaml b/Documentation/devicetree/bindings/iio/accel/adi,adxl367.yaml new file mode 100644 index 000000000000..d259e796c1d6 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/accel/adi,adxl367.yaml @@ -0,0 +1,79 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/accel/adi,adxl367.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Analog Devices ADXL367 3-Axis Digital Accelerometer + +maintainers: + - Cosmin Tanislav + +description: | + The ADXL367 is an ultralow power, 3-axis MEMS accelerometer. + + The ADXL367 does not alias input signals by to achieve ultralow power + consumption, it samples the full bandwidth of the sensor at all + data rates. Measurement ranges of +-2g, +-4g, and +-8g are available, + with a resolution of 0.25mg/LSB on the +-2 g range. + + In addition to its ultralow power consumption, the ADXL367 + has many features to enable true system level power reduction. + It includes a deep multimode output FIFO, a built-in micropower + temperature sensor, and an internal ADC for synchronous conversion + of an additional analog input. + https://www.analog.com/en/products/adxl367.html + +properties: + compatible: + enum: + - adi,adxl367 + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + spi-max-frequency: true + + vdd-supply: true + vddio-supply: true + +required: + - compatible + - reg + - interrupts + +additionalProperties: false + +examples: + - | + #include + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + accelerometer@53 { + compatible = "adi,adxl367"; + reg = <0x53>; + interrupt-parent = <&gpio>; + interrupts = <25 IRQ_TYPE_EDGE_RISING>; + }; + }; + - | + #include + + spi { + #address-cells = <1>; + #size-cells = <0>; + + accelerometer@0 { + compatible = "adi,adxl367"; + reg = <0>; + spi-max-frequency = <1000000>; + interrupt-parent = <&gpio>; + interrupts = <25 IRQ_TYPE_EDGE_RISING>; + }; + }; -- cgit v1.2.3 From cbab791c5e2a58c123d84bd9202c054e5449bc96 Mon Sep 17 00:00:00 2001 From: Cosmin Tanislav Date: Mon, 14 Feb 2022 09:38:10 +0200 Subject: iio: accel: add ADXL367 driver The ADXL367 is an ultralow power, 3-axis MEMS accelerometer. The ADXL367 does not alias input signals to achieve ultralow power consumption, it samples the full bandwidth of the sensor at all data rates. Measurement ranges of +-2g, +-4g, and +-8g are available, with a resolution of 0.25mg/LSB on the +-2 g range. In addition to its ultralow power consumption, the ADXL367 has many features to enable true system level power reduction. It includes a deep multimode output FIFO, a built-in micropower temperature sensor, and an internal ADC for synchronous conversion of an additional analog input. Signed-off-by: Cosmin Tanislav Link: https://lore.kernel.org/r/20220214073810.781016-6-cosmin.tanislav@analog.com Signed-off-by: Jonathan Cameron --- MAINTAINERS | 8 + drivers/iio/accel/Kconfig | 27 + drivers/iio/accel/Makefile | 3 + drivers/iio/accel/adxl367.c | 1588 +++++++++++++++++++++++++++++++++++++++ drivers/iio/accel/adxl367.h | 23 + drivers/iio/accel/adxl367_i2c.c | 90 +++ drivers/iio/accel/adxl367_spi.c | 164 ++++ 7 files changed, 1903 insertions(+) create mode 100644 drivers/iio/accel/adxl367.c create mode 100644 drivers/iio/accel/adxl367.h create mode 100644 drivers/iio/accel/adxl367_i2c.c create mode 100644 drivers/iio/accel/adxl367_spi.c diff --git a/MAINTAINERS b/MAINTAINERS index a2c8699e9e41..3b5393bb6fee 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -606,6 +606,14 @@ F: drivers/iio/accel/adxl355_core.c F: drivers/iio/accel/adxl355_i2c.c F: drivers/iio/accel/adxl355_spi.c +ADXL367 THREE-AXIS DIGITAL ACCELEROMETER DRIVER +M: Cosmin Tanislav +L: linux-iio@vger.kernel.org +S: Supported +W: http://ez.analog.com/community/linux-device-drivers +F: Documentation/devicetree/bindings/iio/accel/adi,adxl367.yaml +F: drivers/iio/accel/adxl367* + ADXL372 THREE-AXIS DIGITAL ACCELEROMETER DRIVER M: Michael Hennerich S: Supported diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig index eb17ca40e08a..eac3f02662ae 100644 --- a/drivers/iio/accel/Kconfig +++ b/drivers/iio/accel/Kconfig @@ -123,6 +123,33 @@ config ADXL355_SPI will be called adxl355_spi and you will also get adxl355_core for the core module. +config ADXL367 + tristate + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER + +config ADXL367_SPI + tristate "Analog Devices ADXL367 3-Axis Accelerometer SPI Driver" + depends on SPI + select ADXL367 + select REGMAP_SPI + help + Say yes here to add support for the Analog Devices ADXL367 triaxial + acceleration sensor. + To compile this driver as a module, choose M here: the + module will be called adxl367_spi. + +config ADXL367_I2C + tristate "Analog Devices ADXL367 3-Axis Accelerometer I2C Driver" + depends on I2C + select ADXL367 + select REGMAP_I2C + help + Say yes here to add support for the Analog Devices ADXL367 triaxial + acceleration sensor. + To compile this driver as a module, choose M here: the + module will be called adxl367_i2c. + config ADXL372 tristate select IIO_BUFFER diff --git a/drivers/iio/accel/Makefile b/drivers/iio/accel/Makefile index d03e2f6bba08..4d8792668838 100644 --- a/drivers/iio/accel/Makefile +++ b/drivers/iio/accel/Makefile @@ -15,6 +15,9 @@ obj-$(CONFIG_ADXL345_SPI) += adxl345_spi.o obj-$(CONFIG_ADXL355) += adxl355_core.o obj-$(CONFIG_ADXL355_I2C) += adxl355_i2c.o obj-$(CONFIG_ADXL355_SPI) += adxl355_spi.o +obj-$(CONFIG_ADXL367) += adxl367.o +obj-$(CONFIG_ADXL367_I2C) += adxl367_i2c.o +obj-$(CONFIG_ADXL367_SPI) += adxl367_spi.o obj-$(CONFIG_ADXL372) += adxl372.o obj-$(CONFIG_ADXL372_I2C) += adxl372_i2c.o obj-$(CONFIG_ADXL372_SPI) += adxl372_spi.o diff --git a/drivers/iio/accel/adxl367.c b/drivers/iio/accel/adxl367.c new file mode 100644 index 000000000000..b452d74b1d4d --- /dev/null +++ b/drivers/iio/accel/adxl367.c @@ -0,0 +1,1588 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2021 Analog Devices, Inc. + * Author: Cosmin Tanislav + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "adxl367.h" + +#define ADXL367_REG_DEVID 0x00 +#define ADXL367_DEVID_AD 0xAD + +#define ADXL367_REG_STATUS 0x0B +#define ADXL367_STATUS_INACT_MASK BIT(5) +#define ADXL367_STATUS_ACT_MASK BIT(4) +#define ADXL367_STATUS_FIFO_FULL_MASK BIT(2) + +#define ADXL367_FIFO_ENT_H_MASK GENMASK(1, 0) + +#define ADXL367_REG_X_DATA_H 0x0E +#define ADXL367_REG_Y_DATA_H 0x10 +#define ADXL367_REG_Z_DATA_H 0x12 +#define ADXL367_REG_TEMP_DATA_H 0x14 +#define ADXL367_REG_EX_ADC_DATA_H 0x16 +#define ADXL367_DATA_MASK GENMASK(15, 2) + +#define ADXL367_TEMP_25C 165 +#define ADXL367_TEMP_PER_C 54 + +#define ADXL367_VOLTAGE_OFFSET 8192 +#define ADXL367_VOLTAGE_MAX_MV 1000 +#define ADXL367_VOLTAGE_MAX_RAW GENMASK(13, 0) + +#define ADXL367_REG_RESET 0x1F +#define ADXL367_RESET_CODE 0x52 + +#define ADXL367_REG_THRESH_ACT_H 0x20 +#define ADXL367_REG_THRESH_INACT_H 0x23 +#define ADXL367_THRESH_MAX GENMASK(12, 0) +#define ADXL367_THRESH_VAL_H_MASK GENMASK(12, 6) +#define ADXL367_THRESH_H_MASK GENMASK(6, 0) +#define ADXL367_THRESH_VAL_L_MASK GENMASK(5, 0) +#define ADXL367_THRESH_L_MASK GENMASK(7, 2) + +#define ADXL367_REG_TIME_ACT 0x22 +#define ADXL367_REG_TIME_INACT_H 0x25 +#define ADXL367_TIME_ACT_MAX GENMASK(7, 0) +#define ADXL367_TIME_INACT_MAX GENMASK(15, 0) +#define ADXL367_TIME_INACT_VAL_H_MASK GENMASK(15, 8) +#define ADXL367_TIME_INACT_H_MASK GENMASK(7, 0) +#define ADXL367_TIME_INACT_VAL_L_MASK GENMASK(7, 0) +#define ADXL367_TIME_INACT_L_MASK GENMASK(7, 0) + +#define ADXL367_REG_ACT_INACT_CTL 0x27 +#define ADXL367_ACT_EN_MASK GENMASK(1, 0) +#define ADXL367_ACT_LINKLOOP_MASK GENMASK(5, 4) + +#define ADXL367_REG_FIFO_CTL 0x28 +#define ADXL367_FIFO_CTL_FORMAT_MASK GENMASK(6, 3) +#define ADXL367_FIFO_CTL_MODE_MASK GENMASK(1, 0) + +#define ADXL367_REG_FIFO_SAMPLES 0x29 +#define ADXL367_FIFO_SIZE 512 +#define ADXL367_FIFO_MAX_WATERMARK 511 + +#define ADXL367_SAMPLES_VAL_H_MASK BIT(8) +#define ADXL367_SAMPLES_H_MASK BIT(2) +#define ADXL367_SAMPLES_VAL_L_MASK GENMASK(7, 0) +#define ADXL367_SAMPLES_L_MASK GENMASK(7, 0) + +#define ADXL367_REG_INT1_MAP 0x2A +#define ADXL367_INT_INACT_MASK BIT(5) +#define ADXL367_INT_ACT_MASK BIT(4) +#define ADXL367_INT_FIFO_WATERMARK_MASK BIT(2) + +#define ADXL367_REG_FILTER_CTL 0x2C +#define ADXL367_FILTER_CTL_RANGE_MASK GENMASK(7, 6) +#define ADXL367_2G_RANGE_1G 4095 +#define ADXL367_2G_RANGE_100MG 409 +#define ADXL367_FILTER_CTL_ODR_MASK GENMASK(2, 0) + +#define ADXL367_REG_POWER_CTL 0x2D +#define ADXL367_POWER_CTL_MODE_MASK GENMASK(1, 0) + +#define ADXL367_REG_ADC_CTL 0x3C +#define ADXL367_REG_TEMP_CTL 0x3D +#define ADXL367_ADC_EN_MASK BIT(0) + +enum adxl367_range { + ADXL367_2G_RANGE, + ADXL367_4G_RANGE, + ADXL367_8G_RANGE, +}; + +enum adxl367_fifo_mode { + ADXL367_FIFO_MODE_DISABLED = 0b00, + ADXL367_FIFO_MODE_STREAM = 0b10, +}; + +enum adxl367_fifo_format { + ADXL367_FIFO_FORMAT_XYZ, + ADXL367_FIFO_FORMAT_X, + ADXL367_FIFO_FORMAT_Y, + ADXL367_FIFO_FORMAT_Z, + ADXL367_FIFO_FORMAT_XYZT, + ADXL367_FIFO_FORMAT_XT, + ADXL367_FIFO_FORMAT_YT, + ADXL367_FIFO_FORMAT_ZT, + ADXL367_FIFO_FORMAT_XYZA, + ADXL367_FIFO_FORMAT_XA, + ADXL367_FIFO_FORMAT_YA, + ADXL367_FIFO_FORMAT_ZA, +}; + +enum adxl367_op_mode { + ADXL367_OP_STANDBY = 0b00, + ADXL367_OP_MEASURE = 0b10, +}; + +enum adxl367_act_proc_mode { + ADXL367_LOOPED = 0b11, +}; + +enum adxl367_act_en_mode { + ADXL367_ACT_DISABLED = 0b00, + ADCL367_ACT_REF_ENABLED = 0b11, +}; + +enum adxl367_activity_type { + ADXL367_ACTIVITY, + ADXL367_INACTIVITY, +}; + +enum adxl367_odr { + ADXL367_ODR_12P5HZ, + ADXL367_ODR_25HZ, + ADXL367_ODR_50HZ, + ADXL367_ODR_100HZ, + ADXL367_ODR_200HZ, + ADXL367_ODR_400HZ, +}; + +struct adxl367_state { + const struct adxl367_ops *ops; + void *context; + + struct device *dev; + struct regmap *regmap; + + struct regulator_bulk_data regulators[2]; + + /* + * Synchronize access to members of driver state, and ensure atomicity + * of consecutive regmap operations. + */ + struct mutex lock; + + enum adxl367_odr odr; + enum adxl367_range range; + + unsigned int act_threshold; + unsigned int act_time_ms; + unsigned int inact_threshold; + unsigned int inact_time_ms; + + unsigned int fifo_set_size; + unsigned int fifo_watermark; + + __be16 fifo_buf[ADXL367_FIFO_SIZE] ____cacheline_aligned; + __be16 sample_buf; + u8 act_threshold_buf[2]; + u8 inact_time_buf[2]; + u8 status_buf[3]; +}; + +static const unsigned int adxl367_threshold_h_reg_tbl[] = { + [ADXL367_ACTIVITY] = ADXL367_REG_THRESH_ACT_H, + [ADXL367_INACTIVITY] = ADXL367_REG_THRESH_INACT_H, +}; + +static const unsigned int adxl367_act_en_shift_tbl[] = { + [ADXL367_ACTIVITY] = 0, + [ADXL367_INACTIVITY] = 2, +}; + +static const unsigned int adxl367_act_int_mask_tbl[] = { + [ADXL367_ACTIVITY] = ADXL367_INT_ACT_MASK, + [ADXL367_INACTIVITY] = ADXL367_INT_INACT_MASK, +}; + +static const int adxl367_samp_freq_tbl[][2] = { + [ADXL367_ODR_12P5HZ] = {12, 500000}, + [ADXL367_ODR_25HZ] = {25, 0}, + [ADXL367_ODR_50HZ] = {50, 0}, + [ADXL367_ODR_100HZ] = {100, 0}, + [ADXL367_ODR_200HZ] = {200, 0}, + [ADXL367_ODR_400HZ] = {400, 0}, +}; + +/* (g * 2) * 9.80665 * 1000000 / (2^14 - 1) */ +static const int adxl367_range_scale_tbl[][2] = { + [ADXL367_2G_RANGE] = {0, 2394347}, + [ADXL367_4G_RANGE] = {0, 4788695}, + [ADXL367_8G_RANGE] = {0, 9577391}, +}; + +static const int adxl367_range_scale_factor_tbl[] = { + [ADXL367_2G_RANGE] = 1, + [ADXL367_4G_RANGE] = 2, + [ADXL367_8G_RANGE] = 4, +}; + +enum { + ADXL367_X_CHANNEL_INDEX, + ADXL367_Y_CHANNEL_INDEX, + ADXL367_Z_CHANNEL_INDEX, + ADXL367_TEMP_CHANNEL_INDEX, + ADXL367_EX_ADC_CHANNEL_INDEX +}; + +#define ADXL367_X_CHANNEL_MASK BIT(ADXL367_X_CHANNEL_INDEX) +#define ADXL367_Y_CHANNEL_MASK BIT(ADXL367_Y_CHANNEL_INDEX) +#define ADXL367_Z_CHANNEL_MASK BIT(ADXL367_Z_CHANNEL_INDEX) +#define ADXL367_TEMP_CHANNEL_MASK BIT(ADXL367_TEMP_CHANNEL_INDEX) +#define ADXL367_EX_ADC_CHANNEL_MASK BIT(ADXL367_EX_ADC_CHANNEL_INDEX) + +static const enum adxl367_fifo_format adxl367_fifo_formats[] = { + ADXL367_FIFO_FORMAT_X, + ADXL367_FIFO_FORMAT_Y, + ADXL367_FIFO_FORMAT_Z, + ADXL367_FIFO_FORMAT_XT, + ADXL367_FIFO_FORMAT_YT, + ADXL367_FIFO_FORMAT_ZT, + ADXL367_FIFO_FORMAT_XA, + ADXL367_FIFO_FORMAT_YA, + ADXL367_FIFO_FORMAT_ZA, + ADXL367_FIFO_FORMAT_XYZ, + ADXL367_FIFO_FORMAT_XYZT, + ADXL367_FIFO_FORMAT_XYZA, +}; + +static const unsigned long adxl367_channel_masks[] = { + ADXL367_X_CHANNEL_MASK, + ADXL367_Y_CHANNEL_MASK, + ADXL367_Z_CHANNEL_MASK, + ADXL367_X_CHANNEL_MASK | ADXL367_TEMP_CHANNEL_MASK, + ADXL367_Y_CHANNEL_MASK | ADXL367_TEMP_CHANNEL_MASK, + ADXL367_Z_CHANNEL_MASK | ADXL367_TEMP_CHANNEL_MASK, + ADXL367_X_CHANNEL_MASK | ADXL367_EX_ADC_CHANNEL_MASK, + ADXL367_Y_CHANNEL_MASK | ADXL367_EX_ADC_CHANNEL_MASK, + ADXL367_Z_CHANNEL_MASK | ADXL367_EX_ADC_CHANNEL_MASK, + ADXL367_X_CHANNEL_MASK | ADXL367_Y_CHANNEL_MASK | ADXL367_Z_CHANNEL_MASK, + ADXL367_X_CHANNEL_MASK | ADXL367_Y_CHANNEL_MASK | ADXL367_Z_CHANNEL_MASK | + ADXL367_TEMP_CHANNEL_MASK, + ADXL367_X_CHANNEL_MASK | ADXL367_Y_CHANNEL_MASK | ADXL367_Z_CHANNEL_MASK | + ADXL367_EX_ADC_CHANNEL_MASK, + 0, +}; + +static int adxl367_set_measure_en(struct adxl367_state *st, bool en) +{ + enum adxl367_op_mode op_mode = en ? ADXL367_OP_MEASURE + : ADXL367_OP_STANDBY; + int ret; + + ret = regmap_update_bits(st->regmap, ADXL367_REG_POWER_CTL, + ADXL367_POWER_CTL_MODE_MASK, + FIELD_PREP(ADXL367_POWER_CTL_MODE_MASK, + op_mode)); + if (ret) + return ret; + + /* + * Wait for acceleration output to settle after entering + * measure mode. + */ + if (en) + msleep(100); + + return 0; +} + +static void adxl367_scale_act_thresholds(struct adxl367_state *st, + enum adxl367_range old_range, + enum adxl367_range new_range) +{ + st->act_threshold = st->act_threshold + * adxl367_range_scale_factor_tbl[old_range] + / adxl367_range_scale_factor_tbl[new_range]; + st->inact_threshold = st->inact_threshold + * adxl367_range_scale_factor_tbl[old_range] + / adxl367_range_scale_factor_tbl[new_range]; +} + +static int _adxl367_set_act_threshold(struct adxl367_state *st, + enum adxl367_activity_type act, + unsigned int threshold) +{ + u8 reg = adxl367_threshold_h_reg_tbl[act]; + int ret; + + if (threshold > ADXL367_THRESH_MAX) + return -EINVAL; + + st->act_threshold_buf[0] = FIELD_PREP(ADXL367_THRESH_H_MASK, + FIELD_GET(ADXL367_THRESH_VAL_H_MASK, + threshold)); + st->act_threshold_buf[1] = FIELD_PREP(ADXL367_THRESH_L_MASK, + FIELD_GET(ADXL367_THRESH_VAL_L_MASK, + threshold)); + + ret = regmap_bulk_write(st->regmap, reg, st->act_threshold_buf, + sizeof(st->act_threshold_buf)); + if (ret) + return ret; + + if (act == ADXL367_ACTIVITY) + st->act_threshold = threshold; + else + st->inact_threshold = threshold; + + return 0; +} + +static int adxl367_set_act_threshold(struct adxl367_state *st, + enum adxl367_activity_type act, + unsigned int threshold) +{ + int ret; + + mutex_lock(&st->lock); + + ret = adxl367_set_measure_en(st, false); + if (ret) + goto out; + + ret = _adxl367_set_act_threshold(st, act, threshold); + if (ret) + goto out; + + ret = adxl367_set_measure_en(st, true); + +out: + mutex_unlock(&st->lock); + + return ret; +} + +static int adxl367_set_act_proc_mode(struct adxl367_state *st, + enum adxl367_act_proc_mode mode) +{ + return regmap_update_bits(st->regmap, ADXL367_REG_ACT_INACT_CTL, + ADXL367_ACT_LINKLOOP_MASK, + FIELD_PREP(ADXL367_ACT_LINKLOOP_MASK, + mode)); +} + +static int adxl367_set_act_interrupt_en(struct adxl367_state *st, + enum adxl367_activity_type act, + bool en) +{ + unsigned int mask = adxl367_act_int_mask_tbl[act]; + + return regmap_update_bits(st->regmap, ADXL367_REG_INT1_MAP, + mask, en ? mask : 0); +} + +static int adxl367_get_act_interrupt_en(struct adxl367_state *st, + enum adxl367_activity_type act, + bool *en) +{ + unsigned int mask = adxl367_act_int_mask_tbl[act]; + unsigned int val; + int ret; + + ret = regmap_read(st->regmap, ADXL367_REG_INT1_MAP, &val); + if (ret) + return ret; + + *en = !!(val & mask); + + return 0; +} + +static int adxl367_set_act_en(struct adxl367_state *st, + enum adxl367_activity_type act, + enum adxl367_act_en_mode en) +{ + unsigned int ctl_shift = adxl367_act_en_shift_tbl[act]; + + return regmap_update_bits(st->regmap, ADXL367_REG_ACT_INACT_CTL, + ADXL367_ACT_EN_MASK << ctl_shift, + en << ctl_shift); +} + +static int adxl367_set_fifo_watermark_interrupt_en(struct adxl367_state *st, + bool en) +{ + return regmap_update_bits(st->regmap, ADXL367_REG_INT1_MAP, + ADXL367_INT_FIFO_WATERMARK_MASK, + en ? ADXL367_INT_FIFO_WATERMARK_MASK : 0); +} + +static int adxl367_get_fifo_mode(struct adxl367_state *st, + enum adxl367_fifo_mode *fifo_mode) +{ + unsigned int val; + int ret; + + ret = regmap_read(st->regmap, ADXL367_REG_FIFO_CTL, &val); + if (ret) + return ret; + + *fifo_mode = FIELD_GET(ADXL367_FIFO_CTL_MODE_MASK, val); + + return 0; +} + +static int adxl367_set_fifo_mode(struct adxl367_state *st, + enum adxl367_fifo_mode fifo_mode) +{ + return regmap_update_bits(st->regmap, ADXL367_REG_FIFO_CTL, + ADXL367_FIFO_CTL_MODE_MASK, + FIELD_PREP(ADXL367_FIFO_CTL_MODE_MASK, + fifo_mode)); +} + +static int adxl367_set_fifo_format(struct adxl367_state *st, + enum adxl367_fifo_format fifo_format) +{ + return regmap_update_bits(st->regmap, ADXL367_REG_FIFO_CTL, + ADXL367_FIFO_CTL_FORMAT_MASK, + FIELD_PREP(ADXL367_FIFO_CTL_FORMAT_MASK, + fifo_format)); +} + +static int adxl367_set_fifo_samples(struct adxl367_state *st, + unsigned int fifo_watermark, + unsigned int fifo_set_size) +{ + unsigned int fifo_samples = fifo_watermark * fifo_set_size; + unsigned int fifo_samples_h, fifo_samples_l; + int ret; + + if (fifo_samples > ADXL367_FIFO_MAX_WATERMARK) + fifo_samples = ADXL367_FIFO_MAX_WATERMARK; + + if (fifo_set_size == 0) + return 0; + + fifo_samples /= fifo_set_size; + + fifo_samples_h = FIELD_PREP(ADXL367_SAMPLES_H_MASK, + FIELD_GET(ADXL367_SAMPLES_VAL_H_MASK, + fifo_samples)); + fifo_samples_l = FIELD_PREP(ADXL367_SAMPLES_L_MASK, + FIELD_GET(ADXL367_SAMPLES_VAL_L_MASK, + fifo_samples)); + + ret = regmap_update_bits(st->regmap, ADXL367_REG_FIFO_CTL, + ADXL367_SAMPLES_H_MASK, fifo_samples_h); + if (ret) + return ret; + + return regmap_update_bits(st->regmap, ADXL367_REG_FIFO_SAMPLES, + ADXL367_SAMPLES_L_MASK, fifo_samples_l); +} + +static int adxl367_set_fifo_set_size(struct adxl367_state *st, + unsigned int fifo_set_size) +{ + int ret; + + ret = adxl367_set_fifo_samples(st, st->fifo_watermark, fifo_set_size); + if (ret) + return ret; + + st->fifo_set_size = fifo_set_size; + + return 0; +} + +static int adxl367_set_fifo_watermark(struct adxl367_state *st, + unsigned int fifo_watermark) +{ + int ret; + + ret = adxl367_set_fifo_samples(st, fifo_watermark, st->fifo_set_size); + if (ret) + return ret; + + st->fifo_watermark = fifo_watermark; + + return 0; +} + +static int adxl367_set_range(struct iio_dev *indio_dev, + enum adxl367_range range) +{ + struct adxl367_state *st = iio_priv(indio_dev); + int ret; + + ret = iio_device_claim_direct_mode(indio_dev); + if (ret) + return ret; + + mutex_lock(&st->lock); + + ret = adxl367_set_measure_en(st, false); + if (ret) + goto out; + + ret = regmap_update_bits(st->regmap, ADXL367_REG_FILTER_CTL, + ADXL367_FILTER_CTL_RANGE_MASK, + FIELD_PREP(ADXL367_FILTER_CTL_RANGE_MASK, + range)); + if (ret) + goto out; + + adxl367_scale_act_thresholds(st, st->range, range); + + /* Activity thresholds depend on range */ + ret = _adxl367_set_act_threshold(st, ADXL367_ACTIVITY, + st->act_threshold); + if (ret) + goto out; + + ret = _adxl367_set_act_threshold(st, ADXL367_INACTIVITY, + st->inact_threshold); + if (ret) + goto out; + + ret = adxl367_set_measure_en(st, true); + if (ret) + goto out; + + st->range = range; + +out: + mutex_unlock(&st->lock); + + iio_device_release_direct_mode(indio_dev); + + return ret; +} + +static int adxl367_time_ms_to_samples(struct adxl367_state *st, unsigned int ms) +{ + int freq_hz = adxl367_samp_freq_tbl[st->odr][0]; + int freq_microhz = adxl367_samp_freq_tbl[st->odr][1]; + /* Scale to decihertz to prevent precision loss in 12.5Hz case. */ + int freq_dhz = freq_hz * 10 + freq_microhz / 100000; + + return DIV_ROUND_CLOSEST(ms * freq_dhz, 10000); +} + +static int _adxl367_set_act_time_ms(struct adxl367_state *st, unsigned int ms) +{ + unsigned int val = adxl367_time_ms_to_samples(st, ms); + int ret; + + if (val > ADXL367_TIME_ACT_MAX) + val = ADXL367_TIME_ACT_MAX; + + ret = regmap_write(st->regmap, ADXL367_REG_TIME_ACT, val); + if (ret) + return ret; + + st->act_time_ms = ms; + + return 0; +} + +static int _adxl367_set_inact_time_ms(struct adxl367_state *st, unsigned int ms) +{ + unsigned int val = adxl367_time_ms_to_samples(st, ms); + int ret; + + if (val > ADXL367_TIME_INACT_MAX) + val = ADXL367_TIME_INACT_MAX; + + st->inact_time_buf[0] = FIELD_PREP(ADXL367_TIME_INACT_H_MASK, + FIELD_GET(ADXL367_TIME_INACT_VAL_H_MASK, + val)); + st->inact_time_buf[1] = FIELD_PREP(ADXL367_TIME_INACT_L_MASK, + FIELD_GET(ADXL367_TIME_INACT_VAL_L_MASK, + val)); + + ret = regmap_bulk_write(st->regmap, ADXL367_REG_TIME_INACT_H, + st->inact_time_buf, sizeof(st->inact_time_buf)); + if (ret) + return ret; + + st->inact_time_ms = ms; + + return 0; +} + +static int adxl367_set_act_time_ms(struct adxl367_state *st, + enum adxl367_activity_type act, + unsigned int ms) +{ + int ret; + + mutex_lock(&st->lock); + + ret = adxl367_set_measure_en(st, false); + if (ret) + goto out; + + if (act == ADXL367_ACTIVITY) + ret = _adxl367_set_act_time_ms(st, ms); + else + ret = _adxl367_set_inact_time_ms(st, ms); + + if (ret) + goto out; + + ret = adxl367_set_measure_en(st, true); + +out: + mutex_unlock(&st->lock); + + return ret; +} + +static int _adxl367_set_odr(struct adxl367_state *st, enum adxl367_odr odr) +{ + int ret; + + ret = regmap_update_bits(st->regmap, ADXL367_REG_FILTER_CTL, + ADXL367_FILTER_CTL_ODR_MASK, + FIELD_PREP(ADXL367_FILTER_CTL_ODR_MASK, + odr)); + if (ret) + return ret; + + /* Activity timers depend on ODR */ + ret = _adxl367_set_act_time_ms(st, st->act_time_ms); + if (ret) + return ret; + + ret = _adxl367_set_inact_time_ms(st, st->inact_time_ms); + if (ret) + return ret; + + st->odr = odr; + + return 0; +} + +static int adxl367_set_odr(struct iio_dev *indio_dev, enum adxl367_odr odr) +{ + struct adxl367_state *st = iio_priv(indio_dev); + int ret; + + ret = iio_device_claim_direct_mode(indio_dev); + if (ret) + return ret; + + mutex_lock(&st->lock); + + ret = adxl367_set_measure_en(st, false); + if (ret) + goto out; + + ret = _adxl367_set_odr(st, odr); + if (ret) + goto out; + + ret = adxl367_set_measure_en(st, true); + +out: + mutex_unlock(&st->lock); + + iio_device_release_direct_mode(indio_dev); + + return ret; +} + +static int adxl367_set_temp_adc_en(struct adxl367_state *st, unsigned int reg, + bool en) +{ + return regmap_update_bits(st->regmap, reg, ADXL367_ADC_EN_MASK, + en ? ADXL367_ADC_EN_MASK : 0); +} + +static int adxl367_set_temp_adc_reg_en(struct adxl367_state *st, + unsigned int reg, bool en) +{ + int ret; + + switch (reg) { + case ADXL367_REG_TEMP_DATA_H: + ret = adxl367_set_temp_adc_en(st, ADXL367_REG_TEMP_CTL, en); + break; + case ADXL367_REG_EX_ADC_DATA_H: + ret = adxl367_set_temp_adc_en(st, ADXL367_REG_ADC_CTL, en); + break; + default: + return 0; + } + + if (ret) + return ret; + + if (en) + msleep(100); + + return 0; +} + +static int adxl367_set_temp_adc_mask_en(struct adxl367_state *st, + const unsigned long *active_scan_mask, + bool en) +{ + if (*active_scan_mask & ADXL367_TEMP_CHANNEL_MASK) + return adxl367_set_temp_adc_en(st, ADXL367_REG_TEMP_CTL, en); + else if (*active_scan_mask & ADXL367_EX_ADC_CHANNEL_MASK) + return adxl367_set_temp_adc_en(st, ADXL367_REG_ADC_CTL, en); + + return 0; +} + +static int adxl367_find_odr(struct adxl367_state *st, int val, int val2, + enum adxl367_odr *odr) +{ + size_t size = ARRAY_SIZE(adxl367_samp_freq_tbl); + int i; + + for (i = 0; i < size; i++) + if (val == adxl367_samp_freq_tbl[i][0] && + val2 == adxl367_samp_freq_tbl[i][1]) + break; + + if (i == size) + return -EINVAL; + + *odr = i; + + return 0; +} + +static int adxl367_find_range(struct adxl367_state *st, int val, int val2, + enum adxl367_range *range) +{ + size_t size = ARRAY_SIZE(adxl367_range_scale_tbl); + int i; + + for (i = 0; i < size; i++) + if (val == adxl367_range_scale_tbl[i][0] && + val2 == adxl367_range_scale_tbl[i][1]) + break; + + if (i == size) + return -EINVAL; + + *range = i; + + return 0; +} + +static int adxl367_read_sample(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val) +{ + struct adxl367_state *st = iio_priv(indio_dev); + u16 sample; + int ret; + + ret = iio_device_claim_direct_mode(indio_dev); + if (ret) + return ret; + + mutex_lock(&st->lock); + + ret = adxl367_set_temp_adc_reg_en(st, chan->address, true); + if (ret) + goto out; + + ret = regmap_bulk_read(st->regmap, chan->address, &st->sample_buf, + sizeof(st->sample_buf)); + if (ret) + goto out; + + sample = FIELD_GET(ADXL367_DATA_MASK, be16_to_cpu(st->sample_buf)); + *val = sign_extend32(sample, chan->scan_type.realbits - 1); + + ret = adxl367_set_temp_adc_reg_en(st, chan->address, false); + +out: + mutex_unlock(&st->lock); + + iio_device_release_direct_mode(indio_dev); + + return ret ?: IIO_VAL_INT; +} + +static int adxl367_get_status(struct adxl367_state *st, u8 *status, + u16 *fifo_entries) +{ + int ret; + + /* Read STATUS, FIFO_ENT_L and FIFO_ENT_H */ + ret = regmap_bulk_read(st->regmap, ADXL367_REG_STATUS, + st->status_buf, sizeof(st->status_buf)); + if (ret) + return ret; + + st->status_buf[2] &= ADXL367_FIFO_ENT_H_MASK; + + *status = st->status_buf[0]; + *fifo_entries = get_unaligned_le16(&st->status_buf[1]); + + return 0; +} + +static bool adxl367_push_event(struct iio_dev *indio_dev, u8 status) +{ + unsigned int ev_dir; + + if (FIELD_GET(ADXL367_STATUS_ACT_MASK, status)) + ev_dir = IIO_EV_DIR_RISING; + else if (FIELD_GET(ADXL367_STATUS_INACT_MASK, status)) + ev_dir = IIO_EV_DIR_FALLING; + else + return false; + + iio_push_event(indio_dev, + IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, IIO_MOD_X_OR_Y_OR_Z, + IIO_EV_TYPE_THRESH, ev_dir), + iio_get_time_ns(indio_dev)); + + return true; +} + +static bool adxl367_push_fifo_data(struct iio_dev *indio_dev, u8 status, + u16 fifo_entries) +{ + struct adxl367_state *st = iio_priv(indio_dev); + int ret; + int i; + + if (!FIELD_GET(ADXL367_STATUS_FIFO_FULL_MASK, status)) + return false; + + fifo_entries -= fifo_entries % st->fifo_set_size; + + ret = st->ops->read_fifo(st->context, st->fifo_buf, fifo_entries); + if (ret) { + dev_err(st->dev, "Failed to read FIFO: %d\n", ret); + return true; + } + + for (i = 0; i < fifo_entries; i += st->fifo_set_size) + iio_push_to_buffers(indio_dev, &st->fifo_buf[i]); + + return true; +} + +static irqreturn_t adxl367_irq_handler(int irq, void *private) +{ + struct iio_dev *indio_dev = private; + struct adxl367_state *st = iio_priv(indio_dev); + u16 fifo_entries; + bool handled; + u8 status; + int ret; + + ret = adxl367_get_status(st, &status, &fifo_entries); + if (ret) + return IRQ_NONE; + + handled |= adxl367_push_event(indio_dev, status); + handled |= adxl367_push_fifo_data(indio_dev, status, fifo_entries); + + return handled ? IRQ_HANDLED : IRQ_NONE; +} + +static int adxl367_reg_access(struct iio_dev *indio_dev, + unsigned int reg, + unsigned int writeval, + unsigned int *readval) +{ + struct adxl367_state *st = iio_priv(indio_dev); + + if (readval) + return regmap_read(st->regmap, reg, readval); + else + return regmap_write(st->regmap, reg, writeval); +} + +static int adxl367_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long info) +{ + struct adxl367_state *st = iio_priv(indio_dev); + + switch (info) { + case IIO_CHAN_INFO_RAW: + return adxl367_read_sample(indio_dev, chan, val); + case IIO_CHAN_INFO_SCALE: + switch (chan->type) { + case IIO_ACCEL: + mutex_lock(&st->lock); + *val = adxl367_range_scale_tbl[st->range][0]; + *val2 = adxl367_range_scale_tbl[st->range][1]; + mutex_unlock(&st->lock); + return IIO_VAL_INT_PLUS_NANO; + case IIO_TEMP: + *val = 1000; + *val2 = ADXL367_TEMP_PER_C; + return IIO_VAL_FRACTIONAL; + case IIO_VOLTAGE: + *val = ADXL367_VOLTAGE_MAX_MV; + *val2 = ADXL367_VOLTAGE_MAX_RAW; + return IIO_VAL_FRACTIONAL; + default: + return -EINVAL; + } + case IIO_CHAN_INFO_OFFSET: + switch (chan->type) { + case IIO_TEMP: + *val = 25 * ADXL367_TEMP_PER_C - ADXL367_TEMP_25C; + return IIO_VAL_INT; + case IIO_VOLTAGE: + *val = ADXL367_VOLTAGE_OFFSET; + return IIO_VAL_INT; + default: + return -EINVAL; + } + case IIO_CHAN_INFO_SAMP_FREQ: + mutex_lock(&st->lock); + *val = adxl367_samp_freq_tbl[st->odr][0]; + *val2 = adxl367_samp_freq_tbl[st->odr][1]; + mutex_unlock(&st->lock); + return IIO_VAL_INT_PLUS_MICRO; + default: + return -EINVAL; + } +} + +static int adxl367_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long info) +{ + struct adxl367_state *st = iio_priv(indio_dev); + int ret; + + switch (info) { + case IIO_CHAN_INFO_SAMP_FREQ: { + enum adxl367_odr odr; + + ret = adxl367_find_odr(st, val, val2, &odr); + if (ret) + return ret; + + return adxl367_set_odr(indio_dev, odr); + } + case IIO_CHAN_INFO_SCALE: { + enum adxl367_range range; + + ret = adxl367_find_range(st, val, val2, &range); + if (ret) + return ret; + + return adxl367_set_range(indio_dev, range); + } + default: + return -EINVAL; + } +} + +static int adxl367_write_raw_get_fmt(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + long info) +{ + switch (info) { + case IIO_CHAN_INFO_SCALE: + if (chan->type != IIO_ACCEL) + return -EINVAL; + + return IIO_VAL_INT_PLUS_NANO; + default: + return IIO_VAL_INT_PLUS_MICRO; + } +} + +static int adxl367_read_avail(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + const int **vals, int *type, int *length, + long info) +{ + switch (info) { + case IIO_CHAN_INFO_SCALE: + if (chan->type != IIO_ACCEL) + return -EINVAL; + + *vals = (int *)adxl367_range_scale_tbl; + *type = IIO_VAL_INT_PLUS_NANO; + *length = ARRAY_SIZE(adxl367_range_scale_tbl) * 2; + return IIO_AVAIL_LIST; + case IIO_CHAN_INFO_SAMP_FREQ: + *vals = (int *)adxl367_samp_freq_tbl; + *type = IIO_VAL_INT_PLUS_MICRO; + *length = ARRAY_SIZE(adxl367_samp_freq_tbl) * 2; + return IIO_AVAIL_LIST; + default: + return -EINVAL; + } +} + +static int adxl367_read_event_value(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, + int *val, int *val2) +{ + struct adxl367_state *st = iio_priv(indio_dev); + + switch (info) { + case IIO_EV_INFO_VALUE: { + switch (dir) { + case IIO_EV_DIR_RISING: + mutex_lock(&st->lock); + *val = st->act_threshold; + mutex_unlock(&st->lock); + return IIO_VAL_INT; + case IIO_EV_DIR_FALLING: + mutex_lock(&st->lock); + *val = st->inact_threshold; + mutex_unlock(&st->lock); + return IIO_VAL_INT; + default: + return -EINVAL; + } + } + case IIO_EV_INFO_PERIOD: + switch (dir) { + case IIO_EV_DIR_RISING: + mutex_lock(&st->lock); + *val = st->act_time_ms; + mutex_unlock(&st->lock); + *val2 = 1000; + return IIO_VAL_FRACTIONAL; + case IIO_EV_DIR_FALLING: + mutex_lock(&st->lock); + *val = st->inact_time_ms; + mutex_unlock(&st->lock); + *val2 = 1000; + return IIO_VAL_FRACTIONAL; + default: + return -EINVAL; + } + default: + return -EINVAL; + } +} + +static int adxl367_write_event_value(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, + int val, int val2) +{ + struct adxl367_state *st = iio_priv(indio_dev); + + switch (info) { + case IIO_EV_INFO_VALUE: + if (val < 0) + return -EINVAL; + + switch (dir) { + case IIO_EV_DIR_RISING: + return adxl367_set_act_threshold(st, ADXL367_ACTIVITY, val); + case IIO_EV_DIR_FALLING: + return adxl367_set_act_threshold(st, ADXL367_INACTIVITY, val); + default: + return -EINVAL; + } + case IIO_EV_INFO_PERIOD: + if (val < 0) + return -EINVAL; + + val = val * 1000 + DIV_ROUND_UP(val2, 1000); + switch (dir) { + case IIO_EV_DIR_RISING: + return adxl367_set_act_time_ms(st, ADXL367_ACTIVITY, val); + case IIO_EV_DIR_FALLING: + return adxl367_set_act_time_ms(st, ADXL367_INACTIVITY, val); + default: + return -EINVAL; + } + default: + return -EINVAL; + } +} + +static int adxl367_read_event_config(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir) +{ + struct adxl367_state *st = iio_priv(indio_dev); + bool en; + int ret; + + switch (dir) { + case IIO_EV_DIR_RISING: + ret = adxl367_get_act_interrupt_en(st, ADXL367_ACTIVITY, &en); + return ret ?: en; + case IIO_EV_DIR_FALLING: + ret = adxl367_get_act_interrupt_en(st, ADXL367_INACTIVITY, &en); + return ret ?: en; + default: + return -EINVAL; + } +} + +static int adxl367_write_event_config(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + int state) +{ + struct adxl367_state *st = iio_priv(indio_dev); + enum adxl367_activity_type act; + int ret; + + switch (dir) { + case IIO_EV_DIR_RISING: + act = ADXL367_ACTIVITY; + break; + case IIO_EV_DIR_FALLING: + act = ADXL367_INACTIVITY; + break; + default: + return -EINVAL; + } + + ret = iio_device_claim_direct_mode(indio_dev); + if (ret) + return ret; + + mutex_lock(&st->lock); + + ret = adxl367_set_measure_en(st, false); + if (ret) + goto out; + + ret = adxl367_set_act_interrupt_en(st, act, state); + if (ret) + goto out; + + ret = adxl367_set_act_en(st, act, state ? ADCL367_ACT_REF_ENABLED + : ADXL367_ACT_DISABLED); + if (ret) + goto out; + + ret = adxl367_set_measure_en(st, true); + +out: + mutex_unlock(&st->lock); + + iio_device_release_direct_mode(indio_dev); + + return ret; +} + +static ssize_t adxl367_get_fifo_enabled(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct adxl367_state *st = iio_priv(dev_to_iio_dev(dev)); + enum adxl367_fifo_mode fifo_mode; + int ret; + + ret = adxl367_get_fifo_mode(st, &fifo_mode); + if (ret) + return ret; + + return sysfs_emit(buf, "%d\n", fifo_mode != ADXL367_FIFO_MODE_DISABLED); +} + +static ssize_t adxl367_get_fifo_watermark(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct adxl367_state *st = iio_priv(dev_to_iio_dev(dev)); + unsigned int fifo_watermark; + + mutex_lock(&st->lock); + fifo_watermark = st->fifo_watermark; + mutex_unlock(&st->lock); + + return sysfs_emit(buf, "%d\n", fifo_watermark); +} + +static IIO_CONST_ATTR(hwfifo_watermark_min, "1"); +static IIO_CONST_ATTR(hwfifo_watermark_max, + __stringify(ADXL367_FIFO_MAX_WATERMARK)); +static IIO_DEVICE_ATTR(hwfifo_watermark, 0444, + adxl367_get_fifo_watermark, NULL, 0); +static IIO_DEVICE_ATTR(hwfifo_enabled, 0444, + adxl367_get_fifo_enabled, NULL, 0); + +static const struct attribute *adxl367_fifo_attributes[] = { + &iio_const_attr_hwfifo_watermark_min.dev_attr.attr, + &iio_const_attr_hwfifo_watermark_max.dev_attr.attr, + &iio_dev_attr_hwfifo_watermark.dev_attr.attr, + &iio_dev_attr_hwfifo_enabled.dev_attr.attr, + NULL, +}; + +static int adxl367_set_watermark(struct iio_dev *indio_dev, unsigned int val) +{ + struct adxl367_state *st = iio_priv(indio_dev); + int ret; + + if (val > ADXL367_FIFO_MAX_WATERMARK) + return -EINVAL; + + mutex_lock(&st->lock); + + ret = adxl367_set_measure_en(st, false); + if (ret) + goto out; + + ret = adxl367_set_fifo_watermark(st, val); + if (ret) + goto out; + + ret = adxl367_set_measure_en(st, true); + +out: + mutex_unlock(&st->lock); + + return ret; +} + +static bool adxl367_find_mask_fifo_format(const unsigned long *scan_mask, + enum adxl367_fifo_format *fifo_format) +{ + size_t size = ARRAY_SIZE(adxl367_fifo_formats); + int i; + + for (i = 0; i < size; i++) + if (*scan_mask == adxl367_channel_masks[i]) + break; + + if (i == size) + return false; + + *fifo_format = adxl367_fifo_formats[i]; + + return true; +} + +static int adxl367_update_scan_mode(struct iio_dev *indio_dev, + const unsigned long *active_scan_mask) +{ + struct adxl367_state *st = iio_priv(indio_dev); + enum adxl367_fifo_format fifo_format; + unsigned int fifo_set_size; + int ret; + + if (!adxl367_find_mask_fifo_format(active_scan_mask, &fifo_format)) + return -EINVAL; + + fifo_set_size = bitmap_weight(active_scan_mask, indio_dev->masklength); + + mutex_lock(&st->lock); + + ret = adxl367_set_measure_en(st, false); + if (ret) + goto out; + + ret = adxl367_set_fifo_format(st, fifo_format); + if (ret) + goto out; + + ret = adxl367_set_fifo_set_size(st, fifo_set_size); + if (ret) + goto out; + + ret = adxl367_set_measure_en(st, true); + +out: + mutex_unlock(&st->lock); + + return ret; +} + +static int adxl367_buffer_postenable(struct iio_dev *indio_dev) +{ + struct adxl367_state *st = iio_priv(indio_dev); + int ret; + + mutex_lock(&st->lock); + + ret = adxl367_set_temp_adc_mask_en(st, indio_dev->active_scan_mask, + true); + if (ret) + goto out; + + ret = adxl367_set_measure_en(st, false); + if (ret) + goto out; + + ret = adxl367_set_fifo_watermark_interrupt_en(st, true); + if (ret) + goto out; + + ret = adxl367_set_fifo_mode(st, ADXL367_FIFO_MODE_STREAM); + if (ret) + goto out; + + ret = adxl367_set_measure_en(st, true); + +out: + mutex_unlock(&st->lock); + + return ret; +} + +static int adxl367_buffer_predisable(struct iio_dev *indio_dev) +{ + struct adxl367_state *st = iio_priv(indio_dev); + int ret; + + mutex_lock(&st->lock); + + ret = adxl367_set_measure_en(st, false); + if (ret) + goto out; + + ret = adxl367_set_fifo_mode(st, ADXL367_FIFO_MODE_DISABLED); + if (ret) + goto out; + + ret = adxl367_set_fifo_watermark_interrupt_en(st, false); + if (ret) + goto out; + + ret = adxl367_set_measure_en(st, true); + if (ret) + return ret; + + ret = adxl367_set_temp_adc_mask_en(st, indio_dev->active_scan_mask, + false); + +out: + mutex_unlock(&st->lock); + + return ret; +} + +static const struct iio_buffer_setup_ops adxl367_buffer_ops = { + .postenable = adxl367_buffer_postenable, + .predisable = adxl367_buffer_predisable, +}; + +static const struct iio_info adxl367_info = { + .read_raw = adxl367_read_raw, + .write_raw = adxl367_write_raw, + .write_raw_get_fmt = adxl367_write_raw_get_fmt, + .read_avail = adxl367_read_avail, + .read_event_config = adxl367_read_event_config, + .write_event_config = adxl367_write_event_config, + .read_event_value = adxl367_read_event_value, + .write_event_value = adxl367_write_event_value, + .debugfs_reg_access = adxl367_reg_access, + .hwfifo_set_watermark = adxl367_set_watermark, + .update_scan_mode = adxl367_update_scan_mode, +}; + +static const struct iio_event_spec adxl367_events[] = { + { + .type = IIO_EV_TYPE_MAG_REFERENCED, + .dir = IIO_EV_DIR_RISING, + .mask_shared_by_type = BIT(IIO_EV_INFO_ENABLE) | + BIT(IIO_EV_INFO_PERIOD) | + BIT(IIO_EV_INFO_VALUE), + }, + { + .type = IIO_EV_TYPE_MAG_REFERENCED, + .dir = IIO_EV_DIR_FALLING, + .mask_shared_by_type = BIT(IIO_EV_INFO_ENABLE) | + BIT(IIO_EV_INFO_PERIOD) | + BIT(IIO_EV_INFO_VALUE), + }, +}; + +#define ADXL367_ACCEL_CHANNEL(index, reg, axis) { \ + .type = IIO_ACCEL, \ + .address = (reg), \ + .modified = 1, \ + .channel2 = IIO_MOD_##axis, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ + .info_mask_shared_by_type_available = BIT(IIO_CHAN_INFO_SCALE), \ + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \ + .info_mask_shared_by_all_available = \ + BIT(IIO_CHAN_INFO_SAMP_FREQ), \ + .event_spec = adxl367_events, \ + .num_event_specs = ARRAY_SIZE(adxl367_events), \ + .scan_index = (index), \ + .scan_type = { \ + .sign = 's', \ + .realbits = 14, \ + .storagebits = 16, \ + .endianness = IIO_BE, \ + }, \ +} + +#define ADXL367_CHANNEL(index, reg, _type) { \ + .type = (_type), \ + .address = (reg), \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_OFFSET) | \ + BIT(IIO_CHAN_INFO_SCALE), \ + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \ + .scan_index = (index), \ + .scan_type = { \ + .sign = 's', \ + .realbits = 14, \ + .storagebits = 16, \ + .endianness = IIO_BE, \ + }, \ +} + +static const struct iio_chan_spec adxl367_channels[] = { + ADXL367_ACCEL_CHANNEL(ADXL367_X_CHANNEL_INDEX, ADXL367_REG_X_DATA_H, X), + ADXL367_ACCEL_CHANNEL(ADXL367_Y_CHANNEL_INDEX, ADXL367_REG_Y_DATA_H, Y), + ADXL367_ACCEL_CHANNEL(ADXL367_Z_CHANNEL_INDEX, ADXL367_REG_Z_DATA_H, Z), + ADXL367_CHANNEL(ADXL367_TEMP_CHANNEL_INDEX, ADXL367_REG_TEMP_DATA_H, + IIO_TEMP), + ADXL367_CHANNEL(ADXL367_EX_ADC_CHANNEL_INDEX, ADXL367_REG_EX_ADC_DATA_H, + IIO_VOLTAGE), +}; + +static int adxl367_verify_devid(struct adxl367_state *st) +{ + unsigned int val; + int ret; + + ret = regmap_read_poll_timeout(st->regmap, ADXL367_REG_DEVID, val, + val == ADXL367_DEVID_AD, 1000, 10000); + if (ret) + return dev_err_probe(st->dev, -ENODEV, + "Invalid dev id 0x%02X, expected 0x%02X\n", + val, ADXL367_DEVID_AD); + + return 0; +} + +static int adxl367_setup(struct adxl367_state *st) +{ + int ret; + + ret = _adxl367_set_act_threshold(st, ADXL367_ACTIVITY, + ADXL367_2G_RANGE_1G); + if (ret) + return ret; + + ret = _adxl367_set_act_threshold(st, ADXL367_INACTIVITY, + ADXL367_2G_RANGE_100MG); + if (ret) + return ret; + + ret = adxl367_set_act_proc_mode(st, ADXL367_LOOPED); + if (ret) + return ret; + + ret = _adxl367_set_odr(st, ADXL367_ODR_400HZ); + if (ret) + return ret; + + ret = _adxl367_set_act_time_ms(st, 10); + if (ret) + return ret; + + ret = _adxl367_set_inact_time_ms(st, 10000); + if (ret) + return ret; + + return adxl367_set_measure_en(st, true); +} + +static void adxl367_disable_regulators(void *data) +{ + struct adxl367_state *st = data; + + regulator_bulk_disable(ARRAY_SIZE(st->regulators), st->regulators); +} + +int adxl367_probe(struct device *dev, const struct adxl367_ops *ops, + void *context, struct regmap *regmap, int irq) +{ + struct iio_dev *indio_dev; + struct adxl367_state *st; + int ret; + + indio_dev = devm_iio_device_alloc(dev, sizeof(*st)); + if (!indio_dev) + return -ENOMEM; + + st = iio_priv(indio_dev); + st->dev = dev; + st->regmap = regmap; + st->context = context; + st->ops = ops; + + mutex_init(&st->lock); + + indio_dev->channels = adxl367_channels; + indio_dev->num_channels = ARRAY_SIZE(adxl367_channels); + indio_dev->available_scan_masks = adxl367_channel_masks; + indio_dev->name = "adxl367"; + indio_dev->info = &adxl367_info; + indio_dev->modes = INDIO_DIRECT_MODE; + + st->regulators[0].supply = "vdd"; + st->regulators[1].supply = "vddio"; + + ret = devm_regulator_bulk_get(st->dev, ARRAY_SIZE(st->regulators), + st->regulators); + if (ret) + return dev_err_probe(st->dev, ret, + "Failed to get regulators\n"); + + ret = regulator_bulk_enable(ARRAY_SIZE(st->regulators), st->regulators); + if (ret) + return dev_err_probe(st->dev, ret, + "Failed to enable regulators\n"); + + ret = devm_add_action_or_reset(st->dev, adxl367_disable_regulators, st); + if (ret) + return dev_err_probe(st->dev, ret, + "Failed to add regulators disable action\n"); + + ret = regmap_write(st->regmap, ADXL367_REG_RESET, ADXL367_RESET_CODE); + if (ret) + return ret; + + ret = adxl367_verify_devid(st); + if (ret) + return ret; + + ret = adxl367_setup(st); + if (ret) + return ret; + + ret = devm_iio_kfifo_buffer_setup_ext(st->dev, indio_dev, + INDIO_BUFFER_SOFTWARE, + &adxl367_buffer_ops, + adxl367_fifo_attributes); + if (ret) + return ret; + + ret = devm_request_threaded_irq(st->dev, irq, NULL, + adxl367_irq_handler, IRQF_ONESHOT, + indio_dev->name, indio_dev); + if (ret) + return dev_err_probe(st->dev, ret, "Failed to request irq\n"); + + return devm_iio_device_register(dev, indio_dev); +} +EXPORT_SYMBOL_NS_GPL(adxl367_probe, IIO_ADXL367); + +MODULE_AUTHOR("Cosmin Tanislav "); +MODULE_DESCRIPTION("Analog Devices ADXL367 3-axis accelerometer driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/accel/adxl367.h b/drivers/iio/accel/adxl367.h new file mode 100644 index 000000000000..4a42622149b1 --- /dev/null +++ b/drivers/iio/accel/adxl367.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (C) 2021 Analog Devices, Inc. + * Author: Cosmin Tanislav + */ + +#ifndef _ADXL367_H_ +#define _ADXL367_H_ + +#include + +struct device; +struct regmap; + +struct adxl367_ops { + int (*read_fifo)(void *context, __be16 *fifo_buf, + unsigned int fifo_entries); +}; + +int adxl367_probe(struct device *dev, const struct adxl367_ops *ops, + void *context, struct regmap *regmap, int irq); + +#endif /* _ADXL367_H_ */ diff --git a/drivers/iio/accel/adxl367_i2c.c b/drivers/iio/accel/adxl367_i2c.c new file mode 100644 index 000000000000..3606efa25835 --- /dev/null +++ b/drivers/iio/accel/adxl367_i2c.c @@ -0,0 +1,90 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2021 Analog Devices, Inc. + * Author: Cosmin Tanislav + */ + +#include +#include +#include +#include + +#include "adxl367.h" + +#define ADXL367_I2C_FIFO_DATA 0x42 + +struct adxl367_i2c_state { + struct regmap *regmap; +}; + +static bool adxl367_readable_noinc_reg(struct device *dev, unsigned int reg) +{ + return reg == ADXL367_I2C_FIFO_DATA; +} + +static int adxl367_i2c_read_fifo(void *context, __be16 *fifo_buf, + unsigned int fifo_entries) +{ + struct adxl367_i2c_state *st = context; + + return regmap_noinc_read(st->regmap, ADXL367_I2C_FIFO_DATA, fifo_buf, + fifo_entries * sizeof(*fifo_buf)); +} + +static const struct regmap_config adxl367_i2c_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .readable_noinc_reg = adxl367_readable_noinc_reg, +}; + +static const struct adxl367_ops adxl367_i2c_ops = { + .read_fifo = adxl367_i2c_read_fifo, +}; + +static int adxl367_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct adxl367_i2c_state *st; + struct regmap *regmap; + + st = devm_kzalloc(&client->dev, sizeof(*st), GFP_KERNEL); + if (!st) + return -ENOMEM; + + regmap = devm_regmap_init_i2c(client, &adxl367_i2c_regmap_config); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + st->regmap = regmap; + + return adxl367_probe(&client->dev, &adxl367_i2c_ops, st, regmap, + client->irq); +} + +static const struct i2c_device_id adxl367_i2c_id[] = { + { "adxl367", 0 }, + { }, +}; +MODULE_DEVICE_TABLE(i2c, adxl367_i2c_id); + +static const struct of_device_id adxl367_of_match[] = { + { .compatible = "adi,adxl367" }, + { }, +}; +MODULE_DEVICE_TABLE(of, adxl367_of_match); + +static struct i2c_driver adxl367_i2c_driver = { + .driver = { + .name = "adxl367_i2c", + .of_match_table = adxl367_of_match, + }, + .probe = adxl367_i2c_probe, + .id_table = adxl367_i2c_id, +}; + +module_i2c_driver(adxl367_i2c_driver); + +MODULE_IMPORT_NS(IIO_ADXL367); +MODULE_AUTHOR("Cosmin Tanislav "); +MODULE_DESCRIPTION("Analog Devices ADXL367 3-axis accelerometer I2C driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/accel/adxl367_spi.c b/drivers/iio/accel/adxl367_spi.c new file mode 100644 index 000000000000..26dfc821ebbe --- /dev/null +++ b/drivers/iio/accel/adxl367_spi.c @@ -0,0 +1,164 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2021 Analog Devices, Inc. + * Author: Cosmin Tanislav + */ + +#include +#include +#include +#include + +#include "adxl367.h" + +#define ADXL367_SPI_WRITE_COMMAND 0x0A +#define ADXL367_SPI_READ_COMMAND 0x0B +#define ADXL367_SPI_FIFO_COMMAND 0x0D + +struct adxl367_spi_state { + struct spi_device *spi; + + struct spi_message reg_write_msg; + struct spi_transfer reg_write_xfer[2]; + + struct spi_message reg_read_msg; + struct spi_transfer reg_read_xfer[2]; + + struct spi_message fifo_msg; + struct spi_transfer fifo_xfer[2]; + + /* + * DMA (thus cache coherency maintenance) requires the + * transfer buffers to live in their own cache lines. + */ + u8 reg_write_tx_buf[1] ____cacheline_aligned; + u8 reg_read_tx_buf[2]; + u8 fifo_tx_buf[1]; +}; + +static int adxl367_read_fifo(void *context, __be16 *fifo_buf, + unsigned int fifo_entries) +{ + struct adxl367_spi_state *st = context; + + st->fifo_xfer[1].rx_buf = fifo_buf; + st->fifo_xfer[1].len = fifo_entries * sizeof(*fifo_buf); + + return spi_sync(st->spi, &st->fifo_msg); +} + +static int adxl367_read(void *context, const void *reg_buf, size_t reg_size, + void *val_buf, size_t val_size) +{ + struct adxl367_spi_state *st = context; + u8 reg = ((const u8 *)reg_buf)[0]; + + st->reg_read_tx_buf[1] = reg; + st->reg_read_xfer[1].rx_buf = val_buf; + st->reg_read_xfer[1].len = val_size; + + return spi_sync(st->spi, &st->reg_read_msg); +} + +static int adxl367_write(void *context, const void *val_buf, size_t val_size) +{ + struct adxl367_spi_state *st = context; + + st->reg_write_xfer[1].tx_buf = val_buf; + st->reg_write_xfer[1].len = val_size; + + return spi_sync(st->spi, &st->reg_write_msg); +} + +static struct regmap_bus adxl367_spi_regmap_bus = { + .read = adxl367_read, + .write = adxl367_write, +}; + +static const struct regmap_config adxl367_spi_regmap_config = { + .reg_bits = 8, + .val_bits = 8, +}; + +static const struct adxl367_ops adxl367_spi_ops = { + .read_fifo = adxl367_read_fifo, +}; + +static int adxl367_spi_probe(struct spi_device *spi) +{ + struct adxl367_spi_state *st; + struct regmap *regmap; + + st = devm_kzalloc(&spi->dev, sizeof(*st), GFP_KERNEL); + if (!st) + return -ENOMEM; + + st->spi = spi; + + /* + * Xfer: [XFR1] [ XFR2 ] + * Master: 0x0A ADDR DATA0 DATA1 ... DATAN + * Slave: .... .......................... + */ + st->reg_write_tx_buf[0] = ADXL367_SPI_WRITE_COMMAND; + st->reg_write_xfer[0].tx_buf = st->reg_write_tx_buf; + st->reg_write_xfer[0].len = sizeof(st->reg_write_tx_buf); + spi_message_init_with_transfers(&st->reg_write_msg, + st->reg_write_xfer, 2); + + /* + * Xfer: [ XFR1 ] [ XFR2 ] + * Master: 0x0B ADDR ..................... + * Slave: ......... DATA0 DATA1 ... DATAN + */ + st->reg_read_tx_buf[0] = ADXL367_SPI_READ_COMMAND; + st->reg_read_xfer[0].tx_buf = st->reg_read_tx_buf; + st->reg_read_xfer[0].len = sizeof(st->reg_read_tx_buf); + spi_message_init_with_transfers(&st->reg_read_msg, + st->reg_read_xfer, 2); + + /* + * Xfer: [XFR1] [ XFR2 ] + * Master: 0x0D ..................... + * Slave: .... DATA0 DATA1 ... DATAN + */ + st->fifo_tx_buf[0] = ADXL367_SPI_FIFO_COMMAND; + st->fifo_xfer[0].tx_buf = st->fifo_tx_buf; + st->fifo_xfer[0].len = sizeof(st->fifo_tx_buf); + spi_message_init_with_transfers(&st->fifo_msg, st->fifo_xfer, 2); + + regmap = devm_regmap_init(&spi->dev, &adxl367_spi_regmap_bus, st, + &adxl367_spi_regmap_config); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + return adxl367_probe(&spi->dev, &adxl367_spi_ops, st, regmap, spi->irq); +} + +static const struct spi_device_id adxl367_spi_id[] = { + { "adxl367", 0 }, + { }, +}; +MODULE_DEVICE_TABLE(spi, adxl367_spi_id); + +static const struct of_device_id adxl367_of_match[] = { + { .compatible = "adi,adxl367" }, + { }, +}; +MODULE_DEVICE_TABLE(of, adxl367_of_match); + +static struct spi_driver adxl367_spi_driver = { + .driver = { + .name = "adxl367_spi", + .of_match_table = adxl367_of_match, + }, + .probe = adxl367_spi_probe, + .id_table = adxl367_spi_id, +}; + +module_spi_driver(adxl367_spi_driver); + +MODULE_IMPORT_NS(IIO_ADXL367); +MODULE_AUTHOR("Cosmin Tanislav "); +MODULE_DESCRIPTION("Analog Devices ADXL367 3-axis accelerometer SPI driver"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From f4eb9ac7842ff22370e262b8440edada40b1680a Mon Sep 17 00:00:00 2001 From: Antoniu Miclaus Date: Tue, 15 Feb 2022 10:12:13 +0200 Subject: iio: frequency: admv1014: add support for ADMV1014 The ADMV1014 is a silicon germanium (SiGe), wideband, microwave downconverter optimized for point to point microwave radio designs operating in the 24 GHz to 44 GHz frequency range. Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/ADMV1014.pdf Signed-off-by: Antoniu Miclaus Link: https://lore.kernel.org/r/20220215081216.67706-1-antoniu.miclaus@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/frequency/Kconfig | 10 + drivers/iio/frequency/Makefile | 1 + drivers/iio/frequency/admv1014.c | 823 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 834 insertions(+) create mode 100644 drivers/iio/frequency/admv1014.c diff --git a/drivers/iio/frequency/Kconfig b/drivers/iio/frequency/Kconfig index b44036f843af..5695ed478299 100644 --- a/drivers/iio/frequency/Kconfig +++ b/drivers/iio/frequency/Kconfig @@ -60,6 +60,16 @@ config ADMV1013 To compile this driver as a module, choose M here: the module will be called admv1013. +config ADMV1014 + tristate "Analog Devices ADMV1014 Microwave Downconverter" + depends on SPI && COMMON_CLK && 64BIT + help + Say yes here to build support for Analog Devices ADMV1014 + 24 GHz to 44 GHz, Wideband, Microwave Downconverter. + + To compile this driver as a module, choose M here: the + module will be called admv1014. + config ADRF6780 tristate "Analog Devices ADRF6780 Microwave Upconverter" depends on SPI diff --git a/drivers/iio/frequency/Makefile b/drivers/iio/frequency/Makefile index ae6899856c99..fc74f7029a5d 100644 --- a/drivers/iio/frequency/Makefile +++ b/drivers/iio/frequency/Makefile @@ -8,4 +8,5 @@ obj-$(CONFIG_AD9523) += ad9523.o obj-$(CONFIG_ADF4350) += adf4350.o obj-$(CONFIG_ADF4371) += adf4371.o obj-$(CONFIG_ADMV1013) += admv1013.o +obj-$(CONFIG_ADMV1014) += admv1014.o obj-$(CONFIG_ADRF6780) += adrf6780.o diff --git a/drivers/iio/frequency/admv1014.c b/drivers/iio/frequency/admv1014.c new file mode 100644 index 000000000000..a7994f8e6b9b --- /dev/null +++ b/drivers/iio/frequency/admv1014.c @@ -0,0 +1,823 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * ADMV1014 driver + * + * Copyright 2022 Analog Devices Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* ADMV1014 Register Map */ +#define ADMV1014_REG_SPI_CONTROL 0x00 +#define ADMV1014_REG_ALARM 0x01 +#define ADMV1014_REG_ALARM_MASKS 0x02 +#define ADMV1014_REG_ENABLE 0x03 +#define ADMV1014_REG_QUAD 0x04 +#define ADMV1014_REG_LO_AMP_PHASE_ADJUST1 0x05 +#define ADMV1014_REG_MIXER 0x07 +#define ADMV1014_REG_IF_AMP 0x08 +#define ADMV1014_REG_IF_AMP_BB_AMP 0x09 +#define ADMV1014_REG_BB_AMP_AGC 0x0A +#define ADMV1014_REG_VVA_TEMP_COMP 0x0B + +/* ADMV1014_REG_SPI_CONTROL Map */ +#define ADMV1014_PARITY_EN_MSK BIT(15) +#define ADMV1014_SPI_SOFT_RESET_MSK BIT(14) +#define ADMV1014_CHIP_ID_MSK GENMASK(11, 4) +#define ADMV1014_CHIP_ID 0x9 +#define ADMV1014_REVISION_ID_MSK GENMASK(3, 0) + +/* ADMV1014_REG_ALARM Map */ +#define ADMV1014_PARITY_ERROR_MSK BIT(15) +#define ADMV1014_TOO_FEW_ERRORS_MSK BIT(14) +#define ADMV1014_TOO_MANY_ERRORS_MSK BIT(13) +#define ADMV1014_ADDRESS_RANGE_ERROR_MSK BIT(12) + +/* ADMV1014_REG_ENABLE Map */ +#define ADMV1014_IBIAS_PD_MSK BIT(14) +#define ADMV1014_P1DB_COMPENSATION_MSK GENMASK(13, 12) +#define ADMV1014_IF_AMP_PD_MSK BIT(11) +#define ADMV1014_QUAD_BG_PD_MSK BIT(9) +#define ADMV1014_BB_AMP_PD_MSK BIT(8) +#define ADMV1014_QUAD_IBIAS_PD_MSK BIT(7) +#define ADMV1014_DET_EN_MSK BIT(6) +#define ADMV1014_BG_PD_MSK BIT(5) + +/* ADMV1014_REG_QUAD Map */ +#define ADMV1014_QUAD_SE_MODE_MSK GENMASK(9, 6) +#define ADMV1014_QUAD_FILTERS_MSK GENMASK(3, 0) + +/* ADMV1014_REG_LO_AMP_PHASE_ADJUST1 Map */ +#define ADMV1014_LOAMP_PH_ADJ_I_FINE_MSK GENMASK(15, 9) +#define ADMV1014_LOAMP_PH_ADJ_Q_FINE_MSK GENMASK(8, 2) + +/* ADMV1014_REG_MIXER Map */ +#define ADMV1014_MIXER_VGATE_MSK GENMASK(15, 9) +#define ADMV1014_DET_PROG_MSK GENMASK(6, 0) + +/* ADMV1014_REG_IF_AMP Map */ +#define ADMV1014_IF_AMP_COARSE_GAIN_I_MSK GENMASK(11, 8) +#define ADMV1014_IF_AMP_FINE_GAIN_Q_MSK GENMASK(7, 4) +#define ADMV1014_IF_AMP_FINE_GAIN_I_MSK GENMASK(3, 0) + +/* ADMV1014_REG_IF_AMP_BB_AMP Map */ +#define ADMV1014_IF_AMP_COARSE_GAIN_Q_MSK GENMASK(15, 12) +#define ADMV1014_BB_AMP_OFFSET_Q_MSK GENMASK(9, 5) +#define ADMV1014_BB_AMP_OFFSET_I_MSK GENMASK(4, 0) + +/* ADMV1014_REG_BB_AMP_AGC Map */ +#define ADMV1014_BB_AMP_REF_GEN_MSK GENMASK(6, 3) +#define ADMV1014_BB_AMP_GAIN_CTRL_MSK GENMASK(2, 1) +#define ADMV1014_BB_SWITCH_HIGH_LOW_CM_MSK BIT(0) + +/* ADMV1014_REG_VVA_TEMP_COMP Map */ +#define ADMV1014_VVA_TEMP_COMP_MSK GENMASK(15, 0) + +/* ADMV1014 Miscellaneous Defines */ +#define ADMV1014_READ BIT(7) +#define ADMV1014_REG_ADDR_READ_MSK GENMASK(6, 1) +#define ADMV1014_REG_ADDR_WRITE_MSK GENMASK(22, 17) +#define ADMV1014_REG_DATA_MSK GENMASK(16, 1) +#define ADMV1014_NUM_REGULATORS 9 + +enum { + ADMV1014_IQ_MODE, + ADMV1014_IF_MODE, +}; + +enum { + ADMV1014_SE_MODE_POS = 6, + ADMV1014_SE_MODE_NEG = 9, + ADMV1014_SE_MODE_DIFF = 12, +}; + +enum { + ADMV1014_CALIBSCALE_COARSE, + ADMV1014_CALIBSCALE_FINE, +}; + +static const int detector_table[] = {0, 1, 2, 4, 8, 16, 32, 64}; + +static const char * const input_mode_names[] = { "iq", "if" }; + +static const char * const quad_se_mode_names[] = { "se-pos", "se-neg", "diff" }; + +struct admv1014_state { + struct spi_device *spi; + struct clk *clkin; + struct notifier_block nb; + /* Protect against concurrent accesses to the device and to data*/ + struct mutex lock; + struct regulator_bulk_data regulators[ADMV1014_NUM_REGULATORS]; + unsigned int input_mode; + unsigned int quad_se_mode; + unsigned int p1db_comp; + bool det_en; + u8 data[3] ____cacheline_aligned; +}; + +static const int mixer_vgate_table[] = {106, 107, 108, 110, 111, 112, 113, 114, + 117, 118, 119, 120, 122, 123, 44, 45}; + +static int __admv1014_spi_read(struct admv1014_state *st, unsigned int reg, + unsigned int *val) +{ + struct spi_transfer t = {}; + int ret; + + st->data[0] = ADMV1014_READ | FIELD_PREP(ADMV1014_REG_ADDR_READ_MSK, reg); + st->data[1] = 0; + st->data[2] = 0; + + t.rx_buf = &st->data[0]; + t.tx_buf = &st->data[0]; + t.len = sizeof(st->data); + + ret = spi_sync_transfer(st->spi, &t, 1); + if (ret) + return ret; + + *val = FIELD_GET(ADMV1014_REG_DATA_MSK, get_unaligned_be24(&st->data[0])); + + return ret; +} + +static int admv1014_spi_read(struct admv1014_state *st, unsigned int reg, + unsigned int *val) +{ + int ret; + + mutex_lock(&st->lock); + ret = __admv1014_spi_read(st, reg, val); + mutex_unlock(&st->lock); + + return ret; +} + +static int __admv1014_spi_write(struct admv1014_state *st, + unsigned int reg, + unsigned int val) +{ + put_unaligned_be24(FIELD_PREP(ADMV1014_REG_DATA_MSK, val) | + FIELD_PREP(ADMV1014_REG_ADDR_WRITE_MSK, reg), &st->data[0]); + + return spi_write(st->spi, &st->data[0], 3); +} + +static int admv1014_spi_write(struct admv1014_state *st, unsigned int reg, + unsigned int val) +{ + int ret; + + mutex_lock(&st->lock); + ret = __admv1014_spi_write(st, reg, val); + mutex_unlock(&st->lock); + + return ret; +} + +static int __admv1014_spi_update_bits(struct admv1014_state *st, unsigned int reg, + unsigned int mask, unsigned int val) +{ + unsigned int data, temp; + int ret; + + ret = __admv1014_spi_read(st, reg, &data); + if (ret) + return ret; + + temp = (data & ~mask) | (val & mask); + + return __admv1014_spi_write(st, reg, temp); +} + +static int admv1014_spi_update_bits(struct admv1014_state *st, unsigned int reg, + unsigned int mask, unsigned int val) +{ + int ret; + + mutex_lock(&st->lock); + ret = __admv1014_spi_update_bits(st, reg, mask, val); + mutex_unlock(&st->lock); + + return ret; +} + +static int admv1014_update_quad_filters(struct admv1014_state *st) +{ + unsigned int filt_raw; + u64 rate = clk_get_rate(st->clkin); + + if (rate >= (5400 * HZ_PER_MHZ) && rate <= (7000 * HZ_PER_MHZ)) + filt_raw = 15; + else if (rate > (7000 * HZ_PER_MHZ) && rate <= (8000 * HZ_PER_MHZ)) + filt_raw = 10; + else if (rate > (8000 * HZ_PER_MHZ) && rate <= (9200 * HZ_PER_MHZ)) + filt_raw = 5; + else + filt_raw = 0; + + return __admv1014_spi_update_bits(st, ADMV1014_REG_QUAD, + ADMV1014_QUAD_FILTERS_MSK, + FIELD_PREP(ADMV1014_QUAD_FILTERS_MSK, filt_raw)); +} + +static int admv1014_update_vcm_settings(struct admv1014_state *st) +{ + unsigned int i, vcm_mv, vcm_comp, bb_sw_hl_cm; + int ret; + + vcm_mv = regulator_get_voltage(st->regulators[0].consumer) / 1000; + for (i = 0; i < ARRAY_SIZE(mixer_vgate_table); i++) { + vcm_comp = 1050 + mult_frac(i, 450, 8); + if (vcm_mv != vcm_comp) + continue; + + ret = __admv1014_spi_update_bits(st, ADMV1014_REG_MIXER, + ADMV1014_MIXER_VGATE_MSK, + FIELD_PREP(ADMV1014_MIXER_VGATE_MSK, + mixer_vgate_table[i])); + if (ret) + return ret; + + bb_sw_hl_cm = ~(i / 8); + bb_sw_hl_cm = FIELD_PREP(ADMV1014_BB_SWITCH_HIGH_LOW_CM_MSK, bb_sw_hl_cm); + + return __admv1014_spi_update_bits(st, ADMV1014_REG_BB_AMP_AGC, + ADMV1014_BB_AMP_REF_GEN_MSK | + ADMV1014_BB_SWITCH_HIGH_LOW_CM_MSK, + FIELD_PREP(ADMV1014_BB_AMP_REF_GEN_MSK, i) | + bb_sw_hl_cm); + } + + return -EINVAL; +} + +static int admv1014_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long info) +{ + struct admv1014_state *st = iio_priv(indio_dev); + unsigned int data; + int ret; + + switch (info) { + case IIO_CHAN_INFO_OFFSET: + ret = admv1014_spi_read(st, ADMV1014_REG_IF_AMP_BB_AMP, &data); + if (ret) + return ret; + + if (chan->channel2 == IIO_MOD_I) + *val = FIELD_GET(ADMV1014_BB_AMP_OFFSET_I_MSK, data); + else + *val = FIELD_GET(ADMV1014_BB_AMP_OFFSET_Q_MSK, data); + + return IIO_VAL_INT; + case IIO_CHAN_INFO_PHASE: + ret = admv1014_spi_read(st, ADMV1014_REG_LO_AMP_PHASE_ADJUST1, &data); + if (ret) + return ret; + + if (chan->channel2 == IIO_MOD_I) + *val = FIELD_GET(ADMV1014_LOAMP_PH_ADJ_I_FINE_MSK, data); + else + *val = FIELD_GET(ADMV1014_LOAMP_PH_ADJ_Q_FINE_MSK, data); + + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + ret = admv1014_spi_read(st, ADMV1014_REG_MIXER, &data); + if (ret) + return ret; + + *val = FIELD_GET(ADMV1014_DET_PROG_MSK, data); + return IIO_VAL_INT; + case IIO_CHAN_INFO_CALIBSCALE: + ret = admv1014_spi_read(st, ADMV1014_REG_BB_AMP_AGC, &data); + if (ret) + return ret; + + *val = FIELD_GET(ADMV1014_BB_AMP_GAIN_CTRL_MSK, data); + return IIO_VAL_INT; + default: + return -EINVAL; + } +} + +static int admv1014_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long info) +{ + int data; + unsigned int msk; + struct admv1014_state *st = iio_priv(indio_dev); + + switch (info) { + case IIO_CHAN_INFO_OFFSET: + if (chan->channel2 == IIO_MOD_I) { + msk = ADMV1014_BB_AMP_OFFSET_I_MSK; + data = FIELD_PREP(ADMV1014_BB_AMP_OFFSET_I_MSK, val); + } else { + msk = ADMV1014_BB_AMP_OFFSET_Q_MSK; + data = FIELD_PREP(ADMV1014_BB_AMP_OFFSET_Q_MSK, val); + } + + return admv1014_spi_update_bits(st, ADMV1014_REG_IF_AMP_BB_AMP, msk, data); + case IIO_CHAN_INFO_PHASE: + if (chan->channel2 == IIO_MOD_I) { + msk = ADMV1014_LOAMP_PH_ADJ_I_FINE_MSK; + data = FIELD_PREP(ADMV1014_LOAMP_PH_ADJ_I_FINE_MSK, val); + } else { + msk = ADMV1014_LOAMP_PH_ADJ_Q_FINE_MSK; + data = FIELD_PREP(ADMV1014_LOAMP_PH_ADJ_Q_FINE_MSK, val); + } + + return admv1014_spi_update_bits(st, ADMV1014_REG_LO_AMP_PHASE_ADJUST1, msk, data); + case IIO_CHAN_INFO_SCALE: + return admv1014_spi_update_bits(st, ADMV1014_REG_MIXER, + ADMV1014_DET_PROG_MSK, + FIELD_PREP(ADMV1014_DET_PROG_MSK, val)); + case IIO_CHAN_INFO_CALIBSCALE: + return admv1014_spi_update_bits(st, ADMV1014_REG_BB_AMP_AGC, + ADMV1014_BB_AMP_GAIN_CTRL_MSK, + FIELD_PREP(ADMV1014_BB_AMP_GAIN_CTRL_MSK, val)); + default: + return -EINVAL; + } +} + +static ssize_t admv1014_read(struct iio_dev *indio_dev, + uintptr_t private, + const struct iio_chan_spec *chan, + char *buf) +{ + struct admv1014_state *st = iio_priv(indio_dev); + unsigned int data; + int ret; + + switch (private) { + case ADMV1014_CALIBSCALE_COARSE: + if (chan->channel2 == IIO_MOD_I) { + ret = admv1014_spi_read(st, ADMV1014_REG_IF_AMP, &data); + if (ret) + return ret; + + data = FIELD_GET(ADMV1014_IF_AMP_COARSE_GAIN_I_MSK, data); + } else { + ret = admv1014_spi_read(st, ADMV1014_REG_IF_AMP_BB_AMP, &data); + if (ret) + return ret; + + data = FIELD_GET(ADMV1014_IF_AMP_COARSE_GAIN_Q_MSK, data); + } + break; + case ADMV1014_CALIBSCALE_FINE: + ret = admv1014_spi_read(st, ADMV1014_REG_IF_AMP, &data); + if (ret) + return ret; + + if (chan->channel2 == IIO_MOD_I) + data = FIELD_GET(ADMV1014_IF_AMP_FINE_GAIN_I_MSK, data); + else + data = FIELD_GET(ADMV1014_IF_AMP_FINE_GAIN_Q_MSK, data); + break; + default: + return -EINVAL; + } + + return sysfs_emit(buf, "%u\n", data); +} + +static ssize_t admv1014_write(struct iio_dev *indio_dev, + uintptr_t private, + const struct iio_chan_spec *chan, + const char *buf, size_t len) +{ + struct admv1014_state *st = iio_priv(indio_dev); + unsigned int data, addr, msk; + int ret; + + ret = kstrtouint(buf, 10, &data); + if (ret) + return ret; + + switch (private) { + case ADMV1014_CALIBSCALE_COARSE: + if (chan->channel2 == IIO_MOD_I) { + addr = ADMV1014_REG_IF_AMP; + msk = ADMV1014_IF_AMP_COARSE_GAIN_I_MSK; + data = FIELD_PREP(ADMV1014_IF_AMP_COARSE_GAIN_I_MSK, data); + } else { + addr = ADMV1014_REG_IF_AMP_BB_AMP; + msk = ADMV1014_IF_AMP_COARSE_GAIN_Q_MSK; + data = FIELD_PREP(ADMV1014_IF_AMP_COARSE_GAIN_Q_MSK, data); + } + break; + case ADMV1014_CALIBSCALE_FINE: + addr = ADMV1014_REG_IF_AMP; + + if (chan->channel2 == IIO_MOD_I) { + msk = ADMV1014_IF_AMP_FINE_GAIN_I_MSK; + data = FIELD_PREP(ADMV1014_IF_AMP_FINE_GAIN_I_MSK, data); + } else { + msk = ADMV1014_IF_AMP_FINE_GAIN_Q_MSK; + data = FIELD_PREP(ADMV1014_IF_AMP_FINE_GAIN_Q_MSK, data); + } + break; + default: + return -EINVAL; + } + + ret = admv1014_spi_update_bits(st, addr, msk, data); + + return ret ? ret : len; +} + +static int admv1014_read_avail(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + const int **vals, int *type, int *length, + long info) +{ + switch (info) { + case IIO_CHAN_INFO_SCALE: + *vals = detector_table; + *type = IIO_VAL_INT; + *length = ARRAY_SIZE(detector_table); + + return IIO_AVAIL_LIST; + default: + return -EINVAL; + } +} + +static int admv1014_reg_access(struct iio_dev *indio_dev, + unsigned int reg, + unsigned int write_val, + unsigned int *read_val) +{ + struct admv1014_state *st = iio_priv(indio_dev); + + if (read_val) + return admv1014_spi_read(st, reg, read_val); + else + return admv1014_spi_write(st, reg, write_val); +} + +static const struct iio_info admv1014_info = { + .read_raw = admv1014_read_raw, + .write_raw = admv1014_write_raw, + .read_avail = &admv1014_read_avail, + .debugfs_reg_access = &admv1014_reg_access, +}; + +static const char * const admv1014_reg_name[] = { + "vcm", "vcc-if-bb", "vcc-vga", "vcc-vva", "vcc-lna-3p3", + "vcc-lna-1p5", "vcc-bg", "vcc-quad", "vcc-mixer" +}; + +static int admv1014_freq_change(struct notifier_block *nb, unsigned long action, void *data) +{ + struct admv1014_state *st = container_of(nb, struct admv1014_state, nb); + int ret; + + if (action == POST_RATE_CHANGE) { + mutex_lock(&st->lock); + ret = notifier_from_errno(admv1014_update_quad_filters(st)); + mutex_unlock(&st->lock); + return ret; + } + + return NOTIFY_OK; +} + +#define _ADMV1014_EXT_INFO(_name, _shared, _ident) { \ + .name = _name, \ + .read = admv1014_read, \ + .write = admv1014_write, \ + .private = _ident, \ + .shared = _shared, \ +} + +static const struct iio_chan_spec_ext_info admv1014_ext_info[] = { + _ADMV1014_EXT_INFO("calibscale_coarse", IIO_SEPARATE, ADMV1014_CALIBSCALE_COARSE), + _ADMV1014_EXT_INFO("calibscale_fine", IIO_SEPARATE, ADMV1014_CALIBSCALE_FINE), + { } +}; + +#define ADMV1014_CHAN_IQ(_channel, rf_comp) { \ + .type = IIO_ALTVOLTAGE, \ + .modified = 1, \ + .output = 0, \ + .indexed = 1, \ + .channel2 = IIO_MOD_##rf_comp, \ + .channel = _channel, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_PHASE) | \ + BIT(IIO_CHAN_INFO_OFFSET), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_CALIBSCALE), \ + } + +#define ADMV1014_CHAN_IF(_channel, rf_comp) { \ + .type = IIO_ALTVOLTAGE, \ + .modified = 1, \ + .output = 0, \ + .indexed = 1, \ + .channel2 = IIO_MOD_##rf_comp, \ + .channel = _channel, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_PHASE) | \ + BIT(IIO_CHAN_INFO_OFFSET), \ + } + +#define ADMV1014_CHAN_POWER(_channel) { \ + .type = IIO_POWER, \ + .output = 0, \ + .indexed = 1, \ + .channel = _channel, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_SCALE), \ + .info_mask_shared_by_type_available = BIT(IIO_CHAN_INFO_SCALE), \ + } + +#define ADMV1014_CHAN_CALIBSCALE(_channel, rf_comp, _admv1014_ext_info) { \ + .type = IIO_ALTVOLTAGE, \ + .modified = 1, \ + .output = 0, \ + .indexed = 1, \ + .channel2 = IIO_MOD_##rf_comp, \ + .channel = _channel, \ + .ext_info = _admv1014_ext_info, \ + } + +static const struct iio_chan_spec admv1014_channels_iq[] = { + ADMV1014_CHAN_IQ(0, I), + ADMV1014_CHAN_IQ(0, Q), + ADMV1014_CHAN_POWER(0), +}; + +static const struct iio_chan_spec admv1014_channels_if[] = { + ADMV1014_CHAN_IF(0, I), + ADMV1014_CHAN_IF(0, Q), + ADMV1014_CHAN_CALIBSCALE(0, I, admv1014_ext_info), + ADMV1014_CHAN_CALIBSCALE(0, Q, admv1014_ext_info), + ADMV1014_CHAN_POWER(0), +}; + +static void admv1014_clk_disable(void *data) +{ + clk_disable_unprepare(data); +} + +static void admv1014_reg_disable(void *data) +{ + regulator_bulk_disable(ADMV1014_NUM_REGULATORS, data); +} + +static void admv1014_powerdown(void *data) +{ + unsigned int enable_reg, enable_reg_msk; + + /* Disable all components in the Enable Register */ + enable_reg_msk = ADMV1014_IBIAS_PD_MSK | + ADMV1014_IF_AMP_PD_MSK | + ADMV1014_QUAD_BG_PD_MSK | + ADMV1014_BB_AMP_PD_MSK | + ADMV1014_QUAD_IBIAS_PD_MSK | + ADMV1014_BG_PD_MSK; + + enable_reg = FIELD_PREP(ADMV1014_IBIAS_PD_MSK, 1) | + FIELD_PREP(ADMV1014_IF_AMP_PD_MSK, 1) | + FIELD_PREP(ADMV1014_QUAD_BG_PD_MSK, 1) | + FIELD_PREP(ADMV1014_BB_AMP_PD_MSK, 1) | + FIELD_PREP(ADMV1014_QUAD_IBIAS_PD_MSK, 1) | + FIELD_PREP(ADMV1014_BG_PD_MSK, 1); + + admv1014_spi_update_bits(data, ADMV1014_REG_ENABLE, + enable_reg_msk, enable_reg); +} + +static int admv1014_init(struct admv1014_state *st) +{ + unsigned int chip_id, enable_reg, enable_reg_msk; + struct spi_device *spi = st->spi; + int ret; + + ret = regulator_bulk_enable(ADMV1014_NUM_REGULATORS, st->regulators); + if (ret) { + dev_err(&spi->dev, "Failed to enable regulators"); + return ret; + } + + ret = devm_add_action_or_reset(&spi->dev, admv1014_reg_disable, st->regulators); + if (ret) + return ret; + + ret = clk_prepare_enable(st->clkin); + if (ret) + return ret; + + ret = devm_add_action_or_reset(&spi->dev, admv1014_clk_disable, st->clkin); + if (ret) + return ret; + + st->nb.notifier_call = admv1014_freq_change; + ret = devm_clk_notifier_register(&spi->dev, st->clkin, &st->nb); + if (ret) + return ret; + + ret = devm_add_action_or_reset(&spi->dev, admv1014_powerdown, st); + if (ret) + return ret; + + /* Perform a software reset */ + ret = __admv1014_spi_update_bits(st, ADMV1014_REG_SPI_CONTROL, + ADMV1014_SPI_SOFT_RESET_MSK, + FIELD_PREP(ADMV1014_SPI_SOFT_RESET_MSK, 1)); + if (ret) { + dev_err(&spi->dev, "ADMV1014 SPI software reset failed.\n"); + return ret; + } + + ret = __admv1014_spi_update_bits(st, ADMV1014_REG_SPI_CONTROL, + ADMV1014_SPI_SOFT_RESET_MSK, + FIELD_PREP(ADMV1014_SPI_SOFT_RESET_MSK, 0)); + if (ret) { + dev_err(&spi->dev, "ADMV1014 SPI software reset disable failed.\n"); + return ret; + } + + ret = __admv1014_spi_write(st, ADMV1014_REG_VVA_TEMP_COMP, 0x727C); + if (ret) { + dev_err(&spi->dev, "Writing default Temperature Compensation value failed.\n"); + return ret; + } + + ret = __admv1014_spi_read(st, ADMV1014_REG_SPI_CONTROL, &chip_id); + if (ret) + return ret; + + chip_id = FIELD_GET(ADMV1014_CHIP_ID_MSK, chip_id); + if (chip_id != ADMV1014_CHIP_ID) { + dev_err(&spi->dev, "Invalid Chip ID.\n"); + ret = -EINVAL; + return ret; + } + + ret = __admv1014_spi_update_bits(st, ADMV1014_REG_QUAD, + ADMV1014_QUAD_SE_MODE_MSK, + FIELD_PREP(ADMV1014_QUAD_SE_MODE_MSK, + st->quad_se_mode)); + if (ret) { + dev_err(&spi->dev, "Writing Quad SE Mode failed.\n"); + return ret; + } + + ret = admv1014_update_quad_filters(st); + if (ret) { + dev_err(&spi->dev, "Update Quad Filters failed.\n"); + return ret; + } + + ret = admv1014_update_vcm_settings(st); + if (ret) { + dev_err(&spi->dev, "Update VCM Settings failed.\n"); + return ret; + } + + enable_reg_msk = ADMV1014_P1DB_COMPENSATION_MSK | + ADMV1014_IF_AMP_PD_MSK | + ADMV1014_BB_AMP_PD_MSK | + ADMV1014_DET_EN_MSK; + + enable_reg = FIELD_PREP(ADMV1014_P1DB_COMPENSATION_MSK, st->p1db_comp ? 3 : 0) | + FIELD_PREP(ADMV1014_IF_AMP_PD_MSK, !(st->input_mode)) | + FIELD_PREP(ADMV1014_BB_AMP_PD_MSK, st->input_mode) | + FIELD_PREP(ADMV1014_DET_EN_MSK, st->det_en); + + return __admv1014_spi_update_bits(st, ADMV1014_REG_ENABLE, enable_reg_msk, enable_reg); +} + +static int admv1014_properties_parse(struct admv1014_state *st) +{ + const char *str; + unsigned int i; + struct spi_device *spi = st->spi; + int ret; + + st->det_en = device_property_read_bool(&spi->dev, "adi,detector-enable"); + + st->p1db_comp = device_property_read_bool(&spi->dev, "adi,p1db-compensation-enable"); + + ret = device_property_read_string(&spi->dev, "adi,input-mode", &str); + if (ret) { + st->input_mode = ADMV1014_IQ_MODE; + } else { + ret = match_string(input_mode_names, ARRAY_SIZE(input_mode_names), str); + if (ret < 0) + return ret; + + st->input_mode = ret; + } + + ret = device_property_read_string(&spi->dev, "adi,quad-se-mode", &str); + if (ret) { + st->quad_se_mode = ADMV1014_SE_MODE_POS; + } else { + ret = match_string(quad_se_mode_names, ARRAY_SIZE(quad_se_mode_names), str); + if (ret < 0) + return ret; + + st->quad_se_mode = ADMV1014_SE_MODE_POS + (ret * 3); + } + + for (i = 0; i < ADMV1014_NUM_REGULATORS; ++i) + st->regulators[i].supply = admv1014_reg_name[i]; + + ret = devm_regulator_bulk_get(&st->spi->dev, ADMV1014_NUM_REGULATORS, + st->regulators); + if (ret) { + dev_err(&spi->dev, "Failed to request regulators"); + return ret; + } + + st->clkin = devm_clk_get(&spi->dev, "lo_in"); + if (IS_ERR(st->clkin)) + return dev_err_probe(&spi->dev, PTR_ERR(st->clkin), + "failed to get the LO input clock\n"); + + return 0; +} + +static int admv1014_probe(struct spi_device *spi) +{ + struct iio_dev *indio_dev; + struct admv1014_state *st; + int ret; + + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); + if (!indio_dev) + return -ENOMEM; + + st = iio_priv(indio_dev); + + ret = admv1014_properties_parse(st); + if (ret) + return ret; + + indio_dev->info = &admv1014_info; + indio_dev->name = "admv1014"; + + if (st->input_mode == ADMV1014_IQ_MODE) { + indio_dev->channels = admv1014_channels_iq; + indio_dev->num_channels = ARRAY_SIZE(admv1014_channels_iq); + } else { + indio_dev->channels = admv1014_channels_if; + indio_dev->num_channels = ARRAY_SIZE(admv1014_channels_if); + } + + st->spi = spi; + + mutex_init(&st->lock); + + ret = admv1014_init(st); + if (ret) + return ret; + + return devm_iio_device_register(&spi->dev, indio_dev); +} + +static const struct spi_device_id admv1014_id[] = { + { "admv1014", 0 }, + {} +}; +MODULE_DEVICE_TABLE(spi, admv1014_id); + +static const struct of_device_id admv1014_of_match[] = { + { .compatible = "adi,admv1014" }, + {} +}; +MODULE_DEVICE_TABLE(of, admv1014_of_match); + +static struct spi_driver admv1014_driver = { + .driver = { + .name = "admv1014", + .of_match_table = admv1014_of_match, + }, + .probe = admv1014_probe, + .id_table = admv1014_id, +}; +module_spi_driver(admv1014_driver); + +MODULE_AUTHOR("Antoniu Miclaus Date: Tue, 15 Feb 2022 10:12:14 +0200 Subject: dt-bindings: iio: frequency: add admv1014 binding Add device tree bindings for the ADMV1014 Upconverter. Signed-off-by: Antoniu Miclaus Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20220215081216.67706-2-antoniu.miclaus@analog.com Signed-off-by: Jonathan Cameron --- .../bindings/iio/frequency/adi,admv1014.yaml | 134 +++++++++++++++++++++ 1 file changed, 134 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/frequency/adi,admv1014.yaml diff --git a/Documentation/devicetree/bindings/iio/frequency/adi,admv1014.yaml b/Documentation/devicetree/bindings/iio/frequency/adi,admv1014.yaml new file mode 100644 index 000000000000..2716c1e8fe31 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/frequency/adi,admv1014.yaml @@ -0,0 +1,134 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/frequency/adi,admv1014.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: ADMV1014 Microwave Downconverter + +maintainers: + - Antoniu Miclaus + +description: | + Wideband, microwave downconverter optimized for point to point microwave + radio designs operating in the 24 GHz to 44 GHz frequency range. + + https://www.analog.com/en/products/admv1014.html + +properties: + compatible: + enum: + - adi,admv1014 + + reg: + maxItems: 1 + + spi-max-frequency: + maximum: 1000000 + + clocks: + maxItems: 1 + + clock-names: + items: + - const: lo_in + description: + External clock that provides the Local Oscilator input. + + vcm-supply: + description: + Common-mode voltage regulator. + + vcc-if-bb-supply: + description: + BB and IF supply voltage regulator. + + vcc-vga-supply: + description: + RF Amplifier supply voltage regulator. + + vcc-vva-supply: + description: + VVA Control Circuit supply voltage regulator. + + vcc-lna-3p3-supply: + description: + Low Noise Amplifier 3.3V supply voltage regulator. + + vcc-lna-1p5-supply: + description: + Low Noise Amplifier 1.5V supply voltage regulator. + + vcc-bg-supply: + description: + Band Gap Circuit supply voltage regulator. + + vcc-quad-supply: + description: + Quadruple supply voltage regulator. + + vcc-mixer-supply: + description: + Mixer supply voltage regulator. + + adi,input-mode: + description: + Select the input mode. + iq - in-phase quadrature (I/Q) input + if - complex intermediate frequency (IF) input + enum: [iq, if] + + adi,detector-enable: + description: + Digital Rx Detector Enable. The Square Law Detector output is + available at output pin VDET. + type: boolean + + adi,p1db-compensation-enable: + description: + Turn on bits to optimize P1dB. + type: boolean + + adi,quad-se-mode: + description: + Switch the LO path from differential to single-ended operation. + se-neg - Single-Ended Mode, Negative Side Disabled. + se-pos - Single-Ended Mode, Positive Side Disabled. + diff - Differential Mode. + enum: [se-neg, se-pos, diff] + +required: + - compatible + - reg + - clocks + - clock-names + - vcm-supply + +additionalProperties: false + +examples: + - | + spi { + #address-cells = <1>; + #size-cells = <0>; + converter@0 { + compatible = "adi,admv1014"; + reg = <0>; + spi-max-frequency = <1000000>; + clocks = <&admv1014_lo>; + clock-names = "lo_in"; + vcm-supply = <&vcm>; + vcc-if-bb-supply = <&vcc_if_bb>; + vcc-vga-supply = <&vcc_vga>; + vcc-vva-supply = <&vcc_vva>; + vcc-lna-3p3-supply = <&vcc_lna_3p3>; + vcc-lna-1p5-supply = <&vcc_lna_1p5>; + vcc-bg-supply = <&vcc_bg>; + vcc-quad-supply = <&vcc_quad>; + vcc-mixer-supply = <&vcc_mixer>; + adi,quad-se-mode = "diff"; + adi,detector-enable; + adi,p1db-compensation-enable; + }; + }; +... -- cgit v1.2.3 From 0ac02bf5bd8e234f1dd44ca8c090e58b0b603d78 Mon Sep 17 00:00:00 2001 From: Antoniu Miclaus Date: Tue, 15 Feb 2022 10:12:15 +0200 Subject: Documentation: ABI: testing: admv1014: add ABI docs Add documentation for the use of the Digital Attenuator gain. Signed-off-by: Antoniu Miclaus Link: https://lore.kernel.org/r/20220215081216.67706-3-antoniu.miclaus@analog.com Signed-off-by: Jonathan Cameron --- Documentation/ABI/testing/sysfs-bus-iio | 1 + .../ABI/testing/sysfs-bus-iio-frequency-admv1014 | 23 ++++++++++++++++++++++ 2 files changed, 24 insertions(+) create mode 100644 Documentation/ABI/testing/sysfs-bus-iio-frequency-admv1014 diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio index bc98453bdade..d4ccc68fdcf0 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio +++ b/Documentation/ABI/testing/sysfs-bus-iio @@ -476,6 +476,7 @@ What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_i_calibscale What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_q_calibscale What: /sys/bus/iio/devices/iio:deviceX/in_voltage_i_calibscale What: /sys/bus/iio/devices/iio:deviceX/in_voltage_q_calibscale +What: /sys/bus/iio/devices/iio:deviceX/in_altvoltage_calibscale What: /sys/bus/iio/devices/iio:deviceX/in_voltage_calibscale What: /sys/bus/iio/devices/iio:deviceX/in_accel_x_calibscale What: /sys/bus/iio/devices/iio:deviceX/in_accel_y_calibscale diff --git a/Documentation/ABI/testing/sysfs-bus-iio-frequency-admv1014 b/Documentation/ABI/testing/sysfs-bus-iio-frequency-admv1014 new file mode 100644 index 000000000000..395010a0ef8b --- /dev/null +++ b/Documentation/ABI/testing/sysfs-bus-iio-frequency-admv1014 @@ -0,0 +1,23 @@ +What: /sys/bus/iio/devices/iio:deviceX/in_altvoltage0_i_calibscale_coarse +KernelVersion: 5.18 +Contact: linux-iio@vger.kernel.org +Description: + Read/write value for the digital attenuator gain (IF_I) with coarse steps. + +What: /sys/bus/iio/devices/iio:deviceX/in_altvoltage0_q_calibscale_coarse +KernelVersion: 5.18 +Contact: linux-iio@vger.kernel.org +Description: + Read/write value for the digital attenuator gain (IF_Q) with coarse steps. + +What: /sys/bus/iio/devices/iio:deviceX/in_altvoltage0_i_calibscale_fine +KernelVersion: 5.18 +Contact: linux-iio@vger.kernel.org +Description: + Read/write value for the digital attenuator gain (IF_I) with fine steps. + +What: /sys/bus/iio/devices/iio:deviceX/in_altvoltage0_q_calibscale_fine +KernelVersion: 5.18 +Contact: linux-iio@vger.kernel.org +Description: + Read/write value for the digital attenuator gain (IF_Q) with fine steps. -- cgit v1.2.3 From 2be8795a609800e5071d868d459ce29232fce2c8 Mon Sep 17 00:00:00 2001 From: Antoniu Miclaus Date: Tue, 15 Feb 2022 10:12:16 +0200 Subject: MAINTAINERS: add maintainer for ADMV1014 driver Add myself as maintainer for the ADMV1014 driver. Signed-off-by: Antoniu Miclaus Link: https://lore.kernel.org/r/20220215081216.67706-4-antoniu.miclaus@analog.com Signed-off-by: Jonathan Cameron --- MAINTAINERS | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 3b5393bb6fee..96e9243f0242 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1172,6 +1172,14 @@ W: https://ez.analog.com/linux-software-drivers F: Documentation/devicetree/bindings/iio/filter/adi,admv8818.yaml F: drivers/iio/filter/admv8818.c +ANALOG DEVICES INC ADMV1014 DRIVER +M: Antoniu Miclaus +L: linux-iio@vger.kernel.org +S: Supported +W: https://ez.analog.com/linux-software-drivers +F: Documentation/devicetree/bindings/iio/frequency/adi,admv1014.yaml +F: drivers/iio/frequency/admv1014.c + ANALOG DEVICES INC ADP5061 DRIVER M: Michael Hennerich L: linux-pm@vger.kernel.org -- cgit v1.2.3 From 2c43265516b5a507a2bc646453aafea8aaa304e7 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sun, 13 Feb 2022 19:29:05 +0100 Subject: iio: adc: xilinx-ams: Use devm_delayed_work_autocancel() to simplify code Use devm_delayed_work_autocancel() instead of hand writing it. This is less verbose and saves a few lines of code. devm_delayed_work_autocancel() uses devm_add_action() instead of devm_add_action_or_reset(). This is fine, because if the underlying memory allocation fails, no work has been scheduled yet. So there is nothing to undo. Signed-off-by: Christophe JAILLET Acked-by: Michal Simek Link: https://lore.kernel.org/r/2626e6a057e40cd2271ef0e5f81d12e607bad5b4.1644776929.git.christophe.jaillet@wanadoo.fr Signed-off-by: Jonathan Cameron --- drivers/iio/adc/xilinx-ams.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/drivers/iio/adc/xilinx-ams.c b/drivers/iio/adc/xilinx-ams.c index 8343c5f74121..6ffddf4038b8 100644 --- a/drivers/iio/adc/xilinx-ams.c +++ b/drivers/iio/adc/xilinx-ams.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -1348,11 +1349,6 @@ static void ams_clk_disable_unprepare(void *data) clk_disable_unprepare(data); } -static void ams_cancel_delayed_work(void *data) -{ - cancel_delayed_work(data); -} - static int ams_probe(struct platform_device *pdev) { struct iio_dev *indio_dev; @@ -1389,9 +1385,8 @@ static int ams_probe(struct platform_device *pdev) if (ret < 0) return ret; - INIT_DELAYED_WORK(&ams->ams_unmask_work, ams_unmask_worker); - ret = devm_add_action_or_reset(&pdev->dev, ams_cancel_delayed_work, - &ams->ams_unmask_work); + ret = devm_delayed_work_autocancel(&pdev->dev, &ams->ams_unmask_work, + ams_unmask_worker); if (ret < 0) return ret; -- cgit v1.2.3 From 7948d301c24887a27ff560ca91f8b4cf4cd8e0c8 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 24 Feb 2022 18:02:28 +0300 Subject: iio: accel: adxl367: unlock on error in adxl367_buffer_predisable() This error path needs to call the mutex_unlock(&st->lock) before returning. Fixes: cbab791c5e2a ("iio: accel: add ADXL367 driver") Signed-off-by: Dan Carpenter Reviewed-by: Cosmin Tanislav Link: https://lore.kernel.org/r/20220224150228.GB6856@kili Signed-off-by: Jonathan Cameron --- drivers/iio/accel/adxl367.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/accel/adxl367.c b/drivers/iio/accel/adxl367.c index b452d74b1d4d..bdc95409abed 100644 --- a/drivers/iio/accel/adxl367.c +++ b/drivers/iio/accel/adxl367.c @@ -1359,7 +1359,7 @@ static int adxl367_buffer_predisable(struct iio_dev *indio_dev) ret = adxl367_set_measure_en(st, true); if (ret) - return ret; + goto out; ret = adxl367_set_temp_adc_mask_en(st, indio_dev->active_scan_mask, false); -- cgit v1.2.3 From 185897d03ca3c4c98eff5cbf151671c5f88165fb Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Thu, 24 Feb 2022 14:10:34 -0700 Subject: iio: accel: adxl367: Fix handled initialization in adxl367_irq_handler() Clang warns: drivers/iio/accel/adxl367.c:887:2: error: variable 'handled' is uninitialized when used here [-Werror,-Wuninitialized] handled |= adxl367_push_event(indio_dev, status); ^~~~~~~ drivers/iio/accel/adxl367.c:879:14: note: initialize the variable 'handled' to silence this warning bool handled; ^ = 0 1 error generated. This should have used '=' instead of '|='; make that change to resolve the warning. Fixes: cbab791c5e2a ("iio: accel: add ADXL367 driver") Link: https://github.com/ClangBuiltLinux/linux/issues/1605 Reported-by: kernel test robot Reported-by: Colin Ian King Signed-off-by: Nathan Chancellor Link: https://lore.kernel.org/r/20220224211034.625130-1-nathan@kernel.org Signed-off-by: Jonathan Cameron --- drivers/iio/accel/adxl367.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/accel/adxl367.c b/drivers/iio/accel/adxl367.c index bdc95409abed..62960134ea19 100644 --- a/drivers/iio/accel/adxl367.c +++ b/drivers/iio/accel/adxl367.c @@ -884,7 +884,7 @@ static irqreturn_t adxl367_irq_handler(int irq, void *private) if (ret) return IRQ_NONE; - handled |= adxl367_push_event(indio_dev, status); + handled = adxl367_push_event(indio_dev, status); handled |= adxl367_push_fifo_data(indio_dev, status, fifo_entries); return handled ? IRQ_HANDLED : IRQ_NONE; -- cgit v1.2.3 From d3616e09baa5b3fe9b45270c60ef693879e215ff Mon Sep 17 00:00:00 2001 From: Jagath Jog J Date: Wed, 23 Feb 2022 22:05:19 +0530 Subject: iio: potentiometer: ds1803: Alignment to match the open parenthesis Fix following checkpatch.pl check by removing blank space. CHECK: Alignment should match open parenthesis. Signed-off-by: Jagath Jog J Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220223163525.13399-2-jagathjog1996@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/potentiometer/ds1803.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/drivers/iio/potentiometer/ds1803.c b/drivers/iio/potentiometer/ds1803.c index 20b45407eaac..3c542a50ece6 100644 --- a/drivers/iio/potentiometer/ds1803.c +++ b/drivers/iio/potentiometer/ds1803.c @@ -55,8 +55,8 @@ static const struct iio_chan_spec ds1803_channels[] = { }; static int ds1803_read_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int *val, int *val2, long mask) + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) { struct ds1803_data *data = iio_priv(indio_dev); int pot = chan->channel; @@ -66,7 +66,7 @@ static int ds1803_read_raw(struct iio_dev *indio_dev, switch (mask) { case IIO_CHAN_INFO_RAW: ret = i2c_master_recv(data->client, result, - indio_dev->num_channels); + indio_dev->num_channels); if (ret < 0) return ret; @@ -83,8 +83,8 @@ static int ds1803_read_raw(struct iio_dev *indio_dev, } static int ds1803_write_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int val, int val2, long mask) + struct iio_chan_spec const *chan, + int val, int val2, long mask) { struct ds1803_data *data = iio_priv(indio_dev); int pot = chan->channel; @@ -109,8 +109,7 @@ static const struct iio_info ds1803_info = { .write_raw = ds1803_write_raw, }; -static int ds1803_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int ds1803_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct device *dev = &client->dev; struct ds1803_data *data; -- cgit v1.2.3 From 4a68b326112a3afa57d580ccbaf892b1baf3ec35 Mon Sep 17 00:00:00 2001 From: Jagath Jog J Date: Wed, 23 Feb 2022 22:05:20 +0530 Subject: iio: potentiometer: ds1803: Add available functionality Adding available functionality for DS1803 driver which will show the minimum, step and maximum values that the driver can accepts through sysfs entry. Now using the max value present in avail array instead of chip type specific macro to make the driver flexible to add other type of potentiometer with different max position value. Signed-off-by: Jagath Jog J Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220223163525.13399-3-jagathjog1996@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/potentiometer/ds1803.c | 61 ++++++++++++++++++++++++++++---------- 1 file changed, 45 insertions(+), 16 deletions(-) diff --git a/drivers/iio/potentiometer/ds1803.c b/drivers/iio/potentiometer/ds1803.c index 3c542a50ece6..2861c4d39328 100644 --- a/drivers/iio/potentiometer/ds1803.c +++ b/drivers/iio/potentiometer/ds1803.c @@ -16,7 +16,6 @@ #include #include -#define DS1803_MAX_POS 255 #define DS1803_WRITE(chan) (0xa8 | ((chan) + 1)) enum ds1803_type { @@ -26,27 +25,23 @@ enum ds1803_type { }; struct ds1803_cfg { + int avail[3]; int kohms; }; -static const struct ds1803_cfg ds1803_cfg[] = { - [DS1803_010] = { .kohms = 10, }, - [DS1803_050] = { .kohms = 50, }, - [DS1803_100] = { .kohms = 100, }, -}; - struct ds1803_data { struct i2c_client *client; const struct ds1803_cfg *cfg; }; -#define DS1803_CHANNEL(ch) { \ - .type = IIO_RESISTANCE, \ - .indexed = 1, \ - .output = 1, \ - .channel = (ch), \ - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ - .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ +#define DS1803_CHANNEL(ch) { \ + .type = IIO_RESISTANCE, \ + .indexed = 1, \ + .output = 1, \ + .channel = (ch), \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ + .info_mask_shared_by_type_available = BIT(IIO_CHAN_INFO_RAW), \ } static const struct iio_chan_spec ds1803_channels[] = { @@ -54,6 +49,21 @@ static const struct iio_chan_spec ds1803_channels[] = { DS1803_CHANNEL(1), }; +static const struct ds1803_cfg ds1803_cfg[] = { + [DS1803_010] = { + .avail = { 0, 1, 255 }, + .kohms = 10, + }, + [DS1803_050] = { + .avail = { 0, 1, 255 }, + .kohms = 50, + }, + [DS1803_100] = { + .avail = { 0, 1, 255 }, + .kohms = 100, + }, +}; + static int ds1803_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, int *val2, long mask) @@ -75,7 +85,7 @@ static int ds1803_read_raw(struct iio_dev *indio_dev, case IIO_CHAN_INFO_SCALE: *val = 1000 * data->cfg->kohms; - *val2 = DS1803_MAX_POS; + *val2 = data->cfg->avail[2]; /* Max wiper position */ return IIO_VAL_FRACTIONAL; } @@ -88,13 +98,14 @@ static int ds1803_write_raw(struct iio_dev *indio_dev, { struct ds1803_data *data = iio_priv(indio_dev); int pot = chan->channel; + int max_pos = data->cfg->avail[2]; if (val2 != 0) return -EINVAL; switch (mask) { case IIO_CHAN_INFO_RAW: - if (val > DS1803_MAX_POS || val < 0) + if (val > max_pos || val < 0) return -EINVAL; break; default: @@ -104,9 +115,27 @@ static int ds1803_write_raw(struct iio_dev *indio_dev, return i2c_smbus_write_byte_data(data->client, DS1803_WRITE(pot), val); } +static int ds1803_read_avail(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + const int **vals, int *type, + int *length, long mask) +{ + struct ds1803_data *data = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_RAW: + *vals = data->cfg->avail; + *length = ARRAY_SIZE(data->cfg->avail); + *type = IIO_VAL_INT; + return IIO_AVAIL_RANGE; + } + return -EINVAL; +} + static const struct iio_info ds1803_info = { .read_raw = ds1803_read_raw, .write_raw = ds1803_write_raw, + .read_avail = ds1803_read_avail, }; static int ds1803_probe(struct i2c_client *client, const struct i2c_device_id *id) -- cgit v1.2.3 From a98d2b029b7c9ca6cf03cb816da3e8c4800882c6 Mon Sep 17 00:00:00 2001 From: Jagath Jog J Date: Wed, 23 Feb 2022 22:05:21 +0530 Subject: iio: potentiometer: ds1803: Add channel information in device data Adding each device wiper count and channel information into device private data. Utilizing addr member of struct iio_chan_spec to get the wiper register address so that the value can be read or write to the same address. Signed-off-by: Jagath Jog J Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220223163525.13399-4-jagathjog1996@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/potentiometer/ds1803.c | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/drivers/iio/potentiometer/ds1803.c b/drivers/iio/potentiometer/ds1803.c index 2861c4d39328..31ca87dcbf68 100644 --- a/drivers/iio/potentiometer/ds1803.c +++ b/drivers/iio/potentiometer/ds1803.c @@ -16,7 +16,8 @@ #include #include -#define DS1803_WRITE(chan) (0xa8 | ((chan) + 1)) +#define DS1803_WIPER_0 0xA9 +#define DS1803_WIPER_1 0xAA enum ds1803_type { DS1803_010, @@ -25,8 +26,11 @@ enum ds1803_type { }; struct ds1803_cfg { + int wipers; int avail[3]; int kohms; + const struct iio_chan_spec *channels; + u8 num_channels; }; struct ds1803_data { @@ -34,33 +38,43 @@ struct ds1803_data { const struct ds1803_cfg *cfg; }; -#define DS1803_CHANNEL(ch) { \ +#define DS1803_CHANNEL(ch, addr) { \ .type = IIO_RESISTANCE, \ .indexed = 1, \ .output = 1, \ .channel = (ch), \ + .address = (addr), \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ .info_mask_shared_by_type_available = BIT(IIO_CHAN_INFO_RAW), \ } static const struct iio_chan_spec ds1803_channels[] = { - DS1803_CHANNEL(0), - DS1803_CHANNEL(1), + DS1803_CHANNEL(0, DS1803_WIPER_0), + DS1803_CHANNEL(1, DS1803_WIPER_1), }; static const struct ds1803_cfg ds1803_cfg[] = { [DS1803_010] = { + .wipers = 2, .avail = { 0, 1, 255 }, .kohms = 10, + .channels = ds1803_channels, + .num_channels = ARRAY_SIZE(ds1803_channels), }, [DS1803_050] = { + .wipers = 2, .avail = { 0, 1, 255 }, .kohms = 50, + .channels = ds1803_channels, + .num_channels = ARRAY_SIZE(ds1803_channels), }, [DS1803_100] = { + .wipers = 2, .avail = { 0, 1, 255 }, .kohms = 100, + .channels = ds1803_channels, + .num_channels = ARRAY_SIZE(ds1803_channels), }, }; @@ -97,7 +111,7 @@ static int ds1803_write_raw(struct iio_dev *indio_dev, int val, int val2, long mask) { struct ds1803_data *data = iio_priv(indio_dev); - int pot = chan->channel; + u8 addr = chan->address; int max_pos = data->cfg->avail[2]; if (val2 != 0) @@ -112,7 +126,7 @@ static int ds1803_write_raw(struct iio_dev *indio_dev, return -EINVAL; } - return i2c_smbus_write_byte_data(data->client, DS1803_WRITE(pot), val); + return i2c_smbus_write_byte_data(data->client, addr, val); } static int ds1803_read_avail(struct iio_dev *indio_dev, @@ -155,8 +169,8 @@ static int ds1803_probe(struct i2c_client *client, const struct i2c_device_id *i data->cfg = &ds1803_cfg[id->driver_data]; indio_dev->info = &ds1803_info; - indio_dev->channels = ds1803_channels; - indio_dev->num_channels = ARRAY_SIZE(ds1803_channels); + indio_dev->channels = data->cfg->channels; + indio_dev->num_channels = data->cfg->num_channels; indio_dev->name = client->name; return devm_iio_device_register(dev, indio_dev); -- cgit v1.2.3 From 6450b62cb2f28c4a7faf0241fe43dc490e6ed856 Mon Sep 17 00:00:00 2001 From: Jagath Jog J Date: Wed, 23 Feb 2022 22:05:22 +0530 Subject: iio: potentiometer: ds1803: Change to firmware provided data Using firmware provided data to get the device specific structure if not available fall back to id->driver_data. Signed-off-by: Jagath Jog J Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220223163525.13399-5-jagathjog1996@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/potentiometer/ds1803.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/iio/potentiometer/ds1803.c b/drivers/iio/potentiometer/ds1803.c index 31ca87dcbf68..0c274ec75721 100644 --- a/drivers/iio/potentiometer/ds1803.c +++ b/drivers/iio/potentiometer/ds1803.c @@ -15,6 +15,7 @@ #include #include #include +#include #define DS1803_WIPER_0 0xA9 #define DS1803_WIPER_1 0xAA @@ -166,7 +167,9 @@ static int ds1803_probe(struct i2c_client *client, const struct i2c_device_id *i data = iio_priv(indio_dev); data->client = client; - data->cfg = &ds1803_cfg[id->driver_data]; + data->cfg = device_get_match_data(dev); + if (!data->cfg) + data->cfg = &ds1803_cfg[id->driver_data]; indio_dev->info = &ds1803_info; indio_dev->channels = data->cfg->channels; -- cgit v1.2.3 From 9b68725e90e44fdf54dd8838fb8105d1086b0211 Mon Sep 17 00:00:00 2001 From: Jagath Jog J Date: Wed, 23 Feb 2022 22:05:23 +0530 Subject: iio: potentiometer: ds1803: Add device specific read_raw function Added function pointer in the device specific structure to call the appropriate device read_raw function, so that the other type of devices with different read method can be handled. Signed-off-by: Jagath Jog J Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220223163525.13399-6-jagathjog1996@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/potentiometer/ds1803.c | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/drivers/iio/potentiometer/ds1803.c b/drivers/iio/potentiometer/ds1803.c index 0c274ec75721..017afa9fc83d 100644 --- a/drivers/iio/potentiometer/ds1803.c +++ b/drivers/iio/potentiometer/ds1803.c @@ -32,6 +32,8 @@ struct ds1803_cfg { int kohms; const struct iio_chan_spec *channels; u8 num_channels; + int (*read)(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int *val); }; struct ds1803_data { @@ -55,6 +57,22 @@ static const struct iio_chan_spec ds1803_channels[] = { DS1803_CHANNEL(1, DS1803_WIPER_1), }; +static int ds1803_read(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val) +{ + struct ds1803_data *data = iio_priv(indio_dev); + int ret; + u8 result[ARRAY_SIZE(ds1803_channels)]; + + ret = i2c_master_recv(data->client, result, indio_dev->num_channels); + if (ret < 0) + return ret; + + *val = result[chan->channel]; + return ret; +} + static const struct ds1803_cfg ds1803_cfg[] = { [DS1803_010] = { .wipers = 2, @@ -62,6 +80,7 @@ static const struct ds1803_cfg ds1803_cfg[] = { .kohms = 10, .channels = ds1803_channels, .num_channels = ARRAY_SIZE(ds1803_channels), + .read = ds1803_read, }, [DS1803_050] = { .wipers = 2, @@ -69,6 +88,7 @@ static const struct ds1803_cfg ds1803_cfg[] = { .kohms = 50, .channels = ds1803_channels, .num_channels = ARRAY_SIZE(ds1803_channels), + .read = ds1803_read, }, [DS1803_100] = { .wipers = 2, @@ -76,6 +96,7 @@ static const struct ds1803_cfg ds1803_cfg[] = { .kohms = 100, .channels = ds1803_channels, .num_channels = ARRAY_SIZE(ds1803_channels), + .read = ds1803_read, }, }; @@ -84,18 +105,14 @@ static int ds1803_read_raw(struct iio_dev *indio_dev, int *val, int *val2, long mask) { struct ds1803_data *data = iio_priv(indio_dev); - int pot = chan->channel; int ret; - u8 result[ARRAY_SIZE(ds1803_channels)]; switch (mask) { case IIO_CHAN_INFO_RAW: - ret = i2c_master_recv(data->client, result, - indio_dev->num_channels); + ret = data->cfg->read(indio_dev, chan, val); if (ret < 0) return ret; - *val = result[pot]; return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: -- cgit v1.2.3 From 73c169857c1294ce08ece597278003b795881eb1 Mon Sep 17 00:00:00 2001 From: Jagath Jog J Date: Wed, 23 Feb 2022 22:05:24 +0530 Subject: iio: potentiometer: ds1803: Add support for Maxim DS3502 The DS3502 is a 7-bit, nonvolatile digital potentiometer featuring an output voltage range of up to 15.5V. DS3502 support is added into existing DS1803 driver. Datasheet: https://datasheets.maximintegrated.com/en/ds/DS3502.pdf Signed-off-by: Jagath Jog J Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220223163525.13399-7-jagathjog1996@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/potentiometer/Kconfig | 6 +++--- drivers/iio/potentiometer/ds1803.c | 37 ++++++++++++++++++++++++++++++++++++- 2 files changed, 39 insertions(+), 4 deletions(-) diff --git a/drivers/iio/potentiometer/Kconfig b/drivers/iio/potentiometer/Kconfig index 832df8da2bc6..01dd3f858d99 100644 --- a/drivers/iio/potentiometer/Kconfig +++ b/drivers/iio/potentiometer/Kconfig @@ -27,11 +27,11 @@ config AD5272 module will be called ad5272. config DS1803 - tristate "Maxim Integrated DS1803 Digital Potentiometer driver" + tristate "Maxim Integrated DS1803 and similar Digital Potentiometer driver" depends on I2C help - Say yes here to build support for the Maxim Integrated DS1803 - digital potentiometer chip. + Say yes here to build support for the Maxim Integrated DS1803 and + DS3502 digital potentiometer chip. To compile this driver as a module, choose M here: the module will be called ds1803. diff --git a/drivers/iio/potentiometer/ds1803.c b/drivers/iio/potentiometer/ds1803.c index 017afa9fc83d..5c212ed7a931 100644 --- a/drivers/iio/potentiometer/ds1803.c +++ b/drivers/iio/potentiometer/ds1803.c @@ -1,12 +1,15 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Maxim Integrated DS1803 digital potentiometer driver + * Maxim Integrated DS1803 and similar digital potentiometer driver * Copyright (c) 2016 Slawomir Stepien + * Copyright (c) 2022 Jagath Jog J * * Datasheet: https://datasheets.maximintegrated.com/en/ds/DS1803.pdf + * Datasheet: https://datasheets.maximintegrated.com/en/ds/DS3502.pdf * * DEVID #Wipers #Positions Resistor Opts (kOhm) i2c address * ds1803 2 256 10, 50, 100 0101xxx + * ds3502 1 128 10 01010xx */ #include @@ -19,11 +22,13 @@ #define DS1803_WIPER_0 0xA9 #define DS1803_WIPER_1 0xAA +#define DS3502_WR_IVR 0x00 enum ds1803_type { DS1803_010, DS1803_050, DS1803_100, + DS3502, }; struct ds1803_cfg { @@ -57,6 +62,10 @@ static const struct iio_chan_spec ds1803_channels[] = { DS1803_CHANNEL(1, DS1803_WIPER_1), }; +static const struct iio_chan_spec ds3502_channels[] = { + DS1803_CHANNEL(0, DS3502_WR_IVR), +}; + static int ds1803_read(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val) @@ -73,6 +82,21 @@ static int ds1803_read(struct iio_dev *indio_dev, return ret; } +static int ds3502_read(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val) +{ + struct ds1803_data *data = iio_priv(indio_dev); + int ret; + + ret = i2c_smbus_read_byte_data(data->client, chan->address); + if (ret < 0) + return ret; + + *val = ret; + return ret; +} + static const struct ds1803_cfg ds1803_cfg[] = { [DS1803_010] = { .wipers = 2, @@ -98,6 +122,14 @@ static const struct ds1803_cfg ds1803_cfg[] = { .num_channels = ARRAY_SIZE(ds1803_channels), .read = ds1803_read, }, + [DS3502] = { + .wipers = 1, + .avail = { 0, 1, 127 }, + .kohms = 10, + .channels = ds3502_channels, + .num_channels = ARRAY_SIZE(ds3502_channels), + .read = ds3502_read, + }, }; static int ds1803_read_raw(struct iio_dev *indio_dev, @@ -200,6 +232,7 @@ static const struct of_device_id ds1803_dt_ids[] = { { .compatible = "maxim,ds1803-010", .data = &ds1803_cfg[DS1803_010] }, { .compatible = "maxim,ds1803-050", .data = &ds1803_cfg[DS1803_050] }, { .compatible = "maxim,ds1803-100", .data = &ds1803_cfg[DS1803_100] }, + { .compatible = "maxim,ds3502", .data = &ds1803_cfg[DS3502] }, {} }; MODULE_DEVICE_TABLE(of, ds1803_dt_ids); @@ -208,6 +241,7 @@ static const struct i2c_device_id ds1803_id[] = { { "ds1803-010", DS1803_010 }, { "ds1803-050", DS1803_050 }, { "ds1803-100", DS1803_100 }, + { "ds3502", DS3502 }, {} }; MODULE_DEVICE_TABLE(i2c, ds1803_id); @@ -224,5 +258,6 @@ static struct i2c_driver ds1803_driver = { module_i2c_driver(ds1803_driver); MODULE_AUTHOR("Slawomir Stepien "); +MODULE_AUTHOR("Jagath Jog J "); MODULE_DESCRIPTION("DS1803 digital potentiometer"); MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 10dce8deabb523b2cb43be517f6df89d25a11d27 Mon Sep 17 00:00:00 2001 From: Jagath Jog J Date: Wed, 23 Feb 2022 22:05:25 +0530 Subject: dt-bindings: iio: potentiometer: Add Maxim DS3502 in trivial-devices Maxim DS3502 is a 7 bit nonvolatile digital potentiometer. Add DS3502 binding into trivial-devices.yaml. Signed-off-by: Jagath Jog J Acked-by: Rob Herring Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220223163525.13399-8-jagathjog1996@gmail.com Signed-off-by: Jonathan Cameron --- Documentation/devicetree/bindings/trivial-devices.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/trivial-devices.yaml b/Documentation/devicetree/bindings/trivial-devices.yaml index 091792ba993e..b6187603317a 100644 --- a/Documentation/devicetree/bindings/trivial-devices.yaml +++ b/Documentation/devicetree/bindings/trivial-devices.yaml @@ -157,6 +157,8 @@ properties: - maxim,ds1803-050 # 100 kOhm digital potentiometer with I2C interface - maxim,ds1803-100 + # 10 kOhm digital potentiometer with I2C interface + - maxim,ds3502 # Low-Power, 4-/12-Channel, 2-Wire Serial, 12-Bit ADCs - maxim,max1237 # Temperature Sensor, I2C interface -- cgit v1.2.3 From b30537a4cedcacf0ade2f33ebb7610178ed1e7d7 Mon Sep 17 00:00:00 2001 From: Jiasheng Jiang Date: Thu, 24 Feb 2022 14:28:49 +0800 Subject: iio: adc: Add check for devm_request_threaded_irq As the potential failure of the devm_request_threaded_irq(), it should be better to check the return value and return error if fails. Fixes: fa659a40b80b ("iio: adc: twl6030-gpadc: Use devm_* API family") Signed-off-by: Jiasheng Jiang Link: https://lore.kernel.org/r/20220224062849.3280966-1-jiasheng@iscas.ac.cn Signed-off-by: Jonathan Cameron --- drivers/iio/adc/twl6030-gpadc.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/iio/adc/twl6030-gpadc.c b/drivers/iio/adc/twl6030-gpadc.c index 4966997b5319..f53e8558b560 100644 --- a/drivers/iio/adc/twl6030-gpadc.c +++ b/drivers/iio/adc/twl6030-gpadc.c @@ -911,6 +911,8 @@ static int twl6030_gpadc_probe(struct platform_device *pdev) ret = devm_request_threaded_irq(dev, irq, NULL, twl6030_gpadc_irq_handler, IRQF_ONESHOT, "twl6030_gpadc", indio_dev); + if (ret) + return ret; ret = twl6030_gpadc_enable_irq(TWL6030_GPADC_RT_SW1_EOC_MASK); if (ret < 0) { -- cgit v1.2.3 From 01676b0f3b625a9aa608d5b716898e9dba2fb63e Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 22 Feb 2022 11:00:02 +0200 Subject: iio: accel: adxl345: Convert to use dev_err_probe() It's fine to call dev_err_probe() in ->probe() when error code is known. Convert the driver to use dev_err_probe(). Signed-off-by: Andy Shevchenko Tested-by: Kai-Heng Feng Link: https://lore.kernel.org/r/20220222090009.2060-1-andriy.shevchenko@linux.intel.com Signed-off-by: Jonathan Cameron --- drivers/iio/accel/adxl345_core.c | 26 +++++++++----------------- drivers/iio/accel/adxl345_i2c.c | 7 ++----- drivers/iio/accel/adxl345_spi.c | 15 +++++---------- 3 files changed, 16 insertions(+), 32 deletions(-) diff --git a/drivers/iio/accel/adxl345_core.c b/drivers/iio/accel/adxl345_core.c index ef2240e356e0..078e1029e49d 100644 --- a/drivers/iio/accel/adxl345_core.c +++ b/drivers/iio/accel/adxl345_core.c @@ -222,16 +222,12 @@ int adxl345_core_probe(struct device *dev, struct regmap *regmap, int ret; ret = regmap_read(regmap, ADXL345_REG_DEVID, ®val); - if (ret < 0) { - dev_err(dev, "Error reading device ID: %d\n", ret); - return ret; - } + if (ret < 0) + return dev_err_probe(dev, ret, "Error reading device ID\n"); - if (regval != ADXL345_DEVID) { - dev_err(dev, "Invalid device ID: %x, expected %x\n", - regval, ADXL345_DEVID); - return -ENODEV; - } + if (regval != ADXL345_DEVID) + return dev_err_probe(dev, -ENODEV, "Invalid device ID: %x, expected %x\n", + regval, ADXL345_DEVID); indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); if (!indio_dev) @@ -245,10 +241,8 @@ int adxl345_core_probe(struct device *dev, struct regmap *regmap, ret = regmap_write(data->regmap, ADXL345_REG_DATA_FORMAT, data->data_range); - if (ret < 0) { - dev_err(dev, "Failed to set data range: %d\n", ret); - return ret; - } + if (ret < 0) + return dev_err_probe(dev, ret, "Failed to set data range\n"); indio_dev->name = name; indio_dev->info = &adxl345_info; @@ -259,10 +253,8 @@ int adxl345_core_probe(struct device *dev, struct regmap *regmap, /* Enable measurement mode */ ret = regmap_write(data->regmap, ADXL345_REG_POWER_CTL, ADXL345_POWER_CTL_MEASURE); - if (ret < 0) { - dev_err(dev, "Failed to enable measurement mode: %d\n", ret); - return ret; - } + if (ret < 0) + return dev_err_probe(dev, ret, "Failed to enable measurement mode\n"); ret = devm_add_action_or_reset(dev, adxl345_powerdown, data->regmap); if (ret < 0) diff --git a/drivers/iio/accel/adxl345_i2c.c b/drivers/iio/accel/adxl345_i2c.c index 7bc8324c4f07..e3205dce91b8 100644 --- a/drivers/iio/accel/adxl345_i2c.c +++ b/drivers/iio/accel/adxl345_i2c.c @@ -28,11 +28,8 @@ static int adxl345_i2c_probe(struct i2c_client *client, return -ENODEV; regmap = devm_regmap_init_i2c(client, &adxl345_i2c_regmap_config); - if (IS_ERR(regmap)) { - dev_err(&client->dev, "Error initializing i2c regmap: %ld\n", - PTR_ERR(regmap)); - return PTR_ERR(regmap); - } + if (IS_ERR(regmap)) + return dev_err_probe(&client->dev, PTR_ERR(regmap), "Error initializing regmap\n"); return adxl345_core_probe(&client->dev, regmap, id->driver_data, id->name); diff --git a/drivers/iio/accel/adxl345_spi.c b/drivers/iio/accel/adxl345_spi.c index c752562c5d3b..9223302fdd46 100644 --- a/drivers/iio/accel/adxl345_spi.c +++ b/drivers/iio/accel/adxl345_spi.c @@ -26,18 +26,13 @@ static int adxl345_spi_probe(struct spi_device *spi) struct regmap *regmap; /* Bail out if max_speed_hz exceeds 5 MHz */ - if (spi->max_speed_hz > ADXL345_MAX_SPI_FREQ_HZ) { - dev_err(&spi->dev, "SPI CLK, %d Hz exceeds 5 MHz\n", - spi->max_speed_hz); - return -EINVAL; - } + if (spi->max_speed_hz > ADXL345_MAX_SPI_FREQ_HZ) + return dev_err_probe(&spi->dev, -EINVAL, "SPI CLK, %d Hz exceeds 5 MHz\n", + spi->max_speed_hz); regmap = devm_regmap_init_spi(spi, &adxl345_spi_regmap_config); - if (IS_ERR(regmap)) { - dev_err(&spi->dev, "Error initializing spi regmap: %ld\n", - PTR_ERR(regmap)); - return PTR_ERR(regmap); - } + if (IS_ERR(regmap)) + return dev_err_probe(&spi->dev, PTR_ERR(regmap), "Error initializing regmap\n"); return adxl345_core_probe(&spi->dev, regmap, id->driver_data, id->name); } -- cgit v1.2.3 From 024f5d4f0ac087f73732a3084bdea5029ab0ca6b Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 22 Feb 2022 11:00:03 +0200 Subject: iio: accel: adxl345: Set driver_data for OF enumeration In order to enable this driver on mode platforms, assign driver_data field in the OF device ID table. While at it, make sure that device type is not 0 which may be wrongly interpreted by device property APIs in the future. Signed-off-by: Andy Shevchenko Tested-by: Kai-Heng Feng Link: https://lore.kernel.org/r/20220222090009.2060-2-andriy.shevchenko@linux.intel.com Signed-off-by: Jonathan Cameron --- drivers/iio/accel/adxl345.h | 4 ++-- drivers/iio/accel/adxl345_i2c.c | 4 ++-- drivers/iio/accel/adxl345_spi.c | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/iio/accel/adxl345.h b/drivers/iio/accel/adxl345.h index af0fdd02c4f2..5a68d4dac717 100644 --- a/drivers/iio/accel/adxl345.h +++ b/drivers/iio/accel/adxl345.h @@ -9,8 +9,8 @@ #define _ADXL345_H_ enum adxl345_device_type { - ADXL345, - ADXL375, + ADXL345 = 1, + ADXL375 = 2, }; int adxl345_core_probe(struct device *dev, struct regmap *regmap, diff --git a/drivers/iio/accel/adxl345_i2c.c b/drivers/iio/accel/adxl345_i2c.c index e3205dce91b8..4c6efe2eefc1 100644 --- a/drivers/iio/accel/adxl345_i2c.c +++ b/drivers/iio/accel/adxl345_i2c.c @@ -44,8 +44,8 @@ static const struct i2c_device_id adxl345_i2c_id[] = { MODULE_DEVICE_TABLE(i2c, adxl345_i2c_id); static const struct of_device_id adxl345_of_match[] = { - { .compatible = "adi,adxl345" }, - { .compatible = "adi,adxl375" }, + { .compatible = "adi,adxl345", .data = (const void *)ADXL345 }, + { .compatible = "adi,adxl375", .data = (const void *)ADXL375 }, { }, }; diff --git a/drivers/iio/accel/adxl345_spi.c b/drivers/iio/accel/adxl345_spi.c index 9223302fdd46..72550132b1bb 100644 --- a/drivers/iio/accel/adxl345_spi.c +++ b/drivers/iio/accel/adxl345_spi.c @@ -46,8 +46,8 @@ static const struct spi_device_id adxl345_spi_id[] = { MODULE_DEVICE_TABLE(spi, adxl345_spi_id); static const struct of_device_id adxl345_of_match[] = { - { .compatible = "adi,adxl345" }, - { .compatible = "adi,adxl375" }, + { .compatible = "adi,adxl345", .data = (const void *)ADXL345 }, + { .compatible = "adi,adxl375", .data = (const void *)ADXL375 }, { }, }; -- cgit v1.2.3 From c1db3d5cab03a79947736c44fd33f19f234b14a0 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 22 Feb 2022 11:00:04 +0200 Subject: iio: accel: adxl345: Get rid of name parameter in adxl345_core_probe() As a preparation to switch to use device properties, get rid of name parameter in adxl345_core_probe(). Instead, choose it based on the type. Signed-off-by: Andy Shevchenko Tested-by: Kai-Heng Feng Link: https://lore.kernel.org/r/20220222090009.2060-3-andriy.shevchenko@linux.intel.com Signed-off-by: Jonathan Cameron --- drivers/iio/accel/adxl345.h | 3 +-- drivers/iio/accel/adxl345_core.c | 15 +++++++++++++-- drivers/iio/accel/adxl345_i2c.c | 3 +-- drivers/iio/accel/adxl345_spi.c | 2 +- 4 files changed, 16 insertions(+), 7 deletions(-) diff --git a/drivers/iio/accel/adxl345.h b/drivers/iio/accel/adxl345.h index 5a68d4dac717..9b0d4f487c43 100644 --- a/drivers/iio/accel/adxl345.h +++ b/drivers/iio/accel/adxl345.h @@ -13,7 +13,6 @@ enum adxl345_device_type { ADXL375 = 2, }; -int adxl345_core_probe(struct device *dev, struct regmap *regmap, - enum adxl345_device_type type, const char *name); +int adxl345_core_probe(struct device *dev, struct regmap *regmap, enum adxl345_device_type type); #endif /* _ADXL345_H_ */ diff --git a/drivers/iio/accel/adxl345_core.c b/drivers/iio/accel/adxl345_core.c index 078e1029e49d..0f34c349aa1e 100644 --- a/drivers/iio/accel/adxl345_core.c +++ b/drivers/iio/accel/adxl345_core.c @@ -213,14 +213,25 @@ static void adxl345_powerdown(void *regmap) regmap_write(regmap, ADXL345_REG_POWER_CTL, ADXL345_POWER_CTL_STANDBY); } -int adxl345_core_probe(struct device *dev, struct regmap *regmap, - enum adxl345_device_type type, const char *name) +int adxl345_core_probe(struct device *dev, struct regmap *regmap, enum adxl345_device_type type) { struct adxl345_data *data; struct iio_dev *indio_dev; + const char *name; u32 regval; int ret; + switch (type) { + case ADXL345: + name = "adxl345"; + break; + case ADXL375: + name = "adxl375"; + break; + default: + return -EINVAL; + } + ret = regmap_read(regmap, ADXL345_REG_DEVID, ®val); if (ret < 0) return dev_err_probe(dev, ret, "Error reading device ID\n"); diff --git a/drivers/iio/accel/adxl345_i2c.c b/drivers/iio/accel/adxl345_i2c.c index 4c6efe2eefc1..1e42cf3a2991 100644 --- a/drivers/iio/accel/adxl345_i2c.c +++ b/drivers/iio/accel/adxl345_i2c.c @@ -31,8 +31,7 @@ static int adxl345_i2c_probe(struct i2c_client *client, if (IS_ERR(regmap)) return dev_err_probe(&client->dev, PTR_ERR(regmap), "Error initializing regmap\n"); - return adxl345_core_probe(&client->dev, regmap, id->driver_data, - id->name); + return adxl345_core_probe(&client->dev, regmap, id->driver_data); } static const struct i2c_device_id adxl345_i2c_id[] = { diff --git a/drivers/iio/accel/adxl345_spi.c b/drivers/iio/accel/adxl345_spi.c index 72550132b1bb..34b7001d519f 100644 --- a/drivers/iio/accel/adxl345_spi.c +++ b/drivers/iio/accel/adxl345_spi.c @@ -34,7 +34,7 @@ static int adxl345_spi_probe(struct spi_device *spi) if (IS_ERR(regmap)) return dev_err_probe(&spi->dev, PTR_ERR(regmap), "Error initializing regmap\n"); - return adxl345_core_probe(&spi->dev, regmap, id->driver_data, id->name); + return adxl345_core_probe(&spi->dev, regmap, id->driver_data); } static const struct spi_device_id adxl345_spi_id[] = { -- cgit v1.2.3 From 266be7cb11c75f930a5902bc6199ff50ca4282a1 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 22 Feb 2022 11:00:05 +0200 Subject: iio: accel: adxl345: Make use of device properties Convert the module to be property provider agnostic and allow it to be used on non-OF platforms. Signed-off-by: Andy Shevchenko Tested-by: Kai-Heng Feng Link: https://lore.kernel.org/r/20220222090009.2060-4-andriy.shevchenko@linux.intel.com Signed-off-by: Jonathan Cameron --- drivers/iio/accel/adxl345.h | 2 +- drivers/iio/accel/adxl345_core.c | 5 ++++- drivers/iio/accel/adxl345_i2c.c | 10 +++------- drivers/iio/accel/adxl345_spi.c | 3 +-- 4 files changed, 9 insertions(+), 11 deletions(-) diff --git a/drivers/iio/accel/adxl345.h b/drivers/iio/accel/adxl345.h index 9b0d4f487c43..d7e67cb08538 100644 --- a/drivers/iio/accel/adxl345.h +++ b/drivers/iio/accel/adxl345.h @@ -13,6 +13,6 @@ enum adxl345_device_type { ADXL375 = 2, }; -int adxl345_core_probe(struct device *dev, struct regmap *regmap, enum adxl345_device_type type); +int adxl345_core_probe(struct device *dev, struct regmap *regmap); #endif /* _ADXL345_H_ */ diff --git a/drivers/iio/accel/adxl345_core.c b/drivers/iio/accel/adxl345_core.c index 0f34c349aa1e..315a408115b3 100644 --- a/drivers/iio/accel/adxl345_core.c +++ b/drivers/iio/accel/adxl345_core.c @@ -8,6 +8,7 @@ */ #include +#include #include #include @@ -213,14 +214,16 @@ static void adxl345_powerdown(void *regmap) regmap_write(regmap, ADXL345_REG_POWER_CTL, ADXL345_POWER_CTL_STANDBY); } -int adxl345_core_probe(struct device *dev, struct regmap *regmap, enum adxl345_device_type type) +int adxl345_core_probe(struct device *dev, struct regmap *regmap) { + enum adxl345_device_type type; struct adxl345_data *data; struct iio_dev *indio_dev; const char *name; u32 regval; int ret; + type = (uintptr_t)device_get_match_data(dev); switch (type) { case ADXL345: name = "adxl345"; diff --git a/drivers/iio/accel/adxl345_i2c.c b/drivers/iio/accel/adxl345_i2c.c index 1e42cf3a2991..391910df8daa 100644 --- a/drivers/iio/accel/adxl345_i2c.c +++ b/drivers/iio/accel/adxl345_i2c.c @@ -19,19 +19,15 @@ static const struct regmap_config adxl345_i2c_regmap_config = { .val_bits = 8, }; -static int adxl345_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int adxl345_i2c_probe(struct i2c_client *client) { struct regmap *regmap; - if (!id) - return -ENODEV; - regmap = devm_regmap_init_i2c(client, &adxl345_i2c_regmap_config); if (IS_ERR(regmap)) return dev_err_probe(&client->dev, PTR_ERR(regmap), "Error initializing regmap\n"); - return adxl345_core_probe(&client->dev, regmap, id->driver_data); + return adxl345_core_probe(&client->dev, regmap); } static const struct i2c_device_id adxl345_i2c_id[] = { @@ -55,7 +51,7 @@ static struct i2c_driver adxl345_i2c_driver = { .name = "adxl345_i2c", .of_match_table = adxl345_of_match, }, - .probe = adxl345_i2c_probe, + .probe_new = adxl345_i2c_probe, .id_table = adxl345_i2c_id, }; diff --git a/drivers/iio/accel/adxl345_spi.c b/drivers/iio/accel/adxl345_spi.c index 34b7001d519f..ee4c50c8a95b 100644 --- a/drivers/iio/accel/adxl345_spi.c +++ b/drivers/iio/accel/adxl345_spi.c @@ -22,7 +22,6 @@ static const struct regmap_config adxl345_spi_regmap_config = { static int adxl345_spi_probe(struct spi_device *spi) { - const struct spi_device_id *id = spi_get_device_id(spi); struct regmap *regmap; /* Bail out if max_speed_hz exceeds 5 MHz */ @@ -34,7 +33,7 @@ static int adxl345_spi_probe(struct spi_device *spi) if (IS_ERR(regmap)) return dev_err_probe(&spi->dev, PTR_ERR(regmap), "Error initializing regmap\n"); - return adxl345_core_probe(&spi->dev, regmap, id->driver_data); + return adxl345_core_probe(&spi->dev, regmap); } static const struct spi_device_id adxl345_spi_id[] = { -- cgit v1.2.3 From b9493d595226b598ed79b3769f7038fda1a5391b Mon Sep 17 00:00:00 2001 From: Kai-Heng Feng Date: Tue, 22 Feb 2022 11:00:06 +0200 Subject: iio: accel: adxl345: Add ACPI HID table x86 boards may use ACPI HID "ADS0345" for adxl345 device. Analog replied: "ADS034X is not a valid PNP ID. ADS0345 would be. I'm not aware that this ID is already taken. Feel free to submit a mainline Linux input mailing list patch." So add an ACPI match table for that accordingly. Since ACPI device may not match to any I2C ID, use the name and type directly from ACPI ID table in absence of I2C ID. Suggested-by: Andy Shevchenko Signed-off-by: Kai-Heng Feng Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220222090009.2060-5-andriy.shevchenko@linux.intel.com Signed-off-by: Jonathan Cameron --- drivers/iio/accel/adxl345_i2c.c | 7 +++++++ drivers/iio/accel/adxl345_spi.c | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/drivers/iio/accel/adxl345_i2c.c b/drivers/iio/accel/adxl345_i2c.c index 391910df8daa..283edb0babb4 100644 --- a/drivers/iio/accel/adxl345_i2c.c +++ b/drivers/iio/accel/adxl345_i2c.c @@ -46,10 +46,17 @@ static const struct of_device_id adxl345_of_match[] = { MODULE_DEVICE_TABLE(of, adxl345_of_match); +static const struct acpi_device_id adxl345_acpi_match[] = { + { "ADS0345", ADXL345 }, + { } +}; +MODULE_DEVICE_TABLE(acpi, adxl345_acpi_match); + static struct i2c_driver adxl345_i2c_driver = { .driver = { .name = "adxl345_i2c", .of_match_table = adxl345_of_match, + .acpi_match_table = adxl345_acpi_match, }, .probe_new = adxl345_i2c_probe, .id_table = adxl345_i2c_id, diff --git a/drivers/iio/accel/adxl345_spi.c b/drivers/iio/accel/adxl345_spi.c index ee4c50c8a95b..850ac616d65e 100644 --- a/drivers/iio/accel/adxl345_spi.c +++ b/drivers/iio/accel/adxl345_spi.c @@ -52,10 +52,17 @@ static const struct of_device_id adxl345_of_match[] = { MODULE_DEVICE_TABLE(of, adxl345_of_match); +static const struct acpi_device_id adxl345_acpi_match[] = { + { "ADS0345", ADXL345 }, + { } +}; +MODULE_DEVICE_TABLE(acpi, adxl345_acpi_match); + static struct spi_driver adxl345_spi_driver = { .driver = { .name = "adxl345_spi", .of_match_table = adxl345_of_match, + .acpi_match_table = adxl345_acpi_match, }, .probe = adxl345_spi_probe, .id_table = adxl345_spi_id, -- cgit v1.2.3 From 5b4c63f691b848322166cace3be464a90b42065f Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 22 Feb 2022 11:00:07 +0200 Subject: iio: accel: adxl345: Extract adxl345_powerup() helper For the sake of symmetry and possible reuse in the future extract adxl435_powerup() helper. Signed-off-by: Andy Shevchenko Tested-by: Kai-Heng Feng Link: https://lore.kernel.org/r/20220222090009.2060-6-andriy.shevchenko@linux.intel.com Signed-off-by: Jonathan Cameron --- drivers/iio/accel/adxl345_core.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/iio/accel/adxl345_core.c b/drivers/iio/accel/adxl345_core.c index 315a408115b3..4e4562fc35c9 100644 --- a/drivers/iio/accel/adxl345_core.c +++ b/drivers/iio/accel/adxl345_core.c @@ -209,6 +209,11 @@ static const struct iio_info adxl345_info = { .write_raw_get_fmt = adxl345_write_raw_get_fmt, }; +static int adxl345_powerup(void *regmap) +{ + return regmap_write(regmap, ADXL345_REG_POWER_CTL, ADXL345_POWER_CTL_MEASURE); +} + static void adxl345_powerdown(void *regmap) { regmap_write(regmap, ADXL345_REG_POWER_CTL, ADXL345_POWER_CTL_STANDBY); @@ -265,8 +270,7 @@ int adxl345_core_probe(struct device *dev, struct regmap *regmap) indio_dev->num_channels = ARRAY_SIZE(adxl345_channels); /* Enable measurement mode */ - ret = regmap_write(data->regmap, ADXL345_REG_POWER_CTL, - ADXL345_POWER_CTL_MEASURE); + ret = adxl345_powerup(data->regmap); if (ret < 0) return dev_err_probe(dev, ret, "Failed to enable measurement mode\n"); -- cgit v1.2.3 From b8f83abdd2dd5bb71a0ffb62dbd3fbfdcf9d79f7 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 22 Feb 2022 11:00:08 +0200 Subject: iio: accel: adxl345: Drop comma in terminator entries Terminator entries are by definition should terminate the array. Dropping comma make this enforced at compile time. Signed-off-by: Andy Shevchenko Tested-by: Kai-Heng Feng Link: https://lore.kernel.org/r/20220222090009.2060-7-andriy.shevchenko@linux.intel.com Signed-off-by: Jonathan Cameron --- drivers/iio/accel/adxl345_core.c | 2 +- drivers/iio/accel/adxl345_i2c.c | 2 +- drivers/iio/accel/adxl345_spi.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/iio/accel/adxl345_core.c b/drivers/iio/accel/adxl345_core.c index 4e4562fc35c9..370bfec1275a 100644 --- a/drivers/iio/accel/adxl345_core.c +++ b/drivers/iio/accel/adxl345_core.c @@ -195,7 +195,7 @@ static IIO_CONST_ATTR_SAMP_FREQ_AVAIL( static struct attribute *adxl345_attrs[] = { &iio_const_attr_sampling_frequency_available.dev_attr.attr, - NULL, + NULL }; static const struct attribute_group adxl345_attrs_group = { diff --git a/drivers/iio/accel/adxl345_i2c.c b/drivers/iio/accel/adxl345_i2c.c index 283edb0babb4..fa91deaf5b4a 100644 --- a/drivers/iio/accel/adxl345_i2c.c +++ b/drivers/iio/accel/adxl345_i2c.c @@ -41,7 +41,7 @@ MODULE_DEVICE_TABLE(i2c, adxl345_i2c_id); static const struct of_device_id adxl345_of_match[] = { { .compatible = "adi,adxl345", .data = (const void *)ADXL345 }, { .compatible = "adi,adxl375", .data = (const void *)ADXL375 }, - { }, + { } }; MODULE_DEVICE_TABLE(of, adxl345_of_match); diff --git a/drivers/iio/accel/adxl345_spi.c b/drivers/iio/accel/adxl345_spi.c index 850ac616d65e..2f5fc565f1f4 100644 --- a/drivers/iio/accel/adxl345_spi.c +++ b/drivers/iio/accel/adxl345_spi.c @@ -47,7 +47,7 @@ MODULE_DEVICE_TABLE(spi, adxl345_spi_id); static const struct of_device_id adxl345_of_match[] = { { .compatible = "adi,adxl345", .data = (const void *)ADXL345 }, { .compatible = "adi,adxl375", .data = (const void *)ADXL375 }, - { }, + { } }; MODULE_DEVICE_TABLE(of, adxl345_of_match); -- cgit v1.2.3 From 4781f3e0e6cadf332f49f723ba820f35960a058d Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 22 Feb 2022 11:00:09 +0200 Subject: iio: accel: adxl345: Remove unneeded blank lines Remove unneeded blank lines where they separate the data type definitions and the macros which are using them. Signed-off-by: Andy Shevchenko Tested-by: Kai-Heng Feng Link: https://lore.kernel.org/r/20220222090009.2060-8-andriy.shevchenko@linux.intel.com Signed-off-by: Jonathan Cameron --- drivers/iio/accel/adxl345_i2c.c | 3 --- drivers/iio/accel/adxl345_spi.c | 3 --- 2 files changed, 6 deletions(-) diff --git a/drivers/iio/accel/adxl345_i2c.c b/drivers/iio/accel/adxl345_i2c.c index fa91deaf5b4a..098cd83f95b2 100644 --- a/drivers/iio/accel/adxl345_i2c.c +++ b/drivers/iio/accel/adxl345_i2c.c @@ -35,7 +35,6 @@ static const struct i2c_device_id adxl345_i2c_id[] = { { "adxl375", ADXL375 }, { } }; - MODULE_DEVICE_TABLE(i2c, adxl345_i2c_id); static const struct of_device_id adxl345_of_match[] = { @@ -43,7 +42,6 @@ static const struct of_device_id adxl345_of_match[] = { { .compatible = "adi,adxl375", .data = (const void *)ADXL375 }, { } }; - MODULE_DEVICE_TABLE(of, adxl345_of_match); static const struct acpi_device_id adxl345_acpi_match[] = { @@ -61,7 +59,6 @@ static struct i2c_driver adxl345_i2c_driver = { .probe_new = adxl345_i2c_probe, .id_table = adxl345_i2c_id, }; - module_i2c_driver(adxl345_i2c_driver); MODULE_AUTHOR("Eva Rachel Retuya "); diff --git a/drivers/iio/accel/adxl345_spi.c b/drivers/iio/accel/adxl345_spi.c index 2f5fc565f1f4..aaade5808657 100644 --- a/drivers/iio/accel/adxl345_spi.c +++ b/drivers/iio/accel/adxl345_spi.c @@ -41,7 +41,6 @@ static const struct spi_device_id adxl345_spi_id[] = { { "adxl375", ADXL375 }, { } }; - MODULE_DEVICE_TABLE(spi, adxl345_spi_id); static const struct of_device_id adxl345_of_match[] = { @@ -49,7 +48,6 @@ static const struct of_device_id adxl345_of_match[] = { { .compatible = "adi,adxl375", .data = (const void *)ADXL375 }, { } }; - MODULE_DEVICE_TABLE(of, adxl345_of_match); static const struct acpi_device_id adxl345_acpi_match[] = { @@ -67,7 +65,6 @@ static struct spi_driver adxl345_spi_driver = { .probe = adxl345_spi_probe, .id_table = adxl345_spi_id, }; - module_spi_driver(adxl345_spi_driver); MODULE_AUTHOR("Eva Rachel Retuya "); -- cgit v1.2.3 From 602744fa9f8b6160018ff29074ceb607d157395f Mon Sep 17 00:00:00 2001 From: Antoniu Miclaus Date: Wed, 23 Feb 2022 14:01:10 +0200 Subject: dt-bindings: iio: amplifiers: add ada4250 doc Add device tree bindings for the ADA4250 driver. Signed-off-by: Antoniu Miclaus Reviewed-by: Krzysztof Kozlowski Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20220223120112.8067-1-antoniu.miclaus@analog.com Signed-off-by: Jonathan Cameron --- .../bindings/iio/amplifiers/adi,ada4250.yaml | 50 ++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/amplifiers/adi,ada4250.yaml diff --git a/Documentation/devicetree/bindings/iio/amplifiers/adi,ada4250.yaml b/Documentation/devicetree/bindings/iio/amplifiers/adi,ada4250.yaml new file mode 100644 index 000000000000..5277479be382 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/amplifiers/adi,ada4250.yaml @@ -0,0 +1,50 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/amplifiers/adi,ada4250.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: ADA4250 Programmable Gain Instrumentation Amplifier + +maintainers: + - Antoniu Miclaus + +description: | + Precision Low Power, 110kHz, 26uA, Programmable Gain Instrumentation Amplifier. + +properties: + compatible: + enum: + - adi,ada4250 + + reg: + maxItems: 1 + + avdd-supply: true + + adi,refbuf-enable: + description: + Enable internal buffer to drive the reference pin. + type: boolean + + spi-max-frequency: true + +required: + - compatible + - reg + - avdd-supply + +additionalProperties: false + +examples: + - | + spi { + #address-cells = <1>; + #size-cells = <0>; + amplifier@0 { + compatible = "adi,ada4250"; + reg = <0>; + avdd-supply = <&avdd>; + }; + }; +... -- cgit v1.2.3 From 28b4c30bfa5f507879c4d55e1ff45c828875af64 Mon Sep 17 00:00:00 2001 From: Antoniu Miclaus Date: Wed, 23 Feb 2022 14:01:11 +0200 Subject: iio: amplifiers: ada4250: add support for ADA4250 The ADA4250 is an instrumentation amplifier with SPI/pin-strap progammable gains that is optimized for ultra-low power systems. With a minimum supply voltage of 1.7V, 26uA of quiescent current, a shutdown mode, a sleep mode, and a fast wake up settling time, ADA4250 can be power cycled on a battery powered system for even futher savings. Signed-off-by: Antoniu Miclaus Link: https://lore.kernel.org/r/20220223120112.8067-2-antoniu.miclaus@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/amplifiers/Kconfig | 11 ++ drivers/iio/amplifiers/Makefile | 1 + drivers/iio/amplifiers/ada4250.c | 403 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 415 insertions(+) create mode 100644 drivers/iio/amplifiers/ada4250.c diff --git a/drivers/iio/amplifiers/Kconfig b/drivers/iio/amplifiers/Kconfig index 5eb1357a9c78..f217a2a1e958 100644 --- a/drivers/iio/amplifiers/Kconfig +++ b/drivers/iio/amplifiers/Kconfig @@ -23,6 +23,17 @@ config AD8366 To compile this driver as a module, choose M here: the module will be called ad8366. +config ADA4250 + tristate "Analog Devices ADA4250 Instrumentation Amplifier" + depends on SPI + help + Say yes here to build support for Analog Devices ADA4250 + SPI Amplifier's support. The driver provides direct access via + sysfs. + + To compile this driver as a module, choose M here: the + module will be called ada4250. + config HMC425 tristate "Analog Devices HMC425A and similar GPIO Gain Amplifiers" depends on GPIOLIB diff --git a/drivers/iio/amplifiers/Makefile b/drivers/iio/amplifiers/Makefile index cb551d82f56b..2126331129cf 100644 --- a/drivers/iio/amplifiers/Makefile +++ b/drivers/iio/amplifiers/Makefile @@ -5,4 +5,5 @@ # When adding new entries keep the list in alphabetical order obj-$(CONFIG_AD8366) += ad8366.o +obj-$(CONFIG_ADA4250) += ada4250.o obj-$(CONFIG_HMC425) += hmc425a.o diff --git a/drivers/iio/amplifiers/ada4250.c b/drivers/iio/amplifiers/ada4250.c new file mode 100644 index 000000000000..4b32d350dc5d --- /dev/null +++ b/drivers/iio/amplifiers/ada4250.c @@ -0,0 +1,403 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * ADA4250 driver + * + * Copyright 2022 Analog Devices Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* ADA4250 Register Map */ +#define ADA4250_REG_GAIN_MUX 0x00 +#define ADA4250_REG_REFBUF_EN 0x01 +#define ADA4250_REG_RESET 0x02 +#define ADA4250_REG_SNSR_CAL_VAL 0x04 +#define ADA4250_REG_SNSR_CAL_CNFG 0x05 +#define ADA4250_REG_DIE_REV 0x18 +#define ADA4250_REG_CHIP_ID 0x19 + +/* ADA4250_REG_GAIN_MUX Map */ +#define ADA4250_GAIN_MUX_MSK GENMASK(2, 0) + +/* ADA4250_REG_REFBUF Map */ +#define ADA4250_REFBUF_MSK BIT(0) + +/* ADA4250_REG_RESET Map */ +#define ADA4250_RESET_MSK BIT(0) + +/* ADA4250_REG_SNSR_CAL_VAL Map */ +#define ADA4250_CAL_CFG_BIAS_MSK GENMASK(7, 0) + +/* ADA4250_REG_SNSR_CAL_CNFG Bit Definition */ +#define ADA4250_BIAS_SET_MSK GENMASK(3, 2) +#define ADA4250_RANGE_SET_MSK GENMASK(1, 0) + +/* Miscellaneous definitions */ +#define ADA4250_CHIP_ID 0x4250 +#define ADA4250_RANGE1 0 +#define ADA4250_RANGE4 3 + +/* ADA4250 current bias set */ +enum ada4250_current_bias { + ADA4250_BIAS_DISABLED, + ADA4250_BIAS_BANDGAP, + ADA4250_BIAS_AVDD, +}; + +struct ada4250_state { + struct spi_device *spi; + struct regmap *regmap; + struct regulator *reg; + /* Protect against concurrent accesses to the device and data content */ + struct mutex lock; + u8 bias; + u8 gain; + int offset_uv; + bool refbuf_en; +}; + +/* ADA4250 Current Bias Source Settings: Disabled, Bandgap Reference, AVDD */ +static const int calibbias_table[] = {0, 1, 2}; + +/* ADA4250 Gain (V/V) values: 1, 2, 4, 8, 16, 32, 64, 128 */ +static const int hwgain_table[] = {1, 2, 4, 8, 16, 32, 64, 128}; + +static const struct regmap_config ada4250_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .read_flag_mask = BIT(7), + .max_register = 0x1A, +}; + +static int ada4250_set_offset_uv(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + int offset_uv) +{ + struct ada4250_state *st = iio_priv(indio_dev); + + int i, ret, x[8], max_vos, min_vos, voltage_v, vlsb = 0; + u8 offset_raw, range = ADA4250_RANGE1; + u32 lsb_coeff[6] = {1333, 2301, 4283, 8289, 16311, 31599}; + + if (st->bias == 0 || st->bias == 3) + return -EINVAL; + + voltage_v = regulator_get_voltage(st->reg); + voltage_v = DIV_ROUND_CLOSEST(voltage_v, 1000000); + + if (st->bias == ADA4250_BIAS_AVDD) + x[0] = voltage_v; + else + x[0] = 5; + + x[1] = 126 * (x[0] - 1); + + for (i = 0; i < 6; i++) + x[i + 2] = DIV_ROUND_CLOSEST(x[1] * 1000, lsb_coeff[i]); + + if (st->gain == 0) + return -EINVAL; + + /* + * Compute Range and Voltage per LSB for the Sensor Offset Calibration + * Example of computation for Range 1 and Range 2 (Curren Bias Set = AVDD): + * Range 1 Range 2 + * Gain | Max Vos(mV) | LSB(mV) | Max Vos(mV) | LSB(mV) | + * 2 | X1*127 | X1=0.126(AVDD-1) | X1*3*127 | X1*3 | + * 4 | X2*127 | X2=X1/1.3333 | X2*3*127 | X2*3 | + * 8 | X3*127 | X3=X1/2.301 | X3*3*127 | X3*3 | + * 16 | X4*127 | X4=X1/4.283 | X4*3*127 | X4*3 | + * 32 | X5*127 | X5=X1/8.289 | X5*3*127 | X5*3 | + * 64 | X6*127 | X6=X1/16.311 | X6*3*127 | X6*3 | + * 128 | X7*127 | X7=X1/31.599 | X7*3*127 | X7*3 | + */ + for (i = ADA4250_RANGE1; i <= ADA4250_RANGE4; i++) { + max_vos = x[st->gain] * 127 * ((1 << (i + 1)) - 1); + min_vos = -1 * max_vos; + if (offset_uv > min_vos && offset_uv < max_vos) { + range = i; + vlsb = x[st->gain] * ((1 << (i + 1)) - 1); + break; + } + } + + if (vlsb <= 0) + return -EINVAL; + + offset_raw = DIV_ROUND_CLOSEST(abs(offset_uv), vlsb); + + mutex_lock(&st->lock); + ret = regmap_update_bits(st->regmap, ADA4250_REG_SNSR_CAL_CNFG, + ADA4250_RANGE_SET_MSK, + FIELD_PREP(ADA4250_RANGE_SET_MSK, range)); + if (ret) + goto exit; + + st->offset_uv = offset_raw * vlsb; + + /* + * To set the offset calibration value, use bits [6:0] and bit 7 as the + * polarity bit (set to "0" for a negative offset and "1" for a positive + * offset). + */ + if (offset_uv < 0) { + offset_raw |= BIT(7); + st->offset_uv *= (-1); + } + + ret = regmap_write(st->regmap, ADA4250_REG_SNSR_CAL_VAL, offset_raw); + +exit: + mutex_unlock(&st->lock); + + return ret; +} + +static int ada4250_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long info) +{ + struct ada4250_state *st = iio_priv(indio_dev); + int ret; + + switch (info) { + case IIO_CHAN_INFO_HARDWAREGAIN: + ret = regmap_read(st->regmap, ADA4250_REG_GAIN_MUX, val); + if (ret) + return ret; + + *val = BIT(*val); + + return IIO_VAL_INT; + case IIO_CHAN_INFO_OFFSET: + *val = st->offset_uv; + + return IIO_VAL_INT; + case IIO_CHAN_INFO_CALIBBIAS: + ret = regmap_read(st->regmap, ADA4250_REG_SNSR_CAL_CNFG, val); + if (ret) + return ret; + + *val = FIELD_GET(ADA4250_BIAS_SET_MSK, *val); + + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + *val = 1; + *val2 = 1000000; + + return IIO_VAL_FRACTIONAL; + default: + return -EINVAL; + } +} + +static int ada4250_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long info) +{ + struct ada4250_state *st = iio_priv(indio_dev); + int ret; + + switch (info) { + case IIO_CHAN_INFO_HARDWAREGAIN: + ret = regmap_write(st->regmap, ADA4250_REG_GAIN_MUX, + FIELD_PREP(ADA4250_GAIN_MUX_MSK, ilog2(val))); + if (ret) + return ret; + + st->gain = ilog2(val); + + return ret; + case IIO_CHAN_INFO_OFFSET: + return ada4250_set_offset_uv(indio_dev, chan, val); + case IIO_CHAN_INFO_CALIBBIAS: + ret = regmap_update_bits(st->regmap, ADA4250_REG_SNSR_CAL_CNFG, + ADA4250_BIAS_SET_MSK, + FIELD_PREP(ADA4250_BIAS_SET_MSK, val)); + if (ret) + return ret; + + st->bias = val; + + return ret; + default: + return -EINVAL; + } +} + +static int ada4250_read_avail(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + const int **vals, int *type, int *length, + long mask) +{ + switch (mask) { + case IIO_CHAN_INFO_CALIBBIAS: + *vals = calibbias_table; + *type = IIO_VAL_INT; + *length = ARRAY_SIZE(calibbias_table); + + return IIO_AVAIL_LIST; + case IIO_CHAN_INFO_HARDWAREGAIN: + *vals = hwgain_table; + *type = IIO_VAL_INT; + *length = ARRAY_SIZE(hwgain_table); + + return IIO_AVAIL_LIST; + default: + return -EINVAL; + } +} + +static int ada4250_reg_access(struct iio_dev *indio_dev, + unsigned int reg, + unsigned int write_val, + unsigned int *read_val) +{ + struct ada4250_state *st = iio_priv(indio_dev); + + if (read_val) + return regmap_read(st->regmap, reg, read_val); + else + return regmap_write(st->regmap, reg, write_val); +} + +static const struct iio_info ada4250_info = { + .read_raw = ada4250_read_raw, + .write_raw = ada4250_write_raw, + .read_avail = &ada4250_read_avail, + .debugfs_reg_access = &ada4250_reg_access, +}; + +static const struct iio_chan_spec ada4250_channels[] = { + { + .type = IIO_VOLTAGE, + .output = 1, + .indexed = 1, + .channel = 0, + .info_mask_separate = BIT(IIO_CHAN_INFO_HARDWAREGAIN) | + BIT(IIO_CHAN_INFO_OFFSET) | + BIT(IIO_CHAN_INFO_CALIBBIAS) | + BIT(IIO_CHAN_INFO_SCALE), + .info_mask_separate_available = BIT(IIO_CHAN_INFO_CALIBBIAS) | + BIT(IIO_CHAN_INFO_HARDWAREGAIN), + } +}; + +static void ada4250_reg_disable(void *data) +{ + regulator_disable(data); +} + +static int ada4250_init(struct ada4250_state *st) +{ + int ret; + u16 chip_id; + u8 data[2] __aligned(8) = {}; + struct spi_device *spi = st->spi; + + st->refbuf_en = device_property_read_bool(&spi->dev, "adi,refbuf-enable"); + + st->reg = devm_regulator_get(&spi->dev, "avdd"); + if (IS_ERR(st->reg)) + return dev_err_probe(&spi->dev, PTR_ERR(st->reg), + "failed to get the AVDD voltage\n"); + + ret = regulator_enable(st->reg); + if (ret) { + dev_err(&spi->dev, "Failed to enable specified AVDD supply\n"); + return ret; + } + + ret = devm_add_action_or_reset(&spi->dev, ada4250_reg_disable, st->reg); + if (ret) + return ret; + + ret = regmap_write(st->regmap, ADA4250_REG_RESET, + FIELD_PREP(ADA4250_RESET_MSK, 1)); + if (ret) + return ret; + + ret = regmap_bulk_read(st->regmap, ADA4250_REG_CHIP_ID, data, 2); + if (ret) + return ret; + + chip_id = get_unaligned_le16(data); + + if (chip_id != ADA4250_CHIP_ID) { + dev_err(&spi->dev, "Invalid chip ID.\n"); + return -EINVAL; + } + + return regmap_write(st->regmap, ADA4250_REG_REFBUF_EN, + FIELD_PREP(ADA4250_REFBUF_MSK, st->refbuf_en)); +} + +static int ada4250_probe(struct spi_device *spi) +{ + struct iio_dev *indio_dev; + struct regmap *regmap; + struct ada4250_state *st; + int ret; + + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); + if (!indio_dev) + return -ENOMEM; + + regmap = devm_regmap_init_spi(spi, &ada4250_regmap_config); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + st = iio_priv(indio_dev); + st->regmap = regmap; + st->spi = spi; + + indio_dev->info = &ada4250_info; + indio_dev->name = "ada4250"; + indio_dev->channels = ada4250_channels; + indio_dev->num_channels = ARRAY_SIZE(ada4250_channels); + + mutex_init(&st->lock); + + ret = ada4250_init(st); + if (ret) { + dev_err(&spi->dev, "ADA4250 init failed\n"); + return ret; + } + + return devm_iio_device_register(&spi->dev, indio_dev); +} + +static const struct spi_device_id ada4250_id[] = { + { "ada4250", 0 }, + {} +}; +MODULE_DEVICE_TABLE(spi, ada4250_id); + +static const struct of_device_id ada4250_of_match[] = { + { .compatible = "adi,ada4250" }, + {}, +}; +MODULE_DEVICE_TABLE(of, ada4250_of_match); + +static struct spi_driver ada4250_driver = { + .driver = { + .name = "ada4250", + .of_match_table = ada4250_of_match, + }, + .probe = ada4250_probe, + .id_table = ada4250_id, +}; +module_spi_driver(ada4250_driver); + +MODULE_AUTHOR("Antoniu Miclaus Date: Wed, 23 Feb 2022 14:01:12 +0200 Subject: MAINTAINERS: add maintainer for ADA4250 driver Add myself as maintainer for the ADA4250 driver. Signed-off-by: Antoniu Miclaus Link: https://lore.kernel.org/r/20220223120112.8067-3-antoniu.miclaus@analog.com Signed-off-by: Jonathan Cameron --- MAINTAINERS | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 96e9243f0242..22296c5f24de 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1109,6 +1109,14 @@ L: linux-media@vger.kernel.org S: Maintained F: drivers/media/i2c/ad9389b* +ANALOG DEVICES INC ADA4250 DRIVER +M: Antoniu Miclaus +L: linux-iio@vger.kernel.org +S: Supported +W: https://ez.analog.com/linux-software-drivers +F: Documentation/devicetree/bindings/iio/amplifiers/adi,ada4250.yaml +F: drivers/iio/amplifiers/ada4250.c + ANALOG DEVICES INC ADGS1408 DRIVER M: Mircea Caprioru S: Supported -- cgit v1.2.3 From bfdf1635a2d7cc0da1e1b4f2b68e3f20bf3bb16b Mon Sep 17 00:00:00 2001 From: Cristian Pop Date: Wed, 23 Feb 2022 15:08:07 +0200 Subject: dt-bindings: iio: frequency: Add ADMV4420 doc Add device tree bindings for the ADMV4420 K band downconverter. Signed-off-by: Cristian Pop Acked-by: Rob Herring Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20220223130808.13352-1-cristian.pop@analog.com Signed-off-by: Jonathan Cameron --- .../bindings/iio/frequency/adi,admv4420.yaml | 55 ++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/frequency/adi,admv4420.yaml diff --git a/Documentation/devicetree/bindings/iio/frequency/adi,admv4420.yaml b/Documentation/devicetree/bindings/iio/frequency/adi,admv4420.yaml new file mode 100644 index 000000000000..da7fe85ec92e --- /dev/null +++ b/Documentation/devicetree/bindings/iio/frequency/adi,admv4420.yaml @@ -0,0 +1,55 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/frequency/adi,admv4420.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: ADMV4420 K Band Downconverter + +maintainers: + - Cristian Pop + +description: + The ADMV4420 is a highly integrated, double balanced, active + mixer with an integrated fractional-N synthesizer, ideally suited + for next generation K band satellite communications + +properties: + compatible: + enum: + - adi,admv4420 + + reg: + maxItems: 1 + + spi-max-frequency: + maximum: 1000000 + + adi,lo-freq-khz: + description: LO Frequency + $ref: /schemas/types.yaml#/definitions/uint32 + + adi,ref-ext-single-ended-en: + description: External reference selected. + type: boolean + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + spi { + #address-cells = <1>; + #size-cells = <0>; + mixer@0 { + compatible = "adi,admv4420"; + reg = <0>; + spi-max-frequency = <1000000>; + adi,lo-freq-khz = <16750000>; + adi,ref-ext-single-ended-en; + }; + }; +... -- cgit v1.2.3 From b59c04155901fb47b4f7fe7d92447a5b0533c6c8 Mon Sep 17 00:00:00 2001 From: Cristian Pop Date: Wed, 23 Feb 2022 15:08:08 +0200 Subject: iio: frequency: admv4420.c: Add support for ADMV4420 Add support for K Band Downconverter with Integrated Fractional-N PLL and VCO. More info: https://www.analog.com/en/products/admv4420.html Signed-off-by: Cristian Pop Link: https://lore.kernel.org/r/20220223130808.13352-2-cristian.pop@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/frequency/Kconfig | 10 + drivers/iio/frequency/Makefile | 1 + drivers/iio/frequency/admv4420.c | 398 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 409 insertions(+) create mode 100644 drivers/iio/frequency/admv4420.c diff --git a/drivers/iio/frequency/Kconfig b/drivers/iio/frequency/Kconfig index 5695ed478299..f3702f36436c 100644 --- a/drivers/iio/frequency/Kconfig +++ b/drivers/iio/frequency/Kconfig @@ -70,6 +70,16 @@ config ADMV1014 To compile this driver as a module, choose M here: the module will be called admv1014. +config ADMV4420 + tristate "Analog Devices ADMV4420 K Band Downconverter" + depends on SPI + help + Say yes here to build support for Analog Devices K Band + Downconverter with integrated Fractional-N PLL and VCO. + + To compile this driver as a module, choose M here: the + module will be called admv4420. + config ADRF6780 tristate "Analog Devices ADRF6780 Microwave Upconverter" depends on SPI diff --git a/drivers/iio/frequency/Makefile b/drivers/iio/frequency/Makefile index fc74f7029a5d..48add732f1d3 100644 --- a/drivers/iio/frequency/Makefile +++ b/drivers/iio/frequency/Makefile @@ -9,4 +9,5 @@ obj-$(CONFIG_ADF4350) += adf4350.o obj-$(CONFIG_ADF4371) += adf4371.o obj-$(CONFIG_ADMV1013) += admv1013.o obj-$(CONFIG_ADMV1014) += admv1014.o +obj-$(CONFIG_ADMV4420) += admv4420.o obj-$(CONFIG_ADRF6780) += adrf6780.o diff --git a/drivers/iio/frequency/admv4420.c b/drivers/iio/frequency/admv4420.c new file mode 100644 index 000000000000..51134aee8510 --- /dev/null +++ b/drivers/iio/frequency/admv4420.c @@ -0,0 +1,398 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause +/* + * ADMV4420 + * + * Copyright 2021 Analog Devices Inc. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +/* ADMV4420 Register Map */ +#define ADMV4420_SPI_CONFIG_1 0x00 +#define ADMV4420_SPI_CONFIG_2 0x01 +#define ADMV4420_CHIPTYPE 0x03 +#define ADMV4420_PRODUCT_ID_L 0x04 +#define ADMV4420_PRODUCT_ID_H 0x05 +#define ADMV4420_SCRATCHPAD 0x0A +#define ADMV4420_SPI_REV 0x0B +#define ADMV4420_ENABLES 0x103 +#define ADMV4420_SDO_LEVEL 0x108 +#define ADMV4420_INT_L 0x200 +#define ADMV4420_INT_H 0x201 +#define ADMV4420_FRAC_L 0x202 +#define ADMV4420_FRAC_M 0x203 +#define ADMV4420_FRAC_H 0x204 +#define ADMV4420_MOD_L 0x208 +#define ADMV4420_MOD_M 0x209 +#define ADMV4420_MOD_H 0x20A +#define ADMV4420_R_DIV_L 0x20C +#define ADMV4420_R_DIV_H 0x20D +#define ADMV4420_REFERENCE 0x20E +#define ADMV4420_VCO_DATA_READBACK1 0x211 +#define ADMV4420_VCO_DATA_READBACK2 0x212 +#define ADMV4420_PLL_MUX_SEL 0x213 +#define ADMV4420_LOCK_DETECT 0x214 +#define ADMV4420_BAND_SELECT 0x215 +#define ADMV4420_VCO_ALC_TIMEOUT 0x216 +#define ADMV4420_VCO_MANUAL 0x217 +#define ADMV4420_ALC 0x219 +#define ADMV4420_VCO_TIMEOUT1 0x21C +#define ADMV4420_VCO_TIMEOUT2 0x21D +#define ADMV4420_VCO_BAND_DIV 0x21E +#define ADMV4420_VCO_READBACK_SEL 0x21F +#define ADMV4420_AUTOCAL 0x226 +#define ADMV4420_CP_STATE 0x22C +#define ADMV4420_CP_BLEED_EN 0x22D +#define ADMV4420_CP_CURRENT 0x22E +#define ADMV4420_CP_BLEED 0x22F + +#define ADMV4420_SPI_CONFIG_1_SDOACTIVE (BIT(4) | BIT(3)) +#define ADMV4420_SPI_CONFIG_1_ENDIAN (BIT(5) | BIT(2)) +#define ADMV4420_SPI_CONFIG_1_SOFTRESET (BIT(7) | BIT(1)) + +#define ADMV4420_REFERENCE_DIVIDE_BY_2_MASK BIT(0) +#define ADMV4420_REFERENCE_MODE_MASK BIT(1) +#define ADMV4420_REFERENCE_DOUBLER_MASK BIT(2) + +#define ADMV4420_REF_DIVIDER_MAX_VAL GENMASK(9, 0) +#define ADMV4420_N_COUNTER_INT_MAX GENMASK(15, 0) +#define ADMV4420_N_COUNTER_FRAC_MAX GENMASK(23, 0) +#define ADMV4420_N_COUNTER_MOD_MAX GENMASK(23, 0) + +#define ENABLE_PLL BIT(6) +#define ENABLE_LO BIT(5) +#define ENABLE_VCO BIT(3) +#define ENABLE_IFAMP BIT(2) +#define ENABLE_MIXER BIT(1) +#define ENABLE_LNA BIT(0) + +#define ADMV4420_SCRATCH_PAD_VAL_1 0xAD +#define ADMV4420_SCRATCH_PAD_VAL_2 0xEA + +#define ADMV4420_REF_FREQ_HZ 50000000 +#define MAX_N_COUNTER 655360UL +#define MAX_R_DIVIDER 1024 +#define ADMV4420_DEFAULT_LO_FREQ_HZ 16750000000ULL + +enum admv4420_mux_sel { + ADMV4420_LOW = 0, + ADMV4420_LOCK_DTCT = 1, + ADMV4420_R_COUNTER_PER_2 = 4, + ADMV4420_N_CONUTER_PER_2 = 5, + ADMV4420_HIGH = 8, +}; + +struct admv4420_reference_block { + bool doubler_en; + bool divide_by_2_en; + bool ref_single_ended; + u32 divider; +}; + +struct admv4420_n_counter { + u32 int_val; + u32 frac_val; + u32 mod_val; + u32 n_counter; +}; + +struct admv4420_state { + struct spi_device *spi; + struct regmap *regmap; + u64 vco_freq_hz; + u64 lo_freq_hz; + struct admv4420_reference_block ref_block; + struct admv4420_n_counter n_counter; + enum admv4420_mux_sel mux_sel; + struct mutex lock; + u8 transf_buf[4] ____cacheline_aligned; +}; + +static const struct regmap_config admv4420_regmap_config = { + .reg_bits = 16, + .val_bits = 8, + .read_flag_mask = BIT(7), +}; + +static int admv4420_reg_access(struct iio_dev *indio_dev, + u32 reg, u32 writeval, + u32 *readval) +{ + struct admv4420_state *st = iio_priv(indio_dev); + + if (readval) + return regmap_read(st->regmap, reg, readval); + else + return regmap_write(st->regmap, reg, writeval); +} + +static int admv4420_set_n_counter(struct admv4420_state *st, u32 int_val, + u32 frac_val, u32 mod_val) +{ + int ret; + + put_unaligned_le32(frac_val, st->transf_buf); + ret = regmap_bulk_write(st->regmap, ADMV4420_FRAC_L, st->transf_buf, 3); + if (ret) + return ret; + + put_unaligned_le32(mod_val, st->transf_buf); + ret = regmap_bulk_write(st->regmap, ADMV4420_MOD_L, st->transf_buf, 3); + if (ret) + return ret; + + put_unaligned_le32(int_val, st->transf_buf); + return regmap_bulk_write(st->regmap, ADMV4420_INT_L, st->transf_buf, 2); +} + +static int admv4420_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long info) +{ + struct admv4420_state *st = iio_priv(indio_dev); + + switch (info) { + case IIO_CHAN_INFO_FREQUENCY: + + *val = div_u64_rem(st->lo_freq_hz, MICRO, val2); + + return IIO_VAL_INT_PLUS_MICRO; + default: + return -EINVAL; + } +} + +static const struct iio_info admv4420_info = { + .read_raw = admv4420_read_raw, + .debugfs_reg_access = &admv4420_reg_access, +}; + +static const struct iio_chan_spec admv4420_channels[] = { + { + .type = IIO_ALTVOLTAGE, + .output = 0, + .indexed = 1, + .channel = 0, + .info_mask_separate = BIT(IIO_CHAN_INFO_FREQUENCY), + }, +}; + +static void admv4420_fw_parse(struct admv4420_state *st) +{ + struct device *dev = &st->spi->dev; + u32 tmp; + int ret; + + ret = device_property_read_u32(dev, "adi,lo-freq-khz", &tmp); + if (!ret) + st->lo_freq_hz = (u64)tmp * KILO; + + st->ref_block.ref_single_ended = device_property_read_bool(dev, + "adi,ref-ext-single-ended-en"); +} + +static inline uint64_t admv4420_calc_pfd_vco(struct admv4420_state *st) +{ + return div_u64(st->vco_freq_hz * 10, st->n_counter.n_counter); +} + +static inline uint32_t admv4420_calc_pfd_ref(struct admv4420_state *st) +{ + uint32_t tmp; + u8 doubler, divide_by_2; + + doubler = st->ref_block.doubler_en ? 2 : 1; + divide_by_2 = st->ref_block.divide_by_2_en ? 2 : 1; + tmp = ADMV4420_REF_FREQ_HZ * doubler; + + return (tmp / (st->ref_block.divider * divide_by_2)); +} + +static int admv4420_calc_parameters(struct admv4420_state *st) +{ + u64 pfd_ref, pfd_vco; + bool sol_found = false; + + st->ref_block.doubler_en = false; + st->ref_block.divide_by_2_en = false; + st->vco_freq_hz = div_u64(st->lo_freq_hz, 2); + + for (st->ref_block.divider = 1; st->ref_block.divider < MAX_R_DIVIDER; + st->ref_block.divider++) { + pfd_ref = admv4420_calc_pfd_ref(st); + for (st->n_counter.n_counter = 1; st->n_counter.n_counter < MAX_N_COUNTER; + st->n_counter.n_counter++) { + pfd_vco = admv4420_calc_pfd_vco(st); + if (pfd_ref == pfd_vco) { + sol_found = true; + break; + } + } + + if (sol_found) + break; + + st->n_counter.n_counter = 1; + } + if (!sol_found) + return -1; + + st->n_counter.int_val = div_u64_rem(st->n_counter.n_counter, 10, &st->n_counter.frac_val); + st->n_counter.mod_val = 10; + + return 0; +} + +static int admv4420_setup(struct iio_dev *indio_dev) +{ + struct admv4420_state *st = iio_priv(indio_dev); + struct device *dev = indio_dev->dev.parent; + u32 val; + int ret; + + ret = regmap_write(st->regmap, ADMV4420_SPI_CONFIG_1, + ADMV4420_SPI_CONFIG_1_SOFTRESET); + if (ret) + return ret; + + ret = regmap_write(st->regmap, ADMV4420_SPI_CONFIG_1, + ADMV4420_SPI_CONFIG_1_SDOACTIVE | + ADMV4420_SPI_CONFIG_1_ENDIAN); + if (ret) + return ret; + + ret = regmap_write(st->regmap, + ADMV4420_SCRATCHPAD, + ADMV4420_SCRATCH_PAD_VAL_1); + if (ret) + return ret; + + ret = regmap_read(st->regmap, ADMV4420_SCRATCHPAD, &val); + if (ret) + return ret; + + if (val != ADMV4420_SCRATCH_PAD_VAL_1) { + dev_err(dev, "Failed ADMV4420 to read/write scratchpad %x ", val); + return -EIO; + } + + ret = regmap_write(st->regmap, + ADMV4420_SCRATCHPAD, + ADMV4420_SCRATCH_PAD_VAL_2); + if (ret) + return ret; + + ret = regmap_read(st->regmap, ADMV4420_SCRATCHPAD, &val); + if (ret) + return ret; + + if (val != ADMV4420_SCRATCH_PAD_VAL_2) { + dev_err(dev, "Failed to read/write scratchpad %x ", val); + return -EIO; + } + + st->mux_sel = ADMV4420_LOCK_DTCT; + st->lo_freq_hz = ADMV4420_DEFAULT_LO_FREQ_HZ; + + admv4420_fw_parse(st); + + ret = admv4420_calc_parameters(st); + if (ret) { + dev_err(dev, "Failed calc parameters for %lld ", st->vco_freq_hz); + return ret; + } + + ret = regmap_write(st->regmap, ADMV4420_R_DIV_L, + FIELD_GET(0xFF, st->ref_block.divider)); + if (ret) + return ret; + + ret = regmap_write(st->regmap, ADMV4420_R_DIV_H, + FIELD_GET(0xFF00, st->ref_block.divider)); + if (ret) + return ret; + + ret = regmap_write(st->regmap, ADMV4420_REFERENCE, + st->ref_block.divide_by_2_en | + FIELD_PREP(ADMV4420_REFERENCE_MODE_MASK, st->ref_block.ref_single_ended) | + FIELD_PREP(ADMV4420_REFERENCE_DOUBLER_MASK, st->ref_block.doubler_en)); + if (ret) + return ret; + + ret = admv4420_set_n_counter(st, st->n_counter.int_val, + st->n_counter.frac_val, + st->n_counter.mod_val); + if (ret) + return ret; + + ret = regmap_write(st->regmap, ADMV4420_PLL_MUX_SEL, st->mux_sel); + if (ret) + return ret; + + return regmap_write(st->regmap, ADMV4420_ENABLES, + ENABLE_PLL | ENABLE_LO | ENABLE_VCO | + ENABLE_IFAMP | ENABLE_MIXER | ENABLE_LNA); +} + +static int admv4420_probe(struct spi_device *spi) +{ + struct iio_dev *indio_dev; + struct admv4420_state *st; + struct regmap *regmap; + int ret; + + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); + if (!indio_dev) + return -ENOMEM; + + regmap = devm_regmap_init_spi(spi, &admv4420_regmap_config); + if (IS_ERR(regmap)) + return dev_err_probe(&spi->dev, PTR_ERR(regmap), + "Failed to initializing spi regmap\n"); + + st = iio_priv(indio_dev); + st->spi = spi; + st->regmap = regmap; + + indio_dev->name = "admv4420"; + indio_dev->info = &admv4420_info; + indio_dev->channels = admv4420_channels; + indio_dev->num_channels = ARRAY_SIZE(admv4420_channels); + + ret = admv4420_setup(indio_dev); + if (ret) { + dev_err(&spi->dev, "Setup ADMV4420 failed (%d)\n", ret); + return ret; + } + + return devm_iio_device_register(&spi->dev, indio_dev); +} + +static const struct of_device_id admv4420_of_match[] = { + { .compatible = "adi,admv4420" }, + { } +}; + +MODULE_DEVICE_TABLE(of, admv4420_of_match); + +static struct spi_driver admv4420_driver = { + .driver = { + .name = "admv4420", + .of_match_table = admv4420_of_match, + }, + .probe = admv4420_probe, +}; + +module_spi_driver(admv4420_driver); + +MODULE_AUTHOR("Cristian Pop "); +MODULE_DESCRIPTION("Analog Devices ADMV44200 K Band Downconverter"); +MODULE_LICENSE("Dual BSD/GPL"); -- cgit v1.2.3 From bc437f7515f5e14aec9f2801412d9ea48116a97d Mon Sep 17 00:00:00 2001 From: Liam Beguin Date: Sat, 12 Feb 2022 21:57:30 -0500 Subject: iio: afe: rescale: expose scale processing function In preparation for the addition of kunit tests, expose the logic responsible for combining channel scales. Signed-off-by: Liam Beguin Reviewed-by: Peter Rosin Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220213025739.2561834-2-liambeguin@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/afe/iio-rescale.c | 65 ++++++++++++++++++----------------------- include/linux/iio/afe/rescale.h | 32 ++++++++++++++++++++ 2 files changed, 60 insertions(+), 37 deletions(-) create mode 100644 include/linux/iio/afe/rescale.h diff --git a/drivers/iio/afe/iio-rescale.c b/drivers/iio/afe/iio-rescale.c index 69710c481376..65832dd09249 100644 --- a/drivers/iio/afe/iio-rescale.c +++ b/drivers/iio/afe/iio-rescale.c @@ -15,32 +15,43 @@ #include #include +#include #include #include -struct rescale; - -struct rescale_cfg { - enum iio_chan_type type; - int (*props)(struct device *dev, struct rescale *rescale); -}; +int rescale_process_scale(struct rescale *rescale, int scale_type, + int *val, int *val2) +{ + s64 tmp; -struct rescale { - const struct rescale_cfg *cfg; - struct iio_channel *source; - struct iio_chan_spec chan; - struct iio_chan_spec_ext_info *ext_info; - bool chan_processed; - s32 numerator; - s32 denominator; -}; + switch (scale_type) { + case IIO_VAL_FRACTIONAL: + *val *= rescale->numerator; + *val2 *= rescale->denominator; + return scale_type; + case IIO_VAL_INT: + *val *= rescale->numerator; + if (rescale->denominator == 1) + return scale_type; + *val2 = rescale->denominator; + return IIO_VAL_FRACTIONAL; + case IIO_VAL_FRACTIONAL_LOG2: + tmp = (s64)*val * 1000000000LL; + tmp = div_s64(tmp, rescale->denominator); + tmp *= rescale->numerator; + tmp = div_s64(tmp, 1000000000LL); + *val = tmp; + return scale_type; + default: + return -EOPNOTSUPP; + } +} static int rescale_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, int *val2, long mask) { struct rescale *rescale = iio_priv(indio_dev); - s64 tmp; int ret; switch (mask) { @@ -66,27 +77,7 @@ static int rescale_read_raw(struct iio_dev *indio_dev, } else { ret = iio_read_channel_scale(rescale->source, val, val2); } - switch (ret) { - case IIO_VAL_FRACTIONAL: - *val *= rescale->numerator; - *val2 *= rescale->denominator; - return ret; - case IIO_VAL_INT: - *val *= rescale->numerator; - if (rescale->denominator == 1) - return ret; - *val2 = rescale->denominator; - return IIO_VAL_FRACTIONAL; - case IIO_VAL_FRACTIONAL_LOG2: - tmp = (s64)*val * 1000000000LL; - tmp = div_s64(tmp, rescale->denominator); - tmp *= rescale->numerator; - tmp = div_s64(tmp, 1000000000LL); - *val = tmp; - return ret; - default: - return -EOPNOTSUPP; - } + return rescale_process_scale(rescale, ret, val, val2); default: return -EINVAL; } diff --git a/include/linux/iio/afe/rescale.h b/include/linux/iio/afe/rescale.h new file mode 100644 index 000000000000..8a2eb34af327 --- /dev/null +++ b/include/linux/iio/afe/rescale.h @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2018 Axentia Technologies AB + */ + +#ifndef __IIO_RESCALE_H__ +#define __IIO_RESCALE_H__ + +#include +#include + +struct device; +struct rescale; + +struct rescale_cfg { + enum iio_chan_type type; + int (*props)(struct device *dev, struct rescale *rescale); +}; + +struct rescale { + const struct rescale_cfg *cfg; + struct iio_channel *source; + struct iio_chan_spec chan; + struct iio_chan_spec_ext_info *ext_info; + bool chan_processed; + s32 numerator; + s32 denominator; +}; + +int rescale_process_scale(struct rescale *rescale, int scale_type, + int *val, int *val2); +#endif /* __IIO_RESCALE_H__ */ -- cgit v1.2.3 From 701ee14da95dcd25c1bf20dea7c8335b70d73124 Mon Sep 17 00:00:00 2001 From: Liam Beguin Date: Sat, 12 Feb 2022 21:57:31 -0500 Subject: iio: afe: rescale: add INT_PLUS_{MICRO,NANO} support Some ADCs use IIO_VAL_INT_PLUS_{NANO,MICRO} scale types. Add support for these to allow using the iio-rescaler with them. Signed-off-by: Liam Beguin Reviewed-by: Peter Rosin Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220213025739.2561834-3-liambeguin@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/afe/iio-rescale.c | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/drivers/iio/afe/iio-rescale.c b/drivers/iio/afe/iio-rescale.c index 65832dd09249..e67d9a9e6135 100644 --- a/drivers/iio/afe/iio-rescale.c +++ b/drivers/iio/afe/iio-rescale.c @@ -23,6 +23,9 @@ int rescale_process_scale(struct rescale *rescale, int scale_type, int *val, int *val2) { s64 tmp; + s32 rem; + u32 mult; + u32 neg; switch (scale_type) { case IIO_VAL_FRACTIONAL: @@ -41,6 +44,37 @@ int rescale_process_scale(struct rescale *rescale, int scale_type, tmp *= rescale->numerator; tmp = div_s64(tmp, 1000000000LL); *val = tmp; + return scale_type; + case IIO_VAL_INT_PLUS_NANO: + case IIO_VAL_INT_PLUS_MICRO: + mult = scale_type == IIO_VAL_INT_PLUS_NANO ? 1000000000L : 1000000L; + + /* + * For IIO_VAL_INT_PLUS_{MICRO,NANO} scale types if either *val + * OR *val2 is negative the schan scale is negative, i.e. + * *val = 1 and *val2 = -0.5 yields -1.5 not -0.5. + */ + neg = *val < 0 || *val2 < 0; + + tmp = (s64)abs(*val) * abs(rescale->numerator); + *val = div_s64_rem(tmp, abs(rescale->denominator), &rem); + + tmp = (s64)rem * mult + (s64)abs(*val2) * abs(rescale->numerator); + tmp = div_s64(tmp, abs(rescale->denominator)); + + *val += div_s64_rem(tmp, mult, val2); + + /* + * If only one of the rescaler elements or the schan scale is + * negative, the combined scale is negative. + */ + if (neg ^ ((rescale->numerator < 0) ^ (rescale->denominator < 0))) { + if (*val) + *val = -*val; + else + *val2 = -*val2; + } + return scale_type; default: return -EOPNOTSUPP; -- cgit v1.2.3 From a29c3283653b80b916c5ca5292c5d36415e38e92 Mon Sep 17 00:00:00 2001 From: Liam Beguin Date: Sat, 12 Feb 2022 21:57:32 -0500 Subject: iio: afe: rescale: add offset support This is a preparatory change required for the addition of temperature sensing front ends. Signed-off-by: Liam Beguin Reviewed-by: Peter Rosin Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220213025739.2561834-4-liambeguin@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/afe/iio-rescale.c | 81 +++++++++++++++++++++++++++++++++++++++++ include/linux/iio/afe/rescale.h | 4 ++ 2 files changed, 85 insertions(+) diff --git a/drivers/iio/afe/iio-rescale.c b/drivers/iio/afe/iio-rescale.c index e67d9a9e6135..8eaf766e28cc 100644 --- a/drivers/iio/afe/iio-rescale.c +++ b/drivers/iio/afe/iio-rescale.c @@ -3,6 +3,7 @@ * IIO rescale driver * * Copyright (C) 2018 Axentia Technologies AB + * Copyright (C) 2022 Liam Beguin * * Author: Peter Rosin */ @@ -81,11 +82,46 @@ int rescale_process_scale(struct rescale *rescale, int scale_type, } } +int rescale_process_offset(struct rescale *rescale, int scale_type, + int scale, int scale2, int schan_off, + int *val, int *val2) +{ + s64 tmp, tmp2; + + switch (scale_type) { + case IIO_VAL_FRACTIONAL: + tmp = (s64)rescale->offset * scale2; + *val = div_s64(tmp, scale) + schan_off; + return IIO_VAL_INT; + case IIO_VAL_INT: + *val = div_s64(rescale->offset, scale) + schan_off; + return IIO_VAL_INT; + case IIO_VAL_FRACTIONAL_LOG2: + tmp = (s64)rescale->offset * (1 << scale2); + *val = div_s64(tmp, scale) + schan_off; + return IIO_VAL_INT; + case IIO_VAL_INT_PLUS_NANO: + tmp = (s64)rescale->offset * 1000000000LL; + tmp2 = ((s64)scale * 1000000000LL) + scale2; + *val = div64_s64(tmp, tmp2) + schan_off; + return IIO_VAL_INT; + case IIO_VAL_INT_PLUS_MICRO: + tmp = (s64)rescale->offset * 1000000LL; + tmp2 = ((s64)scale * 1000000LL) + scale2; + *val = div64_s64(tmp, tmp2) + schan_off; + return IIO_VAL_INT; + default: + return -EOPNOTSUPP; + } +} + static int rescale_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, int *val2, long mask) { struct rescale *rescale = iio_priv(indio_dev); + int scale, scale2; + int schan_off = 0; int ret; switch (mask) { @@ -112,6 +148,47 @@ static int rescale_read_raw(struct iio_dev *indio_dev, ret = iio_read_channel_scale(rescale->source, val, val2); } return rescale_process_scale(rescale, ret, val, val2); + case IIO_CHAN_INFO_OFFSET: + /* + * Processed channels are scaled 1-to-1 and source offset is + * already taken into account. + * + * In other cases, real world measurement are expressed as: + * + * schan_scale * (raw + schan_offset) + * + * Given that the rescaler parameters are applied recursively: + * + * rescaler_scale * (schan_scale * (raw + schan_offset) + + * rescaler_offset) + * + * Or, + * + * (rescaler_scale * schan_scale) * (raw + + * (schan_offset + rescaler_offset / schan_scale) + * + * Thus, reusing the original expression the parameters exposed + * to userspace are: + * + * scale = schan_scale * rescaler_scale + * offset = schan_offset + rescaler_offset / schan_scale + */ + if (rescale->chan_processed) { + *val = rescale->offset; + return IIO_VAL_INT; + } + + if (iio_channel_has_info(rescale->source->channel, + IIO_CHAN_INFO_OFFSET)) { + ret = iio_read_channel_offset(rescale->source, + &schan_off, NULL); + if (ret != IIO_VAL_INT) + return ret < 0 ? ret : -EOPNOTSUPP; + } + + ret = iio_read_channel_scale(rescale->source, &scale, &scale2); + return rescale_process_offset(rescale, ret, scale, scale2, + schan_off, val, val2); default: return -EINVAL; } @@ -188,6 +265,9 @@ static int rescale_configure_channel(struct device *dev, chan->info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE); + if (rescale->offset) + chan->info_mask_separate |= BIT(IIO_CHAN_INFO_OFFSET); + /* * Using .read_avail() is fringe to begin with and makes no sense * whatsoever for processed channels, so we make sure that this cannot @@ -352,6 +432,7 @@ static int rescale_probe(struct platform_device *pdev) rescale->cfg = of_device_get_match_data(dev); rescale->numerator = 1; rescale->denominator = 1; + rescale->offset = 0; ret = rescale->cfg->props(dev, rescale); if (ret) diff --git a/include/linux/iio/afe/rescale.h b/include/linux/iio/afe/rescale.h index 8a2eb34af327..6eecb435488f 100644 --- a/include/linux/iio/afe/rescale.h +++ b/include/linux/iio/afe/rescale.h @@ -25,8 +25,12 @@ struct rescale { bool chan_processed; s32 numerator; s32 denominator; + s32 offset; }; int rescale_process_scale(struct rescale *rescale, int scale_type, int *val, int *val2); +int rescale_process_offset(struct rescale *rescale, int scale_type, + int scale, int scale2, int schan_off, + int *val, int *val2); #endif /* __IIO_RESCALE_H__ */ -- cgit v1.2.3 From f5fc003d48033559314f1c9de8198f58f14ed557 Mon Sep 17 00:00:00 2001 From: Liam Beguin Date: Sat, 12 Feb 2022 21:57:33 -0500 Subject: iio: afe: rescale: fix accuracy for small fractional scales The approximation caused by integer divisions can be costly on smaller scale values since the decimal part is significant compared to the integer part. Switch to an IIO_VAL_INT_PLUS_NANO scale type in such cases to maintain accuracy. Signed-off-by: Liam Beguin Reviewed-by: Peter Rosin Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220213025739.2561834-5-liambeguin@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/afe/iio-rescale.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/drivers/iio/afe/iio-rescale.c b/drivers/iio/afe/iio-rescale.c index 8eaf766e28cc..5d78f0cf47d2 100644 --- a/drivers/iio/afe/iio-rescale.c +++ b/drivers/iio/afe/iio-rescale.c @@ -24,7 +24,7 @@ int rescale_process_scale(struct rescale *rescale, int scale_type, int *val, int *val2) { s64 tmp; - s32 rem; + s32 rem, rem2; u32 mult; u32 neg; @@ -43,9 +43,23 @@ int rescale_process_scale(struct rescale *rescale, int scale_type, tmp = (s64)*val * 1000000000LL; tmp = div_s64(tmp, rescale->denominator); tmp *= rescale->numerator; - tmp = div_s64(tmp, 1000000000LL); + + tmp = div_s64_rem(tmp, 1000000000LL, &rem); *val = tmp; - return scale_type; + + if (!rem) + return scale_type; + + tmp = 1 << *val2; + + rem2 = *val % (int)tmp; + *val = *val / (int)tmp; + + *val2 = rem / (int)tmp; + if (rem2) + *val2 += div_s64((s64)rem2 * 1000000000LL, tmp); + + return IIO_VAL_INT_PLUS_NANO; case IIO_VAL_INT_PLUS_NANO: case IIO_VAL_INT_PLUS_MICRO: mult = scale_type == IIO_VAL_INT_PLUS_NANO ? 1000000000L : 1000000L; -- cgit v1.2.3 From 2eb30577f2533463afed3456141d4becc4f79e91 Mon Sep 17 00:00:00 2001 From: Liam Beguin Date: Sat, 12 Feb 2022 21:57:34 -0500 Subject: iio: afe: rescale: reduce risk of integer overflow Reduce the risk of integer overflow by doing the scale calculation on a 64-bit integer. Since the rescaling is only performed on *val, reuse the IIO_VAL_FRACTIONAL_LOG2 case. Signed-off-by: Liam Beguin Reviewed-by: Peter Rosin Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220213025739.2561834-6-liambeguin@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/afe/iio-rescale.c | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/drivers/iio/afe/iio-rescale.c b/drivers/iio/afe/iio-rescale.c index 5d78f0cf47d2..46947c68d3a9 100644 --- a/drivers/iio/afe/iio-rescale.c +++ b/drivers/iio/afe/iio-rescale.c @@ -24,21 +24,31 @@ int rescale_process_scale(struct rescale *rescale, int scale_type, int *val, int *val2) { s64 tmp; + int _val, _val2; s32 rem, rem2; u32 mult; u32 neg; switch (scale_type) { - case IIO_VAL_FRACTIONAL: - *val *= rescale->numerator; - *val2 *= rescale->denominator; - return scale_type; case IIO_VAL_INT: *val *= rescale->numerator; if (rescale->denominator == 1) return scale_type; *val2 = rescale->denominator; return IIO_VAL_FRACTIONAL; + case IIO_VAL_FRACTIONAL: + /* + * When the product of both scales doesn't overflow, avoid + * potential accuracy loss (for in kernel consumers) by + * keeping a fractional representation. + */ + if (!check_mul_overflow(*val, rescale->numerator, &_val) && + !check_mul_overflow(*val2, rescale->denominator, &_val2)) { + *val = _val; + *val2 = _val2; + return IIO_VAL_FRACTIONAL; + } + fallthrough; case IIO_VAL_FRACTIONAL_LOG2: tmp = (s64)*val * 1000000000LL; tmp = div_s64(tmp, rescale->denominator); @@ -50,7 +60,10 @@ int rescale_process_scale(struct rescale *rescale, int scale_type, if (!rem) return scale_type; - tmp = 1 << *val2; + if (scale_type == IIO_VAL_FRACTIONAL) + tmp = *val2; + else + tmp = ULL(1) << *val2; rem2 = *val % (int)tmp; *val = *val / (int)tmp; -- cgit v1.2.3 From 8e74a48d17d509bf605e64252f38550b1a9cc376 Mon Sep 17 00:00:00 2001 From: Liam Beguin Date: Sat, 12 Feb 2022 21:57:35 -0500 Subject: iio: test: add basic tests for the iio-rescale driver The iio-rescale driver supports various combinations of scale types and offsets. These can often result in large integer multiplications. Make sure these calculations are done right by adding a set of kunit test cases that build on top of iio-test-format. To run these tests, add the following to .kunitconfig $ cat .kunitconfig CONFIG_IIO=y CONFIG_IIO_RESCALE_KUNIT_TEST=y CONFIG_KUNIT=y Then run: $ ./tools/testing/kunit/kunit.py run --kunitconfig .kunitconfig Signed-off-by: Liam Beguin Reviewed-by: Peter Rosin Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220213025739.2561834-7-liambeguin@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/test/Kconfig | 10 + drivers/iio/test/Makefile | 1 + drivers/iio/test/iio-test-rescale.c | 710 ++++++++++++++++++++++++++++++++++++ 3 files changed, 721 insertions(+) create mode 100644 drivers/iio/test/iio-test-rescale.c diff --git a/drivers/iio/test/Kconfig b/drivers/iio/test/Kconfig index 679a7794af20..56ca0ad7e77a 100644 --- a/drivers/iio/test/Kconfig +++ b/drivers/iio/test/Kconfig @@ -4,6 +4,16 @@ # # Keep in alphabetical order +config IIO_RESCALE_KUNIT_TEST + bool "Test IIO rescale conversion functions" + depends on KUNIT=y && !IIO_RESCALE + default KUNIT_ALL_TESTS + help + If you want to run tests on the iio-rescale code say Y here. + + This takes advantage of ARCH=um to run tests and should be used by + developers to tests their changes to the rescaling logic. + config IIO_TEST_FORMAT bool "Test IIO formatting functions" depends on KUNIT=y diff --git a/drivers/iio/test/Makefile b/drivers/iio/test/Makefile index 467519a2027e..f15ae0a6394f 100644 --- a/drivers/iio/test/Makefile +++ b/drivers/iio/test/Makefile @@ -4,5 +4,6 @@ # # Keep in alphabetical order +obj-$(CONFIG_IIO_RESCALE_KUNIT_TEST) += iio-test-rescale.o ../afe/iio-rescale.o obj-$(CONFIG_IIO_TEST_FORMAT) += iio-test-format.o CFLAGS_iio-test-format.o += $(DISABLE_STRUCTLEAK_PLUGIN) diff --git a/drivers/iio/test/iio-test-rescale.c b/drivers/iio/test/iio-test-rescale.c new file mode 100644 index 000000000000..0b6699bfd553 --- /dev/null +++ b/drivers/iio/test/iio-test-rescale.c @@ -0,0 +1,710 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Kunit tests for IIO rescale conversions + * + * Copyright (c) 2021 Liam Beguin + */ + +#include +#include + +#include +#include + +#include + +struct rescale_tc_data { + const char *name; + + const s32 numerator; + const s32 denominator; + const s32 offset; + + const int schan_val; + const int schan_val2; + const int schan_off; + const int schan_scale_type; + + const char *expected; + const char *expected_off; +}; + +const struct rescale_tc_data scale_cases[] = { + /* + * Typical use cases + */ + { + .name = "typical IIO_VAL_INT, positive", + .numerator = 1000000, + .denominator = 8060, + .schan_scale_type = IIO_VAL_INT, + .schan_val = 42, + .expected = "5210.918114143", + }, + { + .name = "typical IIO_VAL_INT, negative", + .numerator = -1000000, + .denominator = 8060, + .schan_scale_type = IIO_VAL_INT, + .schan_val = 42, + .expected = "-5210.918114143", + }, + { + .name = "typical IIO_VAL_FRACTIONAL, positive", + .numerator = 1000000, + .denominator = 8060, + .schan_scale_type = IIO_VAL_FRACTIONAL, + .schan_val = 42, + .schan_val2 = 20, + .expected = "260.545905707", + }, + { + .name = "typical IIO_VAL_FRACTIONAL, negative", + .numerator = -1000000, + .denominator = 8060, + .schan_scale_type = IIO_VAL_FRACTIONAL, + .schan_val = 42, + .schan_val2 = 20, + .expected = "-260.545905707", + }, + { + .name = "typical IIO_VAL_FRACTIONAL_LOG2, positive", + .numerator = 42, + .denominator = 53, + .schan_scale_type = IIO_VAL_FRACTIONAL_LOG2, + .schan_val = 4096, + .schan_val2 = 16, + .expected = "0.049528301", + }, + { + .name = "typical IIO_VAL_FRACTIONAL_LOG2, negative", + .numerator = -42, + .denominator = 53, + .schan_scale_type = IIO_VAL_FRACTIONAL_LOG2, + .schan_val = 4096, + .schan_val2 = 16, + .expected = "-0.049528301", + }, + { + .name = "typical IIO_VAL_INT_PLUS_NANO, positive", + .numerator = 1000000, + .denominator = 8060, + .schan_scale_type = IIO_VAL_INT_PLUS_NANO, + .schan_val = 10, + .schan_val2 = 123456, + .expected = "1240.710106203", + }, + { + .name = "typical IIO_VAL_INT_PLUS_NANO, negative", + .numerator = -1000000, + .denominator = 8060, + .schan_scale_type = IIO_VAL_INT_PLUS_NANO, + .schan_val = 10, + .schan_val2 = 123456, + .expected = "-1240.710106203", + }, + { + .name = "typical IIO_VAL_INT_PLUS_MICRO, positive", + .numerator = 1000000, + .denominator = 8060, + .schan_scale_type = IIO_VAL_INT_PLUS_MICRO, + .schan_val = 10, + .schan_val2 = 1234, + .expected = "1240.84789", + }, + { + .name = "typical IIO_VAL_INT_PLUS_MICRO, negative", + .numerator = -1000000, + .denominator = 8060, + .schan_scale_type = IIO_VAL_INT_PLUS_MICRO, + .schan_val = 10, + .schan_val2 = 1234, + .expected = "-1240.84789", + }, + /* + * Use cases with small scales involving divisions + */ + { + .name = "small IIO_VAL_FRACTIONAL, 261/509 scaled by 90/1373754273", + .numerator = 261, + .denominator = 509, + .schan_scale_type = IIO_VAL_FRACTIONAL, + .schan_val = 90, + .schan_val2 = 1373754273, + .expected = "0.000000033594", + }, + { + .name = "small IIO_VAL_FRACTIONAL, 90/1373754273 scaled by 261/509", + .numerator = 90, + .denominator = 1373754273, + .schan_scale_type = IIO_VAL_FRACTIONAL, + .schan_val = 261, + .schan_val2 = 509, + .expected = "0.000000033594", + }, + { + .name = "small IIO_VAL_FRACTIONAL, 760/1373754273 scaled by 427/2727", + .numerator = 760, + .denominator = 1373754273, + .schan_scale_type = IIO_VAL_FRACTIONAL, + .schan_val = 427, + .schan_val2 = 2727, + .expected = "0.000000086626", + }, + { + .name = "small IIO_VAL_FRACTIONAL, 761/1373754273 scaled by 427/2727", + .numerator = 761, + .denominator = 1373754273, + .schan_scale_type = IIO_VAL_FRACTIONAL, + .schan_val = 427, + .schan_val2 = 2727, + .expected = "0.000000086740", + }, + { + .name = "small IIO_VAL_FRACTIONAL, 5/32768 scaled by 3/10000", + .numerator = 5, + .denominator = 32768, + .schan_scale_type = IIO_VAL_FRACTIONAL, + .schan_val = 3, + .schan_val2 = 10000, + .expected = "0.0000000457763671875", + }, + { + .name = "small IIO_VAL_FRACTIONAL, 0 < scale < 1", + .numerator = 6, + .denominator = 6, + .schan_scale_type = IIO_VAL_FRACTIONAL, + .schan_val = 1, + .schan_val2 = 3, + .expected = "0.3333333333333333", + }, + { + .name = "small IIO_VAL_FRACTIONAL, -1 < scale < 0", + .numerator = -6, + .denominator = 6, + .schan_scale_type = IIO_VAL_FRACTIONAL, + .schan_val = 1, + .schan_val2 = 3, + .expected = "-0.3333333333333333", + }, + { + .name = "small IIO_VAL_FRACTIONAL, 0 < scale < 2", + .numerator = 8, + .denominator = 2, + .schan_scale_type = IIO_VAL_FRACTIONAL, + .schan_val = 1, + .schan_val2 = 3, + .expected = "1.3333333333333333", + }, + { + .name = "small IIO_VAL_FRACTIONAL, -2 < scale < 0", + .numerator = -8, + .denominator = 2, + .schan_scale_type = IIO_VAL_FRACTIONAL, + .schan_val = 1, + .schan_val2 = 3, + .expected = "-1.3333333333333333", + }, + { + .name = "small IIO_VAL_FRACTIONAL_LOG2, 760/32768 scaled by 15/22", + .numerator = 760, + .denominator = 32768, + .schan_scale_type = IIO_VAL_FRACTIONAL_LOG2, + .schan_val = 15, + .schan_val2 = 22, + .expected = "0.000000082946", + }, + { + .name = "small IIO_VAL_FRACTIONAL_LOG2, 761/32768 scaled by 15/22", + .numerator = 761, + .denominator = 32768, + .schan_scale_type = IIO_VAL_FRACTIONAL_LOG2, + .schan_val = 15, + .schan_val2 = 22, + .expected = "0.000000083055", + }, + { + .name = "small IIO_VAL_FRACTIONAL_LOG2, 0 < scale < 1", + .numerator = 16, + .denominator = 3, + .schan_scale_type = IIO_VAL_FRACTIONAL_LOG2, + .schan_val = 1, + .schan_val2 = 4, + .expected = "0.3333333333333333", + }, + { + .name = "small IIO_VAL_FRACTIONAL_LOG2, -1 < scale < 0", + .numerator = -16, + .denominator = 3, + .schan_scale_type = IIO_VAL_FRACTIONAL_LOG2, + .schan_val = 1, + .schan_val2 = 4, + .expected = "-0.3333333333333333", + }, + { + .name = "small IIO_VAL_FRACTIONAL_LOG2, 0 < scale < 2", + .numerator = 8, + .denominator = 3, + .schan_scale_type = IIO_VAL_FRACTIONAL_LOG2, + .schan_val = 1, + .schan_val2 = 1, + .expected = "1.3333333333333333", + }, + { + .name = "small IIO_VAL_FRACTIONAL_LOG2, -2 < scale < 0", + .numerator = -8, + .denominator = 3, + .schan_scale_type = IIO_VAL_FRACTIONAL_LOG2, + .schan_val = 1, + .schan_val2 = 1, + .expected = "-1.3333333333333333", + }, + { + .name = "small IIO_VAL_INT_PLUS_MICRO, positive", + .numerator = 1, + .denominator = 2, + .schan_scale_type = IIO_VAL_INT_PLUS_MICRO, + .schan_val = 5, + .schan_val2 = 1234, + .expected = "2.500617", + }, + { + .name = "small IIO_VAL_INT_PLUS_MICRO, negative", + .numerator = -1, + .denominator = 2, + .schan_scale_type = IIO_VAL_INT_PLUS_MICRO, + .schan_val = 5, + .schan_val2 = 1234, + .expected = "-2.500617", + }, + /* + * INT_PLUS_{MICRO,NANO} positive/negative corner cases + */ + { + .name = "negative IIO_VAL_INT_PLUS_NANO, negative schan", + .numerator = 1000000, + .denominator = 8060, + .schan_scale_type = IIO_VAL_INT_PLUS_NANO, + .schan_val = -10, + .schan_val2 = 123456, + .expected = "-1240.710106203", + }, + { + .name = "negative IIO_VAL_INT_PLUS_NANO, both negative", + .numerator = -1000000, + .denominator = 8060, + .schan_scale_type = IIO_VAL_INT_PLUS_NANO, + .schan_val = -10, + .schan_val2 = 123456, + .expected = "1240.710106203", + }, + { + .name = "negative IIO_VAL_INT_PLUS_NANO, 3 negative", + .numerator = -1000000, + .denominator = -8060, + .schan_scale_type = IIO_VAL_INT_PLUS_NANO, + .schan_val = -10, + .schan_val2 = 123456, + .expected = "-1240.710106203", + }, + { + .name = "negative IIO_VAL_INT_PLUS_NANO, 4 negative", + .numerator = -1000000, + .denominator = -8060, + .schan_scale_type = IIO_VAL_INT_PLUS_NANO, + .schan_val = -10, + .schan_val2 = -123456, + .expected = "-1240.710106203", + }, + { + .name = "negative IIO_VAL_INT_PLUS_NANO, negative, *val = 0", + .numerator = 1, + .denominator = -10, + .schan_scale_type = IIO_VAL_INT_PLUS_NANO, + .schan_val = 0, + .schan_val2 = 123456789, + .expected = "-0.012345678", + }, + /* + * INT_PLUS_{MICRO,NANO} decimal part overflow + */ + { + .name = "decimal overflow IIO_VAL_INT_PLUS_NANO, positive", + .numerator = 1000000, + .denominator = 8060, + .schan_scale_type = IIO_VAL_INT_PLUS_NANO, + .schan_val = 10, + .schan_val2 = 123456789, + .expected = "1256.01200856", + }, + { + .name = "decimal overflow IIO_VAL_INT_PLUS_NANO, negative", + .numerator = -1000000, + .denominator = 8060, + .schan_scale_type = IIO_VAL_INT_PLUS_NANO, + .schan_val = 10, + .schan_val2 = 123456789, + .expected = "-1256.01200856", + }, + { + .name = "decimal overflow IIO_VAL_INT_PLUS_NANO, negative schan", + .numerator = 1000000, + .denominator = 8060, + .schan_scale_type = IIO_VAL_INT_PLUS_NANO, + .schan_val = -10, + .schan_val2 = 123456789, + .expected = "-1256.01200856", + }, + { + .name = "decimal overflow IIO_VAL_INT_PLUS_MICRO, positive", + .numerator = 1000000, + .denominator = 8060, + .schan_scale_type = IIO_VAL_INT_PLUS_MICRO, + .schan_val = 10, + .schan_val2 = 123456789, + .expected = "16557.914267", + }, + { + .name = "decimal overflow IIO_VAL_INT_PLUS_MICRO, negative", + .numerator = -1000000, + .denominator = 8060, + .schan_scale_type = IIO_VAL_INT_PLUS_MICRO, + .schan_val = 10, + .schan_val2 = 123456789, + .expected = "-16557.914267", + }, + { + .name = "decimal overflow IIO_VAL_INT_PLUS_MICRO, negative schan", + .numerator = 1000000, + .denominator = 8060, + .schan_scale_type = IIO_VAL_INT_PLUS_MICRO, + .schan_val = -10, + .schan_val2 = 123456789, + .expected = "-16557.914267", + }, + /* + * 32-bit overflow conditions + */ + { + .name = "overflow IIO_VAL_FRACTIONAL, positive", + .numerator = 2, + .denominator = 20, + .schan_scale_type = IIO_VAL_FRACTIONAL, + .schan_val = S32_MAX, + .schan_val2 = 1, + .expected = "214748364.7", + }, + { + .name = "overflow IIO_VAL_FRACTIONAL, negative", + .numerator = -2, + .denominator = 20, + .schan_scale_type = IIO_VAL_FRACTIONAL, + .schan_val = S32_MAX, + .schan_val2 = 1, + .expected = "-214748364.7", + }, + { + .name = "overflow IIO_VAL_FRACTIONAL_LOG2, positive", + .numerator = S32_MAX, + .denominator = 4096, + .schan_scale_type = IIO_VAL_FRACTIONAL_LOG2, + .schan_val = 4096, + .schan_val2 = 16, + .expected = "32767.99998474121", + }, + { + .name = "overflow IIO_VAL_FRACTIONAL_LOG2, negative", + .numerator = S32_MAX, + .denominator = 4096, + .schan_scale_type = IIO_VAL_FRACTIONAL_LOG2, + .schan_val = -4096, + .schan_val2 = 16, + .expected = "-32767.99998474121", + }, + { + .name = "overflow IIO_VAL_INT_PLUS_NANO, positive", + .numerator = 2, + .denominator = 20, + .schan_scale_type = IIO_VAL_INT_PLUS_NANO, + .schan_val = 10, + .schan_val2 = S32_MAX, + .expected = "1.214748364", + }, + { + .name = "overflow IIO_VAL_INT_PLUS_NANO, negative", + .numerator = -2, + .denominator = 20, + .schan_scale_type = IIO_VAL_INT_PLUS_NANO, + .schan_val = 10, + .schan_val2 = S32_MAX, + .expected = "-1.214748364", + }, + { + .name = "overflow IIO_VAL_INT_PLUS_NANO, negative schan", + .numerator = 2, + .denominator = 20, + .schan_scale_type = IIO_VAL_INT_PLUS_NANO, + .schan_val = -10, + .schan_val2 = S32_MAX, + .expected = "-1.214748364", + }, + { + .name = "overflow IIO_VAL_INT_PLUS_MICRO, positive", + .numerator = 2, + .denominator = 20, + .schan_scale_type = IIO_VAL_INT_PLUS_MICRO, + .schan_val = 10, + .schan_val2 = S32_MAX, + .expected = "215.748364", + }, + { + .name = "overflow IIO_VAL_INT_PLUS_MICRO, negative", + .numerator = -2, + .denominator = 20, + .schan_scale_type = IIO_VAL_INT_PLUS_MICRO, + .schan_val = 10, + .schan_val2 = S32_MAX, + .expected = "-215.748364", + }, + { + .name = "overflow IIO_VAL_INT_PLUS_MICRO, negative schan", + .numerator = 2, + .denominator = 20, + .schan_scale_type = IIO_VAL_INT_PLUS_MICRO, + .schan_val = -10, + .schan_val2 = S32_MAX, + .expected = "-215.748364", + }, +}; + +const struct rescale_tc_data offset_cases[] = { + /* + * Typical use cases + */ + { + .name = "typical IIO_VAL_INT, positive", + .offset = 1234, + .schan_scale_type = IIO_VAL_INT, + .schan_val = 123, + .schan_val2 = 0, + .schan_off = 14, + .expected_off = "24", /* 23.872 */ + }, + { + .name = "typical IIO_VAL_INT, negative", + .offset = -1234, + .schan_scale_type = IIO_VAL_INT, + .schan_val = 12, + .schan_val2 = 0, + .schan_off = 14, + .expected_off = "-88", /* -88.83333333333333 */ + }, + { + .name = "typical IIO_VAL_FRACTIONAL, positive", + .offset = 1234, + .schan_scale_type = IIO_VAL_FRACTIONAL, + .schan_val = 12, + .schan_val2 = 34, + .schan_off = 14, + .expected_off = "3510", /* 3510.333333333333 */ + }, + { + .name = "typical IIO_VAL_FRACTIONAL, negative", + .offset = -1234, + .schan_scale_type = IIO_VAL_FRACTIONAL, + .schan_val = 12, + .schan_val2 = 34, + .schan_off = 14, + .expected_off = "-3482", /* -3482.333333333333 */ + }, + { + .name = "typical IIO_VAL_FRACTIONAL_LOG2, positive", + .offset = 1234, + .schan_scale_type = IIO_VAL_FRACTIONAL_LOG2, + .schan_val = 12, + .schan_val2 = 16, + .schan_off = 14, + .expected_off = "6739299", /* 6739299.333333333 */ + }, + { + .name = "typical IIO_VAL_FRACTIONAL_LOG2, negative", + .offset = -1234, + .schan_scale_type = IIO_VAL_FRACTIONAL_LOG2, + .schan_val = 12, + .schan_val2 = 16, + .schan_off = 14, + .expected_off = "-6739271", /* -6739271.333333333 */ + }, + { + .name = "typical IIO_VAL_INT_PLUS_NANO, positive", + .offset = 1234, + .schan_scale_type = IIO_VAL_INT_PLUS_NANO, + .schan_val = 10, + .schan_val2 = 123456789, + .schan_off = 14, + .expected_off = "135", /* 135.8951219647469 */ + }, + { + .name = "typical IIO_VAL_INT_PLUS_NANO, negative", + .offset = -1234, + .schan_scale_type = IIO_VAL_INT_PLUS_NANO, + .schan_val = 10, + .schan_val2 = 123456789, + .schan_off = 14, + .expected_off = "-107", /* -107.89512196474689 */ + }, + { + .name = "typical IIO_VAL_INT_PLUS_MICRO, positive", + .offset = 1234, + .schan_scale_type = IIO_VAL_INT_PLUS_MICRO, + .schan_val = 10, + .schan_val2 = 123456789, + .schan_off = 14, + .expected_off = "23", /* 23.246438560723952 */ + }, + { + .name = "typical IIO_VAL_INT_PLUS_MICRO, negative", + .offset = -12345, + .schan_scale_type = IIO_VAL_INT_PLUS_MICRO, + .schan_val = 10, + .schan_val2 = 123456789, + .schan_off = 14, + .expected_off = "-78", /* -78.50185091745313 */ + }, +}; + +static void case_to_desc(const struct rescale_tc_data *t, char *desc) +{ + strcpy(desc, t->name); +} + +KUNIT_ARRAY_PARAM(iio_rescale_scale, scale_cases, case_to_desc); +KUNIT_ARRAY_PARAM(iio_rescale_offset, offset_cases, case_to_desc); + +/** + * iio_str_to_nano() - Parse a fixed-point string to get an + * IIO_VAL_INT_PLUS_NANO value + * @str: The string to parse + * @nano: The number as an integer + * + * Returns 0 on success, or a negative error code if the string cound not be + * parsed. + */ +static int iio_str_to_nano(const char *str, s64 *nano) +{ + int tmp, tmp2; + int ret = 0; + + /* + * iio_str_to_fixpoint() uses 10^8 here instead of 10^9 as fract_mult is + * the multiplier for the first decimal place. + */ + ret = iio_str_to_fixpoint(str, 100000000, &tmp, &tmp2); + if (ret < 0) + return ret; + + if (tmp < 0) + tmp2 *= -1; + + *nano = (s64)tmp * 1000000000UL + tmp2; + + return ret; +} + +/** + * iio_test_relative_error_ppm() - Compute relative error (in parts-per-million) + * between two fixed-point strings + * @real_str: The real value as a string + * @exp_str: The expected value as a string + * + * Returns a negative error code if the strings cound not be parsed, or the + * relative error in parts-per-million. + */ +static int iio_test_relative_error_ppm(const char *real_str, const char *exp_str) +{ + s64 real, exp, err; + int ret; + + ret = iio_str_to_nano(real_str, &real); + if (ret < 0) + return ret; + + ret = iio_str_to_nano(exp_str, &exp); + if (ret < 0) + return ret; + + if (!exp) { + pr_err("Expected value is null, relative error is undefined\n"); + return -EINVAL; + } + + err = 1000000UL * abs(exp - real); + + return (int)div64_u64(err, abs(exp)); +} + +static void iio_rescale_test_scale(struct kunit *test) +{ + struct rescale_tc_data *t = (struct rescale_tc_data *)test->param_value; + char *buff = kunit_kmalloc(test, PAGE_SIZE, GFP_KERNEL); + struct rescale rescale; + int values[2]; + int rel_ppm; + int ret; + + rescale.numerator = t->numerator; + rescale.denominator = t->denominator; + rescale.offset = t->offset; + values[0] = t->schan_val; + values[1] = t->schan_val2; + + ret = rescale_process_scale(&rescale, t->schan_scale_type, + &values[0], &values[1]); + + ret = iio_format_value(buff, ret, 2, values); + KUNIT_EXPECT_EQ(test, (int)strlen(buff), ret); + + rel_ppm = iio_test_relative_error_ppm(buff, t->expected); + KUNIT_EXPECT_GE_MSG(test, rel_ppm, 0, "failed to compute ppm\n"); + + KUNIT_EXPECT_EQ_MSG(test, rel_ppm, 0, + "\t real=%s" + "\texpected=%s\n", + buff, t->expected); +} + +static void iio_rescale_test_offset(struct kunit *test) +{ + struct rescale_tc_data *t = (struct rescale_tc_data *)test->param_value; + char *buff_off = kunit_kmalloc(test, PAGE_SIZE, GFP_KERNEL); + struct rescale rescale; + int values[2]; + int ret; + + rescale.numerator = t->numerator; + rescale.denominator = t->denominator; + rescale.offset = t->offset; + values[0] = t->schan_val; + values[1] = t->schan_val2; + + ret = rescale_process_offset(&rescale, t->schan_scale_type, + t->schan_val, t->schan_val2, t->schan_off, + &values[0], &values[1]); + + ret = iio_format_value(buff_off, ret, 2, values); + KUNIT_EXPECT_EQ(test, (int)strlen(buff_off), ret); + + KUNIT_EXPECT_STREQ(test, strim(buff_off), t->expected_off); +} + +static struct kunit_case iio_rescale_test_cases[] = { + KUNIT_CASE_PARAM(iio_rescale_test_scale, iio_rescale_scale_gen_params), + KUNIT_CASE_PARAM(iio_rescale_test_offset, iio_rescale_offset_gen_params), + {} +}; + +static struct kunit_suite iio_rescale_test_suite = { + .name = "iio-rescale", + .test_cases = iio_rescale_test_cases, +}; +kunit_test_suite(iio_rescale_test_suite); -- cgit v1.2.3 From 278fe1d2d3a70e45267098024dc27390d8a0a157 Mon Sep 17 00:00:00 2001 From: Liam Beguin Date: Sat, 12 Feb 2022 21:57:36 -0500 Subject: iio: afe: rescale: add RTD temperature sensor support An RTD (Resistance Temperature Detector) is a kind of temperature sensor used to get a linear voltage to temperature reading within a give range (usually 0 to 100 degrees Celsius). Common types of RTDs include PT100, PT500, and PT1000. Signed-off-by: Liam Beguin Reviewed-by: Peter Rosin Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220213025739.2561834-8-liambeguin@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/afe/iio-rescale.c | 48 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/drivers/iio/afe/iio-rescale.c b/drivers/iio/afe/iio-rescale.c index 46947c68d3a9..e31a93435536 100644 --- a/drivers/iio/afe/iio-rescale.c +++ b/drivers/iio/afe/iio-rescale.c @@ -394,10 +394,52 @@ static int rescale_voltage_divider_props(struct device *dev, return 0; } +static int rescale_temp_sense_rtd_props(struct device *dev, + struct rescale *rescale) +{ + u32 factor; + u32 alpha; + u32 iexc; + u32 tmp; + int ret; + u32 r0; + + ret = device_property_read_u32(dev, "excitation-current-microamp", + &iexc); + if (ret) { + dev_err(dev, "failed to read excitation-current-microamp: %d\n", + ret); + return ret; + } + + ret = device_property_read_u32(dev, "alpha-ppm-per-celsius", &alpha); + if (ret) { + dev_err(dev, "failed to read alpha-ppm-per-celsius: %d\n", + ret); + return ret; + } + + ret = device_property_read_u32(dev, "r-naught-ohms", &r0); + if (ret) { + dev_err(dev, "failed to read r-naught-ohms: %d\n", ret); + return ret; + } + + tmp = r0 * iexc * alpha / 1000000; + factor = gcd(tmp, 1000000); + rescale->numerator = 1000000 / factor; + rescale->denominator = tmp / factor; + + rescale->offset = -1 * ((r0 * iexc) / 1000); + + return 0; +} + enum rescale_variant { CURRENT_SENSE_AMPLIFIER, CURRENT_SENSE_SHUNT, VOLTAGE_DIVIDER, + TEMP_SENSE_RTD, }; static const struct rescale_cfg rescale_cfg[] = { @@ -413,6 +455,10 @@ static const struct rescale_cfg rescale_cfg[] = { .type = IIO_VOLTAGE, .props = rescale_voltage_divider_props, }, + [TEMP_SENSE_RTD] = { + .type = IIO_TEMP, + .props = rescale_temp_sense_rtd_props, + }, }; static const struct of_device_id rescale_match[] = { @@ -422,6 +468,8 @@ static const struct of_device_id rescale_match[] = { .data = &rescale_cfg[CURRENT_SENSE_SHUNT], }, { .compatible = "voltage-divider", .data = &rescale_cfg[VOLTAGE_DIVIDER], }, + { .compatible = "temperature-sense-rtd", + .data = &rescale_cfg[TEMP_SENSE_RTD], }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, rescale_match); -- cgit v1.2.3 From 03e7d21ee1a975311c2a2c6f1f31e45023af991c Mon Sep 17 00:00:00 2001 From: Liam Beguin Date: Sat, 12 Feb 2022 21:57:37 -0500 Subject: iio: afe: rescale: add temperature transducers A temperature transducer is a device that converts a thermal quantity into any other physical quantity. This patch adds support for temperature to voltage (like the LTC2997) and temperature to current (like the AD590) linear transducers. In both cases these are assumed to be connected to a voltage ADC. Signed-off-by: Liam Beguin Reviewed-by: Peter Rosin Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220213025739.2561834-9-liambeguin@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/afe/iio-rescale.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/drivers/iio/afe/iio-rescale.c b/drivers/iio/afe/iio-rescale.c index e31a93435536..7e511293d6d1 100644 --- a/drivers/iio/afe/iio-rescale.c +++ b/drivers/iio/afe/iio-rescale.c @@ -435,11 +435,37 @@ static int rescale_temp_sense_rtd_props(struct device *dev, return 0; } +static int rescale_temp_transducer_props(struct device *dev, + struct rescale *rescale) +{ + s32 offset = 0; + s32 sense = 1; + s32 alpha; + int ret; + + device_property_read_u32(dev, "sense-offset-millicelsius", &offset); + device_property_read_u32(dev, "sense-resistor-ohms", &sense); + ret = device_property_read_u32(dev, "alpha-ppm-per-celsius", &alpha); + if (ret) { + dev_err(dev, "failed to read alpha-ppm-per-celsius: %d\n", ret); + return ret; + } + + rescale->numerator = 1000000; + rescale->denominator = alpha * sense; + + rescale->offset = div_s64((s64)offset * rescale->denominator, + rescale->numerator); + + return 0; +} + enum rescale_variant { CURRENT_SENSE_AMPLIFIER, CURRENT_SENSE_SHUNT, VOLTAGE_DIVIDER, TEMP_SENSE_RTD, + TEMP_TRANSDUCER, }; static const struct rescale_cfg rescale_cfg[] = { @@ -459,6 +485,10 @@ static const struct rescale_cfg rescale_cfg[] = { .type = IIO_TEMP, .props = rescale_temp_sense_rtd_props, }, + [TEMP_TRANSDUCER] = { + .type = IIO_TEMP, + .props = rescale_temp_transducer_props, + }, }; static const struct of_device_id rescale_match[] = { @@ -470,6 +500,8 @@ static const struct of_device_id rescale_match[] = { .data = &rescale_cfg[VOLTAGE_DIVIDER], }, { .compatible = "temperature-sense-rtd", .data = &rescale_cfg[TEMP_SENSE_RTD], }, + { .compatible = "temperature-transducer", + .data = &rescale_cfg[TEMP_TRANSDUCER], }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, rescale_match); -- cgit v1.2.3 From d065a283fe8109a055930fc438eeea81d7f121df Mon Sep 17 00:00:00 2001 From: Liam Beguin Date: Sat, 12 Feb 2022 21:57:38 -0500 Subject: dt-bindings: iio: afe: add bindings for temperature-sense-rtd An ADC is often used to measure other quantities indirectly. This binding describe one case, the measurement of a temperature through the voltage across an RTD resistor such as a PT1000. Signed-off-by: Liam Beguin Reviewed-by: Rob Herring Reviewed-by: Peter Rosin Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220213025739.2561834-10-liambeguin@gmail.com Signed-off-by: Jonathan Cameron --- .../bindings/iio/afe/temperature-sense-rtd.yaml | 101 +++++++++++++++++++++ 1 file changed, 101 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/afe/temperature-sense-rtd.yaml diff --git a/Documentation/devicetree/bindings/iio/afe/temperature-sense-rtd.yaml b/Documentation/devicetree/bindings/iio/afe/temperature-sense-rtd.yaml new file mode 100644 index 000000000000..336ce96371db --- /dev/null +++ b/Documentation/devicetree/bindings/iio/afe/temperature-sense-rtd.yaml @@ -0,0 +1,101 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/afe/temperature-sense-rtd.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Temperature Sense RTD + +maintainers: + - Liam Beguin + +description: | + RTDs (Resistance Temperature Detectors) are a kind of temperature sensors + used to get a linear voltage to temperature reading within a give range + (usually 0 to 100 degrees Celsius). + + When an io-channel measures the output voltage across an RTD such as a + PT1000, the interesting measurement is almost always the corresponding + temperature, not the voltage output. This binding describes such a circuit. + + The general transfer function here is (using SI units) + + V = R(T) * iexc + R(T) = r0 * (1 + alpha * T) + T = 1 / (alpha * r0 * iexc) * (V - r0 * iexc) + + The following circuit matches what's in the examples section. + + 5V0 + ----- + | + +---+----+ + | R 5k | + +---+----+ + | + V 1mA + | + +---- Vout + | + +---+----+ + | PT1000 | + +---+----+ + | + ----- + GND + +properties: + compatible: + const: temperature-sense-rtd + + io-channels: + maxItems: 1 + description: | + Channel node of a voltage io-channel. + + '#io-channel-cells': + const: 0 + + excitation-current-microamp: + description: The current fed through the RTD sensor. + + alpha-ppm-per-celsius: + description: | + alpha can also be expressed in micro-ohms per ohm Celsius. It's a linear + approximation of the resistance versus temperature relationship + between 0 and 100 degrees Celsius. + + alpha = (R_100 - R_0) / (100 * R_0) + + Where, R_100 is the resistance of the sensor at 100 degrees Celsius, and + R_0 (or r-naught-ohms) is the resistance of the sensor at 0 degrees + Celsius. + + Pure platinum has an alpha of 3925. Industry standards such as IEC60751 + and ASTM E-1137 specify an alpha of 3850. + + r-naught-ohms: + description: | + Resistance of the sensor at 0 degrees Celsius. + Common values are 100 for PT100, 500 for PT500, and 1000 for PT1000 + +additionalProperties: false +required: + - compatible + - io-channels + - excitation-current-microamp + - alpha-ppm-per-celsius + - r-naught-ohms + +examples: + - | + pt1000_1: temperature-sensor0 { + compatible = "temperature-sense-rtd"; + #io-channel-cells = <0>; + io-channels = <&temp_adc1 0>; + + excitation-current-microamp = <1000>; /* i = U/R = 5 / 5000 */ + alpha-ppm-per-celsius = <3908>; + r-naught-ohms = <1000>; + }; +... -- cgit v1.2.3 From 66724c31c0a0959e540c95a82ed87763df7a5a69 Mon Sep 17 00:00:00 2001 From: Liam Beguin Date: Sat, 12 Feb 2022 21:57:39 -0500 Subject: dt-bindings: iio: afe: add bindings for temperature transducers An ADC is often used to measure other quantities indirectly. This binding describe one case, the measurement of a temperature through a temperature transducer (either voltage or current). Signed-off-by: Liam Beguin Reviewed-by: Rob Herring Reviewed-by: Peter Rosin Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220213025739.2561834-11-liambeguin@gmail.com Signed-off-by: Jonathan Cameron --- .../bindings/iio/afe/temperature-transducer.yaml | 114 +++++++++++++++++++++ 1 file changed, 114 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/afe/temperature-transducer.yaml diff --git a/Documentation/devicetree/bindings/iio/afe/temperature-transducer.yaml b/Documentation/devicetree/bindings/iio/afe/temperature-transducer.yaml new file mode 100644 index 000000000000..cfbf5350db27 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/afe/temperature-transducer.yaml @@ -0,0 +1,114 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/afe/temperature-transducer.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Temperature Transducer + +maintainers: + - Liam Beguin + +description: | + A temperature transducer is a device that converts a thermal quantity + into any other physical quantity. This binding applies to temperature to + voltage (like the LTC2997), and temperature to current (like the AD590) + linear transducers. + In both cases these are assumed to be connected to a voltage ADC. + + When an io-channel measures the output voltage of a temperature analog front + end such as a temperature transducer, the interesting measurement is almost + always the corresponding temperature, not the voltage output. This binding + describes such a circuit. + + The general transfer function here is (using SI units) + V(T) = Rsense * Isense(T) + T = (Isense(T) / alpha) + offset + T = 1 / (Rsense * alpha) * (V + offset * Rsense * alpha) + + When using a temperature to voltage transducer, Rsense is set to 1. + + The following circuits show a temperature to current and a temperature to + voltage transducer that can be used with this binding. + + VCC + ----- + | + +---+---+ + | AD590 | VCC + +---+---+ ----- + | | + V proportional to T +----+----+ + | D+ --+ | + +---- Vout | LTC2997 +--- Vout + | D- --+ | + +---+----+ +---------+ + | Rsense | | + +---+----+ ----- + | GND + ----- + GND + +properties: + compatible: + const: temperature-transducer + + io-channels: + maxItems: 1 + description: | + Channel node of a voltage io-channel. + + '#io-channel-cells': + const: 0 + + sense-offset-millicelsius: + description: | + Temperature offset. + This offset is commonly used to convert from Kelvins to degrees Celsius. + In that case, sense-offset-millicelsius would be set to <(-273150)>. + default: 0 + + sense-resistor-ohms: + description: | + The sense resistor. + By default sense-resistor-ohms cancels out the resistor making the + circuit behave like a temperature transducer. + default: 1 + + alpha-ppm-per-celsius: + description: | + Sometimes referred to as output gain, slope, or temperature coefficient. + + alpha is expressed in parts per million which can be micro-amps per + degrees Celsius or micro-volts per degrees Celsius. The is the main + characteristic of a temperature transducer and should be stated in the + datasheet. + +additionalProperties: false + +required: + - compatible + - io-channels + - alpha-ppm-per-celsius + +examples: + - | + ad950: temperature-sensor-0 { + compatible = "temperature-transducer"; + #io-channel-cells = <0>; + io-channels = <&temp_adc 3>; + + sense-offset-millicelsius = <(-273150)>; /* Kelvin to degrees Celsius */ + sense-resistor-ohms = <8060>; + alpha-ppm-per-celsius = <1>; /* 1 uA/K */ + }; + - | + znq_tmp: temperature-sensor-1 { + compatible = "temperature-transducer"; + #io-channel-cells = <0>; + io-channels = <&temp_adc 2>; + + sense-offset-millicelsius = <(-273150)>; /* Kelvin to degrees Celsius */ + alpha-ppm-per-celsius = <4000>; /* 4 mV/K */ + }; +... -- cgit v1.2.3 From 832cb9eeb9312dd2e14133681d3920b773ef1eac Mon Sep 17 00:00:00 2001 From: Nuno Sá Date: Fri, 25 Feb 2022 14:01:27 +0100 Subject: iio: dac: add support for ltc2688 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The LTC2688 is a 16 channel, 16 bit, +-15V DAC with an integrated precision reference. It is guaranteed monotonic and has built in rail-to-rail output buffers that can source or sink up to 20 mA. Signed-off-by: Nuno Sá Link: https://lore.kernel.org/r/20220225130129.69-2-nuno.sa@analog.com Signed-off-by: Jonathan Cameron --- MAINTAINERS | 7 + drivers/iio/dac/Kconfig | 11 + drivers/iio/dac/Makefile | 1 + drivers/iio/dac/ltc2688.c | 1071 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 1090 insertions(+) create mode 100644 drivers/iio/dac/ltc2688.c diff --git a/MAINTAINERS b/MAINTAINERS index 22296c5f24de..7f2e55a5ed2f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -11317,6 +11317,13 @@ S: Maintained F: Documentation/devicetree/bindings/iio/dac/lltc,ltc1660.yaml F: drivers/iio/dac/ltc1660.c +LTC2688 IIO DAC DRIVER +M: Nuno Sá +L: linux-iio@vger.kernel.org +S: Supported +W: http://ez.analog.com/community/linux-device-drivers +F: drivers/iio/dac/ltc2688.c + LTC2947 HARDWARE MONITOR DRIVER M: Nuno Sá L: linux-hwmon@vger.kernel.org diff --git a/drivers/iio/dac/Kconfig b/drivers/iio/dac/Kconfig index bfcf7568de32..c0bf0d84197f 100644 --- a/drivers/iio/dac/Kconfig +++ b/drivers/iio/dac/Kconfig @@ -131,6 +131,17 @@ config AD5624R_SPI Say yes here to build support for Analog Devices AD5624R, AD5644R and AD5664R converters (DAC). This driver uses the common SPI interface. +config LTC2688 + tristate "Analog Devices LTC2688 DAC spi driver" + depends on SPI + select REGMAP + help + Say yes here to build support for Analog Devices + LTC2688 converters (DAC). + + To compile this driver as a module, choose M here: the + module will be called ltc2688. + config AD5686 tristate diff --git a/drivers/iio/dac/Makefile b/drivers/iio/dac/Makefile index 01a50131572f..ec3e42713f00 100644 --- a/drivers/iio/dac/Makefile +++ b/drivers/iio/dac/Makefile @@ -35,6 +35,7 @@ obj-$(CONFIG_DS4424) += ds4424.o obj-$(CONFIG_LPC18XX_DAC) += lpc18xx_dac.o obj-$(CONFIG_LTC1660) += ltc1660.o obj-$(CONFIG_LTC2632) += ltc2632.o +obj-$(CONFIG_LTC2688) += ltc2688.o obj-$(CONFIG_M62332) += m62332.o obj-$(CONFIG_MAX517) += max517.o obj-$(CONFIG_MAX5821) += max5821.o diff --git a/drivers/iio/dac/ltc2688.c b/drivers/iio/dac/ltc2688.c new file mode 100644 index 000000000000..e41861d29767 --- /dev/null +++ b/drivers/iio/dac/ltc2688.c @@ -0,0 +1,1071 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * LTC2688 16 channel, 16 bit Voltage Output SoftSpan DAC driver + * + * Copyright 2022 Analog Devices Inc. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define LTC2688_DAC_CHANNELS 16 + +#define LTC2688_CMD_CH_CODE(x) (0x00 + (x)) +#define LTC2688_CMD_CH_SETTING(x) (0x10 + (x)) +#define LTC2688_CMD_CH_OFFSET(x) (0X20 + (x)) +#define LTC2688_CMD_CH_GAIN(x) (0x30 + (x)) +#define LTC2688_CMD_CH_CODE_UPDATE(x) (0x40 + (x)) + +#define LTC2688_CMD_CONFIG 0x70 +#define LTC2688_CMD_POWERDOWN 0x71 +#define LTC2688_CMD_A_B_SELECT 0x72 +#define LTC2688_CMD_SW_TOGGLE 0x73 +#define LTC2688_CMD_TOGGLE_DITHER_EN 0x74 +#define LTC2688_CMD_THERMAL_STAT 0x77 +#define LTC2688_CMD_UPDATE_ALL 0x7C +#define LTC2688_CMD_NOOP 0xFF + +#define LTC2688_READ_OPERATION 0x80 + +/* Channel Settings */ +#define LTC2688_CH_SPAN_MSK GENMASK(2, 0) +#define LTC2688_CH_OVERRANGE_MSK BIT(3) +#define LTC2688_CH_TD_SEL_MSK GENMASK(5, 4) +#define LTC2688_CH_TGP_MAX 3 +#define LTC2688_CH_DIT_PER_MSK GENMASK(8, 6) +#define LTC2688_CH_DIT_PH_MSK GENMASK(10, 9) +#define LTC2688_CH_MODE_MSK BIT(11) + +#define LTC2688_DITHER_RAW_MASK GENMASK(15, 2) +#define LTC2688_CH_CALIBBIAS_MASK GENMASK(15, 2) +#define LTC2688_DITHER_RAW_MAX_VAL (BIT(14) - 1) +#define LTC2688_CH_CALIBBIAS_MAX_VAL (BIT(14) - 1) + +/* Configuration register */ +#define LTC2688_CONFIG_RST BIT(15) +#define LTC2688_CONFIG_EXT_REF BIT(1) + +#define LTC2688_DITHER_FREQ_AVAIL_N 5 + +enum { + LTC2688_SPAN_RANGE_0V_5V, + LTC2688_SPAN_RANGE_0V_10V, + LTC2688_SPAN_RANGE_M5V_5V, + LTC2688_SPAN_RANGE_M10V_10V, + LTC2688_SPAN_RANGE_M15V_15V, + LTC2688_SPAN_RANGE_MAX +}; + +enum { + LTC2688_MODE_DEFAULT, + LTC2688_MODE_DITHER_TOGGLE, +}; + +struct ltc2688_chan { + long dither_frequency[LTC2688_DITHER_FREQ_AVAIL_N]; + bool overrange; + bool toggle_chan; + u8 mode; +}; + +struct ltc2688_state { + struct spi_device *spi; + struct regmap *regmap; + struct regulator_bulk_data regulators[2]; + struct ltc2688_chan channels[LTC2688_DAC_CHANNELS]; + struct iio_chan_spec *iio_chan; + /* lock to protect against multiple access to the device and shared data */ + struct mutex lock; + int vref; + /* + * DMA (thus cache coherency maintenance) requires the + * transfer buffers to live in their own cache lines. + */ + u8 tx_data[6] ____cacheline_aligned; + u8 rx_data[3]; +}; + +static int ltc2688_spi_read(void *context, const void *reg, size_t reg_size, + void *val, size_t val_size) +{ + struct ltc2688_state *st = context; + struct spi_transfer xfers[] = { + { + .tx_buf = st->tx_data, + .bits_per_word = 8, + .len = reg_size + val_size, + .cs_change = 1, + }, { + .tx_buf = st->tx_data + 3, + .rx_buf = st->rx_data, + .bits_per_word = 8, + .len = reg_size + val_size, + }, + }; + int ret; + + memcpy(st->tx_data, reg, reg_size); + + ret = spi_sync_transfer(st->spi, xfers, ARRAY_SIZE(xfers)); + if (ret) + return ret; + + memcpy(val, &st->rx_data[1], val_size); + + return 0; +} + +static int ltc2688_spi_write(void *context, const void *data, size_t count) +{ + struct ltc2688_state *st = context; + + return spi_write(st->spi, data, count); +} + +static int ltc2688_span_get(const struct ltc2688_state *st, int c) +{ + int ret, reg, span; + + ret = regmap_read(st->regmap, LTC2688_CMD_CH_SETTING(c), ®); + if (ret) + return ret; + + span = FIELD_GET(LTC2688_CH_SPAN_MSK, reg); + /* sanity check to make sure we don't get any weird value from the HW */ + if (span >= LTC2688_SPAN_RANGE_MAX) + return -EIO; + + return span; +} + +static const int ltc2688_span_helper[LTC2688_SPAN_RANGE_MAX][2] = { + {0, 5000}, {0, 10000}, {-5000, 5000}, {-10000, 10000}, {-15000, 15000}, +}; + +static int ltc2688_scale_get(const struct ltc2688_state *st, int c, int *val) +{ + const struct ltc2688_chan *chan = &st->channels[c]; + int span, fs; + + span = ltc2688_span_get(st, c); + if (span < 0) + return span; + + fs = ltc2688_span_helper[span][1] - ltc2688_span_helper[span][0]; + if (chan->overrange) + fs = mult_frac(fs, 105, 100); + + *val = DIV_ROUND_CLOSEST(fs * st->vref, 4096); + + return 0; +} + +static int ltc2688_offset_get(const struct ltc2688_state *st, int c, int *val) +{ + int span; + + span = ltc2688_span_get(st, c); + if (span < 0) + return span; + + if (ltc2688_span_helper[span][0] < 0) + *val = -32768; + else + *val = 0; + + return 0; +} + +enum { + LTC2688_INPUT_A, + LTC2688_INPUT_B, + LTC2688_INPUT_B_AVAIL, + LTC2688_DITHER_OFF, + LTC2688_DITHER_FREQ_AVAIL, +}; + +static int ltc2688_dac_code_write(struct ltc2688_state *st, u32 chan, u32 input, + u16 code) +{ + struct ltc2688_chan *c = &st->channels[chan]; + int ret, reg; + + /* 2 LSBs set to 0 if writing dither amplitude */ + if (!c->toggle_chan && input == LTC2688_INPUT_B) { + if (code > LTC2688_DITHER_RAW_MAX_VAL) + return -EINVAL; + + code = FIELD_PREP(LTC2688_DITHER_RAW_MASK, code); + } + + mutex_lock(&st->lock); + /* select the correct input register to read from */ + ret = regmap_update_bits(st->regmap, LTC2688_CMD_A_B_SELECT, BIT(chan), + input << chan); + if (ret) + goto out_unlock; + + /* + * If in dither/toggle mode the dac should be updated by an + * external signal (or sw toggle) and not here. + */ + if (c->mode == LTC2688_MODE_DEFAULT) + reg = LTC2688_CMD_CH_CODE_UPDATE(chan); + else + reg = LTC2688_CMD_CH_CODE(chan); + + ret = regmap_write(st->regmap, reg, code); +out_unlock: + mutex_unlock(&st->lock); + return ret; +} + +static int ltc2688_dac_code_read(struct ltc2688_state *st, u32 chan, u32 input, + u32 *code) +{ + struct ltc2688_chan *c = &st->channels[chan]; + int ret; + + mutex_lock(&st->lock); + ret = regmap_update_bits(st->regmap, LTC2688_CMD_A_B_SELECT, BIT(chan), + input << chan); + if (ret) + goto out_unlock; + + ret = regmap_read(st->regmap, LTC2688_CMD_CH_CODE(chan), code); +out_unlock: + mutex_unlock(&st->lock); + + if (!c->toggle_chan && input == LTC2688_INPUT_B) + *code = FIELD_GET(LTC2688_DITHER_RAW_MASK, *code); + + return ret; +} + +static const int ltc2688_raw_range[] = {0, 1, U16_MAX}; + +static int ltc2688_read_avail(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + const int **vals, int *type, int *length, + long info) +{ + switch (info) { + case IIO_CHAN_INFO_RAW: + *vals = ltc2688_raw_range; + *type = IIO_VAL_INT; + return IIO_AVAIL_RANGE; + default: + return -EINVAL; + } +} + +static int ltc2688_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int *val, + int *val2, long info) +{ + struct ltc2688_state *st = iio_priv(indio_dev); + int ret; + + switch (info) { + case IIO_CHAN_INFO_RAW: + ret = ltc2688_dac_code_read(st, chan->channel, LTC2688_INPUT_A, + val); + if (ret) + return ret; + + return IIO_VAL_INT; + case IIO_CHAN_INFO_OFFSET: + ret = ltc2688_offset_get(st, chan->channel, val); + if (ret) + return ret; + + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + ret = ltc2688_scale_get(st, chan->channel, val); + if (ret) + return ret; + + *val = 16; + return IIO_VAL_FRACTIONAL_LOG2; + case IIO_CHAN_INFO_CALIBBIAS: + ret = regmap_read(st->regmap, + LTC2688_CMD_CH_OFFSET(chan->channel), val); + if (ret) + return ret; + + *val = FIELD_GET(LTC2688_CH_CALIBBIAS_MASK, *val); + return IIO_VAL_INT; + case IIO_CHAN_INFO_CALIBSCALE: + ret = regmap_read(st->regmap, + LTC2688_CMD_CH_GAIN(chan->channel), val); + if (ret) + return ret; + + return IIO_VAL_INT; + default: + return -EINVAL; + } +} + +static int ltc2688_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int val, + int val2, long info) +{ + struct ltc2688_state *st = iio_priv(indio_dev); + + switch (info) { + case IIO_CHAN_INFO_RAW: + if (val > U16_MAX || val < 0) + return -EINVAL; + + return ltc2688_dac_code_write(st, chan->channel, + LTC2688_INPUT_A, val); + case IIO_CHAN_INFO_CALIBBIAS: + if (val > LTC2688_CH_CALIBBIAS_MAX_VAL) + return -EINVAL; + + return regmap_write(st->regmap, + LTC2688_CMD_CH_OFFSET(chan->channel), + FIELD_PREP(LTC2688_CH_CALIBBIAS_MASK, val)); + case IIO_CHAN_INFO_CALIBSCALE: + return regmap_write(st->regmap, + LTC2688_CMD_CH_GAIN(chan->channel), val); + default: + return -EINVAL; + } +} + +static ssize_t ltc2688_dither_toggle_set(struct iio_dev *indio_dev, + uintptr_t private, + const struct iio_chan_spec *chan, + const char *buf, size_t len) +{ + struct ltc2688_state *st = iio_priv(indio_dev); + struct ltc2688_chan *c = &st->channels[chan->channel]; + int ret; + bool en; + + ret = kstrtobool(buf, &en); + if (ret) + return ret; + + mutex_lock(&st->lock); + ret = regmap_update_bits(st->regmap, LTC2688_CMD_TOGGLE_DITHER_EN, + BIT(chan->channel), en << chan->channel); + if (ret) + goto out_unlock; + + c->mode = en ? LTC2688_MODE_DITHER_TOGGLE : LTC2688_MODE_DEFAULT; +out_unlock: + mutex_unlock(&st->lock); + + return ret ?: len; +} + +static ssize_t ltc2688_reg_bool_get(struct iio_dev *indio_dev, + uintptr_t private, + const struct iio_chan_spec *chan, + char *buf) +{ + const struct ltc2688_state *st = iio_priv(indio_dev); + int ret; + u32 val; + + ret = regmap_read(st->regmap, private, &val); + if (ret) + return ret; + + return sysfs_emit(buf, "%u\n", !!(val & BIT(chan->channel))); +} + +static ssize_t ltc2688_reg_bool_set(struct iio_dev *indio_dev, + uintptr_t private, + const struct iio_chan_spec *chan, + const char *buf, size_t len) +{ + const struct ltc2688_state *st = iio_priv(indio_dev); + int ret; + bool en; + + ret = kstrtobool(buf, &en); + if (ret) + return ret; + + ret = regmap_update_bits(st->regmap, private, BIT(chan->channel), + en << chan->channel); + if (ret) + return ret; + + return len; +} + +static ssize_t ltc2688_dither_freq_avail(const struct ltc2688_state *st, + const struct ltc2688_chan *chan, + char *buf) +{ + int sz = 0; + u32 f; + + for (f = 0; f < ARRAY_SIZE(chan->dither_frequency); f++) + sz += sysfs_emit_at(buf, sz, "%ld ", chan->dither_frequency[f]); + + buf[sz - 1] = '\n'; + + return sz; +} + +static ssize_t ltc2688_dither_freq_get(struct iio_dev *indio_dev, + uintptr_t private, + const struct iio_chan_spec *chan, + char *buf) +{ + const struct ltc2688_state *st = iio_priv(indio_dev); + const struct ltc2688_chan *c = &st->channels[chan->channel]; + u32 reg, freq; + int ret; + + if (private == LTC2688_DITHER_FREQ_AVAIL) + return ltc2688_dither_freq_avail(st, c, buf); + + ret = regmap_read(st->regmap, LTC2688_CMD_CH_SETTING(chan->channel), + ®); + if (ret) + return ret; + + freq = FIELD_GET(LTC2688_CH_DIT_PER_MSK, reg); + if (freq >= ARRAY_SIZE(c->dither_frequency)) + return -EIO; + + return sysfs_emit(buf, "%ld\n", c->dither_frequency[freq]); +} + +static ssize_t ltc2688_dither_freq_set(struct iio_dev *indio_dev, + uintptr_t private, + const struct iio_chan_spec *chan, + const char *buf, size_t len) +{ + const struct ltc2688_state *st = iio_priv(indio_dev); + const struct ltc2688_chan *c = &st->channels[chan->channel]; + long val; + u32 freq; + int ret; + + if (private == LTC2688_DITHER_FREQ_AVAIL) + return -EINVAL; + + ret = kstrtol(buf, 10, &val); + if (ret) + return ret; + + for (freq = 0; freq < ARRAY_SIZE(c->dither_frequency); freq++) { + if (val == c->dither_frequency[freq]) + break; + } + + if (freq == ARRAY_SIZE(c->dither_frequency)) + return -EINVAL; + + ret = regmap_update_bits(st->regmap, + LTC2688_CMD_CH_SETTING(chan->channel), + LTC2688_CH_DIT_PER_MSK, + FIELD_PREP(LTC2688_CH_DIT_PER_MSK, freq)); + if (ret) + return ret; + + return len; +} + +static ssize_t ltc2688_dac_input_read(struct iio_dev *indio_dev, + uintptr_t private, + const struct iio_chan_spec *chan, + char *buf) +{ + struct ltc2688_state *st = iio_priv(indio_dev); + int ret; + u32 val; + + if (private == LTC2688_INPUT_B_AVAIL) + return sysfs_emit(buf, "[%u %u %u]\n", ltc2688_raw_range[0], + ltc2688_raw_range[1], + ltc2688_raw_range[2] / 4); + + if (private == LTC2688_DITHER_OFF) + return sysfs_emit(buf, "0\n"); + + ret = ltc2688_dac_code_read(st, chan->channel, private, &val); + if (ret) + return ret; + + return sysfs_emit(buf, "%u\n", val); +} + +static ssize_t ltc2688_dac_input_write(struct iio_dev *indio_dev, + uintptr_t private, + const struct iio_chan_spec *chan, + const char *buf, size_t len) +{ + struct ltc2688_state *st = iio_priv(indio_dev); + int ret; + u16 val; + + if (private == LTC2688_INPUT_B_AVAIL || private == LTC2688_DITHER_OFF) + return -EINVAL; + + ret = kstrtou16(buf, 10, &val); + if (ret) + return ret; + + ret = ltc2688_dac_code_write(st, chan->channel, private, val); + if (ret) + return ret; + + return len; +} + +static int ltc2688_get_dither_phase(struct iio_dev *dev, + const struct iio_chan_spec *chan) +{ + struct ltc2688_state *st = iio_priv(dev); + int ret, regval; + + ret = regmap_read(st->regmap, LTC2688_CMD_CH_SETTING(chan->channel), + ®val); + if (ret) + return ret; + + return FIELD_GET(LTC2688_CH_DIT_PH_MSK, regval); +} + +static int ltc2688_set_dither_phase(struct iio_dev *dev, + const struct iio_chan_spec *chan, + unsigned int phase) +{ + struct ltc2688_state *st = iio_priv(dev); + + return regmap_update_bits(st->regmap, + LTC2688_CMD_CH_SETTING(chan->channel), + LTC2688_CH_DIT_PH_MSK, + FIELD_PREP(LTC2688_CH_DIT_PH_MSK, phase)); +} + +static int ltc2688_reg_access(struct iio_dev *indio_dev, + unsigned int reg, + unsigned int writeval, + unsigned int *readval) +{ + struct ltc2688_state *st = iio_priv(indio_dev); + + if (readval) + return regmap_read(st->regmap, reg, readval); + + return regmap_write(st->regmap, reg, writeval); +} + +static const char * const ltc2688_dither_phase[] = { + "0", "1.5708", "3.14159", "4.71239", +}; + +static const struct iio_enum ltc2688_dither_phase_enum = { + .items = ltc2688_dither_phase, + .num_items = ARRAY_SIZE(ltc2688_dither_phase), + .set = ltc2688_set_dither_phase, + .get = ltc2688_get_dither_phase, +}; + +#define LTC2688_CHAN_EXT_INFO(_name, _what, _shared, _read, _write) { \ + .name = _name, \ + .read = (_read), \ + .write = (_write), \ + .private = (_what), \ + .shared = (_shared), \ +} + +/* + * For toggle mode we only expose the symbol attr (sw_toggle) in case a TGPx is + * not provided in dts. + */ +static const struct iio_chan_spec_ext_info ltc2688_toggle_sym_ext_info[] = { + LTC2688_CHAN_EXT_INFO("raw0", LTC2688_INPUT_A, IIO_SEPARATE, + ltc2688_dac_input_read, ltc2688_dac_input_write), + LTC2688_CHAN_EXT_INFO("raw1", LTC2688_INPUT_B, IIO_SEPARATE, + ltc2688_dac_input_read, ltc2688_dac_input_write), + LTC2688_CHAN_EXT_INFO("toggle_en", LTC2688_CMD_TOGGLE_DITHER_EN, + IIO_SEPARATE, ltc2688_reg_bool_get, + ltc2688_dither_toggle_set), + LTC2688_CHAN_EXT_INFO("powerdown", LTC2688_CMD_POWERDOWN, IIO_SEPARATE, + ltc2688_reg_bool_get, ltc2688_reg_bool_set), + LTC2688_CHAN_EXT_INFO("symbol", LTC2688_CMD_SW_TOGGLE, IIO_SEPARATE, + ltc2688_reg_bool_get, ltc2688_reg_bool_set), + {} +}; + +static const struct iio_chan_spec_ext_info ltc2688_toggle_ext_info[] = { + LTC2688_CHAN_EXT_INFO("raw0", LTC2688_INPUT_A, IIO_SEPARATE, + ltc2688_dac_input_read, ltc2688_dac_input_write), + LTC2688_CHAN_EXT_INFO("raw1", LTC2688_INPUT_B, IIO_SEPARATE, + ltc2688_dac_input_read, ltc2688_dac_input_write), + LTC2688_CHAN_EXT_INFO("toggle_en", LTC2688_CMD_TOGGLE_DITHER_EN, + IIO_SEPARATE, ltc2688_reg_bool_get, + ltc2688_dither_toggle_set), + LTC2688_CHAN_EXT_INFO("powerdown", LTC2688_CMD_POWERDOWN, IIO_SEPARATE, + ltc2688_reg_bool_get, ltc2688_reg_bool_set), + {} +}; + +static struct iio_chan_spec_ext_info ltc2688_dither_ext_info[] = { + LTC2688_CHAN_EXT_INFO("dither_raw", LTC2688_INPUT_B, IIO_SEPARATE, + ltc2688_dac_input_read, ltc2688_dac_input_write), + LTC2688_CHAN_EXT_INFO("dither_raw_available", LTC2688_INPUT_B_AVAIL, + IIO_SEPARATE, ltc2688_dac_input_read, + ltc2688_dac_input_write), + LTC2688_CHAN_EXT_INFO("dither_offset", LTC2688_DITHER_OFF, IIO_SEPARATE, + ltc2688_dac_input_read, ltc2688_dac_input_write), + /* + * Not IIO_ENUM because the available freq needs to be computed at + * probe. We could still use it, but it didn't felt much right. + */ + LTC2688_CHAN_EXT_INFO("dither_frequency", 0, IIO_SEPARATE, + ltc2688_dither_freq_get, ltc2688_dither_freq_set), + LTC2688_CHAN_EXT_INFO("dither_frequency_available", + LTC2688_DITHER_FREQ_AVAIL, IIO_SEPARATE, + ltc2688_dither_freq_get, ltc2688_dither_freq_set), + IIO_ENUM("dither_phase", IIO_SEPARATE, <c2688_dither_phase_enum), + IIO_ENUM_AVAILABLE("dither_phase", IIO_SEPARATE, + <c2688_dither_phase_enum), + LTC2688_CHAN_EXT_INFO("dither_en", LTC2688_CMD_TOGGLE_DITHER_EN, + IIO_SEPARATE, ltc2688_reg_bool_get, + ltc2688_dither_toggle_set), + LTC2688_CHAN_EXT_INFO("powerdown", LTC2688_CMD_POWERDOWN, IIO_SEPARATE, + ltc2688_reg_bool_get, ltc2688_reg_bool_set), + {} +}; + +static const struct iio_chan_spec_ext_info ltc2688_ext_info[] = { + LTC2688_CHAN_EXT_INFO("powerdown", LTC2688_CMD_POWERDOWN, IIO_SEPARATE, + ltc2688_reg_bool_get, ltc2688_reg_bool_set), + {} +}; + +#define LTC2688_CHANNEL(_chan) { \ + .type = IIO_VOLTAGE, \ + .indexed = 1, \ + .output = 1, \ + .channel = (_chan), \ + .info_mask_separate = BIT(IIO_CHAN_INFO_CALIBSCALE) | \ + BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_OFFSET) | \ + BIT(IIO_CHAN_INFO_CALIBBIAS) | BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_separate_available = BIT(IIO_CHAN_INFO_RAW), \ + .ext_info = ltc2688_ext_info, \ +} + +static const struct iio_chan_spec ltc2688_channels[] = { + LTC2688_CHANNEL(0), + LTC2688_CHANNEL(1), + LTC2688_CHANNEL(2), + LTC2688_CHANNEL(3), + LTC2688_CHANNEL(4), + LTC2688_CHANNEL(5), + LTC2688_CHANNEL(6), + LTC2688_CHANNEL(7), + LTC2688_CHANNEL(8), + LTC2688_CHANNEL(9), + LTC2688_CHANNEL(10), + LTC2688_CHANNEL(11), + LTC2688_CHANNEL(12), + LTC2688_CHANNEL(13), + LTC2688_CHANNEL(14), + LTC2688_CHANNEL(15), +}; + +static void ltc2688_clk_disable(void *clk) +{ + clk_disable_unprepare(clk); +} + +static const int ltc2688_period[LTC2688_DITHER_FREQ_AVAIL_N] = { + 4, 8, 16, 32, 64, +}; + +static int ltc2688_tgp_clk_setup(struct ltc2688_state *st, + struct ltc2688_chan *chan, + struct fwnode_handle *node, int tgp) +{ + unsigned long rate; + struct clk *clk; + int ret, f; + + clk = devm_get_clk_from_child(&st->spi->dev, to_of_node(node), NULL); + if (IS_ERR(clk)) + return dev_err_probe(&st->spi->dev, PTR_ERR(clk), + "failed to get tgp clk.\n"); + + ret = clk_prepare_enable(clk); + if (ret) + return dev_err_probe(&st->spi->dev, ret, + "failed to enable tgp clk.\n"); + + ret = devm_add_action_or_reset(&st->spi->dev, ltc2688_clk_disable, clk); + if (ret) + return ret; + + if (chan->toggle_chan) + return 0; + + /* calculate available dither frequencies */ + rate = clk_get_rate(clk); + for (f = 0; f < ARRAY_SIZE(chan->dither_frequency); f++) + chan->dither_frequency[f] = DIV_ROUND_CLOSEST(rate, ltc2688_period[f]); + + return 0; +} + +static int ltc2688_span_lookup(const struct ltc2688_state *st, int min, int max) +{ + u32 span; + + for (span = 0; span < ARRAY_SIZE(ltc2688_span_helper); span++) { + if (min == ltc2688_span_helper[span][0] && + max == ltc2688_span_helper[span][1]) + return span; + } + + return -EINVAL; +} + +static int ltc2688_channel_config(struct ltc2688_state *st) +{ + struct device *dev = &st->spi->dev; + struct fwnode_handle *child; + u32 reg, clk_input, val, tmp[2]; + int ret, span; + + device_for_each_child_node(dev, child) { + struct ltc2688_chan *chan; + + ret = fwnode_property_read_u32(child, "reg", ®); + if (ret) { + fwnode_handle_put(child); + return dev_err_probe(dev, ret, + "Failed to get reg property\n"); + } + + if (reg >= LTC2688_DAC_CHANNELS) { + fwnode_handle_put(child); + return dev_err_probe(dev, -EINVAL, + "reg bigger than: %d\n", + LTC2688_DAC_CHANNELS); + } + + val = 0; + chan = &st->channels[reg]; + if (fwnode_property_read_bool(child, "adi,toggle-mode")) { + chan->toggle_chan = true; + /* assume sw toggle ABI */ + st->iio_chan[reg].ext_info = ltc2688_toggle_sym_ext_info; + /* + * Clear IIO_CHAN_INFO_RAW bit as toggle channels expose + * out_voltage_raw{0|1} files. + */ + __clear_bit(IIO_CHAN_INFO_RAW, + &st->iio_chan[reg].info_mask_separate); + } + + ret = fwnode_property_read_u32_array(child, "adi,output-range-microvolt", + tmp, ARRAY_SIZE(tmp)); + if (!ret) { + span = ltc2688_span_lookup(st, (int)tmp[0] / 1000, + tmp[1] / 1000); + if (span < 0) { + fwnode_handle_put(child); + return dev_err_probe(dev, -EINVAL, + "output range not valid:[%d %d]\n", + tmp[0], tmp[1]); + } + + val |= FIELD_PREP(LTC2688_CH_SPAN_MSK, span); + } + + ret = fwnode_property_read_u32(child, "adi,toggle-dither-input", + &clk_input); + if (!ret) { + if (clk_input >= LTC2688_CH_TGP_MAX) { + fwnode_handle_put(child); + return dev_err_probe(dev, -EINVAL, + "toggle-dither-input inv value(%d)\n", + clk_input); + } + + ret = ltc2688_tgp_clk_setup(st, chan, child, clk_input); + if (ret) { + fwnode_handle_put(child); + return ret; + } + + /* + * 0 means software toggle which is the default mode. + * Hence the +1. + */ + val |= FIELD_PREP(LTC2688_CH_TD_SEL_MSK, clk_input + 1); + + /* + * If a TGPx is given, we automatically assume a dither + * capable channel (unless toggle is already enabled). + * On top of this we just set here the dither bit in the + * channel settings. It won't have any effect until the + * global toggle/dither bit is enabled. + */ + if (!chan->toggle_chan) { + val |= FIELD_PREP(LTC2688_CH_MODE_MSK, 1); + st->iio_chan[reg].ext_info = ltc2688_dither_ext_info; + } else { + /* wait, no sw toggle after all */ + st->iio_chan[reg].ext_info = ltc2688_toggle_ext_info; + } + } + + if (fwnode_property_read_bool(child, "adi,overrange")) { + chan->overrange = true; + val |= LTC2688_CH_OVERRANGE_MSK; + } + + if (!val) + continue; + + ret = regmap_write(st->regmap, LTC2688_CMD_CH_SETTING(reg), + val); + if (ret) { + fwnode_handle_put(child); + return dev_err_probe(dev, -EINVAL, + "failed to set chan settings\n"); + } + } + + return 0; +} + +static int ltc2688_setup(struct ltc2688_state *st, struct regulator *vref) +{ + struct gpio_desc *gpio; + int ret; + + /* + * If we have a reset pin, use that to reset the board, If not, use + * the reset bit. + */ + gpio = devm_gpiod_get_optional(&st->spi->dev, "clr", GPIOD_OUT_HIGH); + if (IS_ERR(gpio)) + return dev_err_probe(&st->spi->dev, PTR_ERR(gpio), + "Failed to get reset gpio"); + if (gpio) { + usleep_range(1000, 1200); + /* bring device out of reset */ + gpiod_set_value_cansleep(gpio, 0); + } else { + ret = regmap_update_bits(st->regmap, LTC2688_CMD_CONFIG, + LTC2688_CONFIG_RST, + LTC2688_CONFIG_RST); + if (ret) + return ret; + } + + usleep_range(10000, 12000); + + /* + * Duplicate the default channel configuration as it can change during + * @ltc2688_channel_config() + */ + st->iio_chan = devm_kmemdup(&st->spi->dev, ltc2688_channels, + sizeof(ltc2688_channels), GFP_KERNEL); + if (!st->iio_chan) + return -ENOMEM; + + ret = ltc2688_channel_config(st); + if (ret) + return ret; + + if (!vref) + return 0; + + return regmap_set_bits(st->regmap, LTC2688_CMD_CONFIG, + LTC2688_CONFIG_EXT_REF); +} + +static void ltc2688_disable_regulators(void *data) +{ + struct ltc2688_state *st = data; + + regulator_bulk_disable(ARRAY_SIZE(st->regulators), st->regulators); +} + +static void ltc2688_disable_regulator(void *regulator) +{ + regulator_disable(regulator); +} + +static bool ltc2688_reg_readable(struct device *dev, unsigned int reg) +{ + switch (reg) { + case LTC2688_CMD_CH_CODE(0) ... LTC2688_CMD_CH_GAIN(15): + return true; + case LTC2688_CMD_CONFIG ... LTC2688_CMD_THERMAL_STAT: + return true; + default: + return false; + } +} + +static bool ltc2688_reg_writable(struct device *dev, unsigned int reg) +{ + /* + * There's a jump from 0x76 to 0x78 in the write codes and the thermal + * status code is 0x77 (which is read only) so that we need to check + * that special condition. + */ + if (reg <= LTC2688_CMD_UPDATE_ALL && reg != LTC2688_CMD_THERMAL_STAT) + return true; + + return false; +} + +static struct regmap_bus ltc2688_regmap_bus = { + .read = ltc2688_spi_read, + .write = ltc2688_spi_write, + .read_flag_mask = LTC2688_READ_OPERATION, + .reg_format_endian_default = REGMAP_ENDIAN_BIG, + .val_format_endian_default = REGMAP_ENDIAN_BIG, +}; + +static const struct regmap_config ltc2688_regmap_config = { + .reg_bits = 8, + .val_bits = 16, + .readable_reg = ltc2688_reg_readable, + .writeable_reg = ltc2688_reg_writable, + /* ignoring the no op command */ + .max_register = LTC2688_CMD_UPDATE_ALL, +}; + +static const struct iio_info ltc2688_info = { + .write_raw = ltc2688_write_raw, + .read_raw = ltc2688_read_raw, + .read_avail = ltc2688_read_avail, + .debugfs_reg_access = ltc2688_reg_access, +}; + +static int ltc2688_probe(struct spi_device *spi) +{ + struct ltc2688_state *st; + struct iio_dev *indio_dev; + struct regulator *vref_reg; + struct device *dev = &spi->dev; + int ret; + + indio_dev = devm_iio_device_alloc(dev, sizeof(*st)); + if (!indio_dev) + return -ENOMEM; + + st = iio_priv(indio_dev); + st->spi = spi; + + /* Just write this once. No need to do it in every regmap read. */ + st->tx_data[3] = LTC2688_CMD_NOOP; + mutex_init(&st->lock); + + st->regmap = devm_regmap_init(dev, <c2688_regmap_bus, st, + <c2688_regmap_config); + if (IS_ERR(st->regmap)) + return dev_err_probe(dev, PTR_ERR(st->regmap), + "Failed to init regmap"); + + st->regulators[0].supply = "vcc"; + st->regulators[1].supply = "iovcc"; + ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(st->regulators), + st->regulators); + if (ret) + return dev_err_probe(dev, ret, "Failed to get regulators\n"); + + ret = regulator_bulk_enable(ARRAY_SIZE(st->regulators), st->regulators); + if (ret) + return dev_err_probe(dev, ret, "Failed to enable regulators\n"); + + ret = devm_add_action_or_reset(dev, ltc2688_disable_regulators, st); + if (ret) + return ret; + + vref_reg = devm_regulator_get_optional(dev, "vref"); + if (IS_ERR(vref_reg)) { + if (PTR_ERR(vref_reg) != -ENODEV) + return dev_err_probe(dev, PTR_ERR(vref_reg), + "Failed to get vref regulator"); + + vref_reg = NULL; + /* internal reference */ + st->vref = 4096; + } else { + ret = regulator_enable(vref_reg); + if (ret) + return dev_err_probe(dev, ret, + "Failed to enable vref regulators\n"); + + ret = devm_add_action_or_reset(dev, ltc2688_disable_regulator, + vref_reg); + if (ret) + return ret; + + ret = regulator_get_voltage(vref_reg); + if (ret < 0) + return dev_err_probe(dev, ret, "Failed to get vref\n"); + + st->vref = ret / 1000; + } + + ret = ltc2688_setup(st, vref_reg); + if (ret) + return ret; + + indio_dev->name = "ltc2688"; + indio_dev->info = <c2688_info; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->channels = st->iio_chan; + indio_dev->num_channels = ARRAY_SIZE(ltc2688_channels); + + return devm_iio_device_register(dev, indio_dev); +} + +static const struct of_device_id ltc2688_of_id[] = { + { .compatible = "adi,ltc2688" }, + {} +}; +MODULE_DEVICE_TABLE(of, ltc2688_of_id); + +static const struct spi_device_id ltc2688_id[] = { + { "ltc2688" }, + {} +}; +MODULE_DEVICE_TABLE(spi, ltc2688_id); + +static struct spi_driver ltc2688_driver = { + .driver = { + .name = "ltc2688", + .of_match_table = ltc2688_of_id, + }, + .probe = ltc2688_probe, + .id_table = ltc2688_id, +}; +module_spi_driver(ltc2688_driver); + +MODULE_AUTHOR("Nuno Sá "); +MODULE_DESCRIPTION("Analog Devices LTC2688 DAC"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 52302f87d0a126a34686f40cdd4ab28f9e824a68 Mon Sep 17 00:00:00 2001 From: Nuno Sá Date: Fri, 25 Feb 2022 14:01:28 +0100 Subject: iio: ABI: add ABI file for the LTC2688 DAC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Define the sysfs interface for toggle or dither capable channels. Dither capable channels will have the extended interface: * out_voltageY_dither_en * out_voltageY_dither_raw * out_voltageY_dither_offset * out_voltageY_dither_raw_available * out_voltageY_dither_frequency * out_voltageY_dither_frequency_available * out_voltageY_dither_phase * out_voltageY_dither_phase_available Toggle enabled channels will have: * out_voltageY_toggle_en * out_voltageY_raw0 * out_voltageY_raw1 * out_voltageY_symbol The common interface present in all channels is: * out_voltageY_raw (not present in toggle enabled channels) * out_voltageY_raw_available * out_voltageY_powerdown * out_voltageY_scale * out_voltageY_offset * out_voltageY_calibbias * out_voltageY_calibscale Signed-off-by: Nuno Sá Link: https://lore.kernel.org/r/20220225130129.69-3-nuno.sa@analog.com Signed-off-by: Jonathan Cameron --- .../ABI/testing/sysfs-bus-iio-dac-ltc2688 | 86 ++++++++++++++++++++++ MAINTAINERS | 1 + 2 files changed, 87 insertions(+) create mode 100644 Documentation/ABI/testing/sysfs-bus-iio-dac-ltc2688 diff --git a/Documentation/ABI/testing/sysfs-bus-iio-dac-ltc2688 b/Documentation/ABI/testing/sysfs-bus-iio-dac-ltc2688 new file mode 100644 index 000000000000..1c35971277ba --- /dev/null +++ b/Documentation/ABI/testing/sysfs-bus-iio-dac-ltc2688 @@ -0,0 +1,86 @@ +What: /sys/bus/iio/devices/iio:deviceX/out_voltageY_dither_en +KernelVersion: 5.18 +Contact: linux-iio@vger.kernel.org +Description: + Dither enable. Write 1 to enable dither or 0 to disable it. This is useful + for changing the dither parameters. They way it should be done is: + + - disable dither operation; + - change dither parameters (eg: frequency, phase...); + - enabled dither operation + +What: /sys/bus/iio/devices/iio:deviceX/out_voltageY_dither_raw +KernelVersion: 5.18 +Contact: linux-iio@vger.kernel.org +Description: + This raw, unscaled value refers to the dither signal amplitude. + The same scale as in out_voltageY_raw applies. However, the + offset might be different as it's always 0 for this attribute. + +What: /sys/bus/iio/devices/iio:deviceX/out_voltageY_dither_raw_available +KernelVersion: 5.18 +Contact: linux-iio@vger.kernel.org +Description: + Available range for dither raw amplitude values. + +What: /sys/bus/iio/devices/iio:deviceX/out_voltageY_dither_offset +KernelVersion: 5.18 +Contact: linux-iio@vger.kernel.org +Description: + Offset applied to out_voltageY_dither_raw. Read only attribute + always set to 0. + +What: /sys/bus/iio/devices/iio:deviceX/out_voltageY_dither_frequency +KernelVersion: 5.18 +Contact: linux-iio@vger.kernel.org +Description: + Sets the dither signal frequency. Units are in Hz. + +What: /sys/bus/iio/devices/iio:deviceX/out_voltageY_dither_frequency_available +KernelVersion: 5.18 +Contact: linux-iio@vger.kernel.org +Description: + Returns the available values for the dither frequency. + +What: /sys/bus/iio/devices/iio:deviceX/out_voltageY_dither_phase +KernelVersion: 5.18 +Contact: linux-iio@vger.kernel.org +Description: + Sets the dither signal phase. Units are in Radians. + +What: /sys/bus/iio/devices/iio:deviceX/out_voltageY_dither_phase_available +KernelVersion: 5.18 +Contact: linux-iio@vger.kernel.org +Description: + Returns the available values for the dither phase. + +What: /sys/bus/iio/devices/iio:deviceX/out_voltageY_toggle_en +KernelVersion: 5.18 +Contact: linux-iio@vger.kernel.org +Description: + Toggle enable. Write 1 to enable toggle or 0 to disable it. This is + useful when one wants to change the DAC output codes. The way it should + be done is: + + - disable toggle operation; + - change out_voltageY_raw0 and out_voltageY_raw1; + - enable toggle operation. + +What: /sys/bus/iio/devices/iio:deviceX/out_voltageY_raw0 +What: /sys/bus/iio/devices/iio:deviceX/out_voltageY_raw1 +KernelVersion: 5.18 +Contact: linux-iio@vger.kernel.org +Description: + It has the same meaning as out_voltageY_raw. This attribute is + specific to toggle enabled channels and refers to the DAC output + code in INPUT_A (_raw0) and INPUT_B (_raw1). The same scale and offset + as in out_voltageY_raw applies. + +What: /sys/bus/iio/devices/iio:deviceX/out_voltageY_symbol +KernelVersion: 5.18 +Contact: linux-iio@vger.kernel.org +Description: + Performs a SW toggle. This attribute is specific to toggle + enabled channels and allows to toggle between out_voltageY_raw0 + and out_voltageY_raw1 through software. Writing 0 will select + out_voltageY_raw0 while 1 selects out_voltageY_raw1. diff --git a/MAINTAINERS b/MAINTAINERS index 7f2e55a5ed2f..29f4b6d39f3a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -11322,6 +11322,7 @@ M: Nuno Sá L: linux-iio@vger.kernel.org S: Supported W: http://ez.analog.com/community/linux-device-drivers +F: Documentation/ABI/testing/sysfs-bus-iio-dac-ltc2688 F: drivers/iio/dac/ltc2688.c LTC2947 HARDWARE MONITOR DRIVER -- cgit v1.2.3 From f568cbd9aef24a02b22884d92c154f3af076b383 Mon Sep 17 00:00:00 2001 From: Nuno Sá Date: Fri, 25 Feb 2022 14:01:29 +0100 Subject: dt-bindings: iio: Add ltc2688 documentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Document the LTC2688 devicetree properties. Signed-off-by: Nuno Sá Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20220225130129.69-4-nuno.sa@analog.com Signed-off-by: Jonathan Cameron --- .../devicetree/bindings/iio/dac/adi,ltc2688.yaml | 146 +++++++++++++++++++++ MAINTAINERS | 1 + 2 files changed, 147 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/dac/adi,ltc2688.yaml diff --git a/Documentation/devicetree/bindings/iio/dac/adi,ltc2688.yaml b/Documentation/devicetree/bindings/iio/dac/adi,ltc2688.yaml new file mode 100644 index 000000000000..48f9e7d29423 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/dac/adi,ltc2688.yaml @@ -0,0 +1,146 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/dac/adi,ltc2688.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Analog Devices LTC2688 DAC + +maintainers: + - Nuno Sá + +description: | + Analog Devices LTC2688 16 channel, 16 bit, +-15V DAC + https://www.analog.com/media/en/technical-documentation/data-sheets/ltc2688.pdf + +properties: + compatible: + enum: + - adi,ltc2688 + + reg: + maxItems: 1 + + vcc-supply: + description: Analog Supply Voltage Input. + + iovcc-supply: + description: Digital Input/Output Supply Voltage. + + vref-supply: + description: + Reference Input/Output. The voltage at the REF pin sets the full-scale + range of all channels. If not provided the internal reference is used and + also provided on the VREF pin". + + clr-gpios: + description: + If specified, it will be asserted during driver probe. As the line is + active low, it should be marked GPIO_ACTIVE_LOW. + maxItems: 1 + + '#address-cells': + const: 1 + + '#size-cells': + const: 0 + +patternProperties: + "^channel@([0-9]|1[0-5])$": + type: object + + properties: + reg: + description: The channel number representing the DAC output channel. + maximum: 15 + + adi,toggle-mode: + description: + Set the channel as a toggle enabled channel. Toggle operation enables + fast switching of a DAC output between two different DAC codes without + any SPI transaction. + type: boolean + + adi,output-range-microvolt: + description: Specify the channel output full scale range. + oneOf: + - items: + - const: 0 + - enum: [5000000, 10000000] + - items: + - const: -5000000 + - const: 5000000 + - items: + - const: -10000000 + - const: 10000000 + - items: + - const: -15000000 + - const: 15000000 + + adi,overrange: + description: Enable 5% overrange over the selected full scale range. + type: boolean + + clocks: + maxItems: 1 + + adi,toggle-dither-input: + description: + Selects the TGPx pin to be associated with this channel. This setting + only makes sense for toggle or dither enabled channels. If + @adi,toggle-mode is not set and this property is given, the channel is + assumed to be a dither capable channel. Note that multiple channels + can be mapped to the same pin. If this setting is given, the + respective @clock must also be provided. Mappings between this and + input pins + 0 - TGP1 + 1 - TGP2 + 2 - TGP3 + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [0, 1, 2] + + dependencies: + adi,toggle-dither-input: [ clocks ] + + required: + - reg + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + + spi { + #address-cells = <1>; + #size-cells = <0>; + ltc2688: ltc2688@0 { + compatible = "adi,ltc2688"; + reg = <0>; + + vcc-supply = <&vcc>; + iovcc-supply = <&vcc>; + vref-supply = <&vref>; + + #address-cells = <1>; + #size-cells = <0>; + channel@0 { + reg = <0>; + adi,toggle-mode; + adi,overrange; + }; + + channel@1 { + reg = <1>; + adi,output-range-microvolt = <0 10000000>; + + clocks = <&clock_tgp3>; + adi,toggle-dither-input = <2>; + }; + }; + }; + +... diff --git a/MAINTAINERS b/MAINTAINERS index 29f4b6d39f3a..80244d55a4bc 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -11323,6 +11323,7 @@ L: linux-iio@vger.kernel.org S: Supported W: http://ez.analog.com/community/linux-device-drivers F: Documentation/ABI/testing/sysfs-bus-iio-dac-ltc2688 +F: Documentation/devicetree/bindings/iio/dac/adi,ltc2688.yaml F: drivers/iio/dac/ltc2688.c LTC2947 HARDWARE MONITOR DRIVER -- cgit v1.2.3 From 6270bf1f0197739a9cddaf0a40699a99b7357cb5 Mon Sep 17 00:00:00 2001 From: Haibo Chen Date: Thu, 24 Feb 2022 19:29:51 +0800 Subject: iio: imu: st_lsm6dsx: use dev_to_iio_dev() to get iio_dev struct dev_get_drvdata() on iio_dev->dev no longer returns the iio_dev. Use dev_to_iio_dev() to get iio_dev struct. Fixes: 8b7651f25962 ("iio: iio_device_alloc(): Remove unnecessary self drvdata") Signed-off-by: Haibo Chen Link: https://lore.kernel.org/r/1645702191-9400-1-git-send-email-haibo.chen@nxp.com Cc: Signed-off-by: Jonathan Cameron --- drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c index 727b4b6ac696..8b662332c282 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c @@ -1629,7 +1629,7 @@ st_lsm6dsx_sysfs_sampling_frequency_avail(struct device *dev, struct device_attribute *attr, char *buf) { - struct st_lsm6dsx_sensor *sensor = iio_priv(dev_get_drvdata(dev)); + struct st_lsm6dsx_sensor *sensor = iio_priv(dev_to_iio_dev(dev)); const struct st_lsm6dsx_odr_table_entry *odr_table; int i, len = 0; @@ -1647,7 +1647,7 @@ static ssize_t st_lsm6dsx_sysfs_scale_avail(struct device *dev, struct device_attribute *attr, char *buf) { - struct st_lsm6dsx_sensor *sensor = iio_priv(dev_get_drvdata(dev)); + struct st_lsm6dsx_sensor *sensor = iio_priv(dev_to_iio_dev(dev)); const struct st_lsm6dsx_fs_table_entry *fs_table; struct st_lsm6dsx_hw *hw = sensor->hw; int i, len = 0; -- cgit v1.2.3 From 571426631acf46e2999c7ecd1e9d048172969a43 Mon Sep 17 00:00:00 2001 From: Billy Tsai Date: Mon, 21 Feb 2022 09:27:05 +0800 Subject: iio: adc: aspeed: Add divider flag to fix incorrect voltage reading. The formula for the ADC sampling period in ast2400/ast2500 is: ADC clock period = PCLK * 2 * (ADC0C[31:17] + 1) * (ADC0C[9:0]) When ADC0C[9:0] is set to 0 the sampling voltage will be lower than expected, because the hardware may not have enough time to charge/discharge to a stable voltage. This patch use the flag CLK_DIVIDER_ONE_BASED which will use the raw value read from the register, with the value of zero considered invalid to conform to the corrected formula. Fixes: 573803234e72 ("iio: Aspeed ADC") Reported-by: Konstantin Klubnichkin Signed-off-by: Billy Tsai Reviewed-by: Joel Stanley Link: https://lore.kernel.org/r/20220221012705.22008-1-billy_tsai@aspeedtech.com Cc: Signed-off-by: Jonathan Cameron --- drivers/iio/adc/aspeed_adc.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/iio/adc/aspeed_adc.c b/drivers/iio/adc/aspeed_adc.c index e939b84cbb56..0793d2474cdc 100644 --- a/drivers/iio/adc/aspeed_adc.c +++ b/drivers/iio/adc/aspeed_adc.c @@ -539,7 +539,9 @@ static int aspeed_adc_probe(struct platform_device *pdev) data->clk_scaler = devm_clk_hw_register_divider( &pdev->dev, clk_name, clk_parent_name, scaler_flags, data->base + ASPEED_REG_CLOCK_CONTROL, 0, - data->model_data->scaler_bit_width, 0, &data->clk_lock); + data->model_data->scaler_bit_width, + data->model_data->need_prescaler ? CLK_DIVIDER_ONE_BASED : 0, + &data->clk_lock); if (IS_ERR(data->clk_scaler)) return PTR_ERR(data->clk_scaler); -- cgit v1.2.3 From c87b7b12f48db86ac9909894f4dc0107d7df6375 Mon Sep 17 00:00:00 2001 From: Haibo Chen Date: Tue, 22 Feb 2022 10:42:21 +0800 Subject: iio: accel: mma8452: use the correct logic to get mma8452_data The original logic to get mma8452_data is wrong, the *dev point to the device belong to iio_dev. we can't use this dev to find the correct i2c_client. The original logic happen to work because it finally use dev->driver_data to get iio_dev. Here use the API to_i2c_client() is wrong and make reader confuse. To correct the logic, it should be like this struct mma8452_data *data = iio_priv(dev_get_drvdata(dev)); But after commit 8b7651f25962 ("iio: iio_device_alloc(): Remove unnecessary self drvdata"), the upper logic also can't work. When try to show the avialable scale in userspace, will meet kernel dump, kernel handle NULL pointer dereference. So use dev_to_iio_dev() to correct the logic. Dual fixes tags as the second reflects when the bug was exposed, whilst the first reflects when the original bug was introduced. Fixes: c3cdd6e48e35 ("iio: mma8452: refactor for seperating chip specific data") Fixes: 8b7651f25962 ("iio: iio_device_alloc(): Remove unnecessary self drvdata") Signed-off-by: Haibo Chen Reviewed-by: Martin Kepplinger Cc: Link: https://lore.kernel.org/r/1645497741-5402-1-git-send-email-haibo.chen@nxp.com Signed-off-by: Jonathan Cameron --- drivers/iio/accel/mma8452.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/iio/accel/mma8452.c b/drivers/iio/accel/mma8452.c index 6ea10700d048..9c02c681c84c 100644 --- a/drivers/iio/accel/mma8452.c +++ b/drivers/iio/accel/mma8452.c @@ -381,8 +381,8 @@ static ssize_t mma8452_show_scale_avail(struct device *dev, struct device_attribute *attr, char *buf) { - struct mma8452_data *data = iio_priv(i2c_get_clientdata( - to_i2c_client(dev))); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct mma8452_data *data = iio_priv(indio_dev); return mma8452_show_int_plus_micros(buf, data->chip_info->mma_scales, ARRAY_SIZE(data->chip_info->mma_scales)); -- cgit v1.2.3 From 5165102efa41c2aedc77441612f4506a8a8671db Mon Sep 17 00:00:00 2001 From: Robert Hancock Date: Thu, 27 Jan 2022 11:34:47 -0600 Subject: dt-bindings: iio: adc: zynqmp_ams: Add clock entry The AMS driver DT binding was missing the clock entry, which is actually mandatory according to the driver implementation. Add this in. Fixes: 39dd2d1e251d ("dt-bindings: iio: adc: Add Xilinx AMS binding documentation") Signed-off-by: Robert Hancock Reviewed-by: Rob Herring Acked-by: Michal Simek Link: https://lore.kernel.org/r/20220127173450.3684318-2-robert.hancock@calian.com Cc: Signed-off-by: Jonathan Cameron --- Documentation/devicetree/bindings/iio/adc/xlnx,zynqmp-ams.yaml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Documentation/devicetree/bindings/iio/adc/xlnx,zynqmp-ams.yaml b/Documentation/devicetree/bindings/iio/adc/xlnx,zynqmp-ams.yaml index 87992db389b2..3698b4b0900f 100644 --- a/Documentation/devicetree/bindings/iio/adc/xlnx,zynqmp-ams.yaml +++ b/Documentation/devicetree/bindings/iio/adc/xlnx,zynqmp-ams.yaml @@ -92,6 +92,10 @@ properties: description: AMS Controller register space maxItems: 1 + clocks: + items: + - description: AMS reference clock + ranges: description: Maps the child address space for PS and/or PL. @@ -181,12 +185,15 @@ properties: required: - compatible - reg + - clocks - ranges additionalProperties: false examples: - | + #include + bus { #address-cells = <2>; #size-cells = <2>; @@ -196,6 +203,7 @@ examples: interrupt-parent = <&gic>; interrupts = <0 56 4>; reg = <0x0 0xffa50000 0x0 0x800>; + clocks = <&zynqmp_clk AMS_REF>; #address-cells = <1>; #size-cells = <1>; #io-channel-cells = <1>; -- cgit v1.2.3 From 1f21a41578062d439cc485bce2d8b664f9a6170e Mon Sep 17 00:00:00 2001 From: Robert Hancock Date: Thu, 27 Jan 2022 11:34:48 -0600 Subject: iio: adc: xilinx-ams: Fixed missing PS channels The code forgot to increment num_channels for the PS channel inputs, resulting in them not being enabled as they should. Fixes: d5c70627a794 ("iio: adc: Add Xilinx AMS driver") Signed-off-by: Robert Hancock Reviewed-by: Michael Tretter Acked-by: Michal Simek Link: https://lore.kernel.org/r/20220127173450.3684318-3-robert.hancock@calian.com Cc: Signed-off-by: Jonathan Cameron --- drivers/iio/adc/xilinx-ams.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/iio/adc/xilinx-ams.c b/drivers/iio/adc/xilinx-ams.c index 6ffddf4038b8..6746bc966bfd 100644 --- a/drivers/iio/adc/xilinx-ams.c +++ b/drivers/iio/adc/xilinx-ams.c @@ -1225,6 +1225,7 @@ static int ams_init_module(struct iio_dev *indio_dev, /* add PS channels to iio device channels */ memcpy(channels, ams_ps_channels, sizeof(ams_ps_channels)); + num_channels = ARRAY_SIZE(ams_ps_channels); } else if (fwnode_property_match_string(fwnode, "compatible", "xlnx,zynqmp-ams-pl") == 0) { ams->pl_base = fwnode_iomap(fwnode, 0); -- cgit v1.2.3 From d5d786fb531697be74c567b3844c6897ddf1ffdd Mon Sep 17 00:00:00 2001 From: Robert Hancock Date: Thu, 27 Jan 2022 11:34:49 -0600 Subject: iio: adc: xilinx-ams: Fixed wrong sequencer register settings Register settings used for the sequencer configuration register were incorrect, causing some inputs to not be read properly. Fixes: d5c70627a794 ("iio: adc: Add Xilinx AMS driver") Signed-off-by: Robert Hancock Reviewed-by: Michael Tretter Acked-by: Michal Simek Link: https://lore.kernel.org/r/20220127173450.3684318-4-robert.hancock@calian.com Cc: Signed-off-by: Jonathan Cameron --- drivers/iio/adc/xilinx-ams.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/iio/adc/xilinx-ams.c b/drivers/iio/adc/xilinx-ams.c index 6746bc966bfd..0c491667c464 100644 --- a/drivers/iio/adc/xilinx-ams.c +++ b/drivers/iio/adc/xilinx-ams.c @@ -92,8 +92,8 @@ #define AMS_CONF1_SEQ_MASK GENMASK(15, 12) #define AMS_CONF1_SEQ_DEFAULT FIELD_PREP(AMS_CONF1_SEQ_MASK, 0) -#define AMS_CONF1_SEQ_CONTINUOUS FIELD_PREP(AMS_CONF1_SEQ_MASK, 1) -#define AMS_CONF1_SEQ_SINGLE_CHANNEL FIELD_PREP(AMS_CONF1_SEQ_MASK, 2) +#define AMS_CONF1_SEQ_CONTINUOUS FIELD_PREP(AMS_CONF1_SEQ_MASK, 2) +#define AMS_CONF1_SEQ_SINGLE_CHANNEL FIELD_PREP(AMS_CONF1_SEQ_MASK, 3) #define AMS_REG_SEQ0_MASK GENMASK(15, 0) #define AMS_REG_SEQ2_MASK GENMASK(21, 16) -- cgit v1.2.3 From 0bf126163c3e7e6d722622073046aed567a5551e Mon Sep 17 00:00:00 2001 From: Robert Hancock Date: Thu, 27 Jan 2022 11:34:50 -0600 Subject: iio: adc: xilinx-ams: Fix single channel switching sequence Some of the AMS channels need to be read by switching into single-channel mode from the normal polling sequence. There was a logic issue in this switching code that could cause the first read of these channels to read back as zero. It appears that the sequencer should be set back to default mode before changing the channel selection, and the channel should be set before switching the sequencer back into single-channel mode. Also, write 1 to the EOC bit in the status register to clear it before waiting for it to become set, so that we actually wait for a new conversion to complete, and don't proceed based on a previous conversion completing. Fixes: d5c70627a794 ("iio: adc: Add Xilinx AMS driver") Signed-off-by: Robert Hancock Acked-by: Michal Simek Link: https://lore.kernel.org/r/20220127173450.3684318-5-robert.hancock@calian.com Cc: Signed-off-by: Jonathan Cameron --- drivers/iio/adc/xilinx-ams.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/iio/adc/xilinx-ams.c b/drivers/iio/adc/xilinx-ams.c index 0c491667c464..a55396c1f8b2 100644 --- a/drivers/iio/adc/xilinx-ams.c +++ b/drivers/iio/adc/xilinx-ams.c @@ -531,14 +531,18 @@ static int ams_enable_single_channel(struct ams *ams, unsigned int offset) return -EINVAL; } - /* set single channel, sequencer off mode */ + /* put sysmon in a soft reset to change the sequence */ ams_ps_update_reg(ams, AMS_REG_CONFIG1, AMS_CONF1_SEQ_MASK, - AMS_CONF1_SEQ_SINGLE_CHANNEL); + AMS_CONF1_SEQ_DEFAULT); /* write the channel number */ ams_ps_update_reg(ams, AMS_REG_CONFIG0, AMS_CONF0_CHANNEL_NUM_MASK, channel_num); + /* set single channel, sequencer off mode */ + ams_ps_update_reg(ams, AMS_REG_CONFIG1, AMS_CONF1_SEQ_MASK, + AMS_CONF1_SEQ_SINGLE_CHANNEL); + return 0; } @@ -552,6 +556,8 @@ static int ams_read_vcc_reg(struct ams *ams, unsigned int offset, u32 *data) if (ret) return ret; + /* clear end-of-conversion flag, wait for next conversion to complete */ + writel(expect, ams->base + AMS_ISR_1); ret = readl_poll_timeout(ams->base + AMS_ISR_1, reg, (reg & expect), AMS_INIT_POLL_TIME_US, AMS_INIT_TIMEOUT_US); if (ret) -- cgit v1.2.3