diff options
author | Pierre Ossman <drzeus-list@cx.rmk.(none)> | 2005-05-08 14:35:27 -0400 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2005-05-08 14:35:27 -0400 |
commit | 85bcc13072c54592596c5b41d40d1c6a18b04e19 (patch) | |
tree | 1f3fe7a88f37ed72f6cdaf6117f0299caf4ab59a /drivers/mmc/wbsd.c | |
parent | 88d7bd8cb9eb8d64bf7997600b0d64f7834047c5 (diff) |
[PATCH] MMC: wbsd update
Updates to the wbsd driver.
* Fix to handle DAT3 card detection.
* Fixed bug which could cause large writes to stall in FIFO mode.
* Plug 'n Play support. In most cases you need ACPI PNP for this to work.
* Uses generic DMA API (ISA dependency removed).
Diffstat (limited to 'drivers/mmc/wbsd.c')
-rw-r--r-- | drivers/mmc/wbsd.c | 716 |
1 files changed, 531 insertions, 185 deletions
diff --git a/drivers/mmc/wbsd.c b/drivers/mmc/wbsd.c index 39747526c719..b7fbd30b49a0 100644 --- a/drivers/mmc/wbsd.c +++ b/drivers/mmc/wbsd.c | |||
@@ -28,7 +28,9 @@ | |||
28 | #include <linux/ioport.h> | 28 | #include <linux/ioport.h> |
29 | #include <linux/device.h> | 29 | #include <linux/device.h> |
30 | #include <linux/interrupt.h> | 30 | #include <linux/interrupt.h> |
31 | #include <linux/dma-mapping.h> | ||
31 | #include <linux/delay.h> | 32 | #include <linux/delay.h> |
33 | #include <linux/pnp.h> | ||
32 | #include <linux/highmem.h> | 34 | #include <linux/highmem.h> |
33 | #include <linux/mmc/host.h> | 35 | #include <linux/mmc/host.h> |
34 | #include <linux/mmc/protocol.h> | 36 | #include <linux/mmc/protocol.h> |
@@ -40,7 +42,7 @@ | |||
40 | #include "wbsd.h" | 42 | #include "wbsd.h" |
41 | 43 | ||
42 | #define DRIVER_NAME "wbsd" | 44 | #define DRIVER_NAME "wbsd" |
43 | #define DRIVER_VERSION "1.1" | 45 | #define DRIVER_VERSION "1.2" |
44 | 46 | ||
45 | #ifdef CONFIG_MMC_DEBUG | 47 | #ifdef CONFIG_MMC_DEBUG |
46 | #define DBG(x...) \ | 48 | #define DBG(x...) \ |
@@ -52,10 +54,6 @@ | |||
52 | #define DBGF(x...) do { } while (0) | 54 | #define DBGF(x...) do { } while (0) |
53 | #endif | 55 | #endif |
54 | 56 | ||
55 | static unsigned int io = 0x248; | ||
56 | static unsigned int irq = 6; | ||
57 | static int dma = 2; | ||
58 | |||
59 | #ifdef CONFIG_MMC_DEBUG | 57 | #ifdef CONFIG_MMC_DEBUG |
60 | void DBG_REG(int reg, u8 value) | 58 | void DBG_REG(int reg, u8 value) |
61 | { | 59 | { |
@@ -79,28 +77,61 @@ void DBG_REG(int reg, u8 value) | |||
79 | #endif | 77 | #endif |
80 | 78 | ||
81 | /* | 79 | /* |
80 | * Device resources | ||
81 | */ | ||
82 | |||
83 | #ifdef CONFIG_PNP | ||
84 | |||
85 | static const struct pnp_device_id pnp_dev_table[] = { | ||
86 | { "WEC0517", 0 }, | ||
87 | { "WEC0518", 0 }, | ||
88 | { "", 0 }, | ||
89 | }; | ||
90 | |||
91 | MODULE_DEVICE_TABLE(pnp, pnp_dev_table); | ||
92 | |||
93 | #endif /* CONFIG_PNP */ | ||
94 | |||
95 | #ifdef CONFIG_PNP | ||
96 | static unsigned int nopnp = 0; | ||
97 | #else | ||
98 | static const unsigned int nopnp = 1; | ||
99 | #endif | ||
100 | static unsigned int io = 0x248; | ||
101 | static unsigned int irq = 6; | ||
102 | static int dma = 2; | ||
103 | |||
104 | /* | ||
82 | * Basic functions | 105 | * Basic functions |
83 | */ | 106 | */ |
84 | 107 | ||
85 | static inline void wbsd_unlock_config(struct wbsd_host* host) | 108 | static inline void wbsd_unlock_config(struct wbsd_host* host) |
86 | { | 109 | { |
110 | BUG_ON(host->config == 0); | ||
111 | |||
87 | outb(host->unlock_code, host->config); | 112 | outb(host->unlock_code, host->config); |
88 | outb(host->unlock_code, host->config); | 113 | outb(host->unlock_code, host->config); |
89 | } | 114 | } |
90 | 115 | ||
91 | static inline void wbsd_lock_config(struct wbsd_host* host) | 116 | static inline void wbsd_lock_config(struct wbsd_host* host) |
92 | { | 117 | { |
118 | BUG_ON(host->config == 0); | ||
119 | |||
93 | outb(LOCK_CODE, host->config); | 120 | outb(LOCK_CODE, host->config); |
94 | } | 121 | } |
95 | 122 | ||
96 | static inline void wbsd_write_config(struct wbsd_host* host, u8 reg, u8 value) | 123 | static inline void wbsd_write_config(struct wbsd_host* host, u8 reg, u8 value) |
97 | { | 124 | { |
125 | BUG_ON(host->config == 0); | ||
126 | |||
98 | outb(reg, host->config); | 127 | outb(reg, host->config); |
99 | outb(value, host->config + 1); | 128 | outb(value, host->config + 1); |
100 | } | 129 | } |
101 | 130 | ||
102 | static inline u8 wbsd_read_config(struct wbsd_host* host, u8 reg) | 131 | static inline u8 wbsd_read_config(struct wbsd_host* host, u8 reg) |
103 | { | 132 | { |
133 | BUG_ON(host->config == 0); | ||
134 | |||
104 | outb(reg, host->config); | 135 | outb(reg, host->config); |
105 | return inb(host->config + 1); | 136 | return inb(host->config + 1); |
106 | } | 137 | } |
@@ -133,6 +164,13 @@ static void wbsd_init_device(struct wbsd_host* host) | |||
133 | wbsd_write_index(host, WBSD_IDX_SETUP, setup); | 164 | wbsd_write_index(host, WBSD_IDX_SETUP, setup); |
134 | 165 | ||
135 | /* | 166 | /* |
167 | * Set DAT3 to input | ||
168 | */ | ||
169 | setup &= ~WBSD_DAT3_H; | ||
170 | wbsd_write_index(host, WBSD_IDX_SETUP, setup); | ||
171 | host->flags &= ~WBSD_FIGNORE_DETECT; | ||
172 | |||
173 | /* | ||
136 | * Read back default clock. | 174 | * Read back default clock. |
137 | */ | 175 | */ |
138 | host->clk = wbsd_read_index(host, WBSD_IDX_CLK); | 176 | host->clk = wbsd_read_index(host, WBSD_IDX_CLK); |
@@ -148,6 +186,14 @@ static void wbsd_init_device(struct wbsd_host* host) | |||
148 | wbsd_write_index(host, WBSD_IDX_TAAC, 0x7F); | 186 | wbsd_write_index(host, WBSD_IDX_TAAC, 0x7F); |
149 | 187 | ||
150 | /* | 188 | /* |
189 | * Test for card presence | ||
190 | */ | ||
191 | if (inb(host->base + WBSD_CSR) & WBSD_CARDPRESENT) | ||
192 | host->flags |= WBSD_FCARD_PRESENT; | ||
193 | else | ||
194 | host->flags &= ~WBSD_FCARD_PRESENT; | ||
195 | |||
196 | /* | ||
151 | * Enable interesting interrupts. | 197 | * Enable interesting interrupts. |
152 | */ | 198 | */ |
153 | ier = 0; | 199 | ier = 0; |
@@ -407,8 +453,6 @@ static inline void wbsd_get_long_reply(struct wbsd_host* host, | |||
407 | } | 453 | } |
408 | } | 454 | } |
409 | 455 | ||
410 | static irqreturn_t wbsd_irq(int irq, void *dev_id, struct pt_regs *regs); | ||
411 | |||
412 | static void wbsd_send_command(struct wbsd_host* host, struct mmc_command* cmd) | 456 | static void wbsd_send_command(struct wbsd_host* host, struct mmc_command* cmd) |
413 | { | 457 | { |
414 | int i; | 458 | int i; |
@@ -646,6 +690,13 @@ static void wbsd_fill_fifo(struct wbsd_host* host) | |||
646 | } | 690 | } |
647 | 691 | ||
648 | wbsd_kunmap_sg(host); | 692 | wbsd_kunmap_sg(host); |
693 | |||
694 | /* | ||
695 | * The controller stops sending interrupts for | ||
696 | * 'FIFO empty' under certain conditions. So we | ||
697 | * need to be a bit more pro-active. | ||
698 | */ | ||
699 | tasklet_schedule(&host->fifo_tasklet); | ||
649 | } | 700 | } |
650 | 701 | ||
651 | static void wbsd_prepare_data(struct wbsd_host* host, struct mmc_data* data) | 702 | static void wbsd_prepare_data(struct wbsd_host* host, struct mmc_data* data) |
@@ -850,9 +901,11 @@ static void wbsd_finish_data(struct wbsd_host* host, struct mmc_data* data) | |||
850 | wbsd_request_end(host, host->mrq); | 901 | wbsd_request_end(host, host->mrq); |
851 | } | 902 | } |
852 | 903 | ||
853 | /* | 904 | /*****************************************************************************\ |
854 | * MMC Callbacks | 905 | * * |
855 | */ | 906 | * MMC layer callbacks * |
907 | * * | ||
908 | \*****************************************************************************/ | ||
856 | 909 | ||
857 | static void wbsd_request(struct mmc_host* mmc, struct mmc_request* mrq) | 910 | static void wbsd_request(struct mmc_host* mmc, struct mmc_request* mrq) |
858 | { | 911 | { |
@@ -874,7 +927,7 @@ static void wbsd_request(struct mmc_host* mmc, struct mmc_request* mrq) | |||
874 | * If there is no card in the slot then | 927 | * If there is no card in the slot then |
875 | * timeout immediatly. | 928 | * timeout immediatly. |
876 | */ | 929 | */ |
877 | if (!(inb(host->base + WBSD_CSR) & WBSD_CARDPRESENT)) | 930 | if (!(host->flags & WBSD_FCARD_PRESENT)) |
878 | { | 931 | { |
879 | cmd->error = MMC_ERR_TIMEOUT; | 932 | cmd->error = MMC_ERR_TIMEOUT; |
880 | goto done; | 933 | goto done; |
@@ -953,33 +1006,50 @@ static void wbsd_set_ios(struct mmc_host* mmc, struct mmc_ios* ios) | |||
953 | host->clk = clk; | 1006 | host->clk = clk; |
954 | } | 1007 | } |
955 | 1008 | ||
1009 | /* | ||
1010 | * Power up card. | ||
1011 | */ | ||
956 | if (ios->power_mode != MMC_POWER_OFF) | 1012 | if (ios->power_mode != MMC_POWER_OFF) |
957 | { | 1013 | { |
958 | /* | ||
959 | * Power up card. | ||
960 | */ | ||
961 | pwr = inb(host->base + WBSD_CSR); | 1014 | pwr = inb(host->base + WBSD_CSR); |
962 | pwr &= ~WBSD_POWER_N; | 1015 | pwr &= ~WBSD_POWER_N; |
963 | outb(pwr, host->base + WBSD_CSR); | 1016 | outb(pwr, host->base + WBSD_CSR); |
964 | |||
965 | /* | ||
966 | * This behaviour is stolen from the | ||
967 | * Windows driver. Don't know why, but | ||
968 | * it is needed. | ||
969 | */ | ||
970 | setup = wbsd_read_index(host, WBSD_IDX_SETUP); | ||
971 | if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN) | ||
972 | setup |= WBSD_DAT3_H; | ||
973 | else | ||
974 | setup &= ~WBSD_DAT3_H; | ||
975 | wbsd_write_index(host, WBSD_IDX_SETUP, setup); | ||
976 | |||
977 | mdelay(1); | ||
978 | } | 1017 | } |
979 | 1018 | ||
1019 | /* | ||
1020 | * MMC cards need to have pin 1 high during init. | ||
1021 | * Init time corresponds rather nicely with the bus mode. | ||
1022 | * It wreaks havoc with the card detection though so | ||
1023 | * that needs to be disabed. | ||
1024 | */ | ||
1025 | setup = wbsd_read_index(host, WBSD_IDX_SETUP); | ||
1026 | if ((ios->power_mode == MMC_POWER_ON) && | ||
1027 | (ios->bus_mode == MMC_BUSMODE_OPENDRAIN)) | ||
1028 | { | ||
1029 | setup |= WBSD_DAT3_H; | ||
1030 | host->flags |= WBSD_FIGNORE_DETECT; | ||
1031 | } | ||
1032 | else | ||
1033 | { | ||
1034 | setup &= ~WBSD_DAT3_H; | ||
1035 | host->flags &= ~WBSD_FIGNORE_DETECT; | ||
1036 | } | ||
1037 | wbsd_write_index(host, WBSD_IDX_SETUP, setup); | ||
1038 | |||
980 | spin_unlock_bh(&host->lock); | 1039 | spin_unlock_bh(&host->lock); |
981 | } | 1040 | } |
982 | 1041 | ||
1042 | static struct mmc_host_ops wbsd_ops = { | ||
1043 | .request = wbsd_request, | ||
1044 | .set_ios = wbsd_set_ios, | ||
1045 | }; | ||
1046 | |||
1047 | /*****************************************************************************\ | ||
1048 | * * | ||
1049 | * Interrupt handling * | ||
1050 | * * | ||
1051 | \*****************************************************************************/ | ||
1052 | |||
983 | /* | 1053 | /* |
984 | * Tasklets | 1054 | * Tasklets |
985 | */ | 1055 | */ |
@@ -1005,17 +1075,33 @@ static void wbsd_tasklet_card(unsigned long param) | |||
1005 | { | 1075 | { |
1006 | struct wbsd_host* host = (struct wbsd_host*)param; | 1076 | struct wbsd_host* host = (struct wbsd_host*)param; |
1007 | u8 csr; | 1077 | u8 csr; |
1078 | int change = 0; | ||
1008 | 1079 | ||
1009 | spin_lock(&host->lock); | 1080 | spin_lock(&host->lock); |
1010 | 1081 | ||
1082 | if (host->flags & WBSD_FIGNORE_DETECT) | ||
1083 | { | ||
1084 | spin_unlock(&host->lock); | ||
1085 | return; | ||
1086 | } | ||
1087 | |||
1011 | csr = inb(host->base + WBSD_CSR); | 1088 | csr = inb(host->base + WBSD_CSR); |
1012 | WARN_ON(csr == 0xff); | 1089 | WARN_ON(csr == 0xff); |
1013 | 1090 | ||
1014 | if (csr & WBSD_CARDPRESENT) | 1091 | if (csr & WBSD_CARDPRESENT) |
1015 | DBG("Card inserted\n"); | 1092 | { |
1016 | else | 1093 | if (!(host->flags & WBSD_FCARD_PRESENT)) |
1094 | { | ||
1095 | DBG("Card inserted\n"); | ||
1096 | host->flags |= WBSD_FCARD_PRESENT; | ||
1097 | change = 1; | ||
1098 | } | ||
1099 | } | ||
1100 | else if (host->flags & WBSD_FCARD_PRESENT) | ||
1017 | { | 1101 | { |
1018 | DBG("Card removed\n"); | 1102 | DBG("Card removed\n"); |
1103 | host->flags &= ~WBSD_FCARD_PRESENT; | ||
1104 | change = 1; | ||
1019 | 1105 | ||
1020 | if (host->mrq) | 1106 | if (host->mrq) |
1021 | { | 1107 | { |
@@ -1033,7 +1119,8 @@ static void wbsd_tasklet_card(unsigned long param) | |||
1033 | */ | 1119 | */ |
1034 | spin_unlock(&host->lock); | 1120 | spin_unlock(&host->lock); |
1035 | 1121 | ||
1036 | mmc_detect_change(host->mmc); | 1122 | if (change) |
1123 | mmc_detect_change(host->mmc); | ||
1037 | } | 1124 | } |
1038 | 1125 | ||
1039 | static void wbsd_tasklet_fifo(unsigned long param) | 1126 | static void wbsd_tasklet_fifo(unsigned long param) |
@@ -1200,11 +1287,85 @@ static irqreturn_t wbsd_irq(int irq, void *dev_id, struct pt_regs *regs) | |||
1200 | return IRQ_HANDLED; | 1287 | return IRQ_HANDLED; |
1201 | } | 1288 | } |
1202 | 1289 | ||
1290 | /*****************************************************************************\ | ||
1291 | * * | ||
1292 | * Device initialisation and shutdown * | ||
1293 | * * | ||
1294 | \*****************************************************************************/ | ||
1295 | |||
1203 | /* | 1296 | /* |
1204 | * Support functions for probe | 1297 | * Allocate/free MMC structure. |
1205 | */ | 1298 | */ |
1206 | 1299 | ||
1207 | static int wbsd_scan(struct wbsd_host* host) | 1300 | static int __devinit wbsd_alloc_mmc(struct device* dev) |
1301 | { | ||
1302 | struct mmc_host* mmc; | ||
1303 | struct wbsd_host* host; | ||
1304 | |||
1305 | /* | ||
1306 | * Allocate MMC structure. | ||
1307 | */ | ||
1308 | mmc = mmc_alloc_host(sizeof(struct wbsd_host), dev); | ||
1309 | if (!mmc) | ||
1310 | return -ENOMEM; | ||
1311 | |||
1312 | host = mmc_priv(mmc); | ||
1313 | host->mmc = mmc; | ||
1314 | |||
1315 | host->dma = -1; | ||
1316 | |||
1317 | /* | ||
1318 | * Set host parameters. | ||
1319 | */ | ||
1320 | mmc->ops = &wbsd_ops; | ||
1321 | mmc->f_min = 375000; | ||
1322 | mmc->f_max = 24000000; | ||
1323 | mmc->ocr_avail = MMC_VDD_32_33|MMC_VDD_33_34; | ||
1324 | |||
1325 | spin_lock_init(&host->lock); | ||
1326 | |||
1327 | /* | ||
1328 | * Maximum number of segments. Worst case is one sector per segment | ||
1329 | * so this will be 64kB/512. | ||
1330 | */ | ||
1331 | mmc->max_hw_segs = 128; | ||
1332 | mmc->max_phys_segs = 128; | ||
1333 | |||
1334 | /* | ||
1335 | * Maximum number of sectors in one transfer. Also limited by 64kB | ||
1336 | * buffer. | ||
1337 | */ | ||
1338 | mmc->max_sectors = 128; | ||
1339 | |||
1340 | /* | ||
1341 | * Maximum segment size. Could be one segment with the maximum number | ||
1342 | * of segments. | ||
1343 | */ | ||
1344 | mmc->max_seg_size = mmc->max_sectors * 512; | ||
1345 | |||
1346 | dev_set_drvdata(dev, mmc); | ||
1347 | |||
1348 | return 0; | ||
1349 | } | ||
1350 | |||
1351 | static void __devexit wbsd_free_mmc(struct device* dev) | ||
1352 | { | ||
1353 | struct mmc_host* mmc; | ||
1354 | |||
1355 | mmc = dev_get_drvdata(dev); | ||
1356 | if (!mmc) | ||
1357 | return; | ||
1358 | |||
1359 | mmc_free_host(mmc); | ||
1360 | |||
1361 | dev_set_drvdata(dev, NULL); | ||
1362 | } | ||
1363 | |||
1364 | /* | ||
1365 | * Scan for known chip id:s | ||
1366 | */ | ||
1367 | |||
1368 | static int __devinit wbsd_scan(struct wbsd_host* host) | ||
1208 | { | 1369 | { |
1209 | int i, j, k; | 1370 | int i, j, k; |
1210 | int id; | 1371 | int id; |
@@ -1258,12 +1419,16 @@ static int wbsd_scan(struct wbsd_host* host) | |||
1258 | return -ENODEV; | 1419 | return -ENODEV; |
1259 | } | 1420 | } |
1260 | 1421 | ||
1261 | static int wbsd_request_regions(struct wbsd_host* host) | 1422 | /* |
1423 | * Allocate/free io port ranges | ||
1424 | */ | ||
1425 | |||
1426 | static int __devinit wbsd_request_region(struct wbsd_host* host, int base) | ||
1262 | { | 1427 | { |
1263 | if (io & 0x7) | 1428 | if (io & 0x7) |
1264 | return -EINVAL; | 1429 | return -EINVAL; |
1265 | 1430 | ||
1266 | if (!request_region(io, 8, DRIVER_NAME)) | 1431 | if (!request_region(base, 8, DRIVER_NAME)) |
1267 | return -EIO; | 1432 | return -EIO; |
1268 | 1433 | ||
1269 | host->base = io; | 1434 | host->base = io; |
@@ -1271,19 +1436,25 @@ static int wbsd_request_regions(struct wbsd_host* host) | |||
1271 | return 0; | 1436 | return 0; |
1272 | } | 1437 | } |
1273 | 1438 | ||
1274 | static void wbsd_release_regions(struct wbsd_host* host) | 1439 | static void __devexit wbsd_release_regions(struct wbsd_host* host) |
1275 | { | 1440 | { |
1276 | if (host->base) | 1441 | if (host->base) |
1277 | release_region(host->base, 8); | 1442 | release_region(host->base, 8); |
1443 | |||
1444 | host->base = 0; | ||
1278 | 1445 | ||
1279 | if (host->config) | 1446 | if (host->config) |
1280 | release_region(host->config, 2); | 1447 | release_region(host->config, 2); |
1448 | |||
1449 | host->config = 0; | ||
1281 | } | 1450 | } |
1282 | 1451 | ||
1283 | static void wbsd_init_dma(struct wbsd_host* host) | 1452 | /* |
1453 | * Allocate/free DMA port and buffer | ||
1454 | */ | ||
1455 | |||
1456 | static void __devinit wbsd_request_dma(struct wbsd_host* host, int dma) | ||
1284 | { | 1457 | { |
1285 | host->dma = -1; | ||
1286 | |||
1287 | if (dma < 0) | 1458 | if (dma < 0) |
1288 | return; | 1459 | return; |
1289 | 1460 | ||
@@ -1294,7 +1465,7 @@ static void wbsd_init_dma(struct wbsd_host* host) | |||
1294 | * We need to allocate a special buffer in | 1465 | * We need to allocate a special buffer in |
1295 | * order for ISA to be able to DMA to it. | 1466 | * order for ISA to be able to DMA to it. |
1296 | */ | 1467 | */ |
1297 | host->dma_buffer = kmalloc(65536, | 1468 | host->dma_buffer = kmalloc(WBSD_DMA_SIZE, |
1298 | GFP_NOIO | GFP_DMA | __GFP_REPEAT | __GFP_NOWARN); | 1469 | GFP_NOIO | GFP_DMA | __GFP_REPEAT | __GFP_NOWARN); |
1299 | if (!host->dma_buffer) | 1470 | if (!host->dma_buffer) |
1300 | goto free; | 1471 | goto free; |
@@ -1302,7 +1473,8 @@ static void wbsd_init_dma(struct wbsd_host* host) | |||
1302 | /* | 1473 | /* |
1303 | * Translate the address to a physical address. | 1474 | * Translate the address to a physical address. |
1304 | */ | 1475 | */ |
1305 | host->dma_addr = isa_virt_to_bus(host->dma_buffer); | 1476 | host->dma_addr = dma_map_single(host->mmc->dev, host->dma_buffer, |
1477 | WBSD_DMA_SIZE, DMA_BIDIRECTIONAL); | ||
1306 | 1478 | ||
1307 | /* | 1479 | /* |
1308 | * ISA DMA must be aligned on a 64k basis. | 1480 | * ISA DMA must be aligned on a 64k basis. |
@@ -1325,6 +1497,10 @@ kfree: | |||
1325 | */ | 1497 | */ |
1326 | BUG_ON(1); | 1498 | BUG_ON(1); |
1327 | 1499 | ||
1500 | dma_unmap_single(host->mmc->dev, host->dma_addr, WBSD_DMA_SIZE, | ||
1501 | DMA_BIDIRECTIONAL); | ||
1502 | host->dma_addr = (dma_addr_t)NULL; | ||
1503 | |||
1328 | kfree(host->dma_buffer); | 1504 | kfree(host->dma_buffer); |
1329 | host->dma_buffer = NULL; | 1505 | host->dma_buffer = NULL; |
1330 | 1506 | ||
@@ -1336,60 +1512,122 @@ err: | |||
1336 | "Falling back on FIFO.\n", dma); | 1512 | "Falling back on FIFO.\n", dma); |
1337 | } | 1513 | } |
1338 | 1514 | ||
1339 | static struct mmc_host_ops wbsd_ops = { | 1515 | static void __devexit wbsd_release_dma(struct wbsd_host* host) |
1340 | .request = wbsd_request, | 1516 | { |
1341 | .set_ios = wbsd_set_ios, | 1517 | if (host->dma_addr) |
1342 | }; | 1518 | dma_unmap_single(host->mmc->dev, host->dma_addr, WBSD_DMA_SIZE, |
1519 | DMA_BIDIRECTIONAL); | ||
1520 | if (host->dma_buffer) | ||
1521 | kfree(host->dma_buffer); | ||
1522 | if (host->dma >= 0) | ||
1523 | free_dma(host->dma); | ||
1524 | |||
1525 | host->dma = -1; | ||
1526 | host->dma_buffer = NULL; | ||
1527 | host->dma_addr = (dma_addr_t)NULL; | ||
1528 | } | ||
1343 | 1529 | ||
1344 | /* | 1530 | /* |
1345 | * Device probe | 1531 | * Allocate/free IRQ. |
1346 | */ | 1532 | */ |
1347 | 1533 | ||
1348 | static int wbsd_probe(struct device* dev) | 1534 | static int __devinit wbsd_request_irq(struct wbsd_host* host, int irq) |
1349 | { | 1535 | { |
1350 | struct wbsd_host* host = NULL; | ||
1351 | struct mmc_host* mmc = NULL; | ||
1352 | int ret; | 1536 | int ret; |
1353 | 1537 | ||
1354 | /* | 1538 | /* |
1355 | * Allocate MMC structure. | 1539 | * Allocate interrupt. |
1356 | */ | 1540 | */ |
1357 | mmc = mmc_alloc_host(sizeof(struct wbsd_host), dev); | 1541 | |
1358 | if (!mmc) | 1542 | ret = request_irq(irq, wbsd_irq, SA_SHIRQ, DRIVER_NAME, host); |
1359 | return -ENOMEM; | 1543 | if (ret) |
1360 | 1544 | return ret; | |
1361 | host = mmc_priv(mmc); | ||
1362 | host->mmc = mmc; | ||
1363 | 1545 | ||
1546 | host->irq = irq; | ||
1547 | |||
1364 | /* | 1548 | /* |
1365 | * Scan for hardware. | 1549 | * Set up tasklets. |
1366 | */ | 1550 | */ |
1367 | ret = wbsd_scan(host); | 1551 | tasklet_init(&host->card_tasklet, wbsd_tasklet_card, (unsigned long)host); |
1368 | if (ret) | 1552 | tasklet_init(&host->fifo_tasklet, wbsd_tasklet_fifo, (unsigned long)host); |
1369 | goto freemmc; | 1553 | tasklet_init(&host->crc_tasklet, wbsd_tasklet_crc, (unsigned long)host); |
1554 | tasklet_init(&host->timeout_tasklet, wbsd_tasklet_timeout, (unsigned long)host); | ||
1555 | tasklet_init(&host->finish_tasklet, wbsd_tasklet_finish, (unsigned long)host); | ||
1556 | tasklet_init(&host->block_tasklet, wbsd_tasklet_block, (unsigned long)host); | ||
1557 | |||
1558 | return 0; | ||
1559 | } | ||
1370 | 1560 | ||
1371 | /* | 1561 | static void __devexit wbsd_release_irq(struct wbsd_host* host) |
1372 | * Reset the chip. | 1562 | { |
1373 | */ | 1563 | if (!host->irq) |
1374 | wbsd_write_config(host, WBSD_CONF_SWRST, 1); | 1564 | return; |
1375 | wbsd_write_config(host, WBSD_CONF_SWRST, 0); | ||
1376 | 1565 | ||
1566 | free_irq(host->irq, host); | ||
1567 | |||
1568 | host->irq = 0; | ||
1569 | |||
1570 | tasklet_kill(&host->card_tasklet); | ||
1571 | tasklet_kill(&host->fifo_tasklet); | ||
1572 | tasklet_kill(&host->crc_tasklet); | ||
1573 | tasklet_kill(&host->timeout_tasklet); | ||
1574 | tasklet_kill(&host->finish_tasklet); | ||
1575 | tasklet_kill(&host->block_tasklet); | ||
1576 | } | ||
1577 | |||
1578 | /* | ||
1579 | * Allocate all resources for the host. | ||
1580 | */ | ||
1581 | |||
1582 | static int __devinit wbsd_request_resources(struct wbsd_host* host, | ||
1583 | int base, int irq, int dma) | ||
1584 | { | ||
1585 | int ret; | ||
1586 | |||
1377 | /* | 1587 | /* |
1378 | * Allocate I/O ports. | 1588 | * Allocate I/O ports. |
1379 | */ | 1589 | */ |
1380 | ret = wbsd_request_regions(host); | 1590 | ret = wbsd_request_region(host, base); |
1381 | if (ret) | 1591 | if (ret) |
1382 | goto release; | 1592 | return ret; |
1383 | 1593 | ||
1384 | /* | 1594 | /* |
1385 | * Set host parameters. | 1595 | * Allocate interrupt. |
1386 | */ | 1596 | */ |
1387 | mmc->ops = &wbsd_ops; | 1597 | ret = wbsd_request_irq(host, irq); |
1388 | mmc->f_min = 375000; | 1598 | if (ret) |
1389 | mmc->f_max = 24000000; | 1599 | return ret; |
1390 | mmc->ocr_avail = MMC_VDD_32_33|MMC_VDD_33_34; | 1600 | |
1601 | /* | ||
1602 | * Allocate DMA. | ||
1603 | */ | ||
1604 | wbsd_request_dma(host, dma); | ||
1391 | 1605 | ||
1392 | spin_lock_init(&host->lock); | 1606 | return 0; |
1607 | } | ||
1608 | |||
1609 | /* | ||
1610 | * Release all resources for the host. | ||
1611 | */ | ||
1612 | |||
1613 | static void __devexit wbsd_release_resources(struct wbsd_host* host) | ||
1614 | { | ||
1615 | wbsd_release_dma(host); | ||
1616 | wbsd_release_irq(host); | ||
1617 | wbsd_release_regions(host); | ||
1618 | } | ||
1619 | |||
1620 | /* | ||
1621 | * Configure the resources the chip should use. | ||
1622 | */ | ||
1623 | |||
1624 | static void __devinit wbsd_chip_config(struct wbsd_host* host) | ||
1625 | { | ||
1626 | /* | ||
1627 | * Reset the chip. | ||
1628 | */ | ||
1629 | wbsd_write_config(host, WBSD_CONF_SWRST, 1); | ||
1630 | wbsd_write_config(host, WBSD_CONF_SWRST, 0); | ||
1393 | 1631 | ||
1394 | /* | 1632 | /* |
1395 | * Select SD/MMC function. | 1633 | * Select SD/MMC function. |
@@ -1399,165 +1637,241 @@ static int wbsd_probe(struct device* dev) | |||
1399 | /* | 1637 | /* |
1400 | * Set up card detection. | 1638 | * Set up card detection. |
1401 | */ | 1639 | */ |
1402 | wbsd_write_config(host, WBSD_CONF_PINS, 0x02); | 1640 | wbsd_write_config(host, WBSD_CONF_PINS, WBSD_PINS_DETECT_GP11); |
1403 | 1641 | ||
1404 | /* | 1642 | /* |
1405 | * Configure I/O port. | 1643 | * Configure chip |
1406 | */ | 1644 | */ |
1407 | wbsd_write_config(host, WBSD_CONF_PORT_HI, host->base >> 8); | 1645 | wbsd_write_config(host, WBSD_CONF_PORT_HI, host->base >> 8); |
1408 | wbsd_write_config(host, WBSD_CONF_PORT_LO, host->base & 0xff); | 1646 | wbsd_write_config(host, WBSD_CONF_PORT_LO, host->base & 0xff); |
1409 | |||
1410 | /* | ||
1411 | * Allocate interrupt. | ||
1412 | */ | ||
1413 | ret = request_irq(irq, wbsd_irq, SA_SHIRQ, DRIVER_NAME, host); | ||
1414 | if (ret) | ||
1415 | goto release; | ||
1416 | 1647 | ||
1417 | host->irq = irq; | 1648 | wbsd_write_config(host, WBSD_CONF_IRQ, host->irq); |
1418 | 1649 | ||
1419 | /* | 1650 | if (host->dma >= 0) |
1420 | * Set up tasklets. | 1651 | wbsd_write_config(host, WBSD_CONF_DRQ, host->dma); |
1421 | */ | ||
1422 | tasklet_init(&host->card_tasklet, wbsd_tasklet_card, (unsigned long)host); | ||
1423 | tasklet_init(&host->fifo_tasklet, wbsd_tasklet_fifo, (unsigned long)host); | ||
1424 | tasklet_init(&host->crc_tasklet, wbsd_tasklet_crc, (unsigned long)host); | ||
1425 | tasklet_init(&host->timeout_tasklet, wbsd_tasklet_timeout, (unsigned long)host); | ||
1426 | tasklet_init(&host->finish_tasklet, wbsd_tasklet_finish, (unsigned long)host); | ||
1427 | tasklet_init(&host->block_tasklet, wbsd_tasklet_block, (unsigned long)host); | ||
1428 | 1652 | ||
1429 | /* | 1653 | /* |
1430 | * Configure interrupt. | 1654 | * Enable and power up chip. |
1431 | */ | 1655 | */ |
1432 | wbsd_write_config(host, WBSD_CONF_IRQ, host->irq); | 1656 | wbsd_write_config(host, WBSD_CONF_ENABLE, 1); |
1657 | wbsd_write_config(host, WBSD_CONF_POWER, 0x20); | ||
1658 | } | ||
1659 | |||
1660 | /* | ||
1661 | * Check that configured resources are correct. | ||
1662 | */ | ||
1663 | |||
1664 | static int __devinit wbsd_chip_validate(struct wbsd_host* host) | ||
1665 | { | ||
1666 | int base, irq, dma; | ||
1433 | 1667 | ||
1434 | /* | 1668 | /* |
1435 | * Allocate DMA. | 1669 | * Select SD/MMC function. |
1436 | */ | 1670 | */ |
1437 | wbsd_init_dma(host); | 1671 | wbsd_write_config(host, WBSD_CONF_DEVICE, DEVICE_SD); |
1438 | 1672 | ||
1439 | /* | 1673 | /* |
1440 | * If all went well, then configure DMA. | 1674 | * Read configuration. |
1441 | */ | 1675 | */ |
1442 | if (host->dma >= 0) | 1676 | base = wbsd_read_config(host, WBSD_CONF_PORT_HI) << 8; |
1443 | wbsd_write_config(host, WBSD_CONF_DRQ, host->dma); | 1677 | base |= wbsd_read_config(host, WBSD_CONF_PORT_LO); |
1444 | 1678 | ||
1445 | /* | 1679 | irq = wbsd_read_config(host, WBSD_CONF_IRQ); |
1446 | * Maximum number of segments. Worst case is one sector per segment | 1680 | |
1447 | * so this will be 64kB/512. | 1681 | dma = wbsd_read_config(host, WBSD_CONF_DRQ); |
1448 | */ | ||
1449 | mmc->max_hw_segs = 128; | ||
1450 | mmc->max_phys_segs = 128; | ||
1451 | 1682 | ||
1452 | /* | 1683 | /* |
1453 | * Maximum number of sectors in one transfer. Also limited by 64kB | 1684 | * Validate against given configuration. |
1454 | * buffer. | ||
1455 | */ | 1685 | */ |
1456 | mmc->max_sectors = 128; | 1686 | if (base != host->base) |
1687 | return 0; | ||
1688 | if (irq != host->irq) | ||
1689 | return 0; | ||
1690 | if ((dma != host->dma) && (host->dma != -1)) | ||
1691 | return 0; | ||
1692 | |||
1693 | return 1; | ||
1694 | } | ||
1695 | |||
1696 | /*****************************************************************************\ | ||
1697 | * * | ||
1698 | * Devices setup and shutdown * | ||
1699 | * * | ||
1700 | \*****************************************************************************/ | ||
1701 | |||
1702 | static int __devinit wbsd_init(struct device* dev, int base, int irq, int dma, | ||
1703 | int pnp) | ||
1704 | { | ||
1705 | struct wbsd_host* host = NULL; | ||
1706 | struct mmc_host* mmc = NULL; | ||
1707 | int ret; | ||
1708 | |||
1709 | ret = wbsd_alloc_mmc(dev); | ||
1710 | if (ret) | ||
1711 | return ret; | ||
1712 | |||
1713 | mmc = dev_get_drvdata(dev); | ||
1714 | host = mmc_priv(mmc); | ||
1457 | 1715 | ||
1458 | /* | 1716 | /* |
1459 | * Maximum segment size. Could be one segment with the maximum number | 1717 | * Scan for hardware. |
1460 | * of segments. | ||
1461 | */ | 1718 | */ |
1462 | mmc->max_seg_size = mmc->max_sectors * 512; | 1719 | ret = wbsd_scan(host); |
1720 | if (ret) | ||
1721 | { | ||
1722 | if (pnp && (ret == -ENODEV)) | ||
1723 | { | ||
1724 | printk(KERN_WARNING DRIVER_NAME | ||
1725 | ": Unable to confirm device presence. You may " | ||
1726 | "experience lock-ups.\n"); | ||
1727 | } | ||
1728 | else | ||
1729 | { | ||
1730 | wbsd_free_mmc(dev); | ||
1731 | return ret; | ||
1732 | } | ||
1733 | } | ||
1463 | 1734 | ||
1464 | /* | 1735 | /* |
1465 | * Enable chip. | 1736 | * Request resources. |
1466 | */ | 1737 | */ |
1467 | wbsd_write_config(host, WBSD_CONF_ENABLE, 1); | 1738 | ret = wbsd_request_resources(host, io, irq, dma); |
1739 | if (ret) | ||
1740 | { | ||
1741 | wbsd_release_resources(host); | ||
1742 | wbsd_free_mmc(dev); | ||
1743 | return ret; | ||
1744 | } | ||
1468 | 1745 | ||
1469 | /* | 1746 | /* |
1470 | * Power up chip. | 1747 | * See if chip needs to be configured. |
1471 | */ | 1748 | */ |
1472 | wbsd_write_config(host, WBSD_CONF_POWER, 0x20); | 1749 | if (pnp && (host->config != 0)) |
1750 | { | ||
1751 | if (!wbsd_chip_validate(host)) | ||
1752 | { | ||
1753 | printk(KERN_WARNING DRIVER_NAME | ||
1754 | ": PnP active but chip not configured! " | ||
1755 | "You probably have a buggy BIOS. " | ||
1756 | "Configuring chip manually.\n"); | ||
1757 | wbsd_chip_config(host); | ||
1758 | } | ||
1759 | } | ||
1760 | else | ||
1761 | wbsd_chip_config(host); | ||
1473 | 1762 | ||
1474 | /* | 1763 | /* |
1475 | * Power Management stuff. No idea how this works. | 1764 | * Power Management stuff. No idea how this works. |
1476 | * Not tested. | 1765 | * Not tested. |
1477 | */ | 1766 | */ |
1478 | #ifdef CONFIG_PM | 1767 | #ifdef CONFIG_PM |
1479 | wbsd_write_config(host, WBSD_CONF_PME, 0xA0); | 1768 | if (host->config) |
1769 | wbsd_write_config(host, WBSD_CONF_PME, 0xA0); | ||
1480 | #endif | 1770 | #endif |
1771 | /* | ||
1772 | * Allow device to initialise itself properly. | ||
1773 | */ | ||
1774 | mdelay(5); | ||
1481 | 1775 | ||
1482 | /* | 1776 | /* |
1483 | * Reset the chip into a known state. | 1777 | * Reset the chip into a known state. |
1484 | */ | 1778 | */ |
1485 | wbsd_init_device(host); | 1779 | wbsd_init_device(host); |
1486 | 1780 | ||
1487 | dev_set_drvdata(dev, mmc); | ||
1488 | |||
1489 | /* | ||
1490 | * Add host to MMC layer. | ||
1491 | */ | ||
1492 | mmc_add_host(mmc); | 1781 | mmc_add_host(mmc); |
1493 | 1782 | ||
1494 | printk(KERN_INFO "%s: W83L51xD id %x at 0x%x irq %d dma %d\n", | 1783 | printk(KERN_INFO "%s: W83L51xD", mmc->host_name); |
1495 | mmc->host_name, (int)host->chip_id, (int)host->base, | 1784 | if (host->chip_id != 0) |
1496 | (int)host->irq, (int)host->dma); | 1785 | printk(" id %x", (int)host->chip_id); |
1786 | printk(" at 0x%x irq %d", (int)host->base, (int)host->irq); | ||
1787 | if (host->dma >= 0) | ||
1788 | printk(" dma %d", (int)host->dma); | ||
1789 | else | ||
1790 | printk(" FIFO"); | ||
1791 | if (pnp) | ||
1792 | printk(" PnP"); | ||
1793 | printk("\n"); | ||
1497 | 1794 | ||
1498 | return 0; | 1795 | return 0; |
1499 | |||
1500 | release: | ||
1501 | wbsd_release_regions(host); | ||
1502 | |||
1503 | freemmc: | ||
1504 | mmc_free_host(mmc); | ||
1505 | |||
1506 | return ret; | ||
1507 | } | 1796 | } |
1508 | 1797 | ||
1509 | /* | 1798 | static void __devexit wbsd_shutdown(struct device* dev, int pnp) |
1510 | * Device remove | ||
1511 | */ | ||
1512 | |||
1513 | static int wbsd_remove(struct device* dev) | ||
1514 | { | 1799 | { |
1515 | struct mmc_host* mmc = dev_get_drvdata(dev); | 1800 | struct mmc_host* mmc = dev_get_drvdata(dev); |
1516 | struct wbsd_host* host; | 1801 | struct wbsd_host* host; |
1517 | 1802 | ||
1518 | if (!mmc) | 1803 | if (!mmc) |
1519 | return 0; | 1804 | return; |
1520 | 1805 | ||
1521 | host = mmc_priv(mmc); | 1806 | host = mmc_priv(mmc); |
1522 | 1807 | ||
1523 | /* | ||
1524 | * Unregister host with MMC layer. | ||
1525 | */ | ||
1526 | mmc_remove_host(mmc); | 1808 | mmc_remove_host(mmc); |
1527 | 1809 | ||
1528 | /* | 1810 | if (!pnp) |
1529 | * Power down the SD/MMC function. | 1811 | { |
1530 | */ | 1812 | /* |
1531 | wbsd_unlock_config(host); | 1813 | * Power down the SD/MMC function. |
1532 | wbsd_write_config(host, WBSD_CONF_DEVICE, DEVICE_SD); | 1814 | */ |
1533 | wbsd_write_config(host, WBSD_CONF_ENABLE, 0); | 1815 | wbsd_unlock_config(host); |
1534 | wbsd_lock_config(host); | 1816 | wbsd_write_config(host, WBSD_CONF_DEVICE, DEVICE_SD); |
1817 | wbsd_write_config(host, WBSD_CONF_ENABLE, 0); | ||
1818 | wbsd_lock_config(host); | ||
1819 | } | ||
1535 | 1820 | ||
1536 | /* | 1821 | wbsd_release_resources(host); |
1537 | * Free resources. | ||
1538 | */ | ||
1539 | if (host->dma_buffer) | ||
1540 | kfree(host->dma_buffer); | ||
1541 | 1822 | ||
1542 | if (host->dma >= 0) | 1823 | wbsd_free_mmc(dev); |
1543 | free_dma(host->dma); | 1824 | } |
1544 | 1825 | ||
1545 | free_irq(host->irq, host); | 1826 | /* |
1827 | * Non-PnP | ||
1828 | */ | ||
1829 | |||
1830 | static int __devinit wbsd_probe(struct device* dev) | ||
1831 | { | ||
1832 | return wbsd_init(dev, io, irq, dma, 0); | ||
1833 | } | ||
1834 | |||
1835 | static int __devexit wbsd_remove(struct device* dev) | ||
1836 | { | ||
1837 | wbsd_shutdown(dev, 0); | ||
1838 | |||
1839 | return 0; | ||
1840 | } | ||
1841 | |||
1842 | /* | ||
1843 | * PnP | ||
1844 | */ | ||
1845 | |||
1846 | #ifdef CONFIG_PNP | ||
1847 | |||
1848 | static int __devinit | ||
1849 | wbsd_pnp_probe(struct pnp_dev * pnpdev, const struct pnp_device_id *dev_id) | ||
1850 | { | ||
1851 | int io, irq, dma; | ||
1546 | 1852 | ||
1547 | tasklet_kill(&host->card_tasklet); | 1853 | /* |
1548 | tasklet_kill(&host->fifo_tasklet); | 1854 | * Get resources from PnP layer. |
1549 | tasklet_kill(&host->crc_tasklet); | 1855 | */ |
1550 | tasklet_kill(&host->timeout_tasklet); | 1856 | io = pnp_port_start(pnpdev, 0); |
1551 | tasklet_kill(&host->finish_tasklet); | 1857 | irq = pnp_irq(pnpdev, 0); |
1552 | tasklet_kill(&host->block_tasklet); | 1858 | if (pnp_dma_valid(pnpdev, 0)) |
1859 | dma = pnp_dma(pnpdev, 0); | ||
1860 | else | ||
1861 | dma = -1; | ||
1553 | 1862 | ||
1554 | wbsd_release_regions(host); | 1863 | DBGF("PnP resources: port %3x irq %d dma %d\n", io, irq, dma); |
1555 | 1864 | ||
1556 | mmc_free_host(mmc); | 1865 | return wbsd_init(&pnpdev->dev, io, irq, dma, 1); |
1866 | } | ||
1557 | 1867 | ||
1558 | return 0; | 1868 | static void __devexit wbsd_pnp_remove(struct pnp_dev * dev) |
1869 | { | ||
1870 | wbsd_shutdown(&dev->dev, 1); | ||
1559 | } | 1871 | } |
1560 | 1872 | ||
1873 | #endif /* CONFIG_PNP */ | ||
1874 | |||
1561 | /* | 1875 | /* |
1562 | * Power management | 1876 | * Power management |
1563 | */ | 1877 | */ |
@@ -1581,17 +1895,7 @@ static int wbsd_resume(struct device *dev, u32 level) | |||
1581 | #define wbsd_resume NULL | 1895 | #define wbsd_resume NULL |
1582 | #endif | 1896 | #endif |
1583 | 1897 | ||
1584 | static void wbsd_release(struct device *dev) | 1898 | static struct platform_device *wbsd_device; |
1585 | { | ||
1586 | } | ||
1587 | |||
1588 | static struct platform_device wbsd_device = { | ||
1589 | .name = DRIVER_NAME, | ||
1590 | .id = -1, | ||
1591 | .dev = { | ||
1592 | .release = wbsd_release, | ||
1593 | }, | ||
1594 | }; | ||
1595 | 1899 | ||
1596 | static struct device_driver wbsd_driver = { | 1900 | static struct device_driver wbsd_driver = { |
1597 | .name = DRIVER_NAME, | 1901 | .name = DRIVER_NAME, |
@@ -1603,6 +1907,17 @@ static struct device_driver wbsd_driver = { | |||
1603 | .resume = wbsd_resume, | 1907 | .resume = wbsd_resume, |
1604 | }; | 1908 | }; |
1605 | 1909 | ||
1910 | #ifdef CONFIG_PNP | ||
1911 | |||
1912 | static struct pnp_driver wbsd_pnp_driver = { | ||
1913 | .name = DRIVER_NAME, | ||
1914 | .id_table = pnp_dev_table, | ||
1915 | .probe = wbsd_pnp_probe, | ||
1916 | .remove = wbsd_pnp_remove, | ||
1917 | }; | ||
1918 | |||
1919 | #endif /* CONFIG_PNP */ | ||
1920 | |||
1606 | /* | 1921 | /* |
1607 | * Module loading/unloading | 1922 | * Module loading/unloading |
1608 | */ | 1923 | */ |
@@ -1615,29 +1930,57 @@ static int __init wbsd_drv_init(void) | |||
1615 | ": Winbond W83L51xD SD/MMC card interface driver, " | 1930 | ": Winbond W83L51xD SD/MMC card interface driver, " |
1616 | DRIVER_VERSION "\n"); | 1931 | DRIVER_VERSION "\n"); |
1617 | printk(KERN_INFO DRIVER_NAME ": Copyright(c) Pierre Ossman\n"); | 1932 | printk(KERN_INFO DRIVER_NAME ": Copyright(c) Pierre Ossman\n"); |
1618 | |||
1619 | result = driver_register(&wbsd_driver); | ||
1620 | if (result < 0) | ||
1621 | return result; | ||
1622 | 1933 | ||
1623 | result = platform_device_register(&wbsd_device); | 1934 | #ifdef CONFIG_PNP |
1624 | if (result < 0) | 1935 | |
1625 | return result; | 1936 | if (!nopnp) |
1937 | { | ||
1938 | result = pnp_register_driver(&wbsd_pnp_driver); | ||
1939 | if (result < 0) | ||
1940 | return result; | ||
1941 | } | ||
1942 | |||
1943 | #endif /* CONFIG_PNP */ | ||
1944 | |||
1945 | if (nopnp) | ||
1946 | { | ||
1947 | result = driver_register(&wbsd_driver); | ||
1948 | if (result < 0) | ||
1949 | return result; | ||
1950 | |||
1951 | wbsd_device = platform_device_register_simple(DRIVER_NAME, -1, | ||
1952 | NULL, 0); | ||
1953 | if (IS_ERR(wbsd_device)) | ||
1954 | return PTR_ERR(wbsd_device); | ||
1955 | } | ||
1626 | 1956 | ||
1627 | return 0; | 1957 | return 0; |
1628 | } | 1958 | } |
1629 | 1959 | ||
1630 | static void __exit wbsd_drv_exit(void) | 1960 | static void __exit wbsd_drv_exit(void) |
1631 | { | 1961 | { |
1632 | platform_device_unregister(&wbsd_device); | 1962 | #ifdef CONFIG_PNP |
1963 | |||
1964 | if (!nopnp) | ||
1965 | pnp_unregister_driver(&wbsd_pnp_driver); | ||
1633 | 1966 | ||
1634 | driver_unregister(&wbsd_driver); | 1967 | #endif /* CONFIG_PNP */ |
1968 | |||
1969 | if (nopnp) | ||
1970 | { | ||
1971 | platform_device_unregister(wbsd_device); | ||
1972 | |||
1973 | driver_unregister(&wbsd_driver); | ||
1974 | } | ||
1635 | 1975 | ||
1636 | DBG("unloaded\n"); | 1976 | DBG("unloaded\n"); |
1637 | } | 1977 | } |
1638 | 1978 | ||
1639 | module_init(wbsd_drv_init); | 1979 | module_init(wbsd_drv_init); |
1640 | module_exit(wbsd_drv_exit); | 1980 | module_exit(wbsd_drv_exit); |
1981 | #ifdef CONFIG_PNP | ||
1982 | module_param(nopnp, uint, 0444); | ||
1983 | #endif | ||
1641 | module_param(io, uint, 0444); | 1984 | module_param(io, uint, 0444); |
1642 | module_param(irq, uint, 0444); | 1985 | module_param(irq, uint, 0444); |
1643 | module_param(dma, int, 0444); | 1986 | module_param(dma, int, 0444); |
@@ -1646,6 +1989,9 @@ MODULE_LICENSE("GPL"); | |||
1646 | MODULE_DESCRIPTION("Winbond W83L51xD SD/MMC card interface driver"); | 1989 | MODULE_DESCRIPTION("Winbond W83L51xD SD/MMC card interface driver"); |
1647 | MODULE_VERSION(DRIVER_VERSION); | 1990 | MODULE_VERSION(DRIVER_VERSION); |
1648 | 1991 | ||
1992 | #ifdef CONFIG_PNP | ||
1993 | MODULE_PARM_DESC(nopnp, "Scan for device instead of relying on PNP. (default 0)"); | ||
1994 | #endif | ||
1649 | MODULE_PARM_DESC(io, "I/O base to allocate. Must be 8 byte aligned. (default 0x248)"); | 1995 | MODULE_PARM_DESC(io, "I/O base to allocate. Must be 8 byte aligned. (default 0x248)"); |
1650 | MODULE_PARM_DESC(irq, "IRQ to allocate. (default 6)"); | 1996 | MODULE_PARM_DESC(irq, "IRQ to allocate. (default 6)"); |
1651 | MODULE_PARM_DESC(dma, "DMA channel to allocate. -1 for no DMA. (default 2)"); | 1997 | MODULE_PARM_DESC(dma, "DMA channel to allocate. -1 for no DMA. (default 2)"); |