1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * Copyright (C) 2023 Anshul Dalal <anshulusr@gmail.com> |
4 | * |
5 | * Driver for Microchip MCP4801, MCP4802, MCP4811, MCP4812, MCP4821 and MCP4822 |
6 | * |
7 | * Based on the work of: |
8 | * Michael Welling (MCP4922 Driver) |
9 | * |
10 | * Datasheet: |
11 | * MCP48x1: https://ww1.microchip.com/downloads/en/DeviceDoc/22244B.pdf |
12 | * MCP48x2: https://ww1.microchip.com/downloads/en/DeviceDoc/20002249B.pdf |
13 | * |
14 | * TODO: |
15 | * - Configurable gain |
16 | * - Regulator control |
17 | */ |
18 | |
19 | #include <linux/module.h> |
20 | #include <linux/mod_devicetable.h> |
21 | #include <linux/spi/spi.h> |
22 | |
23 | #include <linux/iio/iio.h> |
24 | #include <linux/iio/types.h> |
25 | |
26 | #include <asm/unaligned.h> |
27 | |
28 | #define MCP4821_ACTIVE_MODE BIT(12) |
29 | #define MCP4802_SECOND_CHAN BIT(15) |
30 | |
31 | /* DAC uses an internal Voltage reference of 4.096V at a gain of 2x */ |
32 | #define MCP4821_2X_GAIN_VREF_MV 4096 |
33 | |
34 | enum mcp4821_supported_drvice_ids { |
35 | ID_MCP4801, |
36 | ID_MCP4802, |
37 | ID_MCP4811, |
38 | ID_MCP4812, |
39 | ID_MCP4821, |
40 | ID_MCP4822, |
41 | }; |
42 | |
43 | struct mcp4821_state { |
44 | struct spi_device *spi; |
45 | u16 dac_value[2]; |
46 | }; |
47 | |
48 | struct mcp4821_chip_info { |
49 | const char *name; |
50 | int num_channels; |
51 | const struct iio_chan_spec channels[2]; |
52 | }; |
53 | |
54 | #define MCP4821_CHAN(channel_id, resolution) \ |
55 | { \ |
56 | .type = IIO_VOLTAGE, .output = 1, .indexed = 1, \ |
57 | .channel = (channel_id), \ |
58 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ |
59 | .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ |
60 | .scan_type = { \ |
61 | .realbits = (resolution), \ |
62 | .shift = 12 - (resolution), \ |
63 | }, \ |
64 | } |
65 | |
66 | static const struct mcp4821_chip_info mcp4821_chip_info_table[6] = { |
67 | [ID_MCP4801] = { |
68 | .name = "mcp4801" , |
69 | .num_channels = 1, |
70 | .channels = { |
71 | MCP4821_CHAN(0, 8), |
72 | }, |
73 | }, |
74 | [ID_MCP4802] = { |
75 | .name = "mcp4802" , |
76 | .num_channels = 2, |
77 | .channels = { |
78 | MCP4821_CHAN(0, 8), |
79 | MCP4821_CHAN(1, 8), |
80 | }, |
81 | }, |
82 | [ID_MCP4811] = { |
83 | .name = "mcp4811" , |
84 | .num_channels = 1, |
85 | .channels = { |
86 | MCP4821_CHAN(0, 10), |
87 | }, |
88 | }, |
89 | [ID_MCP4812] = { |
90 | .name = "mcp4812" , |
91 | .num_channels = 2, |
92 | .channels = { |
93 | MCP4821_CHAN(0, 10), |
94 | MCP4821_CHAN(1, 10), |
95 | }, |
96 | }, |
97 | [ID_MCP4821] = { |
98 | .name = "mcp4821" , |
99 | .num_channels = 1, |
100 | .channels = { |
101 | MCP4821_CHAN(0, 12), |
102 | }, |
103 | }, |
104 | [ID_MCP4822] = { |
105 | .name = "mcp4822" , |
106 | .num_channels = 2, |
107 | .channels = { |
108 | MCP4821_CHAN(0, 12), |
109 | MCP4821_CHAN(1, 12), |
110 | }, |
111 | }, |
112 | }; |
113 | |
114 | static int mcp4821_read_raw(struct iio_dev *indio_dev, |
115 | struct iio_chan_spec const *chan, int *val, |
116 | int *val2, long mask) |
117 | { |
118 | struct mcp4821_state *state; |
119 | |
120 | switch (mask) { |
121 | case IIO_CHAN_INFO_RAW: |
122 | state = iio_priv(indio_dev); |
123 | *val = state->dac_value[chan->channel]; |
124 | return IIO_VAL_INT; |
125 | case IIO_CHAN_INFO_SCALE: |
126 | *val = MCP4821_2X_GAIN_VREF_MV; |
127 | *val2 = chan->scan_type.realbits; |
128 | return IIO_VAL_FRACTIONAL_LOG2; |
129 | default: |
130 | return -EINVAL; |
131 | } |
132 | } |
133 | |
134 | static int mcp4821_write_raw(struct iio_dev *indio_dev, |
135 | struct iio_chan_spec const *chan, int val, |
136 | int val2, long mask) |
137 | { |
138 | struct mcp4821_state *state = iio_priv(indio_dev); |
139 | u16 write_val; |
140 | __be16 write_buffer; |
141 | int ret; |
142 | |
143 | if (val2 != 0) |
144 | return -EINVAL; |
145 | |
146 | if (val < 0 || val >= BIT(chan->scan_type.realbits)) |
147 | return -EINVAL; |
148 | |
149 | if (mask != IIO_CHAN_INFO_RAW) |
150 | return -EINVAL; |
151 | |
152 | write_val = MCP4821_ACTIVE_MODE | val << chan->scan_type.shift; |
153 | if (chan->channel) |
154 | write_val |= MCP4802_SECOND_CHAN; |
155 | |
156 | write_buffer = cpu_to_be16(write_val); |
157 | ret = spi_write(spi: state->spi, buf: &write_buffer, len: sizeof(write_buffer)); |
158 | if (ret) { |
159 | dev_err(&state->spi->dev, "Failed to write to device: %d" , ret); |
160 | return ret; |
161 | } |
162 | |
163 | state->dac_value[chan->channel] = val; |
164 | |
165 | return 0; |
166 | } |
167 | |
168 | static const struct iio_info mcp4821_info = { |
169 | .read_raw = &mcp4821_read_raw, |
170 | .write_raw = &mcp4821_write_raw, |
171 | }; |
172 | |
173 | static int mcp4821_probe(struct spi_device *spi) |
174 | { |
175 | struct iio_dev *indio_dev; |
176 | struct mcp4821_state *state; |
177 | const struct mcp4821_chip_info *info; |
178 | |
179 | indio_dev = devm_iio_device_alloc(parent: &spi->dev, sizeof_priv: sizeof(*state)); |
180 | if (indio_dev == NULL) |
181 | return -ENOMEM; |
182 | |
183 | state = iio_priv(indio_dev); |
184 | state->spi = spi; |
185 | |
186 | info = spi_get_device_match_data(sdev: spi); |
187 | indio_dev->name = info->name; |
188 | indio_dev->info = &mcp4821_info; |
189 | indio_dev->modes = INDIO_DIRECT_MODE; |
190 | indio_dev->channels = info->channels; |
191 | indio_dev->num_channels = info->num_channels; |
192 | |
193 | return devm_iio_device_register(&spi->dev, indio_dev); |
194 | } |
195 | |
196 | #define MCP4821_COMPATIBLE(of_compatible, id) \ |
197 | { \ |
198 | .compatible = of_compatible, \ |
199 | .data = &mcp4821_chip_info_table[id] \ |
200 | } |
201 | |
202 | static const struct of_device_id mcp4821_of_table[] = { |
203 | MCP4821_COMPATIBLE("microchip,mcp4801" , ID_MCP4801), |
204 | MCP4821_COMPATIBLE("microchip,mcp4802" , ID_MCP4802), |
205 | MCP4821_COMPATIBLE("microchip,mcp4811" , ID_MCP4811), |
206 | MCP4821_COMPATIBLE("microchip,mcp4812" , ID_MCP4812), |
207 | MCP4821_COMPATIBLE("microchip,mcp4821" , ID_MCP4821), |
208 | MCP4821_COMPATIBLE("microchip,mcp4822" , ID_MCP4822), |
209 | { /* Sentinel */ } |
210 | }; |
211 | MODULE_DEVICE_TABLE(of, mcp4821_of_table); |
212 | |
213 | static const struct spi_device_id mcp4821_id_table[] = { |
214 | { "mcp4801" , (kernel_ulong_t)&mcp4821_chip_info_table[ID_MCP4801]}, |
215 | { "mcp4802" , (kernel_ulong_t)&mcp4821_chip_info_table[ID_MCP4802]}, |
216 | { "mcp4811" , (kernel_ulong_t)&mcp4821_chip_info_table[ID_MCP4811]}, |
217 | { "mcp4812" , (kernel_ulong_t)&mcp4821_chip_info_table[ID_MCP4812]}, |
218 | { "mcp4821" , (kernel_ulong_t)&mcp4821_chip_info_table[ID_MCP4821]}, |
219 | { "mcp4822" , (kernel_ulong_t)&mcp4821_chip_info_table[ID_MCP4822]}, |
220 | { /* Sentinel */ } |
221 | }; |
222 | MODULE_DEVICE_TABLE(spi, mcp4821_id_table); |
223 | |
224 | static struct spi_driver mcp4821_driver = { |
225 | .driver = { |
226 | .name = "mcp4821" , |
227 | .of_match_table = mcp4821_of_table, |
228 | }, |
229 | .probe = mcp4821_probe, |
230 | .id_table = mcp4821_id_table, |
231 | }; |
232 | module_spi_driver(mcp4821_driver); |
233 | |
234 | MODULE_AUTHOR("Anshul Dalal <anshulusr@gmail.com>" ); |
235 | MODULE_DESCRIPTION("Microchip MCP4821 DAC Driver" ); |
236 | MODULE_LICENSE("GPL" ); |
237 | |