13a96dff0STony Prisk /* 23a96dff0STony Prisk * WM8505/WM8650 SD/MMC Host Controller 33a96dff0STony Prisk * 43a96dff0STony Prisk * Copyright (C) 2010 Tony Prisk 53a96dff0STony Prisk * Copyright (C) 2008 WonderMedia Technologies, Inc. 63a96dff0STony Prisk * 73a96dff0STony Prisk * This program is free software; you can redistribute it and/or modify 83a96dff0STony Prisk * it under the terms of the GNU General Public License version 2 as 93a96dff0STony Prisk * published by the Free Software Foundation 103a96dff0STony Prisk */ 113a96dff0STony Prisk 123a96dff0STony Prisk #include <linux/init.h> 133a96dff0STony Prisk #include <linux/module.h> 143a96dff0STony Prisk #include <linux/platform_device.h> 153a96dff0STony Prisk #include <linux/ioport.h> 163a96dff0STony Prisk #include <linux/errno.h> 173a96dff0STony Prisk #include <linux/dma-mapping.h> 183a96dff0STony Prisk #include <linux/delay.h> 193a96dff0STony Prisk #include <linux/io.h> 203a96dff0STony Prisk #include <linux/irq.h> 213a96dff0STony Prisk #include <linux/clk.h> 223a96dff0STony Prisk #include <linux/gpio.h> 233a96dff0STony Prisk 243a96dff0STony Prisk #include <linux/of.h> 253a96dff0STony Prisk #include <linux/of_address.h> 263a96dff0STony Prisk #include <linux/of_irq.h> 273a96dff0STony Prisk #include <linux/of_device.h> 283a96dff0STony Prisk 293a96dff0STony Prisk #include <linux/mmc/host.h> 303a96dff0STony Prisk #include <linux/mmc/mmc.h> 313a96dff0STony Prisk #include <linux/mmc/sd.h> 323a96dff0STony Prisk 333a96dff0STony Prisk #include <asm/byteorder.h> 343a96dff0STony Prisk 353a96dff0STony Prisk 363a96dff0STony Prisk #define DRIVER_NAME "wmt-sdhc" 373a96dff0STony Prisk 383a96dff0STony Prisk 393a96dff0STony Prisk /* MMC/SD controller registers */ 403a96dff0STony Prisk #define SDMMC_CTLR 0x00 413a96dff0STony Prisk #define SDMMC_CMD 0x01 423a96dff0STony Prisk #define SDMMC_RSPTYPE 0x02 433a96dff0STony Prisk #define SDMMC_ARG 0x04 443a96dff0STony Prisk #define SDMMC_BUSMODE 0x08 453a96dff0STony Prisk #define SDMMC_BLKLEN 0x0C 463a96dff0STony Prisk #define SDMMC_BLKCNT 0x0E 473a96dff0STony Prisk #define SDMMC_RSP 0x10 483a96dff0STony Prisk #define SDMMC_CBCR 0x20 493a96dff0STony Prisk #define SDMMC_INTMASK0 0x24 503a96dff0STony Prisk #define SDMMC_INTMASK1 0x25 513a96dff0STony Prisk #define SDMMC_STS0 0x28 523a96dff0STony Prisk #define SDMMC_STS1 0x29 533a96dff0STony Prisk #define SDMMC_STS2 0x2A 543a96dff0STony Prisk #define SDMMC_STS3 0x2B 553a96dff0STony Prisk #define SDMMC_RSPTIMEOUT 0x2C 563a96dff0STony Prisk #define SDMMC_CLK 0x30 /* VT8500 only */ 573a96dff0STony Prisk #define SDMMC_EXTCTRL 0x34 583a96dff0STony Prisk #define SDMMC_SBLKLEN 0x38 593a96dff0STony Prisk #define SDMMC_DMATIMEOUT 0x3C 603a96dff0STony Prisk 613a96dff0STony Prisk 623a96dff0STony Prisk /* SDMMC_CTLR bit fields */ 633a96dff0STony Prisk #define CTLR_CMD_START 0x01 643a96dff0STony Prisk #define CTLR_CMD_WRITE 0x04 653a96dff0STony Prisk #define CTLR_FIFO_RESET 0x08 663a96dff0STony Prisk 673a96dff0STony Prisk /* SDMMC_BUSMODE bit fields */ 683a96dff0STony Prisk #define BM_SPI_MODE 0x01 693a96dff0STony Prisk #define BM_FOURBIT_MODE 0x02 703a96dff0STony Prisk #define BM_EIGHTBIT_MODE 0x04 713a96dff0STony Prisk #define BM_SD_OFF 0x10 723a96dff0STony Prisk #define BM_SPI_CS 0x20 733a96dff0STony Prisk #define BM_SD_POWER 0x40 743a96dff0STony Prisk #define BM_SOFT_RESET 0x80 753a96dff0STony Prisk #define BM_ONEBIT_MASK 0xFD 763a96dff0STony Prisk 773a96dff0STony Prisk /* SDMMC_BLKLEN bit fields */ 783a96dff0STony Prisk #define BLKL_CRCERR_ABORT 0x0800 793a96dff0STony Prisk #define BLKL_CD_POL_HIGH 0x1000 803a96dff0STony Prisk #define BLKL_GPI_CD 0x2000 813a96dff0STony Prisk #define BLKL_DATA3_CD 0x4000 823a96dff0STony Prisk #define BLKL_INT_ENABLE 0x8000 833a96dff0STony Prisk 843a96dff0STony Prisk /* SDMMC_INTMASK0 bit fields */ 853a96dff0STony Prisk #define INT0_MBLK_TRAN_DONE_INT_EN 0x10 863a96dff0STony Prisk #define INT0_BLK_TRAN_DONE_INT_EN 0x20 873a96dff0STony Prisk #define INT0_CD_INT_EN 0x40 883a96dff0STony Prisk #define INT0_DI_INT_EN 0x80 893a96dff0STony Prisk 903a96dff0STony Prisk /* SDMMC_INTMASK1 bit fields */ 913a96dff0STony Prisk #define INT1_CMD_RES_TRAN_DONE_INT_EN 0x02 923a96dff0STony Prisk #define INT1_CMD_RES_TOUT_INT_EN 0x04 933a96dff0STony Prisk #define INT1_MBLK_AUTO_STOP_INT_EN 0x08 943a96dff0STony Prisk #define INT1_DATA_TOUT_INT_EN 0x10 953a96dff0STony Prisk #define INT1_RESCRC_ERR_INT_EN 0x20 963a96dff0STony Prisk #define INT1_RCRC_ERR_INT_EN 0x40 973a96dff0STony Prisk #define INT1_WCRC_ERR_INT_EN 0x80 983a96dff0STony Prisk 993a96dff0STony Prisk /* SDMMC_STS0 bit fields */ 1003a96dff0STony Prisk #define STS0_WRITE_PROTECT 0x02 1013a96dff0STony Prisk #define STS0_CD_DATA3 0x04 1023a96dff0STony Prisk #define STS0_CD_GPI 0x08 1033a96dff0STony Prisk #define STS0_MBLK_DONE 0x10 1043a96dff0STony Prisk #define STS0_BLK_DONE 0x20 1053a96dff0STony Prisk #define STS0_CARD_DETECT 0x40 1063a96dff0STony Prisk #define STS0_DEVICE_INS 0x80 1073a96dff0STony Prisk 1083a96dff0STony Prisk /* SDMMC_STS1 bit fields */ 1093a96dff0STony Prisk #define STS1_SDIO_INT 0x01 1103a96dff0STony Prisk #define STS1_CMDRSP_DONE 0x02 1113a96dff0STony Prisk #define STS1_RSP_TIMEOUT 0x04 1123a96dff0STony Prisk #define STS1_AUTOSTOP_DONE 0x08 1133a96dff0STony Prisk #define STS1_DATA_TIMEOUT 0x10 1143a96dff0STony Prisk #define STS1_RSP_CRC_ERR 0x20 1153a96dff0STony Prisk #define STS1_RCRC_ERR 0x40 1163a96dff0STony Prisk #define STS1_WCRC_ERR 0x80 1173a96dff0STony Prisk 1183a96dff0STony Prisk /* SDMMC_STS2 bit fields */ 1193a96dff0STony Prisk #define STS2_CMD_RES_BUSY 0x10 1203a96dff0STony Prisk #define STS2_DATARSP_BUSY 0x20 1213a96dff0STony Prisk #define STS2_DIS_FORCECLK 0x80 1223a96dff0STony Prisk 1233a96dff0STony Prisk 1243a96dff0STony Prisk /* MMC/SD DMA Controller Registers */ 1253a96dff0STony Prisk #define SDDMA_GCR 0x100 1263a96dff0STony Prisk #define SDDMA_IER 0x104 1273a96dff0STony Prisk #define SDDMA_ISR 0x108 1283a96dff0STony Prisk #define SDDMA_DESPR 0x10C 1293a96dff0STony Prisk #define SDDMA_RBR 0x110 1303a96dff0STony Prisk #define SDDMA_DAR 0x114 1313a96dff0STony Prisk #define SDDMA_BAR 0x118 1323a96dff0STony Prisk #define SDDMA_CPR 0x11C 1333a96dff0STony Prisk #define SDDMA_CCR 0x120 1343a96dff0STony Prisk 1353a96dff0STony Prisk 1363a96dff0STony Prisk /* SDDMA_GCR bit fields */ 1373a96dff0STony Prisk #define DMA_GCR_DMA_EN 0x00000001 1383a96dff0STony Prisk #define DMA_GCR_SOFT_RESET 0x00000100 1393a96dff0STony Prisk 1403a96dff0STony Prisk /* SDDMA_IER bit fields */ 1413a96dff0STony Prisk #define DMA_IER_INT_EN 0x00000001 1423a96dff0STony Prisk 1433a96dff0STony Prisk /* SDDMA_ISR bit fields */ 1443a96dff0STony Prisk #define DMA_ISR_INT_STS 0x00000001 1453a96dff0STony Prisk 1463a96dff0STony Prisk /* SDDMA_RBR bit fields */ 1473a96dff0STony Prisk #define DMA_RBR_FORMAT 0x40000000 1483a96dff0STony Prisk #define DMA_RBR_END 0x80000000 1493a96dff0STony Prisk 1503a96dff0STony Prisk /* SDDMA_CCR bit fields */ 1513a96dff0STony Prisk #define DMA_CCR_RUN 0x00000080 1523a96dff0STony Prisk #define DMA_CCR_IF_TO_PERIPHERAL 0x00000000 1533a96dff0STony Prisk #define DMA_CCR_PERIPHERAL_TO_IF 0x00400000 1543a96dff0STony Prisk 1553a96dff0STony Prisk /* SDDMA_CCR event status */ 1563a96dff0STony Prisk #define DMA_CCR_EVT_NO_STATUS 0x00000000 1573a96dff0STony Prisk #define DMA_CCR_EVT_UNDERRUN 0x00000001 1583a96dff0STony Prisk #define DMA_CCR_EVT_OVERRUN 0x00000002 1593a96dff0STony Prisk #define DMA_CCR_EVT_DESP_READ 0x00000003 1603a96dff0STony Prisk #define DMA_CCR_EVT_DATA_RW 0x00000004 1613a96dff0STony Prisk #define DMA_CCR_EVT_EARLY_END 0x00000005 1623a96dff0STony Prisk #define DMA_CCR_EVT_SUCCESS 0x0000000F 1633a96dff0STony Prisk 1643a96dff0STony Prisk #define PDMA_READ 0x00 1653a96dff0STony Prisk #define PDMA_WRITE 0x01 1663a96dff0STony Prisk 1673a96dff0STony Prisk #define WMT_SD_POWER_OFF 0 1683a96dff0STony Prisk #define WMT_SD_POWER_ON 1 1693a96dff0STony Prisk 1703a96dff0STony Prisk struct wmt_dma_descriptor { 1713a96dff0STony Prisk u32 flags; 1723a96dff0STony Prisk u32 data_buffer_addr; 1733a96dff0STony Prisk u32 branch_addr; 1743a96dff0STony Prisk u32 reserved1; 1753a96dff0STony Prisk }; 1763a96dff0STony Prisk 1773a96dff0STony Prisk struct wmt_mci_caps { 1783a96dff0STony Prisk unsigned int f_min; 1793a96dff0STony Prisk unsigned int f_max; 1803a96dff0STony Prisk u32 ocr_avail; 1813a96dff0STony Prisk u32 caps; 1823a96dff0STony Prisk u32 max_seg_size; 1833a96dff0STony Prisk u32 max_segs; 1843a96dff0STony Prisk u32 max_blk_size; 1853a96dff0STony Prisk }; 1863a96dff0STony Prisk 1873a96dff0STony Prisk struct wmt_mci_priv { 1883a96dff0STony Prisk struct mmc_host *mmc; 1893a96dff0STony Prisk void __iomem *sdmmc_base; 1903a96dff0STony Prisk 1913a96dff0STony Prisk int irq_regular; 1923a96dff0STony Prisk int irq_dma; 1933a96dff0STony Prisk 1943a96dff0STony Prisk void *dma_desc_buffer; 1953a96dff0STony Prisk dma_addr_t dma_desc_device_addr; 1963a96dff0STony Prisk 1973a96dff0STony Prisk struct completion cmdcomp; 1983a96dff0STony Prisk struct completion datacomp; 1993a96dff0STony Prisk 2003a96dff0STony Prisk struct completion *comp_cmd; 2013a96dff0STony Prisk struct completion *comp_dma; 2023a96dff0STony Prisk 2033a96dff0STony Prisk struct mmc_request *req; 2043a96dff0STony Prisk struct mmc_command *cmd; 2053a96dff0STony Prisk 2063a96dff0STony Prisk struct clk *clk_sdmmc; 2073a96dff0STony Prisk struct device *dev; 2083a96dff0STony Prisk 2093a96dff0STony Prisk u8 power_inverted; 2103a96dff0STony Prisk u8 cd_inverted; 2113a96dff0STony Prisk }; 2123a96dff0STony Prisk 2133a96dff0STony Prisk static void wmt_set_sd_power(struct wmt_mci_priv *priv, int enable) 2143a96dff0STony Prisk { 2157b239903SAxel Lin u32 reg_tmp = readb(priv->sdmmc_base + SDMMC_BUSMODE); 2167b239903SAxel Lin 2177b239903SAxel Lin if (enable ^ priv->power_inverted) 2187b239903SAxel Lin reg_tmp &= ~BM_SD_OFF; 2197b239903SAxel Lin else 2207b239903SAxel Lin reg_tmp |= BM_SD_OFF; 2217b239903SAxel Lin 2227b239903SAxel Lin writeb(reg_tmp, priv->sdmmc_base + SDMMC_BUSMODE); 2233a96dff0STony Prisk } 2243a96dff0STony Prisk 2253a96dff0STony Prisk static void wmt_mci_read_response(struct mmc_host *mmc) 2263a96dff0STony Prisk { 2273a96dff0STony Prisk struct wmt_mci_priv *priv; 2283a96dff0STony Prisk int idx1, idx2; 2293a96dff0STony Prisk u8 tmp_resp; 2303a96dff0STony Prisk u32 response; 2313a96dff0STony Prisk 2323a96dff0STony Prisk priv = mmc_priv(mmc); 2333a96dff0STony Prisk 2343a96dff0STony Prisk for (idx1 = 0; idx1 < 4; idx1++) { 2353a96dff0STony Prisk response = 0; 2363a96dff0STony Prisk for (idx2 = 0; idx2 < 4; idx2++) { 2373a96dff0STony Prisk if ((idx1 == 3) && (idx2 == 3)) 2383a96dff0STony Prisk tmp_resp = readb(priv->sdmmc_base + SDMMC_RSP); 2393a96dff0STony Prisk else 2403a96dff0STony Prisk tmp_resp = readb(priv->sdmmc_base + SDMMC_RSP + 2413a96dff0STony Prisk (idx1*4) + idx2 + 1); 2423a96dff0STony Prisk response |= (tmp_resp << (idx2 * 8)); 2433a96dff0STony Prisk } 2443a96dff0STony Prisk priv->cmd->resp[idx1] = cpu_to_be32(response); 2453a96dff0STony Prisk } 2463a96dff0STony Prisk } 2473a96dff0STony Prisk 2483a96dff0STony Prisk static void wmt_mci_start_command(struct wmt_mci_priv *priv) 2493a96dff0STony Prisk { 2503a96dff0STony Prisk u32 reg_tmp; 2513a96dff0STony Prisk 2523a96dff0STony Prisk reg_tmp = readb(priv->sdmmc_base + SDMMC_CTLR); 2533a96dff0STony Prisk writeb(reg_tmp | CTLR_CMD_START, priv->sdmmc_base + SDMMC_CTLR); 2543a96dff0STony Prisk } 2553a96dff0STony Prisk 2563a96dff0STony Prisk static int wmt_mci_send_command(struct mmc_host *mmc, u8 command, u8 cmdtype, 2573a96dff0STony Prisk u32 arg, u8 rsptype) 2583a96dff0STony Prisk { 2593a96dff0STony Prisk struct wmt_mci_priv *priv; 2603a96dff0STony Prisk u32 reg_tmp; 2613a96dff0STony Prisk 2623a96dff0STony Prisk priv = mmc_priv(mmc); 2633a96dff0STony Prisk 2643a96dff0STony Prisk /* write command, arg, resptype registers */ 2653a96dff0STony Prisk writeb(command, priv->sdmmc_base + SDMMC_CMD); 2663a96dff0STony Prisk writel(arg, priv->sdmmc_base + SDMMC_ARG); 2673a96dff0STony Prisk writeb(rsptype, priv->sdmmc_base + SDMMC_RSPTYPE); 2683a96dff0STony Prisk 2693a96dff0STony Prisk /* reset response FIFO */ 2703a96dff0STony Prisk reg_tmp = readb(priv->sdmmc_base + SDMMC_CTLR); 2713a96dff0STony Prisk writeb(reg_tmp | CTLR_FIFO_RESET, priv->sdmmc_base + SDMMC_CTLR); 2723a96dff0STony Prisk 2733a96dff0STony Prisk /* ensure clock enabled - VT3465 */ 2743a96dff0STony Prisk wmt_set_sd_power(priv, WMT_SD_POWER_ON); 2753a96dff0STony Prisk 2763a96dff0STony Prisk /* clear status bits */ 2773a96dff0STony Prisk writeb(0xFF, priv->sdmmc_base + SDMMC_STS0); 2783a96dff0STony Prisk writeb(0xFF, priv->sdmmc_base + SDMMC_STS1); 2793a96dff0STony Prisk writeb(0xFF, priv->sdmmc_base + SDMMC_STS2); 2803a96dff0STony Prisk writeb(0xFF, priv->sdmmc_base + SDMMC_STS3); 2813a96dff0STony Prisk 2823a96dff0STony Prisk /* set command type */ 2833a96dff0STony Prisk reg_tmp = readb(priv->sdmmc_base + SDMMC_CTLR); 2843a96dff0STony Prisk writeb((reg_tmp & 0x0F) | (cmdtype << 4), 2853a96dff0STony Prisk priv->sdmmc_base + SDMMC_CTLR); 2863a96dff0STony Prisk 2873a96dff0STony Prisk return 0; 2883a96dff0STony Prisk } 2893a96dff0STony Prisk 2903a96dff0STony Prisk static void wmt_mci_disable_dma(struct wmt_mci_priv *priv) 2913a96dff0STony Prisk { 2923a96dff0STony Prisk writel(DMA_ISR_INT_STS, priv->sdmmc_base + SDDMA_ISR); 2933a96dff0STony Prisk writel(0, priv->sdmmc_base + SDDMA_IER); 2943a96dff0STony Prisk } 2953a96dff0STony Prisk 2963a96dff0STony Prisk static void wmt_complete_data_request(struct wmt_mci_priv *priv) 2973a96dff0STony Prisk { 2983a96dff0STony Prisk struct mmc_request *req; 2993a96dff0STony Prisk req = priv->req; 3003a96dff0STony Prisk 3013a96dff0STony Prisk req->data->bytes_xfered = req->data->blksz * req->data->blocks; 3023a96dff0STony Prisk 3033a96dff0STony Prisk /* unmap the DMA pages used for write data */ 3043a96dff0STony Prisk if (req->data->flags & MMC_DATA_WRITE) 3053a96dff0STony Prisk dma_unmap_sg(mmc_dev(priv->mmc), req->data->sg, 3063a96dff0STony Prisk req->data->sg_len, DMA_TO_DEVICE); 3073a96dff0STony Prisk else 3083a96dff0STony Prisk dma_unmap_sg(mmc_dev(priv->mmc), req->data->sg, 3093a96dff0STony Prisk req->data->sg_len, DMA_FROM_DEVICE); 3103a96dff0STony Prisk 3113a96dff0STony Prisk /* Check if the DMA ISR returned a data error */ 3123a96dff0STony Prisk if ((req->cmd->error) || (req->data->error)) 3133a96dff0STony Prisk mmc_request_done(priv->mmc, req); 3143a96dff0STony Prisk else { 3153a96dff0STony Prisk wmt_mci_read_response(priv->mmc); 3163a96dff0STony Prisk if (!req->data->stop) { 3173a96dff0STony Prisk /* single-block read/write requests end here */ 3183a96dff0STony Prisk mmc_request_done(priv->mmc, req); 3193a96dff0STony Prisk } else { 3203a96dff0STony Prisk /* 3213a96dff0STony Prisk * we change the priv->cmd variable so the response is 3223a96dff0STony Prisk * stored in the stop struct rather than the original 3233a96dff0STony Prisk * calling command struct 3243a96dff0STony Prisk */ 3253a96dff0STony Prisk priv->comp_cmd = &priv->cmdcomp; 3263a96dff0STony Prisk init_completion(priv->comp_cmd); 3273a96dff0STony Prisk priv->cmd = req->data->stop; 3283a96dff0STony Prisk wmt_mci_send_command(priv->mmc, req->data->stop->opcode, 3293a96dff0STony Prisk 7, req->data->stop->arg, 9); 3303a96dff0STony Prisk wmt_mci_start_command(priv); 3313a96dff0STony Prisk } 3323a96dff0STony Prisk } 3333a96dff0STony Prisk } 3343a96dff0STony Prisk 3353a96dff0STony Prisk static irqreturn_t wmt_mci_dma_isr(int irq_num, void *data) 3363a96dff0STony Prisk { 3373a96dff0STony Prisk struct wmt_mci_priv *priv; 3383a96dff0STony Prisk 3393a96dff0STony Prisk int status; 3403a96dff0STony Prisk 3413a96dff0STony Prisk priv = (struct wmt_mci_priv *)data; 3423a96dff0STony Prisk 3433a96dff0STony Prisk status = readl(priv->sdmmc_base + SDDMA_CCR) & 0x0F; 3443a96dff0STony Prisk 3453a96dff0STony Prisk if (status != DMA_CCR_EVT_SUCCESS) { 3463a96dff0STony Prisk dev_err(priv->dev, "DMA Error: Status = %d\n", status); 3473a96dff0STony Prisk priv->req->data->error = -ETIMEDOUT; 3483a96dff0STony Prisk complete(priv->comp_dma); 3493a96dff0STony Prisk return IRQ_HANDLED; 3503a96dff0STony Prisk } 3513a96dff0STony Prisk 3523a96dff0STony Prisk priv->req->data->error = 0; 3533a96dff0STony Prisk 3543a96dff0STony Prisk wmt_mci_disable_dma(priv); 3553a96dff0STony Prisk 3563a96dff0STony Prisk complete(priv->comp_dma); 3573a96dff0STony Prisk 3583a96dff0STony Prisk if (priv->comp_cmd) { 3593a96dff0STony Prisk if (completion_done(priv->comp_cmd)) { 3603a96dff0STony Prisk /* 3613a96dff0STony Prisk * if the command (regular) interrupt has already 3623a96dff0STony Prisk * completed, finish off the request otherwise we wait 3633a96dff0STony Prisk * for the command interrupt and finish from there. 3643a96dff0STony Prisk */ 3653a96dff0STony Prisk wmt_complete_data_request(priv); 3663a96dff0STony Prisk } 3673a96dff0STony Prisk } 3683a96dff0STony Prisk 3693a96dff0STony Prisk return IRQ_HANDLED; 3703a96dff0STony Prisk } 3713a96dff0STony Prisk 3723a96dff0STony Prisk static irqreturn_t wmt_mci_regular_isr(int irq_num, void *data) 3733a96dff0STony Prisk { 3743a96dff0STony Prisk struct wmt_mci_priv *priv; 3753a96dff0STony Prisk u32 status0; 3763a96dff0STony Prisk u32 status1; 3773a96dff0STony Prisk u32 status2; 3783a96dff0STony Prisk u32 reg_tmp; 3793a96dff0STony Prisk int cmd_done; 3803a96dff0STony Prisk 3813a96dff0STony Prisk priv = (struct wmt_mci_priv *)data; 3823a96dff0STony Prisk cmd_done = 0; 3833a96dff0STony Prisk status0 = readb(priv->sdmmc_base + SDMMC_STS0); 3843a96dff0STony Prisk status1 = readb(priv->sdmmc_base + SDMMC_STS1); 3853a96dff0STony Prisk status2 = readb(priv->sdmmc_base + SDMMC_STS2); 3863a96dff0STony Prisk 3873a96dff0STony Prisk /* Check for card insertion */ 3883a96dff0STony Prisk reg_tmp = readb(priv->sdmmc_base + SDMMC_INTMASK0); 3893a96dff0STony Prisk if ((reg_tmp & INT0_DI_INT_EN) && (status0 & STS0_DEVICE_INS)) { 3903a96dff0STony Prisk mmc_detect_change(priv->mmc, 0); 3913a96dff0STony Prisk if (priv->cmd) 3923a96dff0STony Prisk priv->cmd->error = -ETIMEDOUT; 3933a96dff0STony Prisk if (priv->comp_cmd) 3943a96dff0STony Prisk complete(priv->comp_cmd); 3953a96dff0STony Prisk if (priv->comp_dma) { 3963a96dff0STony Prisk wmt_mci_disable_dma(priv); 3973a96dff0STony Prisk complete(priv->comp_dma); 3983a96dff0STony Prisk } 3993a96dff0STony Prisk writeb(STS0_DEVICE_INS, priv->sdmmc_base + SDMMC_STS0); 4003a96dff0STony Prisk return IRQ_HANDLED; 4013a96dff0STony Prisk } 4023a96dff0STony Prisk 4033a96dff0STony Prisk if ((!priv->req->data) || 4043a96dff0STony Prisk ((priv->req->data->stop) && (priv->cmd == priv->req->data->stop))) { 4053a96dff0STony Prisk /* handle non-data & stop_transmission requests */ 4063a96dff0STony Prisk if (status1 & STS1_CMDRSP_DONE) { 4073a96dff0STony Prisk priv->cmd->error = 0; 4083a96dff0STony Prisk cmd_done = 1; 4093a96dff0STony Prisk } else if ((status1 & STS1_RSP_TIMEOUT) || 4103a96dff0STony Prisk (status1 & STS1_DATA_TIMEOUT)) { 4113a96dff0STony Prisk priv->cmd->error = -ETIMEDOUT; 4123a96dff0STony Prisk cmd_done = 1; 4133a96dff0STony Prisk } 4143a96dff0STony Prisk 4153a96dff0STony Prisk if (cmd_done) { 4163a96dff0STony Prisk priv->comp_cmd = NULL; 4173a96dff0STony Prisk 4183a96dff0STony Prisk if (!priv->cmd->error) 4193a96dff0STony Prisk wmt_mci_read_response(priv->mmc); 4203a96dff0STony Prisk 4213a96dff0STony Prisk priv->cmd = NULL; 4223a96dff0STony Prisk 4233a96dff0STony Prisk mmc_request_done(priv->mmc, priv->req); 4243a96dff0STony Prisk } 4253a96dff0STony Prisk } else { 4263a96dff0STony Prisk /* handle data requests */ 4273a96dff0STony Prisk if (status1 & STS1_CMDRSP_DONE) { 4283a96dff0STony Prisk if (priv->cmd) 4293a96dff0STony Prisk priv->cmd->error = 0; 4303a96dff0STony Prisk if (priv->comp_cmd) 4313a96dff0STony Prisk complete(priv->comp_cmd); 4323a96dff0STony Prisk } 4333a96dff0STony Prisk 4343a96dff0STony Prisk if ((status1 & STS1_RSP_TIMEOUT) || 4353a96dff0STony Prisk (status1 & STS1_DATA_TIMEOUT)) { 4363a96dff0STony Prisk if (priv->cmd) 4373a96dff0STony Prisk priv->cmd->error = -ETIMEDOUT; 4383a96dff0STony Prisk if (priv->comp_cmd) 4393a96dff0STony Prisk complete(priv->comp_cmd); 4403a96dff0STony Prisk if (priv->comp_dma) { 4413a96dff0STony Prisk wmt_mci_disable_dma(priv); 4423a96dff0STony Prisk complete(priv->comp_dma); 4433a96dff0STony Prisk } 4443a96dff0STony Prisk } 4453a96dff0STony Prisk 4463a96dff0STony Prisk if (priv->comp_dma) { 4473a96dff0STony Prisk /* 4483a96dff0STony Prisk * If the dma interrupt has already completed, finish 4493a96dff0STony Prisk * off the request; otherwise we wait for the DMA 4503a96dff0STony Prisk * interrupt and finish from there. 4513a96dff0STony Prisk */ 4523a96dff0STony Prisk if (completion_done(priv->comp_dma)) 4533a96dff0STony Prisk wmt_complete_data_request(priv); 4543a96dff0STony Prisk } 4553a96dff0STony Prisk } 4563a96dff0STony Prisk 4573a96dff0STony Prisk writeb(status0, priv->sdmmc_base + SDMMC_STS0); 4583a96dff0STony Prisk writeb(status1, priv->sdmmc_base + SDMMC_STS1); 4593a96dff0STony Prisk writeb(status2, priv->sdmmc_base + SDMMC_STS2); 4603a96dff0STony Prisk 4613a96dff0STony Prisk return IRQ_HANDLED; 4623a96dff0STony Prisk } 4633a96dff0STony Prisk 4643a96dff0STony Prisk static void wmt_reset_hardware(struct mmc_host *mmc) 4653a96dff0STony Prisk { 4663a96dff0STony Prisk struct wmt_mci_priv *priv; 4673a96dff0STony Prisk u32 reg_tmp; 4683a96dff0STony Prisk 4693a96dff0STony Prisk priv = mmc_priv(mmc); 4703a96dff0STony Prisk 4713a96dff0STony Prisk /* reset controller */ 4723a96dff0STony Prisk reg_tmp = readb(priv->sdmmc_base + SDMMC_BUSMODE); 4733a96dff0STony Prisk writeb(reg_tmp | BM_SOFT_RESET, priv->sdmmc_base + SDMMC_BUSMODE); 4743a96dff0STony Prisk 4753a96dff0STony Prisk /* reset response FIFO */ 4763a96dff0STony Prisk reg_tmp = readb(priv->sdmmc_base + SDMMC_CTLR); 4773a96dff0STony Prisk writeb(reg_tmp | CTLR_FIFO_RESET, priv->sdmmc_base + SDMMC_CTLR); 4783a96dff0STony Prisk 4793a96dff0STony Prisk /* enable GPI pin to detect card */ 4803a96dff0STony Prisk writew(BLKL_INT_ENABLE | BLKL_GPI_CD, priv->sdmmc_base + SDMMC_BLKLEN); 4813a96dff0STony Prisk 4823a96dff0STony Prisk /* clear interrupt status */ 4833a96dff0STony Prisk writeb(0xFF, priv->sdmmc_base + SDMMC_STS0); 4843a96dff0STony Prisk writeb(0xFF, priv->sdmmc_base + SDMMC_STS1); 4853a96dff0STony Prisk 4863a96dff0STony Prisk /* setup interrupts */ 4873a96dff0STony Prisk writeb(INT0_CD_INT_EN | INT0_DI_INT_EN, priv->sdmmc_base + 4883a96dff0STony Prisk SDMMC_INTMASK0); 4893a96dff0STony Prisk writeb(INT1_DATA_TOUT_INT_EN | INT1_CMD_RES_TRAN_DONE_INT_EN | 4903a96dff0STony Prisk INT1_CMD_RES_TOUT_INT_EN, priv->sdmmc_base + SDMMC_INTMASK1); 4913a96dff0STony Prisk 4923a96dff0STony Prisk /* set the DMA timeout */ 4933a96dff0STony Prisk writew(8191, priv->sdmmc_base + SDMMC_DMATIMEOUT); 4943a96dff0STony Prisk 4953a96dff0STony Prisk /* auto clock freezing enable */ 4963a96dff0STony Prisk reg_tmp = readb(priv->sdmmc_base + SDMMC_STS2); 4973a96dff0STony Prisk writeb(reg_tmp | STS2_DIS_FORCECLK, priv->sdmmc_base + SDMMC_STS2); 4983a96dff0STony Prisk 4993a96dff0STony Prisk /* set a default clock speed of 400Khz */ 5003a96dff0STony Prisk clk_set_rate(priv->clk_sdmmc, 400000); 5013a96dff0STony Prisk } 5023a96dff0STony Prisk 5033a96dff0STony Prisk static int wmt_dma_init(struct mmc_host *mmc) 5043a96dff0STony Prisk { 5053a96dff0STony Prisk struct wmt_mci_priv *priv; 5063a96dff0STony Prisk 5073a96dff0STony Prisk priv = mmc_priv(mmc); 5083a96dff0STony Prisk 5093a96dff0STony Prisk writel(DMA_GCR_SOFT_RESET, priv->sdmmc_base + SDDMA_GCR); 5103a96dff0STony Prisk writel(DMA_GCR_DMA_EN, priv->sdmmc_base + SDDMA_GCR); 5113a96dff0STony Prisk if ((readl(priv->sdmmc_base + SDDMA_GCR) & DMA_GCR_DMA_EN) != 0) 5123a96dff0STony Prisk return 0; 5133a96dff0STony Prisk else 5143a96dff0STony Prisk return 1; 5153a96dff0STony Prisk } 5163a96dff0STony Prisk 5173a96dff0STony Prisk static void wmt_dma_init_descriptor(struct wmt_dma_descriptor *desc, 5183a96dff0STony Prisk u16 req_count, u32 buffer_addr, u32 branch_addr, int end) 5193a96dff0STony Prisk { 5203a96dff0STony Prisk desc->flags = 0x40000000 | req_count; 5213a96dff0STony Prisk if (end) 5223a96dff0STony Prisk desc->flags |= 0x80000000; 5233a96dff0STony Prisk desc->data_buffer_addr = buffer_addr; 5243a96dff0STony Prisk desc->branch_addr = branch_addr; 5253a96dff0STony Prisk } 5263a96dff0STony Prisk 5273a96dff0STony Prisk static void wmt_dma_config(struct mmc_host *mmc, u32 descaddr, u8 dir) 5283a96dff0STony Prisk { 5293a96dff0STony Prisk struct wmt_mci_priv *priv; 5303a96dff0STony Prisk u32 reg_tmp; 5313a96dff0STony Prisk 5323a96dff0STony Prisk priv = mmc_priv(mmc); 5333a96dff0STony Prisk 5343a96dff0STony Prisk /* Enable DMA Interrupts */ 5353a96dff0STony Prisk writel(DMA_IER_INT_EN, priv->sdmmc_base + SDDMA_IER); 5363a96dff0STony Prisk 5373a96dff0STony Prisk /* Write DMA Descriptor Pointer Register */ 5383a96dff0STony Prisk writel(descaddr, priv->sdmmc_base + SDDMA_DESPR); 5393a96dff0STony Prisk 5403a96dff0STony Prisk writel(0x00, priv->sdmmc_base + SDDMA_CCR); 5413a96dff0STony Prisk 5423a96dff0STony Prisk if (dir == PDMA_WRITE) { 5433a96dff0STony Prisk reg_tmp = readl(priv->sdmmc_base + SDDMA_CCR); 5443a96dff0STony Prisk writel(reg_tmp & DMA_CCR_IF_TO_PERIPHERAL, priv->sdmmc_base + 5453a96dff0STony Prisk SDDMA_CCR); 5463a96dff0STony Prisk } else { 5473a96dff0STony Prisk reg_tmp = readl(priv->sdmmc_base + SDDMA_CCR); 5483a96dff0STony Prisk writel(reg_tmp | DMA_CCR_PERIPHERAL_TO_IF, priv->sdmmc_base + 5493a96dff0STony Prisk SDDMA_CCR); 5503a96dff0STony Prisk } 5513a96dff0STony Prisk } 5523a96dff0STony Prisk 5533a96dff0STony Prisk static void wmt_dma_start(struct wmt_mci_priv *priv) 5543a96dff0STony Prisk { 5553a96dff0STony Prisk u32 reg_tmp; 5563a96dff0STony Prisk 5573a96dff0STony Prisk reg_tmp = readl(priv->sdmmc_base + SDDMA_CCR); 5583a96dff0STony Prisk writel(reg_tmp | DMA_CCR_RUN, priv->sdmmc_base + SDDMA_CCR); 5593a96dff0STony Prisk } 5603a96dff0STony Prisk 5613a96dff0STony Prisk static void wmt_mci_request(struct mmc_host *mmc, struct mmc_request *req) 5623a96dff0STony Prisk { 5633a96dff0STony Prisk struct wmt_mci_priv *priv; 5643a96dff0STony Prisk struct wmt_dma_descriptor *desc; 5653a96dff0STony Prisk u8 command; 5663a96dff0STony Prisk u8 cmdtype; 5673a96dff0STony Prisk u32 arg; 5683a96dff0STony Prisk u8 rsptype; 5693a96dff0STony Prisk u32 reg_tmp; 5703a96dff0STony Prisk 5713a96dff0STony Prisk struct scatterlist *sg; 5723a96dff0STony Prisk int i; 5733a96dff0STony Prisk int sg_cnt; 5743a96dff0STony Prisk int offset; 5753a96dff0STony Prisk u32 dma_address; 5763a96dff0STony Prisk int desc_cnt; 5773a96dff0STony Prisk 5783a96dff0STony Prisk priv = mmc_priv(mmc); 5793a96dff0STony Prisk priv->req = req; 5803a96dff0STony Prisk 5813a96dff0STony Prisk /* 5823a96dff0STony Prisk * Use the cmd variable to pass a pointer to the resp[] structure 5833a96dff0STony Prisk * This is required on multi-block requests to pass the pointer to the 5843a96dff0STony Prisk * stop command 5853a96dff0STony Prisk */ 5863a96dff0STony Prisk priv->cmd = req->cmd; 5873a96dff0STony Prisk 5883a96dff0STony Prisk command = req->cmd->opcode; 5893a96dff0STony Prisk arg = req->cmd->arg; 5903a96dff0STony Prisk rsptype = mmc_resp_type(req->cmd); 5913a96dff0STony Prisk cmdtype = 0; 5923a96dff0STony Prisk 5933a96dff0STony Prisk /* rsptype=7 only valid for SPI commands - should be =2 for SD */ 5943a96dff0STony Prisk if (rsptype == 7) 5953a96dff0STony Prisk rsptype = 2; 5963a96dff0STony Prisk /* rsptype=21 is R1B, convert for controller */ 5973a96dff0STony Prisk if (rsptype == 21) 5983a96dff0STony Prisk rsptype = 9; 5993a96dff0STony Prisk 6003a96dff0STony Prisk if (!req->data) { 6013a96dff0STony Prisk wmt_mci_send_command(mmc, command, cmdtype, arg, rsptype); 6023a96dff0STony Prisk wmt_mci_start_command(priv); 6033a96dff0STony Prisk /* completion is now handled in the regular_isr() */ 6043a96dff0STony Prisk } 6053a96dff0STony Prisk if (req->data) { 6063a96dff0STony Prisk priv->comp_cmd = &priv->cmdcomp; 6073a96dff0STony Prisk init_completion(priv->comp_cmd); 6083a96dff0STony Prisk 6093a96dff0STony Prisk wmt_dma_init(mmc); 6103a96dff0STony Prisk 6113a96dff0STony Prisk /* set controller data length */ 6123a96dff0STony Prisk reg_tmp = readw(priv->sdmmc_base + SDMMC_BLKLEN); 6133a96dff0STony Prisk writew((reg_tmp & 0xF800) | (req->data->blksz - 1), 6143a96dff0STony Prisk priv->sdmmc_base + SDMMC_BLKLEN); 6153a96dff0STony Prisk 6163a96dff0STony Prisk /* set controller block count */ 6173a96dff0STony Prisk writew(req->data->blocks, priv->sdmmc_base + SDMMC_BLKCNT); 6183a96dff0STony Prisk 6193a96dff0STony Prisk desc = (struct wmt_dma_descriptor *)priv->dma_desc_buffer; 6203a96dff0STony Prisk 6213a96dff0STony Prisk if (req->data->flags & MMC_DATA_WRITE) { 6223a96dff0STony Prisk sg_cnt = dma_map_sg(mmc_dev(mmc), req->data->sg, 6233a96dff0STony Prisk req->data->sg_len, DMA_TO_DEVICE); 6243a96dff0STony Prisk cmdtype = 1; 6253a96dff0STony Prisk if (req->data->blocks > 1) 6263a96dff0STony Prisk cmdtype = 3; 6273a96dff0STony Prisk } else { 6283a96dff0STony Prisk sg_cnt = dma_map_sg(mmc_dev(mmc), req->data->sg, 6293a96dff0STony Prisk req->data->sg_len, DMA_FROM_DEVICE); 6303a96dff0STony Prisk cmdtype = 2; 6313a96dff0STony Prisk if (req->data->blocks > 1) 6323a96dff0STony Prisk cmdtype = 4; 6333a96dff0STony Prisk } 6343a96dff0STony Prisk 6353a96dff0STony Prisk dma_address = priv->dma_desc_device_addr + 16; 6363a96dff0STony Prisk desc_cnt = 0; 6373a96dff0STony Prisk 6383a96dff0STony Prisk for_each_sg(req->data->sg, sg, sg_cnt, i) { 6393a96dff0STony Prisk offset = 0; 6403a96dff0STony Prisk while (offset < sg_dma_len(sg)) { 6413a96dff0STony Prisk wmt_dma_init_descriptor(desc, req->data->blksz, 6423a96dff0STony Prisk sg_dma_address(sg)+offset, 6433a96dff0STony Prisk dma_address, 0); 6443a96dff0STony Prisk desc++; 6453a96dff0STony Prisk desc_cnt++; 6463a96dff0STony Prisk offset += req->data->blksz; 6473a96dff0STony Prisk dma_address += 16; 6483a96dff0STony Prisk if (desc_cnt == req->data->blocks) 6493a96dff0STony Prisk break; 6503a96dff0STony Prisk } 6513a96dff0STony Prisk } 6523a96dff0STony Prisk desc--; 6533a96dff0STony Prisk desc->flags |= 0x80000000; 6543a96dff0STony Prisk 6553a96dff0STony Prisk if (req->data->flags & MMC_DATA_WRITE) 6563a96dff0STony Prisk wmt_dma_config(mmc, priv->dma_desc_device_addr, 6573a96dff0STony Prisk PDMA_WRITE); 6583a96dff0STony Prisk else 6593a96dff0STony Prisk wmt_dma_config(mmc, priv->dma_desc_device_addr, 6603a96dff0STony Prisk PDMA_READ); 6613a96dff0STony Prisk 6623a96dff0STony Prisk wmt_mci_send_command(mmc, command, cmdtype, arg, rsptype); 6633a96dff0STony Prisk 6643a96dff0STony Prisk priv->comp_dma = &priv->datacomp; 6653a96dff0STony Prisk init_completion(priv->comp_dma); 6663a96dff0STony Prisk 6673a96dff0STony Prisk wmt_dma_start(priv); 6683a96dff0STony Prisk wmt_mci_start_command(priv); 6693a96dff0STony Prisk } 6703a96dff0STony Prisk } 6713a96dff0STony Prisk 6723a96dff0STony Prisk static void wmt_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) 6733a96dff0STony Prisk { 6743a96dff0STony Prisk struct wmt_mci_priv *priv; 6753a96dff0STony Prisk u32 reg_tmp; 6763a96dff0STony Prisk 6773a96dff0STony Prisk priv = mmc_priv(mmc); 6783a96dff0STony Prisk 6793a96dff0STony Prisk if (ios->power_mode == MMC_POWER_UP) { 6803a96dff0STony Prisk wmt_reset_hardware(mmc); 6813a96dff0STony Prisk 6823a96dff0STony Prisk wmt_set_sd_power(priv, WMT_SD_POWER_ON); 6833a96dff0STony Prisk } 6843a96dff0STony Prisk if (ios->power_mode == MMC_POWER_OFF) 6853a96dff0STony Prisk wmt_set_sd_power(priv, WMT_SD_POWER_OFF); 6863a96dff0STony Prisk 6873a96dff0STony Prisk if (ios->clock != 0) 6883a96dff0STony Prisk clk_set_rate(priv->clk_sdmmc, ios->clock); 6893a96dff0STony Prisk 6903a96dff0STony Prisk switch (ios->bus_width) { 6913a96dff0STony Prisk case MMC_BUS_WIDTH_8: 6923a96dff0STony Prisk reg_tmp = readb(priv->sdmmc_base + SDMMC_EXTCTRL); 6933a96dff0STony Prisk writeb(reg_tmp | 0x04, priv->sdmmc_base + SDMMC_EXTCTRL); 6943a96dff0STony Prisk break; 6953a96dff0STony Prisk case MMC_BUS_WIDTH_4: 6963a96dff0STony Prisk reg_tmp = readb(priv->sdmmc_base + SDMMC_BUSMODE); 6973a96dff0STony Prisk writeb(reg_tmp | BM_FOURBIT_MODE, priv->sdmmc_base + 6983a96dff0STony Prisk SDMMC_BUSMODE); 6993a96dff0STony Prisk 7003a96dff0STony Prisk reg_tmp = readb(priv->sdmmc_base + SDMMC_EXTCTRL); 7013a96dff0STony Prisk writeb(reg_tmp & 0xFB, priv->sdmmc_base + SDMMC_EXTCTRL); 7023a96dff0STony Prisk break; 7033a96dff0STony Prisk case MMC_BUS_WIDTH_1: 7043a96dff0STony Prisk reg_tmp = readb(priv->sdmmc_base + SDMMC_BUSMODE); 7053a96dff0STony Prisk writeb(reg_tmp & BM_ONEBIT_MASK, priv->sdmmc_base + 7063a96dff0STony Prisk SDMMC_BUSMODE); 7073a96dff0STony Prisk 7083a96dff0STony Prisk reg_tmp = readb(priv->sdmmc_base + SDMMC_EXTCTRL); 7093a96dff0STony Prisk writeb(reg_tmp & 0xFB, priv->sdmmc_base + SDMMC_EXTCTRL); 7103a96dff0STony Prisk break; 7113a96dff0STony Prisk } 7123a96dff0STony Prisk } 7133a96dff0STony Prisk 7143a96dff0STony Prisk static int wmt_mci_get_ro(struct mmc_host *mmc) 7153a96dff0STony Prisk { 7163a96dff0STony Prisk struct wmt_mci_priv *priv = mmc_priv(mmc); 7173a96dff0STony Prisk 7183a96dff0STony Prisk return !(readb(priv->sdmmc_base + SDMMC_STS0) & STS0_WRITE_PROTECT); 7193a96dff0STony Prisk } 7203a96dff0STony Prisk 7213a96dff0STony Prisk static int wmt_mci_get_cd(struct mmc_host *mmc) 7223a96dff0STony Prisk { 7233a96dff0STony Prisk struct wmt_mci_priv *priv = mmc_priv(mmc); 7243a96dff0STony Prisk u32 cd = (readb(priv->sdmmc_base + SDMMC_STS0) & STS0_CD_GPI) >> 3; 7253a96dff0STony Prisk 7263a96dff0STony Prisk return !(cd ^ priv->cd_inverted); 7273a96dff0STony Prisk } 7283a96dff0STony Prisk 7293a96dff0STony Prisk static struct mmc_host_ops wmt_mci_ops = { 7303a96dff0STony Prisk .request = wmt_mci_request, 7313a96dff0STony Prisk .set_ios = wmt_mci_set_ios, 7323a96dff0STony Prisk .get_ro = wmt_mci_get_ro, 7333a96dff0STony Prisk .get_cd = wmt_mci_get_cd, 7343a96dff0STony Prisk }; 7353a96dff0STony Prisk 7363a96dff0STony Prisk /* Controller capabilities */ 7373a96dff0STony Prisk static struct wmt_mci_caps wm8505_caps = { 7383a96dff0STony Prisk .f_min = 390425, 7393a96dff0STony Prisk .f_max = 50000000, 7403a96dff0STony Prisk .ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34, 7413a96dff0STony Prisk .caps = MMC_CAP_4_BIT_DATA | MMC_CAP_MMC_HIGHSPEED | 7423a96dff0STony Prisk MMC_CAP_SD_HIGHSPEED, 7433a96dff0STony Prisk .max_seg_size = 65024, 7443a96dff0STony Prisk .max_segs = 128, 7453a96dff0STony Prisk .max_blk_size = 2048, 7463a96dff0STony Prisk }; 7473a96dff0STony Prisk 7483a96dff0STony Prisk static struct of_device_id wmt_mci_dt_ids[] = { 7493a96dff0STony Prisk { .compatible = "wm,wm8505-sdhc", .data = &wm8505_caps }, 7503a96dff0STony Prisk { /* Sentinel */ }, 7513a96dff0STony Prisk }; 7523a96dff0STony Prisk 7534e608e4eSGreg Kroah-Hartman static int wmt_mci_probe(struct platform_device *pdev) 7543a96dff0STony Prisk { 7553a96dff0STony Prisk struct mmc_host *mmc; 7563a96dff0STony Prisk struct wmt_mci_priv *priv; 7573a96dff0STony Prisk struct device_node *np = pdev->dev.of_node; 7583a96dff0STony Prisk const struct of_device_id *of_id = 7593a96dff0STony Prisk of_match_device(wmt_mci_dt_ids, &pdev->dev); 76043aaa50fSSachin Kamat const struct wmt_mci_caps *wmt_caps; 7613a96dff0STony Prisk int ret; 7623a96dff0STony Prisk int regular_irq, dma_irq; 7633a96dff0STony Prisk 7643a96dff0STony Prisk if (!of_id || !of_id->data) { 7653a96dff0STony Prisk dev_err(&pdev->dev, "Controller capabilities data missing\n"); 7663a96dff0STony Prisk return -EFAULT; 7673a96dff0STony Prisk } 7683a96dff0STony Prisk 76943aaa50fSSachin Kamat wmt_caps = of_id->data; 77043aaa50fSSachin Kamat 7713a96dff0STony Prisk if (!np) { 7723a96dff0STony Prisk dev_err(&pdev->dev, "Missing SDMMC description in devicetree\n"); 7733a96dff0STony Prisk return -EFAULT; 7743a96dff0STony Prisk } 7753a96dff0STony Prisk 7763a96dff0STony Prisk regular_irq = irq_of_parse_and_map(np, 0); 7773a96dff0STony Prisk dma_irq = irq_of_parse_and_map(np, 1); 7783a96dff0STony Prisk 7793a96dff0STony Prisk if (!regular_irq || !dma_irq) { 7803a96dff0STony Prisk dev_err(&pdev->dev, "Getting IRQs failed!\n"); 7813a96dff0STony Prisk ret = -ENXIO; 7823a96dff0STony Prisk goto fail1; 7833a96dff0STony Prisk } 7843a96dff0STony Prisk 7853a96dff0STony Prisk mmc = mmc_alloc_host(sizeof(struct wmt_mci_priv), &pdev->dev); 7863a96dff0STony Prisk if (!mmc) { 7873a96dff0STony Prisk dev_err(&pdev->dev, "Failed to allocate mmc_host\n"); 7883a96dff0STony Prisk ret = -ENOMEM; 7893a96dff0STony Prisk goto fail1; 7903a96dff0STony Prisk } 7913a96dff0STony Prisk 7923a96dff0STony Prisk mmc->ops = &wmt_mci_ops; 7933a96dff0STony Prisk mmc->f_min = wmt_caps->f_min; 7943a96dff0STony Prisk mmc->f_max = wmt_caps->f_max; 7953a96dff0STony Prisk mmc->ocr_avail = wmt_caps->ocr_avail; 7963a96dff0STony Prisk mmc->caps = wmt_caps->caps; 7973a96dff0STony Prisk 7983a96dff0STony Prisk mmc->max_seg_size = wmt_caps->max_seg_size; 7993a96dff0STony Prisk mmc->max_segs = wmt_caps->max_segs; 8003a96dff0STony Prisk mmc->max_blk_size = wmt_caps->max_blk_size; 8013a96dff0STony Prisk 8023a96dff0STony Prisk mmc->max_req_size = (16*512*mmc->max_segs); 8033a96dff0STony Prisk mmc->max_blk_count = mmc->max_req_size / 512; 8043a96dff0STony Prisk 8053a96dff0STony Prisk priv = mmc_priv(mmc); 8063a96dff0STony Prisk priv->mmc = mmc; 8073a96dff0STony Prisk priv->dev = &pdev->dev; 8083a96dff0STony Prisk 8093a96dff0STony Prisk priv->power_inverted = 0; 8103a96dff0STony Prisk priv->cd_inverted = 0; 8113a96dff0STony Prisk 8123a96dff0STony Prisk if (of_get_property(np, "sdon-inverted", NULL)) 8133a96dff0STony Prisk priv->power_inverted = 1; 8143a96dff0STony Prisk if (of_get_property(np, "cd-inverted", NULL)) 8153a96dff0STony Prisk priv->cd_inverted = 1; 8163a96dff0STony Prisk 8173a96dff0STony Prisk priv->sdmmc_base = of_iomap(np, 0); 8183a96dff0STony Prisk if (!priv->sdmmc_base) { 8193a96dff0STony Prisk dev_err(&pdev->dev, "Failed to map IO space\n"); 8203a96dff0STony Prisk ret = -ENOMEM; 8213a96dff0STony Prisk goto fail2; 8223a96dff0STony Prisk } 8233a96dff0STony Prisk 8243a96dff0STony Prisk priv->irq_regular = regular_irq; 8253a96dff0STony Prisk priv->irq_dma = dma_irq; 8263a96dff0STony Prisk 8273a96dff0STony Prisk ret = request_irq(regular_irq, wmt_mci_regular_isr, 0, "sdmmc", priv); 8283a96dff0STony Prisk if (ret) { 8293a96dff0STony Prisk dev_err(&pdev->dev, "Register regular IRQ fail\n"); 8303a96dff0STony Prisk goto fail3; 8313a96dff0STony Prisk } 8323a96dff0STony Prisk 8333a96dff0STony Prisk ret = request_irq(dma_irq, wmt_mci_dma_isr, 32, "sdmmc", priv); 8343a96dff0STony Prisk if (ret) { 8353a96dff0STony Prisk dev_err(&pdev->dev, "Register DMA IRQ fail\n"); 8363a96dff0STony Prisk goto fail4; 8373a96dff0STony Prisk } 8383a96dff0STony Prisk 8393a96dff0STony Prisk /* alloc some DMA buffers for descriptors/transfers */ 8403a96dff0STony Prisk priv->dma_desc_buffer = dma_alloc_coherent(&pdev->dev, 8413a96dff0STony Prisk mmc->max_blk_count * 16, 8423a96dff0STony Prisk &priv->dma_desc_device_addr, 8436f243f63SAxel Lin GFP_KERNEL); 8443a96dff0STony Prisk if (!priv->dma_desc_buffer) { 8453a96dff0STony Prisk dev_err(&pdev->dev, "DMA alloc fail\n"); 8463a96dff0STony Prisk ret = -EPERM; 8473a96dff0STony Prisk goto fail5; 8483a96dff0STony Prisk } 8493a96dff0STony Prisk 8503a96dff0STony Prisk platform_set_drvdata(pdev, mmc); 8513a96dff0STony Prisk 8523a96dff0STony Prisk priv->clk_sdmmc = of_clk_get(np, 0); 8533a96dff0STony Prisk if (IS_ERR(priv->clk_sdmmc)) { 8543a96dff0STony Prisk dev_err(&pdev->dev, "Error getting clock\n"); 8553a96dff0STony Prisk ret = PTR_ERR(priv->clk_sdmmc); 8563a96dff0STony Prisk goto fail5; 8573a96dff0STony Prisk } 8583a96dff0STony Prisk 8593a96dff0STony Prisk clk_prepare_enable(priv->clk_sdmmc); 8603a96dff0STony Prisk 8613a96dff0STony Prisk /* configure the controller to a known 'ready' state */ 8623a96dff0STony Prisk wmt_reset_hardware(mmc); 8633a96dff0STony Prisk 8643a96dff0STony Prisk mmc_add_host(mmc); 8653a96dff0STony Prisk 8663a96dff0STony Prisk dev_info(&pdev->dev, "WMT SDHC Controller initialized\n"); 8673a96dff0STony Prisk 8683a96dff0STony Prisk return 0; 8693a96dff0STony Prisk fail5: 8703a96dff0STony Prisk free_irq(dma_irq, priv); 8713a96dff0STony Prisk fail4: 8723a96dff0STony Prisk free_irq(regular_irq, priv); 8733a96dff0STony Prisk fail3: 8743a96dff0STony Prisk iounmap(priv->sdmmc_base); 8753a96dff0STony Prisk fail2: 8763a96dff0STony Prisk mmc_free_host(mmc); 8773a96dff0STony Prisk fail1: 8783a96dff0STony Prisk return ret; 8793a96dff0STony Prisk } 8803a96dff0STony Prisk 8814e608e4eSGreg Kroah-Hartman static int wmt_mci_remove(struct platform_device *pdev) 8823a96dff0STony Prisk { 8833a96dff0STony Prisk struct mmc_host *mmc; 8843a96dff0STony Prisk struct wmt_mci_priv *priv; 8853a96dff0STony Prisk struct resource *res; 8863a96dff0STony Prisk u32 reg_tmp; 8873a96dff0STony Prisk 8883a96dff0STony Prisk mmc = platform_get_drvdata(pdev); 8893a96dff0STony Prisk priv = mmc_priv(mmc); 8903a96dff0STony Prisk 8913a96dff0STony Prisk /* reset SD controller */ 8923a96dff0STony Prisk reg_tmp = readb(priv->sdmmc_base + SDMMC_BUSMODE); 8933a96dff0STony Prisk writel(reg_tmp | BM_SOFT_RESET, priv->sdmmc_base + SDMMC_BUSMODE); 8943a96dff0STony Prisk reg_tmp = readw(priv->sdmmc_base + SDMMC_BLKLEN); 8953a96dff0STony Prisk writew(reg_tmp & ~(0xA000), priv->sdmmc_base + SDMMC_BLKLEN); 8963a96dff0STony Prisk writeb(0xFF, priv->sdmmc_base + SDMMC_STS0); 8973a96dff0STony Prisk writeb(0xFF, priv->sdmmc_base + SDMMC_STS1); 8983a96dff0STony Prisk 8993a96dff0STony Prisk /* release the dma buffers */ 9003a96dff0STony Prisk dma_free_coherent(&pdev->dev, priv->mmc->max_blk_count * 16, 9013a96dff0STony Prisk priv->dma_desc_buffer, priv->dma_desc_device_addr); 9023a96dff0STony Prisk 9033a96dff0STony Prisk mmc_remove_host(mmc); 9043a96dff0STony Prisk 9053a96dff0STony Prisk free_irq(priv->irq_regular, priv); 9063a96dff0STony Prisk free_irq(priv->irq_dma, priv); 9073a96dff0STony Prisk 9083a96dff0STony Prisk iounmap(priv->sdmmc_base); 9093a96dff0STony Prisk 9103a96dff0STony Prisk clk_disable_unprepare(priv->clk_sdmmc); 9113a96dff0STony Prisk clk_put(priv->clk_sdmmc); 9123a96dff0STony Prisk 9133a96dff0STony Prisk res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 91422119901SAlexandru Gheorghiu release_mem_region(res->start, resource_size(res)); 9153a96dff0STony Prisk 9163a96dff0STony Prisk mmc_free_host(mmc); 9173a96dff0STony Prisk 9183a96dff0STony Prisk dev_info(&pdev->dev, "WMT MCI device removed\n"); 9193a96dff0STony Prisk 9203a96dff0STony Prisk return 0; 9213a96dff0STony Prisk } 9223a96dff0STony Prisk 9233a96dff0STony Prisk #ifdef CONFIG_PM 9243a96dff0STony Prisk static int wmt_mci_suspend(struct device *dev) 9253a96dff0STony Prisk { 9263a96dff0STony Prisk u32 reg_tmp; 9273a96dff0STony Prisk struct platform_device *pdev = to_platform_device(dev); 9283a96dff0STony Prisk struct mmc_host *mmc = platform_get_drvdata(pdev); 9293a96dff0STony Prisk struct wmt_mci_priv *priv; 9303a96dff0STony Prisk 9313a96dff0STony Prisk if (!mmc) 9323a96dff0STony Prisk return 0; 9333a96dff0STony Prisk 9343a96dff0STony Prisk priv = mmc_priv(mmc); 9353a96dff0STony Prisk reg_tmp = readb(priv->sdmmc_base + SDMMC_BUSMODE); 9363a96dff0STony Prisk writeb(reg_tmp | BM_SOFT_RESET, priv->sdmmc_base + 9373a96dff0STony Prisk SDMMC_BUSMODE); 9383a96dff0STony Prisk 9393a96dff0STony Prisk reg_tmp = readw(priv->sdmmc_base + SDMMC_BLKLEN); 9403a96dff0STony Prisk writew(reg_tmp & 0x5FFF, priv->sdmmc_base + SDMMC_BLKLEN); 9413a96dff0STony Prisk 9423a96dff0STony Prisk writeb(0xFF, priv->sdmmc_base + SDMMC_STS0); 9433a96dff0STony Prisk writeb(0xFF, priv->sdmmc_base + SDMMC_STS1); 9443a96dff0STony Prisk 9453a96dff0STony Prisk clk_disable(priv->clk_sdmmc); 9467af37663SUlf Hansson return 0; 9473a96dff0STony Prisk } 9483a96dff0STony Prisk 9493a96dff0STony Prisk static int wmt_mci_resume(struct device *dev) 9503a96dff0STony Prisk { 9513a96dff0STony Prisk u32 reg_tmp; 9523a96dff0STony Prisk struct platform_device *pdev = to_platform_device(dev); 9533a96dff0STony Prisk struct mmc_host *mmc = platform_get_drvdata(pdev); 9543a96dff0STony Prisk struct wmt_mci_priv *priv; 9553a96dff0STony Prisk 9563a96dff0STony Prisk if (mmc) { 9573a96dff0STony Prisk priv = mmc_priv(mmc); 9583a96dff0STony Prisk clk_enable(priv->clk_sdmmc); 9593a96dff0STony Prisk 9603a96dff0STony Prisk reg_tmp = readb(priv->sdmmc_base + SDMMC_BUSMODE); 9613a96dff0STony Prisk writeb(reg_tmp | BM_SOFT_RESET, priv->sdmmc_base + 9623a96dff0STony Prisk SDMMC_BUSMODE); 9633a96dff0STony Prisk 9643a96dff0STony Prisk reg_tmp = readw(priv->sdmmc_base + SDMMC_BLKLEN); 9653a96dff0STony Prisk writew(reg_tmp | (BLKL_GPI_CD | BLKL_INT_ENABLE), 9663a96dff0STony Prisk priv->sdmmc_base + SDMMC_BLKLEN); 9673a96dff0STony Prisk 9683a96dff0STony Prisk reg_tmp = readb(priv->sdmmc_base + SDMMC_INTMASK0); 9693a96dff0STony Prisk writeb(reg_tmp | INT0_DI_INT_EN, priv->sdmmc_base + 9703a96dff0STony Prisk SDMMC_INTMASK0); 9713a96dff0STony Prisk 9723a96dff0STony Prisk } 9733a96dff0STony Prisk 9747af37663SUlf Hansson return 0; 9753a96dff0STony Prisk } 9763a96dff0STony Prisk 9773a96dff0STony Prisk static const struct dev_pm_ops wmt_mci_pm = { 9783a96dff0STony Prisk .suspend = wmt_mci_suspend, 9793a96dff0STony Prisk .resume = wmt_mci_resume, 9803a96dff0STony Prisk }; 9813a96dff0STony Prisk 9823a96dff0STony Prisk #define wmt_mci_pm_ops (&wmt_mci_pm) 9833a96dff0STony Prisk 9843a96dff0STony Prisk #else /* !CONFIG_PM */ 9853a96dff0STony Prisk 9863a96dff0STony Prisk #define wmt_mci_pm_ops NULL 9873a96dff0STony Prisk 9883a96dff0STony Prisk #endif 9893a96dff0STony Prisk 9903a96dff0STony Prisk static struct platform_driver wmt_mci_driver = { 9913a96dff0STony Prisk .probe = wmt_mci_probe, 992893613b0STony Prisk .remove = wmt_mci_remove, 9933a96dff0STony Prisk .driver = { 9943a96dff0STony Prisk .name = DRIVER_NAME, 9953a96dff0STony Prisk .owner = THIS_MODULE, 9963a96dff0STony Prisk .pm = wmt_mci_pm_ops, 9973a96dff0STony Prisk .of_match_table = wmt_mci_dt_ids, 9983a96dff0STony Prisk }, 9993a96dff0STony Prisk }; 10003a96dff0STony Prisk 10013a96dff0STony Prisk module_platform_driver(wmt_mci_driver); 10023a96dff0STony Prisk 10033a96dff0STony Prisk MODULE_DESCRIPTION("Wondermedia MMC/SD Driver"); 10043a96dff0STony Prisk MODULE_AUTHOR("Tony Prisk"); 10053a96dff0STony Prisk MODULE_LICENSE("GPL v2"); 10063a96dff0STony Prisk MODULE_DEVICE_TABLE(of, wmt_mci_dt_ids); 1007