diff options
author | Alagu Sankar <alagusankar@embwise.com> | 2011-01-03 02:13:27 -0500 |
---|---|---|
committer | Chris Ball <cjb@laptop.org> | 2011-01-09 19:16:18 -0500 |
commit | f9db92cb8084c756890ddf953e9329588c59e8e8 (patch) | |
tree | 463d0f1e10eb04f2325132031e4f8c50d62b9dc3 /drivers/mmc | |
parent | e9b86841b372de01ae865080118e29159d8b7c39 (diff) |
mmc: davinci: add support for SDIO irq handling
This patch adds support for handling SDIO interrupt on DaVinci MMC/SD
controller.
The patch has been tested on DM355 and DA850 EVMs with Marvell Libertas
based SDIO wireless LAN card.
Signed-off-by: Alagu Sankar <alagusankar@embwise.com>
Signed-off-by: Sekhar Nori <nsekhar@ti.com>
Signed-off-by: Chris Ball <cjb@laptop.org>
Diffstat (limited to 'drivers/mmc')
-rw-r--r-- | drivers/mmc/host/davinci_mmc.c | 78 |
1 files changed, 73 insertions, 5 deletions
diff --git a/drivers/mmc/host/davinci_mmc.c b/drivers/mmc/host/davinci_mmc.c index b643ddef4f70..0076c7448fe6 100644 --- a/drivers/mmc/host/davinci_mmc.c +++ b/drivers/mmc/host/davinci_mmc.c | |||
@@ -66,8 +66,8 @@ | |||
66 | #define DAVINCI_MMCBLNC 0x60 | 66 | #define DAVINCI_MMCBLNC 0x60 |
67 | #define DAVINCI_SDIOCTL 0x64 | 67 | #define DAVINCI_SDIOCTL 0x64 |
68 | #define DAVINCI_SDIOST0 0x68 | 68 | #define DAVINCI_SDIOST0 0x68 |
69 | #define DAVINCI_SDIOEN 0x6C | 69 | #define DAVINCI_SDIOIEN 0x6C |
70 | #define DAVINCI_SDIOST 0x70 | 70 | #define DAVINCI_SDIOIST 0x70 |
71 | #define DAVINCI_MMCFIFOCTL 0x74 /* FIFO Control Register */ | 71 | #define DAVINCI_MMCFIFOCTL 0x74 /* FIFO Control Register */ |
72 | 72 | ||
73 | /* DAVINCI_MMCCTL definitions */ | 73 | /* DAVINCI_MMCCTL definitions */ |
@@ -131,6 +131,14 @@ | |||
131 | #define MMCFIFOCTL_ACCWD_2 (2 << 3) /* access width of 2 bytes */ | 131 | #define MMCFIFOCTL_ACCWD_2 (2 << 3) /* access width of 2 bytes */ |
132 | #define MMCFIFOCTL_ACCWD_1 (3 << 3) /* access width of 1 byte */ | 132 | #define MMCFIFOCTL_ACCWD_1 (3 << 3) /* access width of 1 byte */ |
133 | 133 | ||
134 | /* DAVINCI_SDIOST0 definitions */ | ||
135 | #define SDIOST0_DAT1_HI BIT(0) | ||
136 | |||
137 | /* DAVINCI_SDIOIEN definitions */ | ||
138 | #define SDIOIEN_IOINTEN BIT(0) | ||
139 | |||
140 | /* DAVINCI_SDIOIST definitions */ | ||
141 | #define SDIOIST_IOINT BIT(0) | ||
134 | 142 | ||
135 | /* MMCSD Init clock in Hz in opendrain mode */ | 143 | /* MMCSD Init clock in Hz in opendrain mode */ |
136 | #define MMCSD_INIT_CLOCK 200000 | 144 | #define MMCSD_INIT_CLOCK 200000 |
@@ -164,7 +172,7 @@ struct mmc_davinci_host { | |||
164 | unsigned int mmc_input_clk; | 172 | unsigned int mmc_input_clk; |
165 | void __iomem *base; | 173 | void __iomem *base; |
166 | struct resource *mem_res; | 174 | struct resource *mem_res; |
167 | int irq; | 175 | int mmc_irq, sdio_irq; |
168 | unsigned char bus_mode; | 176 | unsigned char bus_mode; |
169 | 177 | ||
170 | #define DAVINCI_MMC_DATADIR_NONE 0 | 178 | #define DAVINCI_MMC_DATADIR_NONE 0 |
@@ -184,6 +192,7 @@ struct mmc_davinci_host { | |||
184 | u32 rxdma, txdma; | 192 | u32 rxdma, txdma; |
185 | bool use_dma; | 193 | bool use_dma; |
186 | bool do_dma; | 194 | bool do_dma; |
195 | bool sdio_int; | ||
187 | 196 | ||
188 | /* Scatterlist DMA uses one or more parameter RAM entries: | 197 | /* Scatterlist DMA uses one or more parameter RAM entries: |
189 | * the main one (associated with rxdma or txdma) plus zero or | 198 | * the main one (associated with rxdma or txdma) plus zero or |
@@ -866,6 +875,19 @@ mmc_davinci_xfer_done(struct mmc_davinci_host *host, struct mmc_data *data) | |||
866 | { | 875 | { |
867 | host->data = NULL; | 876 | host->data = NULL; |
868 | 877 | ||
878 | if (host->mmc->caps & MMC_CAP_SDIO_IRQ) { | ||
879 | /* | ||
880 | * SDIO Interrupt Detection work-around as suggested by | ||
881 | * Davinci Errata (TMS320DM355 Silicon Revision 1.1 Errata | ||
882 | * 2.1.6): Signal SDIO interrupt only if it is enabled by core | ||
883 | */ | ||
884 | if (host->sdio_int && !(readl(host->base + DAVINCI_SDIOST0) & | ||
885 | SDIOST0_DAT1_HI)) { | ||
886 | writel(SDIOIST_IOINT, host->base + DAVINCI_SDIOIST); | ||
887 | mmc_signal_sdio_irq(host->mmc); | ||
888 | } | ||
889 | } | ||
890 | |||
869 | if (host->do_dma) { | 891 | if (host->do_dma) { |
870 | davinci_abort_dma(host); | 892 | davinci_abort_dma(host); |
871 | 893 | ||
@@ -932,6 +954,21 @@ davinci_abort_data(struct mmc_davinci_host *host, struct mmc_data *data) | |||
932 | mmc_davinci_reset_ctrl(host, 0); | 954 | mmc_davinci_reset_ctrl(host, 0); |
933 | } | 955 | } |
934 | 956 | ||
957 | static irqreturn_t mmc_davinci_sdio_irq(int irq, void *dev_id) | ||
958 | { | ||
959 | struct mmc_davinci_host *host = dev_id; | ||
960 | unsigned int status; | ||
961 | |||
962 | status = readl(host->base + DAVINCI_SDIOIST); | ||
963 | if (status & SDIOIST_IOINT) { | ||
964 | dev_dbg(mmc_dev(host->mmc), | ||
965 | "SDIO interrupt status %x\n", status); | ||
966 | writel(status | SDIOIST_IOINT, host->base + DAVINCI_SDIOIST); | ||
967 | mmc_signal_sdio_irq(host->mmc); | ||
968 | } | ||
969 | return IRQ_HANDLED; | ||
970 | } | ||
971 | |||
935 | static irqreturn_t mmc_davinci_irq(int irq, void *dev_id) | 972 | static irqreturn_t mmc_davinci_irq(int irq, void *dev_id) |
936 | { | 973 | { |
937 | struct mmc_davinci_host *host = (struct mmc_davinci_host *)dev_id; | 974 | struct mmc_davinci_host *host = (struct mmc_davinci_host *)dev_id; |
@@ -1076,11 +1113,32 @@ static int mmc_davinci_get_ro(struct mmc_host *mmc) | |||
1076 | return config->get_ro(pdev->id); | 1113 | return config->get_ro(pdev->id); |
1077 | } | 1114 | } |
1078 | 1115 | ||
1116 | static void mmc_davinci_enable_sdio_irq(struct mmc_host *mmc, int enable) | ||
1117 | { | ||
1118 | struct mmc_davinci_host *host = mmc_priv(mmc); | ||
1119 | |||
1120 | if (enable) { | ||
1121 | if (!(readl(host->base + DAVINCI_SDIOST0) & SDIOST0_DAT1_HI)) { | ||
1122 | writel(SDIOIST_IOINT, host->base + DAVINCI_SDIOIST); | ||
1123 | mmc_signal_sdio_irq(host->mmc); | ||
1124 | } else { | ||
1125 | host->sdio_int = true; | ||
1126 | writel(readl(host->base + DAVINCI_SDIOIEN) | | ||
1127 | SDIOIEN_IOINTEN, host->base + DAVINCI_SDIOIEN); | ||
1128 | } | ||
1129 | } else { | ||
1130 | host->sdio_int = false; | ||
1131 | writel(readl(host->base + DAVINCI_SDIOIEN) & ~SDIOIEN_IOINTEN, | ||
1132 | host->base + DAVINCI_SDIOIEN); | ||
1133 | } | ||
1134 | } | ||
1135 | |||
1079 | static struct mmc_host_ops mmc_davinci_ops = { | 1136 | static struct mmc_host_ops mmc_davinci_ops = { |
1080 | .request = mmc_davinci_request, | 1137 | .request = mmc_davinci_request, |
1081 | .set_ios = mmc_davinci_set_ios, | 1138 | .set_ios = mmc_davinci_set_ios, |
1082 | .get_cd = mmc_davinci_get_cd, | 1139 | .get_cd = mmc_davinci_get_cd, |
1083 | .get_ro = mmc_davinci_get_ro, | 1140 | .get_ro = mmc_davinci_get_ro, |
1141 | .enable_sdio_irq = mmc_davinci_enable_sdio_irq, | ||
1084 | }; | 1142 | }; |
1085 | 1143 | ||
1086 | /*----------------------------------------------------------------------*/ | 1144 | /*----------------------------------------------------------------------*/ |
@@ -1209,7 +1267,8 @@ static int __init davinci_mmcsd_probe(struct platform_device *pdev) | |||
1209 | host->nr_sg = MAX_NR_SG; | 1267 | host->nr_sg = MAX_NR_SG; |
1210 | 1268 | ||
1211 | host->use_dma = use_dma; | 1269 | host->use_dma = use_dma; |
1212 | host->irq = irq; | 1270 | host->mmc_irq = irq; |
1271 | host->sdio_irq = platform_get_irq(pdev, 1); | ||
1213 | 1272 | ||
1214 | if (host->use_dma && davinci_acquire_dma_channels(host) != 0) | 1273 | if (host->use_dma && davinci_acquire_dma_channels(host) != 0) |
1215 | host->use_dma = 0; | 1274 | host->use_dma = 0; |
@@ -1270,6 +1329,13 @@ static int __init davinci_mmcsd_probe(struct platform_device *pdev) | |||
1270 | if (ret) | 1329 | if (ret) |
1271 | goto out; | 1330 | goto out; |
1272 | 1331 | ||
1332 | if (host->sdio_irq >= 0) { | ||
1333 | ret = request_irq(host->sdio_irq, mmc_davinci_sdio_irq, 0, | ||
1334 | mmc_hostname(mmc), host); | ||
1335 | if (!ret) | ||
1336 | mmc->caps |= MMC_CAP_SDIO_IRQ; | ||
1337 | } | ||
1338 | |||
1273 | rename_region(mem, mmc_hostname(mmc)); | 1339 | rename_region(mem, mmc_hostname(mmc)); |
1274 | 1340 | ||
1275 | dev_info(mmc_dev(host->mmc), "Using %s, %d-bit mode\n", | 1341 | dev_info(mmc_dev(host->mmc), "Using %s, %d-bit mode\n", |
@@ -1313,7 +1379,9 @@ static int __exit davinci_mmcsd_remove(struct platform_device *pdev) | |||
1313 | mmc_davinci_cpufreq_deregister(host); | 1379 | mmc_davinci_cpufreq_deregister(host); |
1314 | 1380 | ||
1315 | mmc_remove_host(host->mmc); | 1381 | mmc_remove_host(host->mmc); |
1316 | free_irq(host->irq, host); | 1382 | free_irq(host->mmc_irq, host); |
1383 | if (host->mmc->caps & MMC_CAP_SDIO_IRQ) | ||
1384 | free_irq(host->sdio_irq, host); | ||
1317 | 1385 | ||
1318 | davinci_release_dma_channels(host); | 1386 | davinci_release_dma_channels(host); |
1319 | 1387 | ||