From: Linus Torvalds Date: Sun, 5 Apr 2009 17:18:21 +0000 (-0700) Subject: Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/drzeus/mmc X-Git-Url: http://www.pilppa.org/gitweb/gitweb.cgi?a=commitdiff_plain;h=0a053e8c71d666daf30da2d407147b1293923d8b;hp=-c;p=linux-2.6-omap-h63xx.git Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/drzeus/mmc * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/drzeus/mmc: (42 commits) atmel-mci: fix sdc_reg typo tmio_mmc: add maintainer mmc: Add OpenFirmware bindings for SDHCI driver sdhci: Add quirk for forcing maximum block size to 2048 bytes sdhci: Add quirk for controllers that need IRQ re-init after reset sdhci: Add quirk for controllers that need small delays for PIO sdhci: Add set_clock callback and a quirk for nonstandard clocks sdhci: Add get_{max,timeout}_clock callbacks sdhci: Add support for hosts reporting inverted write-protect state sdhci: Add support for card-detection polling sdhci: Enable only relevant (DMA/PIO) interrupts during transfers sdhci: Split card-detection IRQs management from sdhci_init() sdhci: Add support for bus-specific IO memory accessors mmc_spi: adjust for delayed data token response omap_hsmmc: Wait for SDBP omap_hsmmc: Fix MMC3 dma omap_hsmmc: Disable SDBP at suspend omap_hsmmc: Do not prefix slot name omap_hsmmc: Allow cover switch to cause rescan omap_hsmmc: Add 8-bit bus width mode support ... --- 0a053e8c71d666daf30da2d407147b1293923d8b diff --combined MAINTAINERS index 6360b9b9bbb,ef5522153f4..9e2eb319113 --- a/MAINTAINERS +++ b/MAINTAINERS @@@ -357,7 -357,6 +357,7 @@@ S: Odd Fixes for 2.4; Maintained for 2. P: Ivan Kokshaysky M: ink@jurassic.park.msu.ru S: Maintained for 2.4; PCI support for 2.6. +L: linux-alpha@vger.kernel.org AMD GEODE CS5536 USB DEVICE CONTROLLER DRIVER P: Thomas Dahlmann @@@ -503,13 -502,6 +503,13 @@@ P: Richard Purdi M: rpurdie@rpsys.net S: Maintained +ARM/CORTINA SYSTEMS GEMINI ARM ARCHITECTURE +P: Paulius Zaleckas +M: paulius.zaleckas@teltonika.lt +L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only) +T: git gitorious.org/linux-gemini/mainline.git +S: Maintained + ARM/EZX SMARTPHONES (A780, A910, A1200, E680, ROKR E2 and ROKR E6) P: Daniel Ribeiro M: drwyrm@gmail.com @@@ -521,12 -513,6 +521,12 @@@ L: openezx-devel@lists.openezx.org (sub W: http://www.openezx.org/ S: Maintained +ARM/FARADAY FA526 PORT +P: Paulius Zaleckas +M: paulius.zaleckas@teltonika.lt +L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only) +S: Maintained + ARM/FREESCALE IMX / MXC ARM ARCHITECTURE P: Sascha Hauer M: kernel@pengutronix.de @@@ -636,7 -622,7 +636,7 @@@ P: Dirk Opfe M: dirk@opfer-online.de S: Maintained -ARM/PALMTX SUPPORT +ARM/PALMTX,PALMT5,PALMLD SUPPORT P: Marek Vasut M: marek.vasut@gmail.com W: http://hackndev.com @@@ -779,14 -765,6 +779,14 @@@ L: linux-wireless@vger.kernel.or L: ath9k-devel@lists.ath9k.org S: Supported +ATHEROS AR9170 WIRELESS DRIVER +P: Christian Lamparter +M: chunkeey@web.de +L: linux-wireless@vger.kernel.org +W: http://wireless.kernel.org/en/users/Drivers/ar9170 +S: Maintained +F: drivers/net/wireless/ar9170/ + ATI_REMOTE2 DRIVER P: Ville Syrjala M: syrjala@sci.fi @@@ -1033,8 -1011,6 +1033,8 @@@ L: netdev@vger.kernel.or S: Supported BROADCOM TG3 GIGABIT ETHERNET DRIVER +P: Matt Carlson +M: mcarlson@broadcom.com P: Michael Chan M: mchan@broadcom.com L: netdev@vger.kernel.org @@@ -1064,6 -1040,7 +1064,6 @@@ BTTV VIDEO4LINUX DRIVE P: Mauro Carvalho Chehab M: mchehab@infradead.org L: linux-media@vger.kernel.org -L: video4linux-list@redhat.com W: http://linuxtv.org T: git kernel.org:/pub/scm/linux/kernel/git/mchehab/linux-2.6.git S: Maintained @@@ -1292,12 -1269,6 +1292,12 @@@ L: linux-crypto@vger.kernel.or T: git kernel.org:/pub/scm/linux/kernel/git/herbert/crypto-2.6.git S: Maintained +CRYPTOGRAPHIC RANDOM NUMBER GENERATOR +P: Neil Horman +M: nhorman@tuxdriver.com +L: linux-crypto@vger.kernel.org +S: Maintained + CS5535 Audio ALSA driver P: Jaya Kumar M: jayakumar.alsa@gmail.com @@@ -1763,12 -1734,6 +1763,12 @@@ M: viro@zeniv.linux.org.u L: linux-fsdevel@vger.kernel.org S: Maintained +FINTEK F75375S HARDWARE MONITOR AND FAN CONTROLLER DRIVER +P: Riku Voipio +M: riku.vipio@iki.fi +L: lm-sensors@lm-sensors.org +S: Maintained + FIREWIRE SUBSYSTEM (drivers/firewire, ) P: Kristian Hoegsberg, Stefan Richter M: krh@redhat.com, stefanr@s5r6.in-berlin.de @@@ -1951,12 -1916,6 +1951,12 @@@ L: lm-sensors@lm-sensors.or W: http://www.kernel.org/pub/linux/kernel/people/fseidel/hdaps/ S: Maintained +HYPERVISOR VIRTUAL CONSOLE DRIVER +L: linuxppc-dev@ozlabs.org +L: linux-kernel@vger.kernel.org +S: Odd Fixes +F: drivers/char/hvc_* + GSPCA FINEPIX SUBDRIVER P: Frank Zago M: frank@zago.net @@@ -2214,12 -2173,25 +2214,12 @@@ L: linux-ide@vger.kernel.or T: quilt kernel.org/pub/linux/kernel/people/bart/pata-2.6/ S: Maintained -IDE/ATAPI CDROM DRIVER +IDE/ATAPI DRIVERS P: Borislav Petkov M: petkovbb@gmail.com L: linux-ide@vger.kernel.org S: Maintained -IDE/ATAPI FLOPPY DRIVERS -P: Paul Bristow -M: Paul Bristow -W: http://paulbristow.net/linux/idefloppy.html -L: linux-kernel@vger.kernel.org -S: Maintained - -IDE/ATAPI TAPE DRIVERS -P: Gadi Oxman -M: Gadi Oxman -L: linux-kernel@vger.kernel.org -S: Maintained - IDLE-I7300 P: Andy Henroid M: andrew.d.henroid@intel.com @@@ -2244,11 -2216,6 +2244,11 @@@ M: stefanr@s5r6.in-berlin.d L: linux1394-devel@lists.sourceforge.net S: Maintained +INTEGRITY MEASUREMENT ARCHITECTURE (IMA) +P: Mimi Zohar +M: zohar@us.ibm.com +S: Supported + IMS TWINTURBO FRAMEBUFFER DRIVER L: linux-fbdev-devel@lists.sourceforge.net (moderated for non-subscribers) S: Orphan @@@ -2865,7 -2832,7 +2865,7 @@@ P: Roman Zippe M: zippel@linux-m68k.org L: linux-m68k@lists.linux-m68k.org W: http://www.linux-m68k.org/ -W: http://linux-m68k-cvs.ubb.ca/ +T: git git.kernel.org/pub/scm/linux/kernel/git/geert/linux-m68k.git S: Maintained M68K ON APPLE MACINTOSH @@@ -2924,6 -2891,12 +2924,12 @@@ M: buytenh@marvell.co L: netdev@vger.kernel.org S: Supported + MARVELL SOC MMC/SD/SDIO CONTROLLER DRIVER + P: Nicolas Pitre + M: nico@cam.org + L: linux-kernel@vger.kernel.org + S: Maintained + MARVELL YUKON / SYSKONNECT DRIVER P: Mirko Lindner M: mlindner@syskonnect.de @@@ -3110,7 -3083,7 +3116,7 @@@ M: shemminger@linux-foundation.or L: netem@lists.linux-foundation.org S: Maintained -NETERION (S2IO) Xframe 10GbE DRIVER +NETERION (S2IO) 10GbE DRIVER (xframe/vxge) P: Ramkrishna Vepa M: ram.vepa@neterion.com P: Rastapur Santosh @@@ -3119,11 -3092,8 +3125,11 @@@ P: Sivakumar Subraman M: sivakumar.subramani@neterion.com P: Sreenivasa Honnur M: sreenivasa.honnur@neterion.com +P: Anil Murthy +M: anil.murthy@neterion.com L: netdev@vger.kernel.org -W: http://trac.neterion.com/cgi-bin/trac.cgi/wiki/TitleIndex?anonymous +W: http://trac.neterion.com/cgi-bin/trac.cgi/wiki/Linux?Anonymous +W: http://trac.neterion.com/cgi-bin/trac.cgi/wiki/X3100Linux?Anonymous S: Supported NETFILTER/IPTABLES/IPCHAINS @@@ -3325,16 -3295,6 +3331,16 @@@ L: orinoco-devel@lists.sourceforge.ne W: http://www.nongnu.org/orinoco/ S: Maintained +OSD LIBRARY +P: Boaz Harrosh +M: bharrosh@panasas.com +P: Benny Halevy +M: bhalevy@panasas.com +L: osd-dev@open-osd.org +W: http://open-osd.org +T: git://git.open-osd.org/open-osd.git +S: Maintained + P54 WIRELESS DRIVER P: Michael Wu M: flamingice@sourmilk.net @@@ -3414,11 -3374,6 +3420,11 @@@ P: Jim Cromi M: jim.cromie@gmail.com S: Maintained +PCA9532 LED DRIVER +P: Riku Voipio +M: riku.voipio@iki.fi +S: Maintained + PCI ERROR RECOVERY P: Linas Vepstas M: linas@austin.ibm.com @@@ -3590,22 -3545,6 +3596,22 @@@ M: linux@arm.linux.org.u L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only) S: Maintained +PXA168 SUPPORT +P: Eric Miao +M: eric.miao@marvell.com +P: Jason Chagas +M: jason.chagas@marvell.com +L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only) +T: git kernel.org:/pub/scm/linux/kernel/git/ycmiao/pxa-linux-2.6.git +S: Supported + +PXA910 SUPPORT +P: Eric Miao +M: eric.miao@marvell.com +L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only) +T: git kernel.org:/pub/scm/linux/kernel/git/ycmiao/pxa-linux-2.6.git +S: Supported + PXA MMCI DRIVER S: Orphan @@@ -3656,7 -3595,7 +3662,7 @@@ S: Maintaine RALINK RT2X00 WIRELESS LAN DRIVER P: rt2x00 project L: linux-wireless@vger.kernel.org -L: rt2400-devel@lists.sourceforge.net +L: users@rt2x00.serialmonkey.com W: http://rt2x00.serialmonkey.com/ S: Maintained T: git kernel.org:/pub/scm/linux/kernel/git/ivd/rt2x00.git @@@ -3702,12 -3641,6 +3708,12 @@@ M: florian.fainelli@telecomint.e L: netdev@vger.kernel.org S: Maintained +RDS - RELIABLE DATAGRAM SOCKETS +P: Andy Grover +M: andy.grover@oracle.com +L: rds-devel@oss.oracle.com +S: Supported + READ-COPY UPDATE (RCU) P: Dipankar Sarma M: dipankar@in.ibm.com @@@ -3799,15 -3732,6 +3805,15 @@@ L: linux-s390@vger.kernel.or W: http://www.ibm.com/developerworks/linux/linux390/ S: Supported +S390 ZCRYPT DRIVER +P: Felix Beck +M: felix.beck@de.ibm.com +P: Ralph Wuerthner +M: ralph.wuerthner@de.ibm.com +M: linux390@de.ibm.com +L: linux-s390@vger.kernel.org +S: Supported + S390 ZFCP DRIVER P: Christof Schmitt M: christof.schmitt@de.ibm.com @@@ -3916,7 -3840,14 +3922,14 @@@ S: Maintaine SECURE DIGITAL HOST CONTROLLER INTERFACE (SDHCI) DRIVER P: Pierre Ossman M: drzeus-sdhci@drzeus.cx - L: sdhci-devel@list.drzeus.cx + L: sdhci-devel@lists.ossman.eu + S: Maintained + + SECURE DIGITAL HOST CONTROLLER INTERFACE, OPEN FIRMWARE BINDINGS (SDHCI-OF) + P: Anton Vorontsov + M: avorontsov@ru.mvista.com + L: linuxppc-dev@ozlabs.org + L: sdhci-devel@lists.ossman.eu S: Maintained SECURITY SUBSYSTEM @@@ -3926,7 -3857,6 +3939,7 @@@ M: jmorris@namei.or L: linux-kernel@vger.kernel.org L: linux-security-module@vger.kernel.org (suggested Cc:) T: git kernel.org:pub/scm/linux/kernel/git/jmorris/security-testing-2.6.git +W: http://security.wiki.kernel.org/ S: Supported SECURITY CONTACT @@@ -4368,19 -4298,6 +4381,19 @@@ L: tlan-devel@lists.sourceforge.net (su W: http://sourceforge.net/projects/tlan/ S: Maintained +TOMOYO SECURITY MODULE +P: Kentaro Takeda +M: takedakn@nttdata.co.jp +P: Tetsuo Handa +M: penguin-kernel@I-love.SAKURA.ne.jp +L: linux-kernel@vger.kernel.org (kernel issues) +L: tomoyo-users-en@lists.sourceforge.jp (subscribers-only, for developers and users in English) +L: tomoyo-dev@lists.sourceforge.jp (subscribers-only, for developers in Japanese) +L: tomoyo-users@lists.sourceforge.jp (subscribers-only, for users in Japanese) +W: http://tomoyo.sourceforge.jp/ +T: quilt http://svn.sourceforge.jp/svnroot/tomoyo/trunk/2.2.x/tomoyo-lsm/patches/ +S: Maintained + TOSHIBA ACPI EXTRAS DRIVER P: John Belmonte M: toshiba_acpi@memebeam.org @@@ -4394,6 -4311,11 +4407,11 @@@ L: tlinux-users@tce.toshiba-dme.co.j W: http://www.buzzard.org.uk/toshiba/ S: Maintained + TMIO MMC DRIVER + P: Ian Molton + M: ian@mnementh.co.uk + S: Maintained + TPM DEVICE DRIVER P: Debora Velarde M: debora@linux.vnet.ibm.com @@@ -4842,6 -4764,7 +4860,6 @@@ VIDEO FOR LINUX (V4L P: Mauro Carvalho Chehab M: mchehab@infradead.org L: linux-media@vger.kernel.org -L: video4linux-list@redhat.com W: http://linuxtv.org T: git kernel.org:/pub/scm/linux/kernel/git/mchehab/linux-2.6.git S: Maintained @@@ -4858,7 -4781,7 +4876,7 @@@ M: lrg@slimlogic.co.u P: Mark Brown M: broonie@opensource.wolfsonmicro.com W: http://opensource.wolfsonmicro.com/node/15 -W: http://www.slimlogic.co.uk/?page_id=5 +W: http://www.slimlogic.co.uk/?p=48 T: git kernel.org/pub/scm/linux/kernel/git/lrg/voltage-2.6.git S: Supported @@@ -4980,8 -4903,7 +4998,8 @@@ S: Supporte XFS FILESYSTEM P: Silicon Graphics Inc -P: Bill O'Donnell +P: Felix Blyakher +M: felixb@sgi.com M: xfs-masters@oss.sgi.com L: xfs@oss.sgi.com W: http://oss.sgi.com/projects/xfs diff --combined drivers/mmc/core/core.c index 1445ea8f10a,5c83c67b186..fa073ab3fa3 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@@ -21,7 -21,6 +21,7 @@@ #include #include #include +#include #include #include @@@ -298,6 -297,21 +298,21 @@@ void mmc_set_data_timeout(struct mmc_da data->timeout_clks = 0; } } + /* + * Some cards need very high timeouts if driven in SPI mode. + * The worst observed timeout was 900ms after writing a + * continuous stream of data until the internal logic + * overflowed. + */ + if (mmc_host_is_spi(card->host)) { + if (data->flags & MMC_DATA_WRITE) { + if (data->timeout_ns < 1000000000) + data->timeout_ns = 1000000000; /* 1s */ + } else { + if (data->timeout_ns < 100000000) + data->timeout_ns = 100000000; /* 100ms */ + } + } } EXPORT_SYMBOL(mmc_set_data_timeout); @@@ -524,105 -538,6 +539,105 @@@ u32 mmc_vddrange_to_ocrmask(int vdd_min } EXPORT_SYMBOL(mmc_vddrange_to_ocrmask); +#ifdef CONFIG_REGULATOR + +/** + * mmc_regulator_get_ocrmask - return mask of supported voltages + * @supply: regulator to use + * + * This returns either a negative errno, or a mask of voltages that + * can be provided to MMC/SD/SDIO devices using the specified voltage + * regulator. This would normally be called before registering the + * MMC host adapter. + */ +int mmc_regulator_get_ocrmask(struct regulator *supply) +{ + int result = 0; + int count; + int i; + + count = regulator_count_voltages(supply); + if (count < 0) + return count; + + for (i = 0; i < count; i++) { + int vdd_uV; + int vdd_mV; + + vdd_uV = regulator_list_voltage(supply, i); + if (vdd_uV <= 0) + continue; + + vdd_mV = vdd_uV / 1000; + result |= mmc_vddrange_to_ocrmask(vdd_mV, vdd_mV); + } + + return result; +} +EXPORT_SYMBOL(mmc_regulator_get_ocrmask); + +/** + * mmc_regulator_set_ocr - set regulator to match host->ios voltage + * @vdd_bit: zero for power off, else a bit number (host->ios.vdd) + * @supply: regulator to use + * + * Returns zero on success, else negative errno. + * + * MMC host drivers may use this to enable or disable a regulator using + * a particular supply voltage. This would normally be called from the + * set_ios() method. + */ +int mmc_regulator_set_ocr(struct regulator *supply, unsigned short vdd_bit) +{ + int result = 0; + int min_uV, max_uV; + int enabled; + + enabled = regulator_is_enabled(supply); + if (enabled < 0) + return enabled; + + if (vdd_bit) { + int tmp; + int voltage; + + /* REVISIT mmc_vddrange_to_ocrmask() may have set some + * bits this regulator doesn't quite support ... don't + * be too picky, most cards and regulators are OK with + * a 0.1V range goof (it's a small error percentage). + */ + tmp = vdd_bit - ilog2(MMC_VDD_165_195); + if (tmp == 0) { + min_uV = 1650 * 1000; + max_uV = 1950 * 1000; + } else { + min_uV = 1900 * 1000 + tmp * 100 * 1000; + max_uV = min_uV + 100 * 1000; + } + + /* avoid needless changes to this voltage; the regulator + * might not allow this operation + */ + voltage = regulator_get_voltage(supply); + if (voltage < 0) + result = voltage; + else if (voltage < min_uV || voltage > max_uV) + result = regulator_set_voltage(supply, min_uV, max_uV); + else + result = 0; + + if (result == 0 && !enabled) + result = regulator_enable(supply); + } else if (enabled) { + result = regulator_disable(supply); + } + + return result; +} +EXPORT_SYMBOL(mmc_regulator_set_ocr); + +#endif + /* * Mask off any voltages we don't support and select * the lowest voltage @@@ -915,6 -830,7 +930,7 @@@ void mmc_stop_host(struct mmc_host *hos spin_unlock_irqrestore(&host->lock, flags); #endif + cancel_delayed_work(&host->detect); mmc_flush_scheduled_work(); mmc_bus_get(host); @@@ -942,6 -858,7 +958,7 @@@ */ int mmc_suspend_host(struct mmc_host *host, pm_message_t state) { + cancel_delayed_work(&host->detect); mmc_flush_scheduled_work(); mmc_bus_get(host); @@@ -975,6 -892,7 +992,7 @@@ int mmc_resume_host(struct mmc_host *ho mmc_bus_get(host); if (host->bus_ops && !host->bus_dead) { mmc_power_up(host); + mmc_select_voltage(host, host->ocr); BUG_ON(!host->bus_ops->resume); host->bus_ops->resume(host); } diff --combined drivers/mmc/host/Kconfig index 6fbb246c40b,126a0da095e..b4cf691f3f6 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@@ -37,6 -37,13 +37,13 @@@ config MMC_SDHC If unsure, say N. + config MMC_SDHCI_IO_ACCESSORS + bool + depends on MMC_SDHCI + help + This is silent Kconfig symbol that is selected by the drivers that + need to overwrite SDHCI IO memory accessors. + config MMC_SDHCI_PCI tristate "SDHCI support on PCI bus" depends on MMC_SDHCI && PCI @@@ -65,6 -72,17 +72,17 @@@ config MMC_RICOH_MM If unsure, say Y. + config MMC_SDHCI_OF + tristate "SDHCI support on OpenFirmware platforms" + depends on MMC_SDHCI && PPC_OF + select MMC_SDHCI_IO_ACCESSORS + help + This selects the OF support for Secure Digital Host Controller + Interfaces. So far, only the Freescale eSDHC controller is known + to exist on OF platforms. + + If unsure, say N. + config MMC_OMAP tristate "TI OMAP Multimedia Card Interface support" depends on ARCH_OMAP @@@ -171,13 -189,24 +189,24 @@@ config MMC_TIFM_S To compile this driver as a module, choose M here: the module will be called tifm_sd. + config MMC_MVSDIO + tristate "Marvell MMC/SD/SDIO host driver" + depends on PLAT_ORION + ---help--- + This selects the Marvell SDIO host driver. + SDIO may currently be found on the Kirkwood 88F6281 and 88F6192 + SoC controllers. + + To compile this driver as a module, choose M here: the + module will be called mvsdio. + config MMC_SPI tristate "MMC/SD/SDIO over SPI" depends on SPI_MASTER && !HIGHMEM && HAS_DMA select CRC7 select CRC_ITU_T help - Some systems accss MMC/SD/SDIO cards using a SPI controller + Some systems access MMC/SD/SDIO cards using a SPI controller instead of using a "native" MMC/SD/SDIO controller. This has a disadvantage of being relatively high overhead, but a compensating advantage of working on many systems without dedicated MMC/SD/SDIO diff --combined drivers/mmc/host/omap_hsmmc.c index 3916a5618e2,488f222054f..d183be6f2a5 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@@ -56,6 -56,7 +56,7 @@@ #define SDVS18 (0x5 << 9) #define SDVS30 (0x6 << 9) #define SDVS33 (0x7 << 9) + #define SDVS_MASK 0x00000E00 #define SDVSCLR 0xFFFFF1FF #define SDVSDET 0x00000400 #define AUTOIDLE 0x1 @@@ -76,6 -77,7 +77,7 @@@ #define MSBS (1 << 5) #define BCE (1 << 1) #define FOUR_BIT (1 << 1) + #define DW8 (1 << 5) #define CC 0x1 #define TC 0x02 #define OD 0x1 @@@ -98,10 -100,8 +100,8 @@@ */ #define OMAP_MMC1_DEVID 0 #define OMAP_MMC2_DEVID 1 + #define OMAP_MMC3_DEVID 2 - #define OMAP_MMC_DATADIR_NONE 0 - #define OMAP_MMC_DATADIR_READ 1 - #define OMAP_MMC_DATADIR_WRITE 2 #define MMC_TIMEOUT_MS 20 #define OMAP_MMC_MASTER_CLOCK 96000000 #define DRIVER_NAME "mmci-omap-hs" @@@ -137,18 -137,18 +137,18 @@@ struct mmc_omap_host resource_size_t mapbase; unsigned int id; unsigned int dma_len; - unsigned int dma_dir; + unsigned int dma_sg_idx; unsigned char bus_mode; - unsigned char datadir; u32 *buffer; u32 bytesleft; int suspended; int irq; int carddetect; int use_dma, dma_ch; - int initstr; + int dma_line_tx, dma_line_rx; int slot_id; int dbclk_enabled; + int response_busy; struct omap_mmc_platform_data *pdata; }; @@@ -218,7 -218,7 +218,7 @@@ mmc_omap_show_slot_name(struct device * struct mmc_omap_host *host = mmc_priv(mmc); struct omap_mmc_slot_data slot = host->pdata->slots[host->slot_id]; - return sprintf(buf, "slot:%s\n", slot.name); + return sprintf(buf, "%s\n", slot.name); } static DEVICE_ATTR(slot_name, S_IRUGO, mmc_omap_show_slot_name, NULL); @@@ -243,10 -243,14 +243,14 @@@ mmc_omap_start_command(struct mmc_omap_ OMAP_HSMMC_WRITE(host->base, ISE, INT_EN_MASK); OMAP_HSMMC_WRITE(host->base, IE, INT_EN_MASK); + host->response_busy = 0; if (cmd->flags & MMC_RSP_PRESENT) { if (cmd->flags & MMC_RSP_136) resptype = 1; - else + else if (cmd->flags & MMC_RSP_BUSY) { + resptype = 3; + host->response_busy = 1; + } else resptype = 2; } @@@ -275,19 -279,35 +279,35 @@@ OMAP_HSMMC_WRITE(host->base, CMD, cmdreg); } + static int + mmc_omap_get_dma_dir(struct mmc_omap_host *host, struct mmc_data *data) + { + if (data->flags & MMC_DATA_WRITE) + return DMA_TO_DEVICE; + else + return DMA_FROM_DEVICE; + } + /* * Notify the transfer complete to MMC core */ static void mmc_omap_xfer_done(struct mmc_omap_host *host, struct mmc_data *data) { + if (!data) { + struct mmc_request *mrq = host->mrq; + + host->mrq = NULL; + mmc_omap_fclk_lazy_disable(host); + mmc_request_done(host->mmc, mrq); + return; + } + host->data = NULL; if (host->use_dma && host->dma_ch != -1) dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->dma_len, - host->dma_dir); - - host->datadir = OMAP_MMC_DATADIR_NONE; + mmc_omap_get_dma_dir(host, data)); if (!data->error) data->bytes_xfered += data->blocks * (data->blksz); @@@ -322,7 -342,7 +342,7 @@@ mmc_omap_cmd_done(struct mmc_omap_host cmd->resp[0] = OMAP_HSMMC_READ(host->base, RSP10); } } - if (host->data == NULL || cmd->error) { + if ((host->data == NULL && !host->response_busy) || cmd->error) { host->mrq = NULL; mmc_request_done(host->mmc, cmd->mrq); } @@@ -331,19 -351,18 +351,18 @@@ /* * DMA clean up for command errors */ - static void mmc_dma_cleanup(struct mmc_omap_host *host) + static void mmc_dma_cleanup(struct mmc_omap_host *host, int errno) { - host->data->error = -ETIMEDOUT; + host->data->error = errno; if (host->use_dma && host->dma_ch != -1) { dma_unmap_sg(mmc_dev(host->mmc), host->data->sg, host->dma_len, - host->dma_dir); + mmc_omap_get_dma_dir(host, host->data)); omap_free_dma(host->dma_ch); host->dma_ch = -1; up(&host->sem); } host->data = NULL; - host->datadir = OMAP_MMC_DATADIR_NONE; } /* @@@ -412,7 -431,7 +431,7 @@@ static irqreturn_t mmc_omap_irq(int irq struct mmc_data *data; int end_cmd = 0, end_trans = 0, status; - if (host->cmd == NULL && host->data == NULL) { + if (host->mrq == NULL) { OMAP_HSMMC_WRITE(host->base, STAT, OMAP_HSMMC_READ(host->base, STAT)); return IRQ_HANDLED; @@@ -437,18 -456,24 +456,24 @@@ } end_cmd = 1; } - if (host->data) { - mmc_dma_cleanup(host); + if (host->data || host->response_busy) { + if (host->data) + mmc_dma_cleanup(host, -ETIMEDOUT); + host->response_busy = 0; mmc_omap_reset_controller_fsm(host, SRD); } } if ((status & DATA_TIMEOUT) || (status & DATA_CRC)) { - if (host->data) { - if (status & DATA_TIMEOUT) - mmc_dma_cleanup(host); + if (host->data || host->response_busy) { + int err = (status & DATA_TIMEOUT) ? + -ETIMEDOUT : -EILSEQ; + + if (host->data) + mmc_dma_cleanup(host, err); else - host->data->error = -EILSEQ; + host->mrq->cmd->error = err; + host->response_busy = 0; mmc_omap_reset_controller_fsm(host, SRD); end_trans = 1; } @@@ -473,6 -498,19 +498,19 @@@ return IRQ_HANDLED; } + static void set_sd_bus_power(struct mmc_omap_host *host) + { + unsigned long i; + + OMAP_HSMMC_WRITE(host->base, HCTL, + OMAP_HSMMC_READ(host->base, HCTL) | SDBP); + for (i = 0; i < loops_per_jiffy; i++) { + if (OMAP_HSMMC_READ(host->base, HCTL) & SDBP) + break; + cpu_relax(); + } + } + /* * Switch MMC interface voltage ... only relevant for MMC1. * @@@ -485,9 -523,6 +523,6 @@@ static int omap_mmc_switch_opcond(struc u32 reg_val = 0; int ret; - if (host->id != OMAP_MMC1_DEVID) - return 0; - /* Disable the clocks */ clk_disable(host->fclk); clk_disable(host->iclk); @@@ -532,9 -567,7 +567,7 @@@ reg_val |= SDVS30; OMAP_HSMMC_WRITE(host->base, HCTL, reg_val); - - OMAP_HSMMC_WRITE(host->base, HCTL, - OMAP_HSMMC_READ(host->base, HCTL) | SDBP); + set_sd_bus_power(host); return 0; err: @@@ -551,7 -584,10 +584,10 @@@ static void mmc_omap_detect(struct work mmc_carddetect_work); struct omap_mmc_slot_data *slot = &mmc_slot(host); - host->carddetect = slot->card_detect(slot->card_detect_irq); + if (mmc_slot(host).card_detect) + host->carddetect = slot->card_detect(slot->card_detect_irq); + else + host->carddetect = -ENOSYS; sysfs_notify(&host->mmc->class_dev.kobj, NULL, "cover_switch"); if (host->carddetect) { @@@ -574,6 -610,48 +610,48 @@@ static irqreturn_t omap_mmc_cd_handler( return IRQ_HANDLED; } + static int mmc_omap_get_dma_sync_dev(struct mmc_omap_host *host, + struct mmc_data *data) + { + int sync_dev; + + if (data->flags & MMC_DATA_WRITE) + sync_dev = host->dma_line_tx; + else + sync_dev = host->dma_line_rx; + return sync_dev; + } + + static void mmc_omap_config_dma_params(struct mmc_omap_host *host, + struct mmc_data *data, + struct scatterlist *sgl) + { + int blksz, nblk, dma_ch; + + dma_ch = host->dma_ch; + if (data->flags & MMC_DATA_WRITE) { + omap_set_dma_dest_params(dma_ch, 0, OMAP_DMA_AMODE_CONSTANT, + (host->mapbase + OMAP_HSMMC_DATA), 0, 0); + omap_set_dma_src_params(dma_ch, 0, OMAP_DMA_AMODE_POST_INC, + sg_dma_address(sgl), 0, 0); + } else { + omap_set_dma_src_params(dma_ch, 0, OMAP_DMA_AMODE_CONSTANT, + (host->mapbase + OMAP_HSMMC_DATA), 0, 0); + omap_set_dma_dest_params(dma_ch, 0, OMAP_DMA_AMODE_POST_INC, + sg_dma_address(sgl), 0, 0); + } + + blksz = host->data->blksz; + nblk = sg_dma_len(sgl) / blksz; + + omap_set_dma_transfer_params(dma_ch, OMAP_DMA_DATA_TYPE_S32, + blksz / 4, nblk, OMAP_DMA_SYNC_FRAME, + mmc_omap_get_dma_sync_dev(host, data), + !(data->flags & MMC_DATA_WRITE)); + + omap_start_dma(dma_ch); + } + /* * DMA call back function */ @@@ -587,6 -665,14 +665,14 @@@ static void mmc_omap_dma_cb(int lch, u1 if (host->dma_ch < 0) return; + host->dma_sg_idx++; + if (host->dma_sg_idx < host->dma_len) { + /* Fire up the next transfer. */ + mmc_omap_config_dma_params(host, host->data, + host->data->sg + host->dma_sg_idx); + return; + } + omap_free_dma(host->dma_ch); host->dma_ch = -1; /* @@@ -596,39 -682,29 +682,29 @@@ up(&host->sem); } - /* - * Configure dma src and destination parameters - */ - static int mmc_omap_config_dma_param(int sync_dir, struct mmc_omap_host *host, - struct mmc_data *data) - { - if (sync_dir == 0) { - omap_set_dma_dest_params(host->dma_ch, 0, - OMAP_DMA_AMODE_CONSTANT, - (host->mapbase + OMAP_HSMMC_DATA), 0, 0); - omap_set_dma_src_params(host->dma_ch, 0, - OMAP_DMA_AMODE_POST_INC, - sg_dma_address(&data->sg[0]), 0, 0); - } else { - omap_set_dma_src_params(host->dma_ch, 0, - OMAP_DMA_AMODE_CONSTANT, - (host->mapbase + OMAP_HSMMC_DATA), 0, 0); - omap_set_dma_dest_params(host->dma_ch, 0, - OMAP_DMA_AMODE_POST_INC, - sg_dma_address(&data->sg[0]), 0, 0); - } - return 0; - } /* * Routine to configure and start DMA for the MMC card */ static int mmc_omap_start_dma_transfer(struct mmc_omap_host *host, struct mmc_request *req) { - int sync_dev, sync_dir = 0; - int dma_ch = 0, ret = 0, err = 1; + int dma_ch = 0, ret = 0, err = 1, i; struct mmc_data *data = req->data; + /* Sanity check: all the SG entries must be aligned by block size. */ + for (i = 0; i < host->dma_len; i++) { + struct scatterlist *sgl; + + sgl = data->sg + i; + if (sgl->length % data->blksz) + return -EINVAL; + } + if ((data->blksz % 4) != 0) + /* REVISIT: The MMC buffer increments only when MSB is written. + * Return error for blksz which is non multiple of four. + */ + return -EINVAL; + /* * If for some reason the DMA transfer is still active, * we wait for timeout period and free the dma @@@ -647,49 -723,22 +723,22 @@@ return err; } - if (!(data->flags & MMC_DATA_WRITE)) { - host->dma_dir = DMA_FROM_DEVICE; - if (host->id == OMAP_MMC1_DEVID) - sync_dev = OMAP24XX_DMA_MMC1_RX; - else - sync_dev = OMAP24XX_DMA_MMC2_RX; - } else { - host->dma_dir = DMA_TO_DEVICE; - if (host->id == OMAP_MMC1_DEVID) - sync_dev = OMAP24XX_DMA_MMC1_TX; - else - sync_dev = OMAP24XX_DMA_MMC2_TX; - } - - ret = omap_request_dma(sync_dev, "MMC/SD", mmc_omap_dma_cb, - host, &dma_ch); + ret = omap_request_dma(mmc_omap_get_dma_sync_dev(host, data), "MMC/SD", + mmc_omap_dma_cb,host, &dma_ch); if (ret != 0) { - dev_dbg(mmc_dev(host->mmc), + dev_err(mmc_dev(host->mmc), "%s: omap_request_dma() failed with %d\n", mmc_hostname(host->mmc), ret); return ret; } host->dma_len = dma_map_sg(mmc_dev(host->mmc), data->sg, - data->sg_len, host->dma_dir); + data->sg_len, mmc_omap_get_dma_dir(host, data)); host->dma_ch = dma_ch; + host->dma_sg_idx = 0; - if (!(data->flags & MMC_DATA_WRITE)) - mmc_omap_config_dma_param(1, host, data); - else - mmc_omap_config_dma_param(0, host, data); - - if ((data->blksz % 4) == 0) - omap_set_dma_transfer_params(dma_ch, OMAP_DMA_DATA_TYPE_S32, - (data->blksz / 4), data->blocks, OMAP_DMA_SYNC_FRAME, - sync_dev, sync_dir); - else - /* REVISIT: The MMC buffer increments only when MSB is written. - * Return error for blksz which is non multiple of four. - */ - return -EINVAL; + mmc_omap_config_dma_params(host, data, data->sg); - omap_start_dma(dma_ch); return 0; } @@@ -739,7 -788,6 +788,6 @@@ mmc_omap_prepare_data(struct mmc_omap_h host->data = req->data; if (req->data == NULL) { - host->datadir = OMAP_MMC_DATADIR_NONE; OMAP_HSMMC_WRITE(host->base, BLK, 0); return 0; } @@@ -748,9 -796,6 +796,6 @@@ | (req->data->blocks << 16)); set_data_timeout(host, req); - host->datadir = (req->data->flags & MMC_DATA_WRITE) ? - OMAP_MMC_DATADIR_WRITE : OMAP_MMC_DATADIR_READ; - if (host->use_dma) { ret = mmc_omap_start_dma_transfer(host, req); if (ret != 0) { @@@ -782,36 -827,29 +827,29 @@@ static void omap_mmc_set_ios(struct mmc u16 dsor = 0; unsigned long regval; unsigned long timeout; + u32 con; switch (ios->power_mode) { case MMC_POWER_OFF: mmc_slot(host).set_power(host->dev, host->slot_id, 0, 0); - /* - * Reset interface voltage to 3V if it's 1.8V now; - * only relevant on MMC-1, the others always use 1.8V. - * - * REVISIT: If we are able to detect cards after unplugging - * a 1.8V card, this code should not be needed. - */ - if (host->id != OMAP_MMC1_DEVID) - break; - if (!(OMAP_HSMMC_READ(host->base, HCTL) & SDVSDET)) { - int vdd = fls(host->mmc->ocr_avail) - 1; - if (omap_mmc_switch_opcond(host, vdd) != 0) - host->mmc->ios.vdd = vdd; - } break; case MMC_POWER_UP: mmc_slot(host).set_power(host->dev, host->slot_id, 1, ios->vdd); break; } + con = OMAP_HSMMC_READ(host->base, CON); switch (mmc->ios.bus_width) { + case MMC_BUS_WIDTH_8: + OMAP_HSMMC_WRITE(host->base, CON, con | DW8); + break; case MMC_BUS_WIDTH_4: + OMAP_HSMMC_WRITE(host->base, CON, con & ~DW8); OMAP_HSMMC_WRITE(host->base, HCTL, OMAP_HSMMC_READ(host->base, HCTL) | FOUR_BIT); break; case MMC_BUS_WIDTH_1: + OMAP_HSMMC_WRITE(host->base, CON, con & ~DW8); OMAP_HSMMC_WRITE(host->base, HCTL, OMAP_HSMMC_READ(host->base, HCTL) & ~FOUR_BIT); break; @@@ -891,6 -929,33 +929,33 @@@ static int omap_hsmmc_get_ro(struct mmc return pdata->slots[0].get_ro(host->dev, 0); } + static void omap_hsmmc_init(struct mmc_omap_host *host) + { + u32 hctl, capa, value; + + /* Only MMC1 supports 3.0V */ + if (host->id == OMAP_MMC1_DEVID) { + hctl = SDVS30; + capa = VS30 | VS18; + } else { + hctl = SDVS18; + capa = VS18; + } + + value = OMAP_HSMMC_READ(host->base, HCTL) & ~SDVS_MASK; + OMAP_HSMMC_WRITE(host->base, HCTL, value | hctl); + + value = OMAP_HSMMC_READ(host->base, CAPA); + OMAP_HSMMC_WRITE(host->base, CAPA, value | capa); + + /* Set the controller to AUTO IDLE mode */ + value = OMAP_HSMMC_READ(host->base, SYSCONFIG); + OMAP_HSMMC_WRITE(host->base, SYSCONFIG, value | AUTOIDLE); + + /* Set SD bus power bit */ + set_sd_bus_power(host); + } + static struct mmc_host_ops mmc_omap_ops = { .request = omap_mmc_request, .set_ios = omap_mmc_set_ios, @@@ -906,7 -971,6 +971,6 @@@ static int __init omap_mmc_probe(struc struct mmc_omap_host *host = NULL; struct resource *res; int ret = 0, irq; - u32 hctl, capa; if (pdata == NULL) { dev_err(&pdev->dev, "Platform Data is missing\n"); @@@ -956,13 -1020,13 +1020,13 @@@ sema_init(&host->sem, 1); - host->iclk = clk_get(&pdev->dev, "mmchs_ick"); + host->iclk = clk_get(&pdev->dev, "ick"); if (IS_ERR(host->iclk)) { ret = PTR_ERR(host->iclk); host->iclk = NULL; goto err1; } - host->fclk = clk_get(&pdev->dev, "mmchs_fck"); + host->fclk = clk_get(&pdev->dev, "fck"); if (IS_ERR(host->fclk)) { ret = PTR_ERR(host->fclk); host->fclk = NULL; @@@ -996,10 -1060,11 +1060,11 @@@ else host->dbclk_enabled = 1; - #ifdef CONFIG_MMC_BLOCK_BOUNCE - mmc->max_phys_segs = 1; - mmc->max_hw_segs = 1; - #endif + /* Since we do only SG emulation, we can have as many segs + * as we want. */ + mmc->max_phys_segs = 1024; + mmc->max_hw_segs = 1024; + mmc->max_blk_size = 512; /* Block Length at max can be 1024 */ mmc->max_blk_count = 0xFFFF; /* No. of Blocks is 16 bits */ mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count; @@@ -1008,31 -1073,31 +1073,31 @@@ mmc->ocr_avail = mmc_slot(host).ocr_mask; mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED; - if (pdata->slots[host->slot_id].wires >= 4) + if (pdata->slots[host->slot_id].wires >= 8) + mmc->caps |= MMC_CAP_8_BIT_DATA; + else if (pdata->slots[host->slot_id].wires >= 4) mmc->caps |= MMC_CAP_4_BIT_DATA; - /* Only MMC1 supports 3.0V */ - if (host->id == OMAP_MMC1_DEVID) { - hctl = SDVS30; - capa = VS30 | VS18; - } else { - hctl = SDVS18; - capa = VS18; - } - - OMAP_HSMMC_WRITE(host->base, HCTL, - OMAP_HSMMC_READ(host->base, HCTL) | hctl); - - OMAP_HSMMC_WRITE(host->base, CAPA, - OMAP_HSMMC_READ(host->base, CAPA) | capa); - - /* Set the controller to AUTO IDLE mode */ - OMAP_HSMMC_WRITE(host->base, SYSCONFIG, - OMAP_HSMMC_READ(host->base, SYSCONFIG) | AUTOIDLE); + omap_hsmmc_init(host); - /* Set SD bus power bit */ - OMAP_HSMMC_WRITE(host->base, HCTL, - OMAP_HSMMC_READ(host->base, HCTL) | SDBP); + /* Select DMA lines */ + switch (host->id) { + case OMAP_MMC1_DEVID: + host->dma_line_tx = OMAP24XX_DMA_MMC1_TX; + host->dma_line_rx = OMAP24XX_DMA_MMC1_RX; + break; + case OMAP_MMC2_DEVID: + host->dma_line_tx = OMAP24XX_DMA_MMC2_TX; + host->dma_line_rx = OMAP24XX_DMA_MMC2_RX; + break; + case OMAP_MMC3_DEVID: + host->dma_line_tx = OMAP34XX_DMA_MMC3_TX; + host->dma_line_rx = OMAP34XX_DMA_MMC3_RX; + break; + default: + dev_err(mmc_dev(host->mmc), "Invalid MMC id\n"); + goto err_irq; + } /* Request IRQ for MMC operations */ ret = request_irq(host->irq, mmc_omap_irq, IRQF_DISABLED, @@@ -1051,7 -1116,7 +1116,7 @@@ } /* Request IRQ for card detect */ - if ((mmc_slot(host).card_detect_irq) && (mmc_slot(host).card_detect)) { + if ((mmc_slot(host).card_detect_irq)) { ret = request_irq(mmc_slot(host).card_detect_irq, omap_mmc_cd_handler, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING @@@ -1074,8 -1139,8 +1139,8 @@@ if (ret < 0) goto err_slot_name; } - if (mmc_slot(host).card_detect_irq && mmc_slot(host).card_detect && - host->pdata->slots[host->slot_id].get_cover_state) { + if (mmc_slot(host).card_detect_irq && + host->pdata->slots[host->slot_id].get_cover_state) { ret = device_create_file(&mmc->class_dev, &dev_attr_cover_switch); if (ret < 0) @@@ -1173,20 -1238,8 +1238,8 @@@ static int omap_mmc_suspend(struct plat " level suspend\n"); } - if (host->id == OMAP_MMC1_DEVID - && !(OMAP_HSMMC_READ(host->base, HCTL) - & SDVSDET)) { - OMAP_HSMMC_WRITE(host->base, HCTL, - OMAP_HSMMC_READ(host->base, HCTL) - & SDVSCLR); - OMAP_HSMMC_WRITE(host->base, HCTL, - OMAP_HSMMC_READ(host->base, HCTL) - | SDVS30); - OMAP_HSMMC_WRITE(host->base, HCTL, - OMAP_HSMMC_READ(host->base, HCTL) - | SDBP); - } - + OMAP_HSMMC_WRITE(host->base, HCTL, + OMAP_HSMMC_READ(host->base, HCTL) & ~SDBP); clk_disable(host->fclk); clk_disable(host->iclk); clk_disable(host->dbclk); @@@ -1222,6 -1275,8 +1275,8 @@@ static int omap_mmc_resume(struct platf dev_dbg(mmc_dev(host->mmc), "Enabling debounce clk failed\n"); + omap_hsmmc_init(host); + if (host->pdata->resume) { ret = host->pdata->resume(&pdev->dev, host->slot_id); if (ret)