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