1 /* $NetBSD: mcp3k.c,v 1.4 2022/01/19 05:21:44 thorpej 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 178 if (strcmp(cf->cf_name, "mcp3kadc") != 0) 179 return 0; 180 181 return 1; 182 } 183 184 static void 185 mcp3kadc_attach(device_t parent, device_t self, void *aux) 186 { 187 const struct sysctlnode *rnode, *node; 188 struct spi_attach_args *sa; 189 struct mcp3kadc_softc *sc; 190 struct mcp3kadc_model *model; 191 int error, ch, i; 192 193 sa = aux; 194 sc = device_private(self); 195 sc->sc_dev = self; 196 sc->sc_sh = sa->sa_handle; 197 198 /* device flags define the model */ 199 sc->sc_model = device_cfdata(sc->sc_dev)->cf_flags; 200 model = &mcp3k_models[sc->sc_model]; 201 202 aprint_naive(": Analog to Digital converter\n"); 203 aprint_normal(": MCP%u %u-channel %u-bit ADC\n", 204 (unsigned)model->name, (unsigned)model->channels, 205 (unsigned)model->bits); 206 207 /* configure for 1MHz */ 208 error = spi_configure(self, sa->sa_handle, SPI_MODE_0, 1000000); 209 if (error) { 210 return; 211 } 212 213 /* set a default Vref in mV according to the chip's ADC resolution */ 214 sc->sc_vref_mv = 1 << ((model->flags & M3K_SIGNED) ? 215 model->bits - 1 : model->bits); 216 217 /* remember maximum value for this ADC - also used for masking */ 218 sc->sc_adc_max = (1 << model->bits) - 1; 219 220 /* attach voltage sensors to envsys */ 221 sc->sc_sme = sysmon_envsys_create(); 222 223 /* adc difference from two neighbouring channels */ 224 for (ch = 0; ch < model->channels; ch++) { 225 KASSERT(ch < M3K_MAX_SENSORS); 226 sc->sc_sensors[ch].units = ENVSYS_SVOLTS_DC; 227 sc->sc_sensors[ch].state = ENVSYS_SINVALID; 228 if (model->channels == 1) 229 strlcpy(sc->sc_sensors[ch].desc, "adc diff ch0", 230 sizeof(sc->sc_sensors[ch].desc)); 231 else 232 snprintf(sc->sc_sensors[ch].desc, 233 sizeof(sc->sc_sensors[ch].desc), 234 "adc diff ch%d-ch%d", ch, ch ^ 1); 235 sc->sc_sensors[ch].private = ch; 236 sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensors[ch]); 237 } 238 239 if (model->flags & M3K_SGLDIFF) { 240 /* adc from single ended channels */ 241 for (i = 0; i < model->channels; i++, ch++) { 242 KASSERT(ch < M3K_MAX_SENSORS); 243 sc->sc_sensors[ch].units = ENVSYS_SVOLTS_DC; 244 sc->sc_sensors[ch].state = ENVSYS_SINVALID; 245 snprintf(sc->sc_sensors[ch].desc, 246 sizeof(sc->sc_sensors[ch].desc), 247 "adc single ch%d", i); 248 sc->sc_sensors[ch].private = ch; 249 sysmon_envsys_sensor_attach(sc->sc_sme, 250 &sc->sc_sensors[ch]); 251 } 252 } 253 254 sc->sc_sme->sme_name = device_xname(self); 255 sc->sc_sme->sme_refresh = mcp3kadc_envsys_refresh; 256 sc->sc_sme->sme_cookie = sc; 257 if (sysmon_envsys_register(sc->sc_sme)) { 258 aprint_error_dev(self, "unable to register with sysmon\n"); 259 sysmon_envsys_destroy(sc->sc_sme); 260 } 261 262 /* create a sysctl node for adjusting the ADC's reference voltage */ 263 rnode = node = NULL; 264 sysctl_createv(NULL, 0, NULL, &rnode, 265 CTLFLAG_READWRITE, 266 CTLTYPE_NODE, device_xname(sc->sc_dev), NULL, 267 NULL, 0, NULL, 0, 268 CTL_HW, CTL_CREATE, CTL_EOL); 269 270 if (rnode != NULL) 271 sysctl_createv(NULL, 0, NULL, &node, 272 CTLFLAG_READWRITE | CTLFLAG_OWNDESC, 273 CTLTYPE_INT, "vref", 274 SYSCTL_DESCR("ADC reference voltage"), 275 sysctl_mcp3kadc_vref, 0, (void *)sc, 0, 276 CTL_HW, rnode->sysctl_num, CTL_CREATE, CTL_EOL); 277 } 278 279 static void 280 mcp3kadc_envsys_refresh(struct sysmon_envsys *sme, envsys_data_t *edata) 281 { 282 struct mcp3kadc_softc *sc; 283 struct mcp3kadc_model *model; 284 uint8_t buf[2], ctrl; 285 int32_t val, scale; 286 287 sc = sme->sme_cookie; 288 model = &mcp3k_models[sc->sc_model]; 289 scale = sc->sc_adc_max + 1; 290 291 if (model->flags & M3K_CTRL_NEEDED) { 292 /* we need to send some control bits first */ 293 ctrl = 1; /* start bit */ 294 295 if (model->flags & M3K_SGLDIFF) { 296 /* bit set to select single-ended mode */ 297 ctrl <<= 1; 298 ctrl |= edata->private >= model->channels; 299 } 300 301 if (model->flags & M3K_D2D1D0) { 302 /* 3 bits select the channel */ 303 ctrl <<= 3; 304 ctrl |= edata->private & (model->channels - 1); 305 } else { 306 /* 1 bit selects between two channels */ 307 ctrl <<= 1; 308 ctrl |= edata->private & 1; 309 } 310 311 if (model->flags & M3K_MSBF) { 312 /* bit select MSB first format */ 313 ctrl <<= 1; 314 ctrl |= 1; 315 } 316 317 /* send control bits, receive ADC data */ 318 if (spi_send_recv(sc->sc_sh, 1, &ctrl, 2, buf) != 0) { 319 edata->state = ENVSYS_SINVALID; 320 return; 321 } 322 } else { 323 324 /* just read data from the ADC */ 325 if (spi_recv(sc->sc_sh, 2, buf) != 0) { 326 edata->state = ENVSYS_SINVALID; 327 return; 328 } 329 } 330 331 /* extract big-endian ADC data from buffer */ 332 val = (buf[0] << 8) | buf[1]; 333 val = (val >> (16 - (model->bits + model->lead))) & sc->sc_adc_max; 334 335 /* sign-extend the result, when needed */ 336 if (model->flags & M3K_SIGNED) { 337 if (val & (1 << (model->bits - 1))) 338 val -= sc->sc_adc_max + 1; 339 scale >>= 1; /* MSB is the sign */ 340 } 341 342 /* scale the value for Vref and convert to mV */ 343 edata->value_cur = (sc->sc_vref_mv * val / scale) * 1000; 344 edata->state = ENVSYS_SVALID; 345 } 346 347 static int 348 sysctl_mcp3kadc_vref(SYSCTLFN_ARGS) 349 { 350 struct sysctlnode node; 351 struct mcp3kadc_softc *sc; 352 int32_t t; 353 int error; 354 355 node = *rnode; 356 sc = node.sysctl_data; 357 358 t = sc->sc_vref_mv; 359 node.sysctl_data = &t; 360 361 error = sysctl_lookup(SYSCTLFN_CALL(&node)); 362 if (error || newp == NULL) 363 return error; 364 if (t <= 0) 365 return EINVAL; 366 367 sc->sc_vref_mv = t; 368 return 0; 369 } 370