Merge tag 'char-misc-7.1-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc

Pull char/misc/iio fixes from Greg KH:
 "Here are some small char/misc/iio driver fixes for 7.1-rc6. Included
  in here are:

   - lots of small IIO driver fixes for reported problems.

   - Android binder bugfixes for reported issues.

   - small comedi test driver fixes

   - counter driver fix

   - parport driver fix (people still use this?)

   - rpi driver fix

   - uio driver fix

  All of these have been in linux-next for over a week with no reported
  problems"

* tag 'char-misc-7.1-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc: (41 commits)
  Revert "gpib: cb7210: Fix region leak when request_irq fails"
  misc: rp1: Send IACK on IRQ activate to fix kdump/kexec
  gpib: cb7210: Fix region leak when request_irq fails
  parport: Fix race between port and client registration
  uio: uio_pci_generic_sva: fix double free of devm_kzalloc() memory
  rust_binder: Avoid holding lock when dropping delivered_death
  rust_binder: avoid calling pending_oneway_finished() on TF_UPDATE_TXN
  comedi: comedi_test: fix check for valid scan_begin_src in waveform_ai_cmdtest()
  comedi: comedi_test: Fix limiting of convert_arg in waveform_ai_cmdtest()
  iio: adc: viperboard: Fix error handling in vprbrd_iio_read_raw
  iio: gyro: itg3200: fix i2c read into the wrong stack location
  iio: dac: ad5686: fix powerdown control on dual-channel devices
  iio: dac: ad5686: acquire lock when doing powerdown control
  iio: temperature: tsys01: fix broken PROM checksum validation
  iio: dac: ad3530r: Fix AD3531/AD3531R powerdown mode strings
  iio: buffer: hw-consumer: fix use-after-free in error path
  iio: dac: ad5686: fix input raw value check
  iio: dac: ad5686: fix ref bit initialization for single-channel parts
  iio: ssp_sensors: cancel delayed work_refresh on remove
  iio: adc: meson-saradc: fix calibration buffer leak on error
  ...
This commit is contained in:
Linus Torvalds
2026-05-30 08:30:12 -07:00
36 changed files with 235 additions and 109 deletions
+8
View File
@@ -157,6 +157,14 @@ impl Allocation {
self.get_or_init_info().target_node = Some(target_node);
}
pub(crate) fn take_oneway_node(&mut self) -> Option<DArc<Node>> {
if let Some(info) = self.allocation_info.as_mut() {
info.oneway_node.take()
} else {
None
}
}
/// Reserve enough space to push at least `num_fds` fds.
pub(crate) fn info_add_fd_reserve(&mut self, num_fds: usize) -> Result {
self.get_or_init_info()
+6 -1
View File
@@ -1402,7 +1402,12 @@ impl Process {
// Clear delivered_deaths list.
//
// Scope ensures that MutexGuard is dropped while executing the body.
while let Some(delivered_death) = { self.inner.lock().delivered_deaths.pop_front() } {
while let Some(delivered_death) = {
// Explicitly bind to avoid tail expression lifetime extension of the lockguard
// Can be removed when the kernel moves to edition 2024
let maybe_death = self.inner.lock().delivered_deaths.pop_front();
maybe_death
} {
drop(delivered_death);
}
+10 -1
View File
@@ -270,7 +270,8 @@ impl Transaction {
/// Not used for replies.
pub(crate) fn submit(self: DLArc<Self>, info: &mut TransactionInfo) -> BinderResult {
// Defined before `process_inner` so that the destructor runs after releasing the lock.
let mut _t_outdated;
let _t_outdated;
let _oneway_node;
let oneway = self.flags & TF_ONE_WAY != 0;
let process = self.to.clone();
@@ -287,6 +288,14 @@ impl Transaction {
if let Some(t_outdated) =
target_node.take_outdated_transaction(&self, &mut process_inner)
{
let mut alloc_guard = t_outdated.allocation.lock();
if let Some(alloc) = (*alloc_guard).as_mut() {
// Take the oneway node to prevent `Allocation::drop` from calling
// `pending_oneway_finished()`, which would be incorrect as this
// transaction is not being submitted.
_oneway_node = alloc.take_oneway_node();
}
drop(alloc_guard);
// Save the transaction to be dropped after locks are released.
_t_outdated = t_outdated;
}
+3 -2
View File
@@ -274,6 +274,7 @@ static int waveform_ai_cmdtest(struct comedi_device *dev,
/* Step 2a : make sure trigger sources are unique */
err |= comedi_check_trigger_is_unique(cmd->convert_src);
err |= comedi_check_trigger_is_unique(cmd->scan_begin_src);
err |= comedi_check_trigger_is_unique(cmd->stop_src);
/* Step 2b : and mutually compatible */
@@ -324,10 +325,10 @@ static int waveform_ai_cmdtest(struct comedi_device *dev,
arg = min(arg,
rounddown(UINT_MAX, (unsigned int)NSEC_PER_USEC));
arg = NSEC_PER_USEC * DIV_ROUND_CLOSEST(arg, NSEC_PER_USEC);
if (cmd->scan_begin_arg == TRIG_TIMER) {
if (cmd->scan_begin_src == TRIG_TIMER) {
/* limit convert_arg to keep scan_begin_arg in range */
limit = UINT_MAX / cmd->scan_end_arg;
limit = rounddown(limit, (unsigned int)NSEC_PER_SEC);
limit = rounddown(limit, (unsigned int)NSEC_PER_USEC);
arg = min(arg, limit);
}
err |= comedi_check_trigger_arg_is(&cmd->convert_arg, arg);
+2 -1
View File
@@ -124,7 +124,8 @@ struct counter_device *counter_alloc(size_t sizeof_priv)
err_dev_set_name:
counter_chrdev_remove(counter);
put_device(dev);
return NULL;
err_chrdev_add:
ida_free(&counter_ida, dev->id);
+8 -15
View File
@@ -876,14 +876,14 @@ static int ad4695_offload_buffer_postenable(struct iio_dev *indio_dev)
if (ret)
goto err_unoptimize_message;
ret = spi_offload_trigger_enable(st->offload, st->offload_trigger,
&config);
ret = ad4695_enter_advanced_sequencer_mode(st, num_slots);
if (ret)
goto err_disable_busy_output;
ret = ad4695_enter_advanced_sequencer_mode(st, num_slots);
ret = spi_offload_trigger_enable(st->offload, st->offload_trigger,
&config);
if (ret)
goto err_offload_trigger_disable;
goto err_exit_conversion_mode;
mutex_lock(&st->cnv_pwm_lock);
pwm_get_state(st->cnv_pwm, &state);
@@ -895,23 +895,16 @@ static int ad4695_offload_buffer_postenable(struct iio_dev *indio_dev)
ret = pwm_apply_might_sleep(st->cnv_pwm, &state);
mutex_unlock(&st->cnv_pwm_lock);
if (ret)
goto err_offload_exit_conversion_mode;
goto err_offload_trigger_disable;
return 0;
err_offload_exit_conversion_mode:
/*
* We have to unwind in a different order to avoid triggering offload.
* ad4695_exit_conversion_mode() triggers a conversion, so it has to be
* done after spi_offload_trigger_disable().
*/
spi_offload_trigger_disable(st->offload, st->offload_trigger);
ad4695_exit_conversion_mode(st);
goto err_disable_busy_output;
err_offload_trigger_disable:
spi_offload_trigger_disable(st->offload, st->offload_trigger);
err_exit_conversion_mode:
ad4695_exit_conversion_mode(st);
err_disable_busy_output:
regmap_clear_bits(st->regmap, AD4695_REG_GP_MODE,
AD4695_REG_GP_MODE_BUSY_GP_EN);
+3 -1
View File
@@ -817,9 +817,11 @@ static int meson_sar_adc_temp_sensor_init(struct iio_dev *indio_dev)
}
priv->tsc_regmap = syscon_regmap_lookup_by_phandle(dev->of_node, "amlogic,hhi-sysctrl");
if (IS_ERR(priv->tsc_regmap))
if (IS_ERR(priv->tsc_regmap)) {
kfree(buf);
return dev_err_probe(dev, PTR_ERR(priv->tsc_regmap),
"failed to get amlogic,hhi-sysctrl regmap\n");
}
trimming_bits = priv->param->temperature_trimming_bits;
trimming_mask = BIT(trimming_bits) - 1;
+1
View File
@@ -497,6 +497,7 @@ static int mt6358_read_imp(struct mt6359_auxadc *adc_dev,
return ret;
/* Read the params before stopping */
val_v = 0;
regmap_read(regmap, reg_adc0 + (cinfo->imp_adc_num << 1), &val_v);
mt6358_stop_imp_conv(adc_dev);
+8 -17
View File
@@ -231,7 +231,7 @@ static int npcm_adc_probe(struct platform_device *pdev)
if (IS_ERR(info->reset))
return PTR_ERR(info->reset);
info->adc_clk = devm_clk_get(&pdev->dev, NULL);
info->adc_clk = devm_clk_get_enabled(&pdev->dev, NULL);
if (IS_ERR(info->adc_clk)) {
dev_warn(&pdev->dev, "ADC clock failed: can't read clk\n");
return PTR_ERR(info->adc_clk);
@@ -244,17 +244,13 @@ static int npcm_adc_probe(struct platform_device *pdev)
info->adc_sample_hz = clk_get_rate(info->adc_clk) / ((div + 1) * 2);
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
ret = irq;
goto err_disable_clk;
}
if (irq < 0)
return irq;
ret = devm_request_irq(&pdev->dev, irq, npcm_adc_isr, 0,
"NPCM_ADC", indio_dev);
if (ret < 0) {
dev_err(dev, "failed requesting interrupt\n");
goto err_disable_clk;
}
if (ret < 0)
return ret;
reg_con = ioread32(info->regs + NPCM_ADCCON);
info->vref = devm_regulator_get_optional(&pdev->dev, "vref");
@@ -262,7 +258,7 @@ static int npcm_adc_probe(struct platform_device *pdev)
ret = regulator_enable(info->vref);
if (ret) {
dev_err(&pdev->dev, "Can't enable ADC reference voltage\n");
goto err_disable_clk;
return ret;
}
iowrite32(reg_con & ~NPCM_ADCCON_REFSEL,
@@ -272,10 +268,8 @@ static int npcm_adc_probe(struct platform_device *pdev)
* Any error which is not ENODEV indicates the regulator
* has been specified and so is a failure case.
*/
if (PTR_ERR(info->vref) != -ENODEV) {
ret = PTR_ERR(info->vref);
goto err_disable_clk;
}
if (PTR_ERR(info->vref) != -ENODEV)
return PTR_ERR(info->vref);
/* Use internal reference */
iowrite32(reg_con | NPCM_ADCCON_REFSEL,
@@ -314,8 +308,6 @@ err_iio_register:
iowrite32(reg_con & ~NPCM_ADCCON_ADC_EN, info->regs + NPCM_ADCCON);
if (!IS_ERR(info->vref))
regulator_disable(info->vref);
err_disable_clk:
clk_disable_unprepare(info->adc_clk);
return ret;
}
@@ -332,7 +324,6 @@ static void npcm_adc_remove(struct platform_device *pdev)
iowrite32(regtemp & ~NPCM_ADCCON_ADC_EN, info->regs + NPCM_ADCCON);
if (!IS_ERR(info->vref))
regulator_disable(info->vref);
clk_disable_unprepare(info->adc_clk);
}
static struct platform_driver npcm_adc_driver = {
+20 -4
View File
@@ -198,6 +198,15 @@ static void nxp_sar_adc_irq_cfg(struct nxp_sar_adc *info, bool enable)
writel(0, NXP_SAR_ADC_IMR(info->regs));
}
static void nxp_sar_adc_wait_for(struct nxp_sar_adc *info, unsigned int cycles)
{
u64 rate;
rate = clk_get_rate(info->clk);
if (rate)
ndelay(div64_u64(NSEC_PER_SEC, rate * cycles));
}
static bool nxp_sar_adc_set_enabled(struct nxp_sar_adc *info, bool enable)
{
u32 mcr;
@@ -221,7 +230,7 @@ static bool nxp_sar_adc_set_enabled(struct nxp_sar_adc *info, bool enable)
* configuration of NCMR and the setting of NSTART.
*/
if (enable)
ndelay(div64_u64(NSEC_PER_SEC, clk_get_rate(info->clk) * 3));
nxp_sar_adc_wait_for(info, 3);
return pwdn;
}
@@ -469,7 +478,7 @@ static void nxp_sar_adc_stop_conversion(struct nxp_sar_adc *info)
* only when the capture finishes. The delay will be very
* short, usec-ish, which is acceptable in the atomic context.
*/
ndelay(div64_u64(NSEC_PER_SEC, clk_get_rate(info->clk)) * 80);
nxp_sar_adc_wait_for(info, 80);
}
static int nxp_sar_adc_start_conversion(struct nxp_sar_adc *info, bool raw)
@@ -560,6 +569,9 @@ static int nxp_sar_adc_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec
switch (mask) {
case IIO_CHAN_INFO_SAMP_FREQ:
if (val <= 0)
return -EINVAL;
/*
* Configures the sample period duration in terms of the SAR
* controller clock. The minimum acceptable value is 8.
@@ -568,7 +580,11 @@ static int nxp_sar_adc_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec
* sampling timing which gives us the number of cycles expected.
* The value is 8-bit wide, consequently the max value is 0xFF.
*/
inpsamp = clk_get_rate(info->clk) / val - NXP_SAR_ADC_CONV_TIME;
inpsamp = clk_get_rate(info->clk) / val;
if (inpsamp < NXP_SAR_ADC_CONV_TIME)
return -EINVAL;
inpsamp -= NXP_SAR_ADC_CONV_TIME;
nxp_sar_adc_conversion_timing_set(info, inpsamp);
return 0;
@@ -660,7 +676,7 @@ static void nxp_sar_adc_dma_cb(void *data)
static int nxp_sar_adc_start_cyclic_dma(struct iio_dev *indio_dev)
{
struct nxp_sar_adc *info = iio_priv(indio_dev);
struct dma_slave_config config;
struct dma_slave_config config = { };
struct dma_async_tx_descriptor *desc;
int ret;
+1 -1
View File
@@ -482,7 +482,7 @@ static int adc5_gen3_get_fw_channel_data(struct adc5_chip *adc,
sid = FIELD_GET(ADC5_GEN3_VIRTUAL_SID_MASK, chan);
chan = FIELD_GET(ADC5_GEN3_CHANNEL_MASK, chan);
if (chan > ADC5_MAX_CHANNEL)
if (chan >= ADC5_MAX_CHANNEL)
return dev_err_probe(dev, -EINVAL,
"%s invalid channel number %d\n",
name, chan);
+3 -1
View File
@@ -70,8 +70,10 @@ static int vprbrd_iio_read_raw(struct iio_dev *iio_dev,
VPRBRD_USB_TYPE_OUT, 0x0000, 0x0000, admsg,
sizeof(struct vprbrd_adc_msg), VPRBRD_USB_TIMEOUT_MS);
if (ret != sizeof(struct vprbrd_adc_msg)) {
dev_err(&iio_dev->dev, "usb send error on adc read\n");
mutex_unlock(&vb->lock);
error = -EREMOTEIO;
dev_err(&iio_dev->dev, "usb send error on adc read\n");
goto error;
}
ret = usb_control_msg(vb->usb_dev,
+9 -2
View File
@@ -817,6 +817,7 @@ static int xadc_postdisable(struct iio_dev *indio_dev)
{
struct xadc *xadc = iio_priv(indio_dev);
unsigned long scan_mask;
int seq_mode;
int ret;
int i;
@@ -824,6 +825,12 @@ static int xadc_postdisable(struct iio_dev *indio_dev)
for (i = 0; i < indio_dev->num_channels; i++)
scan_mask |= BIT(indio_dev->channels[i].scan_index);
/*
* Use the correct sequencer mode for the idle state: simultaneous
* mode for dual external mux configurations, continuous otherwise.
*/
seq_mode = xadc_get_seq_mode(xadc, scan_mask);
/* Enable all channels and calibration */
ret = xadc_write_adc_reg(xadc, XADC_REG_SEQ(0), scan_mask & 0xffff);
if (ret)
@@ -834,11 +841,11 @@ static int xadc_postdisable(struct iio_dev *indio_dev)
return ret;
ret = xadc_update_adc_reg(xadc, XADC_REG_CONF1, XADC_CONF1_SEQ_MASK,
XADC_CONF1_SEQ_CONTINUOUS);
seq_mode);
if (ret)
return ret;
return xadc_power_adc_b(xadc, XADC_CONF1_SEQ_CONTINUOUS);
return xadc_power_adc_b(xadc, seq_mode);
}
static int xadc_preenable(struct iio_dev *indio_dev)
@@ -85,7 +85,7 @@ static struct hw_consumer_buffer *iio_hw_consumer_get_buffer(
*/
struct iio_hw_consumer *iio_hw_consumer_alloc(struct device *dev)
{
struct hw_consumer_buffer *buf;
struct hw_consumer_buffer *buf, *tmp;
struct iio_hw_consumer *hwc;
struct iio_channel *chan;
int ret;
@@ -116,7 +116,7 @@ struct iio_hw_consumer *iio_hw_consumer_alloc(struct device *dev)
return hwc;
err_put_buffers:
list_for_each_entry(buf, &hwc->buffers, head)
list_for_each_entry_safe(buf, tmp, &hwc->buffers, head)
iio_buffer_put(&buf->buffer);
iio_channel_release_all(hwc->channels);
err_free_hwc:
+17
View File
@@ -52,6 +52,8 @@ struct mhz19b_state {
struct completion buf_ready;
u8 buf_idx;
bool buf_overflow;
/*
* Serdev receive buffer.
* When data is received from the MH-Z19B,
@@ -106,6 +108,10 @@ static int mhz19b_serdev_cmd(struct iio_dev *indio_dev, int cmd, u16 arg)
cmd_buf[8] = mhz19b_get_checksum(cmd_buf);
/* Write buf to uart ctrl synchronously */
st->buf_idx = 0;
st->buf_overflow = false;
reinit_completion(&st->buf_ready);
ret = serdev_device_write(serdev, cmd_buf, MHZ19B_CMD_SIZE, 0);
if (ret < 0)
return ret;
@@ -121,6 +127,9 @@ static int mhz19b_serdev_cmd(struct iio_dev *indio_dev, int cmd, u16 arg)
if (!ret)
return -ETIMEDOUT;
if (st->buf_overflow)
return -EMSGSIZE;
if (st->buf[8] != mhz19b_get_checksum(st->buf)) {
dev_err(dev, "checksum err");
return -EINVAL;
@@ -240,6 +249,14 @@ static size_t mhz19b_receive_buf(struct serdev_device *serdev,
{
struct iio_dev *indio_dev = dev_get_drvdata(&serdev->dev);
struct mhz19b_state *st = iio_priv(indio_dev);
size_t remaining = MHZ19B_CMD_SIZE - st->buf_idx;
if (len > remaining) {
st->buf_idx = 0;
st->buf_overflow = true;
complete(&st->buf_ready);
return len;
}
memcpy(st->buf + st->buf_idx, data, len);
st->buf_idx += len;
+1 -1
View File
@@ -256,7 +256,7 @@ static int scd30_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec const
guard(mutex)(&state->lock);
switch (mask) {
case IIO_CHAN_INFO_SAMP_FREQ:
if (val)
if (val || !val2)
return -EINVAL;
val = 1000000000 / val2;
+1
View File
@@ -590,6 +590,7 @@ static void ssp_remove(struct spi_device *spi)
ssp_clean_pending_list(data);
free_irq(data->spi->irq, data);
cancel_delayed_work_sync(&data->work_refresh);
timer_delete_sync(&data->wdt_timer);
cancel_work_sync(&data->work_wdt);
+40 -14
View File
@@ -105,6 +105,12 @@ static const char * const ad3530r_powerdown_modes[] = {
"32kohm_to_gnd",
};
static const char * const ad3531r_powerdown_modes[] = {
"500ohm_to_gnd",
"3.85kohm_to_gnd",
"16kohm_to_gnd",
};
static int ad3530r_get_powerdown_mode(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan)
{
@@ -133,6 +139,13 @@ static const struct iio_enum ad3530r_powerdown_mode_enum = {
.set = ad3530r_set_powerdown_mode,
};
static const struct iio_enum ad3531r_powerdown_mode_enum = {
.items = ad3531r_powerdown_modes,
.num_items = ARRAY_SIZE(ad3531r_powerdown_modes),
.get = ad3530r_get_powerdown_mode,
.set = ad3530r_set_powerdown_mode,
};
static ssize_t ad3530r_get_dac_powerdown(struct iio_dev *indio_dev,
uintptr_t private,
const struct iio_chan_spec *chan,
@@ -276,7 +289,20 @@ static const struct iio_chan_spec_ext_info ad3530r_ext_info[] = {
{ }
};
#define AD3530R_CHAN(_chan) \
static const struct iio_chan_spec_ext_info ad3531r_ext_info[] = {
{
.name = "powerdown",
.shared = IIO_SEPARATE,
.read = ad3530r_get_dac_powerdown,
.write = ad3530r_set_dac_powerdown,
},
IIO_ENUM("powerdown_mode", IIO_SEPARATE, &ad3531r_powerdown_mode_enum),
IIO_ENUM_AVAILABLE("powerdown_mode", IIO_SHARED_BY_TYPE,
&ad3531r_powerdown_mode_enum),
{ }
};
#define AD3530R_CHAN(_chan, _ext_info) \
{ \
.type = IIO_VOLTAGE, \
.indexed = 1, \
@@ -284,25 +310,25 @@ static const struct iio_chan_spec_ext_info ad3530r_ext_info[] = {
.output = 1, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
BIT(IIO_CHAN_INFO_SCALE), \
.ext_info = ad3530r_ext_info, \
.ext_info = _ext_info, \
}
static const struct iio_chan_spec ad3530r_channels[] = {
AD3530R_CHAN(0),
AD3530R_CHAN(1),
AD3530R_CHAN(2),
AD3530R_CHAN(3),
AD3530R_CHAN(4),
AD3530R_CHAN(5),
AD3530R_CHAN(6),
AD3530R_CHAN(7),
AD3530R_CHAN(0, ad3530r_ext_info),
AD3530R_CHAN(1, ad3530r_ext_info),
AD3530R_CHAN(2, ad3530r_ext_info),
AD3530R_CHAN(3, ad3530r_ext_info),
AD3530R_CHAN(4, ad3530r_ext_info),
AD3530R_CHAN(5, ad3530r_ext_info),
AD3530R_CHAN(6, ad3530r_ext_info),
AD3530R_CHAN(7, ad3530r_ext_info),
};
static const struct iio_chan_spec ad3531r_channels[] = {
AD3530R_CHAN(0),
AD3530R_CHAN(1),
AD3530R_CHAN(2),
AD3530R_CHAN(3),
AD3530R_CHAN(0, ad3531r_ext_info),
AD3530R_CHAN(1, ad3531r_ext_info),
AD3530R_CHAN(2, ad3531r_ext_info),
AD3530R_CHAN(3, ad3531r_ext_info),
};
static const struct ad3530r_chip_info ad3530_chip = {
+42 -14
View File
@@ -25,22 +25,37 @@ static const char * const ad5686_powerdown_modes[] = {
"three_state"
};
static inline unsigned int ad5686_pd_mask_shift(const struct iio_chan_spec *chan)
{
if (chan->channel == chan->address)
return chan->channel * 2;
/* one-hot encoding is used in dual/quad channel devices */
return __ffs(chan->address) * 2;
}
static int ad5686_get_powerdown_mode(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan)
{
unsigned int shift = ad5686_pd_mask_shift(chan);
struct ad5686_state *st = iio_priv(indio_dev);
return ((st->pwr_down_mode >> (chan->channel * 2)) & 0x3) - 1;
guard(mutex)(&st->lock);
return ((st->pwr_down_mode >> shift) & 0x3U) - 1;
}
static int ad5686_set_powerdown_mode(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan,
unsigned int mode)
{
unsigned int shift = ad5686_pd_mask_shift(chan);
struct ad5686_state *st = iio_priv(indio_dev);
st->pwr_down_mode &= ~(0x3 << (chan->channel * 2));
st->pwr_down_mode |= ((mode + 1) << (chan->channel * 2));
guard(mutex)(&st->lock);
st->pwr_down_mode &= ~(0x3U << shift);
st->pwr_down_mode |= (mode + 1) << shift;
return 0;
}
@@ -55,10 +70,12 @@ static const struct iio_enum ad5686_powerdown_mode_enum = {
static ssize_t ad5686_read_dac_powerdown(struct iio_dev *indio_dev,
uintptr_t private, const struct iio_chan_spec *chan, char *buf)
{
unsigned int shift = ad5686_pd_mask_shift(chan);
struct ad5686_state *st = iio_priv(indio_dev);
return sysfs_emit(buf, "%d\n", !!(st->pwr_down_mask &
(0x3 << (chan->channel * 2))));
guard(mutex)(&st->lock);
return sysfs_emit(buf, "%d\n", !!(st->pwr_down_mask & (0x3U << shift)));
}
static ssize_t ad5686_write_dac_powerdown(struct iio_dev *indio_dev,
@@ -77,10 +94,12 @@ static ssize_t ad5686_write_dac_powerdown(struct iio_dev *indio_dev,
if (ret)
return ret;
guard(mutex)(&st->lock);
if (readin)
st->pwr_down_mask |= (0x3 << (chan->channel * 2));
st->pwr_down_mask |= 0x3U << ad5686_pd_mask_shift(chan);
else
st->pwr_down_mask &= ~(0x3 << (chan->channel * 2));
st->pwr_down_mask &= ~(0x3U << ad5686_pd_mask_shift(chan));
switch (st->chip_info->regmap_type) {
case AD5310_REGMAP:
@@ -154,7 +173,7 @@ static int ad5686_write_raw(struct iio_dev *indio_dev,
switch (mask) {
case IIO_CHAN_INFO_RAW:
if (val > (1 << chan->scan_type.realbits) || val < 0)
if (val >= (1 << chan->scan_type.realbits) || val < 0)
return -EINVAL;
mutex_lock(&st->lock);
@@ -460,7 +479,7 @@ int ad5686_probe(struct device *dev,
{
struct ad5686_state *st;
struct iio_dev *indio_dev;
unsigned int val, ref_bit_msk;
unsigned int val, ref_bit_msk, shift;
bool has_external_vref;
u8 cmd;
int ret, i;
@@ -484,9 +503,18 @@ int ad5686_probe(struct device *dev,
has_external_vref = ret != -ENODEV;
st->vref_mv = has_external_vref ? ret / 1000 : st->chip_info->int_vref_mv;
/* Initialize masks to all ones provided the max shift (last channel) */
shift = ad5686_pd_mask_shift(&st->chip_info->channels[st->chip_info->num_channels - 1]);
st->pwr_down_mask = GENMASK(shift + 1, 0);
st->pwr_down_mode = GENMASK(shift + 1, 0);
/* Set all the power down mode for all channels to 1K pulldown */
for (i = 0; i < st->chip_info->num_channels; i++)
st->pwr_down_mode |= (0x01 << (i * 2));
for (i = 0; i < st->chip_info->num_channels; i++) {
shift = ad5686_pd_mask_shift(&st->chip_info->channels[i]);
st->pwr_down_mask &= ~(0x3U << shift); /* powered up state */
st->pwr_down_mode &= ~(0x3U << shift);
st->pwr_down_mode |= 0x01U << shift;
}
indio_dev->name = name;
indio_dev->info = &ad5686_info;
@@ -509,7 +537,7 @@ int ad5686_probe(struct device *dev,
break;
case AD5686_REGMAP:
cmd = AD5686_CMD_INTERNAL_REFER_SETUP;
ref_bit_msk = 0;
ref_bit_msk = AD5686_REF_BIT_MSK;
break;
case AD5693_REGMAP:
cmd = AD5686_CMD_CONTROL_REG;
@@ -520,9 +548,9 @@ int ad5686_probe(struct device *dev,
return -EINVAL;
}
val = (has_external_vref | ref_bit_msk);
val = has_external_vref ? ref_bit_msk : 0;
ret = st->write(st, cmd, 0, !!val);
ret = st->write(st, cmd, 0, val);
if (ret)
return ret;
+1
View File
@@ -46,6 +46,7 @@
#define AD5310_REF_BIT_MSK BIT(8)
#define AD5683_REF_BIT_MSK BIT(12)
#define AD5686_REF_BIT_MSK BIT(0)
#define AD5693_REF_BIT_MSK BIT(12)
/**

Some files were not shown because too many files have changed in this diff Show More