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/dev/ic/w83l518d_sdmmc.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 /* $NetBSD: w83l518d_sdmmc.c,v 1.1.2.3 2010/11/21 21:44:07 riz Exp $ */
    2 
    3 /*
    4  * Copyright (c) 2009 Jared D. McNeill <jmcneill@invisible.ca>
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. The name of the author may not be used to endorse or promote products
   13  *    derived from this software without specific prior written permission.
   14  *
   15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
   20  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   21  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
   22  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   23  * 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 __KERNEL_RCSID(0, "$NetBSD: w83l518d_sdmmc.c,v 1.1.2.3 2010/11/21 21:44:07 riz Exp $");
   30 
   31 #include <sys/param.h>
   32 #include <sys/kernel.h>
   33 #include <sys/systm.h>
   34 #include <sys/errno.h>
   35 #include <sys/ioctl.h>
   36 #include <sys/syslog.h>
   37 #include <sys/device.h>
   38 #include <sys/proc.h>
   39 
   40 #include <sys/bus.h>
   41 
   42 #include <dev/sdmmc/sdmmcvar.h>
   43 #include <dev/sdmmc/sdmmcchip.h>
   44 #include <dev/sdmmc/sdmmc_ioreg.h>
   45 
   46 #include <dev/isa/isavar.h>
   47 #include <dev/isa/isadmavar.h>
   48 
   49 #include <dev/ic/w83l518dreg.h>
   50 #include <dev/ic/w83l518dvar.h>
   51 #include <dev/ic/w83l518d_sdmmc.h>
   52 
   53 /* #define WB_SDMMC_DEBUG */
   54 
   55 #ifdef WB_SDMMC_DEBUG
   56 static int wb_sdmmc_debug = 1;
   57 #else
   58 static int wb_sdmmc_debug = 0;
   59 #endif
   60 
   61 #if defined(__NetBSD__) && __NetBSD_Version__ < 599000600
   62 #define snprintb(b, l, f, v) bitmask_snprintf((v), (f), (b), (l))
   63 #endif
   64 
   65 #define REPORT(_wb, ...)                                        \
   66         if (wb_sdmmc_debug > 0)                                 \
   67                 aprint_normal_dev(((struct wb_softc *)(_wb))->wb_dev, \
   68                                   __VA_ARGS__)
   69 
   70 static int      wb_sdmmc_host_reset(sdmmc_chipset_handle_t);
   71 static uint32_t wb_sdmmc_host_ocr(sdmmc_chipset_handle_t);
   72 static int      wb_sdmmc_host_maxblklen(sdmmc_chipset_handle_t);
   73 static int      wb_sdmmc_card_detect(sdmmc_chipset_handle_t);
   74 static int      wb_sdmmc_write_protect(sdmmc_chipset_handle_t);
   75 static int      wb_sdmmc_bus_power(sdmmc_chipset_handle_t, uint32_t);
   76 static int      wb_sdmmc_bus_clock(sdmmc_chipset_handle_t, int);
   77 static int      wb_sdmmc_bus_width(sdmmc_chipset_handle_t, int);
   78 static void     wb_sdmmc_exec_command(sdmmc_chipset_handle_t,
   79                                       struct sdmmc_command *);
   80 static void     wb_sdmmc_card_enable_intr(sdmmc_chipset_handle_t, int);
   81 static void     wb_sdmmc_card_intr_ack(sdmmc_chipset_handle_t);
   82 
   83 static struct sdmmc_chip_functions wb_sdmmc_chip_functions = {
   84         .host_reset = wb_sdmmc_host_reset,
   85         .host_ocr = wb_sdmmc_host_ocr,
   86         .host_maxblklen = wb_sdmmc_host_maxblklen,
   87         .card_detect = wb_sdmmc_card_detect,
   88         .write_protect = wb_sdmmc_write_protect,
   89         .bus_power = wb_sdmmc_bus_power,
   90         .bus_clock = wb_sdmmc_bus_clock,
   91         .bus_width = wb_sdmmc_bus_width,
   92         .exec_command = wb_sdmmc_exec_command,
   93         .card_enable_intr = wb_sdmmc_card_enable_intr,
   94         .card_intr_ack = wb_sdmmc_card_intr_ack,
   95 };
   96 
   97 static void
   98 wb_sdmmc_read_data(struct wb_softc *wb, uint8_t *data, int len)
   99 {
  100         bus_space_read_multi_1(wb->wb_iot, wb->wb_ioh, WB_SD_FIFO, data, len);
  101 }
  102 
  103 static void
  104 wb_sdmmc_write_data(struct wb_softc *wb, uint8_t *data, int len)
  105 {
  106         bus_space_write_multi_1(wb->wb_iot, wb->wb_ioh, WB_SD_FIFO, data, len);
  107 }
  108 
  109 static void
  110 wb_sdmmc_discover(void *opaque)
  111 {
  112         struct wb_softc *wb = opaque;
  113 
  114         REPORT(wb, "TRACE: discover(wb)\n");
  115 
  116         sdmmc_needs_discover(wb->wb_sdmmc_dev);
  117 }
  118 
  119 static bool
  120 wb_sdmmc_enable(struct wb_softc *wb)
  121 {
  122         int i = 5000;
  123 
  124         REPORT(wb, "TRACE: enable(wb)\n");
  125 
  126         /* put the device in a known state */
  127         wb_idx_write(wb, WB_INDEX_SETUP, WB_SETUP_SOFT_RST);
  128         while (--i > 0 && wb_idx_read(wb, WB_INDEX_SETUP) & WB_SETUP_SOFT_RST)
  129                 delay(100);
  130         if (i == 0) {
  131                 aprint_error_dev(wb->wb_dev, "timeout resetting device\n");
  132                 return false;
  133         }
  134         wb_idx_write(wb, WB_INDEX_CLK, wb->wb_sdmmc_clk);
  135         wb_idx_write(wb, WB_INDEX_FIFOEN, 0);
  136         wb_idx_write(wb, WB_INDEX_DMA, 0);
  137         wb_idx_write(wb, WB_INDEX_PBSMSB, 0);
  138         wb_idx_write(wb, WB_INDEX_PBSLSB, 0);
  139         /* drain FIFO */
  140         while ((wb_read(wb, WB_SD_FIFOSTS) & WB_FIFO_EMPTY) == 0)
  141                 wb_read(wb, WB_SD_FIFO);
  142 
  143         wb_write(wb, WB_SD_CSR, 0);
  144 
  145         wb_write(wb, WB_SD_INTCTL, WB_INT_DEFAULT);
  146 
  147         wb_sdmmc_card_detect(wb);
  148 
  149         return true;
  150 }
  151 
  152 static bool
  153 wb_sdmmc_disable(struct wb_softc *wb)
  154 {
  155         uint8_t val;
  156 
  157         REPORT(wb, "TRACE: disable(wb)\n");
  158 
  159         val = wb_read(wb, WB_SD_CSR);
  160         val |= WB_CSR_POWER_N;
  161         wb_write(wb, WB_SD_CSR, val);
  162 
  163         return true;
  164 }
  165 
  166 void
  167 wb_sdmmc_attach(struct wb_softc *wb)
  168 {
  169         struct sdmmcbus_attach_args saa;
  170 
  171         callout_init(&wb->wb_sdmmc_callout, 0);
  172         callout_setfunc(&wb->wb_sdmmc_callout, wb_sdmmc_discover, wb);
  173 
  174         wb->wb_sdmmc_width = 1;
  175         wb->wb_sdmmc_clk = WB_CLK_375K;
  176 
  177         if (wb_sdmmc_enable(wb) == false)
  178                 return;
  179 
  180         memset(&saa, 0, sizeof(saa));
  181         saa.saa_busname = "sdmmc";
  182         saa.saa_sct = &wb_sdmmc_chip_functions;
  183         saa.saa_sch = wb;
  184         saa.saa_clkmin = 375;
  185         saa.saa_clkmax = 24000;
  186         saa.saa_caps = SMC_CAPS_4BIT_MODE;
  187 
  188         wb->wb_sdmmc_dev = config_found(wb->wb_dev, &saa, NULL);
  189 }
  190 
  191 int
  192 wb_sdmmc_detach(struct wb_softc *wb, int flags)
  193 {
  194         int rv;
  195 
  196         if (wb->wb_sdmmc_dev) {
  197                 rv = config_detach(wb->wb_sdmmc_dev, flags);
  198                 if (rv)
  199                         return rv;
  200         }
  201         wb_sdmmc_disable(wb);
  202 
  203         callout_halt(&wb->wb_sdmmc_callout, NULL);
  204         callout_destroy(&wb->wb_sdmmc_callout);
  205 
  206         return 0;
  207 }
  208 
  209 /*
  210  * SD/MMC interface
  211  */
  212 static int
  213 wb_sdmmc_host_reset(sdmmc_chipset_handle_t sch)
  214 {
  215         REPORT(sch, "TRACE: sdmmc/host_reset(wb)\n");
  216 
  217         return 0;
  218 }
  219 
  220 static uint32_t
  221 wb_sdmmc_host_ocr(sdmmc_chipset_handle_t sch)
  222 {
  223         REPORT(sch, "TRACE: sdmmc/host_ocr(wb)\n");
  224 
  225         return MMC_OCR_3_2V_3_3V | MMC_OCR_3_3V_3_4V;
  226 }
  227 
  228 static int
  229 wb_sdmmc_host_maxblklen(sdmmc_chipset_handle_t sch)
  230 {
  231         REPORT(sch, "TRACE: sdmmc/host_maxblklen(wb)\n");
  232 
  233         return 512;     /* XXX */
  234 }
  235 
  236 static int
  237 wb_sdmmc_card_detect(sdmmc_chipset_handle_t sch)
  238 {
  239         struct wb_softc *wb = sch;
  240         int rv;
  241 
  242         wb_led(wb, true);
  243         rv = (wb_read(wb, WB_SD_CSR) & WB_CSR_CARD_PRESENT) ? 1 : 0;
  244         wb_led(wb, false);
  245 
  246         REPORT(wb, "TRACE: sdmmc/card_detect(wb) -> %d\n", rv);
  247 
  248         return rv;
  249 }
  250 
  251 static int
  252 wb_sdmmc_write_protect(sdmmc_chipset_handle_t sch)
  253 {
  254         struct wb_softc *wb = sch;
  255         int rv;
  256 
  257         wb_led(wb, true);
  258         rv = (wb_read(wb, WB_SD_CSR) & WB_CSR_WRITE_PROTECT) ? 1 : 0;
  259         wb_led(wb, false);
  260 
  261         REPORT(wb, "TRACE: sdmmc/write_protect(wb) -> %d\n", rv);
  262 
  263         return rv;
  264 }
  265 
  266 static int
  267 wb_sdmmc_bus_power(sdmmc_chipset_handle_t sch, uint32_t ocr)
  268 {
  269         REPORT(sch, "TRACE: sdmmc/bus_power(wb, ocr=%d)\n", ocr);
  270 
  271         return 0;
  272 }
  273 
  274 static int
  275 wb_sdmmc_bus_clock(sdmmc_chipset_handle_t sch, int freq)
  276 {
  277         struct wb_softc *wb = sch;
  278         uint8_t clk;
  279 
  280         REPORT(wb, "TRACE: sdmmc/bus_clock(wb, freq=%d)\n", freq);
  281 
  282         if (freq >= 24000)
  283                 clk = WB_CLK_24M;
  284         else if (freq >= 16000)
  285                 clk = WB_CLK_16M;
  286         else if (freq >= 12000)
  287                 clk = WB_CLK_12M;
  288         else
  289                 clk = WB_CLK_375K;
  290 
  291         wb->wb_sdmmc_clk = clk;
  292 
  293         if (wb_idx_read(wb, WB_INDEX_CLK) != clk)
  294                 wb_idx_write(wb, WB_INDEX_CLK, clk);
  295 
  296         return 0;
  297 }
  298 
  299 static int
  300 wb_sdmmc_bus_width(sdmmc_chipset_handle_t sch, int width)
  301 {
  302         struct wb_softc *wb = sch;
  303 
  304         REPORT(wb, "TRACE: sdmmc/bus_width(wb, width=%d)\n", width);
  305 
  306         if (width != 1 && width != 4)
  307                 return 1;
  308 
  309         wb->wb_sdmmc_width = width;
  310 
  311         return 0;
  312 }
  313 
  314 static void
  315 wb_sdmmc_rsp_read_long(struct wb_softc *wb, struct sdmmc_command *cmd)
  316 {
  317         uint8_t *p = (uint8_t *)cmd->c_resp;
  318         int i;
  319 
  320         if (wb_idx_read(wb, WB_INDEX_RESPLEN) != 1) {
  321                 cmd->c_error = ENXIO;
  322                 return;
  323         }
  324 
  325         for (i = 12; i >= 0; i -= 4) {
  326                 p[3] = wb_idx_read(wb, WB_INDEX_RESP(i + 0));
  327                 p[2] = wb_idx_read(wb, WB_INDEX_RESP(i + 1));
  328                 p[1] = wb_idx_read(wb, WB_INDEX_RESP(i + 2));
  329                 p[0] = wb_idx_read(wb, WB_INDEX_RESP(i + 3));
  330                 p += 4;
  331         }
  332 }
  333 
  334 static void
  335 wb_sdmmc_rsp_read_short(struct wb_softc *wb, struct sdmmc_command *cmd)
  336 {
  337         uint8_t *p = (uint8_t *)cmd->c_resp;
  338 
  339         if (wb_idx_read(wb, WB_INDEX_RESPLEN) != 0) {
  340                 cmd->c_error = ENXIO;
  341                 return;
  342         }
  343 
  344         p[3] = wb_idx_read(wb, WB_INDEX_RESP(12));
  345         p[2] = wb_idx_read(wb, WB_INDEX_RESP(13));
  346         p[1] = wb_idx_read(wb, WB_INDEX_RESP(14));
  347         p[0] = wb_idx_read(wb, WB_INDEX_RESP(15));
  348 }
  349 
  350 static int
  351 wb_sdmmc_transfer_data(struct wb_softc *wb, struct sdmmc_command *cmd)
  352 {
  353         uint8_t fifosts;
  354         int datalen, retry = 5000;
  355 
  356         if (wb->wb_sdmmc_intsts & WB_INT_CARD)
  357                 return EIO;
  358 
  359         fifosts = wb_read(wb, WB_SD_FIFOSTS);
  360         if (ISSET(cmd->c_flags, SCF_CMD_READ)) {
  361                 if (fifosts & WB_FIFO_EMPTY) {
  362                         while (--retry > 0) {
  363                                 fifosts = wb_read(wb, WB_SD_FIFOSTS);
  364                                 if ((fifosts & WB_FIFO_EMPTY) == 0)
  365                                         break;
  366                                 delay(100);
  367                         }
  368                         if (retry == 0)
  369                                 return EBUSY;
  370                 }
  371 
  372                 if (fifosts & WB_FIFO_FULL)
  373                         datalen = 16;
  374                 else
  375                         datalen = fifosts & WB_FIFO_DEPTH_MASK;
  376         } else {
  377                 if (fifosts & WB_FIFO_FULL) {
  378                         while (--retry > 0) {
  379                                 fifosts = wb_read(wb, WB_SD_FIFOSTS);
  380                                 if ((fifosts & WB_FIFO_FULL) == 0)
  381                                         break;
  382                                 delay(100);
  383                         }
  384                         if (retry == 0)
  385                                 return EBUSY;
  386                 }
  387 
  388                 if (fifosts & WB_FIFO_EMPTY)
  389                         datalen = 16;
  390                 else
  391                         datalen = 16 - (fifosts & WB_FIFO_DEPTH_MASK);
  392         }
  393 
  394         datalen = MIN(datalen, cmd->c_resid);
  395         if (datalen > 0) {
  396                 if (ISSET(cmd->c_flags, SCF_CMD_READ))
  397                         wb_sdmmc_read_data(wb, cmd->c_buf, datalen);
  398                 else
  399                         wb_sdmmc_write_data(wb, cmd->c_buf, datalen);
  400 
  401                 cmd->c_buf += datalen;
  402                 cmd->c_resid -= datalen;
  403         }
  404 
  405         return 0;
  406 }
  407 
  408 static void
  409 wb_sdmmc_exec_command(sdmmc_chipset_handle_t sch, struct sdmmc_command *cmd)
  410 {
  411         static const int opcodes[] = {
  412                 11, 17, 18, 20, 24, 25, 26, 27, 30, 42, 51, 56
  413         };
  414         struct wb_softc *wb = sch;
  415         uint8_t val;
  416         int blklen;
  417         int error;
  418         int i, retry;
  419         int s;
  420 
  421         REPORT(wb, "TRACE: sdmmc/exec_command(wb, cmd) "
  422             "opcode %d flags 0x%x data %p datalen %d\n",
  423             cmd->c_opcode, cmd->c_flags, cmd->c_data, cmd->c_datalen);
  424 
  425         if (cmd->c_datalen > 0) {
  426                 /* controller only supports a select number of data opcodes */
  427                 for (i = 0; i < __arraycount(opcodes); i++)
  428                         if (opcodes[i] == cmd->c_opcode)
  429                                 break;
  430                 if (i == __arraycount(opcodes)) {
  431                         cmd->c_error = EINVAL;
  432                         goto done;
  433                 }
  434 
  435                 /* Fragment the data into proper blocks */
  436                 blklen = MIN(cmd->c_datalen, cmd->c_blklen);
  437 
  438                 if (cmd->c_datalen % blklen > 0) {
  439                         aprint_error_dev(wb->wb_dev,
  440                             "data is not a multiple of %u bytes\n", blklen);
  441                         cmd->c_error = EINVAL;
  442                         goto done;
  443                 }
  444 
  445                 /* setup block size registers */
  446                 blklen = blklen + 2 * wb->wb_sdmmc_width;
  447                 wb_idx_write(wb, WB_INDEX_PBSMSB,
  448                     ((blklen >> 4) & 0xf0) | (wb->wb_sdmmc_width / 4));
  449                 wb_idx_write(wb, WB_INDEX_PBSLSB, blklen & 0xff);
  450 
  451                 /* clear FIFO */
  452                 val = wb_idx_read(wb, WB_INDEX_SETUP);
  453                 val |= WB_SETUP_FIFO_RST;
  454                 wb_idx_write(wb, WB_INDEX_SETUP, val);
  455                 while (wb_idx_read(wb, WB_INDEX_SETUP) & WB_SETUP_FIFO_RST)
  456                         ;
  457 
  458                 cmd->c_resid = cmd->c_datalen;
  459                 cmd->c_buf = cmd->c_data;
  460 
  461                 /* setup FIFO thresholds */
  462                 if (ISSET(cmd->c_flags, SCF_CMD_READ))
  463                         wb_idx_write(wb, WB_INDEX_FIFOEN, WB_FIFOEN_FULL | 8);
  464                 else {
  465                         wb_idx_write(wb, WB_INDEX_FIFOEN, WB_FIFOEN_EMPTY | 8);
  466 
  467                         /* pre-fill the FIFO on write */
  468                         error = wb_sdmmc_transfer_data(wb, cmd);
  469                         if (error) {
  470                                 cmd->c_error = error;
  471                                 goto done;
  472                         }
  473                 }
  474         }
  475 
  476         s = splsdmmc();
  477         wb->wb_sdmmc_intsts = 0;
  478         wb_write(wb, WB_SD_COMMAND, cmd->c_opcode);
  479         wb_write(wb, WB_SD_COMMAND, (cmd->c_arg >> 24) & 0xff);
  480         wb_write(wb, WB_SD_COMMAND, (cmd->c_arg >> 16) & 0xff);
  481         wb_write(wb, WB_SD_COMMAND, (cmd->c_arg >> 8) & 0xff);
  482         wb_write(wb, WB_SD_COMMAND, (cmd->c_arg >> 0) & 0xff);
  483         splx(s);
  484 
  485         retry = 100000;
  486         while (wb_idx_read(wb, WB_INDEX_STATUS) & WB_STATUS_CARD_TRAFFIC) {
  487                 if (--retry == 0)
  488                         break;
  489                 delay(1);
  490         }
  491         if (wb_idx_read(wb, WB_INDEX_STATUS) & WB_STATUS_CARD_TRAFFIC) {
  492                 REPORT(wb,
  493                     "command timed out, WB_INDEX_STATUS = 0x%02x\n",
  494                     wb_idx_read(wb, WB_INDEX_STATUS));
  495                 cmd->c_error = ETIMEDOUT;
  496                 goto done;
  497         }
  498 
  499         if (ISSET(cmd->c_flags, SCF_RSP_PRESENT)) {
  500                 if (wb->wb_sdmmc_intsts & WB_INT_TIMEOUT) {
  501                         cmd->c_error = ETIMEDOUT;
  502                         goto done;
  503                 }
  504 
  505                 if (ISSET(cmd->c_flags, SCF_RSP_136))
  506                         wb_sdmmc_rsp_read_long(wb, cmd);
  507                 else
  508                         wb_sdmmc_rsp_read_short(wb, cmd);
  509         }
  510 
  511         if (cmd->c_error == 0 && cmd->c_datalen > 0) {
  512                 wb_led(wb, true);
  513                 while (cmd->c_resid > 0) {
  514                         error = wb_sdmmc_transfer_data(wb, cmd);
  515                         if (error) {
  516                                 cmd->c_error = error;
  517                                 break;
  518                         }
  519                 }
  520                 wb_led(wb, false);
  521         }
  522 
  523 done:
  524         SET(cmd->c_flags, SCF_ITSDONE);
  525 
  526         if (cmd->c_error) {
  527                 REPORT(wb,
  528                     "cmd error = %d, op = %d [%s] "
  529                     "blklen %d datalen %d resid %d\n",
  530                     cmd->c_error, cmd->c_opcode,
  531                     ISSET(cmd->c_flags, SCF_CMD_READ) ? "rd" : "wr",
  532                     cmd->c_blklen, cmd->c_datalen, cmd->c_resid);
  533         }
  534 }
  535                                       
  536 static void
  537 wb_sdmmc_card_enable_intr(sdmmc_chipset_handle_t sch, int enable)
  538 {
  539         REPORT(sch, "TRACE: sdmmc/card_enable_intr(wb, enable=%d)\n", enable);
  540 }
  541 
  542 static void
  543 wb_sdmmc_card_intr_ack(sdmmc_chipset_handle_t sch)
  544 {
  545         REPORT(sch, "TRACE: sdmmc/card_intr_ack(wb)\n");
  546 }
  547 
  548 /*
  549  * intr handler 
  550  */
  551 int
  552 wb_sdmmc_intr(struct wb_softc *wb)
  553 {
  554         uint8_t val;
  555 
  556         val = wb_read(wb, WB_SD_INTSTS);
  557         if (val == 0xff || val == 0x00)
  558                 return 0;
  559 
  560         if (wb->wb_sdmmc_dev == NULL)
  561                 return 1;
  562 
  563         wb->wb_sdmmc_intsts |= val;
  564 
  565         if (wb_sdmmc_debug) {
  566                 char buf[64];
  567                 snprintb(buf, sizeof(buf),
  568                     "\2\1TC\2BUSYEND\3PROGEND\4TIMEOUT"
  569                     "\5CRC\6FIFO\7CARD\010PENDING",
  570                     val);
  571                 REPORT(wb, "WB_SD_INTSTS = %s\n", buf);
  572         }
  573 
  574         if (val & WB_INT_CARD)
  575                 callout_schedule(&wb->wb_sdmmc_callout, hz / 4);
  576 
  577         return 1;
  578 }
  579 
  580 /*
  581  * pmf
  582  */
  583 bool
  584 wb_sdmmc_suspend(struct wb_softc *wb)
  585 {
  586         return wb_sdmmc_disable(wb);
  587 }
  588 
  589 bool
  590 wb_sdmmc_resume(struct wb_softc *wb)
  591 {
  592         uint8_t val;
  593 
  594         val = wb_read(wb, WB_SD_CSR);
  595         val &= ~WB_CSR_POWER_N;
  596         wb_write(wb, WB_SD_CSR, val);
  597 
  598         if (wb_sdmmc_enable(wb) == false)
  599                 return false;
  600 
  601         if (wb_idx_read(wb, WB_INDEX_CLK) != wb->wb_sdmmc_clk)
  602                 wb_idx_write(wb, WB_INDEX_CLK, wb->wb_sdmmc_clk);
  603 
  604         return true;
  605 }

Cache object: a27d062b5a414427d3aa3fed80c89733


[ 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.