xref: /linux/drivers/iio/dac/mcf54415_dac.c (revision 3a2c4d55e32ad65efebdb6de44eef3bfa08bb49d)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * NXP mcf54415 DAC driver
4  *
5  * Copyright 2026 BayLibre - adureghello@baylibre.com
6  */
7 
8 #include <linux/bitfield.h>
9 #include <linux/bits.h>
10 #include <linux/clk.h>
11 #include <linux/delay.h>
12 #include <linux/err.h>
13 #include <linux/mod_devicetable.h>
14 #include <linux/module.h>
15 #include <linux/platform_device.h>
16 #include <linux/regmap.h>
17 #include <linux/types.h>
18 
19 #include <linux/iio/iio.h>
20 
21 #define MCF54415_DAC_CR			0x00
22 #define MCF54415_DAC_CR_PDN		BIT(0)
23 #define MCF54415_DAC_CR_HSLS		BIT(6)
24 #define MCF54415_DAC_CR_WMLVL		GENMASK(9, 8)
25 #define MCF54415_DAC_CR_FILT		BIT(12)
26 
27 #define MCF54415_DAC_DATA		0x02
28 
29 struct mcf54415_dac {
30 	struct regmap *map;
31 	struct clk *clk;
32 };
33 
34 static const struct regmap_config mcf54415_dac_regmap_config = {
35 	.reg_bits = 16,
36 	.reg_stride = 2,
37 	.val_bits = 16,
38 	.max_register = 0x0c, /* DACX_FILTCNT,  R.M. Table 30-2 */
39 	.val_format_endian = REGMAP_ENDIAN_BIG,
40 	.reg_format_endian = REGMAP_ENDIAN_BIG,
41 };
42 
43 static int mcf54415_dac_init(struct mcf54415_dac *info)
44 {
45 	u16 val = MCF54415_DAC_CR_FILT | FIELD_PREP(MCF54415_DAC_CR_WMLVL, 1);
46 	int ret;
47 
48 	/* Fixed defaults and enable DAC (bit 0 set to 0) */
49 	ret = regmap_write(info->map, MCF54415_DAC_CR, val);
50 	if (ret)
51 		return ret;
52 
53 	/* DAC is ready after 12us, from RM table 40-3  */
54 	fsleep(12);
55 
56 	return 0;
57 }
58 
59 static void mcf54415_dac_exit(void *data)
60 {
61 	struct mcf54415_dac *info = data;
62 
63 	regmap_set_bits(info->map, MCF54415_DAC_CR, MCF54415_DAC_CR_PDN);
64 }
65 
66 static const struct iio_chan_spec mcf54415_dac_iio_channel = {
67 	.type = IIO_VOLTAGE,
68 	.output = 1,
69 	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
70 	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
71 };
72 
73 static int mcf54415_read_raw(struct iio_dev *indio_dev,
74 			     struct iio_chan_spec const *chan,
75 			     int *val, int *val2, long mask)
76 {
77 	struct mcf54415_dac *info = iio_priv(indio_dev);
78 	unsigned int reg;
79 	int ret;
80 
81 	switch (mask) {
82 	case IIO_CHAN_INFO_RAW:
83 		ret = regmap_read(info->map, MCF54415_DAC_DATA, &reg);
84 		if (ret)
85 			return ret;
86 		*val = reg & GENMASK(11, 0);
87 		return IIO_VAL_INT;
88 	case IIO_CHAN_INFO_SCALE:
89 		/* Reference voltage as per ColdFire datasheet is 3.3V */
90 		*val = 3300 /* mV */;
91 		*val2 = 12;
92 		return IIO_VAL_FRACTIONAL_LOG2;
93 	default:
94 		return -EINVAL;
95 	}
96 }
97 
98 static int mcf54415_write_raw(struct iio_dev *indio_dev,
99 			      struct iio_chan_spec const *chan,
100 			      int val, int val2, long mask)
101 {
102 	struct mcf54415_dac *info = iio_priv(indio_dev);
103 
104 	switch (mask) {
105 	case IIO_CHAN_INFO_RAW:
106 		/* Check based on RM 30.3.2 (DACn_DATA) reg. resolution */
107 		if (val < 0 || val > 4095)
108 			return -EINVAL;
109 		return regmap_write(info->map, MCF54415_DAC_DATA, val);
110 	default:
111 		return -EINVAL;
112 	}
113 }
114 
115 static const struct iio_info mcf54415_dac_iio_info = {
116 	.read_raw = &mcf54415_read_raw,
117 	.write_raw = &mcf54415_write_raw,
118 };
119 
120 static int mcf54415_dac_probe(struct platform_device *pdev)
121 {
122 	struct device *dev = &pdev->dev;
123 	struct iio_dev *indio_dev;
124 	struct mcf54415_dac *info;
125 	void __iomem *regs;
126 	int ret;
127 
128 	indio_dev = devm_iio_device_alloc(dev, sizeof(*info));
129 	if (!indio_dev)
130 		return -ENOMEM;
131 
132 	info = iio_priv(indio_dev);
133 
134 	regs = devm_platform_ioremap_resource(pdev, 0);
135 	if (IS_ERR(regs))
136 		return dev_err_probe(dev, PTR_ERR(regs), "failed to get io regs\n");
137 
138 	info->map = devm_regmap_init_mmio(dev, regs, &mcf54415_dac_regmap_config);
139 	if (IS_ERR(info->map))
140 		return PTR_ERR(info->map);
141 
142 	info->clk = devm_clk_get_enabled(dev, "dac");
143 	if (IS_ERR(info->clk))
144 		return dev_err_probe(dev, PTR_ERR(info->clk), "failed getting clock\n");
145 
146 	indio_dev->name = "mcf54415";
147 	indio_dev->info = &mcf54415_dac_iio_info;
148 	indio_dev->modes = INDIO_DIRECT_MODE;
149 	indio_dev->channels = &mcf54415_dac_iio_channel;
150 	indio_dev->num_channels = 1;
151 
152 	ret = mcf54415_dac_init(info);
153 	if (ret)
154 		return ret;
155 
156 	ret = devm_add_action_or_reset(dev, mcf54415_dac_exit, info);
157 	if (ret)
158 		return ret;
159 
160 	return devm_iio_device_register(dev, indio_dev);
161 }
162 
163 static const struct platform_device_id mcf54415_dac_ids[] = {
164 	{ .name = "mcfdac" },
165 	{ }
166 };
167 MODULE_DEVICE_TABLE(platform, mcf54415_dac_ids);
168 
169 static struct platform_driver mcf54415_dac_driver = {
170 	.driver = {
171 		.name = "mcf54415_dac",
172 	},
173 	.probe = mcf54415_dac_probe,
174 	.id_table = mcf54415_dac_ids,
175 };
176 module_platform_driver(mcf54415_dac_driver);
177 
178 MODULE_AUTHOR("Angelo Dureghello <angelo@kernel-space.org>");
179 MODULE_DESCRIPTION("NXP MCF54415 DAC driver");
180 MODULE_LICENSE("GPL");
181