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