The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/arm/ti/ti_adc.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright 2014 Luiz Otavio O Souza <loos@freebsd.org>
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  *
   14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   24  * SUCH DAMAGE.
   25  */
   26 
   27 #include <sys/cdefs.h>
   28 __FBSDID("$FreeBSD: releng/10.2/sys/arm/ti/ti_adc.c 270238 2014-08-20 18:10:12Z loos $");
   29 
   30 #include <sys/param.h>
   31 #include <sys/systm.h>
   32 #include <sys/bus.h>
   33 
   34 #include <sys/kernel.h>
   35 #include <sys/limits.h>
   36 #include <sys/lock.h>
   37 #include <sys/module.h>
   38 #include <sys/mutex.h>
   39 #include <sys/resource.h>
   40 #include <sys/rman.h>
   41 #include <sys/sysctl.h>
   42 
   43 #include <machine/bus.h>
   44 
   45 #include <dev/ofw/openfirm.h>
   46 #include <dev/ofw/ofw_bus.h>
   47 #include <dev/ofw/ofw_bus_subr.h>
   48 
   49 #include <arm/ti/ti_prcm.h>
   50 #include <arm/ti/ti_adcreg.h>
   51 #include <arm/ti/ti_adcvar.h>
   52 
   53 /* Define our 8 steps, one for each input channel. */
   54 static struct ti_adc_input ti_adc_inputs[TI_ADC_NPINS] = {
   55         { .stepconfig = ADC_STEPCFG1, .stepdelay = ADC_STEPDLY1 },
   56         { .stepconfig = ADC_STEPCFG2, .stepdelay = ADC_STEPDLY2 },
   57         { .stepconfig = ADC_STEPCFG3, .stepdelay = ADC_STEPDLY3 },
   58         { .stepconfig = ADC_STEPCFG4, .stepdelay = ADC_STEPDLY4 },
   59         { .stepconfig = ADC_STEPCFG5, .stepdelay = ADC_STEPDLY5 },
   60         { .stepconfig = ADC_STEPCFG6, .stepdelay = ADC_STEPDLY6 },
   61         { .stepconfig = ADC_STEPCFG7, .stepdelay = ADC_STEPDLY7 },
   62         { .stepconfig = ADC_STEPCFG8, .stepdelay = ADC_STEPDLY8 },
   63 };
   64 
   65 static int ti_adc_samples[5] = { 0, 2, 4, 8, 16 };
   66 
   67 static void
   68 ti_adc_enable(struct ti_adc_softc *sc)
   69 {
   70 
   71         TI_ADC_LOCK_ASSERT(sc);
   72 
   73         if (sc->sc_last_state == 1)
   74                 return;
   75 
   76         /* Enable the FIFO0 threshold and the end of sequence interrupt. */
   77         ADC_WRITE4(sc, ADC_IRQENABLE_SET,
   78             ADC_IRQ_FIFO0_THRES | ADC_IRQ_END_OF_SEQ);
   79 
   80         /* Enable the ADC.  Run thru enabled steps, start the conversions. */
   81         ADC_WRITE4(sc, ADC_CTRL, ADC_READ4(sc, ADC_CTRL) | ADC_CTRL_ENABLE);
   82 
   83         sc->sc_last_state = 1;
   84 }
   85 
   86 static void
   87 ti_adc_disable(struct ti_adc_softc *sc)
   88 {
   89         int count;
   90         uint32_t data;
   91 
   92         TI_ADC_LOCK_ASSERT(sc);
   93 
   94         if (sc->sc_last_state == 0)
   95                 return;
   96 
   97         /* Disable all the enabled steps. */
   98         ADC_WRITE4(sc, ADC_STEPENABLE, 0);
   99 
  100         /* Disable the ADC. */
  101         ADC_WRITE4(sc, ADC_CTRL, ADC_READ4(sc, ADC_CTRL) & ~ADC_CTRL_ENABLE);
  102 
  103         /* Disable the FIFO0 threshold and the end of sequence interrupt. */
  104         ADC_WRITE4(sc, ADC_IRQENABLE_CLR,
  105             ADC_IRQ_FIFO0_THRES | ADC_IRQ_END_OF_SEQ);
  106 
  107         /* ACK any pending interrupt. */
  108         ADC_WRITE4(sc, ADC_IRQSTATUS, ADC_READ4(sc, ADC_IRQSTATUS));
  109 
  110         /* Drain the FIFO data. */
  111         count = ADC_READ4(sc, ADC_FIFO0COUNT) & ADC_FIFO_COUNT_MSK;
  112         while (count > 0) {
  113                 data = ADC_READ4(sc, ADC_FIFO0DATA);
  114                 count = ADC_READ4(sc, ADC_FIFO0COUNT) & ADC_FIFO_COUNT_MSK;
  115         }
  116 
  117         sc->sc_last_state = 0;
  118 }
  119 
  120 static int
  121 ti_adc_setup(struct ti_adc_softc *sc)
  122 {
  123         int ain;
  124         uint32_t enabled;
  125 
  126         TI_ADC_LOCK_ASSERT(sc);
  127 
  128         /* Check for enabled inputs. */
  129         enabled = 0;
  130         for (ain = 0; ain < TI_ADC_NPINS; ain++) {
  131                 if (ti_adc_inputs[ain].enable)
  132                         enabled |= (1U << (ain + 1));
  133         }
  134 
  135         /* Set the ADC global status. */
  136         if (enabled != 0) {
  137                 ti_adc_enable(sc);
  138                 /* Update the enabled steps. */
  139                 if (enabled != ADC_READ4(sc, ADC_STEPENABLE))
  140                         ADC_WRITE4(sc, ADC_STEPENABLE, enabled);
  141         } else
  142                 ti_adc_disable(sc);
  143 
  144         return (0);
  145 }
  146 
  147 static void
  148 ti_adc_input_setup(struct ti_adc_softc *sc, int32_t ain)
  149 {
  150         struct ti_adc_input *input;
  151         uint32_t reg, val;
  152 
  153         TI_ADC_LOCK_ASSERT(sc);
  154 
  155         input = &ti_adc_inputs[ain];
  156         reg = input->stepconfig;
  157         val = ADC_READ4(sc, reg);
  158 
  159         /* Set single ended operation. */
  160         val &= ~ADC_STEP_DIFF_CNTRL;
  161 
  162         /* Set the negative voltage reference. */
  163         val &= ~ADC_STEP_RFM_MSK;
  164         val |= ADC_STEP_RFM_VREFN << ADC_STEP_RFM_SHIFT;
  165 
  166         /* Set the positive voltage reference. */
  167         val &= ~ADC_STEP_RFP_MSK;
  168         val |= ADC_STEP_RFP_VREFP << ADC_STEP_RFP_SHIFT;
  169 
  170         /* Set the samples average. */
  171         val &= ~ADC_STEP_AVG_MSK;
  172         val |= input->samples << ADC_STEP_AVG_SHIFT;
  173 
  174         /* Select the desired input. */
  175         val &= ~ADC_STEP_INP_MSK;
  176         val |= ain << ADC_STEP_INP_SHIFT;
  177 
  178         /* Set the ADC to one-shot mode. */
  179         val &= ~ADC_STEP_MODE_MSK;
  180 
  181         ADC_WRITE4(sc, reg, val);
  182 }
  183 
  184 static void
  185 ti_adc_reset(struct ti_adc_softc *sc)
  186 {
  187         int ain;
  188 
  189         TI_ADC_LOCK_ASSERT(sc);
  190 
  191         /* Disable all the inputs. */
  192         for (ain = 0; ain < TI_ADC_NPINS; ain++)
  193                 ti_adc_inputs[ain].enable = 0;
  194 }
  195 
  196 static int
  197 ti_adc_clockdiv_proc(SYSCTL_HANDLER_ARGS)
  198 {
  199         int error, reg;
  200         struct ti_adc_softc *sc;
  201 
  202         sc = (struct ti_adc_softc *)arg1;
  203 
  204         TI_ADC_LOCK(sc);
  205         reg = (int)ADC_READ4(sc, ADC_CLKDIV) + 1;
  206         TI_ADC_UNLOCK(sc);
  207 
  208         error = sysctl_handle_int(oidp, &reg, sizeof(reg), req);
  209         if (error != 0 || req->newptr == NULL)
  210                 return (error);
  211 
  212         /*
  213          * The actual written value is the prescaler setting - 1.
  214          * Enforce a minimum value of 10 (i.e. 9) which limits the maximum
  215          * ADC clock to ~2.4Mhz (CLK_M_OSC / 10).
  216          */
  217         reg--;
  218         if (reg < 9)
  219                 reg = 9;
  220         if (reg > USHRT_MAX)
  221                 reg = USHRT_MAX;
  222 
  223         TI_ADC_LOCK(sc);
  224         /* Disable the ADC. */
  225         ti_adc_disable(sc);
  226         /* Update the ADC prescaler setting. */
  227         ADC_WRITE4(sc, ADC_CLKDIV, reg);
  228         /* Enable the ADC again. */
  229         ti_adc_setup(sc);
  230         TI_ADC_UNLOCK(sc);
  231 
  232         return (0);
  233 }
  234 
  235 static int
  236 ti_adc_enable_proc(SYSCTL_HANDLER_ARGS)
  237 {
  238         int error;
  239         int32_t enable;
  240         struct ti_adc_softc *sc;
  241         struct ti_adc_input *input;
  242 
  243         input = (struct ti_adc_input *)arg1;
  244         sc = input->sc;
  245 
  246         enable = input->enable;
  247         error = sysctl_handle_int(oidp, &enable, sizeof(enable),
  248             req);
  249         if (error != 0 || req->newptr == NULL)
  250                 return (error);
  251 
  252         if (enable)
  253                 enable = 1;
  254 
  255         TI_ADC_LOCK(sc);
  256         /* Setup the ADC as needed. */
  257         if (input->enable != enable) {
  258                 input->enable = enable;
  259                 ti_adc_setup(sc);
  260                 if (input->enable == 0)
  261                         input->value = 0;
  262         }
  263         TI_ADC_UNLOCK(sc);
  264 
  265         return (0);
  266 }
  267 
  268 static int
  269 ti_adc_open_delay_proc(SYSCTL_HANDLER_ARGS)
  270 {
  271         int error, reg;
  272         struct ti_adc_softc *sc;
  273         struct ti_adc_input *input;
  274 
  275         input = (struct ti_adc_input *)arg1;
  276         sc = input->sc;
  277 
  278         TI_ADC_LOCK(sc);
  279         reg = (int)ADC_READ4(sc, input->stepdelay) & ADC_STEP_OPEN_DELAY;
  280         TI_ADC_UNLOCK(sc);
  281 
  282         error = sysctl_handle_int(oidp, &reg, sizeof(reg), req);
  283         if (error != 0 || req->newptr == NULL)
  284                 return (error);
  285 
  286         if (reg < 0)
  287                 reg = 0;
  288 
  289         TI_ADC_LOCK(sc);
  290         ADC_WRITE4(sc, input->stepdelay, reg & ADC_STEP_OPEN_DELAY);
  291         TI_ADC_UNLOCK(sc);
  292 
  293         return (0);
  294 }
  295 
  296 static int
  297 ti_adc_samples_avg_proc(SYSCTL_HANDLER_ARGS)
  298 {
  299         int error, samples, i;
  300         struct ti_adc_softc *sc;
  301         struct ti_adc_input *input;
  302 
  303         input = (struct ti_adc_input *)arg1;
  304         sc = input->sc;
  305 
  306         if (input->samples > nitems(ti_adc_samples))
  307                 input->samples = nitems(ti_adc_samples);
  308         samples = ti_adc_samples[input->samples];
  309 
  310         error = sysctl_handle_int(oidp, &samples, 0, req);
  311         if (error != 0 || req->newptr == NULL)
  312                 return (error);
  313 
  314         TI_ADC_LOCK(sc);
  315         if (samples != ti_adc_samples[input->samples]) {
  316                 input->samples = 0;
  317                 for (i = 0; i < nitems(ti_adc_samples); i++)
  318                         if (samples >= ti_adc_samples[i])
  319                                 input->samples = i;
  320                 ti_adc_input_setup(sc, input->input);
  321         }
  322         TI_ADC_UNLOCK(sc);
  323 
  324         return (error);
  325 }
  326 
  327 static void
  328 ti_adc_read_data(struct ti_adc_softc *sc)
  329 {
  330         int count, ain;
  331         struct ti_adc_input *input;
  332         uint32_t data;
  333 
  334         TI_ADC_LOCK_ASSERT(sc);
  335 
  336         /* Read the available data. */
  337         count = ADC_READ4(sc, ADC_FIFO0COUNT) & ADC_FIFO_COUNT_MSK;
  338         while (count > 0) {
  339                 data = ADC_READ4(sc, ADC_FIFO0DATA);
  340                 ain = (data & ADC_FIFO_STEP_ID_MSK) >> ADC_FIFO_STEP_ID_SHIFT;
  341                 input = &ti_adc_inputs[ain];
  342                 if (input->enable == 0)
  343                         input->value = 0;
  344                 else
  345                         input->value = (int32_t)(data & ADC_FIFO_DATA_MSK);
  346                 count = ADC_READ4(sc, ADC_FIFO0COUNT) & ADC_FIFO_COUNT_MSK;
  347         }
  348 }
  349 
  350 static void
  351 ti_adc_intr(void *arg)
  352 {
  353         struct ti_adc_softc *sc;
  354         uint32_t status;
  355 
  356         sc = (struct ti_adc_softc *)arg;
  357 
  358         status = ADC_READ4(sc, ADC_IRQSTATUS);
  359         if (status == 0)
  360                 return;
  361         if (status & ~(ADC_IRQ_FIFO0_THRES | ADC_IRQ_END_OF_SEQ))
  362                 device_printf(sc->sc_dev, "stray interrupt: %#x\n", status);
  363 
  364         TI_ADC_LOCK(sc);
  365         /* ACK the interrupt. */
  366         ADC_WRITE4(sc, ADC_IRQSTATUS, status);
  367 
  368         /* Read the available data. */
  369         if (status & ADC_IRQ_FIFO0_THRES)
  370                 ti_adc_read_data(sc);
  371 
  372         /* Start the next conversion ? */
  373         if (status & ADC_IRQ_END_OF_SEQ)
  374                 ti_adc_setup(sc);
  375         TI_ADC_UNLOCK(sc);
  376 }
  377 
  378 static void
  379 ti_adc_sysctl_init(struct ti_adc_softc *sc)
  380 {
  381         char pinbuf[3];
  382         struct sysctl_ctx_list *ctx;
  383         struct sysctl_oid *tree_node, *inp_node, *inpN_node;
  384         struct sysctl_oid_list *tree, *inp_tree, *inpN_tree;
  385         int ain;
  386 
  387         /*
  388          * Add per-pin sysctl tree/handlers.
  389          */
  390         ctx = device_get_sysctl_ctx(sc->sc_dev);
  391         tree_node = device_get_sysctl_tree(sc->sc_dev);
  392         tree = SYSCTL_CHILDREN(tree_node);
  393         SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "clockdiv",
  394             CTLFLAG_RW | CTLTYPE_UINT,  sc, 0,
  395             ti_adc_clockdiv_proc, "IU", "ADC clock prescaler");
  396         inp_node = SYSCTL_ADD_NODE(ctx, tree, OID_AUTO, "ain",
  397             CTLFLAG_RD, NULL, "ADC inputs");
  398         inp_tree = SYSCTL_CHILDREN(inp_node);
  399 
  400         for (ain = 0; ain < TI_ADC_NPINS; ain++) {
  401 
  402                 snprintf(pinbuf, sizeof(pinbuf), "%d", ain);
  403                 inpN_node = SYSCTL_ADD_NODE(ctx, inp_tree, OID_AUTO, pinbuf,
  404                     CTLFLAG_RD, NULL, "ADC input");
  405                 inpN_tree = SYSCTL_CHILDREN(inpN_node);
  406 
  407                 SYSCTL_ADD_PROC(ctx, inpN_tree, OID_AUTO, "enable",
  408                     CTLFLAG_RW | CTLTYPE_UINT, &ti_adc_inputs[ain], 0,
  409                     ti_adc_enable_proc, "IU", "Enable ADC input");
  410                 SYSCTL_ADD_PROC(ctx, inpN_tree, OID_AUTO, "open_delay",
  411                     CTLFLAG_RW | CTLTYPE_UINT,  &ti_adc_inputs[ain], 0,
  412                     ti_adc_open_delay_proc, "IU", "ADC open delay");
  413                 SYSCTL_ADD_PROC(ctx, inpN_tree, OID_AUTO, "samples_avg",
  414                     CTLFLAG_RW | CTLTYPE_UINT,  &ti_adc_inputs[ain], 0,
  415                     ti_adc_samples_avg_proc, "IU", "ADC samples average");
  416                 SYSCTL_ADD_INT(ctx, inpN_tree, OID_AUTO, "input",
  417                     CTLFLAG_RD, &ti_adc_inputs[ain].value, 0,
  418                     "Converted raw value for the ADC input");
  419         }
  420 }
  421 
  422 static void
  423 ti_adc_inputs_init(struct ti_adc_softc *sc)
  424 {
  425         int ain;
  426         struct ti_adc_input *input;
  427 
  428         TI_ADC_LOCK(sc);
  429         for (ain = 0; ain < TI_ADC_NPINS; ain++) {
  430                 input = &ti_adc_inputs[ain];
  431                 input->sc = sc;
  432                 input->input = ain;
  433                 input->value = 0;
  434                 input->enable = 0;
  435                 input->samples = 0;
  436                 ti_adc_input_setup(sc, ain);
  437         }
  438         TI_ADC_UNLOCK(sc);
  439 }
  440 
  441 static void
  442 ti_adc_idlestep_init(struct ti_adc_softc *sc)
  443 {
  444         uint32_t val;
  445 
  446         val = ADC_READ4(sc, ADC_IDLECONFIG);
  447 
  448         /* Set single ended operation. */
  449         val &= ~ADC_STEP_DIFF_CNTRL;
  450 
  451         /* Set the negative voltage reference. */
  452         val &= ~ADC_STEP_RFM_MSK;
  453         val |= ADC_STEP_RFM_VREFN << ADC_STEP_RFM_SHIFT;
  454 
  455         /* Set the positive voltage reference. */
  456         val &= ~ADC_STEP_RFP_MSK;
  457         val |= ADC_STEP_RFP_VREFP << ADC_STEP_RFP_SHIFT;
  458 
  459         /* Connect the input to VREFN. */
  460         val &= ~ADC_STEP_INP_MSK;
  461         val |= ADC_STEP_IN_VREFN << ADC_STEP_INP_SHIFT;
  462 
  463         ADC_WRITE4(sc, ADC_IDLECONFIG, val);
  464 }
  465 
  466 static int
  467 ti_adc_probe(device_t dev)
  468 {
  469 
  470         if (!ofw_bus_is_compatible(dev, "ti,adc"))
  471                 return (ENXIO);
  472         device_set_desc(dev, "TI ADC controller");
  473 
  474         return (BUS_PROBE_DEFAULT);
  475 }
  476 
  477 static int
  478 ti_adc_attach(device_t dev)
  479 {
  480         int err, rid;
  481         struct ti_adc_softc *sc;
  482         uint32_t reg, rev;
  483 
  484         sc = device_get_softc(dev);
  485         sc->sc_dev = dev;
  486 
  487         rid = 0;
  488         sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
  489             RF_ACTIVE);
  490         if (!sc->sc_mem_res) {
  491                 device_printf(dev, "cannot allocate memory window\n");
  492                 return (ENXIO);
  493         }
  494 
  495         rid = 0;
  496         sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
  497             RF_ACTIVE);
  498         if (!sc->sc_irq_res) {
  499                 bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res);
  500                 device_printf(dev, "cannot allocate interrupt\n");
  501                 return (ENXIO);
  502         }
  503 
  504         if (bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_MISC | INTR_MPSAFE,
  505             NULL, ti_adc_intr, sc, &sc->sc_intrhand) != 0) {
  506                 bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_irq_res);
  507                 bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res);
  508                 device_printf(dev, "Unable to setup the irq handler.\n");
  509                 return (ENXIO);
  510         }
  511 
  512         /* Activate the ADC_TSC module. */
  513         err = ti_prcm_clk_enable(TSC_ADC_CLK);
  514         if (err)
  515                 return (err);
  516 
  517         /* Check the ADC revision. */
  518         rev = ADC_READ4(sc, ADC_REVISION);
  519         device_printf(dev,
  520             "scheme: %#x func: %#x rtl: %d rev: %d.%d custom rev: %d\n",
  521             (rev & ADC_REV_SCHEME_MSK) >> ADC_REV_SCHEME_SHIFT,
  522             (rev & ADC_REV_FUNC_MSK) >> ADC_REV_FUNC_SHIFT,
  523             (rev & ADC_REV_RTL_MSK) >> ADC_REV_RTL_SHIFT,
  524             (rev & ADC_REV_MAJOR_MSK) >> ADC_REV_MAJOR_SHIFT,
  525             rev & ADC_REV_MINOR_MSK,
  526             (rev & ADC_REV_CUSTOM_MSK) >> ADC_REV_CUSTOM_SHIFT);
  527 
  528         /*
  529          * Disable the step write protect and make it store the step ID for
  530          * the captured data on FIFO.
  531          */
  532         reg = ADC_READ4(sc, ADC_CTRL);
  533         ADC_WRITE4(sc, ADC_CTRL, reg | ADC_CTRL_STEP_WP | ADC_CTRL_STEP_ID);
  534 
  535         /*
  536          * Set the ADC prescaler to 2400 (yes, the actual value written here
  537          * is 2400 - 1).
  538          * This sets the ADC clock to ~10Khz (CLK_M_OSC / 2400).
  539          */
  540         ADC_WRITE4(sc, ADC_CLKDIV, 2399);
  541 
  542         TI_ADC_LOCK_INIT(sc);
  543 
  544         ti_adc_idlestep_init(sc);
  545         ti_adc_inputs_init(sc);
  546         ti_adc_sysctl_init(sc);
  547 
  548         return (0);
  549 }
  550 
  551 static int
  552 ti_adc_detach(device_t dev)
  553 {
  554         struct ti_adc_softc *sc;
  555 
  556         sc = device_get_softc(dev);
  557 
  558         /* Turn off the ADC. */
  559         TI_ADC_LOCK(sc);
  560         ti_adc_reset(sc);
  561         ti_adc_setup(sc);
  562         TI_ADC_UNLOCK(sc);
  563 
  564         TI_ADC_LOCK_DESTROY(sc);
  565 
  566         if (sc->sc_intrhand)
  567                 bus_teardown_intr(dev, sc->sc_irq_res, sc->sc_intrhand);
  568         if (sc->sc_irq_res)
  569                 bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_irq_res);
  570         if (sc->sc_mem_res)
  571                 bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res);
  572 
  573         return (bus_generic_detach(dev));
  574 }
  575 
  576 static device_method_t ti_adc_methods[] = {
  577         DEVMETHOD(device_probe,         ti_adc_probe),
  578         DEVMETHOD(device_attach,        ti_adc_attach),
  579         DEVMETHOD(device_detach,        ti_adc_detach),
  580 
  581         DEVMETHOD_END
  582 };
  583 
  584 static driver_t ti_adc_driver = {
  585         "ti_adc",
  586         ti_adc_methods,
  587         sizeof(struct ti_adc_softc),
  588 };
  589 
  590 static devclass_t ti_adc_devclass;
  591 
  592 DRIVER_MODULE(ti_adc, simplebus, ti_adc_driver, ti_adc_devclass, 0, 0);
  593 MODULE_VERSION(ti_adc, 1);
  594 MODULE_DEPEND(ti_adc, simplebus, 1, 1, 1);

Cache object: 1a8a9bb2038748ef82d283d3a1d2184f


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.