1 /* $NetBSD: mcp3k.c,v 1.10 2025/09/13 14:10: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 "opt_fdt.h" 49 50 #include <sys/param.h> 51 #include <sys/systm.h> 52 #include <sys/device.h> 53 #include <sys/kernel.h> 54 #include <sys/types.h> 55 #include <sys/sysctl.h> 56 57 #include <dev/sysmon/sysmonvar.h> 58 #include <dev/spi/spivar.h> 59 60 #ifdef FDT 61 #include <dev/fdt/fdtvar.h> 62 #endif 63 64 #define M3K_MAX_SENSORS 16 /* 8 single-ended & 8 diff. */ 65 66 /* mcp3x0x model description */ 67 struct mcp3kadc_model { 68 uint32_t name; 69 uint8_t bits; 70 uint8_t channels; 71 uint8_t lead; /* leading bits to ignore */ 72 uint8_t flags; 73 #define M3K_SGLDIFF 0x01 /* single-ended/differential */ 74 #define M3K_D2D1D0 0x02 /* 3 channel select bits */ 75 #define M3K_MSBF 0x04 /* MSBF select bit */ 76 #define M3K_SIGNED 0x80 /* result is signed */ 77 #define M3K_CTRL_NEEDED (M3K_SGLDIFF | M3K_D2D1D0 | M3K_MSBF) 78 }; 79 80 struct mcp3kadc_softc { 81 device_t sc_dev; 82 spi_handle_t sc_sh; 83 const struct mcp3kadc_model *sc_model; 84 uint32_t sc_adc_max; 85 int32_t sc_vref_mv; 86 #ifdef FDT 87 struct fdtbus_regulator *sc_vref_supply; 88 #endif 89 90 struct sysmon_envsys *sc_sme; 91 envsys_data_t sc_sensors[M3K_MAX_SENSORS]; 92 }; 93 94 static int mcp3kadc_match(device_t, cfdata_t, void *); 95 static void mcp3kadc_attach(device_t, device_t, void *); 96 static void mcp3kadc_envsys_refresh(struct sysmon_envsys *, 97 envsys_data_t *); 98 static int sysctl_mcp3kadc_vref(SYSCTLFN_ARGS); 99 100 CFATTACH_DECL_NEW(mcp3kadc, sizeof(struct mcp3kadc_softc), 101 mcp3kadc_match, mcp3kadc_attach, NULL, NULL); 102 103 static const struct mcp3kadc_model mcp3001 = { 104 .name = 3001, 105 .bits = 10, 106 .channels = 1, 107 .lead = 3, 108 .flags = 0 109 }; 110 111 static const struct mcp3kadc_model mcp3002 = { 112 .name = 3002, 113 .bits = 10, 114 .channels = 2, 115 .lead = 2, 116 .flags = M3K_SGLDIFF | M3K_MSBF 117 }; 118 119 static const struct mcp3kadc_model mcp3004 = { 120 .name = 3004, 121 .bits = 10, 122 .channels = 4, 123 .lead = 2, 124 .flags = M3K_SGLDIFF | M3K_D2D1D0 125 }; 126 127 static const struct mcp3kadc_model mcp3008 = { 128 .name = 3008, 129 .bits = 10, 130 .channels = 8, 131 .lead = 2, 132 .flags = M3K_SGLDIFF | M3K_D2D1D0 133 }; 134 135 static const struct mcp3kadc_model mcp3201 = { 136 .name = 3201, 137 .bits = 12, 138 .channels = 1, 139 .lead = 3, 140 .flags = 0 141 }; 142 143 static const struct mcp3kadc_model mcp3202 = { 144 .name = 3202, 145 .bits = 12, 146 .channels = 2, 147 .lead = 2, 148 .flags = M3K_SGLDIFF | M3K_MSBF 149 }; 150 151 static const struct mcp3kadc_model mcp3204 = { 152 .name = 3204, 153 .bits = 12, 154 .channels = 4, 155 .lead = 2, 156 .flags = M3K_SGLDIFF | M3K_D2D1D0 157 }; 158 159 static const struct mcp3kadc_model mcp3208 = { 160 .name = 3208, 161 .bits = 12, 162 .channels = 8, 163 .lead = 2, 164 .flags = M3K_SGLDIFF | M3K_D2D1D0 165 }; 166 167 static const struct mcp3kadc_model mcp3301 = { 168 .name = 3301, 169 .bits = 13, 170 .channels = 1, 171 .lead = 3, 172 .flags = M3K_SIGNED 173 }; 174 175 static const struct mcp3kadc_model mcp3302 = { 176 .name = 3302, 177 .bits = 13, 178 .channels = 4, 179 .lead = 2, 180 .flags = M3K_SIGNED | M3K_SGLDIFF | M3K_D2D1D0 181 }; 182 183 static const struct mcp3kadc_model mcp3304 = { 184 .name = 3304, 185 .bits = 13, 186 .channels = 8, 187 .lead = 2, 188 .flags = M3K_SIGNED | M3K_SGLDIFF | M3K_D2D1D0 189 }; 190 191 /* 192 * N.B. The order of this table is important! It matches the order 193 * of the legacy mcp3k_models[] array, which is used to manually 194 * select the device type in the kernel configuration file when 195 * direct configuration is not available. 196 */ 197 static const struct device_compatible_entry compat_data[] = { 198 { .compat = "microchip,mcp3001", .data = &mcp3001 }, 199 { .compat = "microchip,mcp3002", .data = &mcp3002 }, 200 { .compat = "microchip,mcp3004", .data = &mcp3004 }, 201 { .compat = "microchip,mcp3008", .data = &mcp3008 }, 202 { .compat = "microchip,mcp3201", .data = &mcp3201 }, 203 { .compat = "microchip,mcp3202", .data = &mcp3202 }, 204 { .compat = "microchip,mcp3204", .data = &mcp3204 }, 205 { .compat = "microchip,mcp3208", .data = &mcp3208 }, 206 { .compat = "microchip,mcp3301", .data = &mcp3301 }, 207 { .compat = "microchip,mcp3302", .data = &mcp3302 }, 208 { .compat = "microchip,mcp3304", .data = &mcp3304 }, 209 210 #if 0 /* We should also add support for these: */ 211 { .compat = "microchip,mcp3550-50" }, 212 { .compat = "microchip,mcp3550-60" }, 213 { .compat = "microchip,mcp3551" }, 214 { .compat = "microchip,mcp3553" }, 215 #endif 216 217 DEVICE_COMPAT_EOL 218 }; 219 static const int mcp3k_nmodels = __arraycount(compat_data) - 1; 220 221 static const struct mcp3kadc_model * 222 mcp3kadc_lookup(const struct spi_attach_args *sa, const cfdata_t cf) 223 { 224 const struct mcp3kadc_model *model = NULL; 225 const struct device_compatible_entry *dce = 226 spi_compatible_lookup(sa, compat_data); 227 228 if (dce != NULL) { 229 model = dce->data; 230 } else if (cf->cf_flags >= 0 && cf->cf_flags < mcp3k_nmodels) { 231 model = compat_data[cf->cf_flags].data; 232 } 233 return model; 234 } 235 236 static int 237 mcp3kadc_match(device_t parent, cfdata_t cf, void *aux) 238 { 239 struct spi_attach_args *sa = aux; 240 int match_result; 241 242 if (spi_use_direct_match(sa, compat_data, &match_result)) { 243 return match_result; 244 } 245 246 /* 247 * If we're doing indirect config, the user must 248 * have specified a valid model. 249 */ 250 if (mcp3kadc_lookup(sa, cf) == NULL) { 251 return 0; 252 } 253 254 return SPI_MATCH_DEFAULT; 255 } 256 257 #ifdef FDT 258 static bool 259 mcp3kadc_vref_fdt(struct mcp3kadc_softc *sc) 260 { 261 devhandle_t devhandle = device_handle(sc->sc_dev); 262 int phandle = devhandle_to_of(devhandle); 263 int error; 264 u_int uvolts; 265 266 sc->sc_vref_supply = fdtbus_regulator_acquire(phandle, "vref-supply"); 267 if (sc->sc_vref_supply == NULL) { 268 aprint_error_dev(sc->sc_dev, 269 "unable to acquire \"vref-supply\"\n"); 270 return false; 271 } 272 273 error = fdtbus_regulator_enable(sc->sc_vref_supply); 274 if (error) { 275 aprint_error_dev(sc->sc_dev, 276 "failed to enable \"vref-supply\" (error = %d)\n", 277 error); 278 return false; 279 } 280 281 error = fdtbus_regulator_get_voltage(sc->sc_vref_supply, &uvolts); 282 if (error) { 283 aprint_error_dev(sc->sc_dev, 284 "unable to get \"vref-supply\" voltage (error = %d)\n", 285 error); 286 (void) fdtbus_regulator_disable(sc->sc_vref_supply); 287 return false; 288 } 289 290 /* 291 * Device tree property is uV, convert to mV that we use 292 * internally. 293 */ 294 sc->sc_vref_mv = uvolts / 1000; 295 return true; 296 } 297 #endif /* FDT */ 298 299 static void 300 mcp3kadc_attach(device_t parent, device_t self, void *aux) 301 { 302 const struct sysctlnode *rnode, *node; 303 struct spi_attach_args *sa = aux; 304 struct mcp3kadc_softc *sc = device_private(self); 305 devhandle_t devhandle = device_handle(self); 306 const struct mcp3kadc_model *model; 307 int error, ch, i; 308 bool vref_read_only; 309 310 sc->sc_dev = self; 311 sc->sc_sh = sa->sa_handle; 312 313 model = mcp3kadc_lookup(sa, device_cfdata(self)); 314 KASSERT(model != NULL); 315 316 sc->sc_model = model; 317 318 aprint_naive(": Analog to Digital converter\n"); 319 aprint_normal(": MCP%u %u-channel %u-bit ADC\n", 320 (unsigned)model->name, (unsigned)model->channels, 321 (unsigned)model->bits); 322 323 /* configure for 1MHz */ 324 error = spi_configure(self, sa->sa_handle, SPI_MODE_0, SPI_FREQ_MHz(1)); 325 if (error) { 326 return; 327 } 328 329 vref_read_only = false; 330 switch (devhandle_type(devhandle)) { 331 #ifdef FDT 332 case DEVHANDLE_TYPE_OF: 333 vref_read_only = mcp3kadc_vref_fdt(sc); 334 if (! vref_read_only) { 335 /* Error already displayed. */ 336 return; 337 } 338 break; 339 #endif /* FDT */ 340 default: 341 /* 342 * Set a default Vref in mV according to the chip's ADC 343 * resolution. 344 */ 345 sc->sc_vref_mv = 1 << ((model->flags & M3K_SIGNED) ? 346 model->bits - 1 : model->bits); 347 break; 348 } 349 350 /* remember maximum value for this ADC - also used for masking */ 351 sc->sc_adc_max = (1 << model->bits) - 1; 352 353 /* attach voltage sensors to envsys */ 354 sc->sc_sme = sysmon_envsys_create(); 355 356 /* adc difference from two neighbouring channels */ 357 for (ch = 0; ch < model->channels; ch++) { 358 KASSERT(ch < M3K_MAX_SENSORS); 359 sc->sc_sensors[ch].units = ENVSYS_SVOLTS_DC; 360 sc->sc_sensors[ch].state = ENVSYS_SINVALID; 361 if (model->channels == 1) 362 strlcpy(sc->sc_sensors[ch].desc, "adc diff ch0", 363 sizeof(sc->sc_sensors[ch].desc)); 364 else 365 snprintf(sc->sc_sensors[ch].desc, 366 sizeof(sc->sc_sensors[ch].desc), 367 "adc diff ch%d-ch%d", ch, ch ^ 1); 368 sc->sc_sensors[ch].private = ch; 369 sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensors[ch]); 370 } 371 372 if (model->flags & M3K_SGLDIFF) { 373 /* adc from single ended channels */ 374 for (i = 0; i < model->channels; i++, ch++) { 375 KASSERT(ch < M3K_MAX_SENSORS); 376 sc->sc_sensors[ch].units = ENVSYS_SVOLTS_DC; 377 sc->sc_sensors[ch].state = ENVSYS_SINVALID; 378 snprintf(sc->sc_sensors[ch].desc, 379 sizeof(sc->sc_sensors[ch].desc), 380 "adc single ch%d", i); 381 sc->sc_sensors[ch].private = ch; 382 sysmon_envsys_sensor_attach(sc->sc_sme, 383 &sc->sc_sensors[ch]); 384 } 385 } 386 387 sc->sc_sme->sme_name = device_xname(self); 388 sc->sc_sme->sme_refresh = mcp3kadc_envsys_refresh; 389 sc->sc_sme->sme_cookie = sc; 390 if (sysmon_envsys_register(sc->sc_sme)) { 391 aprint_error_dev(self, "unable to register with sysmon\n"); 392 sysmon_envsys_destroy(sc->sc_sme); 393 } 394 395 /* create a sysctl node for adjusting the ADC's reference voltage */ 396 rnode = node = NULL; 397 sysctl_createv(NULL, 0, NULL, &rnode, 398 CTLFLAG_READWRITE, 399 CTLTYPE_NODE, device_xname(sc->sc_dev), NULL, 400 NULL, 0, NULL, 0, 401 CTL_HW, CTL_CREATE, CTL_EOL); 402 403 const int ctlflag = vref_read_only ? CTLFLAG_READONLY 404 : CTLFLAG_READWRITE; 405 406 if (rnode != NULL) 407 sysctl_createv(NULL, 0, NULL, &node, 408 ctlflag | CTLFLAG_OWNDESC, 409 CTLTYPE_INT, "vref", 410 SYSCTL_DESCR("ADC reference voltage"), 411 sysctl_mcp3kadc_vref, 0, (void *)sc, 0, 412 CTL_HW, rnode->sysctl_num, CTL_CREATE, CTL_EOL); 413 } 414 415 static void 416 mcp3kadc_envsys_refresh(struct sysmon_envsys *sme, envsys_data_t *edata) 417 { 418 struct mcp3kadc_softc *sc; 419 const struct mcp3kadc_model *model; 420 uint8_t buf[2], ctrl; 421 int32_t val, scale; 422 423 sc = sme->sme_cookie; 424 model = sc->sc_model; 425 scale = sc->sc_adc_max + 1; 426 427 if (model->flags & M3K_CTRL_NEEDED) { 428 /* we need to send some control bits first */ 429 ctrl = 1; /* start bit */ 430 431 if (model->flags & M3K_SGLDIFF) { 432 /* bit set to select single-ended mode */ 433 ctrl <<= 1; 434 ctrl |= edata->private >= model->channels; 435 } 436 437 if (model->flags & M3K_D2D1D0) { 438 /* 3 bits select the channel */ 439 ctrl <<= 3; 440 ctrl |= edata->private & (model->channels - 1); 441 } else { 442 /* 1 bit selects between two channels */ 443 ctrl <<= 1; 444 ctrl |= edata->private & 1; 445 } 446 447 if (model->flags & M3K_MSBF) { 448 /* bit select MSB first format */ 449 ctrl <<= 1; 450 ctrl |= 1; 451 } 452 453 /* send control bits, receive ADC data */ 454 if (spi_send_recv(sc->sc_sh, 1, &ctrl, 2, buf) != 0) { 455 edata->state = ENVSYS_SINVALID; 456 return; 457 } 458 } else { 459 460 /* just read data from the ADC */ 461 if (spi_recv(sc->sc_sh, 2, buf) != 0) { 462 edata->state = ENVSYS_SINVALID; 463 return; 464 } 465 } 466 467 /* extract big-endian ADC data from buffer */ 468 val = (buf[0] << 8) | buf[1]; 469 val = (val >> (16 - (model->bits + model->lead))) & sc->sc_adc_max; 470 471 /* sign-extend the result, when needed */ 472 if (model->flags & M3K_SIGNED) { 473 if (val & (1 << (model->bits - 1))) 474 val -= sc->sc_adc_max + 1; 475 scale >>= 1; /* MSB is the sign */ 476 } 477 478 /* scale the value for Vref and convert to mV */ 479 edata->value_cur = (sc->sc_vref_mv * val / scale) * 1000; 480 edata->state = ENVSYS_SVALID; 481 } 482 483 static int 484 sysctl_mcp3kadc_vref(SYSCTLFN_ARGS) 485 { 486 struct sysctlnode node; 487 struct mcp3kadc_softc *sc; 488 int32_t t; 489 int error; 490 491 node = *rnode; 492 sc = node.sysctl_data; 493 494 t = sc->sc_vref_mv; 495 node.sysctl_data = &t; 496 497 error = sysctl_lookup(SYSCTLFN_CALL(&node)); 498 if (error || newp == NULL) 499 return error; 500 if (t <= 0) 501 return EINVAL; 502 503 sc->sc_vref_mv = t; 504 return 0; 505 } 506