* [PATCH v6 00/11] Refactor Microchip MCP47FEB02 I2C driver in separate modules to add support for MCP48FEB02 SPI driver
@ 2026-09-16 14:16 Ariana Lazar
2026-09-16 14:16 ` [PATCH v6 01/11] iio: dac: mcp47feb02: initialize dac_data field in channel data struct at probe Ariana Lazar
` (11 more replies)
0 siblings, 12 replies; 17+ messages in thread
From: Ariana Lazar @ 2026-09-16 14:16 UTC (permalink / raw)
To: Jonathan Cameron, David Lechner, Nuno Sá,
Andy Shevchenko, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: linux-kernel, linux-iio, devicetree, Ariana Lazar,
Jonathan Cameron, sashiko-bot, stable, Joshua Crofts
Refactor I2C driver implementation into separate modules in order to add
support for SPI MCP48FxBy1/2/4/8 DAC family on top of the I2C
implementation. The I2C and SPI devices have the same memory map and
supported functionalities.
Signed-off-by: Ariana Lazar <ariana.lazar@microchip.com>
---
Changes in v6:
- use field_get() in Gain, Vref and Power-Down registers channel formulas
- rebase from 7.2 to 7.3-rc1
- add fixes tags and Cc stable in the commit messages
- add numeric constants in front of time defines for better readability
- replaced dev_err() with dev_warn_probe() for missing label
- if match data is not found at probe, return -ENODATA and a suitable
error message
- Link to v5: https://lore.kernel.org/r/20260909-mcp47feb02_refactor-v5-0-8b67bcab93d1@microchip.com
Changes in v5:
- improve commit messages by justifying the changes made
- increase polling time for EEPROM writes
- delete unnecessary comments and extra blank line from header file
- Link to v4: https://lore.kernel.org/r/20260819-mcp47feb02_refactor-v4-0-beb2aa3bfd09@microchip.com
Changes in v4:
- remove unused headers
- add missing header types.h in protocol files
- create 6 precursor commits before the refactor patch for handling:
- comment typo
- renaming command mask define
- for an invalid label use a debug message instead of probe error
- correct return value in store_eeprom_store() for false state case
- correct channel gain formula
- read DAC value register to initialize channel data struct field at
probe
- Link to v3: https://lore.kernel.org/r/20260804-mcp47feb02_refactor-v3-0-97f8b81f3628@microchip.com
Changes in v3:
- renumbering the patch version to include the first patch submision
- fix review comments device tree binding:
- change 'additionalProperties' to unevaluatedProperties
- add else branch with spi-max-frequency in the condition which checks
if a device has SPI interface
- correct SPI address example
- add clock polarity and clock phase properties for SPI devices
- enumerate I2C devices in lexicographic order from the description section
- specify supported SPI modes using dependencies
- fix review comments driver:
- remove unneccesarry libraries and add the missing ones
- correct comment typo
- return -ENODEV using dev_err_probe() in protocol probe functions
- use named initializers
- move defines for registers and enums from the header to the core file
- add dev_set_drvdata() in probe()
- move mutex aquiring from mcp47feb02_write_to_eeprom() to
store_eeprom_store()
- write correct value into Vref register in resume()
- Link to v2: https://lore.kernel.org/r/20260723-mcp47feb02_refactor-v1-0-ee59e63672bc@microchip.com
v2:
- include in the same patch series the refactoring of the driver and the
support for SPI devices, but in different patches
- remove changes regarding review comments received not related to the
code refactoring
- first version of the combined refactoring I2C and adding support for SPI
driver
- Link to v1: https://lore.kernel.org/all/20260403-mcp47feb02-fix2-v1-1-da60c773550e@microchip.com
v1:
- first version which did not separate the refactoring and adding support for
SPI devices (into different patches from the same series)
---
Ariana Lazar (11):
iio: dac: mcp47feb02: initialize dac_data field in channel data struct at probe
iio: dac: mcp47feb02: Fix gain field initialization for active channels
iio: dac: mcp47feb02: use field_get() instead of custom dynamic macros
iio: dac: mcp47feb02: Return len when disabling EEPROM store
iio: dac: mcp47feb02: Increase EEPROM Programming Write Cycle Time
iio: dac: mcp47feb02: Avoid unjustified probe error on missing label
iio: dac: mcp47feb02: correct typo from a comment
iio: dac: mcp47feb02: rename channel mask and value macros
iio: dac: mcp47feb02: refactor MCP47FEB02 I2C driver into two modules
dt-bindings: iio: dac: add support for MCP48FEB02 SPI
iio: dac: add support for Microchip MCP48FEB02
.../bindings/iio/dac/microchip,mcp47feb02.yaml | 221 +++++++++---
MAINTAINERS | 2 +-
drivers/iio/dac/Kconfig | 32 +-
drivers/iio/dac/Makefile | 4 +-
.../iio/dac/{mcp47feb02.c => mcp47feb02-core.c} | 373 +++------------------
drivers/iio/dac/mcp47feb02-i2c.c | 145 ++++++++
drivers/iio/dac/mcp47feb02-spi.c | 145 ++++++++
drivers/iio/dac/mcp47feb02.h | 43 +++
8 files changed, 591 insertions(+), 374 deletions(-)
---
base-commit: cee9395acd8043be0644b25c34bfa86623f2b935
change-id: 20260625-mcp47feb02_refactor-fa8420ae3282
Best regards,
--
Ariana Lazar <ariana.lazar@microchip.com>
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH v6 01/11] iio: dac: mcp47feb02: initialize dac_data field in channel data struct at probe
2026-09-16 14:16 [PATCH v6 00/11] Refactor Microchip MCP47FEB02 I2C driver in separate modules to add support for MCP48FEB02 SPI driver Ariana Lazar
@ 2026-09-16 14:16 ` Ariana Lazar
2026-09-16 14:16 ` [PATCH v6 02/11] iio: dac: mcp47feb02: Fix gain field initialization for active channels Ariana Lazar
` (10 subsequent siblings)
11 siblings, 0 replies; 17+ messages in thread
From: Ariana Lazar @ 2026-09-16 14:16 UTC (permalink / raw)
To: Jonathan Cameron, David Lechner, Nuno Sá,
Andy Shevchenko, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: linux-kernel, linux-iio, devicetree, Ariana Lazar,
Jonathan Cameron, sashiko-bot, stable
Prevent operations which use cache from overwriting default hardware values
with zeros by reading active DAC registers during probe to correctly
initialize the channel struct DAC values.
Fixes: bf394cc80369 ("iio: dac: adding support for Microchip MCP47FEB02")
Reported-by: sashiko-bot@kernel.org
Link: https://lore.kernel.org/all/20260804134616.1D8A21F00A3E@smtp.kernel.org/
Cc: stable@vger.kernel.org
Signed-off-by: Ariana Lazar <ariana.lazar@microchip.com>
---
drivers/iio/dac/mcp47feb02.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/drivers/iio/dac/mcp47feb02.c b/drivers/iio/dac/mcp47feb02.c
index 8640b0ef4433da2b40d4b7e53fe6109737314951..6a3875e1d6a2c0cdd146410358130c44b1360f56 100644
--- a/drivers/iio/dac/mcp47feb02.c
+++ b/drivers/iio/dac/mcp47feb02.c
@@ -1019,7 +1019,12 @@ static int mcp47feb02_init_ctrl_regs(struct mcp47feb02_data *data)
gain_ch = gain_ch & MCP47FEB02_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;
+ unsigned int pd_tmp, dac_val;
+
+ ret = regmap_read(data->regmap, REG_ADDR(i), &dac_val);
+ if (ret)
+ return ret;
+ data->chdata[i].dac_data = dac_val;
data->chdata[i].ref_mode = (vref_ch >> (2 * i)) & MCP47FEB02_DAC_CTRL_MASK;
data->chdata[i].use_2x_gain = (gain_ch >> i) & MCP47FEB02_GAIN_BIT_MASK;
--
2.43.0
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH v6 02/11] iio: dac: mcp47feb02: Fix gain field initialization for active channels
2026-09-16 14:16 [PATCH v6 00/11] Refactor Microchip MCP47FEB02 I2C driver in separate modules to add support for MCP48FEB02 SPI driver Ariana Lazar
2026-09-16 14:16 ` [PATCH v6 01/11] iio: dac: mcp47feb02: initialize dac_data field in channel data struct at probe Ariana Lazar
@ 2026-09-16 14:16 ` Ariana Lazar
2026-09-16 14:16 ` [PATCH v6 03/11] iio: dac: mcp47feb02: use field_get() instead of custom dynamic macros Ariana Lazar
` (9 subsequent siblings)
11 siblings, 0 replies; 17+ messages in thread
From: Ariana Lazar @ 2026-09-16 14:16 UTC (permalink / raw)
To: Jonathan Cameron, David Lechner, Nuno Sá,
Andy Shevchenko, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: linux-kernel, linux-iio, devicetree, Ariana Lazar,
Jonathan Cameron, sashiko-bot, stable
As per MCP47FXBX48 Datasheet, in the format of the Gain Control and System
Status Register each DAC channel has one bit to control its gain,
starting at bit 8, while bits 0-7 contain status or unimplemented bits.
The previous formula didn't initialize correctly all channels, being
replaced by using field_get() with the already defined macro used in write
operations where needed in the rest of the driver implementation.
DAC_GAIN_MASK(i) extracts the gain control bit for each active channel
correctly in one step.
Fixes: bf394cc80369 ("iio: dac: adding support for Microchip MCP47FEB02")
Reported-by: sashiko-bot@kernel.org
Link: https://lore.kernel.org/all/20260804134616.1D8A21F00A3E@smtp.kernel.org/
Cc: stable@vger.kernel.org
Signed-off-by: Ariana Lazar <ariana.lazar@microchip.com>
---
drivers/iio/dac/mcp47feb02.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/drivers/iio/dac/mcp47feb02.c b/drivers/iio/dac/mcp47feb02.c
index 6a3875e1d6a2c0cdd146410358130c44b1360f56..fa4bd1df954844da35a8496758489189aeceb60d 100644
--- a/drivers/iio/dac/mcp47feb02.c
+++ b/drivers/iio/dac/mcp47feb02.c
@@ -1016,7 +1016,6 @@ static int mcp47feb02_init_ctrl_regs(struct mcp47feb02_data *data)
if (ret)
return ret;
- gain_ch = gain_ch & MCP47FEB02_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, dac_val;
@@ -1027,7 +1026,7 @@ static int mcp47feb02_init_ctrl_regs(struct mcp47feb02_data *data)
data->chdata[i].dac_data = dac_val;
data->chdata[i].ref_mode = (vref_ch >> (2 * i)) & MCP47FEB02_DAC_CTRL_MASK;
- data->chdata[i].use_2x_gain = (gain_ch >> i) & MCP47FEB02_GAIN_BIT_MASK;
+ data->chdata[i].use_2x_gain = field_get(DAC_GAIN_MASK(i), gain_ch);
/*
* Inform the user that the current voltage reference read from the volatile
--
2.43.0
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH v6 03/11] iio: dac: mcp47feb02: use field_get() instead of custom dynamic macros
2026-09-16 14:16 [PATCH v6 00/11] Refactor Microchip MCP47FEB02 I2C driver in separate modules to add support for MCP48FEB02 SPI driver Ariana Lazar
2026-09-16 14:16 ` [PATCH v6 01/11] iio: dac: mcp47feb02: initialize dac_data field in channel data struct at probe Ariana Lazar
2026-09-16 14:16 ` [PATCH v6 02/11] iio: dac: mcp47feb02: Fix gain field initialization for active channels Ariana Lazar
@ 2026-09-16 14:16 ` Ariana Lazar
2026-09-16 15:22 ` Andy Shevchenko
2026-09-16 14:16 ` [PATCH v6 04/11] iio: dac: mcp47feb02: Return len when disabling EEPROM store Ariana Lazar
` (8 subsequent siblings)
11 siblings, 1 reply; 17+ messages in thread
From: Ariana Lazar @ 2026-09-16 14:16 UTC (permalink / raw)
To: Jonathan Cameron, David Lechner, Nuno Sá,
Andy Shevchenko, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: linux-kernel, linux-iio, devicetree, Ariana Lazar, Jonathan Cameron
Replace manual bit operations which select channel corresponding bits
from a control register in mcp47feb02_init_ctrl_regs() with field_get()
macro used with masks already defined for regmap operations within the
driver.
Reported-by: Jonathan Cameron <jic23@kernel.org>
Link: https://lore.kernel.org/all/20260913224339.490d89ba@jic23-hlaptop/
Signed-off-by: Ariana Lazar <ariana.lazar@microchip.com>
---
drivers/iio/dac/mcp47feb02.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/iio/dac/mcp47feb02.c b/drivers/iio/dac/mcp47feb02.c
index fa4bd1df954844da35a8496758489189aeceb60d..81aa9063fcf730342d4af114da73ac2fc550243f 100644
--- a/drivers/iio/dac/mcp47feb02.c
+++ b/drivers/iio/dac/mcp47feb02.c
@@ -1025,7 +1025,7 @@ static int mcp47feb02_init_ctrl_regs(struct mcp47feb02_data *data)
return ret;
data->chdata[i].dac_data = dac_val;
- data->chdata[i].ref_mode = (vref_ch >> (2 * i)) & MCP47FEB02_DAC_CTRL_MASK;
+ data->chdata[i].ref_mode = field_get(DAC_CTRL_MASK(i), vref_ch);
data->chdata[i].use_2x_gain = field_get(DAC_GAIN_MASK(i), gain_ch);
/*
@@ -1069,7 +1069,7 @@ static int mcp47feb02_init_ctrl_regs(struct mcp47feb02_data *data)
break;
}
- pd_tmp = (pd_ch >> (2 * i)) & MCP47FEB02_DAC_CTRL_MASK;
+ pd_tmp = field_get(DAC_CTRL_MASK(i), pd_ch);
data->chdata[i].powerdown_mode = pd_tmp ? (pd_tmp - 1) : pd_tmp;
data->chdata[i].powerdown = !!(data->chdata[i].powerdown_mode);
}
--
2.43.0
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH v6 04/11] iio: dac: mcp47feb02: Return len when disabling EEPROM store
2026-09-16 14:16 [PATCH v6 00/11] Refactor Microchip MCP47FEB02 I2C driver in separate modules to add support for MCP48FEB02 SPI driver Ariana Lazar
` (2 preceding siblings ...)
2026-09-16 14:16 ` [PATCH v6 03/11] iio: dac: mcp47feb02: use field_get() instead of custom dynamic macros Ariana Lazar
@ 2026-09-16 14:16 ` Ariana Lazar
2026-09-16 14:16 ` [PATCH v6 05/11] iio: dac: mcp47feb02: Increase EEPROM Programming Write Cycle Time Ariana Lazar
` (7 subsequent siblings)
11 siblings, 0 replies; 17+ messages in thread
From: Ariana Lazar @ 2026-09-16 14:16 UTC (permalink / raw)
To: Jonathan Cameron, David Lechner, Nuno Sá,
Andy Shevchenko, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: linux-kernel, linux-iio, devicetree, Ariana Lazar,
Jonathan Cameron, sashiko-bot, stable
When state is false, return the number of bytes (len) the buffer has
instead of 0 to properly signal that the input buffer was fully consumed,
preventing unnecessary write retries.
Fixes: bf394cc80369 ("iio: dac: adding support for Microchip MCP47FEB02")
Reported-by: sashiko-bot@kernel.org
Link: https://lore.kernel.org/all/20260804134616.1D8A21F00A3E@smtp.kernel.org/
Cc: stable@vger.kernel.org
Signed-off-by: Ariana Lazar <ariana.lazar@microchip.com>
---
drivers/iio/dac/mcp47feb02.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/iio/dac/mcp47feb02.c b/drivers/iio/dac/mcp47feb02.c
index 81aa9063fcf730342d4af114da73ac2fc550243f..117fd41257d5cd430c00847ff64c22c6700dbb6a 100644
--- a/drivers/iio/dac/mcp47feb02.c
+++ b/drivers/iio/dac/mcp47feb02.c
@@ -468,7 +468,7 @@ static ssize_t store_eeprom_store(struct device *dev, struct device_attribute *a
return ret;
if (!state)
- return 0;
+ return len;
/*
* Verify DAC Wiper and DAC Configuration are unlocked. If both are disabled,
--
2.43.0
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH v6 05/11] iio: dac: mcp47feb02: Increase EEPROM Programming Write Cycle Time
2026-09-16 14:16 [PATCH v6 00/11] Refactor Microchip MCP47FEB02 I2C driver in separate modules to add support for MCP48FEB02 SPI driver Ariana Lazar
` (3 preceding siblings ...)
2026-09-16 14:16 ` [PATCH v6 04/11] iio: dac: mcp47feb02: Return len when disabling EEPROM store Ariana Lazar
@ 2026-09-16 14:16 ` Ariana Lazar
2026-09-16 14:16 ` [PATCH v6 06/11] iio: dac: mcp47feb02: Avoid unjustified probe error on missing label Ariana Lazar
` (6 subsequent siblings)
11 siblings, 0 replies; 17+ messages in thread
From: Ariana Lazar @ 2026-09-16 14:16 UTC (permalink / raw)
To: Jonathan Cameron, David Lechner, Nuno Sá,
Andy Shevchenko, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: linux-kernel, linux-iio, devicetree, Ariana Lazar,
Jonathan Cameron, sashiko-bot, stable
Increase the EEPROM write polling timeout to prevent -ETIMEDOUT errors and
incomplete nonvolatile write cycle, according to the time specified in the
datasheets (11-16 ms).
Fixes: bf394cc80369 ("iio: dac: adding support for Microchip MCP47FEB02")
Reported-by: sashiko-bot@kernel.org
Link: https://lore.kernel.org/all/20260819125300.6B9211F000E9@smtp.kernel.org/
Cc: stable@vger.kernel.org
Signed-off-by: Ariana Lazar <ariana.lazar@microchip.com>
---
drivers/iio/dac/mcp47feb02.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/iio/dac/mcp47feb02.c b/drivers/iio/dac/mcp47feb02.c
index 117fd41257d5cd430c00847ff64c22c6700dbb6a..a93e05cda5f36baf8f7573a1bd92bf6167227362 100644
--- a/drivers/iio/dac/mcp47feb02.c
+++ b/drivers/iio/dac/mcp47feb02.c
@@ -448,7 +448,7 @@ static int mcp47feb02_write_to_eeprom(struct mcp47feb02_data *data, unsigned int
ret = regmap_read_poll_timeout(data->regmap, MCP47FEB02_GAIN_CTRL_STATUS_REG_ADDR,
eewa_val,
!(eewa_val & MCP47FEB02_GAIN_BIT_STATUS_EEWA_MASK),
- USEC_PER_MSEC, USEC_PER_MSEC * 5);
+ 1 * USEC_PER_MSEC, 150 * USEC_PER_MSEC);
if (ret)
return ret;
@@ -508,7 +508,7 @@ static ssize_t store_eeprom_store(struct device *dev, struct device_attribute *a
ret = regmap_read_poll_timeout(data->regmap, MCP47FEB02_GAIN_CTRL_STATUS_REG_ADDR, eewa_val,
!(eewa_val & MCP47FEB02_GAIN_BIT_STATUS_EEWA_MASK),
- USEC_PER_MSEC, USEC_PER_MSEC * 5);
+ 1 * USEC_PER_MSEC, 150 * USEC_PER_MSEC);
if (ret)
return ret;
--
2.43.0
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH v6 06/11] iio: dac: mcp47feb02: Avoid unjustified probe error on missing label
2026-09-16 14:16 [PATCH v6 00/11] Refactor Microchip MCP47FEB02 I2C driver in separate modules to add support for MCP48FEB02 SPI driver Ariana Lazar
` (4 preceding siblings ...)
2026-09-16 14:16 ` [PATCH v6 05/11] iio: dac: mcp47feb02: Increase EEPROM Programming Write Cycle Time Ariana Lazar
@ 2026-09-16 14:16 ` Ariana Lazar
2026-09-16 14:16 ` [PATCH v6 07/11] iio: dac: mcp47feb02: correct typo from a comment Ariana Lazar
` (5 subsequent siblings)
11 siblings, 0 replies; 17+ messages in thread
From: Ariana Lazar @ 2026-09-16 14:16 UTC (permalink / raw)
To: Jonathan Cameron, David Lechner, Nuno Sá,
Andy Shevchenko, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: linux-kernel, linux-iio, devicetree, Ariana Lazar,
Jonathan Cameron, sashiko-bot, stable
Fix unjustified probe error on missing optional 'label' property by
replacing dev_err_probe() with dev_warn_probe(). Correct %pfw usage by
passing the child fwnode handle directly in the error message. Besides the
probe warning a read error is returned at the attempt of reading a null
label.
Fixes: bf394cc80369 ("iio: dac: adding support for Microchip MCP47FEB02")
Reported-by: sashiko-bot@kernel.org
Link: https://lore.kernel.org/all/20260804134616.1D8A21F00A3E@smtp.kernel.org/
Cc: stable@vger.kernel.org
Signed-off-by: Ariana Lazar <ariana.lazar@microchip.com>
---
drivers/iio/dac/mcp47feb02.c | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/drivers/iio/dac/mcp47feb02.c b/drivers/iio/dac/mcp47feb02.c
index a93e05cda5f36baf8f7573a1bd92bf6167227362..67bf8d9d9835095263b2ca6b710acca60612354a 100644
--- a/drivers/iio/dac/mcp47feb02.c
+++ b/drivers/iio/dac/mcp47feb02.c
@@ -922,7 +922,10 @@ static int mcp47feb02_read_label(struct iio_dev *indio_dev, struct iio_chan_spec
{
struct mcp47feb02_data *data = iio_priv(indio_dev);
- return sysfs_emit(label, "%s\n", data->labels[ch->address]);
+ if (data->labels[ch->address])
+ return sysfs_emit(label, "%s\n", data->labels[ch->address]);
+
+ return -ENOENT;
}
static const struct iio_info mcp47feb02_info = {
@@ -977,8 +980,7 @@ static int mcp47feb02_parse_fw(struct iio_dev *indio_dev,
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));
+ dev_warn_probe(dev, ret, "%pfw: invalid label\n", child);
chanspec.address = reg;
chanspec.channel = reg;
--
2.43.0
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH v6 07/11] iio: dac: mcp47feb02: correct typo from a comment
2026-09-16 14:16 [PATCH v6 00/11] Refactor Microchip MCP47FEB02 I2C driver in separate modules to add support for MCP48FEB02 SPI driver Ariana Lazar
` (5 preceding siblings ...)
2026-09-16 14:16 ` [PATCH v6 06/11] iio: dac: mcp47feb02: Avoid unjustified probe error on missing label Ariana Lazar
@ 2026-09-16 14:16 ` Ariana Lazar
2026-09-16 15:49 ` Joshua Crofts
2026-09-16 14:16 ` [PATCH v6 08/11] iio: dac: mcp47feb02: rename channel mask and value macros Ariana Lazar
` (4 subsequent siblings)
11 siblings, 1 reply; 17+ messages in thread
From: Ariana Lazar @ 2026-09-16 14:16 UTC (permalink / raw)
To: Jonathan Cameron, David Lechner, Nuno Sá,
Andy Shevchenko, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: linux-kernel, linux-iio, devicetree, Ariana Lazar,
Jonathan Cameron, Joshua Crofts
Typo corrected to 'Register' in the comment regarding defined masks for the
gain register.
Reported-by: Joshua Crofts <joshua.crofts1@gmail.com>
Link: https://lore.kernel.org/all/20260723231859.03f92ce6@systembl0wer/
Signed-off-by: Ariana Lazar <ariana.lazar@microchip.com>
---
drivers/iio/dac/mcp47feb02.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/iio/dac/mcp47feb02.c b/drivers/iio/dac/mcp47feb02.c
index 67bf8d9d9835095263b2ca6b710acca60612354a..8dac4e2fb74fe4563324343ce215af3389129130 100644
--- a/drivers/iio/dac/mcp47feb02.c
+++ b/drivers/iio/dac/mcp47feb02.c
@@ -52,7 +52,7 @@
#define DAC_CTRL_MASK(ch) (GENMASK(1, 0) << (2 * (ch)))
#define DAC_CTRL_VAL(ch, val) ((val) << (2 * (ch)))
-/* Gain Control and I2C Slave Address Reguster fields */
+/* Gain Control and I2C Slave Address Register fields */
#define DAC_GAIN_MASK(ch) (BIT(0) << (8 + (ch)))
#define DAC_GAIN_VAL(ch, val) ((val) << (8 + (ch)))
--
2.43.0
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH v6 08/11] iio: dac: mcp47feb02: rename channel mask and value macros
2026-09-16 14:16 [PATCH v6 00/11] Refactor Microchip MCP47FEB02 I2C driver in separate modules to add support for MCP48FEB02 SPI driver Ariana Lazar
` (6 preceding siblings ...)
2026-09-16 14:16 ` [PATCH v6 07/11] iio: dac: mcp47feb02: correct typo from a comment Ariana Lazar
@ 2026-09-16 14:16 ` Ariana Lazar
2026-09-17 0:53 ` Jonathan Cameron
2026-09-16 14:16 ` [PATCH v6 09/11] iio: dac: mcp47feb02: refactor MCP47FEB02 I2C driver into two modules Ariana Lazar
` (3 subsequent siblings)
11 siblings, 1 reply; 17+ messages in thread
From: Ariana Lazar @ 2026-09-16 14:16 UTC (permalink / raw)
To: Jonathan Cameron, David Lechner, Nuno Sá,
Andy Shevchenko, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: linux-kernel, linux-iio, devicetree, Ariana Lazar, Jonathan Cameron
Rename generic DAC_CTRL_MASK/VAL macros to MCP47FEB02_VREF_PD_MASK/VAL
in order to clearly indicate for which control registers these channel
masks are suitable.
Reported-by: Jonathan Cameron <jic23@kernel.org>
Link: https://lore.kernel.org/all/20260528125140.16a8f173@jic23-huawei/
Signed-off-by: Ariana Lazar <ariana.lazar@microchip.com>
---
drivers/iio/dac/mcp47feb02.c | 23 +++++++++++++----------
1 file changed, 13 insertions(+), 10 deletions(-)
diff --git a/drivers/iio/dac/mcp47feb02.c b/drivers/iio/dac/mcp47feb02.c
index 8dac4e2fb74fe4563324343ce215af3389129130..5c09ca25a75e0ecb2bfc5a2d5e62e5f7d3156810 100644
--- a/drivers/iio/dac/mcp47feb02.c
+++ b/drivers/iio/dac/mcp47feb02.c
@@ -49,8 +49,8 @@
#define MCP47FEB02_NV_I2C_SLAVE_ADDR_MASK GENMASK(7, 0)
/* Voltage reference, Power-Down control register and DAC Wiperlock status register fields */
-#define DAC_CTRL_MASK(ch) (GENMASK(1, 0) << (2 * (ch)))
-#define DAC_CTRL_VAL(ch, val) ((val) << (2 * (ch)))
+#define MCP47FEB02_VREF_PD_MASK(ch) (GENMASK(1, 0) << (2 * (ch)))
+#define MCP47FEB02_VREF_PD_VAL(ch, val) ((val) << (2 * (ch)))
/* Gain Control and I2C Slave Address Register fields */
#define DAC_GAIN_MASK(ch) (BIT(0) << (8 + (ch)))
@@ -555,7 +555,8 @@ static int mcp47feb02_suspend(struct device *dev)
data->chdata[ch].powerdown = true;
pd_mode = data->chdata[ch].powerdown_mode + 1;
ret = regmap_update_bits(data->regmap, MCP47FEB02_POWER_DOWN_REG_ADDR,
- DAC_CTRL_MASK(ch), DAC_CTRL_VAL(ch, pd_mode));
+ MCP47FEB02_VREF_PD_MASK(ch),
+ MCP47FEB02_VREF_PD_VAL(ch, pd_mode));
if (ret)
return ret;
@@ -587,7 +588,8 @@ static int mcp47feb02_resume(struct device *dev)
return ret;
ret = regmap_update_bits(data->regmap, MCP47FEB02_VREF_REG_ADDR,
- DAC_CTRL_MASK(ch), DAC_CTRL_VAL(ch, pd_mode));
+ MCP47FEB02_VREF_PD_MASK(ch),
+ MCP47FEB02_VREF_PD_VAL(ch, pd_mode));
if (ret)
return ret;
@@ -598,8 +600,8 @@ static int mcp47feb02_resume(struct device *dev)
return ret;
ret = regmap_update_bits(data->regmap, MCP47FEB02_POWER_DOWN_REG_ADDR,
- DAC_CTRL_MASK(ch),
- DAC_CTRL_VAL(ch, MCP47FEB02_NORMAL_OPERATION));
+ MCP47FEB02_VREF_PD_MASK(ch),
+ MCP47FEB02_VREF_PD_VAL(ch, MCP47FEB02_NORMAL_OPERATION));
if (ret)
return ret;
}
@@ -656,7 +658,8 @@ static ssize_t mcp47feb02_write_powerdown(struct iio_dev *indio_dev, uintptr_t p
*/
tmp_pd_mode = state ? (data->chdata[reg].powerdown_mode + 1) : MCP47FEB02_NORMAL_OPERATION;
ret = regmap_update_bits(data->regmap, MCP47FEB02_POWER_DOWN_REG_ADDR,
- DAC_CTRL_MASK(reg), DAC_CTRL_VAL(reg, tmp_pd_mode));
+ MCP47FEB02_VREF_PD_MASK(reg),
+ MCP47FEB02_VREF_PD_VAL(reg, tmp_pd_mode));
if (ret)
return ret;
@@ -822,7 +825,7 @@ static int mcp47feb02_ch_scale(struct mcp47feb02_data *data, int ch, int scale)
}
ret = regmap_update_bits(data->regmap, MCP47FEB02_VREF_REG_ADDR,
- DAC_CTRL_MASK(ch), DAC_CTRL_VAL(ch, tmp_val));
+ MCP47FEB02_VREF_PD_MASK(ch), MCP47FEB02_VREF_PD_VAL(ch, tmp_val));
if (ret)
return ret;
@@ -1027,7 +1030,7 @@ static int mcp47feb02_init_ctrl_regs(struct mcp47feb02_data *data)
return ret;
data->chdata[i].dac_data = dac_val;
- data->chdata[i].ref_mode = field_get(DAC_CTRL_MASK(i), vref_ch);
+ data->chdata[i].ref_mode = field_get(MCP47FEB02_VREF_PD_MASK(i), vref_ch);
data->chdata[i].use_2x_gain = field_get(DAC_GAIN_MASK(i), gain_ch);
/*
@@ -1071,7 +1074,7 @@ static int mcp47feb02_init_ctrl_regs(struct mcp47feb02_data *data)
break;
}
- pd_tmp = field_get(DAC_CTRL_MASK(i), pd_ch);
+ pd_tmp = field_get(MCP47FEB02_VREF_PD_MASK(i), pd_ch);
data->chdata[i].powerdown_mode = pd_tmp ? (pd_tmp - 1) : pd_tmp;
data->chdata[i].powerdown = !!(data->chdata[i].powerdown_mode);
}
--
2.43.0
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH v6 09/11] iio: dac: mcp47feb02: refactor MCP47FEB02 I2C driver into two modules
2026-09-16 14:16 [PATCH v6 00/11] Refactor Microchip MCP47FEB02 I2C driver in separate modules to add support for MCP48FEB02 SPI driver Ariana Lazar
` (7 preceding siblings ...)
2026-09-16 14:16 ` [PATCH v6 08/11] iio: dac: mcp47feb02: rename channel mask and value macros Ariana Lazar
@ 2026-09-16 14:16 ` Ariana Lazar
2026-09-16 14:16 ` [PATCH v6 10/11] dt-bindings: iio: dac: add support for MCP48FEB02 SPI Ariana Lazar
` (2 subsequent siblings)
11 siblings, 0 replies; 17+ messages in thread
From: Ariana Lazar @ 2026-09-16 14:16 UTC (permalink / raw)
To: Jonathan Cameron, David Lechner, Nuno Sá,
Andy Shevchenko, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: linux-kernel, linux-iio, devicetree, Ariana Lazar, Jonathan Cameron
Prepare the driver for the bus-specific code by refactoring into separate
files. The renamed file will contain the common DAC functionality shared by
the MCP47FxBy1/2/4/8 I2C and MCP48FxBy1/2/4/8 SPI drivers. The MCP47FEB02
driver was refactored into two modules: mcp47feb02-core.c and
mcp47feb02-i2c.c in order to prepare the support for SPI MCP48FxBy1/2/4/8
DAC family on top of the current implementation.
Signed-off-by: Ariana Lazar <ariana.lazar@microchip.com>
---
MAINTAINERS | 2 +-
drivers/iio/dac/Kconfig | 9 +-
drivers/iio/dac/Makefile | 3 +-
.../iio/dac/{mcp47feb02.c => mcp47feb02-core.c} | 326 ++-------------------
drivers/iio/dac/mcp47feb02-i2c.c | 145 +++++++++
drivers/iio/dac/mcp47feb02.h | 43 +++
6 files changed, 221 insertions(+), 307 deletions(-)
diff --git a/MAINTAINERS b/MAINTAINERS
index 3a19da74d00c9dfb48e900df71a86d4686d3ec2c..81abeab698f43bcfb755ed59ce1217bea1a28eb8 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -16297,7 +16297,7 @@ M: Ariana Lazar <ariana.lazar@microchip.com>
L: linux-iio@vger.kernel.org
S: Supported
F: Documentation/devicetree/bindings/iio/dac/microchip,mcp47feb02.yaml
-F: drivers/iio/dac/mcp47feb02.c
+F: drivers/iio/dac/mcp47feb02*
MCP4821 DAC DRIVER
M: Anshul Dalal <anshulusr@gmail.com>
diff --git a/drivers/iio/dac/Kconfig b/drivers/iio/dac/Kconfig
index 3b3c77d8b3e1b6731df6e96723f92d4225e9783d..c99c32b229fb683d6407f30682f7ea6104984421 100644
--- a/drivers/iio/dac/Kconfig
+++ b/drivers/iio/dac/Kconfig
@@ -593,9 +593,13 @@ config MCP47A1
will be called mcp47a1.
config MCP47FEB02
- tristate "MCP47F(E/V)B01/02/04/08/11/12/14/18/21/22/24/28 DAC driver"
+ tristate
+
+config MCP47FEB02_I2C
+ tristate "MCP47F(E/V)B01/02/04/08/11/12/14/18/21/22/24/28 I2C DAC driver"
depends on I2C
select REGMAP_I2C
+ select MCP47FEB02
help
Say yes here if you want to build the driver for the Microchip:
- 8-bit DAC:
@@ -611,7 +615,8 @@ config MCP47FEB02
(DAC) with I2C interface.
To compile this driver as a module, choose M here: the module
- will be called mcp47feb02.
+ will be called mcp47feb02_i2c and you will also get
+ mcp47feb02_core for the core module.
config MCP4821
tristate "MCP4801/02/11/12/21/22 DAC driver"
diff --git a/drivers/iio/dac/Makefile b/drivers/iio/dac/Makefile
index 992f8930f95caed97ebad891d0f3685b4e23bf29..6377a9c42d983f615a0aa4d36a0c3d3639c62951 100644
--- a/drivers/iio/dac/Makefile
+++ b/drivers/iio/dac/Makefile
@@ -56,7 +56,8 @@ obj-$(CONFIG_MCF54415_DAC) += mcf54415_dac.o
obj-$(CONFIG_MCP4725) += mcp4725.o
obj-$(CONFIG_MCP4728) += mcp4728.o
obj-$(CONFIG_MCP47A1) += mcp47a1.o
-obj-$(CONFIG_MCP47FEB02) += mcp47feb02.o
+obj-$(CONFIG_MCP47FEB02) += mcp47feb02-core.o
+obj-$(CONFIG_MCP47FEB02_I2C) += mcp47feb02-i2c.o
obj-$(CONFIG_MCP4821) += mcp4821.o
obj-$(CONFIG_MCP4922) += mcp4922.o
obj-$(CONFIG_STM32_DAC_CORE) += stm32-dac-core.o
diff --git a/drivers/iio/dac/mcp47feb02.c b/drivers/iio/dac/mcp47feb02-core.c
similarity index 73%
rename from drivers/iio/dac/mcp47feb02.c
rename to drivers/iio/dac/mcp47feb02-core.c
index 5c09ca25a75e0ecb2bfc5a2d5e62e5f7d3156810..4a0abe8ad4c1629ece89d89cbcbf5cd460aaa177 100644
--- a/drivers/iio/dac/mcp47feb02.c
+++ b/drivers/iio/dac/mcp47feb02-core.c
@@ -1,8 +1,8 @@
// SPDX-License-Identifier: GPL-2.0+
/*
- * IIO driver for MCP47FEB02 Multi-Channel DAC with I2C interface
+ * IIO driver for MCP47FEB02 Multi-Channel DAC with I2C and SPI interface
*
- * Copyright (C) 2025 Microchip Technology Inc. and its subsidiaries
+ * Copyright (C) 2025-2026 Microchip Technology Inc. and its subsidiaries
*
* Author: Ariana Lazar <ariana.lazar@microchip.com>
*
@@ -16,7 +16,6 @@
#include <linux/bitfield.h>
#include <linux/delay.h>
#include <linux/err.h>
-#include <linux/i2c.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/kstrtox.h>
@@ -29,6 +28,8 @@
#include <linux/types.h>
#include <linux/units.h>
+#include "mcp47feb02.h"
+
/* Register addresses must be left shifted with 3 positions in order to append command mask */
#define MCP47FEB02_DAC0_REG_ADDR 0x00
#define MCP47FEB02_VREF_REG_ADDR 0x40
@@ -85,220 +86,12 @@ enum mcp47feb02_gain_bit_mode {
MCP47FEB02_GAIN_BIT_X2 = 1,
};
-static const char * const mcp47feb02_powerdown_modes[] = {
+const char * const mcp47feb02_powerdown_modes[] = {
"1kohm_to_gnd",
"100kohm_to_gnd",
"open_circuit",
};
-/**
- * struct mcp47feb02_features - chip specific data
- * @name: device name
- * @phys_channels: number of hardware channels
- * @resolution: DAC resolution
- * @have_ext_vref1: does the hardware have an the second external voltage reference?
- * @have_eeprom: does the hardware have an internal eeprom?
- */
-struct mcp47feb02_features {
- const char *name;
- unsigned int phys_channels;
- unsigned int resolution;
- bool have_ext_vref1;
- bool have_eeprom;
-};
-
-static const struct mcp47feb02_features mcp47feb01_chip_features = {
- .name = "mcp47feb01",
- .phys_channels = 1,
- .resolution = 8,
- .have_ext_vref1 = false,
- .have_eeprom = true,
-};
-
-static const struct mcp47feb02_features mcp47feb02_chip_features = {
- .name = "mcp47feb02",
- .phys_channels = 2,
- .resolution = 8,
- .have_ext_vref1 = false,
- .have_eeprom = true,
-};
-
-static const struct mcp47feb02_features mcp47feb04_chip_features = {
- .name = "mcp47feb04",
- .phys_channels = 4,
- .resolution = 8,
- .have_ext_vref1 = true,
- .have_eeprom = true,
-};
-
-static const struct mcp47feb02_features mcp47feb08_chip_features = {
- .name = "mcp47feb08",
- .phys_channels = 8,
- .resolution = 8,
- .have_ext_vref1 = true,
- .have_eeprom = true,
-};
-
-static const struct mcp47feb02_features mcp47feb11_chip_features = {
- .name = "mcp47feb11",
- .phys_channels = 1,
- .resolution = 10,
- .have_ext_vref1 = false,
- .have_eeprom = true,
-};
-
-static const struct mcp47feb02_features mcp47feb12_chip_features = {
- .name = "mcp47feb12",
- .phys_channels = 2,
- .resolution = 10,
- .have_ext_vref1 = false,
- .have_eeprom = true,
-};
-
-static const struct mcp47feb02_features mcp47feb14_chip_features = {
- .name = "mcp47feb14",
- .phys_channels = 4,
- .resolution = 10,
- .have_ext_vref1 = true,
- .have_eeprom = true,
-};
-
-static const struct mcp47feb02_features mcp47feb18_chip_features = {
- .name = "mcp47feb18",
- .phys_channels = 8,
- .resolution = 10,
- .have_ext_vref1 = true,
- .have_eeprom = true,
-};
-
-static const struct mcp47feb02_features mcp47feb21_chip_features = {
- .name = "mcp47feb21",
- .phys_channels = 1,
- .resolution = 12,
- .have_ext_vref1 = false,
- .have_eeprom = true,
-};
-
-static const struct mcp47feb02_features mcp47feb22_chip_features = {
- .name = "mcp47feb22",
- .phys_channels = 2,
- .resolution = 12,
- .have_ext_vref1 = false,
- .have_eeprom = true,
-};
-
-static const struct mcp47feb02_features mcp47feb24_chip_features = {
- .name = "mcp47feb24",
- .phys_channels = 4,
- .resolution = 12,
- .have_ext_vref1 = true,
- .have_eeprom = true,
-};
-
-static const struct mcp47feb02_features mcp47feb28_chip_features = {
- .name = "mcp47feb28",
- .phys_channels = 8,
- .resolution = 12,
- .have_ext_vref1 = true,
- .have_eeprom = true,
-};
-
-static const struct mcp47feb02_features mcp47fvb01_chip_features = {
- .name = "mcp47fvb01",
- .phys_channels = 1,
- .resolution = 8,
- .have_ext_vref1 = false,
- .have_eeprom = false,
-};
-
-static const struct mcp47feb02_features mcp47fvb02_chip_features = {
- .name = "mcp47fvb02",
- .phys_channels = 2,
- .resolution = 8,
- .have_ext_vref1 = false,
- .have_eeprom = false,
-};
-
-static const struct mcp47feb02_features mcp47fvb04_chip_features = {
- .name = "mcp47fvb04",
- .phys_channels = 4,
- .resolution = 8,
- .have_ext_vref1 = true,
- .have_eeprom = false,
-};
-
-static const struct mcp47feb02_features mcp47fvb08_chip_features = {
- .name = "mcp47fvb08",
- .phys_channels = 8,
- .resolution = 8,
- .have_ext_vref1 = true,
- .have_eeprom = false,
-};
-
-static const struct mcp47feb02_features mcp47fvb11_chip_features = {
- .name = "mcp47fvb11",
- .phys_channels = 1,
- .resolution = 10,
- .have_ext_vref1 = false,
- .have_eeprom = false,
-};
-
-static const struct mcp47feb02_features mcp47fvb12_chip_features = {
- .name = "mcp47fvb12",
- .phys_channels = 2,
- .resolution = 10,
- .have_ext_vref1 = false,
- .have_eeprom = false,
-};
-
-static const struct mcp47feb02_features mcp47fvb14_chip_features = {
- .name = "mcp47fvb14",
- .phys_channels = 4,
- .resolution = 10,
- .have_ext_vref1 = true,
- .have_eeprom = false,
-};
-
-static const struct mcp47feb02_features mcp47fvb18_chip_features = {
- .name = "mcp47fvb18",
- .phys_channels = 8,
- .resolution = 10,
- .have_ext_vref1 = true,
- .have_eeprom = false,
-};
-
-static const struct mcp47feb02_features mcp47fvb21_chip_features = {
- .name = "mcp47fvb21",
- .phys_channels = 1,
- .resolution = 12,
- .have_ext_vref1 = false,
- .have_eeprom = false,
-};
-
-static const struct mcp47feb02_features mcp47fvb22_chip_features = {
- .name = "mcp47fvb22",
- .phys_channels = 2,
- .resolution = 12,
- .have_ext_vref1 = false,
- .have_eeprom = false,
-};
-
-static const struct mcp47feb02_features mcp47fvb24_chip_features = {
- .name = "mcp47fvb24",
- .phys_channels = 4,
- .resolution = 12,
- .have_ext_vref1 = true,
- .have_eeprom = false,
-};
-
-static const struct mcp47feb02_features mcp47fvb28_chip_features = {
- .name = "mcp47fvb28",
- .phys_channels = 8,
- .resolution = 12,
- .have_ext_vref1 = true,
- .have_eeprom = false,
-};
-
/**
* struct mcp47feb02_channel_data - channel configuration
* @ref_mode: chosen voltage for reference
@@ -379,7 +172,7 @@ static const struct regmap_access_table mcp47feb02_volatile_table = {
.n_yes_ranges = ARRAY_SIZE(mcp47feb02_volatile_ranges),
};
-static const struct regmap_config mcp47feb02_regmap_config = {
+const struct regmap_config mcp47feb02_regmap_config = {
.name = "mcp47feb02_regmap",
.reg_bits = 8,
.val_bits = 16,
@@ -391,6 +184,7 @@ static const struct regmap_config mcp47feb02_regmap_config = {
.cache_type = REGCACHE_MAPLE,
.val_format_endian = REGMAP_ENDIAN_BIG,
};
+EXPORT_SYMBOL_NS_GPL(mcp47feb02_regmap_config, "IIO_MCP47FEB02");
/* For devices that doesn't have nonvolatile memory */
static const struct regmap_range mcp47fvb02_readable_ranges[] = {
@@ -421,7 +215,7 @@ static const struct regmap_access_table mcp47fvb02_volatile_table = {
.n_yes_ranges = ARRAY_SIZE(mcp47fvb02_volatile_ranges),
};
-static const struct regmap_config mcp47fvb02_regmap_config = {
+const struct regmap_config mcp47fvb02_regmap_config = {
.name = "mcp47fvb02_regmap",
.reg_bits = 8,
.val_bits = 16,
@@ -433,6 +227,7 @@ static const struct regmap_config mcp47fvb02_regmap_config = {
.cache_type = REGCACHE_MAPLE,
.val_format_endian = REGMAP_ENDIAN_BIG,
};
+EXPORT_SYMBOL_NS_GPL(mcp47fvb02_regmap_config, "IIO_MCP47FEB02");
static int mcp47feb02_write_to_eeprom(struct mcp47feb02_data *data, unsigned int reg,
unsigned int val)
@@ -443,8 +238,6 @@ static int mcp47feb02_write_to_eeprom(struct mcp47feb02_data *data, unsigned int
* Wait until the currently occurring EEPROM Write Cycle is completed.
* Only serial commands to the volatile memory are allowed.
*/
- guard(mutex)(&data->lock);
-
ret = regmap_read_poll_timeout(data->regmap, MCP47FEB02_GAIN_CTRL_STATUS_REG_ADDR,
eewa_val,
!(eewa_val & MCP47FEB02_GAIN_BIT_STATUS_EEWA_MASK),
@@ -470,6 +263,8 @@ static ssize_t store_eeprom_store(struct device *dev, struct device_attribute *a
if (!state)
return len;
+ guard(mutex)(&data->lock);
+
/*
* Verify DAC Wiper and DAC Configuration are unlocked. If both are disabled,
* writing to EEPROM is available.
@@ -577,11 +372,9 @@ static int mcp47feb02_resume(struct device *dev)
guard(mutex)(&data->lock);
for_each_set_bit(ch, &data->active_channels_mask, data->phys_channels) {
- u8 pd_mode;
int ret;
data->chdata[ch].powerdown = false;
- pd_mode = data->chdata[ch].powerdown_mode + 1;
ret = regmap_write(data->regmap, REG_ADDR(ch), data->chdata[ch].dac_data);
if (ret)
@@ -589,7 +382,8 @@ static int mcp47feb02_resume(struct device *dev)
ret = regmap_update_bits(data->regmap, MCP47FEB02_VREF_REG_ADDR,
MCP47FEB02_VREF_PD_MASK(ch),
- MCP47FEB02_VREF_PD_VAL(ch, pd_mode));
+ MCP47FEB02_VREF_PD_VAL(ch, data->chdata[ch].ref_mode));
+
if (ret)
return ret;
@@ -668,7 +462,7 @@ static ssize_t mcp47feb02_write_powerdown(struct iio_dev *indio_dev, uintptr_t p
return len;
}
-static DEFINE_SIMPLE_DEV_PM_OPS(mcp47feb02_pm_ops, mcp47feb02_suspend, mcp47feb02_resume);
+EXPORT_SIMPLE_DEV_PM_OPS(mcp47feb02_pm_ops, mcp47feb02_suspend, mcp47feb02_resume);
static const struct iio_enum mcp47febxx_powerdown_mode_enum = {
.items = mcp47feb02_powerdown_modes,
@@ -1099,10 +893,10 @@ static int mcp47feb02_init_ch_scales(struct mcp47feb02_data *data, int vdd_uV,
return 0;
}
-static int mcp47feb02_probe(struct i2c_client *client)
+int mcp47feb02_common_probe(const struct mcp47feb02_features *chip_features,
+ struct regmap *regmap)
{
- const struct mcp47feb02_features *chip_features;
- struct device *dev = &client->dev;
+ struct device *dev = regmap_get_device(regmap);
struct mcp47feb02_data *data;
struct iio_dev *indio_dev;
int vref1_uV, vref_uV, vdd_uV, ret;
@@ -1111,22 +905,16 @@ static int mcp47feb02_probe(struct i2c_client *client)
if (!indio_dev)
return -ENOMEM;
- data = iio_priv(indio_dev);
- chip_features = i2c_get_match_data(client);
- if (!chip_features)
- return -EINVAL;
+ dev_set_drvdata(dev, indio_dev);
+ data = iio_priv(indio_dev);
data->chip_features = chip_features;
+ data->regmap = regmap;
- if (chip_features->have_eeprom) {
- data->regmap = devm_regmap_init_i2c(client, &mcp47feb02_regmap_config);
+ if (chip_features->have_eeprom)
indio_dev->info = &mcp47feb02_info;
- } else {
- data->regmap = devm_regmap_init_i2c(client, &mcp47fvb02_regmap_config);
+ else
indio_dev->info = &mcp47fvb02_info;
- }
- if (IS_ERR(data->regmap))
- return dev_err_probe(dev, PTR_ERR(data->regmap), "Error initializing i2c regmap\n");
indio_dev->name = chip_features->name;
@@ -1183,75 +971,7 @@ static int mcp47feb02_probe(struct i2c_client *client)
return devm_iio_device_register(dev, indio_dev);
}
-
-static const struct i2c_device_id mcp47feb02_id[] = {
- { .name = "mcp47feb01", .driver_data = (kernel_ulong_t)&mcp47feb01_chip_features },
- { .name = "mcp47feb02", .driver_data = (kernel_ulong_t)&mcp47feb02_chip_features },
- { .name = "mcp47feb04", .driver_data = (kernel_ulong_t)&mcp47feb04_chip_features },
- { .name = "mcp47feb08", .driver_data = (kernel_ulong_t)&mcp47feb08_chip_features },
- { .name = "mcp47feb11", .driver_data = (kernel_ulong_t)&mcp47feb11_chip_features },
- { .name = "mcp47feb12", .driver_data = (kernel_ulong_t)&mcp47feb12_chip_features },
- { .name = "mcp47feb14", .driver_data = (kernel_ulong_t)&mcp47feb14_chip_features },
- { .name = "mcp47feb18", .driver_data = (kernel_ulong_t)&mcp47feb18_chip_features },
- { .name = "mcp47feb21", .driver_data = (kernel_ulong_t)&mcp47feb21_chip_features },
- { .name = "mcp47feb22", .driver_data = (kernel_ulong_t)&mcp47feb22_chip_features },
- { .name = "mcp47feb24", .driver_data = (kernel_ulong_t)&mcp47feb24_chip_features },
- { .name = "mcp47feb28", .driver_data = (kernel_ulong_t)&mcp47feb28_chip_features },
- { .name = "mcp47fvb01", .driver_data = (kernel_ulong_t)&mcp47fvb01_chip_features },
- { .name = "mcp47fvb02", .driver_data = (kernel_ulong_t)&mcp47fvb02_chip_features },
- { .name = "mcp47fvb04", .driver_data = (kernel_ulong_t)&mcp47fvb04_chip_features },
- { .name = "mcp47fvb08", .driver_data = (kernel_ulong_t)&mcp47fvb08_chip_features },
- { .name = "mcp47fvb11", .driver_data = (kernel_ulong_t)&mcp47fvb11_chip_features },
- { .name = "mcp47fvb12", .driver_data = (kernel_ulong_t)&mcp47fvb12_chip_features },
- { .name = "mcp47fvb14", .driver_data = (kernel_ulong_t)&mcp47fvb14_chip_features },
- { .name = "mcp47fvb18", .driver_data = (kernel_ulong_t)&mcp47fvb18_chip_features },
- { .name = "mcp47fvb21", .driver_data = (kernel_ulong_t)&mcp47fvb21_chip_features },
- { .name = "mcp47fvb22", .driver_data = (kernel_ulong_t)&mcp47fvb22_chip_features },
- { .name = "mcp47fvb24", .driver_data = (kernel_ulong_t)&mcp47fvb24_chip_features },
- { .name = "mcp47fvb28", .driver_data = (kernel_ulong_t)&mcp47fvb28_chip_features },
- { }
-};
-MODULE_DEVICE_TABLE(i2c, mcp47feb02_id);
-
-static const struct of_device_id mcp47feb02_of_match[] = {
- { .compatible = "microchip,mcp47feb01", .data = &mcp47feb01_chip_features },
- { .compatible = "microchip,mcp47feb02", .data = &mcp47feb02_chip_features },
- { .compatible = "microchip,mcp47feb04", .data = &mcp47feb04_chip_features },
- { .compatible = "microchip,mcp47feb08", .data = &mcp47feb08_chip_features },
- { .compatible = "microchip,mcp47feb11", .data = &mcp47feb11_chip_features },
- { .compatible = "microchip,mcp47feb12", .data = &mcp47feb12_chip_features },
- { .compatible = "microchip,mcp47feb14", .data = &mcp47feb14_chip_features },
- { .compatible = "microchip,mcp47feb18", .data = &mcp47feb18_chip_features },
- { .compatible = "microchip,mcp47feb21", .data = &mcp47feb21_chip_features },
- { .compatible = "microchip,mcp47feb22", .data = &mcp47feb22_chip_features },
- { .compatible = "microchip,mcp47feb24", .data = &mcp47feb24_chip_features },
- { .compatible = "microchip,mcp47feb28", .data = &mcp47feb28_chip_features },
- { .compatible = "microchip,mcp47fvb01", .data = &mcp47fvb01_chip_features },
- { .compatible = "microchip,mcp47fvb02", .data = &mcp47fvb02_chip_features },
- { .compatible = "microchip,mcp47fvb04", .data = &mcp47fvb04_chip_features },
- { .compatible = "microchip,mcp47fvb08", .data = &mcp47fvb08_chip_features },
- { .compatible = "microchip,mcp47fvb11", .data = &mcp47fvb11_chip_features },
- { .compatible = "microchip,mcp47fvb12", .data = &mcp47fvb12_chip_features },
- { .compatible = "microchip,mcp47fvb14", .data = &mcp47fvb14_chip_features },
- { .compatible = "microchip,mcp47fvb18", .data = &mcp47fvb18_chip_features },
- { .compatible = "microchip,mcp47fvb21", .data = &mcp47fvb21_chip_features },
- { .compatible = "microchip,mcp47fvb22", .data = &mcp47fvb22_chip_features },
- { .compatible = "microchip,mcp47fvb24", .data = &mcp47fvb24_chip_features },
- { .compatible = "microchip,mcp47fvb28", .data = &mcp47fvb28_chip_features },
- { }
-};
-MODULE_DEVICE_TABLE(of, mcp47feb02_of_match);
-
-static struct i2c_driver mcp47feb02_driver = {
- .driver = {
- .name = "mcp47feb02",
- .of_match_table = mcp47feb02_of_match,
- .pm = pm_sleep_ptr(&mcp47feb02_pm_ops),
- },
- .probe = mcp47feb02_probe,
- .id_table = mcp47feb02_id,
-};
-module_i2c_driver(mcp47feb02_driver);
+EXPORT_SYMBOL_NS(mcp47feb02_common_probe, "IIO_MCP47FEB02");
MODULE_AUTHOR("Ariana Lazar <ariana.lazar@microchip.com>");
MODULE_DESCRIPTION("IIO driver for MCP47FEB02 Multi-Channel DAC with I2C interface");
diff --git a/drivers/iio/dac/mcp47feb02-i2c.c b/drivers/iio/dac/mcp47feb02-i2c.c
new file mode 100644
index 0000000000000000000000000000000000000000..7ec0cccad79bc9e9e3f919209c34d0f39656a370
--- /dev/null
+++ b/drivers/iio/dac/mcp47feb02-i2c.c
@@ -0,0 +1,145 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * IIO driver for MCP47FEB02 Multi-Channel DAC with I2C interface
+ *
+ * Copyright (C) 2025-2026 Microchip Technology Inc. and its subsidiaries
+ *
+ * Author: Ariana Lazar <ariana.lazar@microchip.com>
+ *
+ * Datasheet links for devices with I2C interface:
+ * [MCP47FEBxx] https://ww1.microchip.com/downloads/aemDocuments/documents/OTH/ProductDocuments/DataSheets/20005375A.pdf
+ * [MCP47FVBxx] https://ww1.microchip.com/downloads/aemDocuments/documents/OTH/ProductDocuments/DataSheets/20005405A.pdf
+ * [MCP47FxBx4/8] https://ww1.microchip.com/downloads/aemDocuments/documents/MSLD/ProductDocuments/DataSheets/MCP47FXBX48-Data-Sheet-DS200006368A.pdf
+ */
+#include <linux/dev_printk.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/pm.h>
+#include <linux/regmap.h>
+#include <linux/types.h>
+
+#include "mcp47feb02.h"
+
+/* Parts with EEPROM memory */
+MCP47FEB02_CHIP_INFO(mcp47feb01, 1, 8, false, true);
+MCP47FEB02_CHIP_INFO(mcp47feb02, 2, 8, false, true);
+MCP47FEB02_CHIP_INFO(mcp47feb04, 4, 8, true, true);
+MCP47FEB02_CHIP_INFO(mcp47feb08, 8, 8, true, true);
+MCP47FEB02_CHIP_INFO(mcp47feb11, 1, 10, false, true);
+MCP47FEB02_CHIP_INFO(mcp47feb12, 2, 10, false, true);
+MCP47FEB02_CHIP_INFO(mcp47feb14, 4, 10, true, true);
+MCP47FEB02_CHIP_INFO(mcp47feb18, 8, 10, true, true);
+MCP47FEB02_CHIP_INFO(mcp47feb21, 1, 12, false, true);
+MCP47FEB02_CHIP_INFO(mcp47feb22, 2, 12, false, true);
+MCP47FEB02_CHIP_INFO(mcp47feb24, 4, 12, true, true);
+MCP47FEB02_CHIP_INFO(mcp47feb28, 8, 12, true, true);
+
+/* Parts without EEPROM memory */
+MCP47FEB02_CHIP_INFO(mcp47fvb01, 1, 8, false, false);
+MCP47FEB02_CHIP_INFO(mcp47fvb02, 2, 8, false, false);
+MCP47FEB02_CHIP_INFO(mcp47fvb04, 4, 8, true, false);
+MCP47FEB02_CHIP_INFO(mcp47fvb08, 8, 8, true, false);
+MCP47FEB02_CHIP_INFO(mcp47fvb11, 1, 10, false, false);
+MCP47FEB02_CHIP_INFO(mcp47fvb12, 2, 10, false, false);
+MCP47FEB02_CHIP_INFO(mcp47fvb14, 4, 10, true, false);
+MCP47FEB02_CHIP_INFO(mcp47fvb18, 8, 10, true, false);
+MCP47FEB02_CHIP_INFO(mcp47fvb21, 1, 12, false, false);
+MCP47FEB02_CHIP_INFO(mcp47fvb22, 2, 12, false, false);
+MCP47FEB02_CHIP_INFO(mcp47fvb24, 4, 12, true, false);
+MCP47FEB02_CHIP_INFO(mcp47fvb28, 8, 12, true, false);
+
+static int mcp47feb02_i2c_probe(struct i2c_client *client)
+{
+ const struct mcp47feb02_features *chip_features;
+ struct device *dev = &client->dev;
+ struct regmap *regmap;
+
+ chip_features = i2c_get_match_data(client);
+ if (!chip_features)
+ return dev_err_probe(dev, -ENODATA, "No match data found\n");
+
+ if (chip_features->have_eeprom)
+ regmap = devm_regmap_init_i2c(client, &mcp47feb02_regmap_config);
+ else
+ regmap = devm_regmap_init_i2c(client, &mcp47fvb02_regmap_config);
+
+ if (IS_ERR(regmap))
+ return dev_err_probe(dev, PTR_ERR(regmap), "Error initializing I2C regmap\n");
+
+ return mcp47feb02_common_probe(chip_features, regmap);
+}
+
+static const struct i2c_device_id mcp47feb02_i2c_id[] = {
+ { .name = "mcp47feb01", .driver_data = (kernel_ulong_t)&mcp47feb01_chip_features },
+ { .name = "mcp47feb02", .driver_data = (kernel_ulong_t)&mcp47feb02_chip_features },
+ { .name = "mcp47feb04", .driver_data = (kernel_ulong_t)&mcp47feb04_chip_features },
+ { .name = "mcp47feb08", .driver_data = (kernel_ulong_t)&mcp47feb08_chip_features },
+ { .name = "mcp47feb11", .driver_data = (kernel_ulong_t)&mcp47feb11_chip_features },
+ { .name = "mcp47feb12", .driver_data = (kernel_ulong_t)&mcp47feb12_chip_features },
+ { .name = "mcp47feb14", .driver_data = (kernel_ulong_t)&mcp47feb14_chip_features },
+ { .name = "mcp47feb18", .driver_data = (kernel_ulong_t)&mcp47feb18_chip_features },
+ { .name = "mcp47feb21", .driver_data = (kernel_ulong_t)&mcp47feb21_chip_features },
+ { .name = "mcp47feb22", .driver_data = (kernel_ulong_t)&mcp47feb22_chip_features },
+ { .name = "mcp47feb24", .driver_data = (kernel_ulong_t)&mcp47feb24_chip_features },
+ { .name = "mcp47feb28", .driver_data = (kernel_ulong_t)&mcp47feb28_chip_features },
+ { .name = "mcp47fvb01", .driver_data = (kernel_ulong_t)&mcp47fvb01_chip_features },
+ { .name = "mcp47fvb02", .driver_data = (kernel_ulong_t)&mcp47fvb02_chip_features },
+ { .name = "mcp47fvb04", .driver_data = (kernel_ulong_t)&mcp47fvb04_chip_features },
+ { .name = "mcp47fvb08", .driver_data = (kernel_ulong_t)&mcp47fvb08_chip_features },
+ { .name = "mcp47fvb11", .driver_data = (kernel_ulong_t)&mcp47fvb11_chip_features },
+ { .name = "mcp47fvb12", .driver_data = (kernel_ulong_t)&mcp47fvb12_chip_features },
+ { .name = "mcp47fvb14", .driver_data = (kernel_ulong_t)&mcp47fvb14_chip_features },
+ { .name = "mcp47fvb18", .driver_data = (kernel_ulong_t)&mcp47fvb18_chip_features },
+ { .name = "mcp47fvb21", .driver_data = (kernel_ulong_t)&mcp47fvb21_chip_features },
+ { .name = "mcp47fvb22", .driver_data = (kernel_ulong_t)&mcp47fvb22_chip_features },
+ { .name = "mcp47fvb24", .driver_data = (kernel_ulong_t)&mcp47fvb24_chip_features },
+ { .name = "mcp47fvb28", .driver_data = (kernel_ulong_t)&mcp47fvb28_chip_features },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, mcp47feb02_i2c_id);
+
+static const struct of_device_id mcp47feb02_of_i2c_match[] = {
+ { .compatible = "microchip,mcp47feb01", .data = &mcp47feb01_chip_features },
+ { .compatible = "microchip,mcp47feb02", .data = &mcp47feb02_chip_features },
+ { .compatible = "microchip,mcp47feb04", .data = &mcp47feb04_chip_features },
+ { .compatible = "microchip,mcp47feb08", .data = &mcp47feb08_chip_features },
+ { .compatible = "microchip,mcp47feb11", .data = &mcp47feb11_chip_features },
+ { .compatible = "microchip,mcp47feb12", .data = &mcp47feb12_chip_features },
+ { .compatible = "microchip,mcp47feb14", .data = &mcp47feb14_chip_features },
+ { .compatible = "microchip,mcp47feb18", .data = &mcp47feb18_chip_features },
+ { .compatible = "microchip,mcp47feb21", .data = &mcp47feb21_chip_features },
+ { .compatible = "microchip,mcp47feb22", .data = &mcp47feb22_chip_features },
+ { .compatible = "microchip,mcp47feb24", .data = &mcp47feb24_chip_features },
+ { .compatible = "microchip,mcp47feb28", .data = &mcp47feb28_chip_features },
+ { .compatible = "microchip,mcp47fvb01", .data = &mcp47fvb01_chip_features },
+ { .compatible = "microchip,mcp47fvb02", .data = &mcp47fvb02_chip_features },
+ { .compatible = "microchip,mcp47fvb04", .data = &mcp47fvb04_chip_features },
+ { .compatible = "microchip,mcp47fvb08", .data = &mcp47fvb08_chip_features },
+ { .compatible = "microchip,mcp47fvb11", .data = &mcp47fvb11_chip_features },
+ { .compatible = "microchip,mcp47fvb12", .data = &mcp47fvb12_chip_features },
+ { .compatible = "microchip,mcp47fvb14", .data = &mcp47fvb14_chip_features },
+ { .compatible = "microchip,mcp47fvb18", .data = &mcp47fvb18_chip_features },
+ { .compatible = "microchip,mcp47fvb21", .data = &mcp47fvb21_chip_features },
+ { .compatible = "microchip,mcp47fvb22", .data = &mcp47fvb22_chip_features },
+ { .compatible = "microchip,mcp47fvb24", .data = &mcp47fvb24_chip_features },
+ { .compatible = "microchip,mcp47fvb28", .data = &mcp47fvb28_chip_features },
+ { }
+};
+MODULE_DEVICE_TABLE(of, mcp47feb02_of_i2c_match);
+
+static struct i2c_driver mcp47feb02_i2c_driver = {
+ .driver = {
+ .name = "mcp47feb02",
+ .of_match_table = mcp47feb02_of_i2c_match,
+ .pm = pm_sleep_ptr(&mcp47feb02_pm_ops),
+ },
+ .probe = mcp47feb02_i2c_probe,
+ .id_table = mcp47feb02_i2c_id,
+};
+module_i2c_driver(mcp47feb02_i2c_driver);
+
+MODULE_AUTHOR("Ariana Lazar <ariana.lazar@microchip.com>");
+MODULE_DESCRIPTION("IIO driver for MCP47FEB02 Multi-Channel DAC with I2C interface");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("IIO_MCP47FEB02");
diff --git a/drivers/iio/dac/mcp47feb02.h b/drivers/iio/dac/mcp47feb02.h
new file mode 100644
index 0000000000000000000000000000000000000000..5bcce1f9ae112c4fecc930f9927442eb93832f20
--- /dev/null
+++ b/drivers/iio/dac/mcp47feb02.h
@@ -0,0 +1,43 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+#ifndef __DRIVERS_IIO_DAC_MCP47FEB02_H__
+#define __DRIVERS_IIO_DAC_MCP47FEB02_H__
+
+#include <linux/pm.h>
+#include <linux/types.h>
+
+extern const char * const mcp47feb02_powerdown_modes[];
+
+#define MCP47FEB02_CHIP_INFO(_name, _channels, _res, _vref1, _eeprom) \
+static const struct mcp47feb02_features _name##_chip_features = { \
+ .name = #_name, \
+ .phys_channels = _channels, \
+ .resolution = _res, \
+ .have_ext_vref1 = _vref1, \
+ .have_eeprom = _eeprom, \
+}
+
+/**
+ * struct mcp47feb02_features - chip specific data
+ * @name: device name
+ * @phys_channels: number of hardware channels
+ * @resolution: DAC resolution
+ * @have_ext_vref1: does the hardware have an the second external voltage reference?
+ * @have_eeprom: does the hardware have an internal eeprom?
+ */
+struct mcp47feb02_features {
+ const char *name;
+ unsigned int phys_channels;
+ unsigned int resolution;
+ bool have_ext_vref1;
+ bool have_eeprom;
+};
+
+extern const struct regmap_config mcp47feb02_regmap_config;
+extern const struct regmap_config mcp47fvb02_regmap_config;
+
+int mcp47feb02_common_probe(const struct mcp47feb02_features *chip_features,
+ struct regmap *regmap);
+
+extern const struct dev_pm_ops mcp47feb02_pm_ops;
+
+#endif /* __DRIVERS_IIO_DAC_MCP47FEB02_H__ */
--
2.43.0
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH v6 10/11] dt-bindings: iio: dac: add support for MCP48FEB02 SPI
2026-09-16 14:16 [PATCH v6 00/11] Refactor Microchip MCP47FEB02 I2C driver in separate modules to add support for MCP48FEB02 SPI driver Ariana Lazar
` (8 preceding siblings ...)
2026-09-16 14:16 ` [PATCH v6 09/11] iio: dac: mcp47feb02: refactor MCP47FEB02 I2C driver into two modules Ariana Lazar
@ 2026-09-16 14:16 ` Ariana Lazar
2026-09-16 14:16 ` [PATCH v6 11/11] iio: dac: add support for Microchip MCP48FEB02 Ariana Lazar
2026-09-16 15:26 ` [PATCH v6 00/11] Refactor Microchip MCP47FEB02 I2C driver in separate modules to add support for MCP48FEB02 SPI driver Andy Shevchenko
11 siblings, 0 replies; 17+ messages in thread
From: Ariana Lazar @ 2026-09-16 14:16 UTC (permalink / raw)
To: Jonathan Cameron, David Lechner, Nuno Sá,
Andy Shevchenko, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: linux-kernel, linux-iio, devicetree, Ariana Lazar, Jonathan Cameron
Add the SPI MCP48FxBy1/2/4/8 part numbers, the spi-max-frequency property
and a devicetree example for SPI usage to the existing binding.
Signed-off-by: Ariana Lazar <ariana.lazar@microchip.com>
Reviewed-by: Rob Herring (Arm) <robh@kernel.org>
---
.../bindings/iio/dac/microchip,mcp47feb02.yaml | 221 ++++++++++++++++-----
1 file changed, 173 insertions(+), 48 deletions(-)
diff --git a/Documentation/devicetree/bindings/iio/dac/microchip,mcp47feb02.yaml b/Documentation/devicetree/bindings/iio/dac/microchip,mcp47feb02.yaml
index d131f136bd15161666932261bcacd6d124b23ede..a86d094f0d4b54f9d9cc39fd54222f5968714668 100644
--- a/Documentation/devicetree/bindings/iio/dac/microchip,mcp47feb02.yaml
+++ b/Documentation/devicetree/bindings/iio/dac/microchip,mcp47feb02.yaml
@@ -4,58 +4,92 @@
$id: http://devicetree.org/schemas/iio/dac/microchip,mcp47feb02.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
-title: Microchip MCP47F(E/V)B(0/1/2)(1/2/4/8) DAC with I2C Interface Families
+title: Microchip MCP4(7/8)F(E/V)B(0/1/2)(1/2/4/8) DAC with I2C/SPI Interface Families
maintainers:
- Ariana Lazar <ariana.lazar@microchip.com>
description: |
- Datasheet for MCP47FEB01, MCP47FEB11, MCP47FEB21, MCP47FEB02, MCP47FEB12,
- MCP47FEB22 can be found here:
- https://ww1.microchip.com/downloads/aemDocuments/documents/OTH/ProductDocuments/DataSheets/20005375A.pdf
- Datasheet for MCP47FVB01, MCP47FVB11, MCP47FVB21, MCP47FVB02, MCP47FVB12,
- MCP47FVB22 can be found here:
- https://ww1.microchip.com/downloads/aemDocuments/documents/OTH/ProductDocuments/DataSheets/20005405A.pdf
- Datasheet for MCP47FEB04, MCP47FEB14, MCP47FEB24, MCP47FEB08, MCP47FEB18,
- MCP47FEB28, MCP47FVB04, MCP47FVB14, MCP47FVB24, MCP47FVB08, MCP47FVB18,
- MCP47FVB28 can be found here:
- https://ww1.microchip.com/downloads/aemDocuments/documents/MSLD/ProductDocuments/DataSheets/MCP47FXBX48-Data-Sheet-DS200006368A.pdf
-
- +------------+--------------+-------------+-------------+------------+
- | Device | Resolution | Channels | Vref number | Memory |
- |------------|--------------|-------------|-------------|------------|
- | MCP47FEB01 | 8-bit | 1 | 1 | EEPROM |
- | MCP47FEB11 | 10-bit | 1 | 1 | EEPROM |
- | MCP47FEB21 | 12-bit | 1 | 1 | EEPROM |
- |------------|--------------|-------------|-------------|------------|
- | MCP47FEB02 | 8-bit | 2 | 1 | EEPROM |
- | MCP47FEB12 | 10-bit | 2 | 1 | EEPROM |
- | MCP47FEB22 | 12-bit | 2 | 1 | EEPROM |
- |------------|--------------|-------------|-------------|------------|
- | MCP47FVB01 | 8-bit | 1 | 1 | RAM |
- | MCP47FVB11 | 10-bit | 1 | 1 | RAM |
- | MCP47FVB21 | 12-bit | 1 | 1 | RAM |
- |------------|--------------|-------------|-------------|------------|
- | MCP47FVB02 | 8-bit | 2 | 1 | RAM |
- | MCP47FVB12 | 10-bit | 2 | 1 | RAM |
- | MCP47FVB22 | 12-bit | 2 | 1 | RAM |
- |------------|--------------|-------------|-------------|------------|
- | MCP47FVB04 | 8-bit | 4 | 2 | RAM |
- | MCP47FVB14 | 10-bit | 4 | 2 | RAM |
- | MCP47FVB24 | 12-bit | 4 | 2 | RAM |
- |------------|--------------|-------------|-------------|------------|
- | MCP47FVB08 | 8-bit | 8 | 2 | RAM |
- | MCP47FVB18 | 10-bit | 8 | 2 | RAM |
- | MCP47FVB28 | 12-bit | 8 | 2 | RAM |
- |------------|--------------|-------------|-------------|------------|
- | MCP47FEB04 | 8-bit | 4 | 2 | EEPROM |
- | MCP47FEB14 | 10-bit | 4 | 2 | EEPROM |
- | MCP47FEB24 | 12-bit | 4 | 2 | EEPROM |
- |------------|--------------|-------------|-------------|------------|
- | MCP47FEB08 | 8-bit | 8 | 2 | EEPROM |
- | MCP47FEB18 | 10-bit | 8 | 2 | EEPROM |
- | MCP47FEB28 | 12-bit | 8 | 2 | EEPROM |
- +------------+--------------+-------------+-------------+------------+
+ Datasheets for MCP47F(E/V)B(0/1/2)(1/2/4/8) DAC with I2C Interface Families:
+ Datasheet for MCP47FEB01, MCP47FEB02, MCP47FEB11, MCP47FEB12, MCP47FEB21,
+ MCP47FEB22 can be found here:
+ https://ww1.microchip.com/downloads/aemDocuments/documents/OTH/ProductDocuments/DataSheets/20005375A.pdf
+ Datasheet for MCP47FVB01, MCP47FVB02, MCP47FVB11, MCP47FVB12, MCP47FVB21,
+ MCP47FVB22 can be found here:
+ https://ww1.microchip.com/downloads/aemDocuments/documents/OTH/ProductDocuments/DataSheets/20005405A.pdf
+ Datasheet for MCP47FEB04, MCP47FEB08, MCP47FEB14, MCP47FEB18, MCP47FEB24,
+ MCP47FEB28, MCP47FVB04, MCP47FVB08, MCP47FVB14, MCP47FVB18, MCP47FVB24,
+ MCP47FVB28 can be found here:
+ https://ww1.microchip.com/downloads/aemDocuments/documents/MSLD/ProductDocuments/DataSheets/MCP47FXBX48-Data-Sheet-DS200006368A.pdf
+ Datasheets for MCP48F(E/V)B(0/1/2)(1/2/4/8) DAC with SPI Interface Families:
+ Datasheet for MCP48FEB01, MCP48FEB02, MCP48FEB11, MCP48FEB12, MCP48FEB21,
+ MCP48FEB22 can be found here:
+ https://ww1.microchip.com/downloads/aemDocuments/documents/OTH/ProductDocuments/DataSheets/20005429B.pdf
+ Datasheet for MCP48FVB01, MCP48FVB02, MCP48FVB11, MCP48FVB12, MCP48FVB21,
+ MCP48FVB22 can be found here:
+ https://ww1.microchip.com/downloads/aemDocuments/documents/OTH/ProductDocuments/DataSheets/20005466A.pdf
+ Datasheet for MCP48FEB04, MCP48FEB14, MCP48FEB24, MCP48FEB08, MCP48FEB18,
+ MCP48FEB28, MCP48FVB04, MCP48FVB14, MCP48FVB24, MCP48FVB08, MCP48FVB18,
+ MCP48FVB28 can be found here:
+ https://ww1.microchip.com/downloads/aemDocuments/documents/MSLD/ProductDocuments/DataSheets/MCP48FXBX4-8-Family-Data-Sheet-DS20006362A.pdf
+
+ +------------+--------------+-------------+-------------+------------+------------+
+ | Device | Resolution | Channels | Vref number | Memory | Interface |
+ |------------|--------------|-------------|-------------|------------|------------|
+ | MCP47FEB01 | | 1 | 1 | EEPROM | I2C |
+ | MCP47FEB02 | | 2 | 1 | EEPROM | I2C |
+ | MCP47FEB04 | | 4 | 2 | EEPROM | I2C |
+ | MCP47FEB08 | 8-bit | 8 | 2 | EEPROM | I2C |
+ | MCP48FEB01 | | 1 | 1 | EEPROM | SPI |
+ | MCP48FEB02 | | 2 | 1 | EEPROM | SPI |
+ | MCP48FEB04 | | 4 | 2 | EEPROM | SPI |
+ | MCP48FEB08 | | 8 | 2 | EEPROM | SPI |
+ |------------|--------------|-------------|-------------|------------|------------|
+ | MCP47FEB11 | | 1 | 1 | EEPROM | I2C |
+ | MCP47FEB12 | | 2 | 1 | EEPROM | I2C |
+ | MCP47FEB14 | | 4 | 2 | EEPROM | I2C |
+ | MCP47FEB18 | 10-bit | 8 | 2 | EEPROM | I2C |
+ | MCP48FEB11 | | 1 | 1 | EEPROM | SPI |
+ | MCP48FEB12 | | 2 | 1 | EEPROM | SPI |
+ | MCP48FEB14 | | 4 | 2 | EEPROM | SPI |
+ | MCP48FEB18 | | 8 | 2 | EEPROM | SPI |
+ |------------|--------------|-------------|-------------|------------|------------|
+ | MCP47FEB21 | | 1 | 1 | EEPROM | I2C |
+ | MCP47FEB22 | | 2 | 1 | EEPROM | I2C |
+ | MCP47FEB24 | | 4 | 2 | EEPROM | I2C |
+ | MCP47FEB28 | 12-bit | 8 | 2 | EEPROM | I2C |
+ | MCP48FEB21 | | 1 | 1 | EEPROM | SPI |
+ | MCP48FEB22 | | 2 | 1 | EEPROM | SPI |
+ | MCP48FEB24 | | 4 | 2 | EEPROM | SPI |
+ | MCP48FEB28 | | 8 | 2 | EEPROM | SPI |
+ |------------|--------------|-------------|-------------|------------|------------|
+ | MCP47FVB01 | | 1 | 1 | RAM | I2C |
+ | MCP47FVB02 | | 2 | 1 | RAM | I2C |
+ | MCP47FVB04 | | 4 | 2 | RAM | I2C |
+ | MCP47FVB08 | 8-bit | 8 | 2 | RAM | I2C |
+ | MCP48FVB01 | | 1 | 1 | RAM | SPI |
+ | MCP48FVB02 | | 2 | 1 | RAM | SPI |
+ | MCP48FVB04 | | 4 | 2 | RAM | SPI |
+ | MCP48FVB08 | | 8 | 2 | RAM | SPI |
+ |------------|--------------|-------------|-------------|------------|------------|
+ | MCP47FVB11 | | 1 | 1 | RAM | I2C |
+ | MCP47FVB12 | | 2 | 1 | RAM | I2C |
+ | MCP47FVB14 | | 4 | 2 | RAM | I2C |
+ | MCP47FVB18 | 10-bit | 8 | 2 | RAM | I2C |
+ | MCP48FVB11 | | 1 | 1 | RAM | SPI |
+ | MCP48FVB12 | | 2 | 1 | RAM | SPI |
+ | MCP48FVB14 | | 4 | 2 | RAM | SPI |
+ | MCP48FVB18 | | 8 | 2 | RAM | SPI |
+ |------------|--------------|-------------|-------------|------------|------------|
+ | MCP47FVB21 | | 1 | 1 | RAM | I2C |
+ | MCP47FVB22 | | 2 | 1 | RAM | I2C |
+ | MCP47FVB24 | | 4 | 2 | RAM | I2C |
+ | MCP47FVB28 | 12-bit | 8 | 2 | RAM | I2C |
+ | MCP48FVB21 | | 1 | 1 | RAM | SPI |
+ | MCP48FVB22 | | 2 | 1 | RAM | SPI |
+ | MCP48FVB24 | | 4 | 2 | RAM | SPI |
+ | MCP48FVB28 | | 8 | 2 | RAM | SPI |
+ +------------+--------------+-------------+-------------+------------+------------+
properties:
compatible:
@@ -84,10 +118,37 @@ properties:
- microchip,mcp47feb08
- microchip,mcp47feb18
- microchip,mcp47feb28
+ - microchip,mcp48feb01
+ - microchip,mcp48feb02
+ - microchip,mcp48feb04
+ - microchip,mcp48feb08
+ - microchip,mcp48feb11
+ - microchip,mcp48feb12
+ - microchip,mcp48feb14
+ - microchip,mcp48feb18
+ - microchip,mcp48feb21
+ - microchip,mcp48feb22
+ - microchip,mcp48feb24
+ - microchip,mcp48feb28
+ - microchip,mcp48fvb01
+ - microchip,mcp48fvb02
+ - microchip,mcp48fvb04
+ - microchip,mcp48fvb08
+ - microchip,mcp48fvb11
+ - microchip,mcp48fvb12
+ - microchip,mcp48fvb14
+ - microchip,mcp48fvb18
+ - microchip,mcp48fvb21
+ - microchip,mcp48fvb22
+ - microchip,mcp48fvb24
+ - microchip,mcp48fvb28
reg:
maxItems: 1
+ spi-max-frequency:
+ maximum: 10000000
+
"#address-cells":
const: 1
@@ -178,6 +239,21 @@ required:
- vdd-supply
allOf:
+ - if:
+ properties:
+ compatible:
+ contains:
+ pattern: "^microchip,mcp48f[ev]b[0-2][1248]$"
+ then:
+ $ref: /schemas/spi/spi-peripheral-props.yaml#
+ dependencies:
+ spi-cpha: [ spi-cpol ]
+ spi-cpol: [ spi-cpha ]
+ else:
+ properties:
+ spi-max-frequency: false
+ spi-cpha: false
+ spi-cpol: false
- if:
properties:
compatible:
@@ -189,6 +265,12 @@ allOf:
- microchip,mcp47fvb01
- microchip,mcp47fvb11
- microchip,mcp47fvb21
+ - microchip,mcp48feb01
+ - microchip,mcp48feb11
+ - microchip,mcp48feb21
+ - microchip,mcp48fvb01
+ - microchip,mcp48fvb11
+ - microchip,mcp48fvb21
then:
properties:
lat1-gpios: false
@@ -211,6 +293,12 @@ allOf:
- microchip,mcp47fvb02
- microchip,mcp47fvb12
- microchip,mcp47fvb22
+ - microchip,mcp48feb02
+ - microchip,mcp48feb12
+ - microchip,mcp48feb22
+ - microchip,mcp48fvb02
+ - microchip,mcp48fvb12
+ - microchip,mcp48fvb22
then:
properties:
lat1-gpios: false
@@ -233,6 +321,12 @@ allOf:
- microchip,mcp47feb04
- microchip,mcp47feb14
- microchip,mcp47feb24
+ - microchip,mcp48feb04
+ - microchip,mcp48feb14
+ - microchip,mcp48feb24
+ - microchip,mcp48fvb04
+ - microchip,mcp48fvb14
+ - microchip,mcp48fvb24
then:
patternProperties:
"^channel@[0-3]$":
@@ -251,6 +345,12 @@ allOf:
- microchip,mcp47feb08
- microchip,mcp47feb18
- microchip,mcp47feb28
+ - microchip,mcp48feb08
+ - microchip,mcp48feb18
+ - microchip,mcp48feb28
+ - microchip,mcp48fvb08
+ - microchip,mcp48fvb18
+ - microchip,mcp48fvb28
then:
patternProperties:
"^channel@[0-7]$":
@@ -272,7 +372,7 @@ allOf:
properties:
microchip,vref1-buffered: false
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
@@ -299,4 +399,29 @@ examples:
};
};
};
+ - |
+ spi {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ dac@0 {
+ compatible = "microchip,mcp48feb02";
+ reg = <0x0>;
+ vdd-supply = <&vdac_vdd>;
+ vref-supply = <&vref_reg>;
+ spi-max-frequency = <10000000>;
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+ channel@0 {
+ reg = <0>;
+ label = "Adjustable_voltage_ch0";
+ };
+
+ channel@1 {
+ reg = <0x1>;
+ label = "Adjustable_voltage_ch1";
+ };
+ };
+ };
...
--
2.43.0
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH v6 11/11] iio: dac: add support for Microchip MCP48FEB02
2026-09-16 14:16 [PATCH v6 00/11] Refactor Microchip MCP47FEB02 I2C driver in separate modules to add support for MCP48FEB02 SPI driver Ariana Lazar
` (9 preceding siblings ...)
2026-09-16 14:16 ` [PATCH v6 10/11] dt-bindings: iio: dac: add support for MCP48FEB02 SPI Ariana Lazar
@ 2026-09-16 14:16 ` Ariana Lazar
2026-09-16 15:26 ` [PATCH v6 00/11] Refactor Microchip MCP47FEB02 I2C driver in separate modules to add support for MCP48FEB02 SPI driver Andy Shevchenko
11 siblings, 0 replies; 17+ messages in thread
From: Ariana Lazar @ 2026-09-16 14:16 UTC (permalink / raw)
To: Jonathan Cameron, David Lechner, Nuno Sá,
Andy Shevchenko, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: linux-kernel, linux-iio, devicetree, Ariana Lazar, Jonathan Cameron
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.
Signed-off-by: Ariana Lazar <ariana.lazar@microchip.com>
---
drivers/iio/dac/Kconfig | 23 +++++++
drivers/iio/dac/Makefile | 1 +
drivers/iio/dac/mcp47feb02-spi.c | 145 +++++++++++++++++++++++++++++++++++++++
3 files changed, 169 insertions(+)
diff --git a/drivers/iio/dac/Kconfig b/drivers/iio/dac/Kconfig
index c99c32b229fb683d6407f30682f7ea6104984421..3e37db1f772a2ccf9c872d7e128766f342e13d6f 100644
--- a/drivers/iio/dac/Kconfig
+++ b/drivers/iio/dac/Kconfig
@@ -618,6 +618,29 @@ config MCP47FEB02_I2C
will be called mcp47feb02_i2c and you will also get
mcp47feb02_core for the core module.
+config MCP47FEB02_SPI
+ tristate "MCP48F(E/V)B01/02/04/08/11/12/14/18/21/22/24/28 SPI DAC driver"
+ depends on SPI
+ select REGMAP_SPI
+ select MCP47FEB02
+ help
+ Say yes here if you want to build the driver for the Microchip:
+ - 8-bit DAC:
+ MCP48FEB01, MCP48FEB02, MCP48FEB04, MCP48FEB08,
+ MCP48FVB01, MCP48FVB02, MCP48FVB04, MCP48FVB08
+ - 10-bit DAC:
+ MCP48FEB11, MCP48FEB12, MCP48FEB14, MCP48FEB18,
+ MCP48FVB11, MCP48FVB12, MCP48FVB14, MCP48FVB18
+ - 12-bit DAC:
+ MCP48FEB21, MCP48FEB22, MCP48FEB24, MCP48FEB28,
+ MCP48FVB21, MCP48FVB22, MCP48FVB24, MCP48FVB28
+ having 1 to 8 channels, 8/10/12-bit digital-to-analog converter
+ (DAC) with SPI interface.
+
+ To compile this driver as a module, choose M here: the module
+ will be called mcp47feb02_spi and you will also get
+ mcp47feb02_core for the core module.
+
config MCP4821
tristate "MCP4801/02/11/12/21/22 DAC driver"
depends on SPI
diff --git a/drivers/iio/dac/Makefile b/drivers/iio/dac/Makefile
index 6377a9c42d983f615a0aa4d36a0c3d3639c62951..b665ff638cdc6e6e8ee32521c9c12a9e3d192eef 100644
--- a/drivers/iio/dac/Makefile
+++ b/drivers/iio/dac/Makefile
@@ -58,6 +58,7 @@ obj-$(CONFIG_MCP4728) += mcp4728.o
obj-$(CONFIG_MCP47A1) += mcp47a1.o
obj-$(CONFIG_MCP47FEB02) += mcp47feb02-core.o
obj-$(CONFIG_MCP47FEB02_I2C) += mcp47feb02-i2c.o
+obj-$(CONFIG_MCP47FEB02_SPI) += mcp47feb02-spi.o
obj-$(CONFIG_MCP4821) += mcp4821.o
obj-$(CONFIG_MCP4922) += mcp4922.o
obj-$(CONFIG_STM32_DAC_CORE) += stm32-dac-core.o
diff --git a/drivers/iio/dac/mcp47feb02-spi.c b/drivers/iio/dac/mcp47feb02-spi.c
new file mode 100644
index 0000000000000000000000000000000000000000..974f8fe1b86e939e99e6b2a7d3d05f025a73aa67
--- /dev/null
+++ b/drivers/iio/dac/mcp47feb02-spi.c
@@ -0,0 +1,145 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * IIO driver for MCP48FEB02 Multi-Channel DAC with SPI interface
+ *
+ * Copyright (C) 2025-2026 Microchip Technology Inc. and its subsidiaries
+ *
+ * Author: Ariana Lazar <ariana.lazar@microchip.com>
+ *
+ * Datasheet links for devices with SPI interface:
+ * [MCP48FEBxx] https://ww1.microchip.com/downloads/aemDocuments/documents/OTH/ProductDocuments/DataSheets/20005429B.pdf
+ * [MCP48FVBxx] https://ww1.microchip.com/downloads/aemDocuments/documents/OTH/ProductDocuments/DataSheets/20005466A.pdf
+ * [MCP48FxBx4/8] https://ww1.microchip.com/downloads/aemDocuments/documents/MSLD/ProductDocuments/DataSheets/MCP48FXBX4-8-Family-Data-Sheet-DS20006362A.pdf
+ */
+#include <linux/dev_printk.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/pm.h>
+#include <linux/regmap.h>
+#include <linux/spi/spi.h>
+#include <linux/types.h>
+
+#include "mcp47feb02.h"
+
+/* Parts with EEPROM memory */
+MCP47FEB02_CHIP_INFO(mcp48feb01, 1, 8, false, true);
+MCP47FEB02_CHIP_INFO(mcp48feb02, 2, 8, false, true);
+MCP47FEB02_CHIP_INFO(mcp48feb04, 4, 8, true, true);
+MCP47FEB02_CHIP_INFO(mcp48feb08, 8, 8, true, true);
+MCP47FEB02_CHIP_INFO(mcp48feb11, 1, 10, false, true);
+MCP47FEB02_CHIP_INFO(mcp48feb12, 2, 10, false, true);
+MCP47FEB02_CHIP_INFO(mcp48feb14, 4, 10, true, true);
+MCP47FEB02_CHIP_INFO(mcp48feb18, 8, 10, true, true);
+MCP47FEB02_CHIP_INFO(mcp48feb21, 1, 12, false, true);
+MCP47FEB02_CHIP_INFO(mcp48feb22, 2, 12, false, true);
+MCP47FEB02_CHIP_INFO(mcp48feb24, 4, 12, true, true);
+MCP47FEB02_CHIP_INFO(mcp48feb28, 8, 12, true, true);
+
+/* Parts without EEPROM memory */
+MCP47FEB02_CHIP_INFO(mcp48fvb01, 1, 8, false, false);
+MCP47FEB02_CHIP_INFO(mcp48fvb02, 2, 8, false, false);
+MCP47FEB02_CHIP_INFO(mcp48fvb04, 4, 8, true, false);
+MCP47FEB02_CHIP_INFO(mcp48fvb08, 8, 8, true, false);
+MCP47FEB02_CHIP_INFO(mcp48fvb11, 1, 10, false, false);
+MCP47FEB02_CHIP_INFO(mcp48fvb12, 2, 10, false, false);
+MCP47FEB02_CHIP_INFO(mcp48fvb14, 4, 10, true, false);
+MCP47FEB02_CHIP_INFO(mcp48fvb18, 8, 10, true, false);
+MCP47FEB02_CHIP_INFO(mcp48fvb21, 1, 12, false, false);
+MCP47FEB02_CHIP_INFO(mcp48fvb22, 2, 12, false, false);
+MCP47FEB02_CHIP_INFO(mcp48fvb24, 4, 12, true, false);
+MCP47FEB02_CHIP_INFO(mcp48fvb28, 8, 12, true, false);
+
+static int mcp47feb02_spi_probe(struct spi_device *spi)
+{
+ const struct mcp47feb02_features *chip_features;
+ struct device *dev = &spi->dev;
+ struct regmap *regmap;
+
+ chip_features = spi_get_device_match_data(spi);
+ if (!chip_features)
+ return dev_err_probe(dev, -ENODATA, "No match data found\n");
+
+ if (chip_features->have_eeprom)
+ regmap = devm_regmap_init_spi(spi, &mcp47feb02_regmap_config);
+ else
+ regmap = devm_regmap_init_spi(spi, &mcp47fvb02_regmap_config);
+
+ if (IS_ERR(regmap))
+ return dev_err_probe(dev, PTR_ERR(regmap), "Error initializing SPI regmap\n");
+
+ return mcp47feb02_common_probe(chip_features, regmap);
+}
+
+static const struct spi_device_id mcp47feb02_spi_id[] = {
+ { .name = "mcp48feb01", .driver_data = (kernel_ulong_t)&mcp48feb01_chip_features },
+ { .name = "mcp48feb02", .driver_data = (kernel_ulong_t)&mcp48feb02_chip_features },
+ { .name = "mcp48feb04", .driver_data = (kernel_ulong_t)&mcp48feb04_chip_features },
+ { .name = "mcp48feb08", .driver_data = (kernel_ulong_t)&mcp48feb08_chip_features },
+ { .name = "mcp48feb11", .driver_data = (kernel_ulong_t)&mcp48feb11_chip_features },
+ { .name = "mcp48feb12", .driver_data = (kernel_ulong_t)&mcp48feb12_chip_features },
+ { .name = "mcp48feb14", .driver_data = (kernel_ulong_t)&mcp48feb14_chip_features },
+ { .name = "mcp48feb18", .driver_data = (kernel_ulong_t)&mcp48feb18_chip_features },
+ { .name = "mcp48feb21", .driver_data = (kernel_ulong_t)&mcp48feb21_chip_features },
+ { .name = "mcp48feb22", .driver_data = (kernel_ulong_t)&mcp48feb22_chip_features },
+ { .name = "mcp48feb24", .driver_data = (kernel_ulong_t)&mcp48feb24_chip_features },
+ { .name = "mcp48feb28", .driver_data = (kernel_ulong_t)&mcp48feb28_chip_features },
+ { .name = "mcp48fvb01", .driver_data = (kernel_ulong_t)&mcp48fvb01_chip_features },
+ { .name = "mcp48fvb02", .driver_data = (kernel_ulong_t)&mcp48fvb02_chip_features },
+ { .name = "mcp48fvb04", .driver_data = (kernel_ulong_t)&mcp48fvb04_chip_features },
+ { .name = "mcp48fvb08", .driver_data = (kernel_ulong_t)&mcp48fvb08_chip_features },
+ { .name = "mcp48fvb11", .driver_data = (kernel_ulong_t)&mcp48fvb11_chip_features },
+ { .name = "mcp48fvb12", .driver_data = (kernel_ulong_t)&mcp48fvb12_chip_features },
+ { .name = "mcp48fvb14", .driver_data = (kernel_ulong_t)&mcp48fvb14_chip_features },
+ { .name = "mcp48fvb18", .driver_data = (kernel_ulong_t)&mcp48fvb18_chip_features },
+ { .name = "mcp48fvb21", .driver_data = (kernel_ulong_t)&mcp48fvb21_chip_features },
+ { .name = "mcp48fvb22", .driver_data = (kernel_ulong_t)&mcp48fvb22_chip_features },
+ { .name = "mcp48fvb24", .driver_data = (kernel_ulong_t)&mcp48fvb24_chip_features },
+ { .name = "mcp48fvb28", .driver_data = (kernel_ulong_t)&mcp48fvb28_chip_features },
+ { }
+};
+MODULE_DEVICE_TABLE(spi, mcp47feb02_spi_id);
+
+static const struct of_device_id mcp47feb02_of_spi_match[] = {
+ { .compatible = "microchip,mcp48feb01", .data = &mcp48feb01_chip_features },
+ { .compatible = "microchip,mcp48feb02", .data = &mcp48feb02_chip_features },
+ { .compatible = "microchip,mcp48feb04", .data = &mcp48feb04_chip_features },
+ { .compatible = "microchip,mcp48feb08", .data = &mcp48feb08_chip_features },
+ { .compatible = "microchip,mcp48feb11", .data = &mcp48feb11_chip_features },
+ { .compatible = "microchip,mcp48feb12", .data = &mcp48feb12_chip_features },
+ { .compatible = "microchip,mcp48feb14", .data = &mcp48feb14_chip_features },
+ { .compatible = "microchip,mcp48feb18", .data = &mcp48feb18_chip_features },
+ { .compatible = "microchip,mcp48feb21", .data = &mcp48feb21_chip_features },
+ { .compatible = "microchip,mcp48feb22", .data = &mcp48feb22_chip_features },
+ { .compatible = "microchip,mcp48feb24", .data = &mcp48feb24_chip_features },
+ { .compatible = "microchip,mcp48feb28", .data = &mcp48feb28_chip_features },
+ { .compatible = "microchip,mcp48fvb01", .data = &mcp48fvb01_chip_features },
+ { .compatible = "microchip,mcp48fvb02", .data = &mcp48fvb02_chip_features },
+ { .compatible = "microchip,mcp48fvb04", .data = &mcp48fvb04_chip_features },
+ { .compatible = "microchip,mcp48fvb08", .data = &mcp48fvb08_chip_features },
+ { .compatible = "microchip,mcp48fvb11", .data = &mcp48fvb11_chip_features },
+ { .compatible = "microchip,mcp48fvb12", .data = &mcp48fvb12_chip_features },
+ { .compatible = "microchip,mcp48fvb14", .data = &mcp48fvb14_chip_features },
+ { .compatible = "microchip,mcp48fvb18", .data = &mcp48fvb18_chip_features },
+ { .compatible = "microchip,mcp48fvb21", .data = &mcp48fvb21_chip_features },
+ { .compatible = "microchip,mcp48fvb22", .data = &mcp48fvb22_chip_features },
+ { .compatible = "microchip,mcp48fvb24", .data = &mcp48fvb24_chip_features },
+ { .compatible = "microchip,mcp48fvb28", .data = &mcp48fvb28_chip_features },
+ { }
+};
+MODULE_DEVICE_TABLE(of, mcp47feb02_of_spi_match);
+
+static struct spi_driver mcp47feb02_spi_driver = {
+ .driver = {
+ .name = "mcp47feb02",
+ .of_match_table = mcp47feb02_of_spi_match,
+ .pm = pm_sleep_ptr(&mcp47feb02_pm_ops),
+ },
+ .probe = mcp47feb02_spi_probe,
+ .id_table = mcp47feb02_spi_id,
+};
+module_spi_driver(mcp47feb02_spi_driver);
+
+MODULE_AUTHOR("Ariana Lazar <ariana.lazar@microchip.com>");
+MODULE_DESCRIPTION("IIO driver for MCP48FEB02 Multi-Channel DAC with SPI interface");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("IIO_MCP47FEB02");
--
2.43.0
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH v6 03/11] iio: dac: mcp47feb02: use field_get() instead of custom dynamic macros
2026-09-16 14:16 ` [PATCH v6 03/11] iio: dac: mcp47feb02: use field_get() instead of custom dynamic macros Ariana Lazar
@ 2026-09-16 15:22 ` Andy Shevchenko
0 siblings, 0 replies; 17+ messages in thread
From: Andy Shevchenko @ 2026-09-16 15:22 UTC (permalink / raw)
To: Ariana Lazar
Cc: Jonathan Cameron, David Lechner, Nuno Sá,
Andy Shevchenko, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
linux-kernel, linux-iio, devicetree
On Wed, Sep 16, 2026 at 05:16:29PM +0300, Ariana Lazar wrote:
> Replace manual bit operations which select channel corresponding bits
> from a control register in mcp47feb02_init_ctrl_regs() with field_get()
> macro used with masks already defined for regmap operations within the
> driver.
> Reported-by: Jonathan Cameron <jic23@kernel.org>
If it's a fix then better to add a Fixes tag, otherwise I would use Suggested-by.
> Link: https://lore.kernel.org/all/20260913224339.490d89ba@jic23-hlaptop/
Again, if it's a fix, this should be Closes:.
> Signed-off-by: Ariana Lazar <ariana.lazar@microchip.com>
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH v6 00/11] Refactor Microchip MCP47FEB02 I2C driver in separate modules to add support for MCP48FEB02 SPI driver
2026-09-16 14:16 [PATCH v6 00/11] Refactor Microchip MCP47FEB02 I2C driver in separate modules to add support for MCP48FEB02 SPI driver Ariana Lazar
` (10 preceding siblings ...)
2026-09-16 14:16 ` [PATCH v6 11/11] iio: dac: add support for Microchip MCP48FEB02 Ariana Lazar
@ 2026-09-16 15:26 ` Andy Shevchenko
2026-09-17 0:55 ` Jonathan Cameron
11 siblings, 1 reply; 17+ messages in thread
From: Andy Shevchenko @ 2026-09-16 15:26 UTC (permalink / raw)
To: Ariana Lazar
Cc: Jonathan Cameron, David Lechner, Nuno Sá,
Andy Shevchenko, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
linux-kernel, linux-iio, devicetree, sashiko-bot, stable,
Joshua Crofts
On Wed, Sep 16, 2026 at 05:16:26PM +0300, Ariana Lazar wrote:
> Refactor I2C driver implementation into separate modules in order to add
> support for SPI MCP48FxBy1/2/4/8 DAC family on top of the I2C
> implementation. The I2C and SPI devices have the same memory map and
> supported functionalities.
>
> Signed-off-by: Ariana Lazar <ariana.lazar@microchip.com>
> ---
> Changes in v6:
> - use field_get() in Gain, Vref and Power-Down registers channel formulas
> - rebase from 7.2 to 7.3-rc1
> - add fixes tags and Cc stable in the commit messages
> - add numeric constants in front of time defines for better readability
> - replaced dev_err() with dev_warn_probe() for missing label
> - if match data is not found at probe, return -ENODATA and a suitable
> error message
> - Link to v5: https://lore.kernel.org/r/20260909-mcp47feb02_refactor-v5-0-8b67bcab93d1@microchip.com
My main comment against this version is the usage of Reported-by + Closes +
Fixes versus Suggested-by. Note, some of the changes doesn't look like a fix,
such as a typo in the comment, I dunno if Reported + Closes (no Fixes) is
legitimate approach there.
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH v6 07/11] iio: dac: mcp47feb02: correct typo from a comment
2026-09-16 14:16 ` [PATCH v6 07/11] iio: dac: mcp47feb02: correct typo from a comment Ariana Lazar
@ 2026-09-16 15:49 ` Joshua Crofts
0 siblings, 0 replies; 17+ messages in thread
From: Joshua Crofts @ 2026-09-16 15:49 UTC (permalink / raw)
To: Ariana Lazar
Cc: Jonathan Cameron, David Lechner, Nuno Sá,
Andy Shevchenko, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
linux-kernel, linux-iio, devicetree
On Wed, 16 Sept 2026 at 16:19, Ariana Lazar <ariana.lazar@microchip.com> wrote:
>
> Typo corrected to 'Register' in the comment regarding defined masks for the
> gain register.
>
> Reported-by: Joshua Crofts <joshua.crofts1@gmail.com>
> Link: https://lore.kernel.org/all/20260723231859.03f92ce6@systembl0wer/
> Signed-off-by: Ariana Lazar <ariana.lazar@microchip.com>
I agree with what Andy said on the cover letter, Suggested-by is better in these
cases.
--
Kind regards,
Joshua Crofts
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH v6 08/11] iio: dac: mcp47feb02: rename channel mask and value macros
2026-09-16 14:16 ` [PATCH v6 08/11] iio: dac: mcp47feb02: rename channel mask and value macros Ariana Lazar
@ 2026-09-17 0:53 ` Jonathan Cameron
0 siblings, 0 replies; 17+ messages in thread
From: Jonathan Cameron @ 2026-09-17 0:53 UTC (permalink / raw)
To: Ariana Lazar
Cc: David Lechner, Nuno Sá,
Andy Shevchenko, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
linux-kernel, linux-iio, devicetree
On Wed, 16 Sep 2026 17:16:34 +0300
Ariana Lazar <ariana.lazar@microchip.com> wrote:
> Rename generic DAC_CTRL_MASK/VAL macros to MCP47FEB02_VREF_PD_MASK/VAL
> in order to clearly indicate for which control registers these channel
> masks are suitable.
>
> Reported-by: Jonathan Cameron <jic23@kernel.org>
> Link: https://lore.kernel.org/all/20260528125140.16a8f173@jic23-huawei/
> Signed-off-by: Ariana Lazar <ariana.lazar@microchip.com>
> ---
> drivers/iio/dac/mcp47feb02.c | 23 +++++++++++++----------
> 1 file changed, 13 insertions(+), 10 deletions(-)
>
> diff --git a/drivers/iio/dac/mcp47feb02.c b/drivers/iio/dac/mcp47feb02.c
> index 8dac4e2fb74fe4563324343ce215af3389129130..5c09ca25a75e0ecb2bfc5a2d5e62e5f7d3156810 100644
> --- a/drivers/iio/dac/mcp47feb02.c
> +++ b/drivers/iio/dac/mcp47feb02.c
> @@ -49,8 +49,8 @@
> #define MCP47FEB02_NV_I2C_SLAVE_ADDR_MASK GENMASK(7, 0)
>
> /* Voltage reference, Power-Down control register and DAC Wiperlock status register fields */
> -#define DAC_CTRL_MASK(ch) (GENMASK(1, 0) << (2 * (ch)))
> -#define DAC_CTRL_VAL(ch, val) ((val) << (2 * (ch)))
> +#define MCP47FEB02_VREF_PD_MASK(ch) (GENMASK(1, 0) << (2 * (ch)))
> +#define MCP47FEB02_VREF_PD_VAL(ch, val) ((val) << (2 * (ch)))
Can we drop this one...
>
> /* Gain Control and I2C Slave Address Register fields */
> #define DAC_GAIN_MASK(ch) (BIT(0) << (8 + (ch)))
> @@ -555,7 +555,8 @@ static int mcp47feb02_suspend(struct device *dev)
> data->chdata[ch].powerdown = true;
> pd_mode = data->chdata[ch].powerdown_mode + 1;
> ret = regmap_update_bits(data->regmap, MCP47FEB02_POWER_DOWN_REG_ADDR,
> - DAC_CTRL_MASK(ch), DAC_CTRL_VAL(ch, pd_mode));
> + MCP47FEB02_VREF_PD_MASK(ch),
> + MCP47FEB02_VREF_PD_VAL(ch, pd_mode));
.. and here have a local for mask.
mask = MCP47FEB02_VREF_PD_MASK(ch);
ret = regmap_update_bits(data->regmap, MCP47FEB02_POWER_DOWN_REG_ADDR,
mask, field_prep(mask, pd_mode));
Same in all the other cases. Will then match you do the field_get().
> if (ret)
> return ret;
>
> @@ -587,7 +588,8 @@ static int mcp47feb02_resume(struct device *dev)
> return ret;
>
> ret = regmap_update_bits(data->regmap, MCP47FEB02_VREF_REG_ADDR,
> - DAC_CTRL_MASK(ch), DAC_CTRL_VAL(ch, pd_mode));
> + MCP47FEB02_VREF_PD_MASK(ch),
> + MCP47FEB02_VREF_PD_VAL(ch, pd_mode));
> if (ret)
> return ret;
>
> @@ -598,8 +600,8 @@ static int mcp47feb02_resume(struct device *dev)
> return ret;
>
> ret = regmap_update_bits(data->regmap, MCP47FEB02_POWER_DOWN_REG_ADDR,
> - DAC_CTRL_MASK(ch),
> - DAC_CTRL_VAL(ch, MCP47FEB02_NORMAL_OPERATION));
> + MCP47FEB02_VREF_PD_MASK(ch),
> + MCP47FEB02_VREF_PD_VAL(ch, MCP47FEB02_NORMAL_OPERATION));
> if (ret)
> return ret;
> }
> @@ -656,7 +658,8 @@ static ssize_t mcp47feb02_write_powerdown(struct iio_dev *indio_dev, uintptr_t p
> */
> tmp_pd_mode = state ? (data->chdata[reg].powerdown_mode + 1) : MCP47FEB02_NORMAL_OPERATION;
> ret = regmap_update_bits(data->regmap, MCP47FEB02_POWER_DOWN_REG_ADDR,
> - DAC_CTRL_MASK(reg), DAC_CTRL_VAL(reg, tmp_pd_mode));
> + MCP47FEB02_VREF_PD_MASK(reg),
> + MCP47FEB02_VREF_PD_VAL(reg, tmp_pd_mode));
> if (ret)
> return ret;
>
> @@ -822,7 +825,7 @@ static int mcp47feb02_ch_scale(struct mcp47feb02_data *data, int ch, int scale)
> }
>
> ret = regmap_update_bits(data->regmap, MCP47FEB02_VREF_REG_ADDR,
> - DAC_CTRL_MASK(ch), DAC_CTRL_VAL(ch, tmp_val));
> + MCP47FEB02_VREF_PD_MASK(ch), MCP47FEB02_VREF_PD_VAL(ch, tmp_val));
> if (ret)
> return ret;
>
> @@ -1027,7 +1030,7 @@ static int mcp47feb02_init_ctrl_regs(struct mcp47feb02_data *data)
> return ret;
> data->chdata[i].dac_data = dac_val;
>
> - data->chdata[i].ref_mode = field_get(DAC_CTRL_MASK(i), vref_ch);
> + data->chdata[i].ref_mode = field_get(MCP47FEB02_VREF_PD_MASK(i), vref_ch);
> data->chdata[i].use_2x_gain = field_get(DAC_GAIN_MASK(i), gain_ch);
>
> /*
> @@ -1071,7 +1074,7 @@ static int mcp47feb02_init_ctrl_regs(struct mcp47feb02_data *data)
> break;
> }
>
> - pd_tmp = field_get(DAC_CTRL_MASK(i), pd_ch);
> + pd_tmp = field_get(MCP47FEB02_VREF_PD_MASK(i), pd_ch);
> data->chdata[i].powerdown_mode = pd_tmp ? (pd_tmp - 1) : pd_tmp;
> data->chdata[i].powerdown = !!(data->chdata[i].powerdown_mode);
> }
>
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH v6 00/11] Refactor Microchip MCP47FEB02 I2C driver in separate modules to add support for MCP48FEB02 SPI driver
2026-09-16 15:26 ` [PATCH v6 00/11] Refactor Microchip MCP47FEB02 I2C driver in separate modules to add support for MCP48FEB02 SPI driver Andy Shevchenko
@ 2026-09-17 0:55 ` Jonathan Cameron
0 siblings, 0 replies; 17+ messages in thread
From: Jonathan Cameron @ 2026-09-17 0:55 UTC (permalink / raw)
To: Andy Shevchenko
Cc: Ariana Lazar, David Lechner, Nuno Sá,
Andy Shevchenko, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
linux-kernel, linux-iio, devicetree, sashiko-bot, stable,
Joshua Crofts
On Wed, 16 Sep 2026 18:26:07 +0300
Andy Shevchenko <andriy.shevchenko@intel.com> wrote:
> On Wed, Sep 16, 2026 at 05:16:26PM +0300, Ariana Lazar wrote:
> > Refactor I2C driver implementation into separate modules in order to add
> > support for SPI MCP48FxBy1/2/4/8 DAC family on top of the I2C
> > implementation. The I2C and SPI devices have the same memory map and
> > supported functionalities.
> >
> > Signed-off-by: Ariana Lazar <ariana.lazar@microchip.com>
> > ---
> > Changes in v6:
> > - use field_get() in Gain, Vref and Power-Down registers channel formulas
> > - rebase from 7.2 to 7.3-rc1
> > - add fixes tags and Cc stable in the commit messages
> > - add numeric constants in front of time defines for better readability
> > - replaced dev_err() with dev_warn_probe() for missing label
> > - if match data is not found at probe, return -ENODATA and a suitable
> > error message
> > - Link to v5: https://lore.kernel.org/r/20260909-mcp47feb02_refactor-v5-0-8b67bcab93d1@microchip.com
>
> My main comment against this version is the usage of Reported-by + Closes +
> Fixes versus Suggested-by. Note, some of the changes doesn't look like a fix,
> such as a typo in the comment, I dunno if Reported + Closes (no Fixes) is
> legitimate approach there.
>
Other than that one minor thing I raised around field_prep() I think only
need to sort out those tags. Given that it is probably near to merge,
feel free to send a v7 a little quicker than normal.
Jonathan
^ permalink raw reply [flat|nested] 17+ messages in thread
end of thread, other threads:[~2026-09-17 0:55 UTC | newest]
Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-16 14:16 [PATCH v6 00/11] Refactor Microchip MCP47FEB02 I2C driver in separate modules to add support for MCP48FEB02 SPI driver Ariana Lazar
2026-09-16 14:16 ` [PATCH v6 01/11] iio: dac: mcp47feb02: initialize dac_data field in channel data struct at probe Ariana Lazar
2026-09-16 14:16 ` [PATCH v6 02/11] iio: dac: mcp47feb02: Fix gain field initialization for active channels Ariana Lazar
2026-09-16 14:16 ` [PATCH v6 03/11] iio: dac: mcp47feb02: use field_get() instead of custom dynamic macros Ariana Lazar
2026-09-16 15:22 ` Andy Shevchenko
2026-09-16 14:16 ` [PATCH v6 04/11] iio: dac: mcp47feb02: Return len when disabling EEPROM store Ariana Lazar
2026-09-16 14:16 ` [PATCH v6 05/11] iio: dac: mcp47feb02: Increase EEPROM Programming Write Cycle Time Ariana Lazar
2026-09-16 14:16 ` [PATCH v6 06/11] iio: dac: mcp47feb02: Avoid unjustified probe error on missing label Ariana Lazar
2026-09-16 14:16 ` [PATCH v6 07/11] iio: dac: mcp47feb02: correct typo from a comment Ariana Lazar
2026-09-16 15:49 ` Joshua Crofts
2026-09-16 14:16 ` [PATCH v6 08/11] iio: dac: mcp47feb02: rename channel mask and value macros Ariana Lazar
2026-09-17 0:53 ` Jonathan Cameron
2026-09-16 14:16 ` [PATCH v6 09/11] iio: dac: mcp47feb02: refactor MCP47FEB02 I2C driver into two modules Ariana Lazar
2026-09-16 14:16 ` [PATCH v6 10/11] dt-bindings: iio: dac: add support for MCP48FEB02 SPI Ariana Lazar
2026-09-16 14:16 ` [PATCH v6 11/11] iio: dac: add support for Microchip MCP48FEB02 Ariana Lazar
2026-09-16 15:26 ` [PATCH v6 00/11] Refactor Microchip MCP47FEB02 I2C driver in separate modules to add support for MCP48FEB02 SPI driver Andy Shevchenko
2026-09-17 0:55 ` Jonathan Cameron
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®