* [PATCH v8 0/5] Refactor Microchip MCP47FEB02 I2C driver in separate modules to add support for MCP48FEB02 SPI driver
@ 2026-09-24 12:59 Ariana Lazar
2026-09-24 12:59 ` [PATCH v8 1/5] iio: dac: mcp47feb02: Avoid unjustified probe error on missing label Ariana Lazar
` (4 more replies)
0 siblings, 5 replies; 7+ messages in thread
From: Ariana Lazar @ 2026-09-24 12:59 UTC (permalink / raw)
To: Jonathan Cameron, David Lechner, Nuno Sá,
Andy Shevchenko, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: linux-iio, linux-kernel, devicetree, Ariana Lazar,
Jonathan Cameron, sashiko-bot, stable
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 v8:
- create a new precursor patch for moving mutex in store_eeprom_store()
- add property present check for label before reading
- use EXPORT_NS_SIMPLE_DEV_PM_OPS() instead of EXPORT_SIMPLE_DEV_PM_OPS()
- base this version on testing branch in order to send just remaining
patches to be accepted
- Link to v7: https://lore.kernel.org/r/20260918-mcp47feb02_refactor-v7-0-82ca794eafe2@microchip.com
Changes in v7:
- replace custom mask define with standard field_prep()
- use "Suggested-by" instead of "Reported-by" where it was more suitable
- use "Fixes:" with "Closes:" instead of "Link:" for fixes tags in commit
messages
- modified module description for core when adding support for SPI parts
in order to specify SPI families too
- remove unused macro MCP47FEB02_GAIN_BIT_MASK from the second commit
- Link to v6: https://lore.kernel.org/r/20260916-mcp47feb02_refactor-v6-0-285464651f89@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
Changes in 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 (5):
iio: dac: mcp47feb02: Avoid unjustified probe error on missing label
iio: dac: mcp47feb02: protect EEPROM store sequence with mutex
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} | 342 ++-------------------
drivers/iio/dac/mcp47feb02-i2c.c | 145 +++++++++
drivers/iio/dac/mcp47feb02-spi.c | 145 +++++++++
drivers/iio/dac/mcp47feb02.h | 43 +++
8 files changed, 573 insertions(+), 361 deletions(-)
---
base-commit: 81e043887112f846f88ef9ef20c744b5c815de57
change-id: 20260625-mcp47feb02_refactor-fa8420ae3282
Best regards,
--
Ariana Lazar <ariana.lazar@microchip.com>
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v8 1/5] iio: dac: mcp47feb02: Avoid unjustified probe error on missing label
2026-09-24 12:59 [PATCH v8 0/5] Refactor Microchip MCP47FEB02 I2C driver in separate modules to add support for MCP48FEB02 SPI driver Ariana Lazar
@ 2026-09-24 12:59 ` Ariana Lazar
2026-09-24 12:59 ` [PATCH v8 2/5] iio: dac: mcp47feb02: protect EEPROM store sequence with mutex Ariana Lazar
` (3 subsequent siblings)
4 siblings, 0 replies; 7+ messages in thread
From: Ariana Lazar @ 2026-09-24 12:59 UTC (permalink / raw)
To: Jonathan Cameron, David Lechner, Nuno Sá,
Andy Shevchenko, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: linux-iio, linux-kernel, 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
Closes: 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 | 14 +++++++++-----
1 file changed, 9 insertions(+), 5 deletions(-)
diff --git a/drivers/iio/dac/mcp47feb02.c b/drivers/iio/dac/mcp47feb02.c
index 3187a7d95ca8ce4aacf27efc588d9b33eb429aec..349574bc7489d9e5ac9722c3abbaaab0d2c3350e 100644
--- a/drivers/iio/dac/mcp47feb02.c
+++ b/drivers/iio/dac/mcp47feb02.c
@@ -929,7 +929,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 = {
@@ -982,10 +985,11 @@ static int mcp47feb02_parse_fw(struct iio_dev *indio_dev,
set_bit(reg, &data->active_channels_mask);
- 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));
+ if (fwnode_property_present(child, "label")) {
+ ret = fwnode_property_read_string(child, "label", &data->labels[reg]);
+ if (ret)
+ dev_warn_probe(dev, ret, "%pfw: invalid label\n", child);
+ }
chanspec.address = reg;
chanspec.channel = reg;
--
2.43.0
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v8 2/5] iio: dac: mcp47feb02: protect EEPROM store sequence with mutex
2026-09-24 12:59 [PATCH v8 0/5] Refactor Microchip MCP47FEB02 I2C driver in separate modules to add support for MCP48FEB02 SPI driver Ariana Lazar
2026-09-24 12:59 ` [PATCH v8 1/5] iio: dac: mcp47feb02: Avoid unjustified probe error on missing label Ariana Lazar
@ 2026-09-24 12:59 ` Ariana Lazar
2026-09-24 13:19 ` Joshua Crofts
2026-09-24 12:59 ` [PATCH v8 3/5] iio: dac: mcp47feb02: refactor MCP47FEB02 I2C driver into two modules Ariana Lazar
` (2 subsequent siblings)
4 siblings, 1 reply; 7+ messages in thread
From: Ariana Lazar @ 2026-09-24 12:59 UTC (permalink / raw)
To: Jonathan Cameron, David Lechner, Nuno Sá,
Andy Shevchenko, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: linux-iio, linux-kernel, devicetree, Ariana Lazar, Jonathan Cameron
Move the mutex lock into store_eeprom_store() to prevent race conditions
when reading volatile registers and writing them to the EEPROM.
Fixes: bf394cc80369 ("iio: dac: adding support for Microchip MCP47FEB02")
Closes: https://lore.kernel.org/all/20260819125128.970911F000E9@smtp.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 349574bc7489d9e5ac9722c3abbaaab0d2c3350e..8f8a67919cc2ecdb203ad350174bac2be1a307dc 100644
--- a/drivers/iio/dac/mcp47feb02.c
+++ b/drivers/iio/dac/mcp47feb02.c
@@ -440,8 +440,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),
@@ -467,6 +465,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.
--
2.43.0
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v8 3/5] iio: dac: mcp47feb02: refactor MCP47FEB02 I2C driver into two modules
2026-09-24 12:59 [PATCH v8 0/5] Refactor Microchip MCP47FEB02 I2C driver in separate modules to add support for MCP48FEB02 SPI driver Ariana Lazar
2026-09-24 12:59 ` [PATCH v8 1/5] iio: dac: mcp47feb02: Avoid unjustified probe error on missing label Ariana Lazar
2026-09-24 12:59 ` [PATCH v8 2/5] iio: dac: mcp47feb02: protect EEPROM store sequence with mutex Ariana Lazar
@ 2026-09-24 12:59 ` Ariana Lazar
2026-09-24 12:59 ` [PATCH v8 4/5] dt-bindings: iio: dac: add support for MCP48FEB02 SPI Ariana Lazar
2026-09-24 12:59 ` [PATCH v8 5/5] iio: dac: add support for Microchip MCP48FEB02 Ariana Lazar
4 siblings, 0 replies; 7+ messages in thread
From: Ariana Lazar @ 2026-09-24 12:59 UTC (permalink / raw)
To: Jonathan Cameron, David Lechner, Nuno Sá,
Andy Shevchenko, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: linux-iio, linux-kernel, 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} | 322 ++-------------------
drivers/iio/dac/mcp47feb02-i2c.c | 145 ++++++++++
drivers/iio/dac/mcp47feb02.h | 43 +++
6 files changed, 219 insertions(+), 305 deletions(-)
diff --git a/MAINTAINERS b/MAINTAINERS
index 2e98d052fbdcf43f70376fdb3a553e97bf91dc82..ecc22d1149d19ae7798ebd54c52b1b2486d1f9f1 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -16352,7 +16352,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 b6c8873c68c54d13f80ea7116bee1ac00f374574..8121a71945f63a23b35fcab010fda1d03d0afba0 100644
--- a/drivers/iio/dac/Kconfig
+++ b/drivers/iio/dac/Kconfig
@@ -611,9 +611,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:
@@ -629,7 +633,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 8dc644522b1e52152abacc32cacb6ee90881ef9a..4394278d9fd874b94ae2d680378fb3b043ac8672 100644
--- a/drivers/iio/dac/Makefile
+++ b/drivers/iio/dac/Makefile
@@ -57,7 +57,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 8f8a67919cc2ecdb203ad350174bac2be1a307dc..29d69cb2f68b5d7c6a615481bb1045aed468e9cf 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
@@ -82,220 +83,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
@@ -376,7 +169,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,
@@ -388,6 +181,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[] = {
@@ -418,7 +212,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,
@@ -430,6 +224,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)
@@ -575,12 +370,10 @@ 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;
u32 mask;
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)
@@ -588,7 +381,7 @@ static int mcp47feb02_resume(struct device *dev)
mask = MCP47FEB02_VREF_PD_MASK(ch);
ret = regmap_update_bits(data->regmap, MCP47FEB02_VREF_REG_ADDR,
- mask, field_prep(mask, pd_mode));
+ mask, field_prep(mask, data->chdata[ch].ref_mode));
if (ret)
return ret;
@@ -668,7 +461,8 @@ 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_NS_SIMPLE_DEV_PM_OPS(mcp47feb02_pm_ops, mcp47feb02_suspend,
+ mcp47feb02_resume, IIO_MCP47FEB02);
static const struct iio_enum mcp47febxx_powerdown_mode_enum = {
.items = mcp47feb02_powerdown_modes,
@@ -1105,10 +899,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;
@@ -1117,22 +911,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;
@@ -1189,75 +977,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] 7+ messages in thread
* [PATCH v8 4/5] dt-bindings: iio: dac: add support for MCP48FEB02 SPI
2026-09-24 12:59 [PATCH v8 0/5] Refactor Microchip MCP47FEB02 I2C driver in separate modules to add support for MCP48FEB02 SPI driver Ariana Lazar
` (2 preceding siblings ...)
2026-09-24 12:59 ` [PATCH v8 3/5] iio: dac: mcp47feb02: refactor MCP47FEB02 I2C driver into two modules Ariana Lazar
@ 2026-09-24 12:59 ` Ariana Lazar
2026-09-24 12:59 ` [PATCH v8 5/5] iio: dac: add support for Microchip MCP48FEB02 Ariana Lazar
4 siblings, 0 replies; 7+ messages in thread
From: Ariana Lazar @ 2026-09-24 12:59 UTC (permalink / raw)
To: Jonathan Cameron, David Lechner, Nuno Sá,
Andy Shevchenko, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: linux-iio, linux-kernel, 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] 7+ messages in thread
* [PATCH v8 5/5] iio: dac: add support for Microchip MCP48FEB02
2026-09-24 12:59 [PATCH v8 0/5] Refactor Microchip MCP47FEB02 I2C driver in separate modules to add support for MCP48FEB02 SPI driver Ariana Lazar
` (3 preceding siblings ...)
2026-09-24 12:59 ` [PATCH v8 4/5] dt-bindings: iio: dac: add support for MCP48FEB02 SPI Ariana Lazar
@ 2026-09-24 12:59 ` Ariana Lazar
4 siblings, 0 replies; 7+ messages in thread
From: Ariana Lazar @ 2026-09-24 12:59 UTC (permalink / raw)
To: Jonathan Cameron, David Lechner, Nuno Sá,
Andy Shevchenko, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: linux-iio, linux-kernel, 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-core.c | 2 +-
drivers/iio/dac/mcp47feb02-spi.c | 145 ++++++++++++++++++++++++++++++++++++++
4 files changed, 170 insertions(+), 1 deletion(-)
diff --git a/drivers/iio/dac/Kconfig b/drivers/iio/dac/Kconfig
index 8121a71945f63a23b35fcab010fda1d03d0afba0..e373885e7c7a13129f39fb8617763c8c2bf3ae74 100644
--- a/drivers/iio/dac/Kconfig
+++ b/drivers/iio/dac/Kconfig
@@ -636,6 +636,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 4394278d9fd874b94ae2d680378fb3b043ac8672..2cd0fe23db9e60245cbe515a99c5eaff60db3c6c 100644
--- a/drivers/iio/dac/Makefile
+++ b/drivers/iio/dac/Makefile
@@ -59,6 +59,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-core.c b/drivers/iio/dac/mcp47feb02-core.c
index 29d69cb2f68b5d7c6a615481bb1045aed468e9cf..06063d77739582faad3010202390aead1d5a0aa1 100644
--- a/drivers/iio/dac/mcp47feb02-core.c
+++ b/drivers/iio/dac/mcp47feb02-core.c
@@ -980,5 +980,5 @@ int mcp47feb02_common_probe(const struct mcp47feb02_features *chip_features,
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");
+MODULE_DESCRIPTION("IIO driver for MCP47FEB02/MCP48FEB02 Multi-Channel DAC");
MODULE_LICENSE("GPL");
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] 7+ messages in thread
* Re: [PATCH v8 2/5] iio: dac: mcp47feb02: protect EEPROM store sequence with mutex
2026-09-24 12:59 ` [PATCH v8 2/5] iio: dac: mcp47feb02: protect EEPROM store sequence with mutex Ariana Lazar
@ 2026-09-24 13:19 ` Joshua Crofts
0 siblings, 0 replies; 7+ messages in thread
From: Joshua Crofts @ 2026-09-24 13:19 UTC (permalink / raw)
To: Ariana Lazar
Cc: Jonathan Cameron, David Lechner, Nuno Sá,
Andy Shevchenko, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
linux-iio, linux-kernel, devicetree
On Thu, 24 Sep 2026 15:59:20 +0300
Ariana Lazar <ariana.lazar@microchip.com> wrote:
> Move the mutex lock into store_eeprom_store() to prevent race conditions
> when reading volatile registers and writing them to the EEPROM.
>
> Fixes: bf394cc80369 ("iio: dac: adding support for Microchip MCP47FEB02")
> Closes: https://lore.kernel.org/all/20260819125128.970911F000E9@smtp.kernel.org/
> Signed-off-by: Ariana Lazar <ariana.lazar@microchip.com>
> ---
You're missing a Reported-by tag for Sashiko, but perhaps Jonathan can
add it when applying.
Reviewed-by: Joshua Crofts <joshua.crofts1@gmail.com>
--
Kind regards,
Joshua Crofts
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2026-09-24 13:19 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-24 12:59 [PATCH v8 0/5] Refactor Microchip MCP47FEB02 I2C driver in separate modules to add support for MCP48FEB02 SPI driver Ariana Lazar
2026-09-24 12:59 ` [PATCH v8 1/5] iio: dac: mcp47feb02: Avoid unjustified probe error on missing label Ariana Lazar
2026-09-24 12:59 ` [PATCH v8 2/5] iio: dac: mcp47feb02: protect EEPROM store sequence with mutex Ariana Lazar
2026-09-24 13:19 ` Joshua Crofts
2026-09-24 12:59 ` [PATCH v8 3/5] iio: dac: mcp47feb02: refactor MCP47FEB02 I2C driver into two modules Ariana Lazar
2026-09-24 12:59 ` [PATCH v8 4/5] dt-bindings: iio: dac: add support for MCP48FEB02 SPI Ariana Lazar
2026-09-24 12:59 ` [PATCH v8 5/5] iio: dac: add support for Microchip MCP48FEB02 Ariana Lazar
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®