Re: [PATCH 10/10] iio: dac: add mcf54415 DAC

Andy Shevchenko
2026-05-05T08:45:14Z

On Mon, May 04, 2026 at 07:16:48PM +0200, Angelo Dureghello wrote:

> 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. DAC_VREFL and DAC_VREFH defaults respectivley to
> 0 and 0xfff.
>
> 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.

The below doesn't make much sense in the commit message (author must contribute
the tested code), but for the record in the comments block it might be useful
when one digs the lore ML archives.

> Basic tests done on stmark2 mcf54415-based board, voltage check on DAC0:
>
> /sys/bus/iio/devices/iio:device0 # ls
> name out_voltage_raw subsystem
> out_conversion_mode out_voltage_scale uevent
>
> /sys/bus/iio/devices/iio:device0 # cat name
> mcf54415_dac.0
>
> /sys/bus/iio/devices/iio:device0 #
>
> echo 4095 > out_voltage_raw => voltage abt 3.3V by oscilloscope
> echo 4096 > out_voltage_raw => roll over to 0V
> echo 0 > out_voltage_raw => voltage is 0V
> echo 2048 > out_voltage_raw => voltage is abt 1.7V, mid scale
>
> Same behavior for /sys/bus/iio/devices/iio:device1.
>
> Generated a sine wave by shell script, sine shape is good.

^^^ See above.

> Signed-off-by: Angelo Dureghello <adureghello@baylibre.com>
> ---

Put that here.

...

> +#include <linux/bitfield.h>
> +#include <linux/bits.h>
> +#include <linux/clk.h>
> +#include <linux/delay.h>
> +#include <linux/io.h>
> +#include <linux/module.h>
> +#include <linux/mutex.h>
> +#include <linux/platform_device.h>

Follow IWYU. At least the headers for __iomem, ARRAY_SIZE() are missing.

...

> + int val;

Why signed?

> + /* Keeping defaults and enable DAC (bit 0 set to 0) */
> + val = MCF54415_DAC_CR_FILT;
> + val |= FIELD_PREP(MCF54415_DAC_CR_WMLVL, 1);

Why two lines?

val = MCF54415_DAC_CR_FILT | FIELD_PREP(MCF54415_DAC_CR_WMLVL, 1);

even fits 80 limit.

> + writew(val, info->regs + MCF54415_DAC_CR);
> +
> + /* DAC is ready after 12us, from RM table 40-3 */
> + fsleep(MCF54415_DAC_READY_US);

...

> +#define MCF54415_DAC_CHAN { \

Move { to a separate line.

> + .type = IIO_VOLTAGE, \
> + .output = 1, \
> + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
> + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
> +}

...

> +static const struct iio_chan_spec mcf54415_dac_iio_channels[] = {
> + MCF54415_DAC_CHAN

Use trailing commas when it's not a terminator.

> +};

...

> +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);
> +
> + switch (mask) {
> + case IIO_CHAN_INFO_RAW:
> + *val = readw(info->regs + MCF54415_DAC_DATA);
> + 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;
> + }

> + return 0;

Dead code.

> +}

...

> +static int mcf54415_write_raw(struct iio_dev *indio_dev,
> + struct iio_chan_spec const *chan,

> + int val, int val2,
> + long mask)

One line.

> +{
> + struct mcf54415_dac *info = iio_priv(indio_dev);
> +
> + switch (mask) {
> + case IIO_CHAN_INFO_RAW:
> + writew(val, info->regs + MCF54415_DAC_DATA);
> + return 0;

> +

Already mentioned: Stray blank line.

> + default:
> + return -EINVAL;
> + }
> +}

...

> + indio_dev = devm_iio_device_alloc(&pdev->dev,
> + sizeof(struct mcf54415_dac));

Use

struct device *dev = &pdev->dev;

to make it neater. Also it's more robust to use sizeof(*).

indio_dev = devm_iio_device_alloc(dev, sizeof(*info));

> + if (!indio_dev)
> + return -ENOMEM;

...

> +static DEFINE_SIMPLE_DEV_PM_OPS(mcf54415_dac_pm_ops, mcf54415_dac_suspend,
> + mcf54415_dac_resume);

Use logical split:

static DEFINE_SIMPLE_DEV_PM_OPS(mcf54415_dac_pm_ops,
mcf54415_dac_suspend,
mcf54415_dac_resume);

OR

static DEFINE_SIMPLE_DEV_PM_OPS(mcf54415_dac_pm_ops,
mcf54415_dac_suspend, mcf54415_dac_resume);

--
With Best Regards,
Andy Shevchenko