Re: [PATCH v4 11/11] iio: dac: add mcf54415 DAC

From: Jonathan Cameron

Date: Sun May 31 2026 - 12:38:02 EST


On Sun, 31 May 2026 17:26:04 +0200
Angelo Dureghello <adureghello@xxxxxxxxxxxx> wrote:

> From: Angelo Dureghello <adureghello@xxxxxxxxxxxx>
>
> Add basic version of mcf54415 DAC driver. DAC is embedded in the cpu and
> DAC configuration registers are mapped in the internal IO address space.
>
> The DAC accepts a 12-bit digital signal and creates a monotonic 12-bit
> analog output varying from DAC_VREFL to DAC_VREFH. The DAC module
> consists of a conversion unit, an output amplifier, and the associated
> digital control blocks. Default register values for DAC_VREFL and DAC_VREFH
> are respectively 0 and 0xfff, left untouched in this initial version.
>
> This initial version of the driver is minimalistic, "output raw" only, to
> be extended in the future. DMA and external sync are disabled, default mode
> is high speed, default format is right-justified 12bit on 16bit word.
>
> Signed-off-by: Angelo Dureghello <adureghello@xxxxxxxxxxxx>
https://sashiko.dev/#/patchset/20260531-wip-stmark2-dac-v4-0-7e65ab4215dd%40baylibre.com
Has some comments.

My assumption is the DAC registers are not going to be wiped out by
reset, so that one is wrong.

For the others they are the fun question of what do we do if resume()
fails and leaves the device effectively disabled. I'm not that bothered
if the answer is everything fails.

So just really minor stuff inline.

> ---
> Changes in v2:
> - remove tests from commit message, moved to patch 0
> - remove additional blank lines
> - remove dead code and unused definitions
> - use regmap
> - add limit check on raw write
> - non functional style fixes
> - add COMPILE_TEST to Kconfig
> Changes in v3:
> - add comments where needed
> - code style changes
> - remove unneeded variables
> - use regmap_set_bits where possible
> - remove macro not needed to define a single channel
> - set up regmap to big_endian accesses for next patches that will come,
> that will adjust ColdFire readx/writex as standard LE (links in 0/x).
> - add return value check on regmap calls
> - sashiko: remove unneeded .io_port from regmap init.
> - sashiko: add select REGMAP_MMIO in Kconfig
> Changes in v4:
> - remove unused includes
> - sashiko: return "ret" as regmap_read ret value in case of error
> - sashiko: using u32 as regmap_read value
> - use local variable in mcf54415_dac_init() for better readability
> - sashiko: check mcf54415_dac_init return value also in resume()

> diff --git a/drivers/iio/dac/mcf54415_dac.c b/drivers/iio/dac/mcf54415_dac.c
> new file mode 100644
> index 000000000000..474a2c327fcd
> --- /dev/null
> +++ b/drivers/iio/dac/mcf54415_dac.c

> +
> +static int mcf54415_read_raw(struct iio_dev *indio_dev,
> + struct iio_chan_spec const *chan,
> + int *val, int *val2, long mask)
> +{
> + struct mcf54415_dac *info = iio_priv(indio_dev);
> + int ret;
> + u32 reg;
> +
> + switch (mask) {
> + case IIO_CHAN_INFO_RAW:
> + ret = regmap_read(info->map, MCF54415_DAC_DATA, &reg);
> + if (ret)
> + return ret;
> + *val = (int)reg & 0xfff;

Given it's unsigned and the masking means it will fit, I don't see an
obvious reason for needing the cast. Compiler should be able to tell it
can always safely assign this. Maybe GENMASK(11, 0) would be slightly
nicer than 0xfff but up to you as 3 fs isn't easy to count ;)

> + return IIO_VAL_INT;
> + case IIO_CHAN_INFO_SCALE:
> + /* Reference voltage as per ColdFire datasheet is 3.3V */
> + *val = 3300 /* mV */;
> + *val2 = 12;
> + return IIO_VAL_FRACTIONAL_LOG2;
> + default:
> + return -EINVAL;
> + }
> +}

> +
> +static int mcf54415_dac_suspend(struct device *dev)
> +{
> + struct mcf54415_dac *info = iio_priv(dev_get_drvdata(dev));
> +
> + mcf54415_dac_exit(info);
> + clk_disable_unprepare(info->clk);
> +
> + return 0;
> +}
> +
> +static int mcf54415_dac_resume(struct device *dev)
> +{
> + struct mcf54415_dac *info = iio_priv(dev_get_drvdata(dev));
> + int ret;
> +
> + ret = clk_prepare_enable(info->clk);
> + if (ret)
> + return ret;
> +
> + ret = mcf54415_dac_init(info);
> + if (ret) {

Generally we aim for side effect free failure, so I think I agree
with sashiko that you should be turning off the clk again here.
Any failure in here should leave device suspended. That then leaves
us with a dead clock and the shut down path may still try to access
the device.

Anyhow, I'd add the clk_disable_unprepare() call here for consistency
even though it doesn't really help us with carrying on.

> + dev_err(dev, "could not resume device\n");
> + return ret;
> + }
> +
> + return 0;
> +
> +}
> +
> +static DEFINE_SIMPLE_DEV_PM_OPS(mcf54415_dac_pm_ops,
> + mcf54415_dac_suspend, mcf54415_dac_resume);
> +
> +static struct platform_driver mcf54415_dac_driver = {
> + .probe = mcf54415_dac_probe,
> + .driver = {
> + .name = "mcf54415_dac",
> + .pm = pm_sleep_ptr(&mcf54415_dac_pm_ops),
> + },
> +};
> +module_platform_driver(mcf54415_dac_driver);
> +
> +MODULE_AUTHOR("Angelo Dureghello <angelo@xxxxxxxxxxxxxxxx>");
> +MODULE_DESCRIPTION("NXP MCF54415 DAC driver");
> +MODULE_LICENSE("GPL");
>