ti_adc.c revision 263693
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: head/sys/arm/ti/ti_adc.c 263693 2014-03-24 20:06:27Z loos $"); 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 53263693Sloos/* Define our 7 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 }, 62263693Sloos}; 63263693Sloos 64263693Sloosstatic int ti_adc_samples[5] = { 0, 2, 4, 8, 16 }; 65263693Sloos 66263693Sloosstatic void 67263693Sloosti_adc_enable(struct ti_adc_softc *sc) 68263693Sloos{ 69263693Sloos 70263693Sloos TI_ADC_LOCK_ASSERT(sc); 71263693Sloos 72263693Sloos if (sc->sc_last_state == 1) 73263693Sloos return; 74263693Sloos 75263693Sloos /* Enable the FIFO0 threshold and the end of sequence interrupt. */ 76263693Sloos ADC_WRITE4(sc, ADC_IRQENABLE_SET, 77263693Sloos ADC_IRQ_FIFO0_THRES | ADC_IRQ_END_OF_SEQ); 78263693Sloos 79263693Sloos /* Enable the ADC. Run thru enabled steps, start the conversions. */ 80263693Sloos ADC_WRITE4(sc, ADC_CTRL, ADC_READ4(sc, ADC_CTRL) | ADC_CTRL_ENABLE); 81263693Sloos 82263693Sloos sc->sc_last_state = 1; 83263693Sloos} 84263693Sloos 85263693Sloosstatic void 86263693Sloosti_adc_disable(struct ti_adc_softc *sc) 87263693Sloos{ 88263693Sloos int count; 89263693Sloos uint32_t data; 90263693Sloos 91263693Sloos TI_ADC_LOCK_ASSERT(sc); 92263693Sloos 93263693Sloos if (sc->sc_last_state == 0) 94263693Sloos return; 95263693Sloos 96263693Sloos /* Disable all the enabled steps. */ 97263693Sloos ADC_WRITE4(sc, ADC_STEPENABLE, 0); 98263693Sloos 99263693Sloos /* Disable the ADC. */ 100263693Sloos ADC_WRITE4(sc, ADC_CTRL, ADC_READ4(sc, ADC_CTRL) & ~ADC_CTRL_ENABLE); 101263693Sloos 102263693Sloos /* Disable the FIFO0 threshold and the end of sequence interrupt. */ 103263693Sloos ADC_WRITE4(sc, ADC_IRQENABLE_CLR, 104263693Sloos ADC_IRQ_FIFO0_THRES | ADC_IRQ_END_OF_SEQ); 105263693Sloos 106263693Sloos /* ACK any pending interrupt. */ 107263693Sloos ADC_WRITE4(sc, ADC_IRQSTATUS, ADC_READ4(sc, ADC_IRQSTATUS)); 108263693Sloos 109263693Sloos /* Drain the FIFO data. */ 110263693Sloos count = ADC_READ4(sc, ADC_FIFO0COUNT) & ADC_FIFO_COUNT_MSK; 111263693Sloos while (count > 0) { 112263693Sloos data = ADC_READ4(sc, ADC_FIFO0DATA); 113263693Sloos count = ADC_READ4(sc, ADC_FIFO0COUNT) & ADC_FIFO_COUNT_MSK; 114263693Sloos } 115263693Sloos 116263693Sloos sc->sc_last_state = 0; 117263693Sloos} 118263693Sloos 119263693Sloosstatic int 120263693Sloosti_adc_setup(struct ti_adc_softc *sc) 121263693Sloos{ 122263693Sloos int ain; 123263693Sloos uint32_t enabled; 124263693Sloos 125263693Sloos TI_ADC_LOCK_ASSERT(sc); 126263693Sloos 127263693Sloos /* Check for enabled inputs. */ 128263693Sloos enabled = 0; 129263693Sloos for (ain = 0; ain < TI_ADC_NPINS; ain++) { 130263693Sloos if (ti_adc_inputs[ain].enable) 131263693Sloos enabled |= (1U << (ain + 1)); 132263693Sloos } 133263693Sloos 134263693Sloos /* Set the ADC global status. */ 135263693Sloos if (enabled != 0) { 136263693Sloos ti_adc_enable(sc); 137263693Sloos /* Update the enabled steps. */ 138263693Sloos if (enabled != ADC_READ4(sc, ADC_STEPENABLE)) 139263693Sloos ADC_WRITE4(sc, ADC_STEPENABLE, enabled); 140263693Sloos } else 141263693Sloos ti_adc_disable(sc); 142263693Sloos 143263693Sloos return (0); 144263693Sloos} 145263693Sloos 146263693Sloosstatic void 147263693Sloosti_adc_input_setup(struct ti_adc_softc *sc, int32_t ain) 148263693Sloos{ 149263693Sloos struct ti_adc_input *input; 150263693Sloos uint32_t reg, val; 151263693Sloos 152263693Sloos TI_ADC_LOCK_ASSERT(sc); 153263693Sloos 154263693Sloos input = &ti_adc_inputs[ain]; 155263693Sloos reg = input->stepconfig; 156263693Sloos val = ADC_READ4(sc, reg); 157263693Sloos 158263693Sloos /* Set single ended operation. */ 159263693Sloos val &= ~ADC_STEP_DIFF_CNTRL; 160263693Sloos 161263693Sloos /* Set the negative voltage reference. */ 162263693Sloos val &= ~ADC_STEP_RFM_MSK; 163263693Sloos val |= ADC_STEP_RFM_VREFN << ADC_STEP_RFM_SHIFT; 164263693Sloos 165263693Sloos /* Set the positive voltage reference. */ 166263693Sloos val &= ~ADC_STEP_RFP_MSK; 167263693Sloos val |= ADC_STEP_RFP_VREFP << ADC_STEP_RFP_SHIFT; 168263693Sloos 169263693Sloos /* Set the samples average. */ 170263693Sloos val &= ~ADC_STEP_AVG_MSK; 171263693Sloos val |= input->samples << ADC_STEP_AVG_SHIFT; 172263693Sloos 173263693Sloos /* Select the desired input. */ 174263693Sloos val &= ~ADC_STEP_INP_MSK; 175263693Sloos val |= ain << ADC_STEP_INP_SHIFT; 176263693Sloos 177263693Sloos /* Set the ADC to one-shot mode. */ 178263693Sloos val &= ~ADC_STEP_MODE_MSK; 179263693Sloos 180263693Sloos ADC_WRITE4(sc, reg, val); 181263693Sloos} 182263693Sloos 183263693Sloosstatic void 184263693Sloosti_adc_reset(struct ti_adc_softc *sc) 185263693Sloos{ 186263693Sloos int ain; 187263693Sloos 188263693Sloos TI_ADC_LOCK_ASSERT(sc); 189263693Sloos 190263693Sloos /* Disable all the inputs. */ 191263693Sloos for (ain = 0; ain < TI_ADC_NPINS; ain++) 192263693Sloos ti_adc_inputs[ain].enable = 0; 193263693Sloos} 194263693Sloos 195263693Sloosstatic int 196263693Sloosti_adc_clockdiv_proc(SYSCTL_HANDLER_ARGS) 197263693Sloos{ 198263693Sloos int error, reg; 199263693Sloos struct ti_adc_softc *sc; 200263693Sloos 201263693Sloos sc = (struct ti_adc_softc *)arg1; 202263693Sloos 203263693Sloos TI_ADC_LOCK(sc); 204263693Sloos reg = (int)ADC_READ4(sc, ADC_CLKDIV) + 1; 205263693Sloos TI_ADC_UNLOCK(sc); 206263693Sloos 207263693Sloos error = sysctl_handle_int(oidp, ®, sizeof(reg), req); 208263693Sloos if (error != 0 || req->newptr == NULL) 209263693Sloos return (error); 210263693Sloos 211263693Sloos /* 212263693Sloos * The actual written value is the prescaler setting - 1. 213263693Sloos * Enforce a minimum value of 10 (i.e. 9) which limits the maximum 214263693Sloos * ADC clock to ~2.4Mhz (CLK_M_OSC / 10). 215263693Sloos */ 216263693Sloos reg--; 217263693Sloos if (reg < 9) 218263693Sloos reg = 9; 219263693Sloos if (reg > USHRT_MAX) 220263693Sloos reg = USHRT_MAX; 221263693Sloos 222263693Sloos TI_ADC_LOCK(sc); 223263693Sloos /* Disable the ADC. */ 224263693Sloos ti_adc_disable(sc); 225263693Sloos /* Update the ADC prescaler setting. */ 226263693Sloos ADC_WRITE4(sc, ADC_CLKDIV, reg); 227263693Sloos /* Enable the ADC again. */ 228263693Sloos ti_adc_setup(sc); 229263693Sloos TI_ADC_UNLOCK(sc); 230263693Sloos 231263693Sloos return (0); 232263693Sloos} 233263693Sloos 234263693Sloosstatic int 235263693Sloosti_adc_enable_proc(SYSCTL_HANDLER_ARGS) 236263693Sloos{ 237263693Sloos int error; 238263693Sloos int32_t enable; 239263693Sloos struct ti_adc_softc *sc; 240263693Sloos struct ti_adc_input *input; 241263693Sloos 242263693Sloos input = (struct ti_adc_input *)arg1; 243263693Sloos sc = input->sc; 244263693Sloos 245263693Sloos enable = input->enable; 246263693Sloos error = sysctl_handle_int(oidp, &enable, sizeof(enable), 247263693Sloos req); 248263693Sloos if (error != 0 || req->newptr == NULL) 249263693Sloos return (error); 250263693Sloos 251263693Sloos if (enable) 252263693Sloos enable = 1; 253263693Sloos 254263693Sloos TI_ADC_LOCK(sc); 255263693Sloos /* Setup the ADC as needed. */ 256263693Sloos if (input->enable != enable) { 257263693Sloos input->enable = enable; 258263693Sloos ti_adc_setup(sc); 259263693Sloos if (input->enable == 0) 260263693Sloos input->value = 0; 261263693Sloos } 262263693Sloos TI_ADC_UNLOCK(sc); 263263693Sloos 264263693Sloos return (0); 265263693Sloos} 266263693Sloos 267263693Sloosstatic int 268263693Sloosti_adc_open_delay_proc(SYSCTL_HANDLER_ARGS) 269263693Sloos{ 270263693Sloos int error, reg; 271263693Sloos struct ti_adc_softc *sc; 272263693Sloos struct ti_adc_input *input; 273263693Sloos 274263693Sloos input = (struct ti_adc_input *)arg1; 275263693Sloos sc = input->sc; 276263693Sloos 277263693Sloos TI_ADC_LOCK(sc); 278263693Sloos reg = (int)ADC_READ4(sc, input->stepdelay) & ADC_STEP_OPEN_DELAY; 279263693Sloos TI_ADC_UNLOCK(sc); 280263693Sloos 281263693Sloos error = sysctl_handle_int(oidp, ®, sizeof(reg), req); 282263693Sloos if (error != 0 || req->newptr == NULL) 283263693Sloos return (error); 284263693Sloos 285263693Sloos if (reg < 0) 286263693Sloos reg = 0; 287263693Sloos 288263693Sloos TI_ADC_LOCK(sc); 289263693Sloos ADC_WRITE4(sc, input->stepdelay, reg & ADC_STEP_OPEN_DELAY); 290263693Sloos TI_ADC_UNLOCK(sc); 291263693Sloos 292263693Sloos return (0); 293263693Sloos} 294263693Sloos 295263693Sloosstatic int 296263693Sloosti_adc_samples_avg_proc(SYSCTL_HANDLER_ARGS) 297263693Sloos{ 298263693Sloos int error, samples, i; 299263693Sloos struct ti_adc_softc *sc; 300263693Sloos struct ti_adc_input *input; 301263693Sloos 302263693Sloos input = (struct ti_adc_input *)arg1; 303263693Sloos sc = input->sc; 304263693Sloos 305263693Sloos if (input->samples > nitems(ti_adc_samples)) 306263693Sloos input->samples = nitems(ti_adc_samples); 307263693Sloos samples = ti_adc_samples[input->samples]; 308263693Sloos 309263693Sloos error = sysctl_handle_int(oidp, &samples, 0, req); 310263693Sloos if (error != 0 || req->newptr == NULL) 311263693Sloos return (error); 312263693Sloos 313263693Sloos TI_ADC_LOCK(sc); 314263693Sloos if (samples != ti_adc_samples[input->samples]) { 315263693Sloos input->samples = 0; 316263693Sloos for (i = 0; i < nitems(ti_adc_samples); i++) 317263693Sloos if (samples >= ti_adc_samples[i]) 318263693Sloos input->samples = i; 319263693Sloos ti_adc_input_setup(sc, input->input); 320263693Sloos } 321263693Sloos TI_ADC_UNLOCK(sc); 322263693Sloos 323263693Sloos return (error); 324263693Sloos} 325263693Sloos 326263693Sloosstatic void 327263693Sloosti_adc_read_data(struct ti_adc_softc *sc) 328263693Sloos{ 329263693Sloos int count, ain; 330263693Sloos struct ti_adc_input *input; 331263693Sloos uint32_t data; 332263693Sloos 333263693Sloos TI_ADC_LOCK_ASSERT(sc); 334263693Sloos 335263693Sloos /* Read the available data. */ 336263693Sloos count = ADC_READ4(sc, ADC_FIFO0COUNT) & ADC_FIFO_COUNT_MSK; 337263693Sloos while (count > 0) { 338263693Sloos data = ADC_READ4(sc, ADC_FIFO0DATA); 339263693Sloos ain = (data & ADC_FIFO_STEP_ID_MSK) >> ADC_FIFO_STEP_ID_SHIFT; 340263693Sloos input = &ti_adc_inputs[ain]; 341263693Sloos if (input->enable == 0) 342263693Sloos input->value = 0; 343263693Sloos else 344263693Sloos input->value = (int32_t)(data & ADC_FIFO_DATA_MSK); 345263693Sloos count = ADC_READ4(sc, ADC_FIFO0COUNT) & ADC_FIFO_COUNT_MSK; 346263693Sloos } 347263693Sloos} 348263693Sloos 349263693Sloosstatic void 350263693Sloosti_adc_intr(void *arg) 351263693Sloos{ 352263693Sloos struct ti_adc_softc *sc; 353263693Sloos uint32_t status; 354263693Sloos 355263693Sloos sc = (struct ti_adc_softc *)arg; 356263693Sloos 357263693Sloos status = ADC_READ4(sc, ADC_IRQSTATUS); 358263693Sloos if (status == 0) 359263693Sloos return; 360263693Sloos if (status & ~(ADC_IRQ_FIFO0_THRES | ADC_IRQ_END_OF_SEQ)) 361263693Sloos device_printf(sc->sc_dev, "stray interrupt: %#x\n", status); 362263693Sloos 363263693Sloos TI_ADC_LOCK(sc); 364263693Sloos /* ACK the interrupt. */ 365263693Sloos ADC_WRITE4(sc, ADC_IRQSTATUS, status); 366263693Sloos 367263693Sloos /* Read the available data. */ 368263693Sloos if (status & ADC_IRQ_FIFO0_THRES) 369263693Sloos ti_adc_read_data(sc); 370263693Sloos 371263693Sloos /* Start the next conversion ? */ 372263693Sloos if (status & ADC_IRQ_END_OF_SEQ) 373263693Sloos ti_adc_setup(sc); 374263693Sloos TI_ADC_UNLOCK(sc); 375263693Sloos} 376263693Sloos 377263693Sloosstatic void 378263693Sloosti_adc_sysctl_init(struct ti_adc_softc *sc) 379263693Sloos{ 380263693Sloos char pinbuf[3]; 381263693Sloos struct sysctl_ctx_list *ctx; 382263693Sloos struct sysctl_oid *tree_node, *inp_node, *inpN_node; 383263693Sloos struct sysctl_oid_list *tree, *inp_tree, *inpN_tree; 384263693Sloos int ain; 385263693Sloos 386263693Sloos /* 387263693Sloos * Add per-pin sysctl tree/handlers. 388263693Sloos */ 389263693Sloos ctx = device_get_sysctl_ctx(sc->sc_dev); 390263693Sloos tree_node = device_get_sysctl_tree(sc->sc_dev); 391263693Sloos tree = SYSCTL_CHILDREN(tree_node); 392263693Sloos SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "clockdiv", 393263693Sloos CTLFLAG_RW | CTLTYPE_UINT, sc, 0, 394263693Sloos ti_adc_clockdiv_proc, "IU", "ADC clock prescaler"); 395263693Sloos inp_node = SYSCTL_ADD_NODE(ctx, tree, OID_AUTO, "ain", 396263693Sloos CTLFLAG_RD, NULL, "ADC inputs"); 397263693Sloos inp_tree = SYSCTL_CHILDREN(inp_node); 398263693Sloos 399263693Sloos for (ain = 0; ain < TI_ADC_NPINS; ain++) { 400263693Sloos 401263693Sloos snprintf(pinbuf, sizeof(pinbuf), "%d", ain); 402263693Sloos inpN_node = SYSCTL_ADD_NODE(ctx, inp_tree, OID_AUTO, pinbuf, 403263693Sloos CTLFLAG_RD, NULL, "ADC input"); 404263693Sloos inpN_tree = SYSCTL_CHILDREN(inpN_node); 405263693Sloos 406263693Sloos SYSCTL_ADD_PROC(ctx, inpN_tree, OID_AUTO, "enable", 407263693Sloos CTLFLAG_RW | CTLTYPE_UINT, &ti_adc_inputs[ain], 0, 408263693Sloos ti_adc_enable_proc, "IU", "Enable ADC input"); 409263693Sloos SYSCTL_ADD_PROC(ctx, inpN_tree, OID_AUTO, "open_delay", 410263693Sloos CTLFLAG_RW | CTLTYPE_UINT, &ti_adc_inputs[ain], 0, 411263693Sloos ti_adc_open_delay_proc, "IU", "ADC open delay"); 412263693Sloos SYSCTL_ADD_PROC(ctx, inpN_tree, OID_AUTO, "samples_avg", 413263693Sloos CTLFLAG_RW | CTLTYPE_UINT, &ti_adc_inputs[ain], 0, 414263693Sloos ti_adc_samples_avg_proc, "IU", "ADC samples average"); 415263693Sloos SYSCTL_ADD_INT(ctx, inpN_tree, OID_AUTO, "input", 416263693Sloos CTLFLAG_RD, &ti_adc_inputs[ain].value, 0, 417263693Sloos "Converted raw value for the ADC input"); 418263693Sloos } 419263693Sloos} 420263693Sloos 421263693Sloosstatic void 422263693Sloosti_adc_inputs_init(struct ti_adc_softc *sc) 423263693Sloos{ 424263693Sloos int ain; 425263693Sloos struct ti_adc_input *input; 426263693Sloos 427263693Sloos TI_ADC_LOCK(sc); 428263693Sloos for (ain = 0; ain < TI_ADC_NPINS; ain++) { 429263693Sloos input = &ti_adc_inputs[ain]; 430263693Sloos input->sc = sc; 431263693Sloos input->input = ain; 432263693Sloos input->value = 0; 433263693Sloos input->enable = 0; 434263693Sloos input->samples = 0; 435263693Sloos ti_adc_input_setup(sc, ain); 436263693Sloos } 437263693Sloos TI_ADC_UNLOCK(sc); 438263693Sloos} 439263693Sloos 440263693Sloosstatic void 441263693Sloosti_adc_idlestep_init(struct ti_adc_softc *sc) 442263693Sloos{ 443263693Sloos uint32_t val; 444263693Sloos 445263693Sloos val = ADC_READ4(sc, ADC_IDLECONFIG); 446263693Sloos 447263693Sloos /* Set single ended operation. */ 448263693Sloos val &= ~ADC_STEP_DIFF_CNTRL; 449263693Sloos 450263693Sloos /* Set the negative voltage reference. */ 451263693Sloos val &= ~ADC_STEP_RFM_MSK; 452263693Sloos val |= ADC_STEP_RFM_VREFN << ADC_STEP_RFM_SHIFT; 453263693Sloos 454263693Sloos /* Set the positive voltage reference. */ 455263693Sloos val &= ~ADC_STEP_RFP_MSK; 456263693Sloos val |= ADC_STEP_RFP_VREFP << ADC_STEP_RFP_SHIFT; 457263693Sloos 458263693Sloos /* Connect the input to VREFN. */ 459263693Sloos val &= ~ADC_STEP_INP_MSK; 460263693Sloos val |= ADC_STEP_IN_VREFN << ADC_STEP_INP_SHIFT; 461263693Sloos 462263693Sloos ADC_WRITE4(sc, ADC_IDLECONFIG, val); 463263693Sloos} 464263693Sloos 465263693Sloosstatic int 466263693Sloosti_adc_probe(device_t dev) 467263693Sloos{ 468263693Sloos 469263693Sloos if (!ofw_bus_is_compatible(dev, "ti,adc")) 470263693Sloos return (ENXIO); 471263693Sloos device_set_desc(dev, "TI ADC controller"); 472263693Sloos 473263693Sloos return (BUS_PROBE_DEFAULT); 474263693Sloos} 475263693Sloos 476263693Sloosstatic int 477263693Sloosti_adc_attach(device_t dev) 478263693Sloos{ 479263693Sloos int err, rid; 480263693Sloos struct ti_adc_softc *sc; 481263693Sloos uint32_t reg, rev; 482263693Sloos 483263693Sloos sc = device_get_softc(dev); 484263693Sloos sc->sc_dev = dev; 485263693Sloos 486263693Sloos rid = 0; 487263693Sloos sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 488263693Sloos RF_ACTIVE); 489263693Sloos if (!sc->sc_mem_res) { 490263693Sloos device_printf(dev, "cannot allocate memory window\n"); 491263693Sloos return (ENXIO); 492263693Sloos } 493263693Sloos 494263693Sloos rid = 0; 495263693Sloos sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 496263693Sloos RF_ACTIVE); 497263693Sloos if (!sc->sc_irq_res) { 498263693Sloos bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res); 499263693Sloos device_printf(dev, "cannot allocate interrupt\n"); 500263693Sloos return (ENXIO); 501263693Sloos } 502263693Sloos 503263693Sloos if (bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_MISC | INTR_MPSAFE, 504263693Sloos NULL, ti_adc_intr, sc, &sc->sc_intrhand) != 0) { 505263693Sloos bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_irq_res); 506263693Sloos bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res); 507263693Sloos device_printf(dev, "Unable to setup the irq handler.\n"); 508263693Sloos return (ENXIO); 509263693Sloos } 510263693Sloos 511263693Sloos /* Activate the ADC_TSC module. */ 512263693Sloos err = ti_prcm_clk_enable(TSC_ADC_CLK); 513263693Sloos if (err) 514263693Sloos return (err); 515263693Sloos 516263693Sloos /* Check the ADC revision. */ 517263693Sloos rev = ADC_READ4(sc, ADC_REVISION); 518263693Sloos device_printf(dev, 519263693Sloos "scheme: %#x func: %#x rtl: %d rev: %d.%d custom rev: %d\n", 520263693Sloos (rev & ADC_REV_SCHEME_MSK) >> ADC_REV_SCHEME_SHIFT, 521263693Sloos (rev & ADC_REV_FUNC_MSK) >> ADC_REV_FUNC_SHIFT, 522263693Sloos (rev & ADC_REV_RTL_MSK) >> ADC_REV_RTL_SHIFT, 523263693Sloos (rev & ADC_REV_MAJOR_MSK) >> ADC_REV_MAJOR_SHIFT, 524263693Sloos rev & ADC_REV_MINOR_MSK, 525263693Sloos (rev & ADC_REV_CUSTOM_MSK) >> ADC_REV_CUSTOM_SHIFT); 526263693Sloos 527263693Sloos /* 528263693Sloos * Disable the step write protect and make it store the step ID for 529263693Sloos * the captured data on FIFO. 530263693Sloos */ 531263693Sloos reg = ADC_READ4(sc, ADC_CTRL); 532263693Sloos ADC_WRITE4(sc, ADC_CTRL, reg | ADC_CTRL_STEP_WP | ADC_CTRL_STEP_ID); 533263693Sloos 534263693Sloos /* 535263693Sloos * Set the ADC prescaler to 2400 (yes, the actual value written here 536263693Sloos * is 2400 - 1). 537263693Sloos * This sets the ADC clock to ~10Khz (CLK_M_OSC / 2400). 538263693Sloos */ 539263693Sloos ADC_WRITE4(sc, ADC_CLKDIV, 2399); 540263693Sloos 541263693Sloos TI_ADC_LOCK_INIT(sc); 542263693Sloos 543263693Sloos ti_adc_idlestep_init(sc); 544263693Sloos ti_adc_inputs_init(sc); 545263693Sloos ti_adc_sysctl_init(sc); 546263693Sloos 547263693Sloos return (0); 548263693Sloos} 549263693Sloos 550263693Sloosstatic int 551263693Sloosti_adc_detach(device_t dev) 552263693Sloos{ 553263693Sloos struct ti_adc_softc *sc; 554263693Sloos 555263693Sloos sc = device_get_softc(dev); 556263693Sloos 557263693Sloos /* Turn off the ADC. */ 558263693Sloos TI_ADC_LOCK(sc); 559263693Sloos ti_adc_reset(sc); 560263693Sloos ti_adc_setup(sc); 561263693Sloos TI_ADC_UNLOCK(sc); 562263693Sloos 563263693Sloos TI_ADC_LOCK_DESTROY(sc); 564263693Sloos 565263693Sloos if (sc->sc_intrhand) 566263693Sloos bus_teardown_intr(dev, sc->sc_irq_res, sc->sc_intrhand); 567263693Sloos if (sc->sc_irq_res) 568263693Sloos bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_irq_res); 569263693Sloos if (sc->sc_mem_res) 570263693Sloos bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res); 571263693Sloos 572263693Sloos return (bus_generic_detach(dev)); 573263693Sloos} 574263693Sloos 575263693Sloosstatic device_method_t ti_adc_methods[] = { 576263693Sloos DEVMETHOD(device_probe, ti_adc_probe), 577263693Sloos DEVMETHOD(device_attach, ti_adc_attach), 578263693Sloos DEVMETHOD(device_detach, ti_adc_detach), 579263693Sloos 580263693Sloos DEVMETHOD_END 581263693Sloos}; 582263693Sloos 583263693Sloosstatic driver_t ti_adc_driver = { 584263693Sloos "ti_adc", 585263693Sloos ti_adc_methods, 586263693Sloos sizeof(struct ti_adc_softc), 587263693Sloos}; 588263693Sloos 589263693Sloosstatic devclass_t ti_adc_devclass; 590263693Sloos 591263693SloosDRIVER_MODULE(ti_adc, simplebus, ti_adc_driver, ti_adc_devclass, 0, 0); 592263693SloosMODULE_VERSION(ti_adc, 1); 593263693SloosMODULE_DEPEND(ti_adc, simplebus, 1, 1, 1); 594