mmc: add atomic operation for register
authorlintao <lintao@rock-chips.com>
Mon, 22 Sep 2014 02:14:03 +0000 (10:14 +0800)
committerlintao <lintao@rock-chips.com>
Mon, 22 Sep 2014 02:17:20 +0000 (10:17 +0800)
drivers/mmc/host/rk_sdmmc.c
include/linux/mmc/rk_mmc.h

index 57fd3ea65c30155d1ccb3bbb1246664478d15f3d..59d3299b9b6adce37ace25cb1503c2c0f1e8360c 100755 (executable)
@@ -872,6 +872,7 @@ disable:
 static int dw_mci_submit_data_dma(struct dw_mci *host, struct mmc_data *data)
 {
        int sg_len;
+       unsigned long flags;
        u32 temp;
 
        host->using_dma = 0;
@@ -910,9 +911,11 @@ static int dw_mci_submit_data_dma(struct dw_mci *host, struct mmc_data *data)
        mci_writel(host, CTRL, temp);
 
        /* Disable RX/TX IRQs, let DMA handle it */
+       spin_lock_irqsave(&host->slock, flags);
        temp = mci_readl(host, INTMASK);
        temp  &= ~(SDMMC_INT_RXDR | SDMMC_INT_TXDR);
        mci_writel(host, INTMASK, temp);
+       spin_unlock_irqrestore(&host->slock, flags);
 
        host->dma_ops->start(host, sg_len);
 
@@ -922,6 +925,7 @@ static int dw_mci_submit_data_dma(struct dw_mci *host, struct mmc_data *data)
 static void dw_mci_submit_data(struct dw_mci *host, struct mmc_data *data)
 {
        u32 temp;
+       unsigned long flag;
 
        data->error = -EINPROGRESS;
 
@@ -954,10 +958,12 @@ static void dw_mci_submit_data(struct dw_mci *host, struct mmc_data *data)
                host->part_buf_start = 0;
                host->part_buf_count = 0;
 
+               spin_lock_irqsave(&host->slock, flag);
                mci_writel(host, RINTSTS, SDMMC_INT_TXDR | SDMMC_INT_RXDR);
                temp = mci_readl(host, INTMASK);
                temp |= SDMMC_INT_TXDR | SDMMC_INT_RXDR;
                mci_writel(host, INTMASK, temp);
+               spin_unlock_irqrestore(&host->slock, flag);
 
                temp = mci_readl(host, CTRL);
                temp &= ~SDMMC_CTRL_DMA_ENABLE;
@@ -1704,11 +1710,11 @@ static void dw_mci_enable_sdio_irq(struct mmc_host *mmc, int enb)
 {
        struct dw_mci_slot *slot = mmc_priv(mmc);
        struct dw_mci *host = slot->host;
-       //unsigned long flags;
+       unsigned long flags;
        u32 int_mask;
        u32 sdio_int;
 
-        //spin_lock_irqsave(&host->lock, flags);
+        spin_lock_irqsave(&host->slock, flags);
 
        /* Enable/disable Slot Specific SDIO interrupt */
        int_mask = mci_readl(host, INTMASK);
@@ -1734,7 +1740,7 @@ static void dw_mci_enable_sdio_irq(struct mmc_host *mmc, int enb)
                           (int_mask & ~sdio_int));
        }
 
-       //spin_unlock_irqrestore(&host->lock, flags);
+       spin_unlock_irqrestore(&host->slock, flags);
 }
 
 #ifdef CONFIG_MMC_DW_ROCKCHIP_SWITCH_VOLTAGE
@@ -3700,6 +3706,7 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
 static void dw_mci_dealwith_timeout(struct dw_mci *host)
 {
         u32 ret, i, regs;
+       u32 sdio_int;
 
         switch(host->state){
                 case STATE_IDLE:
@@ -3734,7 +3741,18 @@ static void dw_mci_dealwith_timeout(struct dw_mci *host)
                                         | SDMMC_INT_RXDR | SDMMC_INT_VSI | DW_MCI_ERROR_FLAGS;
                         if(!(host->mmc->restrict_caps & RESTRICT_CARD_TYPE_SDIO))
                                 regs |= SDMMC_INT_CD;
-                                mci_writel(host, INTMASK, regs);
+
+                       if ((host->mmc->restrict_caps & RESTRICT_CARD_TYPE_SDIO)) {
+                               if (host->verid < DW_MMC_240A)
+                                       sdio_int = SDMMC_INT_SDIO(0);
+                               else
+                                       sdio_int = SDMMC_INT_SDIO(8);
+
+                               if (mci_readl(host, INTMASK) & sdio_int)
+                                       regs |= sdio_int;
+                       }
+
+                       mci_writel(host, INTMASK, regs);
                         mci_writel(host, CTRL, SDMMC_CTRL_INT_ENABLE);
                         for (i = 0; i < host->num_slots; i++) {
                                 struct dw_mci_slot *slot = host->slot[i];
@@ -3758,6 +3776,7 @@ static void dw_mci_dto_timeout(unsigned long host_data)
 
        disable_irq(host->irq);
 
+       dev_err(host->dev, "data_over interrupt timeout!\n");
        host->data_status = SDMMC_INT_EBE;
        mci_writel(host, RINTSTS, 0xFFFFFFFF);
        dw_mci_dealwith_timeout(host);
@@ -3862,6 +3881,8 @@ int dw_mci_probe(struct dw_mci *host)
         host->svi_flags = 0;
 
        spin_lock_init(&host->lock);
+       spin_lock_init(&host->slock);
+
        INIT_LIST_HEAD(&host->queue);
        INIT_DELAYED_WORK(&host->resume_rescan, resume_rescan_enable);
        /*
index 1a4bf4c75d378fa7f2600a13da7de1dcad97ffa2..34a0413d351b0bd11f0055a300d6b3a0f7b82fdb 100755 (executable)
@@ -128,6 +128,7 @@ struct mmc_data;
  */
 struct dw_mci {
        spinlock_t              lock;
+       spinlock_t              slock;
        void __iomem            *regs;
 
        struct scatterlist      *sg;