1 /*- 2 * Copyright (c) 2013 Ian Lepore <ian@freebsd.org> 3 * Copyright (c) 2014 Steven Lawrance <stl@koffein.net> 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28 #include <sys/cdefs.h> 29 __FBSDID("$FreeBSD$"); 30 31 /* 32 * Analog PLL and power regulator driver for Freescale i.MX6 family of SoCs. 33 * Also, temperature montoring and cpu frequency control. It was Freescale who 34 * kitchen-sinked this device, not us. :) 35 * 36 * We don't really do anything with analog PLLs, but the registers for 37 * controlling them belong to the same block as the power regulator registers. 38 * Since the newbus hierarchy makes it hard for anyone other than us to get at 39 * them, we just export a couple public functions to allow the imx6 CCM clock 40 * driver to read and write those registers. 41 * 42 * We also don't do anything about power regulation yet, but when the need 43 * arises, this would be the place for that code to live. 44 * 45 * I have no idea where the "anatop" name comes from. It's in the standard DTS 46 * source describing i.MX6 SoCs, and in the linux and u-boot code which comes 47 * from Freescale, but it's not in the SoC manual. 48 * 49 * Note that temperature values throughout this code are handled in two types of 50 * units. Items with '_cnt' in the name use the hardware temperature count 51 * units (higher counts are lower temperatures). Items with '_val' in the name 52 * are deci-Celcius, which are converted to/from deci-Kelvins in the sysctl 53 * handlers (dK is the standard unit for temperature in sysctl). 54 */ 55 56 #include <sys/param.h> 57 #include <sys/systm.h> 58 #include <sys/callout.h> 59 #include <sys/kernel.h> 60 #include <sys/sysctl.h> 61 #include <sys/module.h> 62 #include <sys/bus.h> 63 #include <sys/rman.h> 64 65 #include <dev/ofw/ofw_bus.h> 66 #include <dev/ofw/ofw_bus_subr.h> 67 68 #include <machine/bus.h> 69 #include <machine/fdt.h> 70 71 #include <arm/freescale/fsl_ocotpreg.h> 72 #include <arm/freescale/fsl_ocotpvar.h> 73 #include <arm/freescale/imx/imx6_anatopreg.h> 74 #include <arm/freescale/imx/imx6_anatopvar.h> 75 76 static struct resource_spec imx6_anatop_spec[] = { 77 { SYS_RES_MEMORY, 0, RF_ACTIVE }, 78 { SYS_RES_IRQ, 0, RF_ACTIVE }, 79 { -1, 0 } 80 }; 81 #define MEMRES 0 82 #define IRQRES 1 83 84 struct imx6_anatop_softc { 85 device_t dev; 86 struct resource *res[2]; 87 uint32_t cpu_curhz; 88 uint32_t cpu_curmhz; 89 uint32_t cpu_curmv; 90 uint32_t cpu_minhz; 91 uint32_t cpu_minmv; 92 uint32_t cpu_maxhz; 93 uint32_t cpu_maxmv; 94 uint32_t refosc_hz; 95 void *temp_intrhand; 96 uint32_t temp_high_val; 97 uint32_t temp_high_cnt; 98 uint32_t temp_last_cnt; 99 uint32_t temp_room_cnt; 100 struct callout temp_throttle_callout; 101 sbintime_t temp_throttle_delay; 102 uint32_t temp_throttle_reset_cnt; 103 uint32_t temp_throttle_trigger_cnt; 104 uint32_t temp_throttle_val; 105 }; 106 107 static struct imx6_anatop_softc *imx6_anatop_sc; 108 109 /* 110 * Tables of CPU max frequencies and corresponding voltages. This is indexed by 111 * the max frequency value (0-3) from the ocotp CFG3 register. 112 */ 113 static uint32_t imx6_cpu_maxhz_tab[] = { 114 792000000, 852000000, 996000000, 1200000000 115 }; 116 static uint32_t imx6_cpu_millivolt_tab[] = { 117 1150, 1225, 1225, 1275 118 }; 119 120 #define TZ_ZEROC 2732 /* deci-Kelvin <-> deci-Celcius offset. */ 121 122 uint32_t 123 imx6_anatop_read_4(bus_size_t offset) 124 { 125 126 KASSERT(imx6_anatop_sc != NULL, ("imx6_anatop_read_4 sc NULL")); 127 128 return (bus_read_4(imx6_anatop_sc->res[MEMRES], offset)); 129 } 130 131 void 132 imx6_anatop_write_4(bus_size_t offset, uint32_t value) 133 { 134 135 KASSERT(imx6_anatop_sc != NULL, ("imx6_anatop_write_4 sc NULL")); 136 137 bus_write_4(imx6_anatop_sc->res[MEMRES], offset, value); 138 } 139 140 static void 141 vdd_set(struct imx6_anatop_softc *sc, int mv) 142 { 143 int newtarg, oldtarg; 144 uint32_t delay, pmureg; 145 static boolean_t init_done = false; 146 147 /* 148 * The datasheet says VDD_PU and VDD_SOC must be equal, and VDD_ARM 149 * can't be more than 50mV above or 200mV below them. For now to keep 150 * things simple we set all three to the same value. 151 */ 152 153 pmureg = imx6_anatop_read_4(IMX6_ANALOG_PMU_REG_CORE); 154 oldtarg = pmureg & IMX6_ANALOG_PMU_REG0_TARG_MASK; 155 156 /* Convert mV to target value. Clamp target to valid range. */ 157 if (mv < 725) 158 newtarg = 0x00; 159 else if (mv > 1450) 160 newtarg = 0x1F; 161 else 162 newtarg = (mv - 700) / 25; 163 164 /* 165 * The first time through the 3 voltages might not be equal so use a 166 * long conservative delay. After that we need to delay 3uS for every 167 * 25mV step upward. No need to delay at all when lowering. 168 */ 169 if (init_done) { 170 if (newtarg == oldtarg) 171 return; 172 else if (newtarg > oldtarg) 173 delay = (newtarg - oldtarg) * 3; 174 else 175 delay = 0; 176 } else { 177 delay = 700 / 25 * 3; 178 init_done = true; 179 } 180 181 /* 182 * Make the change and wait for it to take effect. 183 */ 184 pmureg &= ~(IMX6_ANALOG_PMU_REG0_TARG_MASK | 185 IMX6_ANALOG_PMU_REG1_TARG_MASK | 186 IMX6_ANALOG_PMU_REG2_TARG_MASK); 187 188 pmureg |= newtarg << IMX6_ANALOG_PMU_REG0_TARG_SHIFT; 189 pmureg |= newtarg << IMX6_ANALOG_PMU_REG1_TARG_SHIFT; 190 pmureg |= newtarg << IMX6_ANALOG_PMU_REG2_TARG_SHIFT; 191 192 imx6_anatop_write_4(IMX6_ANALOG_PMU_REG_CORE, pmureg); 193 DELAY(delay); 194 sc->cpu_curmv = newtarg * 25 + 700; 195 device_printf(sc->dev, "voltage set to %u\n", sc->cpu_curmv); 196 } 197 198 static inline uint32_t 199 cpufreq_hz_from_div(struct imx6_anatop_softc *sc, uint32_t div) 200 { 201 202 return (sc->refosc_hz * (div / 2)); 203 } 204 205 static inline uint32_t 206 cpufreq_hz_to_div(struct imx6_anatop_softc *sc, uint32_t cpu_hz) 207 { 208 209 return (cpu_hz / (sc->refosc_hz / 2)); 210 } 211 212 static inline uint32_t 213 cpufreq_actual_hz(struct imx6_anatop_softc *sc, uint32_t cpu_hz) 214 { 215 216 return (cpufreq_hz_from_div(sc, cpufreq_hz_to_div(sc, cpu_hz))); 217 } 218 219 static void 220 cpufreq_set_clock(struct imx6_anatop_softc * sc, uint32_t cpu_newhz) 221 { 222 uint32_t div, timeout, wrk32; 223 const uint32_t mindiv = 54; 224 const uint32_t maxdiv = 108; 225 226 /* 227 * Clip the requested frequency to the configured max, then clip the 228 * resulting divisor to the documented min/max values. 229 */ 230 cpu_newhz = min(cpu_newhz, sc->cpu_maxhz); 231 div = cpufreq_hz_to_div(sc, cpu_newhz); 232 if (div < mindiv) 233 div = mindiv; 234 else if (div > maxdiv) 235 div = maxdiv; 236 sc->cpu_curhz = cpufreq_hz_from_div(sc, div); 237 sc->cpu_curmhz = sc->cpu_curhz / 1000000; 238 239 /* 240 * I can't find a documented procedure for changing the ARM PLL divisor, 241 * but some trial and error came up with this: 242 * - Set the bypass clock source to REF_CLK_24M (source #0). 243 * - Set the PLL into bypass mode; cpu should now be running at 24mhz. 244 * - Change the divisor. 245 * - Wait for the LOCK bit to come on; it takes ~50 loop iterations. 246 * - Turn off bypass mode; cpu should now be running at cpu_newhz. 247 */ 248 imx6_anatop_write_4(IMX6_ANALOG_CCM_PLL_ARM_CLR, 249 IMX6_ANALOG_CCM_PLL_ARM_CLK_SRC_MASK); 250 imx6_anatop_write_4(IMX6_ANALOG_CCM_PLL_ARM_SET, 251 IMX6_ANALOG_CCM_PLL_ARM_BYPASS); 252 253 wrk32 = imx6_anatop_read_4(IMX6_ANALOG_CCM_PLL_ARM); 254 wrk32 &= ~IMX6_ANALOG_CCM_PLL_ARM_DIV_MASK; 255 wrk32 |= div; 256 imx6_anatop_write_4(IMX6_ANALOG_CCM_PLL_ARM, wrk32); 257 258 timeout = 10000; 259 while ((imx6_anatop_read_4(IMX6_ANALOG_CCM_PLL_ARM) & 260 IMX6_ANALOG_CCM_PLL_ARM_LOCK) == 0) 261 if (--timeout == 0) 262 panic("imx6_set_cpu_clock(): PLL never locked"); 263 264 imx6_anatop_write_4(IMX6_ANALOG_CCM_PLL_ARM_CLR, 265 IMX6_ANALOG_CCM_PLL_ARM_BYPASS); 266 } 267 268 static void 269 cpufreq_initialize(struct imx6_anatop_softc *sc) 270 { 271 uint32_t cfg3speed; 272 struct sysctl_ctx_list *ctx; 273 274 ctx = device_get_sysctl_ctx(sc->dev); 275 SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev)), 276 OID_AUTO, "cpu_mhz", CTLFLAG_RD, &sc->cpu_curmhz, 0, 277 "CPU frequency in MHz"); 278 279 /* 280 * XXX 24mhz shouldn't be hard-coded, should get this from imx6_ccm 281 * (even though in the real world it will always be 24mhz). Oh wait a 282 * sec, I never wrote imx6_ccm. 283 */ 284 sc->refosc_hz = 24000000; 285 286 /* 287 * Get the maximum speed this cpu can be set to. The values in the 288 * OCOTP CFG3 register are not documented in the reference manual. 289 * The following info was in an archived email found via web search: 290 * - 2b'11: 1200000000Hz; 291 * - 2b'10: 996000000Hz; 292 * - 2b'01: 852000000Hz; -- i.MX6Q Only, exclusive with 996MHz. 293 * - 2b'00: 792000000Hz; 294 */ 295 cfg3speed = (fsl_ocotp_read_4(FSL_OCOTP_CFG3) & 296 FSL_OCOTP_CFG3_SPEED_MASK) >> FSL_OCOTP_CFG3_SPEED_SHIFT; 297 298 sc->cpu_minhz = cpufreq_actual_hz(sc, imx6_cpu_maxhz_tab[0]); 299 sc->cpu_minmv = imx6_cpu_millivolt_tab[0]; 300 sc->cpu_maxhz = cpufreq_actual_hz(sc, imx6_cpu_maxhz_tab[cfg3speed]); 301 sc->cpu_maxmv = imx6_cpu_millivolt_tab[cfg3speed]; 302 303 /* 304 * Set the CPU to maximum speed. 305 * 306 * We won't have thermal throttling until interrupts are enabled, but we 307 * want to run at full speed through all the device init stuff. This 308 * basically assumes that a single core can't overheat before interrupts 309 * are enabled; empirical testing shows that to be a safe assumption. 310 */ 311 vdd_set(sc, sc->cpu_maxmv); 312 cpufreq_set_clock(sc, sc->cpu_maxhz); 313 device_printf(sc->dev, "CPU frequency %uMHz\n", sc->cpu_curmhz); 314 } 315 316 static inline uint32_t 317 temp_from_count(struct imx6_anatop_softc *sc, uint32_t count) 318 { 319 320 return (((sc->temp_high_val - (count - sc->temp_high_cnt) * 321 (sc->temp_high_val - 250) / 322 (sc->temp_room_cnt - sc->temp_high_cnt)))); 323 } 324 325 static inline uint32_t 326 temp_to_count(struct imx6_anatop_softc *sc, uint32_t temp) 327 { 328 329 return ((sc->temp_room_cnt - sc->temp_high_cnt) * 330 (sc->temp_high_val - temp) / (sc->temp_high_val - 250) + 331 sc->temp_high_cnt); 332 } 333 334 static void 335 temp_update_count(struct imx6_anatop_softc *sc) 336 { 337 uint32_t val; 338 339 val = imx6_anatop_read_4(IMX6_ANALOG_TEMPMON_TEMPSENSE0); 340 if (!(val & IMX6_ANALOG_TEMPMON_TEMPSENSE0_VALID)) 341 return; 342 sc->temp_last_cnt = 343 (val & IMX6_ANALOG_TEMPMON_TEMPSENSE0_TEMP_CNT_MASK) >> 344 IMX6_ANALOG_TEMPMON_TEMPSENSE0_TEMP_CNT_SHIFT; 345 } 346 347 static int 348 temp_sysctl_handler(SYSCTL_HANDLER_ARGS) 349 { 350 struct imx6_anatop_softc *sc = arg1; 351 uint32_t t; 352 353 temp_update_count(sc); 354 355 t = temp_from_count(sc, sc->temp_last_cnt) + TZ_ZEROC; 356 357 return (sysctl_handle_int(oidp, &t, 0, req)); 358 } 359 360 static int 361 temp_throttle_sysctl_handler(SYSCTL_HANDLER_ARGS) 362 { 363 struct imx6_anatop_softc *sc = arg1; 364 int err; 365 uint32_t temp; 366 367 temp = sc->temp_throttle_val + TZ_ZEROC; 368 err = sysctl_handle_int(oidp, &temp, 0, req); 369 if (temp < TZ_ZEROC) 370 return (ERANGE); 371 temp -= TZ_ZEROC; 372 if (err != 0 || req->newptr == NULL || temp == sc->temp_throttle_val) 373 return (err); 374 375 /* Value changed, update counts in softc and hardware. */ 376 sc->temp_throttle_val = temp; 377 sc->temp_throttle_trigger_cnt = temp_to_count(sc, sc->temp_throttle_val); 378 sc->temp_throttle_reset_cnt = temp_to_count(sc, sc->temp_throttle_val - 100); 379 imx6_anatop_write_4(IMX6_ANALOG_TEMPMON_TEMPSENSE0_CLR, 380 IMX6_ANALOG_TEMPMON_TEMPSENSE0_ALARM_MASK); 381 imx6_anatop_write_4(IMX6_ANALOG_TEMPMON_TEMPSENSE0_SET, 382 (sc->temp_throttle_trigger_cnt << 383 IMX6_ANALOG_TEMPMON_TEMPSENSE0_ALARM_SHIFT)); 384 return (err); 385 } 386 387 static void 388 tempmon_gofast(struct imx6_anatop_softc *sc) 389 { 390 391 if (sc->cpu_curhz < sc->cpu_maxhz) { 392 vdd_set(sc, sc->cpu_maxmv); 393 cpufreq_set_clock(sc, sc->cpu_maxhz); 394 } 395 } 396 397 static void 398 tempmon_goslow(struct imx6_anatop_softc *sc) 399 { 400 401 if (sc->cpu_curhz > sc->cpu_minhz) { 402 cpufreq_set_clock(sc, sc->cpu_minhz); 403 vdd_set(sc, sc->cpu_minmv); 404 } 405 } 406 407 static int 408 tempmon_intr(void *arg) 409 { 410 struct imx6_anatop_softc *sc = arg; 411 412 /* 413 * XXX Note that this code doesn't currently run (for some mysterious 414 * reason we just never get an interrupt), so the real monitoring is 415 * done by tempmon_throttle_check(). 416 */ 417 tempmon_goslow(sc); 418 /* XXX Schedule callout to speed back up eventually. */ 419 return (FILTER_HANDLED); 420 } 421 422 static void 423 tempmon_throttle_check(void *arg) 424 { 425 struct imx6_anatop_softc *sc = arg; 426 427 /* Lower counts are higher temperatures. */ 428 if (sc->temp_last_cnt < sc->temp_throttle_trigger_cnt) 429 tempmon_goslow(sc); 430 else if (sc->temp_last_cnt > (sc->temp_throttle_reset_cnt)) 431 tempmon_gofast(sc); 432 433 callout_reset_sbt(&sc->temp_throttle_callout, sc->temp_throttle_delay, 434 0, tempmon_throttle_check, sc, 0); 435 436 } 437 438 static void 439 initialize_tempmon(struct imx6_anatop_softc *sc) 440 { 441 uint32_t cal; 442 struct sysctl_ctx_list *ctx; 443 444 /* 445 * Fetch calibration data: a sensor count at room temperature (25C), 446 * a sensor count at a high temperature, and that temperature 447 */ 448 cal = fsl_ocotp_read_4(FSL_OCOTP_ANA1); 449 sc->temp_room_cnt = (cal & 0xFFF00000) >> 20; 450 sc->temp_high_cnt = (cal & 0x000FFF00) >> 8; 451 sc->temp_high_val = (cal & 0x000000FF) * 10; 452 453 /* 454 * Throttle to a lower cpu freq at 10C below the "hot" temperature, and 455 * reset back to max cpu freq at 5C below the trigger. 456 */ 457 sc->temp_throttle_val = sc->temp_high_val - 100; 458 sc->temp_throttle_trigger_cnt = 459 temp_to_count(sc, sc->temp_throttle_val); 460 sc->temp_throttle_reset_cnt = 461 temp_to_count(sc, sc->temp_throttle_val - 50); 462 463 /* 464 * Set the sensor to sample automatically at 16Hz (32.768KHz/0x800), set 465 * the throttle count, and begin making measurements. 466 */ 467 imx6_anatop_write_4(IMX6_ANALOG_TEMPMON_TEMPSENSE1, 0x0800); 468 imx6_anatop_write_4(IMX6_ANALOG_TEMPMON_TEMPSENSE0, 469 (sc->temp_throttle_trigger_cnt << 470 IMX6_ANALOG_TEMPMON_TEMPSENSE0_ALARM_SHIFT) | 471 IMX6_ANALOG_TEMPMON_TEMPSENSE0_MEASURE); 472 473 /* 474 * XXX Note that the alarm-interrupt feature isn't working yet, so 475 * we'll use a callout handler to check at 10Hz. Make sure we have an 476 * initial temperature reading before starting up the callouts so we 477 * don't get a bogus reading of zero. 478 */ 479 while (sc->temp_last_cnt == 0) 480 temp_update_count(sc); 481 sc->temp_throttle_delay = 100 * SBT_1MS; 482 callout_init(&sc->temp_throttle_callout, 0); 483 callout_reset_sbt(&sc->temp_throttle_callout, sc->temp_throttle_delay, 484 0, tempmon_throttle_check, sc, 0); 485 486 ctx = device_get_sysctl_ctx(sc->dev); 487 SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev)), 488 OID_AUTO, "temperature", CTLTYPE_INT | CTLFLAG_RD, sc, 0, 489 temp_sysctl_handler, "IK", "Current die temperature"); 490 SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev)), 491 OID_AUTO, "throttle_temperature", CTLTYPE_INT | CTLFLAG_RW, sc, 492 0, temp_throttle_sysctl_handler, "IK", 493 "Throttle CPU when exceeding this temperature"); 494 } 495 496 static int 497 imx6_anatop_detach(device_t dev) 498 { 499 500 return (EBUSY); 501 } 502 503 static int 504 imx6_anatop_attach(device_t dev) 505 { 506 struct imx6_anatop_softc *sc; 507 int err; 508 509 sc = device_get_softc(dev); 510 sc->dev = dev; 511 512 /* Allocate bus_space resources. */ 513 if (bus_alloc_resources(dev, imx6_anatop_spec, sc->res)) { 514 device_printf(dev, "Cannot allocate resources\n"); 515 err = ENXIO; 516 goto out; 517 } 518 519 err = bus_setup_intr(dev, sc->res[IRQRES], INTR_TYPE_MISC | INTR_MPSAFE, 520 tempmon_intr, NULL, sc, &sc->temp_intrhand); 521 if (err != 0) 522 goto out; 523 524 SYSCTL_ADD_UINT(device_get_sysctl_ctx(sc->dev), 525 SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev)), 526 OID_AUTO, "cpu_voltage", CTLFLAG_RD, 527 &sc->cpu_curmv, 0, "Current CPU voltage in millivolts"); 528 529 imx6_anatop_sc = sc; 530 531 /* 532 * Other code seen on the net sets this SELFBIASOFF flag around the same 533 * time the temperature sensor is set up, although it's unclear how the 534 * two are related (if at all). 535 */ 536 imx6_anatop_write_4(IMX6_ANALOG_PMU_MISC0_SET, 537 IMX6_ANALOG_PMU_MISC0_SELFBIASOFF); 538 539 cpufreq_initialize(sc); 540 initialize_tempmon(sc); 541 542 err = 0; 543 544 out: 545 546 if (err != 0) { 547 bus_release_resources(dev, imx6_anatop_spec, sc->res); 548 } 549 550 return (err); 551 } 552 553 static int 554 imx6_anatop_probe(device_t dev) 555 { 556 557 if (!ofw_bus_status_okay(dev)) 558 return (ENXIO); 559 560 if (ofw_bus_is_compatible(dev, "fsl,imx6q-anatop") == 0) 561 return (ENXIO); 562 563 device_set_desc(dev, "Freescale i.MX6 Analog PLLs and Power"); 564 565 return (BUS_PROBE_DEFAULT); 566 } 567 568 uint32_t 569 imx6_get_cpu_clock() 570 { 571 uint32_t div; 572 573 div = imx6_anatop_read_4(IMX6_ANALOG_CCM_PLL_ARM) & 574 IMX6_ANALOG_CCM_PLL_ARM_DIV_MASK; 575 return (cpufreq_hz_from_div(imx6_anatop_sc, div)); 576 } 577 578 static device_method_t imx6_anatop_methods[] = { 579 /* Device interface */ 580 DEVMETHOD(device_probe, imx6_anatop_probe), 581 DEVMETHOD(device_attach, imx6_anatop_attach), 582 DEVMETHOD(device_detach, imx6_anatop_detach), 583 584 DEVMETHOD_END 585 }; 586 587 static driver_t imx6_anatop_driver = { 588 "imx6_anatop", 589 imx6_anatop_methods, 590 sizeof(struct imx6_anatop_softc) 591 }; 592 593 static devclass_t imx6_anatop_devclass; 594 595 DRIVER_MODULE(imx6_anatop, simplebus, imx6_anatop_driver, imx6_anatop_devclass, 0, 0); 596 597