11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 270f10482c668301c483acded13bf68780ad352b9Pierre Ossman * linux/drivers/mmc/host/wbsd.c - Winbond W83L51xD SD/MMC driver 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 414d836e7499c53a1f6a65086c3d11600e871a971Alex Dubov * Copyright (C) 2004-2007 Pierre Ossman, All Rights Reserved. 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is free software; you can redistribute it and/or modify 7643f720cea989d2913fc0120a2384fecc1be1f9aPierre Ossman * it under the terms of the GNU General Public License as published by 8643f720cea989d2913fc0120a2384fecc1be1f9aPierre Ossman * the Free Software Foundation; either version 2 of the License, or (at 9643f720cea989d2913fc0120a2384fecc1be1f9aPierre Ossman * your option) any later version. 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Warning! 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Changes to the FIFO system should be done with extreme care since 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the hardware is full of bugs related to the FIFO. Known issues are: 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - FIFO size field in FSR is always zero. 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - FIFO interrupts tend not to work as they should. Interrupts are 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * triggered only for full/empty events, not for threshold values. 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - On APIC systems the FIFO empty interrupt is sometimes lost. 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/moduleparam.h> 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ioport.h> 29d052d1beff706920e82c5d55006b08e256b5df09Russell King#include <linux/platform_device.h> 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/interrupt.h> 3185bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman#include <linux/dma-mapping.h> 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h> 3385bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman#include <linux/pnp.h> 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/highmem.h> 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/mmc/host.h> 36bd6dee6f30a0f6943df190b387b5f8fe98a848f3Jens Axboe#include <linux/scatterlist.h> 375a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/io.h> 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/dma.h> 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "wbsd.h" 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DRIVER_NAME "wbsd" 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DBG(x...) \ 47c65631781eb0f2e81865017c1484e9aef76e1b61Russell King pr_debug(DRIVER_NAME ": " x) 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DBGF(f, x...) \ 49c65631781eb0f2e81865017c1484e9aef76e1b61Russell King pr_debug(DRIVER_NAME " [%s()]: " f, __func__ , ##x) 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 5285bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman * Device resources 5385bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman */ 5485bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman 5585bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman#ifdef CONFIG_PNP 5685bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman 5785bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossmanstatic const struct pnp_device_id pnp_dev_table[] = { 5885bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman { "WEC0517", 0 }, 5985bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman { "WEC0518", 0 }, 6085bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman { "", 0 }, 6185bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman}; 6285bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman 6385bcc13072c54592596c5b41d40d1c6a18b04e19Pierre OssmanMODULE_DEVICE_TABLE(pnp, pnp_dev_table); 6485bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman 6585bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman#endif /* CONFIG_PNP */ 6685bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman 673eee0d03e33b0294eb3165c96f213a8c8ee461a8Adrian Bunkstatic const int config_ports[] = { 0x2E, 0x4E }; 683eee0d03e33b0294eb3165c96f213a8c8ee461a8Adrian Bunkstatic const int unlock_codes[] = { 0x83, 0x87 }; 693eee0d03e33b0294eb3165c96f213a8c8ee461a8Adrian Bunk 703eee0d03e33b0294eb3165c96f213a8c8ee461a8Adrian Bunkstatic const int valid_ids[] = { 713eee0d03e33b0294eb3165c96f213a8c8ee461a8Adrian Bunk 0x7112, 729eeebd22ca757fee8dc10ffe6fa6992f33a3c5ecTomas Winkler}; 733eee0d03e33b0294eb3165c96f213a8c8ee461a8Adrian Bunk 7485bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman#ifdef CONFIG_PNP 759eeebd22ca757fee8dc10ffe6fa6992f33a3c5ecTomas Winklerstatic unsigned int param_nopnp = 0; 7685bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman#else 779eeebd22ca757fee8dc10ffe6fa6992f33a3c5ecTomas Winklerstatic const unsigned int param_nopnp = 1; 7885bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman#endif 799eeebd22ca757fee8dc10ffe6fa6992f33a3c5ecTomas Winklerstatic unsigned int param_io = 0x248; 809eeebd22ca757fee8dc10ffe6fa6992f33a3c5ecTomas Winklerstatic unsigned int param_irq = 6; 819eeebd22ca757fee8dc10ffe6fa6992f33a3c5ecTomas Winklerstatic int param_dma = 2; 8285bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman 8385bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman/* 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Basic functions 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 87cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossmanstatic inline void wbsd_unlock_config(struct wbsd_host *host) 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8985bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman BUG_ON(host->config == 0); 90fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(host->unlock_code, host->config); 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(host->unlock_code, host->config); 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 95cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossmanstatic inline void wbsd_lock_config(struct wbsd_host *host) 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 9785bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman BUG_ON(host->config == 0); 98fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(LOCK_CODE, host->config); 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 102cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossmanstatic inline void wbsd_write_config(struct wbsd_host *host, u8 reg, u8 value) 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 10485bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman BUG_ON(host->config == 0); 105fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(reg, host->config); 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(value, host->config + 1); 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 110cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossmanstatic inline u8 wbsd_read_config(struct wbsd_host *host, u8 reg) 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 11285bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman BUG_ON(host->config == 0); 113fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(reg, host->config); 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return inb(host->config + 1); 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 118cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossmanstatic inline void wbsd_write_index(struct wbsd_host *host, u8 index, u8 value) 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(index, host->base + WBSD_IDXR); 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(value, host->base + WBSD_DATAR); 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 124cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossmanstatic inline u8 wbsd_read_index(struct wbsd_host *host, u8 index) 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(index, host->base + WBSD_IDXR); 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return inb(host->base + WBSD_DATAR); 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Common routines 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 134cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossmanstatic void wbsd_init_device(struct wbsd_host *host) 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 setup, ier; 137fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Reset chip (SD/MMC part) and fifo. 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds setup = wbsd_read_index(host, WBSD_IDX_SETUP); 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds setup |= WBSD_FIFO_RESET | WBSD_SOFT_RESET; 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wbsd_write_index(host, WBSD_IDX_SETUP, setup); 144fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 14685bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman * Set DAT3 to input 14785bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman */ 14885bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman setup &= ~WBSD_DAT3_H; 14985bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman wbsd_write_index(host, WBSD_IDX_SETUP, setup); 15085bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman host->flags &= ~WBSD_FIGNORE_DETECT; 151fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 15285bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman /* 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Read back default clock. 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->clk = wbsd_read_index(host, WBSD_IDX_CLK); 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Power down port. 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(WBSD_POWER_N, host->base + WBSD_CSR); 161fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Set maximum timeout. 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wbsd_write_index(host, WBSD_IDX_TAAC, 0x7F); 166fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 16885bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman * Test for card presence 16985bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman */ 17085bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman if (inb(host->base + WBSD_CSR) & WBSD_CARDPRESENT) 17185bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman host->flags |= WBSD_FCARD_PRESENT; 17285bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman else 17385bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman host->flags &= ~WBSD_FCARD_PRESENT; 174fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 17585bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman /* 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Enable interesting interrupts. 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ier = 0; 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ier |= WBSD_EINT_CARD; 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ier |= WBSD_EINT_FIFO_THRE; 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ier |= WBSD_EINT_CRC; 1825721dbf217b073b40e31936781379ab2d17ea2aePierre Ossman ier |= WBSD_EINT_TIMEOUT; 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ier |= WBSD_EINT_TC; 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(ier, host->base + WBSD_EIR); 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Clear interrupts. 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds inb(host->base + WBSD_ISR); 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 193cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossmanstatic void wbsd_reset(struct wbsd_host *host) 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 setup; 196fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 197a3c76eb9d4a1e68a69dd880cf0bcb8a52418b993Girish K S pr_err("%s: Resetting chip\n", mmc_hostname(host->mmc)); 198fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Soft reset of chip (SD/MMC part). 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds setup = wbsd_read_index(host, WBSD_IDX_SETUP); 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds setup |= WBSD_SOFT_RESET; 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wbsd_write_index(host, WBSD_IDX_SETUP, setup); 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 207cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossmanstatic void wbsd_request_end(struct wbsd_host *host, struct mmc_request *mrq) 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long dmaflags; 210fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 211cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman if (host->dma >= 0) { 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Release ISA DMA controller. 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dmaflags = claim_dma_lock(); 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds disable_dma(host->dma); 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clear_dma_ff(host->dma); 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds release_dma_lock(dmaflags); 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Disable DMA on host. 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wbsd_write_index(host, WBSD_IDX_DMA, 0); 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 225fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->mrq = NULL; 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * MMC layer might call back into the driver so first unlock. 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock(&host->lock); 2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mmc_request_done(host->mmc, mrq); 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock(&host->lock); 2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Scatter/gather functions 2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 240cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossmanstatic inline void wbsd_init_sg(struct wbsd_host *host, struct mmc_data *data) 2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Get info. about SG list from data structure. 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->cur_sg = data->sg; 2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->num_sg = data->sg_len; 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->offset = 0; 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->remain = host->cur_sg->length; 2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 252cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossmanstatic inline int wbsd_next_sg(struct wbsd_host *host) 2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Skip to next SG entry. 2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->cur_sg++; 2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->num_sg--; 2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Any entries left? 2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 263cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman if (host->num_sg > 0) { 264cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman host->offset = 0; 265cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman host->remain = host->cur_sg->length; 266cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman } 267fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return host->num_sg; 2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2714a0ddbd25ad4e03a0a1657f5cb2259c9a35fe9e6Pierre Ossmanstatic inline char *wbsd_sg_to_buffer(struct wbsd_host *host) 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 27345711f1af6eff1a6d010703b4862e0d2b9afd056Jens Axboe return sg_virt(host->cur_sg); 2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 276cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossmanstatic inline void wbsd_sg_to_dma(struct wbsd_host *host, struct mmc_data *data) 2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 27814d836e7499c53a1f6a65086c3d11600e871a971Alex Dubov unsigned int len, i; 279cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman struct scatterlist *sg; 280cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman char *dmabuf = host->dma_buffer; 281cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman char *sgbuf; 282fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sg = data->sg; 2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds len = data->sg_len; 285fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 286cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman for (i = 0; i < len; i++) { 28745711f1af6eff1a6d010703b4862e0d2b9afd056Jens Axboe sgbuf = sg_virt(&sg[i]); 28814d836e7499c53a1f6a65086c3d11600e871a971Alex Dubov memcpy(dmabuf, sgbuf, sg[i].length); 2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dmabuf += sg[i].length; 2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 293cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossmanstatic inline void wbsd_dma_to_sg(struct wbsd_host *host, struct mmc_data *data) 2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 29514d836e7499c53a1f6a65086c3d11600e871a971Alex Dubov unsigned int len, i; 296cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman struct scatterlist *sg; 297cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman char *dmabuf = host->dma_buffer; 298cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman char *sgbuf; 299fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sg = data->sg; 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds len = data->sg_len; 302fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 303cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman for (i = 0; i < len; i++) { 30445711f1af6eff1a6d010703b4862e0d2b9afd056Jens Axboe sgbuf = sg_virt(&sg[i]); 30514d836e7499c53a1f6a65086c3d11600e871a971Alex Dubov memcpy(sgbuf, dmabuf, sg[i].length); 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dmabuf += sg[i].length; 3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Command handling 3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 313fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 314cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossmanstatic inline void wbsd_get_short_reply(struct wbsd_host *host, 315cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman struct mmc_command *cmd) 3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Correct response type? 3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 320cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman if (wbsd_read_index(host, WBSD_IDX_RSPLEN) != WBSD_RSP_SHORT) { 32117b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman cmd->error = -EILSEQ; 3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 324fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 325cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman cmd->resp[0] = wbsd_read_index(host, WBSD_IDX_RESP12) << 24; 326cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman cmd->resp[0] |= wbsd_read_index(host, WBSD_IDX_RESP13) << 16; 327cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman cmd->resp[0] |= wbsd_read_index(host, WBSD_IDX_RESP14) << 8; 328cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman cmd->resp[0] |= wbsd_read_index(host, WBSD_IDX_RESP15) << 0; 329cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman cmd->resp[1] = wbsd_read_index(host, WBSD_IDX_RESP16) << 24; 3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 332cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossmanstatic inline void wbsd_get_long_reply(struct wbsd_host *host, 333cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman struct mmc_command *cmd) 3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 336fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Correct response type? 3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 340cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman if (wbsd_read_index(host, WBSD_IDX_RSPLEN) != WBSD_RSP_LONG) { 34117b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman cmd->error = -EILSEQ; 3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 344fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 345cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman for (i = 0; i < 4; i++) { 3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmd->resp[i] = 3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wbsd_read_index(host, WBSD_IDX_RESP1 + i * 4) << 24; 3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmd->resp[i] |= 3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wbsd_read_index(host, WBSD_IDX_RESP2 + i * 4) << 16; 3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmd->resp[i] |= 3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wbsd_read_index(host, WBSD_IDX_RESP3 + i * 4) << 8; 3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmd->resp[i] |= 3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wbsd_read_index(host, WBSD_IDX_RESP4 + i * 4) << 0; 3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 357cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossmanstatic void wbsd_send_command(struct wbsd_host *host, struct mmc_command *cmd) 3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 status, isr; 361fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Clear accumulated ISR. The interrupt routine 3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * will fill this one with events that occur during 3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * transfer. 3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->isr = 0; 368fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Send the command (CRC calculated by host). 3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(cmd->opcode, host->base + WBSD_CMDR); 373cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman for (i = 3; i >= 0; i--) 3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb((cmd->arg >> (i * 8)) & 0xff, host->base + WBSD_CMDR); 375fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 37617b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman cmd->error = 0; 377fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Wait for the request to complete. 3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds do { 3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = wbsd_read_index(host, WBSD_IDX_STATUS); 3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } while (status & WBSD_CARDTRAFFIC); 3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Do we expect a reply? 3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 388e92251762d02a46177d4105d1744041e3f8bc465Russell King if (cmd->flags & MMC_RSP_PRESENT) { 3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Read back status. 3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds isr = host->isr; 393fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Card removed? */ 3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (isr & WBSD_INT_CARD) 39617b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman cmd->error = -ENOMEDIUM; 3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Timeout? */ 3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (isr & WBSD_INT_TIMEOUT) 39917b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman cmd->error = -ETIMEDOUT; 4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* CRC? */ 4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if ((cmd->flags & MMC_RSP_CRC) && (isr & WBSD_INT_CRC)) 40217b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman cmd->error = -EILSEQ; 4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* All ok */ 404cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman else { 405e92251762d02a46177d4105d1744041e3f8bc465Russell King if (cmd->flags & MMC_RSP_136) 4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wbsd_get_long_reply(host, cmd); 407e92251762d02a46177d4105d1744041e3f8bc465Russell King else 408e92251762d02a46177d4105d1744041e3f8bc465Russell King wbsd_get_short_reply(host, cmd); 4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Data functions 4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 417cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossmanstatic void wbsd_empty_fifo(struct wbsd_host *host) 4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 419cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman struct mmc_data *data = host->mrq->cmd->data; 420cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman char *buffer; 4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i, fsr, fifo; 422fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Handle excessive data. 4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 42614d836e7499c53a1f6a65086c3d11600e871a971Alex Dubov if (host->num_sg == 0) 4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 428fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 4294a0ddbd25ad4e03a0a1657f5cb2259c9a35fe9e6Pierre Ossman buffer = wbsd_sg_to_buffer(host) + host->offset; 4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Drain the fifo. This has a tendency to loop longer 4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * than the FIFO length (usually one block). 4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 435cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman while (!((fsr = inb(host->base + WBSD_FSR)) & WBSD_FIFO_EMPTY)) { 4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The size field in the FSR is broken so we have to 4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * do some guessing. 439fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman */ 4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (fsr & WBSD_FIFO_FULL) 4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fifo = 16; 4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (fsr & WBSD_FIFO_FUTHRE) 4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fifo = 8; 4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fifo = 1; 446fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 447cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman for (i = 0; i < fifo; i++) { 4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *buffer = inb(host->base + WBSD_DFR); 4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buffer++; 4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->offset++; 4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->remain--; 4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->bytes_xfered++; 454fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * End of scatter list entry? 4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 458cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman if (host->remain == 0) { 4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Get next entry. Check if last. 4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 46214d836e7499c53a1f6a65086c3d11600e871a971Alex Dubov if (!wbsd_next_sg(host)) 4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 464fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 4654a0ddbd25ad4e03a0a1657f5cb2259c9a35fe9e6Pierre Ossman buffer = wbsd_sg_to_buffer(host); 4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 469fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This is a very dirty hack to solve a 4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * hardware problem. The chip doesn't trigger 4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * FIFO threshold interrupts properly. 4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 47514d836e7499c53a1f6a65086c3d11600e871a971Alex Dubov if ((data->blocks * data->blksz - data->bytes_xfered) < 16) 4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tasklet_schedule(&host->fifo_tasklet); 4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 479cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossmanstatic void wbsd_fill_fifo(struct wbsd_host *host) 4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 481cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman struct mmc_data *data = host->mrq->cmd->data; 482cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman char *buffer; 4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i, fsr, fifo; 484fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Check that we aren't being called after the 48725985edcedea6396277003854657b5f3cb31a628Lucas De Marchi * entire buffer has been transferred. 4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 48914d836e7499c53a1f6a65086c3d11600e871a971Alex Dubov if (host->num_sg == 0) 4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4924a0ddbd25ad4e03a0a1657f5cb2259c9a35fe9e6Pierre Ossman buffer = wbsd_sg_to_buffer(host) + host->offset; 4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Fill the fifo. This has a tendency to loop longer 4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * than the FIFO length (usually one block). 4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 498cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman while (!((fsr = inb(host->base + WBSD_FSR)) & WBSD_FIFO_FULL)) { 4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The size field in the FSR is broken so we have to 5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * do some guessing. 502fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman */ 5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (fsr & WBSD_FIFO_EMPTY) 5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fifo = 0; 5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (fsr & WBSD_FIFO_EMTHRE) 5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fifo = 8; 5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fifo = 15; 5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 510cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman for (i = 16; i > fifo; i--) { 5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(*buffer, host->base + WBSD_DFR); 5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buffer++; 5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->offset++; 5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->remain--; 515fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->bytes_xfered++; 517fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * End of scatter list entry? 5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 521cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman if (host->remain == 0) { 5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Get next entry. Check if last. 5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 52514d836e7499c53a1f6a65086c3d11600e871a971Alex Dubov if (!wbsd_next_sg(host)) 5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 527fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 5284a0ddbd25ad4e03a0a1657f5cb2259c9a35fe9e6Pierre Ossman buffer = wbsd_sg_to_buffer(host); 5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 532fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 53385bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman /* 53485bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman * The controller stops sending interrupts for 53585bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman * 'FIFO empty' under certain conditions. So we 53685bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman * need to be a bit more pro-active. 53785bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman */ 53885bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman tasklet_schedule(&host->fifo_tasklet); 5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 541cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossmanstatic void wbsd_prepare_data(struct wbsd_host *host, struct mmc_data *data) 5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u16 blksize; 5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 setup; 5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long dmaflags; 54614d836e7499c53a1f6a65086c3d11600e871a971Alex Dubov unsigned int size; 5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Calculate size. 5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 55114d836e7499c53a1f6a65086c3d11600e871a971Alex Dubov size = data->blocks * data->blksz; 5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Check timeout values for overflow. 5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (Yes, some cards cause this value to overflow). 5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (data->timeout_ns > 127000000) 5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wbsd_write_index(host, WBSD_IDX_TAAC, 127); 559cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman else { 560cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman wbsd_write_index(host, WBSD_IDX_TAAC, 561cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman data->timeout_ns / 1000000); 562cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman } 563fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (data->timeout_clks > 255) 5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wbsd_write_index(host, WBSD_IDX_NSAC, 255); 5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wbsd_write_index(host, WBSD_IDX_NSAC, data->timeout_clks); 568fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Inform the chip of how large blocks will be 5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * sent. It needs this to determine when to 5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * calculate CRC. 5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Space for CRC must be included in the size. 57565ae2118e84616680dce37b951ffc366dcce7cf0Pierre Ossman * Two bytes are needed for each data line. 5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 577cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman if (host->bus_width == MMC_BUS_WIDTH_1) { 5782c171bf13423dc5293188cea7f6c2da1720926e2Pavel Pisa blksize = data->blksz + 2; 57965ae2118e84616680dce37b951ffc366dcce7cf0Pierre Ossman 58065ae2118e84616680dce37b951ffc366dcce7cf0Pierre Ossman wbsd_write_index(host, WBSD_IDX_PBSMSB, (blksize >> 4) & 0xF0); 58165ae2118e84616680dce37b951ffc366dcce7cf0Pierre Ossman wbsd_write_index(host, WBSD_IDX_PBSLSB, blksize & 0xFF); 582cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman } else if (host->bus_width == MMC_BUS_WIDTH_4) { 5832c171bf13423dc5293188cea7f6c2da1720926e2Pavel Pisa blksize = data->blksz + 2 * 4; 584fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 585cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman wbsd_write_index(host, WBSD_IDX_PBSMSB, 586cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman ((blksize >> 4) & 0xF0) | WBSD_DATA_WIDTH); 58765ae2118e84616680dce37b951ffc366dcce7cf0Pierre Ossman wbsd_write_index(host, WBSD_IDX_PBSLSB, blksize & 0xFF); 588cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman } else { 58917b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman data->error = -EINVAL; 59065ae2118e84616680dce37b951ffc366dcce7cf0Pierre Ossman return; 59165ae2118e84616680dce37b951ffc366dcce7cf0Pierre Ossman } 5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Clear the FIFO. This is needed even for DMA 5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * transfers since the chip still uses the FIFO 5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * internally. 5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds setup = wbsd_read_index(host, WBSD_IDX_SETUP); 5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds setup |= WBSD_FIFO_RESET; 6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wbsd_write_index(host, WBSD_IDX_SETUP, setup); 601fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * DMA transfer? 6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 605cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman if (host->dma >= 0) { 6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The buffer for DMA is only 64 kB. 6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 60914d836e7499c53a1f6a65086c3d11600e871a971Alex Dubov BUG_ON(size > 0x10000); 61014d836e7499c53a1f6a65086c3d11600e871a971Alex Dubov if (size > 0x10000) { 61117b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman data->error = -EINVAL; 6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 614fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Transfer data from the SG list to 6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the DMA buffer. 6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (data->flags & MMC_DATA_WRITE) 6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wbsd_sg_to_dma(host, data); 621fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Initialise the ISA DMA controller. 624fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman */ 6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dmaflags = claim_dma_lock(); 6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds disable_dma(host->dma); 6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clear_dma_ff(host->dma); 6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (data->flags & MMC_DATA_READ) 6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_dma_mode(host->dma, DMA_MODE_READ & ~0x40); 6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_dma_mode(host->dma, DMA_MODE_WRITE & ~0x40); 6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_dma_addr(host->dma, host->dma_addr); 63314d836e7499c53a1f6a65086c3d11600e871a971Alex Dubov set_dma_count(host->dma, size); 6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds enable_dma(host->dma); 6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds release_dma_lock(dmaflags); 6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Enable DMA on the host. 6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wbsd_write_index(host, WBSD_IDX_DMA, WBSD_DMA_ENABLE); 642cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman } else { 6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This flag is used to keep printk 6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * output to a minimum. 6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->firsterr = 1; 648fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Initialise the SG list. 6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wbsd_init_sg(host, data); 653fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Turn off DMA. 6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wbsd_write_index(host, WBSD_IDX_DMA, 0); 658fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Set up FIFO threshold levels (and fill 6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * buffer if doing a write). 6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 663cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman if (data->flags & MMC_DATA_READ) { 6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wbsd_write_index(host, WBSD_IDX_FIFOEN, 6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds WBSD_FIFOEN_FULL | 8); 666cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman } else { 6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wbsd_write_index(host, WBSD_IDX_FIFOEN, 6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds WBSD_FIFOEN_EMPTY | 8); 6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wbsd_fill_fifo(host); 6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 671fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman } 672fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 67317b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman data->error = 0; 6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 676cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossmanstatic void wbsd_finish_data(struct wbsd_host *host, struct mmc_data *data) 6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long dmaflags; 6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int count; 6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 status; 681fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds WARN_ON(host->mrq == NULL); 6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Send a stop command if needed. 6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (data->stop) 6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wbsd_send_command(host, data->stop); 6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Wait for the controller to leave data 6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * transfer state. 6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 694cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman do { 6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = wbsd_read_index(host, WBSD_IDX_STATUS); 6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } while (status & (WBSD_BLOCK_READ | WBSD_BLOCK_WRITE)); 697fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * DMA transfer? 7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 701cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman if (host->dma >= 0) { 7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Disable DMA on the host. 7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wbsd_write_index(host, WBSD_IDX_DMA, 0); 706fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Turn of ISA DMA controller. 7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dmaflags = claim_dma_lock(); 7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds disable_dma(host->dma); 7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clear_dma_ff(host->dma); 7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds count = get_dma_residue(host->dma); 7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds release_dma_lock(dmaflags); 715fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 71614d836e7499c53a1f6a65086c3d11600e871a971Alex Dubov data->bytes_xfered = host->mrq->data->blocks * 71714d836e7499c53a1f6a65086c3d11600e871a971Alex Dubov host->mrq->data->blksz - count; 71814d836e7499c53a1f6a65086c3d11600e871a971Alex Dubov data->bytes_xfered -= data->bytes_xfered % data->blksz; 71914d836e7499c53a1f6a65086c3d11600e871a971Alex Dubov 7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Any leftover data? 7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 723cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman if (count) { 724a3c76eb9d4a1e68a69dd880cf0bcb8a52418b993Girish K S pr_err("%s: Incomplete DMA transfer. " 725d191634f7ab3a1c8e9da0c5e986c30b2612f0eb0Pierre Ossman "%d bytes left.\n", 726d191634f7ab3a1c8e9da0c5e986c30b2612f0eb0Pierre Ossman mmc_hostname(host->mmc), count); 727fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 72817b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman if (!data->error) 72917b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman data->error = -EIO; 730cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman } else { 7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 7321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Transfer data from DMA buffer to 7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * SG list. 7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (data->flags & MMC_DATA_READ) 7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wbsd_dma_to_sg(host, data); 73714d836e7499c53a1f6a65086c3d11600e871a971Alex Dubov } 738fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 73917b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman if (data->error) { 74014d836e7499c53a1f6a65086c3d11600e871a971Alex Dubov if (data->bytes_xfered) 74114d836e7499c53a1f6a65086c3d11600e871a971Alex Dubov data->bytes_xfered -= data->blksz; 7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 744fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wbsd_request_end(host, host->mrq); 7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 74885bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman/*****************************************************************************\ 74985bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman * * 75085bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman * MMC layer callbacks * 75185bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman * * 75285bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman\*****************************************************************************/ 7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 754cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossmanstatic void wbsd_request(struct mmc_host *mmc, struct mmc_request *mrq) 7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 756cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman struct wbsd_host *host = mmc_priv(mmc); 757cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman struct mmc_command *cmd; 7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Disable tasklets to avoid a deadlock. 7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_bh(&host->lock); 7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BUG_ON(host->mrq != NULL); 7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmd = mrq->cmd; 7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->mrq = mrq; 769fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 77117b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman * Check that there is actually a card in the slot. 7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 773cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman if (!(host->flags & WBSD_FCARD_PRESENT)) { 77417b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman cmd->error = -ENOMEDIUM; 7751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto done; 7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 778cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman if (cmd->data) { 7791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 7805ba593a97206fb96dc0e63f209e6ade86452844fPierre Ossman * The hardware is so delightfully stupid that it has a list 7815ba593a97206fb96dc0e63f209e6ade86452844fPierre Ossman * of "data" commands. If a command isn't on this list, it'll 7825ba593a97206fb96dc0e63f209e6ade86452844fPierre Ossman * just go back to the idle state and won't send any data 7835ba593a97206fb96dc0e63f209e6ade86452844fPierre Ossman * interrupts. 7845ba593a97206fb96dc0e63f209e6ade86452844fPierre Ossman */ 7855ba593a97206fb96dc0e63f209e6ade86452844fPierre Ossman switch (cmd->opcode) { 7865ba593a97206fb96dc0e63f209e6ade86452844fPierre Ossman case 11: 7875ba593a97206fb96dc0e63f209e6ade86452844fPierre Ossman case 17: 7885ba593a97206fb96dc0e63f209e6ade86452844fPierre Ossman case 18: 7895ba593a97206fb96dc0e63f209e6ade86452844fPierre Ossman case 20: 7905ba593a97206fb96dc0e63f209e6ade86452844fPierre Ossman case 24: 7915ba593a97206fb96dc0e63f209e6ade86452844fPierre Ossman case 25: 7925ba593a97206fb96dc0e63f209e6ade86452844fPierre Ossman case 26: 7935ba593a97206fb96dc0e63f209e6ade86452844fPierre Ossman case 27: 7945ba593a97206fb96dc0e63f209e6ade86452844fPierre Ossman case 30: 7955ba593a97206fb96dc0e63f209e6ade86452844fPierre Ossman case 42: 7965ba593a97206fb96dc0e63f209e6ade86452844fPierre Ossman case 56: 7975ba593a97206fb96dc0e63f209e6ade86452844fPierre Ossman break; 7985ba593a97206fb96dc0e63f209e6ade86452844fPierre Ossman 7995ba593a97206fb96dc0e63f209e6ade86452844fPierre Ossman /* ACMDs. We don't keep track of state, so we just treat them 8005ba593a97206fb96dc0e63f209e6ade86452844fPierre Ossman * like any other command. */ 8015ba593a97206fb96dc0e63f209e6ade86452844fPierre Ossman case 51: 8025ba593a97206fb96dc0e63f209e6ade86452844fPierre Ossman break; 8035ba593a97206fb96dc0e63f209e6ade86452844fPierre Ossman 8045ba593a97206fb96dc0e63f209e6ade86452844fPierre Ossman default: 8055ba593a97206fb96dc0e63f209e6ade86452844fPierre Ossman#ifdef CONFIG_MMC_DEBUG 806a3c76eb9d4a1e68a69dd880cf0bcb8a52418b993Girish K S pr_warning("%s: Data command %d is not " 8075ba593a97206fb96dc0e63f209e6ade86452844fPierre Ossman "supported by this controller.\n", 8085ba593a97206fb96dc0e63f209e6ade86452844fPierre Ossman mmc_hostname(host->mmc), cmd->opcode); 8095ba593a97206fb96dc0e63f209e6ade86452844fPierre Ossman#endif 81017b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman cmd->error = -EINVAL; 8115ba593a97206fb96dc0e63f209e6ade86452844fPierre Ossman 8125ba593a97206fb96dc0e63f209e6ade86452844fPierre Ossman goto done; 8135ba593a97206fb96dc0e63f209e6ade86452844fPierre Ossman }; 814b2670b1c6ddd54be4a0f72f853122510ea5ef285Pierre Ossman } 8155ba593a97206fb96dc0e63f209e6ade86452844fPierre Ossman 816b2670b1c6ddd54be4a0f72f853122510ea5ef285Pierre Ossman /* 817b2670b1c6ddd54be4a0f72f853122510ea5ef285Pierre Ossman * Does the request include data? 818b2670b1c6ddd54be4a0f72f853122510ea5ef285Pierre Ossman */ 819b2670b1c6ddd54be4a0f72f853122510ea5ef285Pierre Ossman if (cmd->data) { 820b2670b1c6ddd54be4a0f72f853122510ea5ef285Pierre Ossman wbsd_prepare_data(host, cmd->data); 821b2670b1c6ddd54be4a0f72f853122510ea5ef285Pierre Ossman 82217b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman if (cmd->data->error) 823b2670b1c6ddd54be4a0f72f853122510ea5ef285Pierre Ossman goto done; 824b2670b1c6ddd54be4a0f72f853122510ea5ef285Pierre Ossman } 825b2670b1c6ddd54be4a0f72f853122510ea5ef285Pierre Ossman 826b2670b1c6ddd54be4a0f72f853122510ea5ef285Pierre Ossman wbsd_send_command(host, cmd); 827b2670b1c6ddd54be4a0f72f853122510ea5ef285Pierre Ossman 828b2670b1c6ddd54be4a0f72f853122510ea5ef285Pierre Ossman /* 829b2670b1c6ddd54be4a0f72f853122510ea5ef285Pierre Ossman * If this is a data transfer the request 830b2670b1c6ddd54be4a0f72f853122510ea5ef285Pierre Ossman * will be finished after the data has 83125985edcedea6396277003854657b5f3cb31a628Lucas De Marchi * transferred. 832b2670b1c6ddd54be4a0f72f853122510ea5ef285Pierre Ossman */ 83317b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman if (cmd->data && !cmd->error) { 8345ba593a97206fb96dc0e63f209e6ade86452844fPierre Ossman /* 8351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Dirty fix for hardware bug. 8361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 8371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (host->dma == -1) 8381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tasklet_schedule(&host->fifo_tasklet); 8391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_bh(&host->lock); 8411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 8431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 844fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 8451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdone: 8461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wbsd_request_end(host, mrq); 8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_bh(&host->lock); 8491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 851cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossmanstatic void wbsd_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) 8521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 853cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman struct wbsd_host *host = mmc_priv(mmc); 8541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 clk, setup, pwr; 855fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 8561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_bh(&host->lock); 8571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Reset the chip on each power off. 8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Should clear out any weird states. 8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 8621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ios->power_mode == MMC_POWER_OFF) 8631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wbsd_init_device(host); 864fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 8651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ios->clock >= 24000000) 8661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clk = WBSD_CLK_24M; 8671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (ios->clock >= 16000000) 8681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clk = WBSD_CLK_16M; 8691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (ios->clock >= 12000000) 8701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clk = WBSD_CLK_12M; 8711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 8721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clk = WBSD_CLK_375K; 8731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Only write to the clock register when 8761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * there is an actual change. 8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 878cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman if (clk != host->clk) { 8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wbsd_write_index(host, WBSD_IDX_CLK, clk); 8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->clk = clk; 8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 88385bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman /* 88485bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman * Power up card. 88585bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman */ 886cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman if (ios->power_mode != MMC_POWER_OFF) { 8871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pwr = inb(host->base + WBSD_CSR); 8881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pwr &= ~WBSD_POWER_N; 8891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(pwr, host->base + WBSD_CSR); 8901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 89285bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman /* 89385bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman * MMC cards need to have pin 1 high during init. 89485bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman * It wreaks havoc with the card detection though so 8951656fa579e44691a860b095016eee910bc0b2793Pierre Ossman * that needs to be disabled. 89685bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman */ 89785bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman setup = wbsd_read_index(host, WBSD_IDX_SETUP); 898cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman if (ios->chip_select == MMC_CS_HIGH) { 89965ae2118e84616680dce37b951ffc366dcce7cf0Pierre Ossman BUG_ON(ios->bus_width != MMC_BUS_WIDTH_1); 90085bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman setup |= WBSD_DAT3_H; 90185bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman host->flags |= WBSD_FIGNORE_DETECT; 902cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman } else { 903cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman if (setup & WBSD_DAT3_H) { 90419c1f3ca4272008a256cc153f3e3feb097799070Pierre Ossman setup &= ~WBSD_DAT3_H; 9051656fa579e44691a860b095016eee910bc0b2793Pierre Ossman 90619c1f3ca4272008a256cc153f3e3feb097799070Pierre Ossman /* 90725985edcedea6396277003854657b5f3cb31a628Lucas De Marchi * We cannot resume card detection immediately 90819c1f3ca4272008a256cc153f3e3feb097799070Pierre Ossman * because of capacitance and delays in the chip. 90919c1f3ca4272008a256cc153f3e3feb097799070Pierre Ossman */ 910cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman mod_timer(&host->ignore_timer, jiffies + HZ / 100); 91119c1f3ca4272008a256cc153f3e3feb097799070Pierre Ossman } 91285bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman } 91385bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman wbsd_write_index(host, WBSD_IDX_SETUP, setup); 914fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 91565ae2118e84616680dce37b951ffc366dcce7cf0Pierre Ossman /* 91665ae2118e84616680dce37b951ffc366dcce7cf0Pierre Ossman * Store bus width for later. Will be used when 91765ae2118e84616680dce37b951ffc366dcce7cf0Pierre Ossman * setting up the data transfer. 91865ae2118e84616680dce37b951ffc366dcce7cf0Pierre Ossman */ 91965ae2118e84616680dce37b951ffc366dcce7cf0Pierre Ossman host->bus_width = ios->bus_width; 92065ae2118e84616680dce37b951ffc366dcce7cf0Pierre Ossman 9211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_bh(&host->lock); 9221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 9231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 924cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossmanstatic int wbsd_get_ro(struct mmc_host *mmc) 92565ae2118e84616680dce37b951ffc366dcce7cf0Pierre Ossman{ 926cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman struct wbsd_host *host = mmc_priv(mmc); 92765ae2118e84616680dce37b951ffc366dcce7cf0Pierre Ossman u8 csr; 92865ae2118e84616680dce37b951ffc366dcce7cf0Pierre Ossman 92965ae2118e84616680dce37b951ffc366dcce7cf0Pierre Ossman spin_lock_bh(&host->lock); 93065ae2118e84616680dce37b951ffc366dcce7cf0Pierre Ossman 93165ae2118e84616680dce37b951ffc366dcce7cf0Pierre Ossman csr = inb(host->base + WBSD_CSR); 93265ae2118e84616680dce37b951ffc366dcce7cf0Pierre Ossman csr |= WBSD_MSLED; 93365ae2118e84616680dce37b951ffc366dcce7cf0Pierre Ossman outb(csr, host->base + WBSD_CSR); 93465ae2118e84616680dce37b951ffc366dcce7cf0Pierre Ossman 93565ae2118e84616680dce37b951ffc366dcce7cf0Pierre Ossman mdelay(1); 93665ae2118e84616680dce37b951ffc366dcce7cf0Pierre Ossman 93765ae2118e84616680dce37b951ffc366dcce7cf0Pierre Ossman csr = inb(host->base + WBSD_CSR); 93865ae2118e84616680dce37b951ffc366dcce7cf0Pierre Ossman csr &= ~WBSD_MSLED; 93965ae2118e84616680dce37b951ffc366dcce7cf0Pierre Ossman outb(csr, host->base + WBSD_CSR); 94065ae2118e84616680dce37b951ffc366dcce7cf0Pierre Ossman 94165ae2118e84616680dce37b951ffc366dcce7cf0Pierre Ossman spin_unlock_bh(&host->lock); 94265ae2118e84616680dce37b951ffc366dcce7cf0Pierre Ossman 94308f80bb5196517a0dfe50dc7c10f234c0ff2f0e8Anton Vorontsov return !!(csr & WBSD_WRPT); 94465ae2118e84616680dce37b951ffc366dcce7cf0Pierre Ossman} 94565ae2118e84616680dce37b951ffc366dcce7cf0Pierre Ossman 946ab7aefd0b38297e6d2d71f43e8f81f9f4a36cdaeDavid Brownellstatic const struct mmc_host_ops wbsd_ops = { 94785bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman .request = wbsd_request, 94885bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman .set_ios = wbsd_set_ios, 94965ae2118e84616680dce37b951ffc366dcce7cf0Pierre Ossman .get_ro = wbsd_get_ro, 95085bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman}; 95185bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman 95285bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman/*****************************************************************************\ 95385bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman * * 95485bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman * Interrupt handling * 95585bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman * * 95685bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman\*****************************************************************************/ 95785bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman 9581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 9591656fa579e44691a860b095016eee910bc0b2793Pierre Ossman * Helper function to reset detection ignore 9601656fa579e44691a860b095016eee910bc0b2793Pierre Ossman */ 9611656fa579e44691a860b095016eee910bc0b2793Pierre Ossman 9621656fa579e44691a860b095016eee910bc0b2793Pierre Ossmanstatic void wbsd_reset_ignore(unsigned long data) 9631656fa579e44691a860b095016eee910bc0b2793Pierre Ossman{ 964cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman struct wbsd_host *host = (struct wbsd_host *)data; 9651656fa579e44691a860b095016eee910bc0b2793Pierre Ossman 9661656fa579e44691a860b095016eee910bc0b2793Pierre Ossman BUG_ON(host == NULL); 9671656fa579e44691a860b095016eee910bc0b2793Pierre Ossman 9681656fa579e44691a860b095016eee910bc0b2793Pierre Ossman DBG("Resetting card detection ignore\n"); 9691656fa579e44691a860b095016eee910bc0b2793Pierre Ossman 9701656fa579e44691a860b095016eee910bc0b2793Pierre Ossman spin_lock_bh(&host->lock); 9711656fa579e44691a860b095016eee910bc0b2793Pierre Ossman 9721656fa579e44691a860b095016eee910bc0b2793Pierre Ossman host->flags &= ~WBSD_FIGNORE_DETECT; 9731656fa579e44691a860b095016eee910bc0b2793Pierre Ossman 9741656fa579e44691a860b095016eee910bc0b2793Pierre Ossman /* 9751656fa579e44691a860b095016eee910bc0b2793Pierre Ossman * Card status might have changed during the 9761656fa579e44691a860b095016eee910bc0b2793Pierre Ossman * blackout. 9771656fa579e44691a860b095016eee910bc0b2793Pierre Ossman */ 9781656fa579e44691a860b095016eee910bc0b2793Pierre Ossman tasklet_schedule(&host->card_tasklet); 9791656fa579e44691a860b095016eee910bc0b2793Pierre Ossman 9801656fa579e44691a860b095016eee910bc0b2793Pierre Ossman spin_unlock_bh(&host->lock); 9811656fa579e44691a860b095016eee910bc0b2793Pierre Ossman} 9821656fa579e44691a860b095016eee910bc0b2793Pierre Ossman 9831656fa579e44691a860b095016eee910bc0b2793Pierre Ossman/* 9841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Tasklets 9851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 9861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 987cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossmanstatic inline struct mmc_data *wbsd_get_data(struct wbsd_host *host) 9881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 9891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds WARN_ON(!host->mrq); 9901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!host->mrq) 9911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; 9921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds WARN_ON(!host->mrq->cmd); 9941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!host->mrq->cmd) 9951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; 9961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds WARN_ON(!host->mrq->cmd->data); 9981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!host->mrq->cmd->data) 9991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; 1000fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 10011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return host->mrq->cmd->data; 10021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 10031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void wbsd_tasklet_card(unsigned long param) 10051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1006cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman struct wbsd_host *host = (struct wbsd_host *)param; 10071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 csr; 1008210ce2a7504e429b7ccc191b1efba4c772c4d8b6Pierre Ossman int delay = -1; 1009fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 10101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock(&host->lock); 1011fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 1012cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman if (host->flags & WBSD_FIGNORE_DETECT) { 101385bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman spin_unlock(&host->lock); 101485bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman return; 101585bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman } 1016fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 10171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds csr = inb(host->base + WBSD_CSR); 10181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds WARN_ON(csr == 0xff); 1019fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 1020cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman if (csr & WBSD_CARDPRESENT) { 1021cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman if (!(host->flags & WBSD_FCARD_PRESENT)) { 102285bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman DBG("Card inserted\n"); 102385bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman host->flags |= WBSD_FCARD_PRESENT; 1024fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 1025210ce2a7504e429b7ccc191b1efba4c772c4d8b6Pierre Ossman delay = 500; 102685bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman } 1027cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman } else if (host->flags & WBSD_FCARD_PRESENT) { 10281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DBG("Card removed\n"); 102985bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman host->flags &= ~WBSD_FCARD_PRESENT; 1030fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 1031cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman if (host->mrq) { 1032a3c76eb9d4a1e68a69dd880cf0bcb8a52418b993Girish K S pr_err("%s: Card removed during transfer!\n", 1033d191634f7ab3a1c8e9da0c5e986c30b2612f0eb0Pierre Ossman mmc_hostname(host->mmc)); 10341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wbsd_reset(host); 1035fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 103617b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman host->mrq->cmd->error = -ENOMEDIUM; 10371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tasklet_schedule(&host->finish_tasklet); 10381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1039fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 1040210ce2a7504e429b7ccc191b1efba4c772c4d8b6Pierre Ossman delay = 0; 10416e6293dd3d4372c114674266158053d049366a0dPierre Ossman } 1042210ce2a7504e429b7ccc191b1efba4c772c4d8b6Pierre Ossman 1043210ce2a7504e429b7ccc191b1efba4c772c4d8b6Pierre Ossman /* 1044210ce2a7504e429b7ccc191b1efba4c772c4d8b6Pierre Ossman * Unlock first since we might get a call back. 1045210ce2a7504e429b7ccc191b1efba4c772c4d8b6Pierre Ossman */ 1046210ce2a7504e429b7ccc191b1efba4c772c4d8b6Pierre Ossman 1047210ce2a7504e429b7ccc191b1efba4c772c4d8b6Pierre Ossman spin_unlock(&host->lock); 1048210ce2a7504e429b7ccc191b1efba4c772c4d8b6Pierre Ossman 1049210ce2a7504e429b7ccc191b1efba4c772c4d8b6Pierre Ossman if (delay != -1) 1050210ce2a7504e429b7ccc191b1efba4c772c4d8b6Pierre Ossman mmc_detect_change(host->mmc, msecs_to_jiffies(delay)); 10511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 10521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void wbsd_tasklet_fifo(unsigned long param) 10541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1055cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman struct wbsd_host *host = (struct wbsd_host *)param; 1056cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman struct mmc_data *data; 1057fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 10581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock(&host->lock); 1059fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 10601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!host->mrq) 10611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto end; 1062fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 10631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data = wbsd_get_data(host); 10641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!data) 10651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto end; 10661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (data->flags & MMC_DATA_WRITE) 10681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wbsd_fill_fifo(host); 10691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 10701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wbsd_empty_fifo(host); 10711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 10731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Done? 10741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 107514d836e7499c53a1f6a65086c3d11600e871a971Alex Dubov if (host->num_sg == 0) { 10761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wbsd_write_index(host, WBSD_IDX_FIFOEN, 0); 10771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tasklet_schedule(&host->finish_tasklet); 10781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1080fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossmanend: 10811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock(&host->lock); 10821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 10831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void wbsd_tasklet_crc(unsigned long param) 10851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1086cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman struct wbsd_host *host = (struct wbsd_host *)param; 1087cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman struct mmc_data *data; 1088fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 10891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock(&host->lock); 1090fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 10911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!host->mrq) 10921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto end; 1093fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 10941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data = wbsd_get_data(host); 10951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!data) 10961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto end; 1097fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 10981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DBGF("CRC error\n"); 10991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 110017b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman data->error = -EILSEQ; 1101fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 11021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tasklet_schedule(&host->finish_tasklet); 11031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1104fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossmanend: 11051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock(&host->lock); 11061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 11071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void wbsd_tasklet_timeout(unsigned long param) 11091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1110cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman struct wbsd_host *host = (struct wbsd_host *)param; 1111cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman struct mmc_data *data; 1112fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 11131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock(&host->lock); 1114fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 11151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!host->mrq) 11161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto end; 1117fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 11181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data = wbsd_get_data(host); 11191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!data) 11201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto end; 1121fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 11221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DBGF("Timeout\n"); 11231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 112417b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman data->error = -ETIMEDOUT; 1125fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 11261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tasklet_schedule(&host->finish_tasklet); 11271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1128fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossmanend: 11291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock(&host->lock); 11301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 11311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void wbsd_tasklet_finish(unsigned long param) 11331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1134cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman struct wbsd_host *host = (struct wbsd_host *)param; 1135cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman struct mmc_data *data; 1136fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 11371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock(&host->lock); 1138fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 11391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds WARN_ON(!host->mrq); 11401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!host->mrq) 11411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto end; 1142fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 11431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data = wbsd_get_data(host); 11441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!data) 11451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto end; 11461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wbsd_finish_data(host, data); 1148fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 1149fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossmanend: 11501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock(&host->lock); 11511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 11521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 11541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Interrupt handling 11551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 11561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11577d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic irqreturn_t wbsd_irq(int irq, void *dev_id) 11581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1159cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman struct wbsd_host *host = dev_id; 11601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int isr; 1161fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 11621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds isr = inb(host->base + WBSD_ISR); 11631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 11651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Was it actually our hardware that caused the interrupt? 11661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 11671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (isr == 0xff || isr == 0x00) 11681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return IRQ_NONE; 1169fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 11701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->isr |= isr; 11711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 11731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Schedule tasklets as needed. 11741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 11751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (isr & WBSD_INT_CARD) 11761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tasklet_schedule(&host->card_tasklet); 11771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (isr & WBSD_INT_FIFO_THRE) 11781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tasklet_schedule(&host->fifo_tasklet); 11791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (isr & WBSD_INT_CRC) 11801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tasklet_hi_schedule(&host->crc_tasklet); 11811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (isr & WBSD_INT_TIMEOUT) 11821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tasklet_hi_schedule(&host->timeout_tasklet); 11831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (isr & WBSD_INT_TC) 11841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tasklet_schedule(&host->finish_tasklet); 1185fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 11861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return IRQ_HANDLED; 11871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 11881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 118985bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman/*****************************************************************************\ 119085bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman * * 119185bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman * Device initialisation and shutdown * 119285bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman * * 119385bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman\*****************************************************************************/ 119485bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman 11951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 119685bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman * Allocate/free MMC structure. 11971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 11981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1199cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossmanstatic int __devinit wbsd_alloc_mmc(struct device *dev) 120085bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman{ 1201cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman struct mmc_host *mmc; 1202cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman struct wbsd_host *host; 1203fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 120485bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman /* 120585bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman * Allocate MMC structure. 120685bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman */ 120785bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman mmc = mmc_alloc_host(sizeof(struct wbsd_host), dev); 120885bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman if (!mmc) 120985bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman return -ENOMEM; 1210fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 121185bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman host = mmc_priv(mmc); 121285bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman host->mmc = mmc; 121385bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman 121485bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman host->dma = -1; 121585bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman 121685bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman /* 121785bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman * Set host parameters. 121885bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman */ 121985bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman mmc->ops = &wbsd_ops; 122085bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman mmc->f_min = 375000; 122185bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman mmc->f_max = 24000000; 1222cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; 122323af60398af2f5033e2f53665538a09f498dbc03Pierre Ossman mmc->caps = MMC_CAP_4_BIT_DATA; 1224fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 122585bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman spin_lock_init(&host->lock); 1226fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 122785bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman /* 12281656fa579e44691a860b095016eee910bc0b2793Pierre Ossman * Set up timers 12296e6293dd3d4372c114674266158053d049366a0dPierre Ossman */ 12301656fa579e44691a860b095016eee910bc0b2793Pierre Ossman init_timer(&host->ignore_timer); 12311656fa579e44691a860b095016eee910bc0b2793Pierre Ossman host->ignore_timer.data = (unsigned long)host; 12321656fa579e44691a860b095016eee910bc0b2793Pierre Ossman host->ignore_timer.function = wbsd_reset_ignore; 1233fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 12346e6293dd3d4372c114674266158053d049366a0dPierre Ossman /* 123585bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman * Maximum number of segments. Worst case is one sector per segment 123685bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman * so this will be 64kB/512. 123785bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman */ 1238a36274e0184193e393fb82957925c3981a6b0477Martin K. Petersen mmc->max_segs = 128; 1239fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 124085bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman /* 124155db890a838c7b37256241b1fc53d6344aa79cc0Pierre Ossman * Maximum request size. Also limited by 64KiB buffer. 124285bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman */ 124355db890a838c7b37256241b1fc53d6344aa79cc0Pierre Ossman mmc->max_req_size = 65536; 1244fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 124585bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman /* 124685bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman * Maximum segment size. Could be one segment with the maximum number 124755db890a838c7b37256241b1fc53d6344aa79cc0Pierre Ossman * of bytes. 124885bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman */ 124955db890a838c7b37256241b1fc53d6344aa79cc0Pierre Ossman mmc->max_seg_size = mmc->max_req_size; 1250fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 1251fe4a3c7a20f14d86022a8132adbf6ddb98e7197cPierre Ossman /* 1252fe4a3c7a20f14d86022a8132adbf6ddb98e7197cPierre Ossman * Maximum block size. We have 12 bits (= 4095) but have to subtract 1253fe4a3c7a20f14d86022a8132adbf6ddb98e7197cPierre Ossman * space for CRC. So the maximum is 4095 - 4*2 = 4087. 1254fe4a3c7a20f14d86022a8132adbf6ddb98e7197cPierre Ossman */ 1255fe4a3c7a20f14d86022a8132adbf6ddb98e7197cPierre Ossman mmc->max_blk_size = 4087; 1256fe4a3c7a20f14d86022a8132adbf6ddb98e7197cPierre Ossman 125755db890a838c7b37256241b1fc53d6344aa79cc0Pierre Ossman /* 125855db890a838c7b37256241b1fc53d6344aa79cc0Pierre Ossman * Maximum block count. There is no real limit so the maximum 125955db890a838c7b37256241b1fc53d6344aa79cc0Pierre Ossman * request size will be the only restriction. 126055db890a838c7b37256241b1fc53d6344aa79cc0Pierre Ossman */ 126155db890a838c7b37256241b1fc53d6344aa79cc0Pierre Ossman mmc->max_blk_count = mmc->max_req_size; 126255db890a838c7b37256241b1fc53d6344aa79cc0Pierre Ossman 126385bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman dev_set_drvdata(dev, mmc); 1264fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 126585bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman return 0; 126685bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman} 126785bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman 1268b3627bb19f8f0ca12136d985d4d73c437cba0e14Gabriel Cstatic void wbsd_free_mmc(struct device *dev) 126985bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman{ 1270cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman struct mmc_host *mmc; 1271cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman struct wbsd_host *host; 1272fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 127385bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman mmc = dev_get_drvdata(dev); 127485bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman if (!mmc) 127585bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman return; 1276fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 12776e6293dd3d4372c114674266158053d049366a0dPierre Ossman host = mmc_priv(mmc); 12786e6293dd3d4372c114674266158053d049366a0dPierre Ossman BUG_ON(host == NULL); 1279fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 12801656fa579e44691a860b095016eee910bc0b2793Pierre Ossman del_timer_sync(&host->ignore_timer); 1281fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 128285bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman mmc_free_host(mmc); 1283fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 128485bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman dev_set_drvdata(dev, NULL); 128585bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman} 128685bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman 128785bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman/* 128885bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman * Scan for known chip id:s 128985bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman */ 129085bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman 1291cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossmanstatic int __devinit wbsd_scan(struct wbsd_host *host) 12921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 12931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i, j, k; 12941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int id; 1295fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 12961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 12971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Iterate through all ports, all codes to 12981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * find hardware that is in our known list. 12991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 130063648fb5c0173614064e329503cc75c907dcb1a1Dmitry Torokhov for (i = 0; i < ARRAY_SIZE(config_ports); i++) { 13011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!request_region(config_ports[i], 2, DRIVER_NAME)) 13021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 1303fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 130463648fb5c0173614064e329503cc75c907dcb1a1Dmitry Torokhov for (j = 0; j < ARRAY_SIZE(unlock_codes); j++) { 13051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds id = 0xFFFF; 1306fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 130719c1f3ca4272008a256cc153f3e3feb097799070Pierre Ossman host->config = config_ports[i]; 130819c1f3ca4272008a256cc153f3e3feb097799070Pierre Ossman host->unlock_code = unlock_codes[j]; 130919c1f3ca4272008a256cc153f3e3feb097799070Pierre Ossman 131019c1f3ca4272008a256cc153f3e3feb097799070Pierre Ossman wbsd_unlock_config(host); 1311fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 13121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(WBSD_CONF_ID_HI, config_ports[i]); 13131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds id = inb(config_ports[i] + 1) << 8; 13141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(WBSD_CONF_ID_LO, config_ports[i]); 13161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds id |= inb(config_ports[i] + 1); 1317fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 131819c1f3ca4272008a256cc153f3e3feb097799070Pierre Ossman wbsd_lock_config(host); 131919c1f3ca4272008a256cc153f3e3feb097799070Pierre Ossman 132063648fb5c0173614064e329503cc75c907dcb1a1Dmitry Torokhov for (k = 0; k < ARRAY_SIZE(valid_ids); k++) { 1321cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman if (id == valid_ids[k]) { 13221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->chip_id = id; 1323fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 13241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 13251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1327fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 1328cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman if (id != 0xFFFF) { 13291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DBG("Unknown hardware (id %x) found at %x\n", 13301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds id, config_ports[i]); 13311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1333fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 13341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds release_region(config_ports[i], 2); 13351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1336fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 133719c1f3ca4272008a256cc153f3e3feb097799070Pierre Ossman host->config = 0; 133819c1f3ca4272008a256cc153f3e3feb097799070Pierre Ossman host->unlock_code = 0; 133919c1f3ca4272008a256cc153f3e3feb097799070Pierre Ossman 13401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENODEV; 13411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 13421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 134385bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman/* 134485bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman * Allocate/free io port ranges 134585bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman */ 134685bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman 1347cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossmanstatic int __devinit wbsd_request_region(struct wbsd_host *host, int base) 13481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1349916f3ac680fcc4c142e9acd46161f55533b11760Pierre Ossman if (base & 0x7) 13501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 1351fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 135285bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman if (!request_region(base, 8, DRIVER_NAME)) 13531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EIO; 1354fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 1355916f3ac680fcc4c142e9acd46161f55533b11760Pierre Ossman host->base = base; 1356fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 13571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 13581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 13591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1360b3627bb19f8f0ca12136d985d4d73c437cba0e14Gabriel Cstatic void wbsd_release_regions(struct wbsd_host *host) 13611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 13621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (host->base) 13631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds release_region(host->base, 8); 1364fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 136585bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman host->base = 0; 13661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (host->config) 13681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds release_region(host->config, 2); 1369fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 137085bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman host->config = 0; 13711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 13721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 137385bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman/* 137485bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman * Allocate/free DMA port and buffer 137585bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman */ 137685bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman 1377cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossmanstatic void __devinit wbsd_request_dma(struct wbsd_host *host, int dma) 13781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 13791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dma < 0) 13801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 1381fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 13821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (request_dma(dma, DRIVER_NAME)) 13831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto err; 1384fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 13851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 13861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We need to allocate a special buffer in 13871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * order for ISA to be able to DMA to it. 13881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 138985bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman host->dma_buffer = kmalloc(WBSD_DMA_SIZE, 13901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds GFP_NOIO | GFP_DMA | __GFP_REPEAT | __GFP_NOWARN); 13911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!host->dma_buffer) 13921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto free; 13931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 13951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Translate the address to a physical address. 13961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1397fcaf71fd51f9cfc504455d3e19ec242e4b2073edGreg Kroah-Hartman host->dma_addr = dma_map_single(mmc_dev(host->mmc), host->dma_buffer, 139885bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman WBSD_DMA_SIZE, DMA_BIDIRECTIONAL); 1399fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 14001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 14011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ISA DMA must be aligned on a 64k basis. 14021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 14031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((host->dma_addr & 0xffff) != 0) 14041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto kfree; 14051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 14061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ISA cannot access memory above 16 MB. 14071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 14081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (host->dma_addr >= 0x1000000) 14091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto kfree; 14101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->dma = dma; 1412fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 14131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 1414fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 14151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldskfree: 14161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 14171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If we've gotten here then there is some kind of alignment bug 14181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 14191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BUG_ON(1); 1420fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 1421fcaf71fd51f9cfc504455d3e19ec242e4b2073edGreg Kroah-Hartman dma_unmap_single(mmc_dev(host->mmc), host->dma_addr, 1422cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman WBSD_DMA_SIZE, DMA_BIDIRECTIONAL); 142397067d5581ec831a75a45a52e417bee0f7943dbfPierre Ossman host->dma_addr = 0; 1424fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 14251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(host->dma_buffer); 14261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->dma_buffer = NULL; 14271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsfree: 14291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_dma(dma); 14301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserr: 1432a3c76eb9d4a1e68a69dd880cf0bcb8a52418b993Girish K S pr_warning(DRIVER_NAME ": Unable to allocate DMA %d. " 14331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "Falling back on FIFO.\n", dma); 14341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 14351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1436b3627bb19f8f0ca12136d985d4d73c437cba0e14Gabriel Cstatic void wbsd_release_dma(struct wbsd_host *host) 143785bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman{ 1438cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman if (host->dma_addr) { 1439fcaf71fd51f9cfc504455d3e19ec242e4b2073edGreg Kroah-Hartman dma_unmap_single(mmc_dev(host->mmc), host->dma_addr, 1440cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman WBSD_DMA_SIZE, DMA_BIDIRECTIONAL); 1441cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman } 14426044ec8882c726e325017bd948aa0cd94ad33abcJesper Juhl kfree(host->dma_buffer); 144385bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman if (host->dma >= 0) 144485bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman free_dma(host->dma); 1445fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 144685bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman host->dma = -1; 144785bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman host->dma_buffer = NULL; 144897067d5581ec831a75a45a52e417bee0f7943dbfPierre Ossman host->dma_addr = 0; 144985bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman} 14501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 145285bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman * Allocate/free IRQ. 14531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 14541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1455cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossmanstatic int __devinit wbsd_request_irq(struct wbsd_host *host, int irq) 14561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 14571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret; 1458fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 14591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 1460cef33400d0349fb24b6f8b7dea79b66e3144fd8bChuck Ebbert * Set up tasklets. Must be done before requesting interrupt. 14611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1462cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman tasklet_init(&host->card_tasklet, wbsd_tasklet_card, 1463cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman (unsigned long)host); 1464cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman tasklet_init(&host->fifo_tasklet, wbsd_tasklet_fifo, 1465cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman (unsigned long)host); 1466cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman tasklet_init(&host->crc_tasklet, wbsd_tasklet_crc, 1467cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman (unsigned long)host); 1468cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman tasklet_init(&host->timeout_tasklet, wbsd_tasklet_timeout, 1469cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman (unsigned long)host); 1470cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman tasklet_init(&host->finish_tasklet, wbsd_tasklet_finish, 1471cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman (unsigned long)host); 1472fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 1473cef33400d0349fb24b6f8b7dea79b66e3144fd8bChuck Ebbert /* 1474cef33400d0349fb24b6f8b7dea79b66e3144fd8bChuck Ebbert * Allocate interrupt. 1475cef33400d0349fb24b6f8b7dea79b66e3144fd8bChuck Ebbert */ 1476cef33400d0349fb24b6f8b7dea79b66e3144fd8bChuck Ebbert ret = request_irq(irq, wbsd_irq, IRQF_SHARED, DRIVER_NAME, host); 1477cef33400d0349fb24b6f8b7dea79b66e3144fd8bChuck Ebbert if (ret) 1478cef33400d0349fb24b6f8b7dea79b66e3144fd8bChuck Ebbert return ret; 1479cef33400d0349fb24b6f8b7dea79b66e3144fd8bChuck Ebbert 1480cef33400d0349fb24b6f8b7dea79b66e3144fd8bChuck Ebbert host->irq = irq; 1481cef33400d0349fb24b6f8b7dea79b66e3144fd8bChuck Ebbert 148285bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman return 0; 148385bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman} 14841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1485b3627bb19f8f0ca12136d985d4d73c437cba0e14Gabriel Cstatic void wbsd_release_irq(struct wbsd_host *host) 148685bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman{ 148785bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman if (!host->irq) 148885bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman return; 14891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 149085bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman free_irq(host->irq, host); 1491fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 149285bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman host->irq = 0; 1493fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 149485bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman tasklet_kill(&host->card_tasklet); 149585bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman tasklet_kill(&host->fifo_tasklet); 149685bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman tasklet_kill(&host->crc_tasklet); 149785bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman tasklet_kill(&host->timeout_tasklet); 149885bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman tasklet_kill(&host->finish_tasklet); 149985bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman} 150085bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman 150185bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman/* 150285bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman * Allocate all resources for the host. 150385bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman */ 150485bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman 1505cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossmanstatic int __devinit wbsd_request_resources(struct wbsd_host *host, 150685bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman int base, int irq, int dma) 150785bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman{ 150885bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman int ret; 1509fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 15101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 15111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Allocate I/O ports. 15121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 151385bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman ret = wbsd_request_region(host, base); 15141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret) 151585bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman return ret; 15161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 151885bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman * Allocate interrupt. 15191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 152085bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman ret = wbsd_request_irq(host, irq); 152185bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman if (ret) 152285bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman return ret; 152385bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman 152485bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman /* 152585bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman * Allocate DMA. 152685bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman */ 152785bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman wbsd_request_dma(host, dma); 1528fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 152985bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman return 0; 153085bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman} 153185bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman 153285bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman/* 153385bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman * Release all resources for the host. 153485bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman */ 153585bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman 1536b3627bb19f8f0ca12136d985d4d73c437cba0e14Gabriel Cstatic void wbsd_release_resources(struct wbsd_host *host) 153785bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman{ 153885bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman wbsd_release_dma(host); 153985bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman wbsd_release_irq(host); 154085bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman wbsd_release_regions(host); 154185bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman} 154285bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman 154385bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman/* 154485bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman * Configure the resources the chip should use. 154585bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman */ 154685bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman 1547cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossmanstatic void wbsd_chip_config(struct wbsd_host *host) 154885bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman{ 154919c1f3ca4272008a256cc153f3e3feb097799070Pierre Ossman wbsd_unlock_config(host); 155019c1f3ca4272008a256cc153f3e3feb097799070Pierre Ossman 155185bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman /* 155285bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman * Reset the chip. 1553fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman */ 155485bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman wbsd_write_config(host, WBSD_CONF_SWRST, 1); 155585bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman wbsd_write_config(host, WBSD_CONF_SWRST, 0); 15561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 15581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Select SD/MMC function. 15591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 15601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wbsd_write_config(host, WBSD_CONF_DEVICE, DEVICE_SD); 1561fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 15621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 15631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Set up card detection. 15641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 156585bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman wbsd_write_config(host, WBSD_CONF_PINS, WBSD_PINS_DETECT_GP11); 1566fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 15671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 156885bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman * Configure chip 15691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 15701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wbsd_write_config(host, WBSD_CONF_PORT_HI, host->base >> 8); 15711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wbsd_write_config(host, WBSD_CONF_PORT_LO, host->base & 0xff); 1572fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 157385bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman wbsd_write_config(host, WBSD_CONF_IRQ, host->irq); 1574fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 157585bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman if (host->dma >= 0) 157685bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman wbsd_write_config(host, WBSD_CONF_DRQ, host->dma); 1577fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 15781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 157985bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman * Enable and power up chip. 15801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 158185bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman wbsd_write_config(host, WBSD_CONF_ENABLE, 1); 158285bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman wbsd_write_config(host, WBSD_CONF_POWER, 0x20); 158319c1f3ca4272008a256cc153f3e3feb097799070Pierre Ossman 158419c1f3ca4272008a256cc153f3e3feb097799070Pierre Ossman wbsd_lock_config(host); 158585bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman} 158685bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman 158785bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman/* 158885bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman * Check that configured resources are correct. 158985bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman */ 1590fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 1591cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossmanstatic int wbsd_chip_validate(struct wbsd_host *host) 159285bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman{ 159385bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman int base, irq, dma; 1594fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 159519c1f3ca4272008a256cc153f3e3feb097799070Pierre Ossman wbsd_unlock_config(host); 159619c1f3ca4272008a256cc153f3e3feb097799070Pierre Ossman 15971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 159885bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman * Select SD/MMC function. 15991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 160085bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman wbsd_write_config(host, WBSD_CONF_DEVICE, DEVICE_SD); 1601fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 16021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 160385bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman * Read configuration. 16041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 160585bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman base = wbsd_read_config(host, WBSD_CONF_PORT_HI) << 8; 160685bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman base |= wbsd_read_config(host, WBSD_CONF_PORT_LO); 1607fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 160885bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman irq = wbsd_read_config(host, WBSD_CONF_IRQ); 1609fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 161085bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman dma = wbsd_read_config(host, WBSD_CONF_DRQ); 1611fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 161219c1f3ca4272008a256cc153f3e3feb097799070Pierre Ossman wbsd_lock_config(host); 161319c1f3ca4272008a256cc153f3e3feb097799070Pierre Ossman 16141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 161585bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman * Validate against given configuration. 16161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 161785bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman if (base != host->base) 161885bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman return 0; 161985bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman if (irq != host->irq) 162085bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman return 0; 162185bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman if ((dma != host->dma) && (host->dma != -1)) 162285bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman return 0; 1623fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 162485bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman return 1; 162585bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman} 162685bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman 162719c1f3ca4272008a256cc153f3e3feb097799070Pierre Ossman/* 162819c1f3ca4272008a256cc153f3e3feb097799070Pierre Ossman * Powers down the SD function 162919c1f3ca4272008a256cc153f3e3feb097799070Pierre Ossman */ 163019c1f3ca4272008a256cc153f3e3feb097799070Pierre Ossman 1631cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossmanstatic void wbsd_chip_poweroff(struct wbsd_host *host) 163219c1f3ca4272008a256cc153f3e3feb097799070Pierre Ossman{ 163319c1f3ca4272008a256cc153f3e3feb097799070Pierre Ossman wbsd_unlock_config(host); 163419c1f3ca4272008a256cc153f3e3feb097799070Pierre Ossman 163519c1f3ca4272008a256cc153f3e3feb097799070Pierre Ossman wbsd_write_config(host, WBSD_CONF_DEVICE, DEVICE_SD); 163619c1f3ca4272008a256cc153f3e3feb097799070Pierre Ossman wbsd_write_config(host, WBSD_CONF_ENABLE, 0); 163719c1f3ca4272008a256cc153f3e3feb097799070Pierre Ossman 163819c1f3ca4272008a256cc153f3e3feb097799070Pierre Ossman wbsd_lock_config(host); 163919c1f3ca4272008a256cc153f3e3feb097799070Pierre Ossman} 164019c1f3ca4272008a256cc153f3e3feb097799070Pierre Ossman 164185bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman/*****************************************************************************\ 164285bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman * * 164385bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman * Devices setup and shutdown * 164485bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman * * 164585bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman\*****************************************************************************/ 164685bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman 1647cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossmanstatic int __devinit wbsd_init(struct device *dev, int base, int irq, int dma, 164885bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman int pnp) 164985bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman{ 1650cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman struct wbsd_host *host = NULL; 1651cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman struct mmc_host *mmc = NULL; 165285bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman int ret; 1653fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 165485bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman ret = wbsd_alloc_mmc(dev); 165585bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman if (ret) 165685bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman return ret; 1657fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 165885bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman mmc = dev_get_drvdata(dev); 165985bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman host = mmc_priv(mmc); 1660fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 16611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 166285bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman * Scan for hardware. 16631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 166485bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman ret = wbsd_scan(host); 1665cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman if (ret) { 1666cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman if (pnp && (ret == -ENODEV)) { 1667a3c76eb9d4a1e68a69dd880cf0bcb8a52418b993Girish K S pr_warning(DRIVER_NAME 166885bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman ": Unable to confirm device presence. You may " 166985bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman "experience lock-ups.\n"); 1670cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman } else { 167185bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman wbsd_free_mmc(dev); 167285bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman return ret; 167385bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman } 167485bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman } 1675fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 16761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 167785bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman * Request resources. 16781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1679dd2c609c59cd9daeb90d58f3d1bc3813e8987df1Pierre Ossman ret = wbsd_request_resources(host, base, irq, dma); 1680cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman if (ret) { 168185bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman wbsd_release_resources(host); 168285bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman wbsd_free_mmc(dev); 168385bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman return ret; 168485bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman } 1685fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 16861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 168785bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman * See if chip needs to be configured. 16881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1689cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman if (pnp) { 1690cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman if ((host->config != 0) && !wbsd_chip_validate(host)) { 1691a3c76eb9d4a1e68a69dd880cf0bcb8a52418b993Girish K S pr_warning(DRIVER_NAME 169285bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman ": PnP active but chip not configured! " 169385bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman "You probably have a buggy BIOS. " 169485bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman "Configuring chip manually.\n"); 169585bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman wbsd_chip_config(host); 169685bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman } 1697cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman } else 169885bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman wbsd_chip_config(host); 1699fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 17001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 17011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Power Management stuff. No idea how this works. 17021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Not tested. 17031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 17041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_PM 1705cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman if (host->config) { 170619c1f3ca4272008a256cc153f3e3feb097799070Pierre Ossman wbsd_unlock_config(host); 170785bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman wbsd_write_config(host, WBSD_CONF_PME, 0xA0); 170819c1f3ca4272008a256cc153f3e3feb097799070Pierre Ossman wbsd_lock_config(host); 170919c1f3ca4272008a256cc153f3e3feb097799070Pierre Ossman } 17101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 171185bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman /* 171285bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman * Allow device to initialise itself properly. 171385bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman */ 171485bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman mdelay(5); 17151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 17171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Reset the chip into a known state. 17181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 17191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wbsd_init_device(host); 1720fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 17211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mmc_add_host(mmc); 17221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1723a3c76eb9d4a1e68a69dd880cf0bcb8a52418b993Girish K S pr_info("%s: W83L51xD", mmc_hostname(mmc)); 172485bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman if (host->chip_id != 0) 172585bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman printk(" id %x", (int)host->chip_id); 172685bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman printk(" at 0x%x irq %d", (int)host->base, (int)host->irq); 172785bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman if (host->dma >= 0) 172885bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman printk(" dma %d", (int)host->dma); 172985bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman else 173085bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman printk(" FIFO"); 173185bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman if (pnp) 173285bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman printk(" PnP"); 173385bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman printk("\n"); 17341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 17361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 17371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1738cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossmanstatic void __devexit wbsd_shutdown(struct device *dev, int pnp) 17391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1740cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman struct mmc_host *mmc = dev_get_drvdata(dev); 1741cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman struct wbsd_host *host; 1742fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 17431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!mmc) 174485bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman return; 17451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host = mmc_priv(mmc); 1747fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 17481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mmc_remove_host(mmc); 17491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 175019c1f3ca4272008a256cc153f3e3feb097799070Pierre Ossman /* 175119c1f3ca4272008a256cc153f3e3feb097799070Pierre Ossman * Power down the SD/MMC function. 175219c1f3ca4272008a256cc153f3e3feb097799070Pierre Ossman */ 175385bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman if (!pnp) 175419c1f3ca4272008a256cc153f3e3feb097799070Pierre Ossman wbsd_chip_poweroff(host); 1755fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 175685bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman wbsd_release_resources(host); 1757fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 175885bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman wbsd_free_mmc(dev); 175985bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman} 17601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 176185bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman/* 176285bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman * Non-PnP 176385bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman */ 176485bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman 1765cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossmanstatic int __devinit wbsd_probe(struct platform_device *dev) 176685bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman{ 1767dd2c609c59cd9daeb90d58f3d1bc3813e8987df1Pierre Ossman /* Use the module parameters for resources */ 17689eeebd22ca757fee8dc10ffe6fa6992f33a3c5ecTomas Winkler return wbsd_init(&dev->dev, param_io, param_irq, param_dma, 0); 176985bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman} 177085bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman 1771cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossmanstatic int __devexit wbsd_remove(struct platform_device *dev) 177285bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman{ 17733ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King wbsd_shutdown(&dev->dev, 0); 177485bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman 177585bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman return 0; 177685bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman} 177785bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman 177885bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman/* 177985bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman * PnP 178085bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman */ 178185bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman 178285bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman#ifdef CONFIG_PNP 178385bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman 178485bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossmanstatic int __devinit 1785cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossmanwbsd_pnp_probe(struct pnp_dev *pnpdev, const struct pnp_device_id *dev_id) 178685bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman{ 178785bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman int io, irq, dma; 1788fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 178985bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman /* 179085bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman * Get resources from PnP layer. 179185bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman */ 179285bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman io = pnp_port_start(pnpdev, 0); 179385bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman irq = pnp_irq(pnpdev, 0); 179485bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman if (pnp_dma_valid(pnpdev, 0)) 179585bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman dma = pnp_dma(pnpdev, 0); 179685bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman else 179785bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman dma = -1; 1798fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 179985bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman DBGF("PnP resources: port %3x irq %d dma %d\n", io, irq, dma); 1800fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 180185bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman return wbsd_init(&pnpdev->dev, io, irq, dma, 1); 180285bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman} 18031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1804cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossmanstatic void __devexit wbsd_pnp_remove(struct pnp_dev *dev) 180585bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman{ 180685bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman wbsd_shutdown(&dev->dev, 1); 18071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 18081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 180985bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman#endif /* CONFIG_PNP */ 181085bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman 18111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 18121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Power management 18131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 18141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_PM 181619c1f3ca4272008a256cc153f3e3feb097799070Pierre Ossman 18175e68d95d155c94e45f16b521fd4e2bcd6c8481b1Pierre Ossmanstatic int wbsd_suspend(struct wbsd_host *host, pm_message_t state) 18185e68d95d155c94e45f16b521fd4e2bcd6c8481b1Pierre Ossman{ 18195e68d95d155c94e45f16b521fd4e2bcd6c8481b1Pierre Ossman BUG_ON(host == NULL); 18205e68d95d155c94e45f16b521fd4e2bcd6c8481b1Pierre Ossman 18211a13f8fa76c880be41d6b1e6a2b44404bcbfdf9eMatt Fleming return mmc_suspend_host(host->mmc); 18225e68d95d155c94e45f16b521fd4e2bcd6c8481b1Pierre Ossman} 18235e68d95d155c94e45f16b521fd4e2bcd6c8481b1Pierre Ossman 18245e68d95d155c94e45f16b521fd4e2bcd6c8481b1Pierre Ossmanstatic int wbsd_resume(struct wbsd_host *host) 18255e68d95d155c94e45f16b521fd4e2bcd6c8481b1Pierre Ossman{ 18265e68d95d155c94e45f16b521fd4e2bcd6c8481b1Pierre Ossman BUG_ON(host == NULL); 18275e68d95d155c94e45f16b521fd4e2bcd6c8481b1Pierre Ossman 18285e68d95d155c94e45f16b521fd4e2bcd6c8481b1Pierre Ossman wbsd_init_device(host); 18295e68d95d155c94e45f16b521fd4e2bcd6c8481b1Pierre Ossman 18305e68d95d155c94e45f16b521fd4e2bcd6c8481b1Pierre Ossman return mmc_resume_host(host->mmc); 18315e68d95d155c94e45f16b521fd4e2bcd6c8481b1Pierre Ossman} 18325e68d95d155c94e45f16b521fd4e2bcd6c8481b1Pierre Ossman 1833cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossmanstatic int wbsd_platform_suspend(struct platform_device *dev, 1834cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman pm_message_t state) 18351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 18363ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King struct mmc_host *mmc = platform_get_drvdata(dev); 183719c1f3ca4272008a256cc153f3e3feb097799070Pierre Ossman struct wbsd_host *host; 183819c1f3ca4272008a256cc153f3e3feb097799070Pierre Ossman int ret; 183919c1f3ca4272008a256cc153f3e3feb097799070Pierre Ossman 18405e68d95d155c94e45f16b521fd4e2bcd6c8481b1Pierre Ossman if (mmc == NULL) 184119c1f3ca4272008a256cc153f3e3feb097799070Pierre Ossman return 0; 184219c1f3ca4272008a256cc153f3e3feb097799070Pierre Ossman 18435e68d95d155c94e45f16b521fd4e2bcd6c8481b1Pierre Ossman DBGF("Suspending...\n"); 184419c1f3ca4272008a256cc153f3e3feb097799070Pierre Ossman 184519c1f3ca4272008a256cc153f3e3feb097799070Pierre Ossman host = mmc_priv(mmc); 184619c1f3ca4272008a256cc153f3e3feb097799070Pierre Ossman 18475e68d95d155c94e45f16b521fd4e2bcd6c8481b1Pierre Ossman ret = wbsd_suspend(host, state); 18485e68d95d155c94e45f16b521fd4e2bcd6c8481b1Pierre Ossman if (ret) 18495e68d95d155c94e45f16b521fd4e2bcd6c8481b1Pierre Ossman return ret; 18505e68d95d155c94e45f16b521fd4e2bcd6c8481b1Pierre Ossman 185119c1f3ca4272008a256cc153f3e3feb097799070Pierre Ossman wbsd_chip_poweroff(host); 18521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 18541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 18551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18565e68d95d155c94e45f16b521fd4e2bcd6c8481b1Pierre Ossmanstatic int wbsd_platform_resume(struct platform_device *dev) 18571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 18583ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King struct mmc_host *mmc = platform_get_drvdata(dev); 185919c1f3ca4272008a256cc153f3e3feb097799070Pierre Ossman struct wbsd_host *host; 18601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18615e68d95d155c94e45f16b521fd4e2bcd6c8481b1Pierre Ossman if (mmc == NULL) 186219c1f3ca4272008a256cc153f3e3feb097799070Pierre Ossman return 0; 186319c1f3ca4272008a256cc153f3e3feb097799070Pierre Ossman 18645e68d95d155c94e45f16b521fd4e2bcd6c8481b1Pierre Ossman DBGF("Resuming...\n"); 186519c1f3ca4272008a256cc153f3e3feb097799070Pierre Ossman 186619c1f3ca4272008a256cc153f3e3feb097799070Pierre Ossman host = mmc_priv(mmc); 186719c1f3ca4272008a256cc153f3e3feb097799070Pierre Ossman 186819c1f3ca4272008a256cc153f3e3feb097799070Pierre Ossman wbsd_chip_config(host); 186919c1f3ca4272008a256cc153f3e3feb097799070Pierre Ossman 187019c1f3ca4272008a256cc153f3e3feb097799070Pierre Ossman /* 187119c1f3ca4272008a256cc153f3e3feb097799070Pierre Ossman * Allow device to initialise itself properly. 187219c1f3ca4272008a256cc153f3e3feb097799070Pierre Ossman */ 187319c1f3ca4272008a256cc153f3e3feb097799070Pierre Ossman mdelay(5); 187419c1f3ca4272008a256cc153f3e3feb097799070Pierre Ossman 18755e68d95d155c94e45f16b521fd4e2bcd6c8481b1Pierre Ossman return wbsd_resume(host); 18765e68d95d155c94e45f16b521fd4e2bcd6c8481b1Pierre Ossman} 18775e68d95d155c94e45f16b521fd4e2bcd6c8481b1Pierre Ossman 18785e68d95d155c94e45f16b521fd4e2bcd6c8481b1Pierre Ossman#ifdef CONFIG_PNP 18795e68d95d155c94e45f16b521fd4e2bcd6c8481b1Pierre Ossman 18805e68d95d155c94e45f16b521fd4e2bcd6c8481b1Pierre Ossmanstatic int wbsd_pnp_suspend(struct pnp_dev *pnp_dev, pm_message_t state) 18815e68d95d155c94e45f16b521fd4e2bcd6c8481b1Pierre Ossman{ 18825e68d95d155c94e45f16b521fd4e2bcd6c8481b1Pierre Ossman struct mmc_host *mmc = dev_get_drvdata(&pnp_dev->dev); 18835e68d95d155c94e45f16b521fd4e2bcd6c8481b1Pierre Ossman struct wbsd_host *host; 18845e68d95d155c94e45f16b521fd4e2bcd6c8481b1Pierre Ossman 18855e68d95d155c94e45f16b521fd4e2bcd6c8481b1Pierre Ossman if (mmc == NULL) 18865e68d95d155c94e45f16b521fd4e2bcd6c8481b1Pierre Ossman return 0; 188719c1f3ca4272008a256cc153f3e3feb097799070Pierre Ossman 18885e68d95d155c94e45f16b521fd4e2bcd6c8481b1Pierre Ossman DBGF("Suspending...\n"); 18895e68d95d155c94e45f16b521fd4e2bcd6c8481b1Pierre Ossman 18905e68d95d155c94e45f16b521fd4e2bcd6c8481b1Pierre Ossman host = mmc_priv(mmc); 18915e68d95d155c94e45f16b521fd4e2bcd6c8481b1Pierre Ossman 18925e68d95d155c94e45f16b521fd4e2bcd6c8481b1Pierre Ossman return wbsd_suspend(host, state); 18931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 189419c1f3ca4272008a256cc153f3e3feb097799070Pierre Ossman 18955e68d95d155c94e45f16b521fd4e2bcd6c8481b1Pierre Ossmanstatic int wbsd_pnp_resume(struct pnp_dev *pnp_dev) 18965e68d95d155c94e45f16b521fd4e2bcd6c8481b1Pierre Ossman{ 18975e68d95d155c94e45f16b521fd4e2bcd6c8481b1Pierre Ossman struct mmc_host *mmc = dev_get_drvdata(&pnp_dev->dev); 18985e68d95d155c94e45f16b521fd4e2bcd6c8481b1Pierre Ossman struct wbsd_host *host; 18995e68d95d155c94e45f16b521fd4e2bcd6c8481b1Pierre Ossman 19005e68d95d155c94e45f16b521fd4e2bcd6c8481b1Pierre Ossman if (mmc == NULL) 19015e68d95d155c94e45f16b521fd4e2bcd6c8481b1Pierre Ossman return 0; 19025e68d95d155c94e45f16b521fd4e2bcd6c8481b1Pierre Ossman 19035e68d95d155c94e45f16b521fd4e2bcd6c8481b1Pierre Ossman DBGF("Resuming...\n"); 19045e68d95d155c94e45f16b521fd4e2bcd6c8481b1Pierre Ossman 19055e68d95d155c94e45f16b521fd4e2bcd6c8481b1Pierre Ossman host = mmc_priv(mmc); 19065e68d95d155c94e45f16b521fd4e2bcd6c8481b1Pierre Ossman 19075e68d95d155c94e45f16b521fd4e2bcd6c8481b1Pierre Ossman /* 19085e68d95d155c94e45f16b521fd4e2bcd6c8481b1Pierre Ossman * See if chip needs to be configured. 19095e68d95d155c94e45f16b521fd4e2bcd6c8481b1Pierre Ossman */ 1910cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman if (host->config != 0) { 1911cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman if (!wbsd_chip_validate(host)) { 1912a3c76eb9d4a1e68a69dd880cf0bcb8a52418b993Girish K S pr_warning(DRIVER_NAME 19135e68d95d155c94e45f16b521fd4e2bcd6c8481b1Pierre Ossman ": PnP active but chip not configured! " 19145e68d95d155c94e45f16b521fd4e2bcd6c8481b1Pierre Ossman "You probably have a buggy BIOS. " 19155e68d95d155c94e45f16b521fd4e2bcd6c8481b1Pierre Ossman "Configuring chip manually.\n"); 19165e68d95d155c94e45f16b521fd4e2bcd6c8481b1Pierre Ossman wbsd_chip_config(host); 19175e68d95d155c94e45f16b521fd4e2bcd6c8481b1Pierre Ossman } 19185e68d95d155c94e45f16b521fd4e2bcd6c8481b1Pierre Ossman } 19195e68d95d155c94e45f16b521fd4e2bcd6c8481b1Pierre Ossman 19205e68d95d155c94e45f16b521fd4e2bcd6c8481b1Pierre Ossman /* 19215e68d95d155c94e45f16b521fd4e2bcd6c8481b1Pierre Ossman * Allow device to initialise itself properly. 19225e68d95d155c94e45f16b521fd4e2bcd6c8481b1Pierre Ossman */ 19235e68d95d155c94e45f16b521fd4e2bcd6c8481b1Pierre Ossman mdelay(5); 19245e68d95d155c94e45f16b521fd4e2bcd6c8481b1Pierre Ossman 19255e68d95d155c94e45f16b521fd4e2bcd6c8481b1Pierre Ossman return wbsd_resume(host); 19265e68d95d155c94e45f16b521fd4e2bcd6c8481b1Pierre Ossman} 19275e68d95d155c94e45f16b521fd4e2bcd6c8481b1Pierre Ossman 19285e68d95d155c94e45f16b521fd4e2bcd6c8481b1Pierre Ossman#endif /* CONFIG_PNP */ 19295e68d95d155c94e45f16b521fd4e2bcd6c8481b1Pierre Ossman 193019c1f3ca4272008a256cc153f3e3feb097799070Pierre Ossman#else /* CONFIG_PM */ 193119c1f3ca4272008a256cc153f3e3feb097799070Pierre Ossman 19325e68d95d155c94e45f16b521fd4e2bcd6c8481b1Pierre Ossman#define wbsd_platform_suspend NULL 19335e68d95d155c94e45f16b521fd4e2bcd6c8481b1Pierre Ossman#define wbsd_platform_resume NULL 19345e68d95d155c94e45f16b521fd4e2bcd6c8481b1Pierre Ossman 19355e68d95d155c94e45f16b521fd4e2bcd6c8481b1Pierre Ossman#define wbsd_pnp_suspend NULL 19365e68d95d155c94e45f16b521fd4e2bcd6c8481b1Pierre Ossman#define wbsd_pnp_resume NULL 193719c1f3ca4272008a256cc153f3e3feb097799070Pierre Ossman 193819c1f3ca4272008a256cc153f3e3feb097799070Pierre Ossman#endif /* CONFIG_PM */ 19391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 194085bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossmanstatic struct platform_device *wbsd_device; 19411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19423ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell Kingstatic struct platform_driver wbsd_driver = { 19431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .probe = wbsd_probe, 194493968d7551f1ff1806f70cdacf1bd997ef30836ePierre Ossman .remove = __devexit_p(wbsd_remove), 1945fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 19465e68d95d155c94e45f16b521fd4e2bcd6c8481b1Pierre Ossman .suspend = wbsd_platform_suspend, 19475e68d95d155c94e45f16b521fd4e2bcd6c8481b1Pierre Ossman .resume = wbsd_platform_resume, 19483ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King .driver = { 19493ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King .name = DRIVER_NAME, 1950bc65c724d5a2c61539b2c52680941505152fcf30Kay Sievers .owner = THIS_MODULE, 19513ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King }, 19521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 19531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 195485bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman#ifdef CONFIG_PNP 195585bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman 195685bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossmanstatic struct pnp_driver wbsd_pnp_driver = { 195785bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman .name = DRIVER_NAME, 195885bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman .id_table = pnp_dev_table, 195985bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman .probe = wbsd_pnp_probe, 196093968d7551f1ff1806f70cdacf1bd997ef30836ePierre Ossman .remove = __devexit_p(wbsd_pnp_remove), 19615e68d95d155c94e45f16b521fd4e2bcd6c8481b1Pierre Ossman 19625e68d95d155c94e45f16b521fd4e2bcd6c8481b1Pierre Ossman .suspend = wbsd_pnp_suspend, 19635e68d95d155c94e45f16b521fd4e2bcd6c8481b1Pierre Ossman .resume = wbsd_pnp_resume, 196485bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman}; 196585bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman 196685bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman#endif /* CONFIG_PNP */ 196785bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman 19681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 19691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Module loading/unloading 19701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 19711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init wbsd_drv_init(void) 19731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 19741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int result; 1975fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 1976a3c76eb9d4a1e68a69dd880cf0bcb8a52418b993Girish K S pr_info(DRIVER_NAME 19771615cc224e5d822c91bf0b8128f54680c6e92d2fPierre Ossman ": Winbond W83L51xD SD/MMC card interface driver\n"); 1978a3c76eb9d4a1e68a69dd880cf0bcb8a52418b993Girish K S pr_info(DRIVER_NAME ": Copyright(c) Pierre Ossman\n"); 19791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 198085bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman#ifdef CONFIG_PNP 198185bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman 19829eeebd22ca757fee8dc10ffe6fa6992f33a3c5ecTomas Winkler if (!param_nopnp) { 198385bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman result = pnp_register_driver(&wbsd_pnp_driver); 198485bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman if (result < 0) 198585bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman return result; 198685bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman } 1987fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman#endif /* CONFIG_PNP */ 1988fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 19899eeebd22ca757fee8dc10ffe6fa6992f33a3c5ecTomas Winkler if (param_nopnp) { 19903ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King result = platform_driver_register(&wbsd_driver); 199185bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman if (result < 0) 199285bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman return result; 199385bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman 199421500bb32acd4c34b50e5d985712e29792c1b9adDmitry Torokhov wbsd_device = platform_device_alloc(DRIVER_NAME, -1); 1995cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman if (!wbsd_device) { 199621500bb32acd4c34b50e5d985712e29792c1b9adDmitry Torokhov platform_driver_unregister(&wbsd_driver); 199721500bb32acd4c34b50e5d985712e29792c1b9adDmitry Torokhov return -ENOMEM; 199821500bb32acd4c34b50e5d985712e29792c1b9adDmitry Torokhov } 199921500bb32acd4c34b50e5d985712e29792c1b9adDmitry Torokhov 200021500bb32acd4c34b50e5d985712e29792c1b9adDmitry Torokhov result = platform_device_add(wbsd_device); 2001cfa7f52164d6cdcb6cea87386562c568da66ff9ePierre Ossman if (result) { 200221500bb32acd4c34b50e5d985712e29792c1b9adDmitry Torokhov platform_device_put(wbsd_device); 200321500bb32acd4c34b50e5d985712e29792c1b9adDmitry Torokhov platform_driver_unregister(&wbsd_driver); 200421500bb32acd4c34b50e5d985712e29792c1b9adDmitry Torokhov return result; 200521500bb32acd4c34b50e5d985712e29792c1b9adDmitry Torokhov } 200685bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman } 20071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 20091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 20101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit wbsd_drv_exit(void) 20121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 201385bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman#ifdef CONFIG_PNP 201485bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman 20159eeebd22ca757fee8dc10ffe6fa6992f33a3c5ecTomas Winkler if (!param_nopnp) 201685bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman pnp_unregister_driver(&wbsd_pnp_driver); 2017fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 2018fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman#endif /* CONFIG_PNP */ 201985bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman 20209eeebd22ca757fee8dc10ffe6fa6992f33a3c5ecTomas Winkler if (param_nopnp) { 202185bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman platform_device_unregister(wbsd_device); 2022fecf92ba050a426b3bd302b6ba1c1525d576ccb9Pierre Ossman 20233ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King platform_driver_unregister(&wbsd_driver); 202485bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman } 20251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DBG("unloaded\n"); 20271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 20281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(wbsd_drv_init); 20301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(wbsd_drv_exit); 203185bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman#ifdef CONFIG_PNP 20329eeebd22ca757fee8dc10ffe6fa6992f33a3c5ecTomas Winklermodule_param_named(nopnp, param_nopnp, uint, 0444); 203385bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman#endif 20349eeebd22ca757fee8dc10ffe6fa6992f33a3c5ecTomas Winklermodule_param_named(io, param_io, uint, 0444); 20359eeebd22ca757fee8dc10ffe6fa6992f33a3c5ecTomas Winklermodule_param_named(irq, param_irq, uint, 0444); 20369eeebd22ca757fee8dc10ffe6fa6992f33a3c5ecTomas Winklermodule_param_named(dma, param_dma, int, 0444); 20371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL"); 203932710e8fd537adeb53f98dec92e4a77caac512f5Pierre OssmanMODULE_AUTHOR("Pierre Ossman <pierre@ossman.eu>"); 20401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION("Winbond W83L51xD SD/MMC card interface driver"); 20411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 204285bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman#ifdef CONFIG_PNP 204385bcc13072c54592596c5b41d40d1c6a18b04e19Pierre OssmanMODULE_PARM_DESC(nopnp, "Scan for device instead of relying on PNP. (default 0)"); 204485bcc13072c54592596c5b41d40d1c6a18b04e19Pierre Ossman#endif 20451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(io, "I/O base to allocate. Must be 8 byte aligned. (default 0x248)"); 20461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(irq, "IRQ to allocate. (default 6)"); 20471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(dma, "DMA channel to allocate. -1 for no DMA. (default 2)"); 2048