xref: /netbsd-src/sys/dev/spi/mcp3k.c (revision deb6f0161a9109e7de9b519dc8dfb9478668dcdd)
1 /*	$NetBSD: mcp3k.c,v 1.2 2016/11/20 12:38:04 phx Exp $ */
2 
3 /*-
4  * Copyright (c) 2015 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Frank Wille.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 /*
33  * Microchip MCP3x0x SAR analog to digital converters.
34  * The driver supports various ADCs with different resolutions, operation
35  * modes and number of input channels.
36  * The reference voltage Vref defaults to the maximum output value in mV,
37  * but can be changed via sysctl(3).
38  *
39  * MCP3001: http://ww1.microchip.com/downloads/en/DeviceDoc/21293C.pdf
40  * MCP3002: http://ww1.microchip.com/downloads/en/DeviceDoc/21294E.pdf
41  * MCP3004/3008: http://ww1.microchip.com/downloads/en/DeviceDoc/21295C.pdf
42  * MCP3201: http://ww1.microchip.com/downloads/en/DeviceDoc/21290D.pdf
43  * MCP3204/3208: http://ww1.microchip.com/downloads/en/DeviceDoc/21298c.pdf
44  * MCP3301: http://ww1.microchip.com/downloads/en/DeviceDoc/21700E.pdf
45  * MPC3302/3304: http://ww1.microchip.com/downloads/en/DeviceDoc/21697F.pdf
46  */
47 
48 #include <sys/param.h>
49 #include <sys/systm.h>
50 #include <sys/device.h>
51 #include <sys/kernel.h>
52 #include <sys/types.h>
53 #include <sys/sysctl.h>
54 
55 #include <dev/sysmon/sysmonvar.h>
56 #include <dev/spi/spivar.h>
57 
58 #define M3K_MAX_SENSORS		16		/* 8 single-ended & 8 diff. */
59 
60 /* mcp3x0x model description */
61 struct mcp3kadc_model {
62 	uint32_t		name;
63 	uint8_t			bits;
64 	uint8_t			channels;
65 	uint8_t			lead;		/* leading bits to ignore */
66 	uint8_t			flags;
67 #define M3K_SGLDIFF		0x01		/* single-ended/differential */
68 #define M3K_D2D1D0		0x02		/* 3 channel select bits */
69 #define M3K_MSBF		0x04		/* MSBF select bit */
70 #define M3K_SIGNED		0x80		/* result is signed */
71 #define M3K_CTRL_NEEDED		(M3K_SGLDIFF | M3K_D2D1D0 | M3K_MSBF)
72 };
73 
74 struct mcp3kadc_softc {
75 	device_t		sc_dev;
76 	struct spi_handle 	*sc_sh;
77 	int			sc_model;
78 	uint32_t		sc_adc_max;
79 	int32_t			sc_vref_mv;
80 
81 	struct sysmon_envsys 	*sc_sme;
82 	envsys_data_t 		sc_sensors[M3K_MAX_SENSORS];
83 };
84 
85 static int	mcp3kadc_match(device_t, cfdata_t, void *);
86 static void	mcp3kadc_attach(device_t, device_t, void *);
87 static void	mcp3kadc_envsys_refresh(struct sysmon_envsys *,
88 		    envsys_data_t *);
89 static int	sysctl_mcp3kadc_vref(SYSCTLFN_ARGS);
90 
91 CFATTACH_DECL_NEW(mcp3kadc, sizeof(struct mcp3kadc_softc),
92     mcp3kadc_match,  mcp3kadc_attach, NULL, NULL);
93 
94 static struct mcp3kadc_model mcp3k_models[] = {
95 	{
96 		.name = 3001,
97 		.bits = 10,
98 		.channels = 1,
99 		.lead = 3,
100 		.flags = 0
101 	},
102 	{
103 		.name = 3002,
104 		.bits = 10,
105 		.channels = 2,
106 		.lead = 2,
107 		.flags = M3K_SGLDIFF | M3K_MSBF
108 	},
109 	{
110 		.name = 3004,
111 		.bits = 10,
112 		.channels = 4,
113 		.lead = 2,
114 		.flags = M3K_SGLDIFF | M3K_D2D1D0
115 	},
116 	{
117 		.name = 3008,
118 		.bits = 10,
119 		.channels = 8,
120 		.lead = 2,
121 		.flags = M3K_SGLDIFF | M3K_D2D1D0
122 	},
123 	{
124 		.name = 3201,
125 		.bits = 12,
126 		.channels = 1,
127 		.lead = 3,
128 		.flags = 0
129 	},
130 	{
131 		.name = 3202,
132 		.bits = 12,
133 		.channels = 2,
134 		.lead = 2,
135 		.flags = M3K_SGLDIFF | M3K_MSBF
136 	},
137 	{
138 		.name = 3204,
139 		.bits = 12,
140 		.channels = 4,
141 		.lead = 2,
142 		.flags = M3K_SGLDIFF | M3K_D2D1D0
143 	},
144 	{
145 		.name = 3208,
146 		.bits = 12,
147 		.channels = 8,
148 		.lead = 2,
149 		.flags = M3K_SGLDIFF | M3K_D2D1D0
150 	},
151 	{
152 		.name = 3301,
153 		.bits = 13,
154 		.channels = 1,
155 		.lead = 3,
156 		.flags = M3K_SIGNED
157 	},
158 	{
159 		.name = 3302,
160 		.bits = 13,
161 		.channels = 4,
162 		.lead = 2,
163 		.flags = M3K_SIGNED | M3K_SGLDIFF | M3K_D2D1D0
164 	},
165 	{
166 		.name = 3304,
167 		.bits = 13,
168 		.channels = 8,
169 		.lead = 2,
170 		.flags = M3K_SIGNED | M3K_SGLDIFF | M3K_D2D1D0
171 	},
172 };
173 
174 static int
175 mcp3kadc_match(device_t parent, cfdata_t cf, void *aux)
176 {
177 	struct spi_attach_args *sa = aux;
178 
179 	if (strcmp(cf->cf_name, "mcp3kadc") != 0)
180 		return 0;
181 
182 	/* configure for 1MHz */
183 	if (spi_configure(sa->sa_handle, SPI_MODE_0, 1000000))
184 		return 0;
185 
186 	return 1;
187 }
188 
189 static void
190 mcp3kadc_attach(device_t parent, device_t self, void *aux)
191 {
192 	const struct sysctlnode *rnode, *node;
193 	struct spi_attach_args *sa;
194 	struct mcp3kadc_softc *sc;
195 	struct mcp3kadc_model *model;
196 	int ch, i;
197 
198 	sa = aux;
199 	sc = device_private(self);
200 	sc->sc_dev = self;
201 	sc->sc_sh = sa->sa_handle;
202 
203 	/* device flags define the model */
204 	sc->sc_model = device_cfdata(sc->sc_dev)->cf_flags;
205 	model = &mcp3k_models[sc->sc_model];
206 
207 	aprint_naive(": Analog to Digital converter\n");
208 	aprint_normal(": MCP%u %u-channel %u-bit ADC\n",
209 	    (unsigned)model->name, (unsigned)model->channels,
210 	    (unsigned)model->bits);
211 
212 	/* set a default Vref in mV according to the chip's ADC resolution */
213 	sc->sc_vref_mv = 1 << ((model->flags & M3K_SIGNED) ?
214 	    model->bits - 1 : model->bits);
215 
216 	/* remember maximum value for this ADC - also used for masking */
217 	sc->sc_adc_max = (1 << model->bits) - 1;
218 
219 	/* attach voltage sensors to envsys */
220 	sc->sc_sme = sysmon_envsys_create();
221 
222 	/* adc difference from two neighbouring channels */
223 	for (ch = 0; ch < model->channels; ch++) {
224 		KASSERT(ch < M3K_MAX_SENSORS);
225 		sc->sc_sensors[ch].units = ENVSYS_SVOLTS_DC;
226 		sc->sc_sensors[ch].state = ENVSYS_SINVALID;
227 		if (model->channels == 1)
228 			strlcpy(sc->sc_sensors[ch].desc, "adc diff ch0",
229 			    sizeof(sc->sc_sensors[ch].desc));
230 		else
231 			snprintf(sc->sc_sensors[ch].desc,
232 			    sizeof(sc->sc_sensors[ch].desc),
233 			    "adc diff ch%d-ch%d", ch, ch ^ 1);
234 		sc->sc_sensors[ch].private = ch;
235 		sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensors[ch]);
236 	}
237 
238 	if (model->flags & M3K_SGLDIFF) {
239 		/* adc from single ended channels */
240 		for (i = 0; i < model->channels; i++, ch++) {
241 			KASSERT(ch < M3K_MAX_SENSORS);
242 			sc->sc_sensors[ch].units = ENVSYS_SVOLTS_DC;
243 			sc->sc_sensors[ch].state = ENVSYS_SINVALID;
244 			snprintf(sc->sc_sensors[ch].desc,
245 			    sizeof(sc->sc_sensors[ch].desc),
246 			    "adc single ch%d", i);
247 			sc->sc_sensors[ch].private = ch;
248 			sysmon_envsys_sensor_attach(sc->sc_sme,
249 			    &sc->sc_sensors[ch]);
250 		}
251 	}
252 
253 	sc->sc_sme->sme_name = device_xname(self);
254 	sc->sc_sme->sme_refresh = mcp3kadc_envsys_refresh;
255 	sc->sc_sme->sme_cookie = sc;
256 	if (sysmon_envsys_register(sc->sc_sme)) {
257 		aprint_error_dev(self, "unable to register with sysmon\n");
258 		sysmon_envsys_destroy(sc->sc_sme);
259 	}
260 
261 	/* create a sysctl node for adjusting the ADC's reference voltage */
262 	rnode = node = NULL;
263 	sysctl_createv(NULL, 0, NULL, &rnode,
264 	    CTLFLAG_READWRITE,
265 	    CTLTYPE_NODE, device_xname(sc->sc_dev), NULL,
266 	    NULL, 0, NULL, 0,
267 	    CTL_HW, CTL_CREATE, CTL_EOL);
268 
269 	if (rnode != NULL)
270 		sysctl_createv(NULL, 0, NULL, &node,
271 		    CTLFLAG_READWRITE | CTLFLAG_OWNDESC,
272 		    CTLTYPE_INT, "vref",
273 		    SYSCTL_DESCR("ADC reference voltage"),
274 		    sysctl_mcp3kadc_vref, 0, (void *)sc, 0,
275 		    CTL_HW, rnode->sysctl_num, CTL_CREATE, CTL_EOL);
276 }
277 
278 static void
279 mcp3kadc_envsys_refresh(struct sysmon_envsys *sme, envsys_data_t *edata)
280 {
281 	struct mcp3kadc_softc *sc;
282 	struct mcp3kadc_model *model;
283 	uint8_t buf[2], ctrl;
284 	int32_t val, scale;
285 
286 	sc = sme->sme_cookie;
287 	model = &mcp3k_models[sc->sc_model];
288 	scale = sc->sc_adc_max + 1;
289 
290 	if (model->flags & M3K_CTRL_NEEDED) {
291 		/* we need to send some control bits first */
292 		ctrl = 1;	/* start bit */
293 
294 		if (model->flags & M3K_SGLDIFF) {
295 			/* bit set to select single-ended mode */
296 			ctrl <<= 1;
297 			ctrl |= edata->private >= model->channels;
298 		}
299 
300 		if (model->flags & M3K_D2D1D0) {
301 			/* 3 bits select the channel */
302 			ctrl <<= 3;
303 			ctrl |= edata->private & (model->channels - 1);
304 		} else {
305 			/* 1 bit selects between two channels */
306 			ctrl <<= 1;
307 			ctrl |= edata->private & 1;
308 		}
309 
310 		if (model->flags & M3K_MSBF) {
311 			/* bit select MSB first format */
312 			ctrl <<= 1;
313 			ctrl |= 1;
314 		}
315 
316 		/* send control bits, receive ADC data */
317 		if (spi_send_recv(sc->sc_sh, 1, &ctrl, 2, buf) != 0) {
318 			edata->state = ENVSYS_SINVALID;
319 			return;
320 		}
321 	} else {
322 
323 		/* just read data from the ADC */
324 		if (spi_recv(sc->sc_sh, 2, buf) != 0) {
325 			edata->state = ENVSYS_SINVALID;
326 			return;
327 		}
328 	}
329 
330 	/* extract big-endian ADC data from buffer */
331 	val = (buf[0] << 8) | buf[1];
332 	val = (val >> (16 - (model->bits + model->lead))) & sc->sc_adc_max;
333 
334 	/* sign-extend the result, when needed */
335 	if (model->flags & M3K_SIGNED) {
336 		if (val & (1 << (model->bits - 1)))
337 			val -= sc->sc_adc_max + 1;
338 		scale >>= 1;	/* MSB is the sign */
339 	}
340 
341 	/* scale the value for Vref and convert to mV */
342 	edata->value_cur = (sc->sc_vref_mv * val / scale) * 1000;
343 	edata->state = ENVSYS_SVALID;
344 }
345 
346 static int
347 sysctl_mcp3kadc_vref(SYSCTLFN_ARGS)
348 {
349 	struct sysctlnode node;
350 	struct mcp3kadc_softc *sc;
351 	int32_t t;
352 	int error;
353 
354 	node = *rnode;
355 	sc = node.sysctl_data;
356 
357 	t = sc->sc_vref_mv;
358 	node.sysctl_data = &t;
359 
360 	error = sysctl_lookup(SYSCTLFN_CALL(&node));
361 	if (error || newp == NULL)
362 		return error;
363 	if (t <= 0)
364 		return EINVAL;
365 
366 	sc->sc_vref_mv = t;
367 	return 0;
368 }
369