1263693Sloos/*- 2263693Sloos * Copyright 2014 Luiz Otavio O Souza <loos@freebsd.org> 3263693Sloos * All rights reserved. 4263693Sloos * 5263693Sloos * Redistribution and use in source and binary forms, with or without 6263693Sloos * modification, are permitted provided that the following conditions 7263693Sloos * are met: 8263693Sloos * 1. Redistributions of source code must retain the above copyright 9263693Sloos * notice, this list of conditions and the following disclaimer. 10263693Sloos * 2. Redistributions in binary form must reproduce the above copyright 11263693Sloos * notice, this list of conditions and the following disclaimer in the 12263693Sloos * documentation and/or other materials provided with the distribution. 13263693Sloos * 14263693Sloos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15263693Sloos * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16263693Sloos * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17263693Sloos * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18263693Sloos * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19263693Sloos * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20263693Sloos * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21263693Sloos * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22263693Sloos * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23263693Sloos * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24263693Sloos * SUCH DAMAGE. 25263693Sloos */ 26263693Sloos 27263693Sloos#include <sys/cdefs.h> 28263693Sloos__FBSDID("$FreeBSD$"); 29263693Sloos 30263693Sloos#include <sys/param.h> 31263693Sloos#include <sys/systm.h> 32263693Sloos#include <sys/bus.h> 33263693Sloos 34263693Sloos#include <sys/kernel.h> 35263693Sloos#include <sys/limits.h> 36263693Sloos#include <sys/lock.h> 37263693Sloos#include <sys/module.h> 38263693Sloos#include <sys/mutex.h> 39263693Sloos#include <sys/resource.h> 40263693Sloos#include <sys/rman.h> 41263693Sloos#include <sys/sysctl.h> 42263693Sloos 43263693Sloos#include <machine/bus.h> 44263693Sloos 45263693Sloos#include <dev/ofw/openfirm.h> 46263693Sloos#include <dev/ofw/ofw_bus.h> 47263693Sloos#include <dev/ofw/ofw_bus_subr.h> 48263693Sloos 49263693Sloos#include <arm/ti/ti_prcm.h> 50263693Sloos#include <arm/ti/ti_adcreg.h> 51263693Sloos#include <arm/ti/ti_adcvar.h> 52263693Sloos 53270238Sloos/* Define our 8 steps, one for each input channel. */ 54263693Sloosstatic struct ti_adc_input ti_adc_inputs[TI_ADC_NPINS] = { 55263693Sloos { .stepconfig = ADC_STEPCFG1, .stepdelay = ADC_STEPDLY1 }, 56263693Sloos { .stepconfig = ADC_STEPCFG2, .stepdelay = ADC_STEPDLY2 }, 57263693Sloos { .stepconfig = ADC_STEPCFG3, .stepdelay = ADC_STEPDLY3 }, 58263693Sloos { .stepconfig = ADC_STEPCFG4, .stepdelay = ADC_STEPDLY4 }, 59263693Sloos { .stepconfig = ADC_STEPCFG5, .stepdelay = ADC_STEPDLY5 }, 60263693Sloos { .stepconfig = ADC_STEPCFG6, .stepdelay = ADC_STEPDLY6 }, 61263693Sloos { .stepconfig = ADC_STEPCFG7, .stepdelay = ADC_STEPDLY7 }, 62270238Sloos { .stepconfig = ADC_STEPCFG8, .stepdelay = ADC_STEPDLY8 }, 63263693Sloos}; 64263693Sloos 65263693Sloosstatic int ti_adc_samples[5] = { 0, 2, 4, 8, 16 }; 66263693Sloos 67263693Sloosstatic void 68263693Sloosti_adc_enable(struct ti_adc_softc *sc) 69263693Sloos{ 70263693Sloos 71263693Sloos TI_ADC_LOCK_ASSERT(sc); 72263693Sloos 73263693Sloos if (sc->sc_last_state == 1) 74263693Sloos return; 75263693Sloos 76263693Sloos /* Enable the FIFO0 threshold and the end of sequence interrupt. */ 77263693Sloos ADC_WRITE4(sc, ADC_IRQENABLE_SET, 78263693Sloos ADC_IRQ_FIFO0_THRES | ADC_IRQ_END_OF_SEQ); 79263693Sloos 80263693Sloos /* Enable the ADC. Run thru enabled steps, start the conversions. */ 81263693Sloos ADC_WRITE4(sc, ADC_CTRL, ADC_READ4(sc, ADC_CTRL) | ADC_CTRL_ENABLE); 82263693Sloos 83263693Sloos sc->sc_last_state = 1; 84263693Sloos} 85263693Sloos 86263693Sloosstatic void 87263693Sloosti_adc_disable(struct ti_adc_softc *sc) 88263693Sloos{ 89263693Sloos int count; 90263693Sloos uint32_t data; 91263693Sloos 92263693Sloos TI_ADC_LOCK_ASSERT(sc); 93263693Sloos 94263693Sloos if (sc->sc_last_state == 0) 95263693Sloos return; 96263693Sloos 97263693Sloos /* Disable all the enabled steps. */ 98263693Sloos ADC_WRITE4(sc, ADC_STEPENABLE, 0); 99263693Sloos 100263693Sloos /* Disable the ADC. */ 101263693Sloos ADC_WRITE4(sc, ADC_CTRL, ADC_READ4(sc, ADC_CTRL) & ~ADC_CTRL_ENABLE); 102263693Sloos 103263693Sloos /* Disable the FIFO0 threshold and the end of sequence interrupt. */ 104263693Sloos ADC_WRITE4(sc, ADC_IRQENABLE_CLR, 105263693Sloos ADC_IRQ_FIFO0_THRES | ADC_IRQ_END_OF_SEQ); 106263693Sloos 107263693Sloos /* ACK any pending interrupt. */ 108263693Sloos ADC_WRITE4(sc, ADC_IRQSTATUS, ADC_READ4(sc, ADC_IRQSTATUS)); 109263693Sloos 110263693Sloos /* Drain the FIFO data. */ 111263693Sloos count = ADC_READ4(sc, ADC_FIFO0COUNT) & ADC_FIFO_COUNT_MSK; 112263693Sloos while (count > 0) { 113263693Sloos data = ADC_READ4(sc, ADC_FIFO0DATA); 114263693Sloos count = ADC_READ4(sc, ADC_FIFO0COUNT) & ADC_FIFO_COUNT_MSK; 115263693Sloos } 116263693Sloos 117263693Sloos sc->sc_last_state = 0; 118263693Sloos} 119263693Sloos 120263693Sloosstatic int 121263693Sloosti_adc_setup(struct ti_adc_softc *sc) 122263693Sloos{ 123263693Sloos int ain; 124263693Sloos uint32_t enabled; 125263693Sloos 126263693Sloos TI_ADC_LOCK_ASSERT(sc); 127263693Sloos 128263693Sloos /* Check for enabled inputs. */ 129263693Sloos enabled = 0; 130263693Sloos for (ain = 0; ain < TI_ADC_NPINS; ain++) { 131263693Sloos if (ti_adc_inputs[ain].enable) 132263693Sloos enabled |= (1U << (ain + 1)); 133263693Sloos } 134263693Sloos 135263693Sloos /* Set the ADC global status. */ 136263693Sloos if (enabled != 0) { 137263693Sloos ti_adc_enable(sc); 138263693Sloos /* Update the enabled steps. */ 139263693Sloos if (enabled != ADC_READ4(sc, ADC_STEPENABLE)) 140263693Sloos ADC_WRITE4(sc, ADC_STEPENABLE, enabled); 141263693Sloos } else 142263693Sloos ti_adc_disable(sc); 143263693Sloos 144263693Sloos return (0); 145263693Sloos} 146263693Sloos 147263693Sloosstatic void 148263693Sloosti_adc_input_setup(struct ti_adc_softc *sc, int32_t ain) 149263693Sloos{ 150263693Sloos struct ti_adc_input *input; 151263693Sloos uint32_t reg, val; 152263693Sloos 153263693Sloos TI_ADC_LOCK_ASSERT(sc); 154263693Sloos 155263693Sloos input = &ti_adc_inputs[ain]; 156263693Sloos reg = input->stepconfig; 157263693Sloos val = ADC_READ4(sc, reg); 158263693Sloos 159263693Sloos /* Set single ended operation. */ 160263693Sloos val &= ~ADC_STEP_DIFF_CNTRL; 161263693Sloos 162263693Sloos /* Set the negative voltage reference. */ 163263693Sloos val &= ~ADC_STEP_RFM_MSK; 164263693Sloos val |= ADC_STEP_RFM_VREFN << ADC_STEP_RFM_SHIFT; 165263693Sloos 166263693Sloos /* Set the positive voltage reference. */ 167263693Sloos val &= ~ADC_STEP_RFP_MSK; 168263693Sloos val |= ADC_STEP_RFP_VREFP << ADC_STEP_RFP_SHIFT; 169263693Sloos 170263693Sloos /* Set the samples average. */ 171263693Sloos val &= ~ADC_STEP_AVG_MSK; 172263693Sloos val |= input->samples << ADC_STEP_AVG_SHIFT; 173263693Sloos 174263693Sloos /* Select the desired input. */ 175263693Sloos val &= ~ADC_STEP_INP_MSK; 176263693Sloos val |= ain << ADC_STEP_INP_SHIFT; 177263693Sloos 178263693Sloos /* Set the ADC to one-shot mode. */ 179263693Sloos val &= ~ADC_STEP_MODE_MSK; 180263693Sloos 181263693Sloos ADC_WRITE4(sc, reg, val); 182263693Sloos} 183263693Sloos 184263693Sloosstatic void 185263693Sloosti_adc_reset(struct ti_adc_softc *sc) 186263693Sloos{ 187263693Sloos int ain; 188263693Sloos 189263693Sloos TI_ADC_LOCK_ASSERT(sc); 190263693Sloos 191263693Sloos /* Disable all the inputs. */ 192263693Sloos for (ain = 0; ain < TI_ADC_NPINS; ain++) 193263693Sloos ti_adc_inputs[ain].enable = 0; 194263693Sloos} 195263693Sloos 196263693Sloosstatic int 197263693Sloosti_adc_clockdiv_proc(SYSCTL_HANDLER_ARGS) 198263693Sloos{ 199263693Sloos int error, reg; 200263693Sloos struct ti_adc_softc *sc; 201263693Sloos 202263693Sloos sc = (struct ti_adc_softc *)arg1; 203263693Sloos 204263693Sloos TI_ADC_LOCK(sc); 205263693Sloos reg = (int)ADC_READ4(sc, ADC_CLKDIV) + 1; 206263693Sloos TI_ADC_UNLOCK(sc); 207263693Sloos 208263693Sloos error = sysctl_handle_int(oidp, ®, sizeof(reg), req); 209263693Sloos if (error != 0 || req->newptr == NULL) 210263693Sloos return (error); 211263693Sloos 212263693Sloos /* 213263693Sloos * The actual written value is the prescaler setting - 1. 214263693Sloos * Enforce a minimum value of 10 (i.e. 9) which limits the maximum 215263693Sloos * ADC clock to ~2.4Mhz (CLK_M_OSC / 10). 216263693Sloos */ 217263693Sloos reg--; 218263693Sloos if (reg < 9) 219263693Sloos reg = 9; 220263693Sloos if (reg > USHRT_MAX) 221263693Sloos reg = USHRT_MAX; 222263693Sloos 223263693Sloos TI_ADC_LOCK(sc); 224263693Sloos /* Disable the ADC. */ 225263693Sloos ti_adc_disable(sc); 226263693Sloos /* Update the ADC prescaler setting. */ 227263693Sloos ADC_WRITE4(sc, ADC_CLKDIV, reg); 228263693Sloos /* Enable the ADC again. */ 229263693Sloos ti_adc_setup(sc); 230263693Sloos TI_ADC_UNLOCK(sc); 231263693Sloos 232263693Sloos return (0); 233263693Sloos} 234263693Sloos 235263693Sloosstatic int 236263693Sloosti_adc_enable_proc(SYSCTL_HANDLER_ARGS) 237263693Sloos{ 238263693Sloos int error; 239263693Sloos int32_t enable; 240263693Sloos struct ti_adc_softc *sc; 241263693Sloos struct ti_adc_input *input; 242263693Sloos 243263693Sloos input = (struct ti_adc_input *)arg1; 244263693Sloos sc = input->sc; 245263693Sloos 246263693Sloos enable = input->enable; 247263693Sloos error = sysctl_handle_int(oidp, &enable, sizeof(enable), 248263693Sloos req); 249263693Sloos if (error != 0 || req->newptr == NULL) 250263693Sloos return (error); 251263693Sloos 252263693Sloos if (enable) 253263693Sloos enable = 1; 254263693Sloos 255263693Sloos TI_ADC_LOCK(sc); 256263693Sloos /* Setup the ADC as needed. */ 257263693Sloos if (input->enable != enable) { 258263693Sloos input->enable = enable; 259263693Sloos ti_adc_setup(sc); 260263693Sloos if (input->enable == 0) 261263693Sloos input->value = 0; 262263693Sloos } 263263693Sloos TI_ADC_UNLOCK(sc); 264263693Sloos 265263693Sloos return (0); 266263693Sloos} 267263693Sloos 268263693Sloosstatic int 269263693Sloosti_adc_open_delay_proc(SYSCTL_HANDLER_ARGS) 270263693Sloos{ 271263693Sloos int error, reg; 272263693Sloos struct ti_adc_softc *sc; 273263693Sloos struct ti_adc_input *input; 274263693Sloos 275263693Sloos input = (struct ti_adc_input *)arg1; 276263693Sloos sc = input->sc; 277263693Sloos 278263693Sloos TI_ADC_LOCK(sc); 279263693Sloos reg = (int)ADC_READ4(sc, input->stepdelay) & ADC_STEP_OPEN_DELAY; 280263693Sloos TI_ADC_UNLOCK(sc); 281263693Sloos 282263693Sloos error = sysctl_handle_int(oidp, ®, sizeof(reg), req); 283263693Sloos if (error != 0 || req->newptr == NULL) 284263693Sloos return (error); 285263693Sloos 286263693Sloos if (reg < 0) 287263693Sloos reg = 0; 288263693Sloos 289263693Sloos TI_ADC_LOCK(sc); 290263693Sloos ADC_WRITE4(sc, input->stepdelay, reg & ADC_STEP_OPEN_DELAY); 291263693Sloos TI_ADC_UNLOCK(sc); 292263693Sloos 293263693Sloos return (0); 294263693Sloos} 295263693Sloos 296263693Sloosstatic int 297263693Sloosti_adc_samples_avg_proc(SYSCTL_HANDLER_ARGS) 298263693Sloos{ 299263693Sloos int error, samples, i; 300263693Sloos struct ti_adc_softc *sc; 301263693Sloos struct ti_adc_input *input; 302263693Sloos 303263693Sloos input = (struct ti_adc_input *)arg1; 304263693Sloos sc = input->sc; 305263693Sloos 306263693Sloos if (input->samples > nitems(ti_adc_samples)) 307263693Sloos input->samples = nitems(ti_adc_samples); 308263693Sloos samples = ti_adc_samples[input->samples]; 309263693Sloos 310263693Sloos error = sysctl_handle_int(oidp, &samples, 0, req); 311263693Sloos if (error != 0 || req->newptr == NULL) 312263693Sloos return (error); 313263693Sloos 314263693Sloos TI_ADC_LOCK(sc); 315263693Sloos if (samples != ti_adc_samples[input->samples]) { 316263693Sloos input->samples = 0; 317263693Sloos for (i = 0; i < nitems(ti_adc_samples); i++) 318263693Sloos if (samples >= ti_adc_samples[i]) 319263693Sloos input->samples = i; 320263693Sloos ti_adc_input_setup(sc, input->input); 321263693Sloos } 322263693Sloos TI_ADC_UNLOCK(sc); 323263693Sloos 324263693Sloos return (error); 325263693Sloos} 326263693Sloos 327263693Sloosstatic void 328263693Sloosti_adc_read_data(struct ti_adc_softc *sc) 329263693Sloos{ 330263693Sloos int count, ain; 331263693Sloos struct ti_adc_input *input; 332263693Sloos uint32_t data; 333263693Sloos 334263693Sloos TI_ADC_LOCK_ASSERT(sc); 335263693Sloos 336263693Sloos /* Read the available data. */ 337263693Sloos count = ADC_READ4(sc, ADC_FIFO0COUNT) & ADC_FIFO_COUNT_MSK; 338263693Sloos while (count > 0) { 339263693Sloos data = ADC_READ4(sc, ADC_FIFO0DATA); 340263693Sloos ain = (data & ADC_FIFO_STEP_ID_MSK) >> ADC_FIFO_STEP_ID_SHIFT; 341263693Sloos input = &ti_adc_inputs[ain]; 342263693Sloos if (input->enable == 0) 343263693Sloos input->value = 0; 344263693Sloos else 345263693Sloos input->value = (int32_t)(data & ADC_FIFO_DATA_MSK); 346263693Sloos count = ADC_READ4(sc, ADC_FIFO0COUNT) & ADC_FIFO_COUNT_MSK; 347263693Sloos } 348263693Sloos} 349263693Sloos 350263693Sloosstatic void 351263693Sloosti_adc_intr(void *arg) 352263693Sloos{ 353263693Sloos struct ti_adc_softc *sc; 354263693Sloos uint32_t status; 355263693Sloos 356263693Sloos sc = (struct ti_adc_softc *)arg; 357263693Sloos 358263693Sloos status = ADC_READ4(sc, ADC_IRQSTATUS); 359263693Sloos if (status == 0) 360263693Sloos return; 361263693Sloos if (status & ~(ADC_IRQ_FIFO0_THRES | ADC_IRQ_END_OF_SEQ)) 362263693Sloos device_printf(sc->sc_dev, "stray interrupt: %#x\n", status); 363263693Sloos 364263693Sloos TI_ADC_LOCK(sc); 365263693Sloos /* ACK the interrupt. */ 366263693Sloos ADC_WRITE4(sc, ADC_IRQSTATUS, status); 367263693Sloos 368263693Sloos /* Read the available data. */ 369263693Sloos if (status & ADC_IRQ_FIFO0_THRES) 370263693Sloos ti_adc_read_data(sc); 371263693Sloos 372263693Sloos /* Start the next conversion ? */ 373263693Sloos if (status & ADC_IRQ_END_OF_SEQ) 374263693Sloos ti_adc_setup(sc); 375263693Sloos TI_ADC_UNLOCK(sc); 376263693Sloos} 377263693Sloos 378263693Sloosstatic void 379263693Sloosti_adc_sysctl_init(struct ti_adc_softc *sc) 380263693Sloos{ 381263693Sloos char pinbuf[3]; 382263693Sloos struct sysctl_ctx_list *ctx; 383263693Sloos struct sysctl_oid *tree_node, *inp_node, *inpN_node; 384263693Sloos struct sysctl_oid_list *tree, *inp_tree, *inpN_tree; 385263693Sloos int ain; 386263693Sloos 387263693Sloos /* 388263693Sloos * Add per-pin sysctl tree/handlers. 389263693Sloos */ 390263693Sloos ctx = device_get_sysctl_ctx(sc->sc_dev); 391263693Sloos tree_node = device_get_sysctl_tree(sc->sc_dev); 392263693Sloos tree = SYSCTL_CHILDREN(tree_node); 393263693Sloos SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "clockdiv", 394263693Sloos CTLFLAG_RW | CTLTYPE_UINT, sc, 0, 395263693Sloos ti_adc_clockdiv_proc, "IU", "ADC clock prescaler"); 396263693Sloos inp_node = SYSCTL_ADD_NODE(ctx, tree, OID_AUTO, "ain", 397263693Sloos CTLFLAG_RD, NULL, "ADC inputs"); 398263693Sloos inp_tree = SYSCTL_CHILDREN(inp_node); 399263693Sloos 400263693Sloos for (ain = 0; ain < TI_ADC_NPINS; ain++) { 401263693Sloos 402263693Sloos snprintf(pinbuf, sizeof(pinbuf), "%d", ain); 403263693Sloos inpN_node = SYSCTL_ADD_NODE(ctx, inp_tree, OID_AUTO, pinbuf, 404263693Sloos CTLFLAG_RD, NULL, "ADC input"); 405263693Sloos inpN_tree = SYSCTL_CHILDREN(inpN_node); 406263693Sloos 407263693Sloos SYSCTL_ADD_PROC(ctx, inpN_tree, OID_AUTO, "enable", 408263693Sloos CTLFLAG_RW | CTLTYPE_UINT, &ti_adc_inputs[ain], 0, 409263693Sloos ti_adc_enable_proc, "IU", "Enable ADC input"); 410263693Sloos SYSCTL_ADD_PROC(ctx, inpN_tree, OID_AUTO, "open_delay", 411263693Sloos CTLFLAG_RW | CTLTYPE_UINT, &ti_adc_inputs[ain], 0, 412263693Sloos ti_adc_open_delay_proc, "IU", "ADC open delay"); 413263693Sloos SYSCTL_ADD_PROC(ctx, inpN_tree, OID_AUTO, "samples_avg", 414263693Sloos CTLFLAG_RW | CTLTYPE_UINT, &ti_adc_inputs[ain], 0, 415263693Sloos ti_adc_samples_avg_proc, "IU", "ADC samples average"); 416263693Sloos SYSCTL_ADD_INT(ctx, inpN_tree, OID_AUTO, "input", 417263693Sloos CTLFLAG_RD, &ti_adc_inputs[ain].value, 0, 418263693Sloos "Converted raw value for the ADC input"); 419263693Sloos } 420263693Sloos} 421263693Sloos 422263693Sloosstatic void 423263693Sloosti_adc_inputs_init(struct ti_adc_softc *sc) 424263693Sloos{ 425263693Sloos int ain; 426263693Sloos struct ti_adc_input *input; 427263693Sloos 428263693Sloos TI_ADC_LOCK(sc); 429263693Sloos for (ain = 0; ain < TI_ADC_NPINS; ain++) { 430263693Sloos input = &ti_adc_inputs[ain]; 431263693Sloos input->sc = sc; 432263693Sloos input->input = ain; 433263693Sloos input->value = 0; 434263693Sloos input->enable = 0; 435263693Sloos input->samples = 0; 436263693Sloos ti_adc_input_setup(sc, ain); 437263693Sloos } 438263693Sloos TI_ADC_UNLOCK(sc); 439263693Sloos} 440263693Sloos 441263693Sloosstatic void 442263693Sloosti_adc_idlestep_init(struct ti_adc_softc *sc) 443263693Sloos{ 444263693Sloos uint32_t val; 445263693Sloos 446263693Sloos val = ADC_READ4(sc, ADC_IDLECONFIG); 447263693Sloos 448263693Sloos /* Set single ended operation. */ 449263693Sloos val &= ~ADC_STEP_DIFF_CNTRL; 450263693Sloos 451263693Sloos /* Set the negative voltage reference. */ 452263693Sloos val &= ~ADC_STEP_RFM_MSK; 453263693Sloos val |= ADC_STEP_RFM_VREFN << ADC_STEP_RFM_SHIFT; 454263693Sloos 455263693Sloos /* Set the positive voltage reference. */ 456263693Sloos val &= ~ADC_STEP_RFP_MSK; 457263693Sloos val |= ADC_STEP_RFP_VREFP << ADC_STEP_RFP_SHIFT; 458263693Sloos 459263693Sloos /* Connect the input to VREFN. */ 460263693Sloos val &= ~ADC_STEP_INP_MSK; 461263693Sloos val |= ADC_STEP_IN_VREFN << ADC_STEP_INP_SHIFT; 462263693Sloos 463263693Sloos ADC_WRITE4(sc, ADC_IDLECONFIG, val); 464263693Sloos} 465263693Sloos 466263693Sloosstatic int 467263693Sloosti_adc_probe(device_t dev) 468263693Sloos{ 469263693Sloos 470263693Sloos if (!ofw_bus_is_compatible(dev, "ti,adc")) 471263693Sloos return (ENXIO); 472263693Sloos device_set_desc(dev, "TI ADC controller"); 473263693Sloos 474263693Sloos return (BUS_PROBE_DEFAULT); 475263693Sloos} 476263693Sloos 477263693Sloosstatic int 478263693Sloosti_adc_attach(device_t dev) 479263693Sloos{ 480263693Sloos int err, rid; 481263693Sloos struct ti_adc_softc *sc; 482263693Sloos uint32_t reg, rev; 483263693Sloos 484263693Sloos sc = device_get_softc(dev); 485263693Sloos sc->sc_dev = dev; 486263693Sloos 487263693Sloos rid = 0; 488263693Sloos sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 489263693Sloos RF_ACTIVE); 490263693Sloos if (!sc->sc_mem_res) { 491263693Sloos device_printf(dev, "cannot allocate memory window\n"); 492263693Sloos return (ENXIO); 493263693Sloos } 494263693Sloos 495263693Sloos rid = 0; 496263693Sloos sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 497263693Sloos RF_ACTIVE); 498263693Sloos if (!sc->sc_irq_res) { 499263693Sloos bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res); 500263693Sloos device_printf(dev, "cannot allocate interrupt\n"); 501263693Sloos return (ENXIO); 502263693Sloos } 503263693Sloos 504263693Sloos if (bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_MISC | INTR_MPSAFE, 505263693Sloos NULL, ti_adc_intr, sc, &sc->sc_intrhand) != 0) { 506263693Sloos bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_irq_res); 507263693Sloos bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res); 508263693Sloos device_printf(dev, "Unable to setup the irq handler.\n"); 509263693Sloos return (ENXIO); 510263693Sloos } 511263693Sloos 512263693Sloos /* Activate the ADC_TSC module. */ 513263693Sloos err = ti_prcm_clk_enable(TSC_ADC_CLK); 514263693Sloos if (err) 515263693Sloos return (err); 516263693Sloos 517263693Sloos /* Check the ADC revision. */ 518263693Sloos rev = ADC_READ4(sc, ADC_REVISION); 519263693Sloos device_printf(dev, 520263693Sloos "scheme: %#x func: %#x rtl: %d rev: %d.%d custom rev: %d\n", 521263693Sloos (rev & ADC_REV_SCHEME_MSK) >> ADC_REV_SCHEME_SHIFT, 522263693Sloos (rev & ADC_REV_FUNC_MSK) >> ADC_REV_FUNC_SHIFT, 523263693Sloos (rev & ADC_REV_RTL_MSK) >> ADC_REV_RTL_SHIFT, 524263693Sloos (rev & ADC_REV_MAJOR_MSK) >> ADC_REV_MAJOR_SHIFT, 525263693Sloos rev & ADC_REV_MINOR_MSK, 526263693Sloos (rev & ADC_REV_CUSTOM_MSK) >> ADC_REV_CUSTOM_SHIFT); 527263693Sloos 528263693Sloos /* 529263693Sloos * Disable the step write protect and make it store the step ID for 530263693Sloos * the captured data on FIFO. 531263693Sloos */ 532263693Sloos reg = ADC_READ4(sc, ADC_CTRL); 533263693Sloos ADC_WRITE4(sc, ADC_CTRL, reg | ADC_CTRL_STEP_WP | ADC_CTRL_STEP_ID); 534263693Sloos 535263693Sloos /* 536263693Sloos * Set the ADC prescaler to 2400 (yes, the actual value written here 537263693Sloos * is 2400 - 1). 538263693Sloos * This sets the ADC clock to ~10Khz (CLK_M_OSC / 2400). 539263693Sloos */ 540263693Sloos ADC_WRITE4(sc, ADC_CLKDIV, 2399); 541263693Sloos 542263693Sloos TI_ADC_LOCK_INIT(sc); 543263693Sloos 544263693Sloos ti_adc_idlestep_init(sc); 545263693Sloos ti_adc_inputs_init(sc); 546263693Sloos ti_adc_sysctl_init(sc); 547263693Sloos 548263693Sloos return (0); 549263693Sloos} 550263693Sloos 551263693Sloosstatic int 552263693Sloosti_adc_detach(device_t dev) 553263693Sloos{ 554263693Sloos struct ti_adc_softc *sc; 555263693Sloos 556263693Sloos sc = device_get_softc(dev); 557263693Sloos 558263693Sloos /* Turn off the ADC. */ 559263693Sloos TI_ADC_LOCK(sc); 560263693Sloos ti_adc_reset(sc); 561263693Sloos ti_adc_setup(sc); 562263693Sloos TI_ADC_UNLOCK(sc); 563263693Sloos 564263693Sloos TI_ADC_LOCK_DESTROY(sc); 565263693Sloos 566263693Sloos if (sc->sc_intrhand) 567263693Sloos bus_teardown_intr(dev, sc->sc_irq_res, sc->sc_intrhand); 568263693Sloos if (sc->sc_irq_res) 569263693Sloos bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_irq_res); 570263693Sloos if (sc->sc_mem_res) 571263693Sloos bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res); 572263693Sloos 573263693Sloos return (bus_generic_detach(dev)); 574263693Sloos} 575263693Sloos 576263693Sloosstatic device_method_t ti_adc_methods[] = { 577263693Sloos DEVMETHOD(device_probe, ti_adc_probe), 578263693Sloos DEVMETHOD(device_attach, ti_adc_attach), 579263693Sloos DEVMETHOD(device_detach, ti_adc_detach), 580263693Sloos 581263693Sloos DEVMETHOD_END 582263693Sloos}; 583263693Sloos 584263693Sloosstatic driver_t ti_adc_driver = { 585263693Sloos "ti_adc", 586263693Sloos ti_adc_methods, 587263693Sloos sizeof(struct ti_adc_softc), 588263693Sloos}; 589263693Sloos 590263693Sloosstatic devclass_t ti_adc_devclass; 591263693Sloos 592263693SloosDRIVER_MODULE(ti_adc, simplebus, ti_adc_driver, ti_adc_devclass, 0, 0); 593263693SloosMODULE_VERSION(ti_adc, 1); 594263693SloosMODULE_DEPEND(ti_adc, simplebus, 1, 1, 1); 595