From: Andy Shevchenko <andriy.shevchenko@intel.com>
To: Ariana Lazar <ariana.lazar@microchip.com>
Cc: "Jonathan Cameron" <jic23@kernel.org>,
"David Lechner" <dlechner@baylibre.com>,
"Nuno Sá" <nuno.sa@analog.com>,
"Andy Shevchenko" <andy@kernel.org>,
"Rob Herring" <robh@kernel.org>,
"Krzysztof Kozlowski" <krzk+dt@kernel.org>,
"Conor Dooley" <conor+dt@kernel.org>,
linux-iio@vger.kernel.org, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org
Subject: Re: [PATCH 2/2] iio: dac: add support for Microchip MCP48FEB02
Date: Thu, 12 Feb 2026 16:42:45 +0200 [thread overview]
Message-ID: <aY3m5V05FOH5sut6@smile.fi.intel.com> (raw)
In-Reply-To: <20260212-mcp48feb02-v1-2-ce5843db65db@microchip.com>
On Thu, Feb 12, 2026 at 02:48:35PM +0200, Ariana Lazar wrote:
> This is the iio driver for Microchip MCP48FxBy1/2/4/8 series of buffered
> voltage output Digital-to-Analog Converters with nonvolatile or volatile
> memory and an SPI Interface.
>
> The families support up to 8 output channels.
>
> The devices can be 8-bit, 10-bit and 12-bit.
...
> +#include <linux/array_size.h>
> +#include <linux/bits.h>
> +#include <linux/bitfield.h>
> +#include <linux/cleanup.h>
> +#include <linux/delay.h>
> +#include <linux/err.h>
> +#include <linux/iio/iio.h>
> +#include <linux/iio/sysfs.h>
I would split this group...
> +#include <linux/kstrtox.h>
> +#include <linux/module.h>
> +#include <linux/mod_devicetable.h>
> +#include <linux/mutex.h>
> +#include <linux/property.h>
> +#include <linux/spi/spi.h>
> +#include <linux/time64.h>
> +#include <linux/types.h>
> +#include <linux/regmap.h>
> +#include <linux/regulator/consumer.h>
> +#include <linux/units.h>
> +
...to be here as other IIO drivers do.
...
> +/* Gain Control and I2C Slave Address Reguster fields */
> +#define DAC_GAIN_MASK(ch) (BIT(0) << (8 + (ch)))
Just BIT(8 + (ch)) should suffice.
> +#define DAC_GAIN_VAL(ch, val) ((val) << (8 + (ch)))
For the sake of consistency this may be also rewritten to
#define DAC_GAIN_VAL(ch, val) ((val) * BIT(8 + (ch)))
...
> +/**
> + * struct mcp48feb02_channel_data - channel configuration
> + * @ref_mode: chosen voltage for reference
> + * @use_2x_gain: output driver gain control
> + * @powerdown: is false if the channel is in normal operation mode
> + * @powerdown_mode: selected power-down mode
> + * @dac_data: dac value
DAC
> + */
> +struct mcp48feb02_channel_data {
> + u8 ref_mode;
> + bool use_2x_gain;
> + bool powerdown;
> + u8 powerdown_mode;
> + u16 dac_data;
Wondering if the following arrangement is slightly better:
u16 dac_data;
u8 ref_mode;
u8 powerdown_mode;
bool powerdown;
bool use_2x_gain;
> +};
...
> +/**
> + * struct mcp48feb02_data - chip configuration
> + * @chdata: options configured for each channel on the device
> + * @lock: prevents concurrent reads/writes to driver's state members
> + * @chip_features: pointer to features struct
> + * @scale_1: scales set on channels that are based on Vref1
> + * @scale: scales set on channels that are based on Vref/Vref0
> + * @active_channels_mask: enabled channels
> + * @regmap: regmap for directly accessing device register
> + * @labels: table with channels labels
> + * @phys_channels: physical channels on the device
> + * @vref1_buffered: Vref1 buffer is enabled
> + * @vref_buffered: Vref/Vref0 buffer is enabled
> + * @use_vref1: vref1-supply is defined
> + * @use_vref: vref-supply is defined
> + */
> +struct mcp48feb02_data {
> + struct mcp48feb02_channel_data chdata[MCP48FEB02_MAX_CH];
> + struct mutex lock; /* prevents concurrent reads/writes to driver's state members */
> + const struct mcp48feb02_features *chip_features;
> + int scale_1[2 * MCP48FEB02_MAX_SCALES_CH];
> + int scale[2 * MCP48FEB02_MAX_SCALES_CH];
I would name it scale1 and scale0. This will increase readability to see that
the sizes are equal and that the first digit is the part of the name.
> + unsigned long active_channels_mask;
> + struct regmap *regmap;
> + const char *labels[MCP48FEB02_MAX_CH];
> + u16 phys_channels;
> + bool vref1_buffered;
> + bool vref_buffered;
> + bool use_vref1;
> + bool use_vref;
> +};
...
> +static int mcp48feb02_write_to_eeprom(struct mcp48feb02_data *data, unsigned int reg,
> + unsigned int val)
> +{
> + int eewa_val, ret;
Is it okay that the eewa_val is signed?
> + ret = regmap_read_poll_timeout(data->regmap, MCP48FEB02_GAIN_CTRL_STATUS_REG_ADDR,
> + eewa_val,
> + !(eewa_val & MCP48FEB02_GAIN_BIT_STATUS_EEWA_MASK),
> + USEC_PER_MSEC, USEC_PER_MSEC * 5);
I would rather put it as
1 * USEC_PER_MSEC, 5 * USEC_PER_MSEC);
This follows the natural (from physics) reading — 1ms, 5ms.
> + if (ret)
> + return ret;
> +
> + return regmap_write(data->regmap, reg, val);
> +}
...
> +static ssize_t store_eeprom_store(struct device *dev, struct device_attribute *attr,
> + const char *buf, size_t len)
> +{
> + struct mcp48feb02_data *data = iio_priv(dev_to_iio_dev(dev));
> + unsigned int i, val, val1, eewa_val;
> + bool state;
> + int ret;
> +
> + ret = kstrtobool(buf, &state);
> + if (ret)
> + return ret;
> +
> + if (!state)
> + return 0;
> +
> + /*
> + * Wait until the currently occurring EEPROM Write Cycle is completed.
> + * Only serial commands to the volatile memory are allowed.
> + */
> + guard(mutex)(&data->lock);
> +
> + /*
> + * Verify DAC Wiper and DAC Configuration are unlocked. If both are disabled,
> + * writing to EEPROM is available.
> + */
> + ret = regmap_read(data->regmap, MCP48FEB02_WIPERLOCK_STATUS_REG_ADDR, &val);
> + if (ret)
> + return ret;
> +
> + if (val) {
> + dev_err(dev, "DAC Wiper and DAC Configuration not are unlocked.\n");
"are not"
> + return -EINVAL;
> + }
> +
> + for_each_set_bit(i, &data->active_channels_mask, data->phys_channels) {
> + ret = mcp48feb02_write_to_eeprom(data, NV_REG_ADDR(i),
> + data->chdata[i].dac_data);
> + if (ret)
> + return ret;
> + }
> +
> + ret = regmap_read(data->regmap, MCP48FEB02_VREF_REG_ADDR, &val);
> + if (ret)
> + return ret;
> +
> + ret = mcp48feb02_write_to_eeprom(data, MCP48FEB02_NV_VREF_REG_ADDR, val);
> + if (ret)
> + return ret;
> +
> + ret = regmap_read(data->regmap, MCP48FEB02_POWER_DOWN_REG_ADDR, &val);
> + if (ret)
> + return ret;
> +
> + ret = mcp48feb02_write_to_eeprom(data, MCP48FEB02_NV_POWER_DOWN_REG_ADDR, val);
> + if (ret)
> + return ret;
> +
> + ret = regmap_read_poll_timeout(data->regmap, MCP48FEB02_GAIN_CTRL_STATUS_REG_ADDR, eewa_val,
> + !(eewa_val & MCP48FEB02_GAIN_BIT_STATUS_EEWA_MASK),
> + USEC_PER_MSEC, USEC_PER_MSEC * 5);
> + if (ret)
> + return ret;
> +
> + ret = regmap_read(data->regmap, MCP48FEB02_NV_GAIN_CTRL_I2C_SLAVE_REG_ADDR, &val);
> + if (ret)
> + return ret;
> +
> + ret = regmap_read(data->regmap, MCP48FEB02_GAIN_CTRL_STATUS_REG_ADDR, &val1);
> + if (ret)
> + return ret;
> +
> + ret = mcp48feb02_write_to_eeprom(data, MCP48FEB02_NV_GAIN_CTRL_I2C_SLAVE_REG_ADDR,
> + (val1 & MCP48FEB02_GAIN_BITS_MASK) |
> + (val & MCP48FEB02_NV_I2C_SLAVE_ADDR_MASK));
> + if (ret)
> + return ret;
> +
> + return len;
> +}
> +
Unneeded blank line.
> +static IIO_DEVICE_ATTR_WO(store_eeprom, 0);
...
> +static void mcp48feb02_init_scale(struct mcp48feb02_data *data, enum mcp48feb02_scale scale,
> + int vref_uV, int scale_avail[])
> +{
> + u32 value_micro, value_int;
> + u64 tmp;
> +
> + /* vref_uV should not be negative */
> + tmp = (u64)vref_uV * MILLI >> data->chip_features->resolution;
If vref_uV is guaranteed to be less than ~33V, this code can be transformed to
avoid 64-bit division. Hints: resolution is always great than 3; MILLI equals
to 2³*5³.
> + value_int = div_u64_rem(tmp, MICRO, &value_micro);
> + scale_avail[scale * 2] = value_int;
> + scale_avail[scale * 2 + 1] = value_micro;
> +}
Since it's kinda a common stuff, perhaps one wants to add a helper
to include/linux/math.h.
...
> +static int mcp48feb02_read_avail(struct iio_dev *indio_dev, struct iio_chan_spec const *ch,
> + const int **vals, int *type, int *length, long info)
> +{
> + struct mcp48feb02_data *data = iio_priv(indio_dev);
> +
> + switch (info) {
> + case IIO_CHAN_INFO_SCALE:
> + switch (ch->type) {
> + case IIO_VOLTAGE:
> + if (data->phys_channels >= 4 && (ch->address % 2))
> + *vals = data->scale_1;
> + else
> + *vals = data->scale;
Actually, if you put the scales as
int scales[2][2 * MCP48FEB02_MAX_SCALES_CH];
this will become as simple as
if (data->phys_channels >= 4)
*vals = data->scales[ch->address];
else
*vals = data->scales[0];
OTOH, I am not sure if it can be always as
*vals = data->scales[ch->address];
which would be the best approach.
> + *length = 2 * MCP48FEB02_MAX_SCALES_CH;
> + *type = IIO_VAL_INT_PLUS_MICRO;
> + return IIO_AVAIL_LIST;
> + default:
> + return -EINVAL;
> + }
> + default:
> + return -EINVAL;
> + }
> +}
...
> +static void mcp48feb02_get_scale(int ch, struct mcp48feb02_data *data, int *val, int *val2)
> +{
> + enum mcp48feb02_scale current_scale;
> +
> + if (data->chdata[ch].ref_mode == MCP48FEB02_VREF_VDD)
> + current_scale = MCP48FEB02_SCALE_VDD;
> + else if (data->chdata[ch].use_2x_gain)
> + current_scale = MCP48FEB02_SCALE_GAIN_X2;
> + else
> + current_scale = MCP48FEB02_SCALE_GAIN_X1;
> +
> + if (data->phys_channels >= 4 && (ch % 2)) {
> + *val = data->scale_1[current_scale * 2];
> + *val2 = data->scale_1[current_scale * 2 + 1];
> + } else {
> + *val = data->scale[current_scale * 2];
> + *val2 = data->scale[current_scale * 2 + 1];
> + }
Ditto. I.o.w. you can avoid (ch % 2) for good.
> +}
...
> +static int mcp48feb02_set_scale(struct mcp48feb02_data *data, int ch, int scale)
> +{
> + int tmp_val, ret;
Why is 'tmp_val' signed?
> + ret = mcp48feb02_ch_scale(data, ch, scale);
> + if (ret)
> + return ret;
> +
> + if (scale == MCP48FEB02_SCALE_GAIN_X2)
> + tmp_val = MCP48FEB02_GAIN_BIT_X2;
> + else
> + tmp_val = MCP48FEB02_GAIN_BIT_X1;
> +
> + ret = regmap_update_bits(data->regmap, MCP48FEB02_GAIN_CTRL_STATUS_REG_ADDR,
> + DAC_GAIN_MASK(ch), DAC_GAIN_VAL(ch, tmp_val));
> + if (ret)
> + return ret;
> +
> + data->chdata[ch].use_2x_gain = tmp_val;
> +
> + return 0;
> +}
...
> +static int mcp48feb02_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *ch,
> + int val, int val2, long mask)
> +{
> + struct mcp48feb02_data *data = iio_priv(indio_dev);
> + int *tmp_scale, ret;
> +
> + guard(mutex)(&data->lock);
> +
> + switch (mask) {
> + case IIO_CHAN_INFO_RAW:
> + ret = regmap_write(data->regmap, REG_ADDR(ch->address), val);
> + if (ret)
> + return ret;
> +
> + data->chdata[ch->address].dac_data = val;
> + return 0;
> + case IIO_CHAN_INFO_SCALE:
> + if (data->phys_channels >= 4 && (ch->address % 2))
> + tmp_scale = data->scale_1;
> + else
> + tmp_scale = data->scale;
Same, (ch->address % 2) can be avoided.
> + ret = mcp48feb02_check_scale(data, val, val2, tmp_scale);
> + if (ret < 0)
> + return ret;
> +
> + return mcp48feb02_set_scale(data, ch->address, ret);
> + default:
> + return -EINVAL;
> + }
> +}
...
> +static int mcp48feb02_parse_fw(struct iio_dev *indio_dev,
> + const struct mcp48feb02_features *chip_features)
> +{
> + struct iio_chan_spec chanspec = mcp48febxx_ch_template;
> + struct mcp48feb02_data *data = iio_priv(indio_dev);
> + struct device *dev = regmap_get_device(data->regmap);
> + struct iio_chan_spec *channels;
> + u32 num_channels;
> + u8 chan_idx = 0;
Assignments like this are harder to maintain and prone to subtle mistakes in
case the variable gets reused. Please, split it...
> + guard(mutex)(&data->lock);
> +
> + num_channels = device_get_child_node_count(dev);
> + if (num_channels > chip_features->phys_channels)
> + return dev_err_probe(dev, -EINVAL, "More channels than the chip supports\n");
> +
> + if (!num_channels)
While this is standard pattern, I find == 0 is more explicit when we compare
counters, but it's up to you and maintainers.
> + return dev_err_probe(dev, -EINVAL, "No channel specified in the devicetree.\n");
> +
> + channels = devm_kcalloc(dev, num_channels, sizeof(*channels), GFP_KERNEL);
> + if (!channels)
> + return -ENOMEM;
...to be here as
chan_idx = 0;
> + device_for_each_child_node_scoped(dev, child) {
> + u32 reg = 0;
Redundant assignment. "reg" is a mandatory property AFAICS from the below code.
> + int ret;
> +
> + ret = fwnode_property_read_u32(child, "reg", ®);
> + if (ret)
> + return dev_err_probe(dev, ret, "Invalid channel number\n");
> +
> + if (reg >= chip_features->phys_channels)
> + return dev_err_probe(dev, -EINVAL,
> + "The index of the channels does not match the chip\n");
> + set_bit(reg, &data->active_channels_mask);
Is atomic bit operation required here?
> + ret = fwnode_property_read_string(child, "label", &data->labels[reg]);
> + if (ret)
> + return dev_err_probe(dev, ret, "%pfw: invalid label\n",
> + fwnode_get_name(child));
Something is really wrong here. Please, fix accordingly.
> + chanspec.address = reg;
> + chanspec.channel = reg;
> + channels[chan_idx] = chanspec;
> + chan_idx++;
> + }
> +
> + indio_dev->num_channels = num_channels;
> + indio_dev->channels = channels;
> + indio_dev->modes = INDIO_DIRECT_MODE;
> + data->phys_channels = chip_features->phys_channels;
> +
> + data->vref_buffered = device_property_read_bool(dev, "microchip,vref-buffered");
> + if (chip_features->have_ext_vref1)
> + data->vref1_buffered = device_property_read_bool(dev, "microchip,vref1-buffered");
Alternatively can be
if (device_property_read_bool(dev, "microchip,vref1-buffered"))
data->vref1_buffered = chip_features->have_ext_vref1;
the difference is that vref1_buffered can be filled with "false", but I don't see
if it can be true before that. You may stick with your variant to avoid this side
effect.
> + return 0;
> +}
...
> +static int mcp48feb02_init_ctrl_regs(struct mcp48feb02_data *data)
> +{
> + unsigned int i, vref_ch, gain_ch, pd_ch;
> + int ret;
> +
> + ret = regmap_read(data->regmap, MCP48FEB02_VREF_REG_ADDR, &vref_ch);
> + if (ret)
> + return ret;
> +
> + ret = regmap_read(data->regmap, MCP48FEB02_GAIN_CTRL_STATUS_REG_ADDR, &gain_ch);
> + if (ret)
> + return ret;
> +
> + ret = regmap_read(data->regmap, MCP48FEB02_POWER_DOWN_REG_ADDR, &pd_ch);
> + if (ret)
> + return ret;
> +
> + gain_ch = gain_ch & MCP48FEB02_GAIN_BITS_MASK;
> + for_each_set_bit(i, &data->active_channels_mask, data->phys_channels) {
> + struct device *dev = regmap_get_device(data->regmap);
> + unsigned int pd_tmp;
> +
> + data->chdata[i].ref_mode = (vref_ch >> (2 * i)) & MCP48FEB02_DAC_CTRL_MASK;
> + data->chdata[i].use_2x_gain = (gain_ch >> i) & MCP48FEB02_GAIN_BIT_MASK;
> +
> + /*
> + * Inform the user that the current voltage reference read from the volatile
> + * register of the chip is different from the one specified in the device tree.
> + * Considering that the user cannot have an external voltage reference connected
> + * to the pin and select the internal Band Gap at the same time, in order to avoid
> + * miscofiguring the reference voltage, the volatile register will not be written.
> + * In order to overwrite the setting from volatile register with the one from the
> + * device tree, the user needs to write the chosen scale.
> + */
> + switch (data->chdata[i].ref_mode) {
> + case MCP48FEB02_INTERNAL_BAND_GAP:
> + if (data->phys_channels >= 4 && (i % 2) && data->use_vref1) {
> + dev_dbg(dev, "ch[%u]: was configured to use internal band gap", i);
> + dev_dbg(dev, "ch[%u]: reference voltage set to VREF1", i);
> + break;
> + }
> + if ((data->phys_channels < 4 || (data->phys_channels >= 4 && !(i % 2))) &&
> + data->use_vref) {
I don't see how these two conditionals can be run both.
> + dev_dbg(dev, "ch[%u]: was configured to use internal band gap", i);
> + dev_dbg(dev, "ch[%u]: reference voltage set to VREF", i);
> + break;
> + }
With that in mind, the above can be simplified a bit.
if (data->use_vref && ((data->phys_channels >= 4 && !(i % 2)) ||
(data->phys_channels < 4))) {
dev_dbg(dev, "ch[%u]: was configured to use internal band gap\n", i);
dev_dbg(dev, "ch[%u]: reference voltage set to Vref\n", i);
} else if (data->use_vref1 && data->phys_channels >= 4 && (i % 2)) {
dev_dbg(dev, "ch[%u]: was configured to use internal band gap\n", i);
dev_dbg(dev, "ch[%u]: reference voltage set to Vref1\n", i);
}
The conditionals were reshuffled to make it shorter and easier to compare
(yes, there is a pair of unneeded parentheses for the sake of good looking
code, a.k.a. readability).
Also note, the messages were missing trailing '\n'; I lowered REF --> ref
in them.
> + break;
> + case MCP48FEB02_EXTERNAL_VREF_UNBUFFERED:
> + case MCP48FEB02_EXTERNAL_VREF_BUFFERED:
> + if (data->phys_channels >= 4 && (i % 2) && !data->use_vref1) {
> + dev_dbg(dev, "ch[%u]: was configured to use VREF1", i);
> + dev_dbg(dev,
> + "ch[%u]: reference voltage set to internal band gap", i);
> + break;
> + }
> + if ((data->phys_channels < 4 || (data->phys_channels >= 4 && !(i % 2))) &&
> + !data->use_vref) {
> + dev_dbg(dev, "ch[%u]: was configured to use VREF", i);
> + dev_dbg(dev,
> + "ch[%u]: reference voltage set to internal band gap", i);
> + break;
> + }
> + break;
Ditto.
> + }
> +
> + pd_tmp = (pd_ch >> (2 * i)) & MCP48FEB02_DAC_CTRL_MASK;
> + data->chdata[i].powerdown_mode = pd_tmp ? (pd_tmp - 1) : pd_tmp;
> + data->chdata[i].powerdown = !!(data->chdata[i].powerdown_mode);
> + }
> +
> + return 0;
> +}
...
> +static int mcp48feb02_probe(struct spi_device *spi)
> +{
> + const struct mcp48feb02_features *chip_features;
> + struct device *dev = &spi->dev;
> + struct mcp48feb02_data *data;
> + struct iio_dev *indio_dev;
> + int vref1_uV = 0;
> + int vref_uV = 0;
Please, split the assignments (the rationale was given somewhere above).
> + int vdd_uV;
> + int ret;
> +
> + indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
> + if (!indio_dev)
> + return -ENOMEM;
> +
> + data = iio_priv(indio_dev);
> +
> + chip_features = spi_get_device_match_data(spi);
> + if (!chip_features)
> + return -EINVAL;
> +
> + data->chip_features = chip_features;
> +
> + if (chip_features->have_eeprom) {
> + data->regmap = devm_regmap_init_spi(spi, &mcp48feb02_regmap_config);
> + indio_dev->info = &mcp48feb02_info;
> + } else {
> + data->regmap = devm_regmap_init_spi(spi, &mcp48fvb02_regmap_config);
> + indio_dev->info = &mcp48fvb02_info;
> + }
> + if (IS_ERR(data->regmap))
> + return dev_err_probe(dev, PTR_ERR(data->regmap), "Error initializing spi regmap\n");
SPI
> + indio_dev->name = chip_features->name;
> +
> + ret = mcp48feb02_parse_fw(indio_dev, chip_features);
> + if (ret)
> + return dev_err_probe(dev, ret, "Error parsing firmware data\n");
> +
> + ret = devm_mutex_init(dev, &data->lock);
> + if (ret)
> + return ret;
> +
> + ret = devm_regulator_get_enable_read_voltage(dev, "vdd");
> + if (ret < 0)
> + return ret;
> +
> + vdd_uV = ret;
> +
> + ret = devm_regulator_get_enable_read_voltage(dev, "vref");
> + if (ret > 0) {
> + vref_uV = ret;
> + data->use_vref = true;
> + } else {
> + dev_dbg(dev, "using internal band gap as voltage reference.\n");
> + dev_dbg(dev, "External Vref is unavailable.\n");
> + }
> +
> + if (chip_features->have_ext_vref1) {
> + ret = devm_regulator_get_enable_read_voltage(dev, "vref1");
> + if (ret > 0) {
> + vref1_uV = ret;
> + data->use_vref1 = true;
> + } else {
> + dev_dbg(dev, "using internal band gap as voltage reference 1.\n");
> + dev_dbg(dev, "External Vref1 is unavailable.\n");
> + }
> + }
> +
> + ret = mcp48feb02_init_ctrl_regs(data);
> + if (ret)
> + return dev_err_probe(dev, ret, "Error initialising vref register\n");
> +
> + ret = mcp48feb02_init_ch_scales(data, vdd_uV, vref_uV, vref1_uV);
> + if (ret)
> + return ret;
> +
> + return devm_iio_device_register(dev, indio_dev);
> +}
--
With Best Regards,
Andy Shevchenko
next prev parent reply other threads:[~2026-02-12 14:42 UTC|newest]
Thread overview: 18+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-02-12 12:48 [PATCH 0/2] Add support for Microchip MCP48FxBy1/2/4/8 DAC with an SPI Interface Ariana Lazar
2026-02-12 12:48 ` [PATCH 1/2] dt-bindings: iio: dac: add support for Microchip MCP48FEB02 Ariana Lazar
2026-02-12 17:31 ` Rob Herring (Arm)
2026-02-12 18:00 ` Conor Dooley
2026-02-12 20:04 ` Andy Shevchenko
2026-02-16 13:31 ` Ariana.Lazar
2026-02-16 15:37 ` David Lechner
2026-02-16 17:34 ` Conor Dooley
2026-02-16 18:38 ` David Lechner
2026-02-12 12:48 ` [PATCH 2/2] " Ariana Lazar
2026-02-12 14:42 ` Andy Shevchenko [this message]
2026-02-16 14:29 ` Ariana.Lazar
2026-02-17 7:54 ` Andy Shevchenko
2026-02-17 11:38 ` Ariana.Lazar
2026-02-17 12:12 ` Andy Shevchenko
2026-02-15 17:58 ` Jonathan Cameron
2026-02-12 13:39 ` [PATCH 0/2] Add support for Microchip MCP48FxBy1/2/4/8 DAC with an SPI Interface Andy Shevchenko
2026-02-12 17:58 ` Conor Dooley
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=aY3m5V05FOH5sut6@smile.fi.intel.com \
--to=andriy.shevchenko@intel.com \
--cc=andy@kernel.org \
--cc=ariana.lazar@microchip.com \
--cc=conor+dt@kernel.org \
--cc=devicetree@vger.kernel.org \
--cc=dlechner@baylibre.com \
--cc=jic23@kernel.org \
--cc=krzk+dt@kernel.org \
--cc=linux-iio@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=nuno.sa@analog.com \
--cc=robh@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox