via-sdmmc.c (a1c613ae4c322ddd58d5a8539dbfba2a0380a8c0) via-sdmmc.c (921c87ba3893b5d3608e7f248366266b40b86c75)
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * drivers/mmc/host/via-sdmmc.c - VIA SD/MMC Card Reader driver
4 * Copyright (c) 2008, VIA Technologies Inc. All Rights Reserved.
5 */
6
7#include <linux/pci.h>
8#include <linux/module.h>
9#include <linux/dma-mapping.h>
10#include <linux/highmem.h>
11#include <linux/delay.h>
12#include <linux/interrupt.h>
13
14#include <linux/mmc/host.h>
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * drivers/mmc/host/via-sdmmc.c - VIA SD/MMC Card Reader driver
4 * Copyright (c) 2008, VIA Technologies Inc. All Rights Reserved.
5 */
6
7#include <linux/pci.h>
8#include <linux/module.h>
9#include <linux/dma-mapping.h>
10#include <linux/highmem.h>
11#include <linux/delay.h>
12#include <linux/interrupt.h>
13
14#include <linux/mmc/host.h>
15#include <linux/workqueue.h>
15
16#define DRV_NAME "via_sdmmc"
17
18#define PCI_DEVICE_ID_VIA_9530 0x9530
19
20#define VIA_CRDR_SDC_OFF 0x200
21#define VIA_CRDR_DDMA_OFF 0x400
22#define VIA_CRDR_PCICTRL_OFF 0x600

--- 279 unchanged lines hidden (view full) ---

302 void __iomem *sdhc_mmiobase;
303 void __iomem *ddma_mmiobase;
304 void __iomem *pcictrl_mmiobase;
305
306 struct pcictrlreg pm_pcictrl_reg;
307 struct sdhcreg pm_sdhc_reg;
308
309 struct work_struct carddet_work;
16
17#define DRV_NAME "via_sdmmc"
18
19#define PCI_DEVICE_ID_VIA_9530 0x9530
20
21#define VIA_CRDR_SDC_OFF 0x200
22#define VIA_CRDR_DDMA_OFF 0x400
23#define VIA_CRDR_PCICTRL_OFF 0x600

--- 279 unchanged lines hidden (view full) ---

303 void __iomem *sdhc_mmiobase;
304 void __iomem *ddma_mmiobase;
305 void __iomem *pcictrl_mmiobase;
306
307 struct pcictrlreg pm_pcictrl_reg;
308 struct sdhcreg pm_sdhc_reg;
309
310 struct work_struct carddet_work;
310 struct tasklet_struct finish_tasklet;
311 struct work_struct finish_bh_work;
311
312 struct timer_list timer;
313 spinlock_t lock;
314 u8 power;
315 int reject;
316 unsigned int quirks;
317};
318

--- 319 unchanged lines hidden (view full) ---

638
639 dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
640 ((data->flags & MMC_DATA_READ) ?
641 DMA_FROM_DEVICE : DMA_TO_DEVICE));
642
643 if (data->stop)
644 via_sdc_send_command(host, data->stop);
645 else
312
313 struct timer_list timer;
314 spinlock_t lock;
315 u8 power;
316 int reject;
317 unsigned int quirks;
318};
319

--- 319 unchanged lines hidden (view full) ---

639
640 dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
641 ((data->flags & MMC_DATA_READ) ?
642 DMA_FROM_DEVICE : DMA_TO_DEVICE));
643
644 if (data->stop)
645 via_sdc_send_command(host, data->stop);
646 else
646 tasklet_schedule(&host->finish_tasklet);
647 queue_work(system_bh_wq, &host->finish_bh_work);
647}
648
649static void via_sdc_finish_command(struct via_crdr_mmc_host *host)
650{
651 via_sdc_get_response(host, host->cmd);
652
653 host->cmd->error = 0;
654
655 if (!host->cmd->data)
648}
649
650static void via_sdc_finish_command(struct via_crdr_mmc_host *host)
651{
652 via_sdc_get_response(host, host->cmd);
653
654 host->cmd->error = 0;
655
656 if (!host->cmd->data)
656 tasklet_schedule(&host->finish_tasklet);
657 queue_work(system_bh_wq, &host->finish_bh_work);
657
658 host->cmd = NULL;
659}
660
661static void via_sdc_request(struct mmc_host *mmc, struct mmc_request *mrq)
662{
663 void __iomem *addrbase;
664 struct via_crdr_mmc_host *host;

--- 12 unchanged lines hidden (view full) ---

677 writew(status, host->sdhc_mmiobase + VIA_CRDR_SDSTATUS);
678
679 WARN_ON(host->mrq != NULL);
680 host->mrq = mrq;
681
682 status = readw(host->sdhc_mmiobase + VIA_CRDR_SDSTATUS);
683 if (!(status & VIA_CRDR_SDSTS_SLOTG) || host->reject) {
684 host->mrq->cmd->error = -ENOMEDIUM;
658
659 host->cmd = NULL;
660}
661
662static void via_sdc_request(struct mmc_host *mmc, struct mmc_request *mrq)
663{
664 void __iomem *addrbase;
665 struct via_crdr_mmc_host *host;

--- 12 unchanged lines hidden (view full) ---

678 writew(status, host->sdhc_mmiobase + VIA_CRDR_SDSTATUS);
679
680 WARN_ON(host->mrq != NULL);
681 host->mrq = mrq;
682
683 status = readw(host->sdhc_mmiobase + VIA_CRDR_SDSTATUS);
684 if (!(status & VIA_CRDR_SDSTS_SLOTG) || host->reject) {
685 host->mrq->cmd->error = -ENOMEDIUM;
685 tasklet_schedule(&host->finish_tasklet);
686 queue_work(system_bh_wq, &host->finish_bh_work);
686 } else {
687 via_sdc_send_command(host, mrq->cmd);
688 }
689
690 spin_unlock_irqrestore(&host->lock, flags);
691}
692
693static void via_sdc_set_power(struct via_crdr_mmc_host *host,

--- 149 unchanged lines hidden (view full) ---

843 }
844
845 if (intmask & VIA_CRDR_SDSTS_CRTO)
846 host->cmd->error = -ETIMEDOUT;
847 else if (intmask & VIA_CRDR_SDSTS_SC)
848 host->cmd->error = -EILSEQ;
849
850 if (host->cmd->error)
687 } else {
688 via_sdc_send_command(host, mrq->cmd);
689 }
690
691 spin_unlock_irqrestore(&host->lock, flags);
692}
693
694static void via_sdc_set_power(struct via_crdr_mmc_host *host,

--- 149 unchanged lines hidden (view full) ---

844 }
845
846 if (intmask & VIA_CRDR_SDSTS_CRTO)
847 host->cmd->error = -ETIMEDOUT;
848 else if (intmask & VIA_CRDR_SDSTS_SC)
849 host->cmd->error = -EILSEQ;
850
851 if (host->cmd->error)
851 tasklet_schedule(&host->finish_tasklet);
852 queue_work(system_bh_wq, &host->finish_bh_work);
852 else if (intmask & VIA_CRDR_SDSTS_CRD)
853 via_sdc_finish_command(host);
854}
855
856static void via_sdc_data_isr(struct via_crdr_mmc_host *host, u16 intmask)
857{
858 BUG_ON(intmask == 0);
859

--- 90 unchanged lines hidden (view full) ---

950 sdhost->ddma_mmiobase + VIA_CRDR_DMACTRL);
951 sdhost->data->error = -ETIMEDOUT;
952 via_sdc_finish_data(sdhost);
953 } else {
954 if (sdhost->cmd)
955 sdhost->cmd->error = -ETIMEDOUT;
956 else
957 sdhost->mrq->cmd->error = -ETIMEDOUT;
853 else if (intmask & VIA_CRDR_SDSTS_CRD)
854 via_sdc_finish_command(host);
855}
856
857static void via_sdc_data_isr(struct via_crdr_mmc_host *host, u16 intmask)
858{
859 BUG_ON(intmask == 0);
860

--- 90 unchanged lines hidden (view full) ---

951 sdhost->ddma_mmiobase + VIA_CRDR_DMACTRL);
952 sdhost->data->error = -ETIMEDOUT;
953 via_sdc_finish_data(sdhost);
954 } else {
955 if (sdhost->cmd)
956 sdhost->cmd->error = -ETIMEDOUT;
957 else
958 sdhost->mrq->cmd->error = -ETIMEDOUT;
958 tasklet_schedule(&sdhost->finish_tasklet);
959 queue_work(system_bh_wq, &sdhost->finish_bh_work);
959 }
960 }
961
962 spin_unlock_irqrestore(&sdhost->lock, flags);
963}
964
960 }
961 }
962
963 spin_unlock_irqrestore(&sdhost->lock, flags);
964}
965
965static void via_sdc_tasklet_finish(struct tasklet_struct *t)
966static void via_sdc_finish_bh_work(struct work_struct *t)
966{
967{
967 struct via_crdr_mmc_host *host = from_tasklet(host, t, finish_tasklet);
968 struct via_crdr_mmc_host *host = from_work(host, t, finish_bh_work);
968 unsigned long flags;
969 struct mmc_request *mrq;
970
971 spin_lock_irqsave(&host->lock, flags);
972
973 del_timer(&host->timer);
974 mrq = host->mrq;
975 host->mrq = NULL;

--- 24 unchanged lines hidden (view full) ---

1000
1001 addrbase = host->sdhc_mmiobase;
1002 status = readw(addrbase + VIA_CRDR_SDSTATUS);
1003 if (!(status & VIA_CRDR_SDSTS_SLOTG)) {
1004 if (host->mrq) {
1005 pr_err("%s: Card removed during transfer!\n",
1006 mmc_hostname(host->mmc));
1007 host->mrq->cmd->error = -ENOMEDIUM;
969 unsigned long flags;
970 struct mmc_request *mrq;
971
972 spin_lock_irqsave(&host->lock, flags);
973
974 del_timer(&host->timer);
975 mrq = host->mrq;
976 host->mrq = NULL;

--- 24 unchanged lines hidden (view full) ---

1001
1002 addrbase = host->sdhc_mmiobase;
1003 status = readw(addrbase + VIA_CRDR_SDSTATUS);
1004 if (!(status & VIA_CRDR_SDSTS_SLOTG)) {
1005 if (host->mrq) {
1006 pr_err("%s: Card removed during transfer!\n",
1007 mmc_hostname(host->mmc));
1008 host->mrq->cmd->error = -ENOMEDIUM;
1008 tasklet_schedule(&host->finish_tasklet);
1009 queue_work(system_bh_wq, &host->finish_bh_work);
1009 }
1010
1011 spin_unlock_irqrestore(&host->lock, flags);
1012
1013 via_reset_pcictrl(host);
1014
1015 spin_lock_irqsave(&host->lock, flags);
1016 }

--- 29 unchanged lines hidden (view full) ---

1046 mmc->max_blk_size = VIA_CRDR_MAX_BLOCK_LENGTH;
1047 mmc->max_blk_count = VIA_CRDR_MAX_BLOCK_COUNT;
1048
1049 mmc->max_seg_size = mmc->max_blk_size * mmc->max_blk_count;
1050 mmc->max_req_size = mmc->max_seg_size;
1051
1052 INIT_WORK(&host->carddet_work, via_sdc_card_detect);
1053
1010 }
1011
1012 spin_unlock_irqrestore(&host->lock, flags);
1013
1014 via_reset_pcictrl(host);
1015
1016 spin_lock_irqsave(&host->lock, flags);
1017 }

--- 29 unchanged lines hidden (view full) ---

1047 mmc->max_blk_size = VIA_CRDR_MAX_BLOCK_LENGTH;
1048 mmc->max_blk_count = VIA_CRDR_MAX_BLOCK_COUNT;
1049
1050 mmc->max_seg_size = mmc->max_blk_size * mmc->max_blk_count;
1051 mmc->max_req_size = mmc->max_seg_size;
1052
1053 INIT_WORK(&host->carddet_work, via_sdc_card_detect);
1054
1054 tasklet_setup(&host->finish_tasklet, via_sdc_tasklet_finish);
1055 INIT_WORK(&host->finish_bh_work, via_sdc_finish_bh_work);
1055
1056 addrbase = host->sdhc_mmiobase;
1057 writel(0x0, addrbase + VIA_CRDR_SDINTMASK);
1058 msleep(1);
1059
1060 lenreg = VIA_CRDR_SDBLKLEN_GPIDET | VIA_CRDR_SDBLKLEN_INTEN;
1061 writel(lenreg, addrbase + VIA_CRDR_SDBLKLEN);
1062

--- 125 unchanged lines hidden (view full) ---

1188 "transfer\n", mmc_hostname(sdhost->mmc));
1189
1190 /* make sure all DMA is stopped */
1191 writel(VIA_CRDR_DMACTRL_SFTRST,
1192 sdhost->ddma_mmiobase + VIA_CRDR_DMACTRL);
1193 sdhost->mrq->cmd->error = -ENOMEDIUM;
1194 if (sdhost->mrq->stop)
1195 sdhost->mrq->stop->error = -ENOMEDIUM;
1056
1057 addrbase = host->sdhc_mmiobase;
1058 writel(0x0, addrbase + VIA_CRDR_SDINTMASK);
1059 msleep(1);
1060
1061 lenreg = VIA_CRDR_SDBLKLEN_GPIDET | VIA_CRDR_SDBLKLEN_INTEN;
1062 writel(lenreg, addrbase + VIA_CRDR_SDBLKLEN);
1063

--- 125 unchanged lines hidden (view full) ---

1189 "transfer\n", mmc_hostname(sdhost->mmc));
1190
1191 /* make sure all DMA is stopped */
1192 writel(VIA_CRDR_DMACTRL_SFTRST,
1193 sdhost->ddma_mmiobase + VIA_CRDR_DMACTRL);
1194 sdhost->mrq->cmd->error = -ENOMEDIUM;
1195 if (sdhost->mrq->stop)
1196 sdhost->mrq->stop->error = -ENOMEDIUM;
1196 tasklet_schedule(&sdhost->finish_tasklet);
1197 queue_work(system_bh_wq, &sdhost->finish_bh_work);
1197 }
1198 spin_unlock_irqrestore(&sdhost->lock, flags);
1199
1200 mmc_remove_host(sdhost->mmc);
1201
1202 free_irq(pcidev->irq, sdhost);
1203
1204 del_timer_sync(&sdhost->timer);
1205
1198 }
1199 spin_unlock_irqrestore(&sdhost->lock, flags);
1200
1201 mmc_remove_host(sdhost->mmc);
1202
1203 free_irq(pcidev->irq, sdhost);
1204
1205 del_timer_sync(&sdhost->timer);
1206
1206 tasklet_kill(&sdhost->finish_tasklet);
1207 cancel_work_sync(&sdhost->finish_bh_work);
1207
1208 /* switch off power */
1209 gatt = readb(sdhost->pcictrl_mmiobase + VIA_CRDR_PCICLKGATT);
1210 gatt &= ~VIA_CRDR_PCICLKGATT_PAD_PWRON;
1211 writeb(gatt, sdhost->pcictrl_mmiobase + VIA_CRDR_PCICLKGATT);
1212
1213 iounmap(sdhost->mmiobase);
1214 mmc_free_host(sdhost->mmc);

--- 100 unchanged lines hidden ---
1208
1209 /* switch off power */
1210 gatt = readb(sdhost->pcictrl_mmiobase + VIA_CRDR_PCICLKGATT);
1211 gatt &= ~VIA_CRDR_PCICLKGATT_PAD_PWRON;
1212 writeb(gatt, sdhost->pcictrl_mmiobase + VIA_CRDR_PCICLKGATT);
1213
1214 iounmap(sdhost->mmiobase);
1215 mmc_free_host(sdhost->mmc);

--- 100 unchanged lines hidden ---