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