diff options
Diffstat (limited to 'ANDROID_3.4.5/drivers/mmc/host')
68 files changed, 0 insertions, 58102 deletions
diff --git a/ANDROID_3.4.5/drivers/mmc/host/Kconfig b/ANDROID_3.4.5/drivers/mmc/host/Kconfig deleted file mode 100644 index e7b73ea5..00000000 --- a/ANDROID_3.4.5/drivers/mmc/host/Kconfig +++ /dev/null @@ -1,646 +0,0 @@ -# -# MMC/SD host controller drivers -# - -comment "MMC/SD/SDIO Host Controller Drivers" - -config MMC_ARMMMCI - tristate "ARM AMBA Multimedia Card Interface support" - depends on ARM_AMBA - help - This selects the ARM(R) AMBA(R) PrimeCell Multimedia Card - Interface (PL180 and PL181) support. If you have an ARM(R) - platform with a Multimedia Card slot, say Y or M here. - - If unsure, say N. - -config MMC_PXA - tristate "Intel PXA25x/26x/27x Multimedia Card Interface support" - depends on ARCH_PXA - help - This selects the Intel(R) PXA(R) Multimedia card Interface. - If you have a PXA(R) platform with a Multimedia Card slot, - say Y or M here. - - If unsure, say N. - -config MMC_SDHCI - tristate "Secure Digital Host Controller Interface support" - depends on HAS_DMA - help - This selects the generic Secure Digital Host Controller Interface. - It is used by manufacturers such as Texas Instruments(R), Ricoh(R) - and Toshiba(R). Most controllers found in laptops are of this type. - - If you have a controller with this interface, say Y or M here. You - also need to enable an appropriate bus interface. - - 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_BIG_ENDIAN_32BIT_BYTE_SWAPPER - bool - select MMC_SDHCI_IO_ACCESSORS - help - This option is selected by drivers running on big endian hosts - and performing I/O to a SDHCI controller through a bus that - implements a hardware byte swapper using a 32-bit datum. - This endian mapping mode is called "data invariance" and - has the effect of scrambling the addresses and formats of data - accessed in sizes other than the datum size. - - This is the case for the Freescale eSDHC and Nintendo Wii SDHCI. - -config MMC_SDHCI_PCI - tristate "SDHCI support on PCI bus" - depends on MMC_SDHCI && PCI - help - This selects the PCI Secure Digital Host Controller Interface. - Most controllers found today are PCI devices. - - If you have a controller with this interface, say Y or M here. - - If unsure, say N. - -config MMC_RICOH_MMC - bool "Ricoh MMC Controller Disabler (EXPERIMENTAL)" - depends on MMC_SDHCI_PCI - help - This adds a pci quirk to disable Ricoh MMC Controller. This - proprietary controller is unnecessary because the SDHCI driver - supports MMC cards on the SD controller, but if it is not - disabled, it will steal the MMC cards away - rendering them - useless. It is safe to select this even if you don't - have a Ricoh based card reader. - - If unsure, say Y. - -config MMC_SDHCI_PLTFM - tristate "SDHCI platform and OF driver helper" - depends on MMC_SDHCI - help - This selects the common helper functions support for Secure Digital - Host Controller Interface based platform and OF drivers. - - If you have a controller with this interface, say Y or M here. - - If unsure, say N. - -config MMC_SDHCI_OF_ESDHC - tristate "SDHCI OF support for the Freescale eSDHC controller" - depends on MMC_SDHCI_PLTFM - depends on PPC_OF - select MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER - help - This selects the Freescale eSDHC controller support. - - If you have a controller with this interface, say Y or M here. - - If unsure, say N. - -config MMC_SDHCI_OF_HLWD - tristate "SDHCI OF support for the Nintendo Wii SDHCI controllers" - depends on MMC_SDHCI_PLTFM - depends on PPC_OF - select MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER - help - This selects the Secure Digital Host Controller Interface (SDHCI) - found in the "Hollywood" chipset of the Nintendo Wii video game - console. - - If you have a controller with this interface, say Y or M here. - - If unsure, say N. - -config MMC_SDHCI_CNS3XXX - tristate "SDHCI support on the Cavium Networks CNS3xxx SoC" - depends on ARCH_CNS3XXX - depends on MMC_SDHCI_PLTFM - help - This selects the SDHCI support for CNS3xxx System-on-Chip devices. - - If you have a controller with this interface, say Y or M here. - - If unsure, say N. - -config MMC_SDHCI_ESDHC_IMX - tristate "SDHCI support for the Freescale eSDHC/uSDHC i.MX controller" - depends on ARCH_MXC - depends on MMC_SDHCI_PLTFM - select MMC_SDHCI_IO_ACCESSORS - help - This selects the Freescale eSDHC/uSDHC controller support - found on i.MX25, i.MX35 i.MX5x and i.MX6x. - - If you have a controller with this interface, say Y or M here. - - If unsure, say N. - -config MMC_SDHCI_DOVE - tristate "SDHCI support on Marvell's Dove SoC" - depends on ARCH_DOVE - depends on MMC_SDHCI_PLTFM - select MMC_SDHCI_IO_ACCESSORS - help - This selects the Secure Digital Host Controller Interface in - Marvell's Dove SoC. - - If you have a controller with this interface, say Y or M here. - - If unsure, say N. - -config MMC_SDHCI_TEGRA - tristate "SDHCI platform support for the Tegra SD/MMC Controller" - depends on ARCH_TEGRA - depends on MMC_SDHCI_PLTFM - select MMC_SDHCI_IO_ACCESSORS - help - This selects the Tegra SD/MMC controller. If you have a Tegra - platform with SD or MMC devices, say Y or M here. - - If unsure, say N. - -config MMC_SDHCI_S3C - tristate "SDHCI support on Samsung S3C SoC" - depends on MMC_SDHCI && PLAT_SAMSUNG - help - This selects the Secure Digital Host Controller Interface (SDHCI) - often referrered to as the HSMMC block in some of the Samsung S3C - range of SoC. - - Note, due to the problems with DMA, the DMA support is only - available with CONFIG_EXPERIMENTAL is selected. - - If you have a controller with this interface, say Y or M here. - - If unsure, say N. - -config MMC_SDHCI_PXAV3 - tristate "Marvell MMP2 SD Host Controller support (PXAV3)" - depends on CLKDEV_LOOKUP - select MMC_SDHCI - select MMC_SDHCI_PLTFM - default CPU_MMP2 - help - This selects the Marvell(R) PXAV3 SD Host Controller. - If you have a MMP2 platform with SD Host Controller - and a card slot, say Y or M here. - - If unsure, say N. - -config MMC_SDHCI_PXAV2 - tristate "Marvell PXA9XX SD Host Controller support (PXAV2)" - depends on CLKDEV_LOOKUP - select MMC_SDHCI - select MMC_SDHCI_PLTFM - default CPU_PXA910 - help - This selects the Marvell(R) PXAV2 SD Host Controller. - If you have a PXA9XX platform with SD Host Controller - and a card slot, say Y or M here. - - If unsure, say N. - -config MMC_SDHCI_SPEAR - tristate "SDHCI support on ST SPEAr platform" - depends on MMC_SDHCI && PLAT_SPEAR - help - This selects the Secure Digital Host Controller Interface (SDHCI) - often referrered to as the HSMMC block in some of the ST SPEAR range - of SoC - - If you have a controller with this interface, say Y or M here. - - If unsure, say N. - -config MMC_SDHCI_S3C_DMA - bool "DMA support on S3C SDHCI" - depends on MMC_SDHCI_S3C && EXPERIMENTAL - help - Enable DMA support on the Samsung S3C SDHCI glue. The DMA - has proved to be problematic if the controller encounters - certain errors, and thus should be treated with care. - - YMMV. - -config MMC_OMAP - tristate "TI OMAP Multimedia Card Interface support" - depends on ARCH_OMAP - select TPS65010 if MACH_OMAP_H2 - help - This selects the TI OMAP Multimedia card Interface. - If you have an OMAP board with a Multimedia Card slot, - say Y or M here. - - If unsure, say N. - -config MMC_OMAP_HS - tristate "TI OMAP High Speed Multimedia Card Interface support" - depends on SOC_OMAP2430 || ARCH_OMAP3 || ARCH_OMAP4 - help - This selects the TI OMAP High Speed Multimedia card Interface. - If you have an OMAP2430 or OMAP3 board or OMAP4 board with a - Multimedia Card slot, say Y or M here. - - If unsure, say N. - -config MMC_WBSD - tristate "Winbond W83L51xD SD/MMC Card Interface support" - depends on ISA_DMA_API - help - This selects the Winbond(R) W83L51xD Secure digital and - Multimedia card Interface. - If you have a machine with a integrated W83L518D or W83L519D - SD/MMC card reader, say Y or M here. - - If unsure, say N. - -config MMC_AU1X - tristate "Alchemy AU1XX0 MMC Card Interface support" - depends on MIPS_ALCHEMY - help - This selects the AMD Alchemy(R) Multimedia card interface. - If you have a Alchemy platform with a MMC slot, say Y or M here. - - If unsure, say N. - -choice - prompt "Atmel SD/MMC Driver" - depends on AVR32 || ARCH_AT91 - default MMC_ATMELMCI if AVR32 - help - Choose which driver to use for the Atmel MCI Silicon - -config MMC_AT91 - tristate "AT91 SD/MMC Card Interface support" - depends on ARCH_AT91 - help - This selects the AT91 MCI controller. - - If unsure, say N. - -config MMC_ATMELMCI - tristate "Atmel Multimedia Card Interface support" - depends on AVR32 || ARCH_AT91 - help - This selects the Atmel Multimedia Card Interface driver. If - you have an AT32 (AVR32) or AT91 platform with a Multimedia - Card slot, say Y or M here. - - If unsure, say N. - -endchoice - -config MMC_ATMELMCI_DMA - bool "Atmel MCI DMA support" - depends on MMC_ATMELMCI && (AVR32 || ARCH_AT91SAM9G45) && DMA_ENGINE - help - Say Y here to have the Atmel MCI driver use a DMA engine to - do data transfers and thus increase the throughput and - reduce the CPU utilization. - - If unsure, say N. - -config MMC_IMX - tristate "Motorola i.MX Multimedia Card Interface support" - depends on ARCH_MX1 - help - This selects the Motorola i.MX Multimedia card Interface. - If you have a i.MX platform with a Multimedia Card slot, - say Y or M here. - - If unsure, say N. - -config MMC_MSM - tristate "Qualcomm SDCC Controller Support" - depends on MMC && ARCH_MSM - help - This provides support for the SD/MMC cell found in the - MSM and QSD SOCs from Qualcomm. The controller also has - support for SDIO devices. - -config MMC_MXC - tristate "Freescale i.MX21/27/31 Multimedia Card Interface support" - depends on ARCH_MXC - help - This selects the Freescale i.MX21, i.MX27 and i.MX31 Multimedia card - Interface. If you have a i.MX platform with a Multimedia Card slot, - say Y or M here. - - If unsure, say N. - -config MMC_MXS - tristate "Freescale MXS Multimedia Card Interface support" - depends on ARCH_MXS && MXS_DMA - help - This selects the Freescale SSP MMC controller found on MXS based - platforms like mx23/28. - - If unsure, say N. - -config MMC_TIFM_SD - tristate "TI Flash Media MMC/SD Interface support (EXPERIMENTAL)" - depends on EXPERIMENTAL && PCI - select TIFM_CORE - help - Say Y here if you want to be able to access MMC/SD cards with - the Texas Instruments(R) Flash Media card reader, found in many - laptops. - This option 'selects' (turns on, enables) 'TIFM_CORE', but you - probably also need appropriate card reader host adapter, such as - 'Misc devices: TI Flash Media PCI74xx/PCI76xx host adapter support - (TIFM_7XX1)'. - - 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_DAVINCI - tristate "TI DAVINCI Multimedia Card Interface support" - depends on ARCH_DAVINCI - help - This selects the TI DAVINCI Multimedia card Interface. - If you have an DAVINCI board with a Multimedia Card slot, - say Y or M here. If unsure, say N. - -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 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 - controllers. - - If unsure, or if your system has no SPI master driver, say N. - -config MMC_S3C - tristate "Samsung S3C SD/MMC Card Interface support" - depends on ARCH_S3C24XX - help - This selects a driver for the MCI interface found in - Samsung's S3C2410, S3C2412, S3C2440, S3C2442 CPUs. - If you have a board based on one of those and a MMC/SD - slot, say Y or M here. - - If unsure, say N. - -config MMC_S3C_HW_SDIO_IRQ - bool "Hardware support for SDIO IRQ" - depends on MMC_S3C - help - Enable the hardware support for SDIO interrupts instead of using - the generic polling code. - -choice - prompt "Samsung S3C SD/MMC transfer code" - depends on MMC_S3C - -config MMC_S3C_PIO - bool "Use PIO transfers only" - help - Use PIO to transfer data between memory and the hardware. - - PIO is slower than DMA as it requires CPU instructions to - move the data. This has been the traditional default for - the S3C MCI driver. - -config MMC_S3C_DMA - bool "Use DMA transfers only (EXPERIMENTAL)" - depends on EXPERIMENTAL - help - Use DMA to transfer data between memory and the hardare. - - Currently, the DMA support in this driver seems to not be - working properly and needs to be debugged before this - option is useful. - -config MMC_S3C_PIODMA - bool "Support for both PIO and DMA (EXPERIMENTAL)" - help - Compile both the PIO and DMA transfer routines into the - driver and let the platform select at run-time which one - is best. - - See notes for the DMA option. - -endchoice - -config MMC_SDRICOH_CS - tristate "MMC/SD driver for Ricoh Bay1Controllers (EXPERIMENTAL)" - depends on EXPERIMENTAL && PCI && PCMCIA - help - Say Y here if your Notebook reports a Ricoh Bay1Controller PCMCIA - card whenever you insert a MMC or SD card into the card slot. - - To compile this driver as a module, choose M here: the - module will be called sdricoh_cs. - -config MMC_TMIO_CORE - tristate - -config MMC_TMIO - tristate "Toshiba Mobile IO Controller (TMIO) MMC/SD function support" - depends on MFD_TMIO || MFD_ASIC3 - select MMC_TMIO_CORE - help - This provides support for the SD/MMC cell found in TC6393XB, - T7L66XB and also HTC ASIC3 - -config MMC_SDHI - tristate "SH-Mobile SDHI SD/SDIO controller support" - depends on SUPERH || ARCH_SHMOBILE - select MMC_TMIO_CORE - help - This provides support for the SDHI SD/SDIO controller found in - SuperH and ARM SH-Mobile SoCs - -config MMC_CB710 - tristate "ENE CB710 MMC/SD Interface support" - depends on PCI - select CB710_CORE - help - This option enables support for MMC/SD part of ENE CB710/720 Flash - memory card reader found in some laptops (ie. some versions of - HP Compaq nx9500). - - This driver can also be built as a module. If so, the module - will be called cb710-mmc. - -config MMC_VIA_SDMMC - tristate "VIA SD/MMC Card Reader Driver" - depends on PCI - help - This selects the VIA SD/MMC Card Reader driver, say Y or M here. - VIA provides one multi-functional card reader which integrated into - some motherboards manufactured by VIA. This card reader supports - SD/MMC/SDHC. - If you have a controller with this interface, say Y or M here. - - If unsure, say N. - -config SDH_BFIN - tristate "Blackfin Secure Digital Host support" - depends on (BF54x && !BF544) || (BF51x && !BF512) - help - If you say yes here you will get support for the Blackfin on-chip - Secure Digital Host interface. This includes support for MMC and - SD cards. - - To compile this driver as a module, choose M here: the - module will be called bfin_sdh. - - If unsure, say N. - -config SDH_BFIN_MISSING_CMD_PULLUP_WORKAROUND - bool "Blackfin EZkit Missing SDH_CMD Pull Up Resistor Workaround" - depends on SDH_BFIN - help - If you say yes here SD-Cards may work on the EZkit. - -config MMC_DW - tristate "Synopsys DesignWare Memory Card Interface" - depends on ARM - help - This selects support for the Synopsys DesignWare Mobile Storage IP - block, this provides host support for SD and MMC interfaces, in both - PIO and external DMA modes. - -config MMC_DW_IDMAC - bool "Internal DMAC interface" - depends on MMC_DW - help - This selects support for the internal DMAC block within the Synopsys - Designware Mobile Storage IP block. This disables the external DMA - interface. - -config MMC_DW_PLTFM - tristate "Synopsys Designware MCI Support as platform device" - depends on MMC_DW - default y - help - This selects the common helper functions support for Host Controller - Interface based platform driver. Please select this option if the IP - is present as a platform device. This is the common interface for the - Synopsys Designware IP. - - If you have a controller with this interface, say Y or M here. - - If unsure, say Y. - -config MMC_DW_PCI - tristate "Synopsys Designware MCI support on PCI bus" - depends on MMC_DW && PCI - help - This selects the PCI bus for the Synopsys Designware Mobile Storage IP. - Select this option if the IP is present on PCI platform. - - If you have a controller with this interface, say Y or M here. - - If unsure, say N. - -config MMC_SH_MMCIF - tristate "SuperH Internal MMCIF support" - depends on MMC_BLOCK && (SUPERH || ARCH_SHMOBILE) - help - This selects the MMC Host Interface controller (MMCIF). - - This driver supports MMCIF in sh7724/sh7757/sh7372. - -config MMC_JZ4740 - tristate "JZ4740 SD/Multimedia Card Interface support" - depends on MACH_JZ4740 - help - This selects support for the SD/MMC controller on Ingenic JZ4740 - SoCs. - If you have a board based on such a SoC and with a SD/MMC slot, - say Y or M here. - -config MMC_VUB300 - tristate "VUB300 USB to SDIO/SD/MMC Host Controller support" - depends on USB - help - This selects support for Elan Digital Systems' VUB300 chip. - - The VUB300 is a USB-SDIO Host Controller Interface chip - that enables the host computer to use SDIO/SD/MMC cards - via a USB 2.0 or USB 1.1 host. - - The VUB300 chip will be found in both physically separate - USB to SDIO/SD/MMC adapters and embedded on some motherboards. - - The VUB300 chip supports SD and MMC memory cards in addition - to single and multifunction SDIO cards. - - Some SDIO cards will need a firmware file to be loaded and - sent to VUB300 chip in order to achieve better data throughput. - Download these "Offload Pseudocode" from Elan Digital Systems' - web-site http://www.elandigitalsystems.com/support/downloads.php - and put them in /lib/firmware. Note that without these additional - firmware files the VUB300 chip will still function, but not at - the best obtainable data rate. - - To compile this mmc host controller driver as a module, - choose M here: the module will be called vub300. - - If you have a computer with an embedded VUB300 chip - or if you intend connecting a USB adapter based on a - VUB300 chip say Y or M here. - -config MMC_USHC - tristate "USB SD Host Controller (USHC) support" - depends on USB - help - This selects support for USB SD Host Controllers based on - the Cypress Astoria chip with firmware compliant with CSR's - USB SD Host Controller specification (CS-118793-SP). - - CSR boards with this device include: USB<>SDIO (M1985v2), - and Ultrasira. - - Note: These controllers only support SDIO cards and do not - support MMC or SD memory cards. - -config MMC_ATSMB - tristate "WonderMedia ATSMB(AHB To MMC/SD BUS)" - help - This selects the WMT Secure digital and Multimedia card Interface. - If you have a machine with WonderMedia ATSMB, say Y or M here. - - If unsure, say N. - -config MMC_ATSMB1 - tristate "WonderMedia ATSMB1(AHB To MMC/SD1 BUS)" - help - This selects the WMT Secure digital and Multimedia card Interface. - If you have a machine with WonderMedia ATSMB1, say Y or M here. - - If unsure, say N. - -config MMC_ATSMB2 - tristate "WonderMedia ATSMB2(AHB To MMC/SD2 BUS)" - help - This selects the WMT Secure digital and Multimedia card Interface. - If you have a machine with WonderMedia ATSMB2, say Y or M here. - - If unsure, say N. - diff --git a/ANDROID_3.4.5/drivers/mmc/host/Makefile b/ANDROID_3.4.5/drivers/mmc/host/Makefile deleted file mode 100644 index b46a087b..00000000 --- a/ANDROID_3.4.5/drivers/mmc/host/Makefile +++ /dev/null @@ -1,63 +0,0 @@ -# -# Makefile for MMC/SD host controller drivers -# - -obj-$(CONFIG_MMC_ARMMMCI) += mmci.o -obj-$(CONFIG_MMC_PXA) += pxamci.o -obj-$(CONFIG_MMC_IMX) += imxmmc.o -obj-$(CONFIG_MMC_MXC) += mxcmmc.o -obj-$(CONFIG_MMC_MXS) += mxs-mmc.o -obj-$(CONFIG_MMC_SDHCI) += sdhci.o -obj-$(CONFIG_MMC_SDHCI_PCI) += sdhci-pci.o -obj-$(subst m,y,$(CONFIG_MMC_SDHCI_PCI)) += sdhci-pci-data.o -obj-$(CONFIG_MMC_SDHCI_PXAV3) += sdhci-pxav3.o -obj-$(CONFIG_MMC_SDHCI_PXAV2) += sdhci-pxav2.o -obj-$(CONFIG_MMC_SDHCI_S3C) += sdhci-s3c.o -obj-$(CONFIG_MMC_SDHCI_SPEAR) += sdhci-spear.o -obj-$(CONFIG_MMC_WBSD) += wbsd.o -obj-$(CONFIG_MMC_AU1X) += au1xmmc.o -obj-$(CONFIG_MMC_OMAP) += omap.o -obj-$(CONFIG_MMC_OMAP_HS) += omap_hsmmc.o -obj-$(CONFIG_MMC_AT91) += at91_mci.o -obj-$(CONFIG_MMC_ATMELMCI) += atmel-mci.o -obj-$(CONFIG_MMC_TIFM_SD) += tifm_sd.o -obj-$(CONFIG_MMC_MSM) += msm_sdcc.o -obj-$(CONFIG_MMC_MVSDIO) += mvsdio.o -obj-$(CONFIG_MMC_DAVINCI) += davinci_mmc.o -obj-$(CONFIG_MMC_SPI) += mmc_spi.o -ifeq ($(CONFIG_OF),y) -obj-$(CONFIG_MMC_SPI) += of_mmc_spi.o -endif -obj-$(CONFIG_MMC_S3C) += s3cmci.o -obj-$(CONFIG_MMC_SDRICOH_CS) += sdricoh_cs.o -obj-$(CONFIG_MMC_TMIO) += tmio_mmc.o -obj-$(CONFIG_MMC_TMIO_CORE) += tmio_mmc_core.o -tmio_mmc_core-y := tmio_mmc_pio.o -tmio_mmc_core-$(subst m,y,$(CONFIG_MMC_SDHI)) += tmio_mmc_dma.o -obj-$(CONFIG_MMC_SDHI) += sh_mobile_sdhi.o -obj-$(CONFIG_MMC_CB710) += cb710-mmc.o -obj-$(CONFIG_MMC_VIA_SDMMC) += via-sdmmc.o -obj-$(CONFIG_SDH_BFIN) += bfin_sdh.o -obj-$(CONFIG_MMC_DW) += dw_mmc.o -obj-$(CONFIG_MMC_DW_PLTFM) += dw_mmc-pltfm.o -obj-$(CONFIG_MMC_DW_PCI) += dw_mmc-pci.o -obj-$(CONFIG_MMC_SH_MMCIF) += sh_mmcif.o -obj-$(CONFIG_MMC_JZ4740) += jz4740_mmc.o -obj-$(CONFIG_MMC_VUB300) += vub300.o -obj-$(CONFIG_MMC_USHC) += ushc.o - -obj-$(CONFIG_MMC_SDHCI_PLTFM) += sdhci-pltfm.o -obj-$(CONFIG_MMC_SDHCI_CNS3XXX) += sdhci-cns3xxx.o -obj-$(CONFIG_MMC_SDHCI_ESDHC_IMX) += sdhci-esdhc-imx.o -obj-$(CONFIG_MMC_SDHCI_DOVE) += sdhci-dove.o -obj-$(CONFIG_MMC_SDHCI_TEGRA) += sdhci-tegra.o -obj-$(CONFIG_MMC_SDHCI_OF_ESDHC) += sdhci-of-esdhc.o -obj-$(CONFIG_MMC_SDHCI_OF_HLWD) += sdhci-of-hlwd.o - -ifeq ($(CONFIG_CB710_DEBUG),y) - CFLAGS-cb710-mmc += -DDEBUG -endif - -obj-$(CONFIG_MMC_ATSMB) += mmc_atsmb.o -obj-$(CONFIG_MMC_ATSMB1) += mmc_atsmb1.o -obj-$(CONFIG_MMC_ATSMB2) += mmc_atsmb2.o diff --git a/ANDROID_3.4.5/drivers/mmc/host/at91_mci.c b/ANDROID_3.4.5/drivers/mmc/host/at91_mci.c deleted file mode 100644 index efdb81d2..00000000 --- a/ANDROID_3.4.5/drivers/mmc/host/at91_mci.c +++ /dev/null @@ -1,1219 +0,0 @@ -/* - * linux/drivers/mmc/host/at91_mci.c - ATMEL AT91 MCI Driver - * - * Copyright (C) 2005 Cougar Creek Computing Devices Ltd, All Rights Reserved - * - * Copyright (C) 2006 Malcolm Noyes - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -/* - This is the AT91 MCI driver that has been tested with both MMC cards - and SD-cards. Boards that support write protect are now supported. - The CCAT91SBC001 board does not support SD cards. - - The three entry points are at91_mci_request, at91_mci_set_ios - and at91_mci_get_ro. - - SET IOS - This configures the device to put it into the correct mode and clock speed - required. - - MCI REQUEST - MCI request processes the commands sent in the mmc_request structure. This - can consist of a processing command and a stop command in the case of - multiple block transfers. - - There are three main types of request, commands, reads and writes. - - Commands are straight forward. The command is submitted to the controller and - the request function returns. When the controller generates an interrupt to indicate - the command is finished, the response to the command are read and the mmc_request_done - function called to end the request. - - Reads and writes work in a similar manner to normal commands but involve the PDC (DMA) - controller to manage the transfers. - - A read is done from the controller directly to the scatterlist passed in from the request. - Due to a bug in the AT91RM9200 controller, when a read is completed, all the words are byte - swapped in the scatterlist buffers. AT91SAM926x are not affected by this bug. - - The sequence of read interrupts is: ENDRX, RXBUFF, CMDRDY - - A write is slightly different in that the bytes to write are read from the scatterlist - into a dma memory buffer (this is in case the source buffer should be read only). The - entire write buffer is then done from this single dma memory buffer. - - The sequence of write interrupts is: ENDTX, TXBUFE, NOTBUSY, CMDRDY - - GET RO - Gets the status of the write protect pin, if available. -*/ - -#include <linux/module.h> -#include <linux/moduleparam.h> -#include <linux/init.h> -#include <linux/ioport.h> -#include <linux/platform_device.h> -#include <linux/interrupt.h> -#include <linux/blkdev.h> -#include <linux/delay.h> -#include <linux/err.h> -#include <linux/dma-mapping.h> -#include <linux/clk.h> -#include <linux/atmel_pdc.h> -#include <linux/gfp.h> -#include <linux/highmem.h> - -#include <linux/mmc/host.h> -#include <linux/mmc/sdio.h> - -#include <asm/io.h> -#include <asm/irq.h> -#include <asm/gpio.h> - -#include <mach/board.h> -#include <mach/cpu.h> - -#include "at91_mci.h" - -#define DRIVER_NAME "at91_mci" - -static inline int at91mci_is_mci1rev2xx(void) -{ - return ( cpu_is_at91sam9260() - || cpu_is_at91sam9263() - || cpu_is_at91sam9rl() - || cpu_is_at91sam9g10() - || cpu_is_at91sam9g20() - ); -} - -#define FL_SENT_COMMAND (1 << 0) -#define FL_SENT_STOP (1 << 1) - -#define AT91_MCI_ERRORS (AT91_MCI_RINDE | AT91_MCI_RDIRE | AT91_MCI_RCRCE \ - | AT91_MCI_RENDE | AT91_MCI_RTOE | AT91_MCI_DCRCE \ - | AT91_MCI_DTOE | AT91_MCI_OVRE | AT91_MCI_UNRE) - -#define at91_mci_read(host, reg) __raw_readl((host)->baseaddr + (reg)) -#define at91_mci_write(host, reg, val) __raw_writel((val), (host)->baseaddr + (reg)) - -#define MCI_BLKSIZE 512 -#define MCI_MAXBLKSIZE 4095 -#define MCI_BLKATONCE 256 -#define MCI_BUFSIZE (MCI_BLKSIZE * MCI_BLKATONCE) - -/* - * Low level type for this driver - */ -struct at91mci_host -{ - struct mmc_host *mmc; - struct mmc_command *cmd; - struct mmc_request *request; - - void __iomem *baseaddr; - int irq; - - struct at91_mmc_data *board; - int present; - - struct clk *mci_clk; - - /* - * Flag indicating when the command has been sent. This is used to - * work out whether or not to send the stop - */ - unsigned int flags; - /* flag for current bus settings */ - u32 bus_mode; - - /* DMA buffer used for transmitting */ - unsigned int* buffer; - dma_addr_t physical_address; - unsigned int total_length; - - /* Latest in the scatterlist that has been enabled for transfer, but not freed */ - int in_use_index; - - /* Latest in the scatterlist that has been enabled for transfer */ - int transfer_index; - - /* Timer for timeouts */ - struct timer_list timer; -}; - -/* - * Reset the controller and restore most of the state - */ -static void at91_reset_host(struct at91mci_host *host) -{ - unsigned long flags; - u32 mr; - u32 sdcr; - u32 dtor; - u32 imr; - - local_irq_save(flags); - imr = at91_mci_read(host, AT91_MCI_IMR); - - at91_mci_write(host, AT91_MCI_IDR, 0xffffffff); - - /* save current state */ - mr = at91_mci_read(host, AT91_MCI_MR) & 0x7fff; - sdcr = at91_mci_read(host, AT91_MCI_SDCR); - dtor = at91_mci_read(host, AT91_MCI_DTOR); - - /* reset the controller */ - at91_mci_write(host, AT91_MCI_CR, AT91_MCI_MCIDIS | AT91_MCI_SWRST); - - /* restore state */ - at91_mci_write(host, AT91_MCI_CR, AT91_MCI_MCIEN); - at91_mci_write(host, AT91_MCI_MR, mr); - at91_mci_write(host, AT91_MCI_SDCR, sdcr); - at91_mci_write(host, AT91_MCI_DTOR, dtor); - at91_mci_write(host, AT91_MCI_IER, imr); - - /* make sure sdio interrupts will fire */ - at91_mci_read(host, AT91_MCI_SR); - - local_irq_restore(flags); -} - -static void at91_timeout_timer(unsigned long data) -{ - struct at91mci_host *host; - - host = (struct at91mci_host *)data; - - if (host->request) { - dev_err(host->mmc->parent, "Timeout waiting end of packet\n"); - - if (host->cmd && host->cmd->data) { - host->cmd->data->error = -ETIMEDOUT; - } else { - if (host->cmd) - host->cmd->error = -ETIMEDOUT; - else - host->request->cmd->error = -ETIMEDOUT; - } - - at91_reset_host(host); - mmc_request_done(host->mmc, host->request); - } -} - -/* - * Copy from sg to a dma block - used for transfers - */ -static inline void at91_mci_sg_to_dma(struct at91mci_host *host, struct mmc_data *data) -{ - unsigned int len, i, size; - unsigned *dmabuf = host->buffer; - - size = data->blksz * data->blocks; - len = data->sg_len; - - /* MCI1 rev2xx Data Write Operation and number of bytes erratum */ - if (at91mci_is_mci1rev2xx()) - if (host->total_length == 12) - memset(dmabuf, 0, 12); - - /* - * Just loop through all entries. Size might not - * be the entire list though so make sure that - * we do not transfer too much. - */ - for (i = 0; i < len; i++) { - struct scatterlist *sg; - int amount; - unsigned int *sgbuffer; - - sg = &data->sg[i]; - - sgbuffer = kmap_atomic(sg_page(sg)) + sg->offset; - amount = min(size, sg->length); - size -= amount; - - if (cpu_is_at91rm9200()) { /* AT91RM9200 errata */ - int index; - - for (index = 0; index < (amount / 4); index++) - *dmabuf++ = swab32(sgbuffer[index]); - } else { - char *tmpv = (char *)dmabuf; - memcpy(tmpv, sgbuffer, amount); - tmpv += amount; - dmabuf = (unsigned *)tmpv; - } - - kunmap_atomic(sgbuffer); - - if (size == 0) - break; - } - - /* - * Check that we didn't get a request to transfer - * more data than can fit into the SG list. - */ - BUG_ON(size != 0); -} - -/* - * Handle after a dma read - */ -static void at91_mci_post_dma_read(struct at91mci_host *host) -{ - struct mmc_command *cmd; - struct mmc_data *data; - unsigned int len, i, size; - unsigned *dmabuf = host->buffer; - - pr_debug("post dma read\n"); - - cmd = host->cmd; - if (!cmd) { - pr_debug("no command\n"); - return; - } - - data = cmd->data; - if (!data) { - pr_debug("no data\n"); - return; - } - - size = data->blksz * data->blocks; - len = data->sg_len; - - at91_mci_write(host, AT91_MCI_IDR, AT91_MCI_ENDRX); - at91_mci_write(host, AT91_MCI_IER, AT91_MCI_RXBUFF); - - for (i = 0; i < len; i++) { - struct scatterlist *sg; - int amount; - unsigned int *sgbuffer; - - sg = &data->sg[i]; - - sgbuffer = kmap_atomic(sg_page(sg)) + sg->offset; - amount = min(size, sg->length); - size -= amount; - - if (cpu_is_at91rm9200()) { /* AT91RM9200 errata */ - int index; - for (index = 0; index < (amount / 4); index++) - sgbuffer[index] = swab32(*dmabuf++); - } else { - char *tmpv = (char *)dmabuf; - memcpy(sgbuffer, tmpv, amount); - tmpv += amount; - dmabuf = (unsigned *)tmpv; - } - - flush_kernel_dcache_page(sg_page(sg)); - kunmap_atomic(sgbuffer); - data->bytes_xfered += amount; - if (size == 0) - break; - } - - pr_debug("post dma read done\n"); -} - -/* - * Handle transmitted data - */ -static void at91_mci_handle_transmitted(struct at91mci_host *host) -{ - struct mmc_command *cmd; - struct mmc_data *data; - - pr_debug("Handling the transmit\n"); - - /* Disable the transfer */ - at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTDIS | ATMEL_PDC_TXTDIS); - - /* Now wait for cmd ready */ - at91_mci_write(host, AT91_MCI_IDR, AT91_MCI_TXBUFE); - - cmd = host->cmd; - if (!cmd) return; - - data = cmd->data; - if (!data) return; - - if (cmd->data->blocks > 1) { - pr_debug("multiple write : wait for BLKE...\n"); - at91_mci_write(host, AT91_MCI_IER, AT91_MCI_BLKE); - } else - at91_mci_write(host, AT91_MCI_IER, AT91_MCI_NOTBUSY); -} - -/* - * Update bytes tranfered count during a write operation - */ -static void at91_mci_update_bytes_xfered(struct at91mci_host *host) -{ - struct mmc_data *data; - - /* always deal with the effective request (and not the current cmd) */ - - if (host->request->cmd && host->request->cmd->error != 0) - return; - - if (host->request->data) { - data = host->request->data; - if (data->flags & MMC_DATA_WRITE) { - /* card is in IDLE mode now */ - pr_debug("-> bytes_xfered %d, total_length = %d\n", - data->bytes_xfered, host->total_length); - data->bytes_xfered = data->blksz * data->blocks; - } - } -} - - -/*Handle after command sent ready*/ -static int at91_mci_handle_cmdrdy(struct at91mci_host *host) -{ - if (!host->cmd) - return 1; - else if (!host->cmd->data) { - if (host->flags & FL_SENT_STOP) { - /*After multi block write, we must wait for NOTBUSY*/ - at91_mci_write(host, AT91_MCI_IER, AT91_MCI_NOTBUSY); - } else return 1; - } else if (host->cmd->data->flags & MMC_DATA_WRITE) { - /*After sendding multi-block-write command, start DMA transfer*/ - at91_mci_write(host, AT91_MCI_IER, AT91_MCI_TXBUFE | AT91_MCI_BLKE); - at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_TXTEN); - } - - /* command not completed, have to wait */ - return 0; -} - - -/* - * Enable the controller - */ -static void at91_mci_enable(struct at91mci_host *host) -{ - unsigned int mr; - - at91_mci_write(host, AT91_MCI_CR, AT91_MCI_MCIEN); - at91_mci_write(host, AT91_MCI_IDR, 0xffffffff); - at91_mci_write(host, AT91_MCI_DTOR, AT91_MCI_DTOMUL_1M | AT91_MCI_DTOCYC); - mr = AT91_MCI_PDCMODE | 0x34a; - - if (at91mci_is_mci1rev2xx()) - mr |= AT91_MCI_RDPROOF | AT91_MCI_WRPROOF; - - at91_mci_write(host, AT91_MCI_MR, mr); - - /* use Slot A or B (only one at same time) */ - at91_mci_write(host, AT91_MCI_SDCR, host->board->slot_b); -} - -/* - * Disable the controller - */ -static void at91_mci_disable(struct at91mci_host *host) -{ - at91_mci_write(host, AT91_MCI_CR, AT91_MCI_MCIDIS | AT91_MCI_SWRST); -} - -/* - * Send a command - */ -static void at91_mci_send_command(struct at91mci_host *host, struct mmc_command *cmd) -{ - unsigned int cmdr, mr; - unsigned int block_length; - struct mmc_data *data = cmd->data; - - unsigned int blocks; - unsigned int ier = 0; - - host->cmd = cmd; - - /* Needed for leaving busy state before CMD1 */ - if ((at91_mci_read(host, AT91_MCI_SR) & AT91_MCI_RTOE) && (cmd->opcode == 1)) { - pr_debug("Clearing timeout\n"); - at91_mci_write(host, AT91_MCI_ARGR, 0); - at91_mci_write(host, AT91_MCI_CMDR, AT91_MCI_OPDCMD); - while (!(at91_mci_read(host, AT91_MCI_SR) & AT91_MCI_CMDRDY)) { - /* spin */ - pr_debug("Clearing: SR = %08X\n", at91_mci_read(host, AT91_MCI_SR)); - } - } - - cmdr = cmd->opcode; - - if (mmc_resp_type(cmd) == MMC_RSP_NONE) - cmdr |= AT91_MCI_RSPTYP_NONE; - else { - /* if a response is expected then allow maximum response latancy */ - cmdr |= AT91_MCI_MAXLAT; - /* set 136 bit response for R2, 48 bit response otherwise */ - if (mmc_resp_type(cmd) == MMC_RSP_R2) - cmdr |= AT91_MCI_RSPTYP_136; - else - cmdr |= AT91_MCI_RSPTYP_48; - } - - if (data) { - - if (cpu_is_at91rm9200() || cpu_is_at91sam9261()) { - if (data->blksz & 0x3) { - pr_debug("Unsupported block size\n"); - cmd->error = -EINVAL; - mmc_request_done(host->mmc, host->request); - return; - } - if (data->flags & MMC_DATA_STREAM) { - pr_debug("Stream commands not supported\n"); - cmd->error = -EINVAL; - mmc_request_done(host->mmc, host->request); - return; - } - } - - block_length = data->blksz; - blocks = data->blocks; - - /* always set data start - also set direction flag for read */ - if (data->flags & MMC_DATA_READ) - cmdr |= (AT91_MCI_TRDIR | AT91_MCI_TRCMD_START); - else if (data->flags & MMC_DATA_WRITE) - cmdr |= AT91_MCI_TRCMD_START; - - if (cmd->opcode == SD_IO_RW_EXTENDED) { - cmdr |= AT91_MCI_TRTYP_SDIO_BLOCK; - } else { - if (data->flags & MMC_DATA_STREAM) - cmdr |= AT91_MCI_TRTYP_STREAM; - if (data->blocks > 1) - cmdr |= AT91_MCI_TRTYP_MULTIPLE; - } - } - else { - block_length = 0; - blocks = 0; - } - - if (host->flags & FL_SENT_STOP) - cmdr |= AT91_MCI_TRCMD_STOP; - - if (host->bus_mode == MMC_BUSMODE_OPENDRAIN) - cmdr |= AT91_MCI_OPDCMD; - - /* - * Set the arguments and send the command - */ - pr_debug("Sending command %d as %08X, arg = %08X, blocks = %d, length = %d (MR = %08X)\n", - cmd->opcode, cmdr, cmd->arg, blocks, block_length, at91_mci_read(host, AT91_MCI_MR)); - - if (!data) { - at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_TXTDIS | ATMEL_PDC_RXTDIS); - at91_mci_write(host, ATMEL_PDC_RPR, 0); - at91_mci_write(host, ATMEL_PDC_RCR, 0); - at91_mci_write(host, ATMEL_PDC_RNPR, 0); - at91_mci_write(host, ATMEL_PDC_RNCR, 0); - at91_mci_write(host, ATMEL_PDC_TPR, 0); - at91_mci_write(host, ATMEL_PDC_TCR, 0); - at91_mci_write(host, ATMEL_PDC_TNPR, 0); - at91_mci_write(host, ATMEL_PDC_TNCR, 0); - ier = AT91_MCI_CMDRDY; - } else { - /* zero block length and PDC mode */ - mr = at91_mci_read(host, AT91_MCI_MR) & 0x5fff; - mr |= (data->blksz & 0x3) ? AT91_MCI_PDCFBYTE : 0; - mr |= (block_length << 16); - mr |= AT91_MCI_PDCMODE; - at91_mci_write(host, AT91_MCI_MR, mr); - - if (!(cpu_is_at91rm9200() || cpu_is_at91sam9261())) - at91_mci_write(host, AT91_MCI_BLKR, - AT91_MCI_BLKR_BCNT(blocks) | - AT91_MCI_BLKR_BLKLEN(block_length)); - - /* - * Disable the PDC controller - */ - at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTDIS | ATMEL_PDC_TXTDIS); - - if (cmdr & AT91_MCI_TRCMD_START) { - data->bytes_xfered = 0; - host->transfer_index = 0; - host->in_use_index = 0; - if (cmdr & AT91_MCI_TRDIR) { - /* - * Handle a read - */ - host->total_length = 0; - - at91_mci_write(host, ATMEL_PDC_RPR, host->physical_address); - at91_mci_write(host, ATMEL_PDC_RCR, (data->blksz & 0x3) ? - (blocks * block_length) : (blocks * block_length) / 4); - at91_mci_write(host, ATMEL_PDC_RNPR, 0); - at91_mci_write(host, ATMEL_PDC_RNCR, 0); - - ier = AT91_MCI_ENDRX /* | AT91_MCI_RXBUFF */; - } - else { - /* - * Handle a write - */ - host->total_length = block_length * blocks; - /* - * MCI1 rev2xx Data Write Operation and - * number of bytes erratum - */ - if (at91mci_is_mci1rev2xx()) - if (host->total_length < 12) - host->total_length = 12; - - at91_mci_sg_to_dma(host, data); - - pr_debug("Transmitting %d bytes\n", host->total_length); - - at91_mci_write(host, ATMEL_PDC_TPR, host->physical_address); - at91_mci_write(host, ATMEL_PDC_TCR, (data->blksz & 0x3) ? - host->total_length : host->total_length / 4); - - ier = AT91_MCI_CMDRDY; - } - } - } - - /* - * Send the command and then enable the PDC - not the other way round as - * the data sheet says - */ - - at91_mci_write(host, AT91_MCI_ARGR, cmd->arg); - at91_mci_write(host, AT91_MCI_CMDR, cmdr); - - if (cmdr & AT91_MCI_TRCMD_START) { - if (cmdr & AT91_MCI_TRDIR) - at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTEN); - } - - /* Enable selected interrupts */ - at91_mci_write(host, AT91_MCI_IER, AT91_MCI_ERRORS | ier); -} - -/* - * Process the next step in the request - */ -static void at91_mci_process_next(struct at91mci_host *host) -{ - if (!(host->flags & FL_SENT_COMMAND)) { - host->flags |= FL_SENT_COMMAND; - at91_mci_send_command(host, host->request->cmd); - } - else if ((!(host->flags & FL_SENT_STOP)) && host->request->stop) { - host->flags |= FL_SENT_STOP; - at91_mci_send_command(host, host->request->stop); - } else { - del_timer(&host->timer); - /* the at91rm9200 mci controller hangs after some transfers, - * and the workaround is to reset it after each transfer. - */ - if (cpu_is_at91rm9200()) - at91_reset_host(host); - mmc_request_done(host->mmc, host->request); - } -} - -/* - * Handle a command that has been completed - */ -static void at91_mci_completed_command(struct at91mci_host *host, unsigned int status) -{ - struct mmc_command *cmd = host->cmd; - struct mmc_data *data = cmd->data; - - at91_mci_write(host, AT91_MCI_IDR, 0xffffffff & ~(AT91_MCI_SDIOIRQA | AT91_MCI_SDIOIRQB)); - - cmd->resp[0] = at91_mci_read(host, AT91_MCI_RSPR(0)); - cmd->resp[1] = at91_mci_read(host, AT91_MCI_RSPR(1)); - cmd->resp[2] = at91_mci_read(host, AT91_MCI_RSPR(2)); - cmd->resp[3] = at91_mci_read(host, AT91_MCI_RSPR(3)); - - pr_debug("Status = %08X/%08x [%08X %08X %08X %08X]\n", - status, at91_mci_read(host, AT91_MCI_SR), - cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3]); - - if (status & AT91_MCI_ERRORS) { - if ((status & AT91_MCI_RCRCE) && !(mmc_resp_type(cmd) & MMC_RSP_CRC)) { - cmd->error = 0; - } - else { - if (status & (AT91_MCI_DTOE | AT91_MCI_DCRCE)) { - if (data) { - if (status & AT91_MCI_DTOE) - data->error = -ETIMEDOUT; - else if (status & AT91_MCI_DCRCE) - data->error = -EILSEQ; - } - } else { - if (status & AT91_MCI_RTOE) - cmd->error = -ETIMEDOUT; - else if (status & AT91_MCI_RCRCE) - cmd->error = -EILSEQ; - else - cmd->error = -EIO; - } - - pr_debug("Error detected and set to %d/%d (cmd = %d, retries = %d)\n", - cmd->error, data ? data->error : 0, - cmd->opcode, cmd->retries); - } - } - else - cmd->error = 0; - - at91_mci_process_next(host); -} - -/* - * Handle an MMC request - */ -static void at91_mci_request(struct mmc_host *mmc, struct mmc_request *mrq) -{ - struct at91mci_host *host = mmc_priv(mmc); - host->request = mrq; - host->flags = 0; - - /* more than 1s timeout needed with slow SD cards */ - mod_timer(&host->timer, jiffies + msecs_to_jiffies(2000)); - - at91_mci_process_next(host); -} - -/* - * Set the IOS - */ -static void at91_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) -{ - int clkdiv; - struct at91mci_host *host = mmc_priv(mmc); - unsigned long at91_master_clock = clk_get_rate(host->mci_clk); - - host->bus_mode = ios->bus_mode; - - if (ios->clock == 0) { - /* Disable the MCI controller */ - at91_mci_write(host, AT91_MCI_CR, AT91_MCI_MCIDIS); - clkdiv = 0; - } - else { - /* Enable the MCI controller */ - at91_mci_write(host, AT91_MCI_CR, AT91_MCI_MCIEN); - - if ((at91_master_clock % (ios->clock * 2)) == 0) - clkdiv = ((at91_master_clock / ios->clock) / 2) - 1; - else - clkdiv = (at91_master_clock / ios->clock) / 2; - - pr_debug("clkdiv = %d. mcck = %ld\n", clkdiv, - at91_master_clock / (2 * (clkdiv + 1))); - } - if (ios->bus_width == MMC_BUS_WIDTH_4 && host->board->wire4) { - pr_debug("MMC: Setting controller bus width to 4\n"); - at91_mci_write(host, AT91_MCI_SDCR, at91_mci_read(host, AT91_MCI_SDCR) | AT91_MCI_SDCBUS); - } - else { - pr_debug("MMC: Setting controller bus width to 1\n"); - at91_mci_write(host, AT91_MCI_SDCR, at91_mci_read(host, AT91_MCI_SDCR) & ~AT91_MCI_SDCBUS); - } - - /* Set the clock divider */ - at91_mci_write(host, AT91_MCI_MR, (at91_mci_read(host, AT91_MCI_MR) & ~AT91_MCI_CLKDIV) | clkdiv); - - /* maybe switch power to the card */ - if (gpio_is_valid(host->board->vcc_pin)) { - switch (ios->power_mode) { - case MMC_POWER_OFF: - gpio_set_value(host->board->vcc_pin, 0); - break; - case MMC_POWER_UP: - gpio_set_value(host->board->vcc_pin, 1); - break; - case MMC_POWER_ON: - break; - default: - WARN_ON(1); - } - } -} - -/* - * Handle an interrupt - */ -static irqreturn_t at91_mci_irq(int irq, void *devid) -{ - struct at91mci_host *host = devid; - int completed = 0; - unsigned int int_status, int_mask; - - int_status = at91_mci_read(host, AT91_MCI_SR); - int_mask = at91_mci_read(host, AT91_MCI_IMR); - - pr_debug("MCI irq: status = %08X, %08X, %08X\n", int_status, int_mask, - int_status & int_mask); - - int_status = int_status & int_mask; - - if (int_status & AT91_MCI_ERRORS) { - completed = 1; - - if (int_status & AT91_MCI_UNRE) - pr_debug("MMC: Underrun error\n"); - if (int_status & AT91_MCI_OVRE) - pr_debug("MMC: Overrun error\n"); - if (int_status & AT91_MCI_DTOE) - pr_debug("MMC: Data timeout\n"); - if (int_status & AT91_MCI_DCRCE) - pr_debug("MMC: CRC error in data\n"); - if (int_status & AT91_MCI_RTOE) - pr_debug("MMC: Response timeout\n"); - if (int_status & AT91_MCI_RENDE) - pr_debug("MMC: Response end bit error\n"); - if (int_status & AT91_MCI_RCRCE) - pr_debug("MMC: Response CRC error\n"); - if (int_status & AT91_MCI_RDIRE) - pr_debug("MMC: Response direction error\n"); - if (int_status & AT91_MCI_RINDE) - pr_debug("MMC: Response index error\n"); - } else { - /* Only continue processing if no errors */ - - if (int_status & AT91_MCI_TXBUFE) { - pr_debug("TX buffer empty\n"); - at91_mci_handle_transmitted(host); - } - - if (int_status & AT91_MCI_ENDRX) { - pr_debug("ENDRX\n"); - at91_mci_post_dma_read(host); - } - - if (int_status & AT91_MCI_RXBUFF) { - pr_debug("RX buffer full\n"); - at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTDIS | ATMEL_PDC_TXTDIS); - at91_mci_write(host, AT91_MCI_IDR, AT91_MCI_RXBUFF | AT91_MCI_ENDRX); - completed = 1; - } - - if (int_status & AT91_MCI_ENDTX) - pr_debug("Transmit has ended\n"); - - if (int_status & AT91_MCI_NOTBUSY) { - pr_debug("Card is ready\n"); - at91_mci_update_bytes_xfered(host); - completed = 1; - } - - if (int_status & AT91_MCI_DTIP) - pr_debug("Data transfer in progress\n"); - - if (int_status & AT91_MCI_BLKE) { - pr_debug("Block transfer has ended\n"); - if (host->request->data && host->request->data->blocks > 1) { - /* multi block write : complete multi write - * command and send stop */ - completed = 1; - } else { - at91_mci_write(host, AT91_MCI_IER, AT91_MCI_NOTBUSY); - } - } - - if (int_status & AT91_MCI_SDIOIRQA) - mmc_signal_sdio_irq(host->mmc); - - if (int_status & AT91_MCI_SDIOIRQB) - mmc_signal_sdio_irq(host->mmc); - - if (int_status & AT91_MCI_TXRDY) - pr_debug("Ready to transmit\n"); - - if (int_status & AT91_MCI_RXRDY) - pr_debug("Ready to receive\n"); - - if (int_status & AT91_MCI_CMDRDY) { - pr_debug("Command ready\n"); - completed = at91_mci_handle_cmdrdy(host); - } - } - - if (completed) { - pr_debug("Completed command\n"); - at91_mci_write(host, AT91_MCI_IDR, 0xffffffff & ~(AT91_MCI_SDIOIRQA | AT91_MCI_SDIOIRQB)); - at91_mci_completed_command(host, int_status); - } else - at91_mci_write(host, AT91_MCI_IDR, int_status & ~(AT91_MCI_SDIOIRQA | AT91_MCI_SDIOIRQB)); - - return IRQ_HANDLED; -} - -static irqreturn_t at91_mmc_det_irq(int irq, void *_host) -{ - struct at91mci_host *host = _host; - int present; - - /* entering this ISR means that we have configured det_pin: - * we can use its value in board structure */ - present = !gpio_get_value(host->board->det_pin); - - /* - * we expect this irq on both insert and remove, - * and use a short delay to debounce. - */ - if (present != host->present) { - host->present = present; - pr_debug("%s: card %s\n", mmc_hostname(host->mmc), - present ? "insert" : "remove"); - if (!present) { - pr_debug("****** Resetting SD-card bus width ******\n"); - at91_mci_write(host, AT91_MCI_SDCR, at91_mci_read(host, AT91_MCI_SDCR) & ~AT91_MCI_SDCBUS); - } - /* 0.5s needed because of early card detect switch firing */ - mmc_detect_change(host->mmc, msecs_to_jiffies(500)); - } - return IRQ_HANDLED; -} - -static int at91_mci_get_ro(struct mmc_host *mmc) -{ - struct at91mci_host *host = mmc_priv(mmc); - - if (gpio_is_valid(host->board->wp_pin)) - return !!gpio_get_value(host->board->wp_pin); - /* - * Board doesn't support read only detection; let the mmc core - * decide what to do. - */ - return -ENOSYS; -} - -static void at91_mci_enable_sdio_irq(struct mmc_host *mmc, int enable) -{ - struct at91mci_host *host = mmc_priv(mmc); - - pr_debug("%s: sdio_irq %c : %s\n", mmc_hostname(host->mmc), - host->board->slot_b ? 'B':'A', enable ? "enable" : "disable"); - at91_mci_write(host, enable ? AT91_MCI_IER : AT91_MCI_IDR, - host->board->slot_b ? AT91_MCI_SDIOIRQB : AT91_MCI_SDIOIRQA); - -} - -static const struct mmc_host_ops at91_mci_ops = { - .request = at91_mci_request, - .set_ios = at91_mci_set_ios, - .get_ro = at91_mci_get_ro, - .enable_sdio_irq = at91_mci_enable_sdio_irq, -}; - -/* - * Probe for the device - */ -static int __init at91_mci_probe(struct platform_device *pdev) -{ - struct mmc_host *mmc; - struct at91mci_host *host; - struct resource *res; - int ret; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) - return -ENXIO; - - if (!request_mem_region(res->start, resource_size(res), DRIVER_NAME)) - return -EBUSY; - - mmc = mmc_alloc_host(sizeof(struct at91mci_host), &pdev->dev); - if (!mmc) { - ret = -ENOMEM; - dev_dbg(&pdev->dev, "couldn't allocate mmc host\n"); - goto fail6; - } - - mmc->ops = &at91_mci_ops; - mmc->f_min = 375000; - mmc->f_max = 25000000; - mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; - mmc->caps = 0; - - mmc->max_blk_size = MCI_MAXBLKSIZE; - mmc->max_blk_count = MCI_BLKATONCE; - mmc->max_req_size = MCI_BUFSIZE; - mmc->max_segs = MCI_BLKATONCE; - mmc->max_seg_size = MCI_BUFSIZE; - - host = mmc_priv(mmc); - host->mmc = mmc; - host->bus_mode = 0; - host->board = pdev->dev.platform_data; - if (host->board->wire4) { - if (at91mci_is_mci1rev2xx()) - mmc->caps |= MMC_CAP_4_BIT_DATA; - else - dev_warn(&pdev->dev, "4 wire bus mode not supported" - " - using 1 wire\n"); - } - - host->buffer = dma_alloc_coherent(&pdev->dev, MCI_BUFSIZE, - &host->physical_address, GFP_KERNEL); - if (!host->buffer) { - ret = -ENOMEM; - dev_err(&pdev->dev, "Can't allocate transmit buffer\n"); - goto fail5; - } - - /* Add SDIO capability when available */ - if (at91mci_is_mci1rev2xx()) { - /* at91mci MCI1 rev2xx sdio interrupt erratum */ - if (host->board->wire4 || !host->board->slot_b) - mmc->caps |= MMC_CAP_SDIO_IRQ; - } - - /* - * Reserve GPIOs ... board init code makes sure these pins are set - * up as GPIOs with the right direction (input, except for vcc) - */ - if (gpio_is_valid(host->board->det_pin)) { - ret = gpio_request(host->board->det_pin, "mmc_detect"); - if (ret < 0) { - dev_dbg(&pdev->dev, "couldn't claim card detect pin\n"); - goto fail4b; - } - } - if (gpio_is_valid(host->board->wp_pin)) { - ret = gpio_request(host->board->wp_pin, "mmc_wp"); - if (ret < 0) { - dev_dbg(&pdev->dev, "couldn't claim wp sense pin\n"); - goto fail4; - } - } - if (gpio_is_valid(host->board->vcc_pin)) { - ret = gpio_request(host->board->vcc_pin, "mmc_vcc"); - if (ret < 0) { - dev_dbg(&pdev->dev, "couldn't claim vcc switch pin\n"); - goto fail3; - } - } - - /* - * Get Clock - */ - host->mci_clk = clk_get(&pdev->dev, "mci_clk"); - if (IS_ERR(host->mci_clk)) { - ret = -ENODEV; - dev_dbg(&pdev->dev, "no mci_clk?\n"); - goto fail2; - } - - /* - * Map I/O region - */ - host->baseaddr = ioremap(res->start, resource_size(res)); - if (!host->baseaddr) { - ret = -ENOMEM; - goto fail1; - } - - /* - * Reset hardware - */ - clk_enable(host->mci_clk); /* Enable the peripheral clock */ - at91_mci_disable(host); - at91_mci_enable(host); - - /* - * Allocate the MCI interrupt - */ - host->irq = platform_get_irq(pdev, 0); - ret = request_irq(host->irq, at91_mci_irq, IRQF_SHARED, - mmc_hostname(mmc), host); - if (ret) { - dev_dbg(&pdev->dev, "request MCI interrupt failed\n"); - goto fail0; - } - - setup_timer(&host->timer, at91_timeout_timer, (unsigned long)host); - - platform_set_drvdata(pdev, mmc); - - /* - * Add host to MMC layer - */ - if (gpio_is_valid(host->board->det_pin)) { - host->present = !gpio_get_value(host->board->det_pin); - } - else - host->present = -1; - - mmc_add_host(mmc); - - /* - * monitor card insertion/removal if we can - */ - if (gpio_is_valid(host->board->det_pin)) { - ret = request_irq(gpio_to_irq(host->board->det_pin), - at91_mmc_det_irq, 0, mmc_hostname(mmc), host); - if (ret) - dev_warn(&pdev->dev, "request MMC detect irq failed\n"); - else - device_init_wakeup(&pdev->dev, 1); - } - - pr_debug("Added MCI driver\n"); - - return 0; - -fail0: - clk_disable(host->mci_clk); - iounmap(host->baseaddr); -fail1: - clk_put(host->mci_clk); -fail2: - if (gpio_is_valid(host->board->vcc_pin)) - gpio_free(host->board->vcc_pin); -fail3: - if (gpio_is_valid(host->board->wp_pin)) - gpio_free(host->board->wp_pin); -fail4: - if (gpio_is_valid(host->board->det_pin)) - gpio_free(host->board->det_pin); -fail4b: - if (host->buffer) - dma_free_coherent(&pdev->dev, MCI_BUFSIZE, - host->buffer, host->physical_address); -fail5: - mmc_free_host(mmc); -fail6: - release_mem_region(res->start, resource_size(res)); - dev_err(&pdev->dev, "probe failed, err %d\n", ret); - return ret; -} - -/* - * Remove a device - */ -static int __exit at91_mci_remove(struct platform_device *pdev) -{ - struct mmc_host *mmc = platform_get_drvdata(pdev); - struct at91mci_host *host; - struct resource *res; - - if (!mmc) - return -1; - - host = mmc_priv(mmc); - - if (host->buffer) - dma_free_coherent(&pdev->dev, MCI_BUFSIZE, - host->buffer, host->physical_address); - - if (gpio_is_valid(host->board->det_pin)) { - if (device_can_wakeup(&pdev->dev)) - free_irq(gpio_to_irq(host->board->det_pin), host); - device_init_wakeup(&pdev->dev, 0); - gpio_free(host->board->det_pin); - } - - at91_mci_disable(host); - del_timer_sync(&host->timer); - mmc_remove_host(mmc); - free_irq(host->irq, host); - - clk_disable(host->mci_clk); /* Disable the peripheral clock */ - clk_put(host->mci_clk); - - if (gpio_is_valid(host->board->vcc_pin)) - gpio_free(host->board->vcc_pin); - if (gpio_is_valid(host->board->wp_pin)) - gpio_free(host->board->wp_pin); - - iounmap(host->baseaddr); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - release_mem_region(res->start, resource_size(res)); - - mmc_free_host(mmc); - platform_set_drvdata(pdev, NULL); - pr_debug("MCI Removed\n"); - - return 0; -} - -#ifdef CONFIG_PM -static int at91_mci_suspend(struct platform_device *pdev, pm_message_t state) -{ - struct mmc_host *mmc = platform_get_drvdata(pdev); - struct at91mci_host *host = mmc_priv(mmc); - int ret = 0; - - if (gpio_is_valid(host->board->det_pin) && device_may_wakeup(&pdev->dev)) - enable_irq_wake(host->board->det_pin); - - if (mmc) - ret = mmc_suspend_host(mmc); - - return ret; -} - -static int at91_mci_resume(struct platform_device *pdev) -{ - struct mmc_host *mmc = platform_get_drvdata(pdev); - struct at91mci_host *host = mmc_priv(mmc); - int ret = 0; - - if (gpio_is_valid(host->board->det_pin) && device_may_wakeup(&pdev->dev)) - disable_irq_wake(host->board->det_pin); - - if (mmc) - ret = mmc_resume_host(mmc); - - return ret; -} -#else -#define at91_mci_suspend NULL -#define at91_mci_resume NULL -#endif - -static struct platform_driver at91_mci_driver = { - .remove = __exit_p(at91_mci_remove), - .suspend = at91_mci_suspend, - .resume = at91_mci_resume, - .driver = { - .name = DRIVER_NAME, - .owner = THIS_MODULE, - }, -}; - -static int __init at91_mci_init(void) -{ - return platform_driver_probe(&at91_mci_driver, at91_mci_probe); -} - -static void __exit at91_mci_exit(void) -{ - platform_driver_unregister(&at91_mci_driver); -} - -module_init(at91_mci_init); -module_exit(at91_mci_exit); - -MODULE_DESCRIPTION("AT91 Multimedia Card Interface driver"); -MODULE_AUTHOR("Nick Randell"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:at91_mci"); diff --git a/ANDROID_3.4.5/drivers/mmc/host/at91_mci.h b/ANDROID_3.4.5/drivers/mmc/host/at91_mci.h deleted file mode 100644 index eec3a6b1..00000000 --- a/ANDROID_3.4.5/drivers/mmc/host/at91_mci.h +++ /dev/null @@ -1,115 +0,0 @@ -/* - * drivers/mmc/host/at91_mci.h - * - * Copyright (C) 2005 Ivan Kokshaysky - * Copyright (C) SAN People - * - * MultiMedia Card Interface (MCI) registers. - * Based on AT91RM9200 datasheet revision F. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - -#ifndef AT91_MCI_H -#define AT91_MCI_H - -#define AT91_MCI_CR 0x00 /* Control Register */ -#define AT91_MCI_MCIEN (1 << 0) /* Multi-Media Interface Enable */ -#define AT91_MCI_MCIDIS (1 << 1) /* Multi-Media Interface Disable */ -#define AT91_MCI_PWSEN (1 << 2) /* Power Save Mode Enable */ -#define AT91_MCI_PWSDIS (1 << 3) /* Power Save Mode Disable */ -#define AT91_MCI_SWRST (1 << 7) /* Software Reset */ - -#define AT91_MCI_MR 0x04 /* Mode Register */ -#define AT91_MCI_CLKDIV (0xff << 0) /* Clock Divider */ -#define AT91_MCI_PWSDIV (7 << 8) /* Power Saving Divider */ -#define AT91_MCI_RDPROOF (1 << 11) /* Read Proof Enable [SAM926[03] only] */ -#define AT91_MCI_WRPROOF (1 << 12) /* Write Proof Enable [SAM926[03] only] */ -#define AT91_MCI_PDCFBYTE (1 << 13) /* PDC Force Byte Transfer [SAM926[03] only] */ -#define AT91_MCI_PDCPADV (1 << 14) /* PDC Padding Value */ -#define AT91_MCI_PDCMODE (1 << 15) /* PDC-orientated Mode */ -#define AT91_MCI_BLKLEN (0xfff << 18) /* Data Block Length */ - -#define AT91_MCI_DTOR 0x08 /* Data Timeout Register */ -#define AT91_MCI_DTOCYC (0xf << 0) /* Data Timeout Cycle Number */ -#define AT91_MCI_DTOMUL (7 << 4) /* Data Timeout Multiplier */ -#define AT91_MCI_DTOMUL_1 (0 << 4) -#define AT91_MCI_DTOMUL_16 (1 << 4) -#define AT91_MCI_DTOMUL_128 (2 << 4) -#define AT91_MCI_DTOMUL_256 (3 << 4) -#define AT91_MCI_DTOMUL_1K (4 << 4) -#define AT91_MCI_DTOMUL_4K (5 << 4) -#define AT91_MCI_DTOMUL_64K (6 << 4) -#define AT91_MCI_DTOMUL_1M (7 << 4) - -#define AT91_MCI_SDCR 0x0c /* SD Card Register */ -#define AT91_MCI_SDCSEL (3 << 0) /* SD Card Selector */ -#define AT91_MCI_SDCBUS (1 << 7) /* 1-bit or 4-bit bus */ - -#define AT91_MCI_ARGR 0x10 /* Argument Register */ - -#define AT91_MCI_CMDR 0x14 /* Command Register */ -#define AT91_MCI_CMDNB (0x3f << 0) /* Command Number */ -#define AT91_MCI_RSPTYP (3 << 6) /* Response Type */ -#define AT91_MCI_RSPTYP_NONE (0 << 6) -#define AT91_MCI_RSPTYP_48 (1 << 6) -#define AT91_MCI_RSPTYP_136 (2 << 6) -#define AT91_MCI_SPCMD (7 << 8) /* Special Command */ -#define AT91_MCI_SPCMD_NONE (0 << 8) -#define AT91_MCI_SPCMD_INIT (1 << 8) -#define AT91_MCI_SPCMD_SYNC (2 << 8) -#define AT91_MCI_SPCMD_ICMD (4 << 8) -#define AT91_MCI_SPCMD_IRESP (5 << 8) -#define AT91_MCI_OPDCMD (1 << 11) /* Open Drain Command */ -#define AT91_MCI_MAXLAT (1 << 12) /* Max Latency for Command to Response */ -#define AT91_MCI_TRCMD (3 << 16) /* Transfer Command */ -#define AT91_MCI_TRCMD_NONE (0 << 16) -#define AT91_MCI_TRCMD_START (1 << 16) -#define AT91_MCI_TRCMD_STOP (2 << 16) -#define AT91_MCI_TRDIR (1 << 18) /* Transfer Direction */ -#define AT91_MCI_TRTYP (3 << 19) /* Transfer Type */ -#define AT91_MCI_TRTYP_BLOCK (0 << 19) -#define AT91_MCI_TRTYP_MULTIPLE (1 << 19) -#define AT91_MCI_TRTYP_STREAM (2 << 19) -#define AT91_MCI_TRTYP_SDIO_BYTE (4 << 19) -#define AT91_MCI_TRTYP_SDIO_BLOCK (5 << 19) - -#define AT91_MCI_BLKR 0x18 /* Block Register */ -#define AT91_MCI_BLKR_BCNT(n) ((0xffff & (n)) << 0) /* Block count */ -#define AT91_MCI_BLKR_BLKLEN(n) ((0xffff & (n)) << 16) /* Block length */ - -#define AT91_MCI_RSPR(n) (0x20 + ((n) * 4)) /* Response Registers 0-3 */ -#define AT91_MCR_RDR 0x30 /* Receive Data Register */ -#define AT91_MCR_TDR 0x34 /* Transmit Data Register */ - -#define AT91_MCI_SR 0x40 /* Status Register */ -#define AT91_MCI_CMDRDY (1 << 0) /* Command Ready */ -#define AT91_MCI_RXRDY (1 << 1) /* Receiver Ready */ -#define AT91_MCI_TXRDY (1 << 2) /* Transmit Ready */ -#define AT91_MCI_BLKE (1 << 3) /* Data Block Ended */ -#define AT91_MCI_DTIP (1 << 4) /* Data Transfer in Progress */ -#define AT91_MCI_NOTBUSY (1 << 5) /* Data Not Busy */ -#define AT91_MCI_ENDRX (1 << 6) /* End of RX Buffer */ -#define AT91_MCI_ENDTX (1 << 7) /* End fo TX Buffer */ -#define AT91_MCI_SDIOIRQA (1 << 8) /* SDIO Interrupt for Slot A */ -#define AT91_MCI_SDIOIRQB (1 << 9) /* SDIO Interrupt for Slot B */ -#define AT91_MCI_RXBUFF (1 << 14) /* RX Buffer Full */ -#define AT91_MCI_TXBUFE (1 << 15) /* TX Buffer Empty */ -#define AT91_MCI_RINDE (1 << 16) /* Response Index Error */ -#define AT91_MCI_RDIRE (1 << 17) /* Response Direction Error */ -#define AT91_MCI_RCRCE (1 << 18) /* Response CRC Error */ -#define AT91_MCI_RENDE (1 << 19) /* Response End Bit Error */ -#define AT91_MCI_RTOE (1 << 20) /* Response Time-out Error */ -#define AT91_MCI_DCRCE (1 << 21) /* Data CRC Error */ -#define AT91_MCI_DTOE (1 << 22) /* Data Time-out Error */ -#define AT91_MCI_OVRE (1 << 30) /* Overrun */ -#define AT91_MCI_UNRE (1 << 31) /* Underrun */ - -#define AT91_MCI_IER 0x44 /* Interrupt Enable Register */ -#define AT91_MCI_IDR 0x48 /* Interrupt Disable Register */ -#define AT91_MCI_IMR 0x4c /* Interrupt Mask Register */ - -#endif diff --git a/ANDROID_3.4.5/drivers/mmc/host/atmel-mci-regs.h b/ANDROID_3.4.5/drivers/mmc/host/atmel-mci-regs.h deleted file mode 100644 index 787aba16..00000000 --- a/ANDROID_3.4.5/drivers/mmc/host/atmel-mci-regs.h +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Atmel MultiMedia Card Interface driver - * - * Copyright (C) 2004-2006 Atmel Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -/* - * Superset of MCI IP registers integrated in Atmel AVR32 and AT91 Processors - * Registers and bitfields marked with [2] are only available in MCI2 - */ - -#ifndef __DRIVERS_MMC_ATMEL_MCI_H__ -#define __DRIVERS_MMC_ATMEL_MCI_H__ - -/* MCI Register Definitions */ -#define ATMCI_CR 0x0000 /* Control */ -# define ATMCI_CR_MCIEN ( 1 << 0) /* MCI Enable */ -# define ATMCI_CR_MCIDIS ( 1 << 1) /* MCI Disable */ -# define ATMCI_CR_PWSEN ( 1 << 2) /* Power Save Enable */ -# define ATMCI_CR_PWSDIS ( 1 << 3) /* Power Save Disable */ -# define ATMCI_CR_SWRST ( 1 << 7) /* Software Reset */ -#define ATMCI_MR 0x0004 /* Mode */ -# define ATMCI_MR_CLKDIV(x) ((x) << 0) /* Clock Divider */ -# define ATMCI_MR_PWSDIV(x) ((x) << 8) /* Power Saving Divider */ -# define ATMCI_MR_RDPROOF ( 1 << 11) /* Read Proof */ -# define ATMCI_MR_WRPROOF ( 1 << 12) /* Write Proof */ -# define ATMCI_MR_PDCFBYTE ( 1 << 13) /* Force Byte Transfer */ -# define ATMCI_MR_PDCPADV ( 1 << 14) /* Padding Value */ -# define ATMCI_MR_PDCMODE ( 1 << 15) /* PDC-oriented Mode */ -# define ATMCI_MR_CLKODD(x) ((x) << 16) /* LSB of Clock Divider */ -#define ATMCI_DTOR 0x0008 /* Data Timeout */ -# define ATMCI_DTOCYC(x) ((x) << 0) /* Data Timeout Cycles */ -# define ATMCI_DTOMUL(x) ((x) << 4) /* Data Timeout Multiplier */ -#define ATMCI_SDCR 0x000c /* SD Card / SDIO */ -# define ATMCI_SDCSEL_SLOT_A ( 0 << 0) /* Select SD slot A */ -# define ATMCI_SDCSEL_SLOT_B ( 1 << 0) /* Select SD slot A */ -# define ATMCI_SDCSEL_MASK ( 3 << 0) -# define ATMCI_SDCBUS_1BIT ( 0 << 6) /* 1-bit data bus */ -# define ATMCI_SDCBUS_4BIT ( 2 << 6) /* 4-bit data bus */ -# define ATMCI_SDCBUS_8BIT ( 3 << 6) /* 8-bit data bus[2] */ -# define ATMCI_SDCBUS_MASK ( 3 << 6) -#define ATMCI_ARGR 0x0010 /* Command Argument */ -#define ATMCI_CMDR 0x0014 /* Command */ -# define ATMCI_CMDR_CMDNB(x) ((x) << 0) /* Command Opcode */ -# define ATMCI_CMDR_RSPTYP_NONE ( 0 << 6) /* No response */ -# define ATMCI_CMDR_RSPTYP_48BIT ( 1 << 6) /* 48-bit response */ -# define ATMCI_CMDR_RSPTYP_136BIT ( 2 << 6) /* 136-bit response */ -# define ATMCI_CMDR_SPCMD_INIT ( 1 << 8) /* Initialization command */ -# define ATMCI_CMDR_SPCMD_SYNC ( 2 << 8) /* Synchronized command */ -# define ATMCI_CMDR_SPCMD_INT ( 4 << 8) /* Interrupt command */ -# define ATMCI_CMDR_SPCMD_INTRESP ( 5 << 8) /* Interrupt response */ -# define ATMCI_CMDR_OPDCMD ( 1 << 11) /* Open Drain */ -# define ATMCI_CMDR_MAXLAT_5CYC ( 0 << 12) /* Max latency 5 cycles */ -# define ATMCI_CMDR_MAXLAT_64CYC ( 1 << 12) /* Max latency 64 cycles */ -# define ATMCI_CMDR_START_XFER ( 1 << 16) /* Start data transfer */ -# define ATMCI_CMDR_STOP_XFER ( 2 << 16) /* Stop data transfer */ -# define ATMCI_CMDR_TRDIR_WRITE ( 0 << 18) /* Write data */ -# define ATMCI_CMDR_TRDIR_READ ( 1 << 18) /* Read data */ -# define ATMCI_CMDR_BLOCK ( 0 << 19) /* Single-block transfer */ -# define ATMCI_CMDR_MULTI_BLOCK ( 1 << 19) /* Multi-block transfer */ -# define ATMCI_CMDR_STREAM ( 2 << 19) /* MMC Stream transfer */ -# define ATMCI_CMDR_SDIO_BYTE ( 4 << 19) /* SDIO Byte transfer */ -# define ATMCI_CMDR_SDIO_BLOCK ( 5 << 19) /* SDIO Block transfer */ -# define ATMCI_CMDR_SDIO_SUSPEND ( 1 << 24) /* SDIO Suspend Command */ -# define ATMCI_CMDR_SDIO_RESUME ( 2 << 24) /* SDIO Resume Command */ -#define ATMCI_BLKR 0x0018 /* Block */ -# define ATMCI_BCNT(x) ((x) << 0) /* Data Block Count */ -# define ATMCI_BLKLEN(x) ((x) << 16) /* Data Block Length */ -#define ATMCI_CSTOR 0x001c /* Completion Signal Timeout[2] */ -# define ATMCI_CSTOCYC(x) ((x) << 0) /* CST cycles */ -# define ATMCI_CSTOMUL(x) ((x) << 4) /* CST multiplier */ -#define ATMCI_RSPR 0x0020 /* Response 0 */ -#define ATMCI_RSPR1 0x0024 /* Response 1 */ -#define ATMCI_RSPR2 0x0028 /* Response 2 */ -#define ATMCI_RSPR3 0x002c /* Response 3 */ -#define ATMCI_RDR 0x0030 /* Receive Data */ -#define ATMCI_TDR 0x0034 /* Transmit Data */ -#define ATMCI_SR 0x0040 /* Status */ -#define ATMCI_IER 0x0044 /* Interrupt Enable */ -#define ATMCI_IDR 0x0048 /* Interrupt Disable */ -#define ATMCI_IMR 0x004c /* Interrupt Mask */ -# define ATMCI_CMDRDY ( 1 << 0) /* Command Ready */ -# define ATMCI_RXRDY ( 1 << 1) /* Receiver Ready */ -# define ATMCI_TXRDY ( 1 << 2) /* Transmitter Ready */ -# define ATMCI_BLKE ( 1 << 3) /* Data Block Ended */ -# define ATMCI_DTIP ( 1 << 4) /* Data Transfer In Progress */ -# define ATMCI_NOTBUSY ( 1 << 5) /* Data Not Busy */ -# define ATMCI_ENDRX ( 1 << 6) /* End of RX Buffer */ -# define ATMCI_ENDTX ( 1 << 7) /* End of TX Buffer */ -# define ATMCI_SDIOIRQA ( 1 << 8) /* SDIO IRQ in slot A */ -# define ATMCI_SDIOIRQB ( 1 << 9) /* SDIO IRQ in slot B */ -# define ATMCI_SDIOWAIT ( 1 << 12) /* SDIO Read Wait Operation Status */ -# define ATMCI_CSRCV ( 1 << 13) /* CE-ATA Completion Signal Received */ -# define ATMCI_RXBUFF ( 1 << 14) /* RX Buffer Full */ -# define ATMCI_TXBUFE ( 1 << 15) /* TX Buffer Empty */ -# define ATMCI_RINDE ( 1 << 16) /* Response Index Error */ -# define ATMCI_RDIRE ( 1 << 17) /* Response Direction Error */ -# define ATMCI_RCRCE ( 1 << 18) /* Response CRC Error */ -# define ATMCI_RENDE ( 1 << 19) /* Response End Bit Error */ -# define ATMCI_RTOE ( 1 << 20) /* Response Time-Out Error */ -# define ATMCI_DCRCE ( 1 << 21) /* Data CRC Error */ -# define ATMCI_DTOE ( 1 << 22) /* Data Time-Out Error */ -# define ATMCI_CSTOE ( 1 << 23) /* Completion Signal Time-out Error */ -# define ATMCI_BLKOVRE ( 1 << 24) /* DMA Block Overrun Error */ -# define ATMCI_DMADONE ( 1 << 25) /* DMA Transfer Done */ -# define ATMCI_FIFOEMPTY ( 1 << 26) /* FIFO Empty Flag */ -# define ATMCI_XFRDONE ( 1 << 27) /* Transfer Done Flag */ -# define ATMCI_ACKRCV ( 1 << 28) /* Boot Operation Acknowledge Received */ -# define ATMCI_ACKRCVE ( 1 << 29) /* Boot Operation Acknowledge Error */ -# define ATMCI_OVRE ( 1 << 30) /* RX Overrun Error */ -# define ATMCI_UNRE ( 1 << 31) /* TX Underrun Error */ -#define ATMCI_DMA 0x0050 /* DMA Configuration[2] */ -# define ATMCI_DMA_OFFSET(x) ((x) << 0) /* DMA Write Buffer Offset */ -# define ATMCI_DMA_CHKSIZE(x) ((x) << 4) /* DMA Channel Read and Write Chunk Size */ -# define ATMCI_DMAEN ( 1 << 8) /* DMA Hardware Handshaking Enable */ -#define ATMCI_CFG 0x0054 /* Configuration[2] */ -# define ATMCI_CFG_FIFOMODE_1DATA ( 1 << 0) /* MCI Internal FIFO control mode */ -# define ATMCI_CFG_FERRCTRL_COR ( 1 << 4) /* Flow Error flag reset control mode */ -# define ATMCI_CFG_HSMODE ( 1 << 8) /* High Speed Mode */ -# define ATMCI_CFG_LSYNC ( 1 << 12) /* Synchronize on the last block */ -#define ATMCI_WPMR 0x00e4 /* Write Protection Mode[2] */ -# define ATMCI_WP_EN ( 1 << 0) /* WP Enable */ -# define ATMCI_WP_KEY (0x4d4349 << 8) /* WP Key */ -#define ATMCI_WPSR 0x00e8 /* Write Protection Status[2] */ -# define ATMCI_GET_WP_VS(x) ((x) & 0x0f) -# define ATMCI_GET_WP_VSRC(x) (((x) >> 8) & 0xffff) -#define ATMCI_VERSION 0x00FC /* Version */ -#define ATMCI_FIFO_APERTURE 0x0200 /* FIFO Aperture[2] */ - -/* This is not including the FIFO Aperture on MCI2 */ -#define ATMCI_REGS_SIZE 0x100 - -/* Register access macros */ -#define atmci_readl(port,reg) \ - __raw_readl((port)->regs + reg) -#define atmci_writel(port,reg,value) \ - __raw_writel((value), (port)->regs + reg) - -#endif /* __DRIVERS_MMC_ATMEL_MCI_H__ */ diff --git a/ANDROID_3.4.5/drivers/mmc/host/atmel-mci.c b/ANDROID_3.4.5/drivers/mmc/host/atmel-mci.c deleted file mode 100644 index e94476be..00000000 --- a/ANDROID_3.4.5/drivers/mmc/host/atmel-mci.c +++ /dev/null @@ -1,2291 +0,0 @@ -/* - * Atmel MultiMedia Card Interface driver - * - * Copyright (C) 2004-2008 Atmel Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ -#include <linux/blkdev.h> -#include <linux/clk.h> -#include <linux/debugfs.h> -#include <linux/device.h> -#include <linux/dmaengine.h> -#include <linux/dma-mapping.h> -#include <linux/err.h> -#include <linux/gpio.h> -#include <linux/init.h> -#include <linux/interrupt.h> -#include <linux/ioport.h> -#include <linux/module.h> -#include <linux/platform_device.h> -#include <linux/scatterlist.h> -#include <linux/seq_file.h> -#include <linux/slab.h> -#include <linux/stat.h> -#include <linux/types.h> - -#include <linux/mmc/host.h> -#include <linux/mmc/sdio.h> - -#include <mach/atmel-mci.h> -#include <linux/atmel-mci.h> -#include <linux/atmel_pdc.h> - -#include <asm/io.h> -#include <asm/unaligned.h> - -#include <mach/cpu.h> -#include <mach/board.h> - -#include "atmel-mci-regs.h" - -#define ATMCI_DATA_ERROR_FLAGS (ATMCI_DCRCE | ATMCI_DTOE | ATMCI_OVRE | ATMCI_UNRE) -#define ATMCI_DMA_THRESHOLD 16 - -enum { - EVENT_CMD_COMPLETE = 0, - EVENT_XFER_COMPLETE, - EVENT_DATA_COMPLETE, - EVENT_DATA_ERROR, -}; - -enum atmel_mci_state { - STATE_IDLE = 0, - STATE_SENDING_CMD, - STATE_SENDING_DATA, - STATE_DATA_BUSY, - STATE_SENDING_STOP, - STATE_DATA_ERROR, -}; - -enum atmci_xfer_dir { - XFER_RECEIVE = 0, - XFER_TRANSMIT, -}; - -enum atmci_pdc_buf { - PDC_FIRST_BUF = 0, - PDC_SECOND_BUF, -}; - -struct atmel_mci_caps { - bool has_dma; - bool has_pdc; - bool has_cfg_reg; - bool has_cstor_reg; - bool has_highspeed; - bool has_rwproof; - bool has_odd_clk_div; -}; - -struct atmel_mci_dma { - struct dma_chan *chan; - struct dma_async_tx_descriptor *data_desc; -}; - -/** - * struct atmel_mci - MMC controller state shared between all slots - * @lock: Spinlock protecting the queue and associated data. - * @regs: Pointer to MMIO registers. - * @sg: Scatterlist entry currently being processed by PIO or PDC code. - * @pio_offset: Offset into the current scatterlist entry. - * @cur_slot: The slot which is currently using the controller. - * @mrq: The request currently being processed on @cur_slot, - * or NULL if the controller is idle. - * @cmd: The command currently being sent to the card, or NULL. - * @data: The data currently being transferred, or NULL if no data - * transfer is in progress. - * @data_size: just data->blocks * data->blksz. - * @dma: DMA client state. - * @data_chan: DMA channel being used for the current data transfer. - * @cmd_status: Snapshot of SR taken upon completion of the current - * command. Only valid when EVENT_CMD_COMPLETE is pending. - * @data_status: Snapshot of SR taken upon completion of the current - * data transfer. Only valid when EVENT_DATA_COMPLETE or - * EVENT_DATA_ERROR is pending. - * @stop_cmdr: Value to be loaded into CMDR when the stop command is - * to be sent. - * @tasklet: Tasklet running the request state machine. - * @pending_events: Bitmask of events flagged by the interrupt handler - * to be processed by the tasklet. - * @completed_events: Bitmask of events which the state machine has - * processed. - * @state: Tasklet state. - * @queue: List of slots waiting for access to the controller. - * @need_clock_update: Update the clock rate before the next request. - * @need_reset: Reset controller before next request. - * @mode_reg: Value of the MR register. - * @cfg_reg: Value of the CFG register. - * @bus_hz: The rate of @mck in Hz. This forms the basis for MMC bus - * rate and timeout calculations. - * @mapbase: Physical address of the MMIO registers. - * @mck: The peripheral bus clock hooked up to the MMC controller. - * @pdev: Platform device associated with the MMC controller. - * @slot: Slots sharing this MMC controller. - * @caps: MCI capabilities depending on MCI version. - * @prepare_data: function to setup MCI before data transfer which - * depends on MCI capabilities. - * @submit_data: function to start data transfer which depends on MCI - * capabilities. - * @stop_transfer: function to stop data transfer which depends on MCI - * capabilities. - * - * Locking - * ======= - * - * @lock is a softirq-safe spinlock protecting @queue as well as - * @cur_slot, @mrq and @state. These must always be updated - * at the same time while holding @lock. - * - * @lock also protects mode_reg and need_clock_update since these are - * used to synchronize mode register updates with the queue - * processing. - * - * The @mrq field of struct atmel_mci_slot is also protected by @lock, - * and must always be written at the same time as the slot is added to - * @queue. - * - * @pending_events and @completed_events are accessed using atomic bit - * operations, so they don't need any locking. - * - * None of the fields touched by the interrupt handler need any - * locking. However, ordering is important: Before EVENT_DATA_ERROR or - * EVENT_DATA_COMPLETE is set in @pending_events, all data-related - * interrupts must be disabled and @data_status updated with a - * snapshot of SR. Similarly, before EVENT_CMD_COMPLETE is set, the - * CMDRDY interrupt must be disabled and @cmd_status updated with a - * snapshot of SR, and before EVENT_XFER_COMPLETE can be set, the - * bytes_xfered field of @data must be written. This is ensured by - * using barriers. - */ -struct atmel_mci { - spinlock_t lock; - void __iomem *regs; - - struct scatterlist *sg; - unsigned int pio_offset; - - struct atmel_mci_slot *cur_slot; - struct mmc_request *mrq; - struct mmc_command *cmd; - struct mmc_data *data; - unsigned int data_size; - - struct atmel_mci_dma dma; - struct dma_chan *data_chan; - struct dma_slave_config dma_conf; - - u32 cmd_status; - u32 data_status; - u32 stop_cmdr; - - struct tasklet_struct tasklet; - unsigned long pending_events; - unsigned long completed_events; - enum atmel_mci_state state; - struct list_head queue; - - bool need_clock_update; - bool need_reset; - u32 mode_reg; - u32 cfg_reg; - unsigned long bus_hz; - unsigned long mapbase; - struct clk *mck; - struct platform_device *pdev; - - struct atmel_mci_slot *slot[ATMCI_MAX_NR_SLOTS]; - - struct atmel_mci_caps caps; - - u32 (*prepare_data)(struct atmel_mci *host, struct mmc_data *data); - void (*submit_data)(struct atmel_mci *host, struct mmc_data *data); - void (*stop_transfer)(struct atmel_mci *host); -}; - -/** - * struct atmel_mci_slot - MMC slot state - * @mmc: The mmc_host representing this slot. - * @host: The MMC controller this slot is using. - * @sdc_reg: Value of SDCR to be written before using this slot. - * @sdio_irq: SDIO irq mask for this slot. - * @mrq: mmc_request currently being processed or waiting to be - * processed, or NULL when the slot is idle. - * @queue_node: List node for placing this node in the @queue list of - * &struct atmel_mci. - * @clock: Clock rate configured by set_ios(). Protected by host->lock. - * @flags: Random state bits associated with the slot. - * @detect_pin: GPIO pin used for card detection, or negative if not - * available. - * @wp_pin: GPIO pin used for card write protect sending, or negative - * if not available. - * @detect_is_active_high: The state of the detect pin when it is active. - * @detect_timer: Timer used for debouncing @detect_pin interrupts. - */ -struct atmel_mci_slot { - struct mmc_host *mmc; - struct atmel_mci *host; - - u32 sdc_reg; - u32 sdio_irq; - - struct mmc_request *mrq; - struct list_head queue_node; - - unsigned int clock; - unsigned long flags; -#define ATMCI_CARD_PRESENT 0 -#define ATMCI_CARD_NEED_INIT 1 -#define ATMCI_SHUTDOWN 2 -#define ATMCI_SUSPENDED 3 - - int detect_pin; - int wp_pin; - bool detect_is_active_high; - - struct timer_list detect_timer; -}; - -#define atmci_test_and_clear_pending(host, event) \ - test_and_clear_bit(event, &host->pending_events) -#define atmci_set_completed(host, event) \ - set_bit(event, &host->completed_events) -#define atmci_set_pending(host, event) \ - set_bit(event, &host->pending_events) - -/* - * The debugfs stuff below is mostly optimized away when - * CONFIG_DEBUG_FS is not set. - */ -static int atmci_req_show(struct seq_file *s, void *v) -{ - struct atmel_mci_slot *slot = s->private; - struct mmc_request *mrq; - struct mmc_command *cmd; - struct mmc_command *stop; - struct mmc_data *data; - - /* Make sure we get a consistent snapshot */ - spin_lock_bh(&slot->host->lock); - mrq = slot->mrq; - - if (mrq) { - cmd = mrq->cmd; - data = mrq->data; - stop = mrq->stop; - - if (cmd) - seq_printf(s, - "CMD%u(0x%x) flg %x rsp %x %x %x %x err %d\n", - cmd->opcode, cmd->arg, cmd->flags, - cmd->resp[0], cmd->resp[1], cmd->resp[2], - cmd->resp[3], cmd->error); - if (data) - seq_printf(s, "DATA %u / %u * %u flg %x err %d\n", - data->bytes_xfered, data->blocks, - data->blksz, data->flags, data->error); - if (stop) - seq_printf(s, - "CMD%u(0x%x) flg %x rsp %x %x %x %x err %d\n", - stop->opcode, stop->arg, stop->flags, - stop->resp[0], stop->resp[1], stop->resp[2], - stop->resp[3], stop->error); - } - - spin_unlock_bh(&slot->host->lock); - - return 0; -} - -static int atmci_req_open(struct inode *inode, struct file *file) -{ - return single_open(file, atmci_req_show, inode->i_private); -} - -static const struct file_operations atmci_req_fops = { - .owner = THIS_MODULE, - .open = atmci_req_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static void atmci_show_status_reg(struct seq_file *s, - const char *regname, u32 value) -{ - static const char *sr_bit[] = { - [0] = "CMDRDY", - [1] = "RXRDY", - [2] = "TXRDY", - [3] = "BLKE", - [4] = "DTIP", - [5] = "NOTBUSY", - [6] = "ENDRX", - [7] = "ENDTX", - [8] = "SDIOIRQA", - [9] = "SDIOIRQB", - [12] = "SDIOWAIT", - [14] = "RXBUFF", - [15] = "TXBUFE", - [16] = "RINDE", - [17] = "RDIRE", - [18] = "RCRCE", - [19] = "RENDE", - [20] = "RTOE", - [21] = "DCRCE", - [22] = "DTOE", - [23] = "CSTOE", - [24] = "BLKOVRE", - [25] = "DMADONE", - [26] = "FIFOEMPTY", - [27] = "XFRDONE", - [30] = "OVRE", - [31] = "UNRE", - }; - unsigned int i; - - seq_printf(s, "%s:\t0x%08x", regname, value); - for (i = 0; i < ARRAY_SIZE(sr_bit); i++) { - if (value & (1 << i)) { - if (sr_bit[i]) - seq_printf(s, " %s", sr_bit[i]); - else - seq_puts(s, " UNKNOWN"); - } - } - seq_putc(s, '\n'); -} - -static int atmci_regs_show(struct seq_file *s, void *v) -{ - struct atmel_mci *host = s->private; - u32 *buf; - - buf = kmalloc(ATMCI_REGS_SIZE, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - /* - * Grab a more or less consistent snapshot. Note that we're - * not disabling interrupts, so IMR and SR may not be - * consistent. - */ - spin_lock_bh(&host->lock); - clk_enable(host->mck); - memcpy_fromio(buf, host->regs, ATMCI_REGS_SIZE); - clk_disable(host->mck); - spin_unlock_bh(&host->lock); - - seq_printf(s, "MR:\t0x%08x%s%s CLKDIV=%u\n", - buf[ATMCI_MR / 4], - buf[ATMCI_MR / 4] & ATMCI_MR_RDPROOF ? " RDPROOF" : "", - buf[ATMCI_MR / 4] & ATMCI_MR_WRPROOF ? " WRPROOF" : "", - buf[ATMCI_MR / 4] & 0xff); - seq_printf(s, "DTOR:\t0x%08x\n", buf[ATMCI_DTOR / 4]); - seq_printf(s, "SDCR:\t0x%08x\n", buf[ATMCI_SDCR / 4]); - seq_printf(s, "ARGR:\t0x%08x\n", buf[ATMCI_ARGR / 4]); - seq_printf(s, "BLKR:\t0x%08x BCNT=%u BLKLEN=%u\n", - buf[ATMCI_BLKR / 4], - buf[ATMCI_BLKR / 4] & 0xffff, - (buf[ATMCI_BLKR / 4] >> 16) & 0xffff); - if (host->caps.has_cstor_reg) - seq_printf(s, "CSTOR:\t0x%08x\n", buf[ATMCI_CSTOR / 4]); - - /* Don't read RSPR and RDR; it will consume the data there */ - - atmci_show_status_reg(s, "SR", buf[ATMCI_SR / 4]); - atmci_show_status_reg(s, "IMR", buf[ATMCI_IMR / 4]); - - if (host->caps.has_dma) { - u32 val; - - val = buf[ATMCI_DMA / 4]; - seq_printf(s, "DMA:\t0x%08x OFFSET=%u CHKSIZE=%u%s\n", - val, val & 3, - ((val >> 4) & 3) ? - 1 << (((val >> 4) & 3) + 1) : 1, - val & ATMCI_DMAEN ? " DMAEN" : ""); - } - if (host->caps.has_cfg_reg) { - u32 val; - - val = buf[ATMCI_CFG / 4]; - seq_printf(s, "CFG:\t0x%08x%s%s%s%s\n", - val, - val & ATMCI_CFG_FIFOMODE_1DATA ? " FIFOMODE_ONE_DATA" : "", - val & ATMCI_CFG_FERRCTRL_COR ? " FERRCTRL_CLEAR_ON_READ" : "", - val & ATMCI_CFG_HSMODE ? " HSMODE" : "", - val & ATMCI_CFG_LSYNC ? " LSYNC" : ""); - } - - kfree(buf); - - return 0; -} - -static int atmci_regs_open(struct inode *inode, struct file *file) -{ - return single_open(file, atmci_regs_show, inode->i_private); -} - -static const struct file_operations atmci_regs_fops = { - .owner = THIS_MODULE, - .open = atmci_regs_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static void atmci_init_debugfs(struct atmel_mci_slot *slot) -{ - struct mmc_host *mmc = slot->mmc; - struct atmel_mci *host = slot->host; - struct dentry *root; - struct dentry *node; - - root = mmc->debugfs_root; - if (!root) - return; - - node = debugfs_create_file("regs", S_IRUSR, root, host, - &atmci_regs_fops); - if (IS_ERR(node)) - return; - if (!node) - goto err; - - node = debugfs_create_file("req", S_IRUSR, root, slot, &atmci_req_fops); - if (!node) - goto err; - - node = debugfs_create_u32("state", S_IRUSR, root, (u32 *)&host->state); - if (!node) - goto err; - - node = debugfs_create_x32("pending_events", S_IRUSR, root, - (u32 *)&host->pending_events); - if (!node) - goto err; - - node = debugfs_create_x32("completed_events", S_IRUSR, root, - (u32 *)&host->completed_events); - if (!node) - goto err; - - return; - -err: - dev_err(&mmc->class_dev, "failed to initialize debugfs for slot\n"); -} - -static inline unsigned int atmci_ns_to_clocks(struct atmel_mci *host, - unsigned int ns) -{ - /* - * It is easier here to use us instead of ns for the timeout, - * it prevents from overflows during calculation. - */ - unsigned int us = DIV_ROUND_UP(ns, 1000); - - /* Maximum clock frequency is host->bus_hz/2 */ - return us * (DIV_ROUND_UP(host->bus_hz, 2000000)); -} - -static void atmci_set_timeout(struct atmel_mci *host, - struct atmel_mci_slot *slot, struct mmc_data *data) -{ - static unsigned dtomul_to_shift[] = { - 0, 4, 7, 8, 10, 12, 16, 20 - }; - unsigned timeout; - unsigned dtocyc; - unsigned dtomul; - - timeout = atmci_ns_to_clocks(host, data->timeout_ns) - + data->timeout_clks; - - for (dtomul = 0; dtomul < 8; dtomul++) { - unsigned shift = dtomul_to_shift[dtomul]; - dtocyc = (timeout + (1 << shift) - 1) >> shift; - if (dtocyc < 15) - break; - } - - if (dtomul >= 8) { - dtomul = 7; - dtocyc = 15; - } - - dev_vdbg(&slot->mmc->class_dev, "setting timeout to %u cycles\n", - dtocyc << dtomul_to_shift[dtomul]); - atmci_writel(host, ATMCI_DTOR, (ATMCI_DTOMUL(dtomul) | ATMCI_DTOCYC(dtocyc))); -} - -/* - * Return mask with command flags to be enabled for this command. - */ -static u32 atmci_prepare_command(struct mmc_host *mmc, - struct mmc_command *cmd) -{ - struct mmc_data *data; - u32 cmdr; - - cmd->error = -EINPROGRESS; - - cmdr = ATMCI_CMDR_CMDNB(cmd->opcode); - - if (cmd->flags & MMC_RSP_PRESENT) { - if (cmd->flags & MMC_RSP_136) - cmdr |= ATMCI_CMDR_RSPTYP_136BIT; - else - cmdr |= ATMCI_CMDR_RSPTYP_48BIT; - } - - /* - * This should really be MAXLAT_5 for CMD2 and ACMD41, but - * it's too difficult to determine whether this is an ACMD or - * not. Better make it 64. - */ - cmdr |= ATMCI_CMDR_MAXLAT_64CYC; - - if (mmc->ios.bus_mode == MMC_BUSMODE_OPENDRAIN) - cmdr |= ATMCI_CMDR_OPDCMD; - - data = cmd->data; - if (data) { - cmdr |= ATMCI_CMDR_START_XFER; - - if (cmd->opcode == SD_IO_RW_EXTENDED) { - cmdr |= ATMCI_CMDR_SDIO_BLOCK; - } else { - if (data->flags & MMC_DATA_STREAM) - cmdr |= ATMCI_CMDR_STREAM; - else if (data->blocks > 1) - cmdr |= ATMCI_CMDR_MULTI_BLOCK; - else - cmdr |= ATMCI_CMDR_BLOCK; - } - - if (data->flags & MMC_DATA_READ) - cmdr |= ATMCI_CMDR_TRDIR_READ; - } - - return cmdr; -} - -static void atmci_send_command(struct atmel_mci *host, - struct mmc_command *cmd, u32 cmd_flags) -{ - WARN_ON(host->cmd); - host->cmd = cmd; - - dev_vdbg(&host->pdev->dev, - "start command: ARGR=0x%08x CMDR=0x%08x\n", - cmd->arg, cmd_flags); - - atmci_writel(host, ATMCI_ARGR, cmd->arg); - atmci_writel(host, ATMCI_CMDR, cmd_flags); -} - -static void atmci_send_stop_cmd(struct atmel_mci *host, struct mmc_data *data) -{ - atmci_send_command(host, data->stop, host->stop_cmdr); - atmci_writel(host, ATMCI_IER, ATMCI_CMDRDY); -} - -/* - * Configure given PDC buffer taking care of alignement issues. - * Update host->data_size and host->sg. - */ -static void atmci_pdc_set_single_buf(struct atmel_mci *host, - enum atmci_xfer_dir dir, enum atmci_pdc_buf buf_nb) -{ - u32 pointer_reg, counter_reg; - - if (dir == XFER_RECEIVE) { - pointer_reg = ATMEL_PDC_RPR; - counter_reg = ATMEL_PDC_RCR; - } else { - pointer_reg = ATMEL_PDC_TPR; - counter_reg = ATMEL_PDC_TCR; - } - - if (buf_nb == PDC_SECOND_BUF) { - pointer_reg += ATMEL_PDC_SCND_BUF_OFF; - counter_reg += ATMEL_PDC_SCND_BUF_OFF; - } - - atmci_writel(host, pointer_reg, sg_dma_address(host->sg)); - if (host->data_size <= sg_dma_len(host->sg)) { - if (host->data_size & 0x3) { - /* If size is different from modulo 4, transfer bytes */ - atmci_writel(host, counter_reg, host->data_size); - atmci_writel(host, ATMCI_MR, host->mode_reg | ATMCI_MR_PDCFBYTE); - } else { - /* Else transfer 32-bits words */ - atmci_writel(host, counter_reg, host->data_size / 4); - } - host->data_size = 0; - } else { - /* We assume the size of a page is 32-bits aligned */ - atmci_writel(host, counter_reg, sg_dma_len(host->sg) / 4); - host->data_size -= sg_dma_len(host->sg); - if (host->data_size) - host->sg = sg_next(host->sg); - } -} - -/* - * Configure PDC buffer according to the data size ie configuring one or two - * buffers. Don't use this function if you want to configure only the second - * buffer. In this case, use atmci_pdc_set_single_buf. - */ -static void atmci_pdc_set_both_buf(struct atmel_mci *host, int dir) -{ - atmci_pdc_set_single_buf(host, dir, PDC_FIRST_BUF); - if (host->data_size) - atmci_pdc_set_single_buf(host, dir, PDC_SECOND_BUF); -} - -/* - * Unmap sg lists, called when transfer is finished. - */ -static void atmci_pdc_cleanup(struct atmel_mci *host) -{ - struct mmc_data *data = host->data; - - if (data) - dma_unmap_sg(&host->pdev->dev, - data->sg, data->sg_len, - ((data->flags & MMC_DATA_WRITE) - ? DMA_TO_DEVICE : DMA_FROM_DEVICE)); -} - -/* - * Disable PDC transfers. Update pending flags to EVENT_XFER_COMPLETE after - * having received ATMCI_TXBUFE or ATMCI_RXBUFF interrupt. Enable ATMCI_NOTBUSY - * interrupt needed for both transfer directions. - */ -static void atmci_pdc_complete(struct atmel_mci *host) -{ - atmci_writel(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTDIS | ATMEL_PDC_TXTDIS); - atmci_pdc_cleanup(host); - - /* - * If the card was removed, data will be NULL. No point trying - * to send the stop command or waiting for NBUSY in this case. - */ - if (host->data) { - atmci_set_pending(host, EVENT_XFER_COMPLETE); - tasklet_schedule(&host->tasklet); - atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY); - } -} - -static void atmci_dma_cleanup(struct atmel_mci *host) -{ - struct mmc_data *data = host->data; - - if (data) - dma_unmap_sg(host->dma.chan->device->dev, - data->sg, data->sg_len, - ((data->flags & MMC_DATA_WRITE) - ? DMA_TO_DEVICE : DMA_FROM_DEVICE)); -} - -/* - * This function is called by the DMA driver from tasklet context. - */ -static void atmci_dma_complete(void *arg) -{ - struct atmel_mci *host = arg; - struct mmc_data *data = host->data; - - dev_vdbg(&host->pdev->dev, "DMA complete\n"); - - if (host->caps.has_dma) - /* Disable DMA hardware handshaking on MCI */ - atmci_writel(host, ATMCI_DMA, atmci_readl(host, ATMCI_DMA) & ~ATMCI_DMAEN); - - atmci_dma_cleanup(host); - - /* - * If the card was removed, data will be NULL. No point trying - * to send the stop command or waiting for NBUSY in this case. - */ - if (data) { - atmci_set_pending(host, EVENT_XFER_COMPLETE); - tasklet_schedule(&host->tasklet); - - /* - * Regardless of what the documentation says, we have - * to wait for NOTBUSY even after block read - * operations. - * - * When the DMA transfer is complete, the controller - * may still be reading the CRC from the card, i.e. - * the data transfer is still in progress and we - * haven't seen all the potential error bits yet. - * - * The interrupt handler will schedule a different - * tasklet to finish things up when the data transfer - * is completely done. - * - * We may not complete the mmc request here anyway - * because the mmc layer may call back and cause us to - * violate the "don't submit new operations from the - * completion callback" rule of the dma engine - * framework. - */ - atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY); - } -} - -/* - * Returns a mask of interrupt flags to be enabled after the whole - * request has been prepared. - */ -static u32 atmci_prepare_data(struct atmel_mci *host, struct mmc_data *data) -{ - u32 iflags; - - data->error = -EINPROGRESS; - - host->sg = data->sg; - host->data = data; - host->data_chan = NULL; - - iflags = ATMCI_DATA_ERROR_FLAGS; - - /* - * Errata: MMC data write operation with less than 12 - * bytes is impossible. - * - * Errata: MCI Transmit Data Register (TDR) FIFO - * corruption when length is not multiple of 4. - */ - if (data->blocks * data->blksz < 12 - || (data->blocks * data->blksz) & 3) - host->need_reset = true; - - host->pio_offset = 0; - if (data->flags & MMC_DATA_READ) - iflags |= ATMCI_RXRDY; - else - iflags |= ATMCI_TXRDY; - - return iflags; -} - -/* - * Set interrupt flags and set block length into the MCI mode register even - * if this value is also accessible in the MCI block register. It seems to be - * necessary before the High Speed MCI version. It also map sg and configure - * PDC registers. - */ -static u32 -atmci_prepare_data_pdc(struct atmel_mci *host, struct mmc_data *data) -{ - u32 iflags, tmp; - unsigned int sg_len; - enum dma_data_direction dir; - - data->error = -EINPROGRESS; - - host->data = data; - host->sg = data->sg; - iflags = ATMCI_DATA_ERROR_FLAGS; - - /* Enable pdc mode */ - atmci_writel(host, ATMCI_MR, host->mode_reg | ATMCI_MR_PDCMODE); - - if (data->flags & MMC_DATA_READ) { - dir = DMA_FROM_DEVICE; - iflags |= ATMCI_ENDRX | ATMCI_RXBUFF; - } else { - dir = DMA_TO_DEVICE; - iflags |= ATMCI_ENDTX | ATMCI_TXBUFE; - } - - /* Set BLKLEN */ - tmp = atmci_readl(host, ATMCI_MR); - tmp &= 0x0000ffff; - tmp |= ATMCI_BLKLEN(data->blksz); - atmci_writel(host, ATMCI_MR, tmp); - - /* Configure PDC */ - host->data_size = data->blocks * data->blksz; - sg_len = dma_map_sg(&host->pdev->dev, data->sg, data->sg_len, dir); - if (host->data_size) - atmci_pdc_set_both_buf(host, - ((dir == DMA_FROM_DEVICE) ? XFER_RECEIVE : XFER_TRANSMIT)); - - return iflags; -} - -static u32 -atmci_prepare_data_dma(struct atmel_mci *host, struct mmc_data *data) -{ - struct dma_chan *chan; - struct dma_async_tx_descriptor *desc; - struct scatterlist *sg; - unsigned int i; - enum dma_data_direction direction; - enum dma_transfer_direction slave_dirn; - unsigned int sglen; - u32 iflags; - - data->error = -EINPROGRESS; - - WARN_ON(host->data); - host->sg = NULL; - host->data = data; - - iflags = ATMCI_DATA_ERROR_FLAGS; - - /* - * We don't do DMA on "complex" transfers, i.e. with - * non-word-aligned buffers or lengths. Also, we don't bother - * with all the DMA setup overhead for short transfers. - */ - if (data->blocks * data->blksz < ATMCI_DMA_THRESHOLD) - return atmci_prepare_data(host, data); - if (data->blksz & 3) - return atmci_prepare_data(host, data); - - for_each_sg(data->sg, sg, data->sg_len, i) { - if (sg->offset & 3 || sg->length & 3) - return atmci_prepare_data(host, data); - } - - /* If we don't have a channel, we can't do DMA */ - chan = host->dma.chan; - if (chan) - host->data_chan = chan; - - if (!chan) - return -ENODEV; - - if (host->caps.has_dma) - atmci_writel(host, ATMCI_DMA, ATMCI_DMA_CHKSIZE(3) | ATMCI_DMAEN); - - if (data->flags & MMC_DATA_READ) { - direction = DMA_FROM_DEVICE; - host->dma_conf.direction = slave_dirn = DMA_DEV_TO_MEM; - } else { - direction = DMA_TO_DEVICE; - host->dma_conf.direction = slave_dirn = DMA_MEM_TO_DEV; - } - - sglen = dma_map_sg(chan->device->dev, data->sg, - data->sg_len, direction); - - dmaengine_slave_config(chan, &host->dma_conf); - desc = dmaengine_prep_slave_sg(chan, - data->sg, sglen, slave_dirn, - DMA_PREP_INTERRUPT | DMA_CTRL_ACK); - if (!desc) - goto unmap_exit; - - host->dma.data_desc = desc; - desc->callback = atmci_dma_complete; - desc->callback_param = host; - - return iflags; -unmap_exit: - dma_unmap_sg(chan->device->dev, data->sg, data->sg_len, direction); - return -ENOMEM; -} - -static void -atmci_submit_data(struct atmel_mci *host, struct mmc_data *data) -{ - return; -} - -/* - * Start PDC according to transfer direction. - */ -static void -atmci_submit_data_pdc(struct atmel_mci *host, struct mmc_data *data) -{ - if (data->flags & MMC_DATA_READ) - atmci_writel(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTEN); - else - atmci_writel(host, ATMEL_PDC_PTCR, ATMEL_PDC_TXTEN); -} - -static void -atmci_submit_data_dma(struct atmel_mci *host, struct mmc_data *data) -{ - struct dma_chan *chan = host->data_chan; - struct dma_async_tx_descriptor *desc = host->dma.data_desc; - - if (chan) { - dmaengine_submit(desc); - dma_async_issue_pending(chan); - } -} - -static void atmci_stop_transfer(struct atmel_mci *host) -{ - atmci_set_pending(host, EVENT_XFER_COMPLETE); - atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY); -} - -/* - * Stop data transfer because error(s) occured. - */ -static void atmci_stop_transfer_pdc(struct atmel_mci *host) -{ - atmci_set_pending(host, EVENT_XFER_COMPLETE); - atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY); -} - -static void atmci_stop_transfer_dma(struct atmel_mci *host) -{ - struct dma_chan *chan = host->data_chan; - - if (chan) { - dmaengine_terminate_all(chan); - atmci_dma_cleanup(host); - } else { - /* Data transfer was stopped by the interrupt handler */ - atmci_set_pending(host, EVENT_XFER_COMPLETE); - atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY); - } -} - -/* - * Start a request: prepare data if needed, prepare the command and activate - * interrupts. - */ -static void atmci_start_request(struct atmel_mci *host, - struct atmel_mci_slot *slot) -{ - struct mmc_request *mrq; - struct mmc_command *cmd; - struct mmc_data *data; - u32 iflags; - u32 cmdflags; - - mrq = slot->mrq; - host->cur_slot = slot; - host->mrq = mrq; - - host->pending_events = 0; - host->completed_events = 0; - host->data_status = 0; - - if (host->need_reset) { - iflags = atmci_readl(host, ATMCI_IMR); - iflags &= (ATMCI_SDIOIRQA | ATMCI_SDIOIRQB); - atmci_writel(host, ATMCI_CR, ATMCI_CR_SWRST); - atmci_writel(host, ATMCI_CR, ATMCI_CR_MCIEN); - atmci_writel(host, ATMCI_MR, host->mode_reg); - if (host->caps.has_cfg_reg) - atmci_writel(host, ATMCI_CFG, host->cfg_reg); - atmci_writel(host, ATMCI_IER, iflags); - host->need_reset = false; - } - atmci_writel(host, ATMCI_SDCR, slot->sdc_reg); - - iflags = atmci_readl(host, ATMCI_IMR); - if (iflags & ~(ATMCI_SDIOIRQA | ATMCI_SDIOIRQB)) - dev_warn(&slot->mmc->class_dev, "WARNING: IMR=0x%08x\n", - iflags); - - if (unlikely(test_and_clear_bit(ATMCI_CARD_NEED_INIT, &slot->flags))) { - /* Send init sequence (74 clock cycles) */ - atmci_writel(host, ATMCI_CMDR, ATMCI_CMDR_SPCMD_INIT); - while (!(atmci_readl(host, ATMCI_SR) & ATMCI_CMDRDY)) - cpu_relax(); - } - iflags = 0; - data = mrq->data; - if (data) { - atmci_set_timeout(host, slot, data); - - /* Must set block count/size before sending command */ - atmci_writel(host, ATMCI_BLKR, ATMCI_BCNT(data->blocks) - | ATMCI_BLKLEN(data->blksz)); - dev_vdbg(&slot->mmc->class_dev, "BLKR=0x%08x\n", - ATMCI_BCNT(data->blocks) | ATMCI_BLKLEN(data->blksz)); - - iflags |= host->prepare_data(host, data); - } - - iflags |= ATMCI_CMDRDY; - cmd = mrq->cmd; - cmdflags = atmci_prepare_command(slot->mmc, cmd); - atmci_send_command(host, cmd, cmdflags); - - if (data) - host->submit_data(host, data); - - if (mrq->stop) { - host->stop_cmdr = atmci_prepare_command(slot->mmc, mrq->stop); - host->stop_cmdr |= ATMCI_CMDR_STOP_XFER; - if (!(data->flags & MMC_DATA_WRITE)) - host->stop_cmdr |= ATMCI_CMDR_TRDIR_READ; - if (data->flags & MMC_DATA_STREAM) - host->stop_cmdr |= ATMCI_CMDR_STREAM; - else - host->stop_cmdr |= ATMCI_CMDR_MULTI_BLOCK; - } - - /* - * We could have enabled interrupts earlier, but I suspect - * that would open up a nice can of interesting race - * conditions (e.g. command and data complete, but stop not - * prepared yet.) - */ - atmci_writel(host, ATMCI_IER, iflags); -} - -static void atmci_queue_request(struct atmel_mci *host, - struct atmel_mci_slot *slot, struct mmc_request *mrq) -{ - dev_vdbg(&slot->mmc->class_dev, "queue request: state=%d\n", - host->state); - - spin_lock_bh(&host->lock); - slot->mrq = mrq; - if (host->state == STATE_IDLE) { - host->state = STATE_SENDING_CMD; - atmci_start_request(host, slot); - } else { - list_add_tail(&slot->queue_node, &host->queue); - } - spin_unlock_bh(&host->lock); -} - -static void atmci_request(struct mmc_host *mmc, struct mmc_request *mrq) -{ - struct atmel_mci_slot *slot = mmc_priv(mmc); - struct atmel_mci *host = slot->host; - struct mmc_data *data; - - WARN_ON(slot->mrq); - - /* - * We may "know" the card is gone even though there's still an - * electrical connection. If so, we really need to communicate - * this to the MMC core since there won't be any more - * interrupts as the card is completely removed. Otherwise, - * the MMC core might believe the card is still there even - * though the card was just removed very slowly. - */ - if (!test_bit(ATMCI_CARD_PRESENT, &slot->flags)) { - mrq->cmd->error = -ENOMEDIUM; - mmc_request_done(mmc, mrq); - return; - } - - /* We don't support multiple blocks of weird lengths. */ - data = mrq->data; - if (data && data->blocks > 1 && data->blksz & 3) { - mrq->cmd->error = -EINVAL; - mmc_request_done(mmc, mrq); - } - - atmci_queue_request(host, slot, mrq); -} - -static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) -{ - struct atmel_mci_slot *slot = mmc_priv(mmc); - struct atmel_mci *host = slot->host; - unsigned int i; - - slot->sdc_reg &= ~ATMCI_SDCBUS_MASK; - switch (ios->bus_width) { - case MMC_BUS_WIDTH_1: - slot->sdc_reg |= ATMCI_SDCBUS_1BIT; - break; - case MMC_BUS_WIDTH_4: - slot->sdc_reg |= ATMCI_SDCBUS_4BIT; - break; - } - - if (ios->clock) { - unsigned int clock_min = ~0U; - u32 clkdiv; - - spin_lock_bh(&host->lock); - if (!host->mode_reg) { - clk_enable(host->mck); - atmci_writel(host, ATMCI_CR, ATMCI_CR_SWRST); - atmci_writel(host, ATMCI_CR, ATMCI_CR_MCIEN); - if (host->caps.has_cfg_reg) - atmci_writel(host, ATMCI_CFG, host->cfg_reg); - } - - /* - * Use mirror of ios->clock to prevent race with mmc - * core ios update when finding the minimum. - */ - slot->clock = ios->clock; - for (i = 0; i < ATMCI_MAX_NR_SLOTS; i++) { - if (host->slot[i] && host->slot[i]->clock - && host->slot[i]->clock < clock_min) - clock_min = host->slot[i]->clock; - } - - /* Calculate clock divider */ - if (host->caps.has_odd_clk_div) { - clkdiv = DIV_ROUND_UP(host->bus_hz, clock_min) - 2; - if (clkdiv > 511) { - dev_warn(&mmc->class_dev, - "clock %u too slow; using %lu\n", - clock_min, host->bus_hz / (511 + 2)); - clkdiv = 511; - } - host->mode_reg = ATMCI_MR_CLKDIV(clkdiv >> 1) - | ATMCI_MR_CLKODD(clkdiv & 1); - } else { - clkdiv = DIV_ROUND_UP(host->bus_hz, 2 * clock_min) - 1; - if (clkdiv > 255) { - dev_warn(&mmc->class_dev, - "clock %u too slow; using %lu\n", - clock_min, host->bus_hz / (2 * 256)); - clkdiv = 255; - } - host->mode_reg = ATMCI_MR_CLKDIV(clkdiv); - } - - /* - * WRPROOF and RDPROOF prevent overruns/underruns by - * stopping the clock when the FIFO is full/empty. - * This state is not expected to last for long. - */ - if (host->caps.has_rwproof) - host->mode_reg |= (ATMCI_MR_WRPROOF | ATMCI_MR_RDPROOF); - - if (host->caps.has_cfg_reg) { - /* setup High Speed mode in relation with card capacity */ - if (ios->timing == MMC_TIMING_SD_HS) - host->cfg_reg |= ATMCI_CFG_HSMODE; - else - host->cfg_reg &= ~ATMCI_CFG_HSMODE; - } - - if (list_empty(&host->queue)) { - atmci_writel(host, ATMCI_MR, host->mode_reg); - if (host->caps.has_cfg_reg) - atmci_writel(host, ATMCI_CFG, host->cfg_reg); - } else { - host->need_clock_update = true; - } - - spin_unlock_bh(&host->lock); - } else { - bool any_slot_active = false; - - spin_lock_bh(&host->lock); - slot->clock = 0; - for (i = 0; i < ATMCI_MAX_NR_SLOTS; i++) { - if (host->slot[i] && host->slot[i]->clock) { - any_slot_active = true; - break; - } - } - if (!any_slot_active) { - atmci_writel(host, ATMCI_CR, ATMCI_CR_MCIDIS); - if (host->mode_reg) { - atmci_readl(host, ATMCI_MR); - clk_disable(host->mck); - } - host->mode_reg = 0; - } - spin_unlock_bh(&host->lock); - } - - switch (ios->power_mode) { - case MMC_POWER_UP: - set_bit(ATMCI_CARD_NEED_INIT, &slot->flags); - break; - default: - /* - * TODO: None of the currently available AVR32-based - * boards allow MMC power to be turned off. Implement - * power control when this can be tested properly. - * - * We also need to hook this into the clock management - * somehow so that newly inserted cards aren't - * subjected to a fast clock before we have a chance - * to figure out what the maximum rate is. Currently, - * there's no way to avoid this, and there never will - * be for boards that don't support power control. - */ - break; - } -} - -static int atmci_get_ro(struct mmc_host *mmc) -{ - int read_only = -ENOSYS; - struct atmel_mci_slot *slot = mmc_priv(mmc); - - if (gpio_is_valid(slot->wp_pin)) { - read_only = gpio_get_value(slot->wp_pin); - dev_dbg(&mmc->class_dev, "card is %s\n", - read_only ? "read-only" : "read-write"); - } - - return read_only; -} - -static int atmci_get_cd(struct mmc_host *mmc) -{ - int present = -ENOSYS; - struct atmel_mci_slot *slot = mmc_priv(mmc); - - if (gpio_is_valid(slot->detect_pin)) { - present = !(gpio_get_value(slot->detect_pin) ^ - slot->detect_is_active_high); - dev_dbg(&mmc->class_dev, "card is %spresent\n", - present ? "" : "not "); - } - - return present; -} - -static void atmci_enable_sdio_irq(struct mmc_host *mmc, int enable) -{ - struct atmel_mci_slot *slot = mmc_priv(mmc); - struct atmel_mci *host = slot->host; - - if (enable) - atmci_writel(host, ATMCI_IER, slot->sdio_irq); - else - atmci_writel(host, ATMCI_IDR, slot->sdio_irq); -} - -static const struct mmc_host_ops atmci_ops = { - .request = atmci_request, - .set_ios = atmci_set_ios, - .get_ro = atmci_get_ro, - .get_cd = atmci_get_cd, - .enable_sdio_irq = atmci_enable_sdio_irq, -}; - -/* Called with host->lock held */ -static void atmci_request_end(struct atmel_mci *host, struct mmc_request *mrq) - __releases(&host->lock) - __acquires(&host->lock) -{ - struct atmel_mci_slot *slot = NULL; - struct mmc_host *prev_mmc = host->cur_slot->mmc; - - WARN_ON(host->cmd || host->data); - - /* - * Update the MMC clock rate if necessary. This may be - * necessary if set_ios() is called when a different slot is - * busy transferring data. - */ - if (host->need_clock_update) { - atmci_writel(host, ATMCI_MR, host->mode_reg); - if (host->caps.has_cfg_reg) - atmci_writel(host, ATMCI_CFG, host->cfg_reg); - } - - host->cur_slot->mrq = NULL; - host->mrq = NULL; - if (!list_empty(&host->queue)) { - slot = list_entry(host->queue.next, - struct atmel_mci_slot, queue_node); - list_del(&slot->queue_node); - dev_vdbg(&host->pdev->dev, "list not empty: %s is next\n", - mmc_hostname(slot->mmc)); - host->state = STATE_SENDING_CMD; - atmci_start_request(host, slot); - } else { - dev_vdbg(&host->pdev->dev, "list empty\n"); - host->state = STATE_IDLE; - } - - spin_unlock(&host->lock); - mmc_request_done(prev_mmc, mrq); - spin_lock(&host->lock); -} - -static void atmci_command_complete(struct atmel_mci *host, - struct mmc_command *cmd) -{ - u32 status = host->cmd_status; - - /* Read the response from the card (up to 16 bytes) */ - cmd->resp[0] = atmci_readl(host, ATMCI_RSPR); - cmd->resp[1] = atmci_readl(host, ATMCI_RSPR); - cmd->resp[2] = atmci_readl(host, ATMCI_RSPR); - cmd->resp[3] = atmci_readl(host, ATMCI_RSPR); - - if (status & ATMCI_RTOE) - cmd->error = -ETIMEDOUT; - else if ((cmd->flags & MMC_RSP_CRC) && (status & ATMCI_RCRCE)) - cmd->error = -EILSEQ; - else if (status & (ATMCI_RINDE | ATMCI_RDIRE | ATMCI_RENDE)) - cmd->error = -EIO; - else - cmd->error = 0; - - if (cmd->error) { - dev_dbg(&host->pdev->dev, - "command error: status=0x%08x\n", status); - - if (cmd->data) { - host->stop_transfer(host); - host->data = NULL; - atmci_writel(host, ATMCI_IDR, ATMCI_NOTBUSY - | ATMCI_TXRDY | ATMCI_RXRDY - | ATMCI_DATA_ERROR_FLAGS); - } - } -} - -static void atmci_detect_change(unsigned long data) -{ - struct atmel_mci_slot *slot = (struct atmel_mci_slot *)data; - bool present; - bool present_old; - - /* - * atmci_cleanup_slot() sets the ATMCI_SHUTDOWN flag before - * freeing the interrupt. We must not re-enable the interrupt - * if it has been freed, and if we're shutting down, it - * doesn't really matter whether the card is present or not. - */ - smp_rmb(); - if (test_bit(ATMCI_SHUTDOWN, &slot->flags)) - return; - - enable_irq(gpio_to_irq(slot->detect_pin)); - present = !(gpio_get_value(slot->detect_pin) ^ - slot->detect_is_active_high); - present_old = test_bit(ATMCI_CARD_PRESENT, &slot->flags); - - dev_vdbg(&slot->mmc->class_dev, "detect change: %d (was %d)\n", - present, present_old); - - if (present != present_old) { - struct atmel_mci *host = slot->host; - struct mmc_request *mrq; - - dev_dbg(&slot->mmc->class_dev, "card %s\n", - present ? "inserted" : "removed"); - - spin_lock(&host->lock); - - if (!present) - clear_bit(ATMCI_CARD_PRESENT, &slot->flags); - else - set_bit(ATMCI_CARD_PRESENT, &slot->flags); - - /* Clean up queue if present */ - mrq = slot->mrq; - if (mrq) { - if (mrq == host->mrq) { - /* - * Reset controller to terminate any ongoing - * commands or data transfers. - */ - atmci_writel(host, ATMCI_CR, ATMCI_CR_SWRST); - atmci_writel(host, ATMCI_CR, ATMCI_CR_MCIEN); - atmci_writel(host, ATMCI_MR, host->mode_reg); - if (host->caps.has_cfg_reg) - atmci_writel(host, ATMCI_CFG, host->cfg_reg); - - host->data = NULL; - host->cmd = NULL; - - switch (host->state) { - case STATE_IDLE: - break; - case STATE_SENDING_CMD: - mrq->cmd->error = -ENOMEDIUM; - if (!mrq->data) - break; - /* fall through */ - case STATE_SENDING_DATA: - mrq->data->error = -ENOMEDIUM; - host->stop_transfer(host); - break; - case STATE_DATA_BUSY: - case STATE_DATA_ERROR: - if (mrq->data->error == -EINPROGRESS) - mrq->data->error = -ENOMEDIUM; - if (!mrq->stop) - break; - /* fall through */ - case STATE_SENDING_STOP: - mrq->stop->error = -ENOMEDIUM; - break; - } - - atmci_request_end(host, mrq); - } else { - list_del(&slot->queue_node); - mrq->cmd->error = -ENOMEDIUM; - if (mrq->data) - mrq->data->error = -ENOMEDIUM; - if (mrq->stop) - mrq->stop->error = -ENOMEDIUM; - - spin_unlock(&host->lock); - mmc_request_done(slot->mmc, mrq); - spin_lock(&host->lock); - } - } - spin_unlock(&host->lock); - - mmc_detect_change(slot->mmc, 0); - } -} - -static void atmci_tasklet_func(unsigned long priv) -{ - struct atmel_mci *host = (struct atmel_mci *)priv; - struct mmc_request *mrq = host->mrq; - struct mmc_data *data = host->data; - struct mmc_command *cmd = host->cmd; - enum atmel_mci_state state = host->state; - enum atmel_mci_state prev_state; - u32 status; - - spin_lock(&host->lock); - - state = host->state; - - dev_vdbg(&host->pdev->dev, - "tasklet: state %u pending/completed/mask %lx/%lx/%x\n", - state, host->pending_events, host->completed_events, - atmci_readl(host, ATMCI_IMR)); - - do { - prev_state = state; - - switch (state) { - case STATE_IDLE: - break; - - case STATE_SENDING_CMD: - if (!atmci_test_and_clear_pending(host, - EVENT_CMD_COMPLETE)) - break; - - host->cmd = NULL; - atmci_set_completed(host, EVENT_CMD_COMPLETE); - atmci_command_complete(host, mrq->cmd); - if (!mrq->data || cmd->error) { - atmci_request_end(host, host->mrq); - goto unlock; - } - - prev_state = state = STATE_SENDING_DATA; - /* fall through */ - - case STATE_SENDING_DATA: - if (atmci_test_and_clear_pending(host, - EVENT_DATA_ERROR)) { - host->stop_transfer(host); - if (data->stop) - atmci_send_stop_cmd(host, data); - state = STATE_DATA_ERROR; - break; - } - - if (!atmci_test_and_clear_pending(host, - EVENT_XFER_COMPLETE)) - break; - - atmci_set_completed(host, EVENT_XFER_COMPLETE); - prev_state = state = STATE_DATA_BUSY; - /* fall through */ - - case STATE_DATA_BUSY: - if (!atmci_test_and_clear_pending(host, - EVENT_DATA_COMPLETE)) - break; - - host->data = NULL; - atmci_set_completed(host, EVENT_DATA_COMPLETE); - status = host->data_status; - if (unlikely(status & ATMCI_DATA_ERROR_FLAGS)) { - if (status & ATMCI_DTOE) { - dev_dbg(&host->pdev->dev, - "data timeout error\n"); - data->error = -ETIMEDOUT; - } else if (status & ATMCI_DCRCE) { - dev_dbg(&host->pdev->dev, - "data CRC error\n"); - data->error = -EILSEQ; - } else { - dev_dbg(&host->pdev->dev, - "data FIFO error (status=%08x)\n", - status); - data->error = -EIO; - } - } else { - data->bytes_xfered = data->blocks * data->blksz; - data->error = 0; - atmci_writel(host, ATMCI_IDR, ATMCI_DATA_ERROR_FLAGS); - } - - if (!data->stop) { - atmci_request_end(host, host->mrq); - goto unlock; - } - - prev_state = state = STATE_SENDING_STOP; - if (!data->error) - atmci_send_stop_cmd(host, data); - /* fall through */ - - case STATE_SENDING_STOP: - if (!atmci_test_and_clear_pending(host, - EVENT_CMD_COMPLETE)) - break; - - host->cmd = NULL; - atmci_command_complete(host, mrq->stop); - atmci_request_end(host, host->mrq); - goto unlock; - - case STATE_DATA_ERROR: - if (!atmci_test_and_clear_pending(host, - EVENT_XFER_COMPLETE)) - break; - - state = STATE_DATA_BUSY; - break; - } - } while (state != prev_state); - - host->state = state; - -unlock: - spin_unlock(&host->lock); -} - -static void atmci_read_data_pio(struct atmel_mci *host) -{ - struct scatterlist *sg = host->sg; - void *buf = sg_virt(sg); - unsigned int offset = host->pio_offset; - struct mmc_data *data = host->data; - u32 value; - u32 status; - unsigned int nbytes = 0; - - do { - value = atmci_readl(host, ATMCI_RDR); - if (likely(offset + 4 <= sg->length)) { - put_unaligned(value, (u32 *)(buf + offset)); - - offset += 4; - nbytes += 4; - - if (offset == sg->length) { - flush_dcache_page(sg_page(sg)); - host->sg = sg = sg_next(sg); - if (!sg) - goto done; - - offset = 0; - buf = sg_virt(sg); - } - } else { - unsigned int remaining = sg->length - offset; - memcpy(buf + offset, &value, remaining); - nbytes += remaining; - - flush_dcache_page(sg_page(sg)); - host->sg = sg = sg_next(sg); - if (!sg) - goto done; - - offset = 4 - remaining; - buf = sg_virt(sg); - memcpy(buf, (u8 *)&value + remaining, offset); - nbytes += offset; - } - - status = atmci_readl(host, ATMCI_SR); - if (status & ATMCI_DATA_ERROR_FLAGS) { - atmci_writel(host, ATMCI_IDR, (ATMCI_NOTBUSY | ATMCI_RXRDY - | ATMCI_DATA_ERROR_FLAGS)); - host->data_status = status; - data->bytes_xfered += nbytes; - smp_wmb(); - atmci_set_pending(host, EVENT_DATA_ERROR); - tasklet_schedule(&host->tasklet); - return; - } - } while (status & ATMCI_RXRDY); - - host->pio_offset = offset; - data->bytes_xfered += nbytes; - - return; - -done: - atmci_writel(host, ATMCI_IDR, ATMCI_RXRDY); - atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY); - data->bytes_xfered += nbytes; - smp_wmb(); - atmci_set_pending(host, EVENT_XFER_COMPLETE); -} - -static void atmci_write_data_pio(struct atmel_mci *host) -{ - struct scatterlist *sg = host->sg; - void *buf = sg_virt(sg); - unsigned int offset = host->pio_offset; - struct mmc_data *data = host->data; - u32 value; - u32 status; - unsigned int nbytes = 0; - - do { - if (likely(offset + 4 <= sg->length)) { - value = get_unaligned((u32 *)(buf + offset)); - atmci_writel(host, ATMCI_TDR, value); - - offset += 4; - nbytes += 4; - if (offset == sg->length) { - host->sg = sg = sg_next(sg); - if (!sg) - goto done; - - offset = 0; - buf = sg_virt(sg); - } - } else { - unsigned int remaining = sg->length - offset; - - value = 0; - memcpy(&value, buf + offset, remaining); - nbytes += remaining; - - host->sg = sg = sg_next(sg); - if (!sg) { - atmci_writel(host, ATMCI_TDR, value); - goto done; - } - - offset = 4 - remaining; - buf = sg_virt(sg); - memcpy((u8 *)&value + remaining, buf, offset); - atmci_writel(host, ATMCI_TDR, value); - nbytes += offset; - } - - status = atmci_readl(host, ATMCI_SR); - if (status & ATMCI_DATA_ERROR_FLAGS) { - atmci_writel(host, ATMCI_IDR, (ATMCI_NOTBUSY | ATMCI_TXRDY - | ATMCI_DATA_ERROR_FLAGS)); - host->data_status = status; - data->bytes_xfered += nbytes; - smp_wmb(); - atmci_set_pending(host, EVENT_DATA_ERROR); - tasklet_schedule(&host->tasklet); - return; - } - } while (status & ATMCI_TXRDY); - - host->pio_offset = offset; - data->bytes_xfered += nbytes; - - return; - -done: - atmci_writel(host, ATMCI_IDR, ATMCI_TXRDY); - atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY); - data->bytes_xfered += nbytes; - smp_wmb(); - atmci_set_pending(host, EVENT_XFER_COMPLETE); -} - -static void atmci_cmd_interrupt(struct atmel_mci *host, u32 status) -{ - atmci_writel(host, ATMCI_IDR, ATMCI_CMDRDY); - - host->cmd_status = status; - smp_wmb(); - atmci_set_pending(host, EVENT_CMD_COMPLETE); - tasklet_schedule(&host->tasklet); -} - -static void atmci_sdio_interrupt(struct atmel_mci *host, u32 status) -{ - int i; - - for (i = 0; i < ATMCI_MAX_NR_SLOTS; i++) { - struct atmel_mci_slot *slot = host->slot[i]; - if (slot && (status & slot->sdio_irq)) { - mmc_signal_sdio_irq(slot->mmc); - } - } -} - - -static irqreturn_t atmci_interrupt(int irq, void *dev_id) -{ - struct atmel_mci *host = dev_id; - u32 status, mask, pending; - unsigned int pass_count = 0; - - do { - status = atmci_readl(host, ATMCI_SR); - mask = atmci_readl(host, ATMCI_IMR); - pending = status & mask; - if (!pending) - break; - - if (pending & ATMCI_DATA_ERROR_FLAGS) { - atmci_writel(host, ATMCI_IDR, ATMCI_DATA_ERROR_FLAGS - | ATMCI_RXRDY | ATMCI_TXRDY); - pending &= atmci_readl(host, ATMCI_IMR); - - host->data_status = status; - smp_wmb(); - atmci_set_pending(host, EVENT_DATA_ERROR); - tasklet_schedule(&host->tasklet); - } - - if (pending & ATMCI_TXBUFE) { - atmci_writel(host, ATMCI_IDR, ATMCI_TXBUFE); - atmci_writel(host, ATMCI_IDR, ATMCI_ENDTX); - /* - * We can receive this interruption before having configured - * the second pdc buffer, so we need to reconfigure first and - * second buffers again - */ - if (host->data_size) { - atmci_pdc_set_both_buf(host, XFER_TRANSMIT); - atmci_writel(host, ATMCI_IER, ATMCI_ENDTX); - atmci_writel(host, ATMCI_IER, ATMCI_TXBUFE); - } else { - atmci_pdc_complete(host); - } - } else if (pending & ATMCI_ENDTX) { - atmci_writel(host, ATMCI_IDR, ATMCI_ENDTX); - - if (host->data_size) { - atmci_pdc_set_single_buf(host, - XFER_TRANSMIT, PDC_SECOND_BUF); - atmci_writel(host, ATMCI_IER, ATMCI_ENDTX); - } - } - - if (pending & ATMCI_RXBUFF) { - atmci_writel(host, ATMCI_IDR, ATMCI_RXBUFF); - atmci_writel(host, ATMCI_IDR, ATMCI_ENDRX); - /* - * We can receive this interruption before having configured - * the second pdc buffer, so we need to reconfigure first and - * second buffers again - */ - if (host->data_size) { - atmci_pdc_set_both_buf(host, XFER_RECEIVE); - atmci_writel(host, ATMCI_IER, ATMCI_ENDRX); - atmci_writel(host, ATMCI_IER, ATMCI_RXBUFF); - } else { - atmci_pdc_complete(host); - } - } else if (pending & ATMCI_ENDRX) { - atmci_writel(host, ATMCI_IDR, ATMCI_ENDRX); - - if (host->data_size) { - atmci_pdc_set_single_buf(host, - XFER_RECEIVE, PDC_SECOND_BUF); - atmci_writel(host, ATMCI_IER, ATMCI_ENDRX); - } - } - - - if (pending & ATMCI_NOTBUSY) { - atmci_writel(host, ATMCI_IDR, - ATMCI_DATA_ERROR_FLAGS | ATMCI_NOTBUSY); - if (!host->data_status) - host->data_status = status; - smp_wmb(); - atmci_set_pending(host, EVENT_DATA_COMPLETE); - tasklet_schedule(&host->tasklet); - } - if (pending & ATMCI_RXRDY) - atmci_read_data_pio(host); - if (pending & ATMCI_TXRDY) - atmci_write_data_pio(host); - - if (pending & ATMCI_CMDRDY) - atmci_cmd_interrupt(host, status); - - if (pending & (ATMCI_SDIOIRQA | ATMCI_SDIOIRQB)) - atmci_sdio_interrupt(host, status); - - } while (pass_count++ < 5); - - return pass_count ? IRQ_HANDLED : IRQ_NONE; -} - -static irqreturn_t atmci_detect_interrupt(int irq, void *dev_id) -{ - struct atmel_mci_slot *slot = dev_id; - - /* - * Disable interrupts until the pin has stabilized and check - * the state then. Use mod_timer() since we may be in the - * middle of the timer routine when this interrupt triggers. - */ - disable_irq_nosync(irq); - mod_timer(&slot->detect_timer, jiffies + msecs_to_jiffies(20)); - - return IRQ_HANDLED; -} - -static int __init atmci_init_slot(struct atmel_mci *host, - struct mci_slot_pdata *slot_data, unsigned int id, - u32 sdc_reg, u32 sdio_irq) -{ - struct mmc_host *mmc; - struct atmel_mci_slot *slot; - - mmc = mmc_alloc_host(sizeof(struct atmel_mci_slot), &host->pdev->dev); - if (!mmc) - return -ENOMEM; - - slot = mmc_priv(mmc); - slot->mmc = mmc; - slot->host = host; - slot->detect_pin = slot_data->detect_pin; - slot->wp_pin = slot_data->wp_pin; - slot->detect_is_active_high = slot_data->detect_is_active_high; - slot->sdc_reg = sdc_reg; - slot->sdio_irq = sdio_irq; - - mmc->ops = &atmci_ops; - mmc->f_min = DIV_ROUND_UP(host->bus_hz, 512); - mmc->f_max = host->bus_hz / 2; - mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; - if (sdio_irq) - mmc->caps |= MMC_CAP_SDIO_IRQ; - if (host->caps.has_highspeed) - mmc->caps |= MMC_CAP_SD_HIGHSPEED; - if (slot_data->bus_width >= 4) - mmc->caps |= MMC_CAP_4_BIT_DATA; - - mmc->max_segs = 64; - mmc->max_req_size = 32768 * 512; - mmc->max_blk_size = 32768; - mmc->max_blk_count = 512; - - /* Assume card is present initially */ - set_bit(ATMCI_CARD_PRESENT, &slot->flags); - if (gpio_is_valid(slot->detect_pin)) { - if (gpio_request(slot->detect_pin, "mmc_detect")) { - dev_dbg(&mmc->class_dev, "no detect pin available\n"); - slot->detect_pin = -EBUSY; - } else if (gpio_get_value(slot->detect_pin) ^ - slot->detect_is_active_high) { - clear_bit(ATMCI_CARD_PRESENT, &slot->flags); - } - } - - if (!gpio_is_valid(slot->detect_pin)) - mmc->caps |= MMC_CAP_NEEDS_POLL; - - if (gpio_is_valid(slot->wp_pin)) { - if (gpio_request(slot->wp_pin, "mmc_wp")) { - dev_dbg(&mmc->class_dev, "no WP pin available\n"); - slot->wp_pin = -EBUSY; - } - } - - host->slot[id] = slot; - mmc_add_host(mmc); - - if (gpio_is_valid(slot->detect_pin)) { - int ret; - - setup_timer(&slot->detect_timer, atmci_detect_change, - (unsigned long)slot); - - ret = request_irq(gpio_to_irq(slot->detect_pin), - atmci_detect_interrupt, - IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, - "mmc-detect", slot); - if (ret) { - dev_dbg(&mmc->class_dev, - "could not request IRQ %d for detect pin\n", - gpio_to_irq(slot->detect_pin)); - gpio_free(slot->detect_pin); - slot->detect_pin = -EBUSY; - } - } - - atmci_init_debugfs(slot); - - return 0; -} - -static void __exit atmci_cleanup_slot(struct atmel_mci_slot *slot, - unsigned int id) -{ - /* Debugfs stuff is cleaned up by mmc core */ - - set_bit(ATMCI_SHUTDOWN, &slot->flags); - smp_wmb(); - - mmc_remove_host(slot->mmc); - - if (gpio_is_valid(slot->detect_pin)) { - int pin = slot->detect_pin; - - free_irq(gpio_to_irq(pin), slot); - del_timer_sync(&slot->detect_timer); - gpio_free(pin); - } - if (gpio_is_valid(slot->wp_pin)) - gpio_free(slot->wp_pin); - - slot->host->slot[id] = NULL; - mmc_free_host(slot->mmc); -} - -static bool atmci_filter(struct dma_chan *chan, void *slave) -{ - struct mci_dma_data *sl = slave; - - if (sl && find_slave_dev(sl) == chan->device->dev) { - chan->private = slave_data_ptr(sl); - return true; - } else { - return false; - } -} - -static bool atmci_configure_dma(struct atmel_mci *host) -{ - struct mci_platform_data *pdata; - - if (host == NULL) - return false; - - pdata = host->pdev->dev.platform_data; - - if (pdata && find_slave_dev(pdata->dma_slave)) { - dma_cap_mask_t mask; - - /* Try to grab a DMA channel */ - dma_cap_zero(mask); - dma_cap_set(DMA_SLAVE, mask); - host->dma.chan = - dma_request_channel(mask, atmci_filter, pdata->dma_slave); - } - if (!host->dma.chan) { - dev_warn(&host->pdev->dev, "no DMA channel available\n"); - return false; - } else { - dev_info(&host->pdev->dev, - "using %s for DMA transfers\n", - dma_chan_name(host->dma.chan)); - - host->dma_conf.src_addr = host->mapbase + ATMCI_RDR; - host->dma_conf.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; - host->dma_conf.src_maxburst = 1; - host->dma_conf.dst_addr = host->mapbase + ATMCI_TDR; - host->dma_conf.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; - host->dma_conf.dst_maxburst = 1; - host->dma_conf.device_fc = false; - return true; - } -} - -static inline unsigned int atmci_get_version(struct atmel_mci *host) -{ - return atmci_readl(host, ATMCI_VERSION) & 0x00000fff; -} - -/* - * HSMCI (High Speed MCI) module is not fully compatible with MCI module. - * HSMCI provides DMA support and a new config register but no more supports - * PDC. - */ -static void __init atmci_get_cap(struct atmel_mci *host) -{ - unsigned int version; - - version = atmci_get_version(host); - dev_info(&host->pdev->dev, - "version: 0x%x\n", version); - - host->caps.has_dma = 0; - host->caps.has_pdc = 1; - host->caps.has_cfg_reg = 0; - host->caps.has_cstor_reg = 0; - host->caps.has_highspeed = 0; - host->caps.has_rwproof = 0; - host->caps.has_odd_clk_div = 0; - - /* keep only major version number */ - switch (version & 0xf00) { - case 0x500: - host->caps.has_odd_clk_div = 1; - case 0x400: - case 0x300: -#ifdef CONFIG_AT_HDMAC - host->caps.has_dma = 1; -#else - dev_info(&host->pdev->dev, - "has dma capability but dma engine is not selected, then use pio\n"); -#endif - host->caps.has_pdc = 0; - host->caps.has_cfg_reg = 1; - host->caps.has_cstor_reg = 1; - host->caps.has_highspeed = 1; - case 0x200: - host->caps.has_rwproof = 1; - case 0x100: - break; - default: - host->caps.has_pdc = 0; - dev_warn(&host->pdev->dev, - "Unmanaged mci version, set minimum capabilities\n"); - break; - } -} - -static int __init atmci_probe(struct platform_device *pdev) -{ - struct mci_platform_data *pdata; - struct atmel_mci *host; - struct resource *regs; - unsigned int nr_slots; - int irq; - int ret; - - regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!regs) - return -ENXIO; - pdata = pdev->dev.platform_data; - if (!pdata) - return -ENXIO; - irq = platform_get_irq(pdev, 0); - if (irq < 0) - return irq; - - host = kzalloc(sizeof(struct atmel_mci), GFP_KERNEL); - if (!host) - return -ENOMEM; - - host->pdev = pdev; - spin_lock_init(&host->lock); - INIT_LIST_HEAD(&host->queue); - - host->mck = clk_get(&pdev->dev, "mci_clk"); - if (IS_ERR(host->mck)) { - ret = PTR_ERR(host->mck); - goto err_clk_get; - } - - ret = -ENOMEM; - host->regs = ioremap(regs->start, resource_size(regs)); - if (!host->regs) - goto err_ioremap; - - clk_enable(host->mck); - atmci_writel(host, ATMCI_CR, ATMCI_CR_SWRST); - host->bus_hz = clk_get_rate(host->mck); - clk_disable(host->mck); - - host->mapbase = regs->start; - - tasklet_init(&host->tasklet, atmci_tasklet_func, (unsigned long)host); - - ret = request_irq(irq, atmci_interrupt, 0, dev_name(&pdev->dev), host); - if (ret) - goto err_request_irq; - - /* Get MCI capabilities and set operations according to it */ - atmci_get_cap(host); - if (host->caps.has_dma && atmci_configure_dma(host)) { - host->prepare_data = &atmci_prepare_data_dma; - host->submit_data = &atmci_submit_data_dma; - host->stop_transfer = &atmci_stop_transfer_dma; - } else if (host->caps.has_pdc) { - dev_info(&pdev->dev, "using PDC\n"); - host->prepare_data = &atmci_prepare_data_pdc; - host->submit_data = &atmci_submit_data_pdc; - host->stop_transfer = &atmci_stop_transfer_pdc; - } else { - dev_info(&pdev->dev, "using PIO\n"); - host->prepare_data = &atmci_prepare_data; - host->submit_data = &atmci_submit_data; - host->stop_transfer = &atmci_stop_transfer; - } - - platform_set_drvdata(pdev, host); - - /* We need at least one slot to succeed */ - nr_slots = 0; - ret = -ENODEV; - if (pdata->slot[0].bus_width) { - ret = atmci_init_slot(host, &pdata->slot[0], - 0, ATMCI_SDCSEL_SLOT_A, ATMCI_SDIOIRQA); - if (!ret) - nr_slots++; - } - if (pdata->slot[1].bus_width) { - ret = atmci_init_slot(host, &pdata->slot[1], - 1, ATMCI_SDCSEL_SLOT_B, ATMCI_SDIOIRQB); - if (!ret) - nr_slots++; - } - - if (!nr_slots) { - dev_err(&pdev->dev, "init failed: no slot defined\n"); - goto err_init_slot; - } - - dev_info(&pdev->dev, - "Atmel MCI controller at 0x%08lx irq %d, %u slots\n", - host->mapbase, irq, nr_slots); - - return 0; - -err_init_slot: - if (host->dma.chan) - dma_release_channel(host->dma.chan); - free_irq(irq, host); -err_request_irq: - iounmap(host->regs); -err_ioremap: - clk_put(host->mck); -err_clk_get: - kfree(host); - return ret; -} - -static int __exit atmci_remove(struct platform_device *pdev) -{ - struct atmel_mci *host = platform_get_drvdata(pdev); - unsigned int i; - - platform_set_drvdata(pdev, NULL); - - for (i = 0; i < ATMCI_MAX_NR_SLOTS; i++) { - if (host->slot[i]) - atmci_cleanup_slot(host->slot[i], i); - } - - clk_enable(host->mck); - atmci_writel(host, ATMCI_IDR, ~0UL); - atmci_writel(host, ATMCI_CR, ATMCI_CR_MCIDIS); - atmci_readl(host, ATMCI_SR); - clk_disable(host->mck); - -#ifdef CONFIG_MMC_ATMELMCI_DMA - if (host->dma.chan) - dma_release_channel(host->dma.chan); -#endif - - free_irq(platform_get_irq(pdev, 0), host); - iounmap(host->regs); - - clk_put(host->mck); - kfree(host); - - return 0; -} - -#ifdef CONFIG_PM -static int atmci_suspend(struct device *dev) -{ - struct atmel_mci *host = dev_get_drvdata(dev); - int i; - - for (i = 0; i < ATMCI_MAX_NR_SLOTS; i++) { - struct atmel_mci_slot *slot = host->slot[i]; - int ret; - - if (!slot) - continue; - ret = mmc_suspend_host(slot->mmc); - if (ret < 0) { - while (--i >= 0) { - slot = host->slot[i]; - if (slot - && test_bit(ATMCI_SUSPENDED, &slot->flags)) { - mmc_resume_host(host->slot[i]->mmc); - clear_bit(ATMCI_SUSPENDED, &slot->flags); - } - } - return ret; - } else { - set_bit(ATMCI_SUSPENDED, &slot->flags); - } - } - - return 0; -} - -static int atmci_resume(struct device *dev) -{ - struct atmel_mci *host = dev_get_drvdata(dev); - int i; - int ret = 0; - - for (i = 0; i < ATMCI_MAX_NR_SLOTS; i++) { - struct atmel_mci_slot *slot = host->slot[i]; - int err; - - slot = host->slot[i]; - if (!slot) - continue; - if (!test_bit(ATMCI_SUSPENDED, &slot->flags)) - continue; - err = mmc_resume_host(slot->mmc); - if (err < 0) - ret = err; - else - clear_bit(ATMCI_SUSPENDED, &slot->flags); - } - - return ret; -} -static SIMPLE_DEV_PM_OPS(atmci_pm, atmci_suspend, atmci_resume); -#define ATMCI_PM_OPS (&atmci_pm) -#else -#define ATMCI_PM_OPS NULL -#endif - -static struct platform_driver atmci_driver = { - .remove = __exit_p(atmci_remove), - .driver = { - .name = "atmel_mci", - .pm = ATMCI_PM_OPS, - }, -}; - -static int __init atmci_init(void) -{ - return platform_driver_probe(&atmci_driver, atmci_probe); -} - -static void __exit atmci_exit(void) -{ - platform_driver_unregister(&atmci_driver); -} - -late_initcall(atmci_init); /* try to load after dma driver when built-in */ -module_exit(atmci_exit); - -MODULE_DESCRIPTION("Atmel Multimedia Card Interface driver"); -MODULE_AUTHOR("Haavard Skinnemoen (Atmel)"); -MODULE_LICENSE("GPL v2"); diff --git a/ANDROID_3.4.5/drivers/mmc/host/au1xmmc.c b/ANDROID_3.4.5/drivers/mmc/host/au1xmmc.c deleted file mode 100644 index dbd0c8a4..00000000 --- a/ANDROID_3.4.5/drivers/mmc/host/au1xmmc.c +++ /dev/null @@ -1,1228 +0,0 @@ -/* - * linux/drivers/mmc/host/au1xmmc.c - AU1XX0 MMC driver - * - * Copyright (c) 2005, Advanced Micro Devices, Inc. - * - * Developed with help from the 2.4.30 MMC AU1XXX controller including - * the following copyright notices: - * Copyright (c) 2003-2004 Embedded Edge, LLC. - * Portions Copyright (C) 2002 Embedix, Inc - * Copyright 2002 Hewlett-Packard Company - - * 2.6 version of this driver inspired by: - * (drivers/mmc/wbsd.c) Copyright (C) 2004-2005 Pierre Ossman, - * All Rights Reserved. - * (drivers/mmc/pxa.c) Copyright (C) 2003 Russell King, - * All Rights Reserved. - * - - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -/* Why don't we use the SD controllers' carddetect feature? - * - * From the AU1100 MMC application guide: - * If the Au1100-based design is intended to support both MultiMediaCards - * and 1- or 4-data bit SecureDigital cards, then the solution is to - * connect a weak (560KOhm) pull-up resistor to connector pin 1. - * In doing so, a MMC card never enters SPI-mode communications, - * but now the SecureDigital card-detect feature of CD/DAT3 is ineffective - * (the low to high transition will not occur). - */ - -#include <linux/module.h> -#include <linux/init.h> -#include <linux/platform_device.h> -#include <linux/mm.h> -#include <linux/interrupt.h> -#include <linux/dma-mapping.h> -#include <linux/scatterlist.h> -#include <linux/leds.h> -#include <linux/mmc/host.h> -#include <linux/slab.h> - -#include <asm/io.h> -#include <asm/mach-au1x00/au1000.h> -#include <asm/mach-au1x00/au1xxx_dbdma.h> -#include <asm/mach-au1x00/au1100_mmc.h> - -#define DRIVER_NAME "au1xxx-mmc" - -/* Set this to enable special debugging macros */ -/* #define DEBUG */ - -#ifdef DEBUG -#define DBG(fmt, idx, args...) \ - pr_debug("au1xmmc(%d): DEBUG: " fmt, idx, ##args) -#else -#define DBG(fmt, idx, args...) do {} while (0) -#endif - -/* Hardware definitions */ -#define AU1XMMC_DESCRIPTOR_COUNT 1 - -/* max DMA seg size: 64KB on Au1100, 4MB on Au1200 */ -#define AU1100_MMC_DESCRIPTOR_SIZE 0x0000ffff -#define AU1200_MMC_DESCRIPTOR_SIZE 0x003fffff - -#define AU1XMMC_OCR (MMC_VDD_27_28 | MMC_VDD_28_29 | MMC_VDD_29_30 | \ - MMC_VDD_30_31 | MMC_VDD_31_32 | MMC_VDD_32_33 | \ - MMC_VDD_33_34 | MMC_VDD_34_35 | MMC_VDD_35_36) - -/* This gives us a hard value for the stop command that we can write directly - * to the command register. - */ -#define STOP_CMD \ - (SD_CMD_RT_1B | SD_CMD_CT_7 | (0xC << SD_CMD_CI_SHIFT) | SD_CMD_GO) - -/* This is the set of interrupts that we configure by default. */ -#define AU1XMMC_INTERRUPTS \ - (SD_CONFIG_SC | SD_CONFIG_DT | SD_CONFIG_RAT | \ - SD_CONFIG_CR | SD_CONFIG_I) - -/* The poll event (looking for insert/remove events runs twice a second. */ -#define AU1XMMC_DETECT_TIMEOUT (HZ/2) - -struct au1xmmc_host { - struct mmc_host *mmc; - struct mmc_request *mrq; - - u32 flags; - u32 iobase; - u32 clock; - u32 bus_width; - u32 power_mode; - - int status; - - struct { - int len; - int dir; - } dma; - - struct { - int index; - int offset; - int len; - } pio; - - u32 tx_chan; - u32 rx_chan; - - int irq; - - struct tasklet_struct finish_task; - struct tasklet_struct data_task; - struct au1xmmc_platform_data *platdata; - struct platform_device *pdev; - struct resource *ioarea; -}; - -/* Status flags used by the host structure */ -#define HOST_F_XMIT 0x0001 -#define HOST_F_RECV 0x0002 -#define HOST_F_DMA 0x0010 -#define HOST_F_DBDMA 0x0020 -#define HOST_F_ACTIVE 0x0100 -#define HOST_F_STOP 0x1000 - -#define HOST_S_IDLE 0x0001 -#define HOST_S_CMD 0x0002 -#define HOST_S_DATA 0x0003 -#define HOST_S_STOP 0x0004 - -/* Easy access macros */ -#define HOST_STATUS(h) ((h)->iobase + SD_STATUS) -#define HOST_CONFIG(h) ((h)->iobase + SD_CONFIG) -#define HOST_ENABLE(h) ((h)->iobase + SD_ENABLE) -#define HOST_TXPORT(h) ((h)->iobase + SD_TXPORT) -#define HOST_RXPORT(h) ((h)->iobase + SD_RXPORT) -#define HOST_CMDARG(h) ((h)->iobase + SD_CMDARG) -#define HOST_BLKSIZE(h) ((h)->iobase + SD_BLKSIZE) -#define HOST_CMD(h) ((h)->iobase + SD_CMD) -#define HOST_CONFIG2(h) ((h)->iobase + SD_CONFIG2) -#define HOST_TIMEOUT(h) ((h)->iobase + SD_TIMEOUT) -#define HOST_DEBUG(h) ((h)->iobase + SD_DEBUG) - -#define DMA_CHANNEL(h) \ - (((h)->flags & HOST_F_XMIT) ? (h)->tx_chan : (h)->rx_chan) - -static inline int has_dbdma(void) -{ - switch (alchemy_get_cputype()) { - case ALCHEMY_CPU_AU1200: - case ALCHEMY_CPU_AU1300: - return 1; - default: - return 0; - } -} - -static inline void IRQ_ON(struct au1xmmc_host *host, u32 mask) -{ - u32 val = au_readl(HOST_CONFIG(host)); - val |= mask; - au_writel(val, HOST_CONFIG(host)); - au_sync(); -} - -static inline void FLUSH_FIFO(struct au1xmmc_host *host) -{ - u32 val = au_readl(HOST_CONFIG2(host)); - - au_writel(val | SD_CONFIG2_FF, HOST_CONFIG2(host)); - au_sync_delay(1); - - /* SEND_STOP will turn off clock control - this re-enables it */ - val &= ~SD_CONFIG2_DF; - - au_writel(val, HOST_CONFIG2(host)); - au_sync(); -} - -static inline void IRQ_OFF(struct au1xmmc_host *host, u32 mask) -{ - u32 val = au_readl(HOST_CONFIG(host)); - val &= ~mask; - au_writel(val, HOST_CONFIG(host)); - au_sync(); -} - -static inline void SEND_STOP(struct au1xmmc_host *host) -{ - u32 config2; - - WARN_ON(host->status != HOST_S_DATA); - host->status = HOST_S_STOP; - - config2 = au_readl(HOST_CONFIG2(host)); - au_writel(config2 | SD_CONFIG2_DF, HOST_CONFIG2(host)); - au_sync(); - - /* Send the stop command */ - au_writel(STOP_CMD, HOST_CMD(host)); -} - -static void au1xmmc_set_power(struct au1xmmc_host *host, int state) -{ - if (host->platdata && host->platdata->set_power) - host->platdata->set_power(host->mmc, state); -} - -static int au1xmmc_card_inserted(struct mmc_host *mmc) -{ - struct au1xmmc_host *host = mmc_priv(mmc); - - if (host->platdata && host->platdata->card_inserted) - return !!host->platdata->card_inserted(host->mmc); - - return -ENOSYS; -} - -static int au1xmmc_card_readonly(struct mmc_host *mmc) -{ - struct au1xmmc_host *host = mmc_priv(mmc); - - if (host->platdata && host->platdata->card_readonly) - return !!host->platdata->card_readonly(mmc); - - return -ENOSYS; -} - -static void au1xmmc_finish_request(struct au1xmmc_host *host) -{ - struct mmc_request *mrq = host->mrq; - - host->mrq = NULL; - host->flags &= HOST_F_ACTIVE | HOST_F_DMA; - - host->dma.len = 0; - host->dma.dir = 0; - - host->pio.index = 0; - host->pio.offset = 0; - host->pio.len = 0; - - host->status = HOST_S_IDLE; - - mmc_request_done(host->mmc, mrq); -} - -static void au1xmmc_tasklet_finish(unsigned long param) -{ - struct au1xmmc_host *host = (struct au1xmmc_host *) param; - au1xmmc_finish_request(host); -} - -static int au1xmmc_send_command(struct au1xmmc_host *host, int wait, - struct mmc_command *cmd, struct mmc_data *data) -{ - u32 mmccmd = (cmd->opcode << SD_CMD_CI_SHIFT); - - switch (mmc_resp_type(cmd)) { - case MMC_RSP_NONE: - break; - case MMC_RSP_R1: - mmccmd |= SD_CMD_RT_1; - break; - case MMC_RSP_R1B: - mmccmd |= SD_CMD_RT_1B; - break; - case MMC_RSP_R2: - mmccmd |= SD_CMD_RT_2; - break; - case MMC_RSP_R3: - mmccmd |= SD_CMD_RT_3; - break; - default: - pr_info("au1xmmc: unhandled response type %02x\n", - mmc_resp_type(cmd)); - return -EINVAL; - } - - if (data) { - if (data->flags & MMC_DATA_READ) { - if (data->blocks > 1) - mmccmd |= SD_CMD_CT_4; - else - mmccmd |= SD_CMD_CT_2; - } else if (data->flags & MMC_DATA_WRITE) { - if (data->blocks > 1) - mmccmd |= SD_CMD_CT_3; - else - mmccmd |= SD_CMD_CT_1; - } - } - - au_writel(cmd->arg, HOST_CMDARG(host)); - au_sync(); - - if (wait) - IRQ_OFF(host, SD_CONFIG_CR); - - au_writel((mmccmd | SD_CMD_GO), HOST_CMD(host)); - au_sync(); - - /* Wait for the command to go on the line */ - while (au_readl(HOST_CMD(host)) & SD_CMD_GO) - /* nop */; - - /* Wait for the command to come back */ - if (wait) { - u32 status = au_readl(HOST_STATUS(host)); - - while (!(status & SD_STATUS_CR)) - status = au_readl(HOST_STATUS(host)); - - /* Clear the CR status */ - au_writel(SD_STATUS_CR, HOST_STATUS(host)); - - IRQ_ON(host, SD_CONFIG_CR); - } - - return 0; -} - -static void au1xmmc_data_complete(struct au1xmmc_host *host, u32 status) -{ - struct mmc_request *mrq = host->mrq; - struct mmc_data *data; - u32 crc; - - WARN_ON((host->status != HOST_S_DATA) && (host->status != HOST_S_STOP)); - - if (host->mrq == NULL) - return; - - data = mrq->cmd->data; - - if (status == 0) - status = au_readl(HOST_STATUS(host)); - - /* The transaction is really over when the SD_STATUS_DB bit is clear */ - while ((host->flags & HOST_F_XMIT) && (status & SD_STATUS_DB)) - status = au_readl(HOST_STATUS(host)); - - data->error = 0; - dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len, host->dma.dir); - - /* Process any errors */ - crc = (status & (SD_STATUS_WC | SD_STATUS_RC)); - if (host->flags & HOST_F_XMIT) - crc |= ((status & 0x07) == 0x02) ? 0 : 1; - - if (crc) - data->error = -EILSEQ; - - /* Clear the CRC bits */ - au_writel(SD_STATUS_WC | SD_STATUS_RC, HOST_STATUS(host)); - - data->bytes_xfered = 0; - - if (!data->error) { - if (host->flags & (HOST_F_DMA | HOST_F_DBDMA)) { - u32 chan = DMA_CHANNEL(host); - - chan_tab_t *c = *((chan_tab_t **)chan); - au1x_dma_chan_t *cp = c->chan_ptr; - data->bytes_xfered = cp->ddma_bytecnt; - } else - data->bytes_xfered = - (data->blocks * data->blksz) - host->pio.len; - } - - au1xmmc_finish_request(host); -} - -static void au1xmmc_tasklet_data(unsigned long param) -{ - struct au1xmmc_host *host = (struct au1xmmc_host *)param; - - u32 status = au_readl(HOST_STATUS(host)); - au1xmmc_data_complete(host, status); -} - -#define AU1XMMC_MAX_TRANSFER 8 - -static void au1xmmc_send_pio(struct au1xmmc_host *host) -{ - struct mmc_data *data; - int sg_len, max, count; - unsigned char *sg_ptr, val; - u32 status; - struct scatterlist *sg; - - data = host->mrq->data; - - if (!(host->flags & HOST_F_XMIT)) - return; - - /* This is the pointer to the data buffer */ - sg = &data->sg[host->pio.index]; - sg_ptr = sg_virt(sg) + host->pio.offset; - - /* This is the space left inside the buffer */ - sg_len = data->sg[host->pio.index].length - host->pio.offset; - - /* Check if we need less than the size of the sg_buffer */ - max = (sg_len > host->pio.len) ? host->pio.len : sg_len; - if (max > AU1XMMC_MAX_TRANSFER) - max = AU1XMMC_MAX_TRANSFER; - - for (count = 0; count < max; count++) { - status = au_readl(HOST_STATUS(host)); - - if (!(status & SD_STATUS_TH)) - break; - - val = *sg_ptr++; - - au_writel((unsigned long)val, HOST_TXPORT(host)); - au_sync(); - } - - host->pio.len -= count; - host->pio.offset += count; - - if (count == sg_len) { - host->pio.index++; - host->pio.offset = 0; - } - - if (host->pio.len == 0) { - IRQ_OFF(host, SD_CONFIG_TH); - - if (host->flags & HOST_F_STOP) - SEND_STOP(host); - - tasklet_schedule(&host->data_task); - } -} - -static void au1xmmc_receive_pio(struct au1xmmc_host *host) -{ - struct mmc_data *data; - int max, count, sg_len = 0; - unsigned char *sg_ptr = NULL; - u32 status, val; - struct scatterlist *sg; - - data = host->mrq->data; - - if (!(host->flags & HOST_F_RECV)) - return; - - max = host->pio.len; - - if (host->pio.index < host->dma.len) { - sg = &data->sg[host->pio.index]; - sg_ptr = sg_virt(sg) + host->pio.offset; - - /* This is the space left inside the buffer */ - sg_len = sg_dma_len(&data->sg[host->pio.index]) - host->pio.offset; - - /* Check if we need less than the size of the sg_buffer */ - if (sg_len < max) - max = sg_len; - } - - if (max > AU1XMMC_MAX_TRANSFER) - max = AU1XMMC_MAX_TRANSFER; - - for (count = 0; count < max; count++) { - status = au_readl(HOST_STATUS(host)); - - if (!(status & SD_STATUS_NE)) - break; - - if (status & SD_STATUS_RC) { - DBG("RX CRC Error [%d + %d].\n", host->pdev->id, - host->pio.len, count); - break; - } - - if (status & SD_STATUS_RO) { - DBG("RX Overrun [%d + %d]\n", host->pdev->id, - host->pio.len, count); - break; - } - else if (status & SD_STATUS_RU) { - DBG("RX Underrun [%d + %d]\n", host->pdev->id, - host->pio.len, count); - break; - } - - val = au_readl(HOST_RXPORT(host)); - - if (sg_ptr) - *sg_ptr++ = (unsigned char)(val & 0xFF); - } - - host->pio.len -= count; - host->pio.offset += count; - - if (sg_len && count == sg_len) { - host->pio.index++; - host->pio.offset = 0; - } - - if (host->pio.len == 0) { - /* IRQ_OFF(host, SD_CONFIG_RA | SD_CONFIG_RF); */ - IRQ_OFF(host, SD_CONFIG_NE); - - if (host->flags & HOST_F_STOP) - SEND_STOP(host); - - tasklet_schedule(&host->data_task); - } -} - -/* This is called when a command has been completed - grab the response - * and check for errors. Then start the data transfer if it is indicated. - */ -static void au1xmmc_cmd_complete(struct au1xmmc_host *host, u32 status) -{ - struct mmc_request *mrq = host->mrq; - struct mmc_command *cmd; - u32 r[4]; - int i, trans; - - if (!host->mrq) - return; - - cmd = mrq->cmd; - cmd->error = 0; - - if (cmd->flags & MMC_RSP_PRESENT) { - if (cmd->flags & MMC_RSP_136) { - r[0] = au_readl(host->iobase + SD_RESP3); - r[1] = au_readl(host->iobase + SD_RESP2); - r[2] = au_readl(host->iobase + SD_RESP1); - r[3] = au_readl(host->iobase + SD_RESP0); - - /* The CRC is omitted from the response, so really - * we only got 120 bytes, but the engine expects - * 128 bits, so we have to shift things up. - */ - for (i = 0; i < 4; i++) { - cmd->resp[i] = (r[i] & 0x00FFFFFF) << 8; - if (i != 3) - cmd->resp[i] |= (r[i + 1] & 0xFF000000) >> 24; - } - } else { - /* Techincally, we should be getting all 48 bits of - * the response (SD_RESP1 + SD_RESP2), but because - * our response omits the CRC, our data ends up - * being shifted 8 bits to the right. In this case, - * that means that the OSR data starts at bit 31, - * so we can just read RESP0 and return that. - */ - cmd->resp[0] = au_readl(host->iobase + SD_RESP0); - } - } - - /* Figure out errors */ - if (status & (SD_STATUS_SC | SD_STATUS_WC | SD_STATUS_RC)) - cmd->error = -EILSEQ; - - trans = host->flags & (HOST_F_XMIT | HOST_F_RECV); - - if (!trans || cmd->error) { - IRQ_OFF(host, SD_CONFIG_TH | SD_CONFIG_RA | SD_CONFIG_RF); - tasklet_schedule(&host->finish_task); - return; - } - - host->status = HOST_S_DATA; - - if ((host->flags & (HOST_F_DMA | HOST_F_DBDMA))) { - u32 channel = DMA_CHANNEL(host); - - /* Start the DBDMA as soon as the buffer gets something in it */ - - if (host->flags & HOST_F_RECV) { - u32 mask = SD_STATUS_DB | SD_STATUS_NE; - - while((status & mask) != mask) - status = au_readl(HOST_STATUS(host)); - } - - au1xxx_dbdma_start(channel); - } -} - -static void au1xmmc_set_clock(struct au1xmmc_host *host, int rate) -{ - unsigned int pbus = get_au1x00_speed(); - unsigned int divisor; - u32 config; - - /* From databook: - * divisor = ((((cpuclock / sbus_divisor) / 2) / mmcclock) / 2) - 1 - */ - pbus /= ((au_readl(SYS_POWERCTRL) & 0x3) + 2); - pbus /= 2; - divisor = ((pbus / rate) / 2) - 1; - - config = au_readl(HOST_CONFIG(host)); - - config &= ~(SD_CONFIG_DIV); - config |= (divisor & SD_CONFIG_DIV) | SD_CONFIG_DE; - - au_writel(config, HOST_CONFIG(host)); - au_sync(); -} - -static int au1xmmc_prepare_data(struct au1xmmc_host *host, - struct mmc_data *data) -{ - int datalen = data->blocks * data->blksz; - - if (data->flags & MMC_DATA_READ) - host->flags |= HOST_F_RECV; - else - host->flags |= HOST_F_XMIT; - - if (host->mrq->stop) - host->flags |= HOST_F_STOP; - - host->dma.dir = DMA_BIDIRECTIONAL; - - host->dma.len = dma_map_sg(mmc_dev(host->mmc), data->sg, - data->sg_len, host->dma.dir); - - if (host->dma.len == 0) - return -ETIMEDOUT; - - au_writel(data->blksz - 1, HOST_BLKSIZE(host)); - - if (host->flags & (HOST_F_DMA | HOST_F_DBDMA)) { - int i; - u32 channel = DMA_CHANNEL(host); - - au1xxx_dbdma_stop(channel); - - for (i = 0; i < host->dma.len; i++) { - u32 ret = 0, flags = DDMA_FLAGS_NOIE; - struct scatterlist *sg = &data->sg[i]; - int sg_len = sg->length; - - int len = (datalen > sg_len) ? sg_len : datalen; - - if (i == host->dma.len - 1) - flags = DDMA_FLAGS_IE; - - if (host->flags & HOST_F_XMIT) { - ret = au1xxx_dbdma_put_source(channel, - sg_phys(sg), len, flags); - } else { - ret = au1xxx_dbdma_put_dest(channel, - sg_phys(sg), len, flags); - } - - if (!ret) - goto dataerr; - - datalen -= len; - } - } else { - host->pio.index = 0; - host->pio.offset = 0; - host->pio.len = datalen; - - if (host->flags & HOST_F_XMIT) - IRQ_ON(host, SD_CONFIG_TH); - else - IRQ_ON(host, SD_CONFIG_NE); - /* IRQ_ON(host, SD_CONFIG_RA | SD_CONFIG_RF); */ - } - - return 0; - -dataerr: - dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len, - host->dma.dir); - return -ETIMEDOUT; -} - -/* This actually starts a command or data transaction */ -static void au1xmmc_request(struct mmc_host* mmc, struct mmc_request* mrq) -{ - struct au1xmmc_host *host = mmc_priv(mmc); - int ret = 0; - - WARN_ON(irqs_disabled()); - WARN_ON(host->status != HOST_S_IDLE); - - host->mrq = mrq; - host->status = HOST_S_CMD; - - /* fail request immediately if no card is present */ - if (0 == au1xmmc_card_inserted(mmc)) { - mrq->cmd->error = -ENOMEDIUM; - au1xmmc_finish_request(host); - return; - } - - if (mrq->data) { - FLUSH_FIFO(host); - ret = au1xmmc_prepare_data(host, mrq->data); - } - - if (!ret) - ret = au1xmmc_send_command(host, 0, mrq->cmd, mrq->data); - - if (ret) { - mrq->cmd->error = ret; - au1xmmc_finish_request(host); - } -} - -static void au1xmmc_reset_controller(struct au1xmmc_host *host) -{ - /* Apply the clock */ - au_writel(SD_ENABLE_CE, HOST_ENABLE(host)); - au_sync_delay(1); - - au_writel(SD_ENABLE_R | SD_ENABLE_CE, HOST_ENABLE(host)); - au_sync_delay(5); - - au_writel(~0, HOST_STATUS(host)); - au_sync(); - - au_writel(0, HOST_BLKSIZE(host)); - au_writel(0x001fffff, HOST_TIMEOUT(host)); - au_sync(); - - au_writel(SD_CONFIG2_EN, HOST_CONFIG2(host)); - au_sync(); - - au_writel(SD_CONFIG2_EN | SD_CONFIG2_FF, HOST_CONFIG2(host)); - au_sync_delay(1); - - au_writel(SD_CONFIG2_EN, HOST_CONFIG2(host)); - au_sync(); - - /* Configure interrupts */ - au_writel(AU1XMMC_INTERRUPTS, HOST_CONFIG(host)); - au_sync(); -} - - -static void au1xmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) -{ - struct au1xmmc_host *host = mmc_priv(mmc); - u32 config2; - - if (ios->power_mode == MMC_POWER_OFF) - au1xmmc_set_power(host, 0); - else if (ios->power_mode == MMC_POWER_ON) { - au1xmmc_set_power(host, 1); - } - - if (ios->clock && ios->clock != host->clock) { - au1xmmc_set_clock(host, ios->clock); - host->clock = ios->clock; - } - - config2 = au_readl(HOST_CONFIG2(host)); - switch (ios->bus_width) { - case MMC_BUS_WIDTH_8: - config2 |= SD_CONFIG2_BB; - break; - case MMC_BUS_WIDTH_4: - config2 &= ~SD_CONFIG2_BB; - config2 |= SD_CONFIG2_WB; - break; - case MMC_BUS_WIDTH_1: - config2 &= ~(SD_CONFIG2_WB | SD_CONFIG2_BB); - break; - } - au_writel(config2, HOST_CONFIG2(host)); - au_sync(); -} - -#define STATUS_TIMEOUT (SD_STATUS_RAT | SD_STATUS_DT) -#define STATUS_DATA_IN (SD_STATUS_NE) -#define STATUS_DATA_OUT (SD_STATUS_TH) - -static irqreturn_t au1xmmc_irq(int irq, void *dev_id) -{ - struct au1xmmc_host *host = dev_id; - u32 status; - - status = au_readl(HOST_STATUS(host)); - - if (!(status & SD_STATUS_I)) - return IRQ_NONE; /* not ours */ - - if (status & SD_STATUS_SI) /* SDIO */ - mmc_signal_sdio_irq(host->mmc); - - if (host->mrq && (status & STATUS_TIMEOUT)) { - if (status & SD_STATUS_RAT) - host->mrq->cmd->error = -ETIMEDOUT; - else if (status & SD_STATUS_DT) - host->mrq->data->error = -ETIMEDOUT; - - /* In PIO mode, interrupts might still be enabled */ - IRQ_OFF(host, SD_CONFIG_NE | SD_CONFIG_TH); - - /* IRQ_OFF(host, SD_CONFIG_TH | SD_CONFIG_RA | SD_CONFIG_RF); */ - tasklet_schedule(&host->finish_task); - } -#if 0 - else if (status & SD_STATUS_DD) { - /* Sometimes we get a DD before a NE in PIO mode */ - if (!(host->flags & HOST_F_DMA) && (status & SD_STATUS_NE)) - au1xmmc_receive_pio(host); - else { - au1xmmc_data_complete(host, status); - /* tasklet_schedule(&host->data_task); */ - } - } -#endif - else if (status & SD_STATUS_CR) { - if (host->status == HOST_S_CMD) - au1xmmc_cmd_complete(host, status); - - } else if (!(host->flags & HOST_F_DMA)) { - if ((host->flags & HOST_F_XMIT) && (status & STATUS_DATA_OUT)) - au1xmmc_send_pio(host); - else if ((host->flags & HOST_F_RECV) && (status & STATUS_DATA_IN)) - au1xmmc_receive_pio(host); - - } else if (status & 0x203F3C70) { - DBG("Unhandled status %8.8x\n", host->pdev->id, - status); - } - - au_writel(status, HOST_STATUS(host)); - au_sync(); - - return IRQ_HANDLED; -} - -/* 8bit memory DMA device */ -static dbdev_tab_t au1xmmc_mem_dbdev = { - .dev_id = DSCR_CMD0_ALWAYS, - .dev_flags = DEV_FLAGS_ANYUSE, - .dev_tsize = 0, - .dev_devwidth = 8, - .dev_physaddr = 0x00000000, - .dev_intlevel = 0, - .dev_intpolarity = 0, -}; -static int memid; - -static void au1xmmc_dbdma_callback(int irq, void *dev_id) -{ - struct au1xmmc_host *host = (struct au1xmmc_host *)dev_id; - - /* Avoid spurious interrupts */ - if (!host->mrq) - return; - - if (host->flags & HOST_F_STOP) - SEND_STOP(host); - - tasklet_schedule(&host->data_task); -} - -static int au1xmmc_dbdma_init(struct au1xmmc_host *host) -{ - struct resource *res; - int txid, rxid; - - res = platform_get_resource(host->pdev, IORESOURCE_DMA, 0); - if (!res) - return -ENODEV; - txid = res->start; - - res = platform_get_resource(host->pdev, IORESOURCE_DMA, 1); - if (!res) - return -ENODEV; - rxid = res->start; - - if (!memid) - return -ENODEV; - - host->tx_chan = au1xxx_dbdma_chan_alloc(memid, txid, - au1xmmc_dbdma_callback, (void *)host); - if (!host->tx_chan) { - dev_err(&host->pdev->dev, "cannot allocate TX DMA\n"); - return -ENODEV; - } - - host->rx_chan = au1xxx_dbdma_chan_alloc(rxid, memid, - au1xmmc_dbdma_callback, (void *)host); - if (!host->rx_chan) { - dev_err(&host->pdev->dev, "cannot allocate RX DMA\n"); - au1xxx_dbdma_chan_free(host->tx_chan); - return -ENODEV; - } - - au1xxx_dbdma_set_devwidth(host->tx_chan, 8); - au1xxx_dbdma_set_devwidth(host->rx_chan, 8); - - au1xxx_dbdma_ring_alloc(host->tx_chan, AU1XMMC_DESCRIPTOR_COUNT); - au1xxx_dbdma_ring_alloc(host->rx_chan, AU1XMMC_DESCRIPTOR_COUNT); - - /* DBDMA is good to go */ - host->flags |= HOST_F_DMA | HOST_F_DBDMA; - - return 0; -} - -static void au1xmmc_dbdma_shutdown(struct au1xmmc_host *host) -{ - if (host->flags & HOST_F_DMA) { - host->flags &= ~HOST_F_DMA; - au1xxx_dbdma_chan_free(host->tx_chan); - au1xxx_dbdma_chan_free(host->rx_chan); - } -} - -static void au1xmmc_enable_sdio_irq(struct mmc_host *mmc, int en) -{ - struct au1xmmc_host *host = mmc_priv(mmc); - - if (en) - IRQ_ON(host, SD_CONFIG_SI); - else - IRQ_OFF(host, SD_CONFIG_SI); -} - -static const struct mmc_host_ops au1xmmc_ops = { - .request = au1xmmc_request, - .set_ios = au1xmmc_set_ios, - .get_ro = au1xmmc_card_readonly, - .get_cd = au1xmmc_card_inserted, - .enable_sdio_irq = au1xmmc_enable_sdio_irq, -}; - -static int __devinit au1xmmc_probe(struct platform_device *pdev) -{ - struct mmc_host *mmc; - struct au1xmmc_host *host; - struct resource *r; - int ret, iflag; - - mmc = mmc_alloc_host(sizeof(struct au1xmmc_host), &pdev->dev); - if (!mmc) { - dev_err(&pdev->dev, "no memory for mmc_host\n"); - ret = -ENOMEM; - goto out0; - } - - host = mmc_priv(mmc); - host->mmc = mmc; - host->platdata = pdev->dev.platform_data; - host->pdev = pdev; - - ret = -ENODEV; - r = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!r) { - dev_err(&pdev->dev, "no mmio defined\n"); - goto out1; - } - - host->ioarea = request_mem_region(r->start, resource_size(r), - pdev->name); - if (!host->ioarea) { - dev_err(&pdev->dev, "mmio already in use\n"); - goto out1; - } - - host->iobase = (unsigned long)ioremap(r->start, 0x3c); - if (!host->iobase) { - dev_err(&pdev->dev, "cannot remap mmio\n"); - goto out2; - } - - r = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!r) { - dev_err(&pdev->dev, "no IRQ defined\n"); - goto out3; - } - host->irq = r->start; - - mmc->ops = &au1xmmc_ops; - - mmc->f_min = 450000; - mmc->f_max = 24000000; - - mmc->max_blk_size = 2048; - mmc->max_blk_count = 512; - - mmc->ocr_avail = AU1XMMC_OCR; - mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ; - mmc->max_segs = AU1XMMC_DESCRIPTOR_COUNT; - - iflag = IRQF_SHARED; /* Au1100/Au1200: one int for both ctrls */ - - switch (alchemy_get_cputype()) { - case ALCHEMY_CPU_AU1100: - mmc->max_seg_size = AU1100_MMC_DESCRIPTOR_SIZE; - break; - case ALCHEMY_CPU_AU1200: - mmc->max_seg_size = AU1200_MMC_DESCRIPTOR_SIZE; - break; - case ALCHEMY_CPU_AU1300: - iflag = 0; /* nothing is shared */ - mmc->max_seg_size = AU1200_MMC_DESCRIPTOR_SIZE; - mmc->f_max = 52000000; - if (host->ioarea->start == AU1100_SD0_PHYS_ADDR) - mmc->caps |= MMC_CAP_8_BIT_DATA; - break; - } - - ret = request_irq(host->irq, au1xmmc_irq, iflag, DRIVER_NAME, host); - if (ret) { - dev_err(&pdev->dev, "cannot grab IRQ\n"); - goto out3; - } - - host->status = HOST_S_IDLE; - - /* board-specific carddetect setup, if any */ - if (host->platdata && host->platdata->cd_setup) { - ret = host->platdata->cd_setup(mmc, 1); - if (ret) { - dev_warn(&pdev->dev, "board CD setup failed\n"); - mmc->caps |= MMC_CAP_NEEDS_POLL; - } - } else - mmc->caps |= MMC_CAP_NEEDS_POLL; - - /* platform may not be able to use all advertised caps */ - if (host->platdata) - mmc->caps &= ~(host->platdata->mask_host_caps); - - tasklet_init(&host->data_task, au1xmmc_tasklet_data, - (unsigned long)host); - - tasklet_init(&host->finish_task, au1xmmc_tasklet_finish, - (unsigned long)host); - - if (has_dbdma()) { - ret = au1xmmc_dbdma_init(host); - if (ret) - pr_info(DRIVER_NAME ": DBDMA init failed; using PIO\n"); - } - -#ifdef CONFIG_LEDS_CLASS - if (host->platdata && host->platdata->led) { - struct led_classdev *led = host->platdata->led; - led->name = mmc_hostname(mmc); - led->brightness = LED_OFF; - led->default_trigger = mmc_hostname(mmc); - ret = led_classdev_register(mmc_dev(mmc), led); - if (ret) - goto out5; - } -#endif - - au1xmmc_reset_controller(host); - - ret = mmc_add_host(mmc); - if (ret) { - dev_err(&pdev->dev, "cannot add mmc host\n"); - goto out6; - } - - platform_set_drvdata(pdev, host); - - pr_info(DRIVER_NAME ": MMC Controller %d set up at %8.8X" - " (mode=%s)\n", pdev->id, host->iobase, - host->flags & HOST_F_DMA ? "dma" : "pio"); - - return 0; /* all ok */ - -out6: -#ifdef CONFIG_LEDS_CLASS - if (host->platdata && host->platdata->led) - led_classdev_unregister(host->platdata->led); -out5: -#endif - au_writel(0, HOST_ENABLE(host)); - au_writel(0, HOST_CONFIG(host)); - au_writel(0, HOST_CONFIG2(host)); - au_sync(); - - if (host->flags & HOST_F_DBDMA) - au1xmmc_dbdma_shutdown(host); - - tasklet_kill(&host->data_task); - tasklet_kill(&host->finish_task); - - if (host->platdata && host->platdata->cd_setup && - !(mmc->caps & MMC_CAP_NEEDS_POLL)) - host->platdata->cd_setup(mmc, 0); - - free_irq(host->irq, host); -out3: - iounmap((void *)host->iobase); -out2: - release_resource(host->ioarea); - kfree(host->ioarea); -out1: - mmc_free_host(mmc); -out0: - return ret; -} - -static int __devexit au1xmmc_remove(struct platform_device *pdev) -{ - struct au1xmmc_host *host = platform_get_drvdata(pdev); - - if (host) { - mmc_remove_host(host->mmc); - -#ifdef CONFIG_LEDS_CLASS - if (host->platdata && host->platdata->led) - led_classdev_unregister(host->platdata->led); -#endif - - if (host->platdata && host->platdata->cd_setup && - !(host->mmc->caps & MMC_CAP_NEEDS_POLL)) - host->platdata->cd_setup(host->mmc, 0); - - au_writel(0, HOST_ENABLE(host)); - au_writel(0, HOST_CONFIG(host)); - au_writel(0, HOST_CONFIG2(host)); - au_sync(); - - tasklet_kill(&host->data_task); - tasklet_kill(&host->finish_task); - - if (host->flags & HOST_F_DBDMA) - au1xmmc_dbdma_shutdown(host); - - au1xmmc_set_power(host, 0); - - free_irq(host->irq, host); - iounmap((void *)host->iobase); - release_resource(host->ioarea); - kfree(host->ioarea); - - mmc_free_host(host->mmc); - platform_set_drvdata(pdev, NULL); - } - return 0; -} - -#ifdef CONFIG_PM -static int au1xmmc_suspend(struct platform_device *pdev, pm_message_t state) -{ - struct au1xmmc_host *host = platform_get_drvdata(pdev); - int ret; - - ret = mmc_suspend_host(host->mmc); - if (ret) - return ret; - - au_writel(0, HOST_CONFIG2(host)); - au_writel(0, HOST_CONFIG(host)); - au_writel(0xffffffff, HOST_STATUS(host)); - au_writel(0, HOST_ENABLE(host)); - au_sync(); - - return 0; -} - -static int au1xmmc_resume(struct platform_device *pdev) -{ - struct au1xmmc_host *host = platform_get_drvdata(pdev); - - au1xmmc_reset_controller(host); - - return mmc_resume_host(host->mmc); -} -#else -#define au1xmmc_suspend NULL -#define au1xmmc_resume NULL -#endif - -static struct platform_driver au1xmmc_driver = { - .probe = au1xmmc_probe, - .remove = au1xmmc_remove, - .suspend = au1xmmc_suspend, - .resume = au1xmmc_resume, - .driver = { - .name = DRIVER_NAME, - .owner = THIS_MODULE, - }, -}; - -static int __init au1xmmc_init(void) -{ - if (has_dbdma()) { - /* DSCR_CMD0_ALWAYS has a stride of 32 bits, we need a stride - * of 8 bits. And since devices are shared, we need to create - * our own to avoid freaking out other devices. - */ - memid = au1xxx_ddma_add_device(&au1xmmc_mem_dbdev); - if (!memid) - pr_err("au1xmmc: cannot add memory dbdma\n"); - } - return platform_driver_register(&au1xmmc_driver); -} - -static void __exit au1xmmc_exit(void) -{ - if (has_dbdma() && memid) - au1xxx_ddma_del_device(memid); - - platform_driver_unregister(&au1xmmc_driver); -} - -module_init(au1xmmc_init); -module_exit(au1xmmc_exit); - -MODULE_AUTHOR("Advanced Micro Devices, Inc"); -MODULE_DESCRIPTION("MMC/SD driver for the Alchemy Au1XXX"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:au1xxx-mmc"); diff --git a/ANDROID_3.4.5/drivers/mmc/host/bfin_sdh.c b/ANDROID_3.4.5/drivers/mmc/host/bfin_sdh.c deleted file mode 100644 index 03666174..00000000 --- a/ANDROID_3.4.5/drivers/mmc/host/bfin_sdh.c +++ /dev/null @@ -1,634 +0,0 @@ -/* - * bfin_sdh.c - Analog Devices Blackfin SDH Controller - * - * Copyright (C) 2007-2009 Analog Device Inc. - * - * Licensed under the GPL-2 or later. - */ - -#define DRIVER_NAME "bfin-sdh" - -#include <linux/module.h> -#include <linux/init.h> -#include <linux/ioport.h> -#include <linux/platform_device.h> -#include <linux/delay.h> -#include <linux/interrupt.h> -#include <linux/dma-mapping.h> -#include <linux/mmc/host.h> -#include <linux/proc_fs.h> -#include <linux/gfp.h> - -#include <asm/cacheflush.h> -#include <asm/dma.h> -#include <asm/portmux.h> -#include <asm/bfin_sdh.h> - -#if defined(CONFIG_BF51x) -#define bfin_read_SDH_PWR_CTL bfin_read_RSI_PWR_CTL -#define bfin_write_SDH_PWR_CTL bfin_write_RSI_PWR_CTL -#define bfin_read_SDH_CLK_CTL bfin_read_RSI_CLK_CTL -#define bfin_write_SDH_CLK_CTL bfin_write_RSI_CLK_CTL -#define bfin_write_SDH_ARGUMENT bfin_write_RSI_ARGUMENT -#define bfin_write_SDH_COMMAND bfin_write_RSI_COMMAND -#define bfin_write_SDH_DATA_TIMER bfin_write_RSI_DATA_TIMER -#define bfin_read_SDH_RESPONSE0 bfin_read_RSI_RESPONSE0 -#define bfin_read_SDH_RESPONSE1 bfin_read_RSI_RESPONSE1 -#define bfin_read_SDH_RESPONSE2 bfin_read_RSI_RESPONSE2 -#define bfin_read_SDH_RESPONSE3 bfin_read_RSI_RESPONSE3 -#define bfin_write_SDH_DATA_LGTH bfin_write_RSI_DATA_LGTH -#define bfin_read_SDH_DATA_CTL bfin_read_RSI_DATA_CTL -#define bfin_write_SDH_DATA_CTL bfin_write_RSI_DATA_CTL -#define bfin_read_SDH_DATA_CNT bfin_read_RSI_DATA_CNT -#define bfin_write_SDH_STATUS_CLR bfin_write_RSI_STATUS_CLR -#define bfin_read_SDH_E_STATUS bfin_read_RSI_E_STATUS -#define bfin_write_SDH_E_STATUS bfin_write_RSI_E_STATUS -#define bfin_read_SDH_STATUS bfin_read_RSI_STATUS -#define bfin_write_SDH_MASK0 bfin_write_RSI_MASK0 -#define bfin_read_SDH_CFG bfin_read_RSI_CFG -#define bfin_write_SDH_CFG bfin_write_RSI_CFG -#endif - -struct dma_desc_array { - unsigned long start_addr; - unsigned short cfg; - unsigned short x_count; - short x_modify; -} __packed; - -struct sdh_host { - struct mmc_host *mmc; - spinlock_t lock; - struct resource *res; - void __iomem *base; - int irq; - int stat_irq; - int dma_ch; - int dma_dir; - struct dma_desc_array *sg_cpu; - dma_addr_t sg_dma; - int dma_len; - - unsigned int imask; - unsigned int power_mode; - unsigned int clk_div; - - struct mmc_request *mrq; - struct mmc_command *cmd; - struct mmc_data *data; -}; - -static struct bfin_sd_host *get_sdh_data(struct platform_device *pdev) -{ - return pdev->dev.platform_data; -} - -static void sdh_stop_clock(struct sdh_host *host) -{ - bfin_write_SDH_CLK_CTL(bfin_read_SDH_CLK_CTL() & ~CLK_E); - SSYNC(); -} - -static void sdh_enable_stat_irq(struct sdh_host *host, unsigned int mask) -{ - unsigned long flags; - - spin_lock_irqsave(&host->lock, flags); - host->imask |= mask; - bfin_write_SDH_MASK0(mask); - SSYNC(); - spin_unlock_irqrestore(&host->lock, flags); -} - -static void sdh_disable_stat_irq(struct sdh_host *host, unsigned int mask) -{ - unsigned long flags; - - spin_lock_irqsave(&host->lock, flags); - host->imask &= ~mask; - bfin_write_SDH_MASK0(host->imask); - SSYNC(); - spin_unlock_irqrestore(&host->lock, flags); -} - -static int sdh_setup_data(struct sdh_host *host, struct mmc_data *data) -{ - unsigned int length; - unsigned int data_ctl; - unsigned int dma_cfg; - unsigned int cycle_ns, timeout; - - dev_dbg(mmc_dev(host->mmc), "%s enter flags: 0x%x\n", __func__, data->flags); - host->data = data; - data_ctl = 0; - dma_cfg = 0; - - length = data->blksz * data->blocks; - bfin_write_SDH_DATA_LGTH(length); - - if (data->flags & MMC_DATA_STREAM) - data_ctl |= DTX_MODE; - - if (data->flags & MMC_DATA_READ) - data_ctl |= DTX_DIR; - /* Only supports power-of-2 block size */ - if (data->blksz & (data->blksz - 1)) - return -EINVAL; - data_ctl |= ((ffs(data->blksz) - 1) << 4); - - bfin_write_SDH_DATA_CTL(data_ctl); - /* the time of a host clock period in ns */ - cycle_ns = 1000000000 / (get_sclk() / (2 * (host->clk_div + 1))); - timeout = data->timeout_ns / cycle_ns; - timeout += data->timeout_clks; - bfin_write_SDH_DATA_TIMER(timeout); - SSYNC(); - - if (data->flags & MMC_DATA_READ) { - host->dma_dir = DMA_FROM_DEVICE; - dma_cfg |= WNR; - } else - host->dma_dir = DMA_TO_DEVICE; - - sdh_enable_stat_irq(host, (DAT_CRC_FAIL | DAT_TIME_OUT | DAT_END)); - host->dma_len = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len, host->dma_dir); -#if defined(CONFIG_BF54x) - dma_cfg |= DMAFLOW_ARRAY | NDSIZE_5 | RESTART | WDSIZE_32 | DMAEN; - { - struct scatterlist *sg; - int i; - for_each_sg(data->sg, sg, host->dma_len, i) { - host->sg_cpu[i].start_addr = sg_dma_address(sg); - host->sg_cpu[i].cfg = dma_cfg; - host->sg_cpu[i].x_count = sg_dma_len(sg) / 4; - host->sg_cpu[i].x_modify = 4; - dev_dbg(mmc_dev(host->mmc), "%d: start_addr:0x%lx, " - "cfg:0x%x, x_count:0x%x, x_modify:0x%x\n", - i, host->sg_cpu[i].start_addr, - host->sg_cpu[i].cfg, host->sg_cpu[i].x_count, - host->sg_cpu[i].x_modify); - } - } - flush_dcache_range((unsigned int)host->sg_cpu, - (unsigned int)host->sg_cpu + - host->dma_len * sizeof(struct dma_desc_array)); - /* Set the last descriptor to stop mode */ - host->sg_cpu[host->dma_len - 1].cfg &= ~(DMAFLOW | NDSIZE); - host->sg_cpu[host->dma_len - 1].cfg |= DI_EN; - - set_dma_curr_desc_addr(host->dma_ch, (unsigned long *)host->sg_dma); - set_dma_x_count(host->dma_ch, 0); - set_dma_x_modify(host->dma_ch, 0); - set_dma_config(host->dma_ch, dma_cfg); -#elif defined(CONFIG_BF51x) - /* RSI DMA doesn't work in array mode */ - dma_cfg |= WDSIZE_32 | DMAEN; - set_dma_start_addr(host->dma_ch, sg_dma_address(&data->sg[0])); - set_dma_x_count(host->dma_ch, length / 4); - set_dma_x_modify(host->dma_ch, 4); - set_dma_config(host->dma_ch, dma_cfg); -#endif - bfin_write_SDH_DATA_CTL(bfin_read_SDH_DATA_CTL() | DTX_DMA_E | DTX_E); - - SSYNC(); - - dev_dbg(mmc_dev(host->mmc), "%s exit\n", __func__); - return 0; -} - -static void sdh_start_cmd(struct sdh_host *host, struct mmc_command *cmd) -{ - unsigned int sdh_cmd; - unsigned int stat_mask; - - dev_dbg(mmc_dev(host->mmc), "%s enter cmd: 0x%p\n", __func__, cmd); - WARN_ON(host->cmd != NULL); - host->cmd = cmd; - - sdh_cmd = 0; - stat_mask = 0; - - sdh_cmd |= cmd->opcode; - - if (cmd->flags & MMC_RSP_PRESENT) { - sdh_cmd |= CMD_RSP; - stat_mask |= CMD_RESP_END; - } else { - stat_mask |= CMD_SENT; - } - - if (cmd->flags & MMC_RSP_136) - sdh_cmd |= CMD_L_RSP; - - stat_mask |= CMD_CRC_FAIL | CMD_TIME_OUT; - - sdh_enable_stat_irq(host, stat_mask); - - bfin_write_SDH_ARGUMENT(cmd->arg); - bfin_write_SDH_COMMAND(sdh_cmd | CMD_E); - bfin_write_SDH_CLK_CTL(bfin_read_SDH_CLK_CTL() | CLK_E); - SSYNC(); -} - -static void sdh_finish_request(struct sdh_host *host, struct mmc_request *mrq) -{ - dev_dbg(mmc_dev(host->mmc), "%s enter\n", __func__); - host->mrq = NULL; - host->cmd = NULL; - host->data = NULL; - mmc_request_done(host->mmc, mrq); -} - -static int sdh_cmd_done(struct sdh_host *host, unsigned int stat) -{ - struct mmc_command *cmd = host->cmd; - int ret = 0; - - dev_dbg(mmc_dev(host->mmc), "%s enter cmd: %p\n", __func__, cmd); - if (!cmd) - return 0; - - host->cmd = NULL; - - if (cmd->flags & MMC_RSP_PRESENT) { - cmd->resp[0] = bfin_read_SDH_RESPONSE0(); - if (cmd->flags & MMC_RSP_136) { - cmd->resp[1] = bfin_read_SDH_RESPONSE1(); - cmd->resp[2] = bfin_read_SDH_RESPONSE2(); - cmd->resp[3] = bfin_read_SDH_RESPONSE3(); - } - } - if (stat & CMD_TIME_OUT) - cmd->error = -ETIMEDOUT; - else if (stat & CMD_CRC_FAIL && cmd->flags & MMC_RSP_CRC) - cmd->error = -EILSEQ; - - sdh_disable_stat_irq(host, (CMD_SENT | CMD_RESP_END | CMD_TIME_OUT | CMD_CRC_FAIL)); - - if (host->data && !cmd->error) { - if (host->data->flags & MMC_DATA_WRITE) { - ret = sdh_setup_data(host, host->data); - if (ret) - return 0; - } - - sdh_enable_stat_irq(host, DAT_END | RX_OVERRUN | TX_UNDERRUN | DAT_TIME_OUT); - } else - sdh_finish_request(host, host->mrq); - - return 1; -} - -static int sdh_data_done(struct sdh_host *host, unsigned int stat) -{ - struct mmc_data *data = host->data; - - dev_dbg(mmc_dev(host->mmc), "%s enter stat: 0x%x\n", __func__, stat); - if (!data) - return 0; - - disable_dma(host->dma_ch); - dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len, - host->dma_dir); - - if (stat & DAT_TIME_OUT) - data->error = -ETIMEDOUT; - else if (stat & DAT_CRC_FAIL) - data->error = -EILSEQ; - else if (stat & (RX_OVERRUN | TX_UNDERRUN)) - data->error = -EIO; - - if (!data->error) - data->bytes_xfered = data->blocks * data->blksz; - else - data->bytes_xfered = 0; - - sdh_disable_stat_irq(host, DAT_END | DAT_TIME_OUT | DAT_CRC_FAIL | RX_OVERRUN | TX_UNDERRUN); - bfin_write_SDH_STATUS_CLR(DAT_END_STAT | DAT_TIMEOUT_STAT | \ - DAT_CRC_FAIL_STAT | DAT_BLK_END_STAT | RX_OVERRUN | TX_UNDERRUN); - bfin_write_SDH_DATA_CTL(0); - SSYNC(); - - host->data = NULL; - if (host->mrq->stop) { - sdh_stop_clock(host); - sdh_start_cmd(host, host->mrq->stop); - } else { - sdh_finish_request(host, host->mrq); - } - - return 1; -} - -static void sdh_request(struct mmc_host *mmc, struct mmc_request *mrq) -{ - struct sdh_host *host = mmc_priv(mmc); - int ret = 0; - - dev_dbg(mmc_dev(host->mmc), "%s enter, mrp:%p, cmd:%p\n", __func__, mrq, mrq->cmd); - WARN_ON(host->mrq != NULL); - - host->mrq = mrq; - host->data = mrq->data; - - if (mrq->data && mrq->data->flags & MMC_DATA_READ) { - ret = sdh_setup_data(host, mrq->data); - if (ret) - return; - } - - sdh_start_cmd(host, mrq->cmd); -} - -static void sdh_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) -{ - struct sdh_host *host; - unsigned long flags; - u16 clk_ctl = 0; - u16 pwr_ctl = 0; - u16 cfg; - host = mmc_priv(mmc); - - spin_lock_irqsave(&host->lock, flags); - if (ios->clock) { - unsigned long sys_clk, ios_clk; - unsigned char clk_div; - ios_clk = 2 * ios->clock; - sys_clk = get_sclk(); - clk_div = sys_clk / ios_clk; - if (sys_clk % ios_clk == 0) - clk_div -= 1; - clk_div = min_t(unsigned char, clk_div, 0xFF); - clk_ctl |= clk_div; - clk_ctl |= CLK_E; - host->clk_div = clk_div; - } else - sdh_stop_clock(host); - - if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN) -#ifdef CONFIG_SDH_BFIN_MISSING_CMD_PULLUP_WORKAROUND - pwr_ctl |= ROD_CTL; -#else - pwr_ctl |= SD_CMD_OD | ROD_CTL; -#endif - - if (ios->bus_width == MMC_BUS_WIDTH_4) { - cfg = bfin_read_SDH_CFG(); - cfg &= ~PD_SDDAT3; - cfg |= PUP_SDDAT3; - /* Enable 4 bit SDIO */ - cfg |= (SD4E | MWE); - bfin_write_SDH_CFG(cfg); - clk_ctl |= WIDE_BUS; - } else { - cfg = bfin_read_SDH_CFG(); - cfg |= MWE; - bfin_write_SDH_CFG(cfg); - } - - bfin_write_SDH_CLK_CTL(clk_ctl); - - host->power_mode = ios->power_mode; - if (ios->power_mode == MMC_POWER_ON) - pwr_ctl |= PWR_ON; - - bfin_write_SDH_PWR_CTL(pwr_ctl); - SSYNC(); - - spin_unlock_irqrestore(&host->lock, flags); - - dev_dbg(mmc_dev(host->mmc), "SDH: clk_div = 0x%x actual clock:%ld expected clock:%d\n", - host->clk_div, - host->clk_div ? get_sclk() / (2 * (host->clk_div + 1)) : 0, - ios->clock); -} - -static const struct mmc_host_ops sdh_ops = { - .request = sdh_request, - .set_ios = sdh_set_ios, -}; - -static irqreturn_t sdh_dma_irq(int irq, void *devid) -{ - struct sdh_host *host = devid; - - dev_dbg(mmc_dev(host->mmc), "%s enter, irq_stat: 0x%04x\n", __func__, - get_dma_curr_irqstat(host->dma_ch)); - clear_dma_irqstat(host->dma_ch); - SSYNC(); - - return IRQ_HANDLED; -} - -static irqreturn_t sdh_stat_irq(int irq, void *devid) -{ - struct sdh_host *host = devid; - unsigned int status; - int handled = 0; - - dev_dbg(mmc_dev(host->mmc), "%s enter\n", __func__); - status = bfin_read_SDH_E_STATUS(); - if (status & SD_CARD_DET) { - mmc_detect_change(host->mmc, 0); - bfin_write_SDH_E_STATUS(SD_CARD_DET); - } - status = bfin_read_SDH_STATUS(); - if (status & (CMD_SENT | CMD_RESP_END | CMD_TIME_OUT | CMD_CRC_FAIL)) { - handled |= sdh_cmd_done(host, status); - bfin_write_SDH_STATUS_CLR(CMD_SENT_STAT | CMD_RESP_END_STAT | \ - CMD_TIMEOUT_STAT | CMD_CRC_FAIL_STAT); - SSYNC(); - } - - status = bfin_read_SDH_STATUS(); - if (status & (DAT_END | DAT_TIME_OUT | DAT_CRC_FAIL | RX_OVERRUN | TX_UNDERRUN)) - handled |= sdh_data_done(host, status); - - dev_dbg(mmc_dev(host->mmc), "%s exit\n\n", __func__); - - return IRQ_RETVAL(handled); -} - -static int __devinit sdh_probe(struct platform_device *pdev) -{ - struct mmc_host *mmc; - struct sdh_host *host; - struct bfin_sd_host *drv_data = get_sdh_data(pdev); - int ret; - - if (!drv_data) { - dev_err(&pdev->dev, "missing platform driver data\n"); - ret = -EINVAL; - goto out; - } - - mmc = mmc_alloc_host(sizeof(struct sdh_host), &pdev->dev); - if (!mmc) { - ret = -ENOMEM; - goto out; - } - - mmc->ops = &sdh_ops; - mmc->max_segs = 32; - mmc->max_seg_size = 1 << 16; - mmc->max_blk_size = 1 << 11; - mmc->max_blk_count = 1 << 11; - mmc->max_req_size = PAGE_SIZE; - mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; - mmc->f_max = get_sclk(); - mmc->f_min = mmc->f_max >> 9; - mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_NEEDS_POLL; - host = mmc_priv(mmc); - host->mmc = mmc; - - spin_lock_init(&host->lock); - host->irq = drv_data->irq_int0; - host->dma_ch = drv_data->dma_chan; - - ret = request_dma(host->dma_ch, DRIVER_NAME "DMA"); - if (ret) { - dev_err(&pdev->dev, "unable to request DMA channel\n"); - goto out1; - } - - ret = set_dma_callback(host->dma_ch, sdh_dma_irq, host); - if (ret) { - dev_err(&pdev->dev, "unable to request DMA irq\n"); - goto out2; - } - - host->sg_cpu = dma_alloc_coherent(&pdev->dev, PAGE_SIZE, &host->sg_dma, GFP_KERNEL); - if (host->sg_cpu == NULL) { - ret = -ENOMEM; - goto out2; - } - - platform_set_drvdata(pdev, mmc); - mmc_add_host(mmc); - - ret = request_irq(host->irq, sdh_stat_irq, 0, "SDH Status IRQ", host); - if (ret) { - dev_err(&pdev->dev, "unable to request status irq\n"); - goto out3; - } - - ret = peripheral_request_list(drv_data->pin_req, DRIVER_NAME); - if (ret) { - dev_err(&pdev->dev, "unable to request peripheral pins\n"); - goto out4; - } -#if defined(CONFIG_BF54x) - /* Secure Digital Host shares DMA with Nand controller */ - bfin_write_DMAC1_PERIMUX(bfin_read_DMAC1_PERIMUX() | 0x1); -#endif - - bfin_write_SDH_CFG(bfin_read_SDH_CFG() | CLKS_EN); - SSYNC(); - - /* Disable card inserting detection pin. set MMC_CAP_NEES_POLL, and - * mmc stack will do the detection. - */ - bfin_write_SDH_CFG((bfin_read_SDH_CFG() & 0x1F) | (PUP_SDDAT | PUP_SDDAT3)); - SSYNC(); - - return 0; - -out4: - free_irq(host->irq, host); -out3: - mmc_remove_host(mmc); - dma_free_coherent(&pdev->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma); -out2: - free_dma(host->dma_ch); -out1: - mmc_free_host(mmc); - out: - return ret; -} - -static int __devexit sdh_remove(struct platform_device *pdev) -{ - struct mmc_host *mmc = platform_get_drvdata(pdev); - - platform_set_drvdata(pdev, NULL); - - if (mmc) { - struct sdh_host *host = mmc_priv(mmc); - - mmc_remove_host(mmc); - - sdh_stop_clock(host); - free_irq(host->irq, host); - free_dma(host->dma_ch); - dma_free_coherent(&pdev->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma); - - mmc_free_host(mmc); - } - - return 0; -} - -#ifdef CONFIG_PM -static int sdh_suspend(struct platform_device *dev, pm_message_t state) -{ - struct mmc_host *mmc = platform_get_drvdata(dev); - struct bfin_sd_host *drv_data = get_sdh_data(dev); - int ret = 0; - - if (mmc) - ret = mmc_suspend_host(mmc); - - bfin_write_SDH_PWR_CTL(bfin_read_SDH_PWR_CTL() & ~PWR_ON); - peripheral_free_list(drv_data->pin_req); - - return ret; -} - -static int sdh_resume(struct platform_device *dev) -{ - struct mmc_host *mmc = platform_get_drvdata(dev); - struct bfin_sd_host *drv_data = get_sdh_data(dev); - int ret = 0; - - ret = peripheral_request_list(drv_data->pin_req, DRIVER_NAME); - if (ret) { - dev_err(&dev->dev, "unable to request peripheral pins\n"); - return ret; - } - - bfin_write_SDH_PWR_CTL(bfin_read_SDH_PWR_CTL() | PWR_ON); -#if defined(CONFIG_BF54x) - /* Secure Digital Host shares DMA with Nand controller */ - bfin_write_DMAC1_PERIMUX(bfin_read_DMAC1_PERIMUX() | 0x1); -#endif - bfin_write_SDH_CFG(bfin_read_SDH_CFG() | CLKS_EN); - SSYNC(); - - bfin_write_SDH_CFG((bfin_read_SDH_CFG() & 0x1F) | (PUP_SDDAT | PUP_SDDAT3)); - SSYNC(); - - if (mmc) - ret = mmc_resume_host(mmc); - - return ret; -} -#else -# define sdh_suspend NULL -# define sdh_resume NULL -#endif - -static struct platform_driver sdh_driver = { - .probe = sdh_probe, - .remove = __devexit_p(sdh_remove), - .suspend = sdh_suspend, - .resume = sdh_resume, - .driver = { - .name = DRIVER_NAME, - }, -}; - -module_platform_driver(sdh_driver); - -MODULE_DESCRIPTION("Blackfin Secure Digital Host Driver"); -MODULE_AUTHOR("Cliff Cai, Roy Huang"); -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/mmc/host/cb710-mmc.c b/ANDROID_3.4.5/drivers/mmc/host/cb710-mmc.c deleted file mode 100644 index 83693fd7..00000000 --- a/ANDROID_3.4.5/drivers/mmc/host/cb710-mmc.c +++ /dev/null @@ -1,788 +0,0 @@ -/* - * cb710/mmc.c - * - * Copyright by Michał Mirosław, 2008-2009 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/pci.h> -#include <linux/delay.h> -#include "cb710-mmc.h" - -static const u8 cb710_clock_divider_log2[8] = { -/* 1, 2, 4, 8, 16, 32, 128, 512 */ - 0, 1, 2, 3, 4, 5, 7, 9 -}; -#define CB710_MAX_DIVIDER_IDX \ - (ARRAY_SIZE(cb710_clock_divider_log2) - 1) - -static const u8 cb710_src_freq_mhz[16] = { - 33, 10, 20, 25, 30, 35, 40, 45, - 50, 55, 60, 65, 70, 75, 80, 85 -}; - -static void cb710_mmc_select_clock_divider(struct mmc_host *mmc, int hz) -{ - struct cb710_slot *slot = cb710_mmc_to_slot(mmc); - struct pci_dev *pdev = cb710_slot_to_chip(slot)->pdev; - u32 src_freq_idx; - u32 divider_idx; - int src_hz; - - /* on CB710 in HP nx9500: - * src_freq_idx == 0 - * indexes 1-7 work as written in the table - * indexes 0,8-15 give no clock output - */ - pci_read_config_dword(pdev, 0x48, &src_freq_idx); - src_freq_idx = (src_freq_idx >> 16) & 0xF; - src_hz = cb710_src_freq_mhz[src_freq_idx] * 1000000; - - for (divider_idx = 0; divider_idx < CB710_MAX_DIVIDER_IDX; ++divider_idx) { - if (hz >= src_hz >> cb710_clock_divider_log2[divider_idx]) - break; - } - - if (src_freq_idx) - divider_idx |= 0x8; - else if (divider_idx == 0) - divider_idx = 1; - - cb710_pci_update_config_reg(pdev, 0x40, ~0xF0000000, divider_idx << 28); - - dev_dbg(cb710_slot_dev(slot), - "clock set to %d Hz, wanted %d Hz; src_freq_idx = %d, divider_idx = %d|%d\n", - src_hz >> cb710_clock_divider_log2[divider_idx & 7], - hz, src_freq_idx, divider_idx & 7, divider_idx & 8); -} - -static void __cb710_mmc_enable_irq(struct cb710_slot *slot, - unsigned short enable, unsigned short mask) -{ - /* clear global IE - * - it gets set later if any interrupt sources are enabled */ - mask |= CB710_MMC_IE_IRQ_ENABLE; - - /* look like interrupt is fired whenever - * WORD[0x0C] & WORD[0x10] != 0; - * -> bit 15 port 0x0C seems to be global interrupt enable - */ - - enable = (cb710_read_port_16(slot, CB710_MMC_IRQ_ENABLE_PORT) - & ~mask) | enable; - - if (enable) - enable |= CB710_MMC_IE_IRQ_ENABLE; - - cb710_write_port_16(slot, CB710_MMC_IRQ_ENABLE_PORT, enable); -} - -static void cb710_mmc_enable_irq(struct cb710_slot *slot, - unsigned short enable, unsigned short mask) -{ - struct cb710_mmc_reader *reader = mmc_priv(cb710_slot_to_mmc(slot)); - unsigned long flags; - - spin_lock_irqsave(&reader->irq_lock, flags); - /* this is the only thing irq_lock protects */ - __cb710_mmc_enable_irq(slot, enable, mask); - spin_unlock_irqrestore(&reader->irq_lock, flags); -} - -static void cb710_mmc_reset_events(struct cb710_slot *slot) -{ - cb710_write_port_8(slot, CB710_MMC_STATUS0_PORT, 0xFF); - cb710_write_port_8(slot, CB710_MMC_STATUS1_PORT, 0xFF); - cb710_write_port_8(slot, CB710_MMC_STATUS2_PORT, 0xFF); -} - -static void cb710_mmc_enable_4bit_data(struct cb710_slot *slot, int enable) -{ - if (enable) - cb710_modify_port_8(slot, CB710_MMC_CONFIG1_PORT, - CB710_MMC_C1_4BIT_DATA_BUS, 0); - else - cb710_modify_port_8(slot, CB710_MMC_CONFIG1_PORT, - 0, CB710_MMC_C1_4BIT_DATA_BUS); -} - -static int cb710_check_event(struct cb710_slot *slot, u8 what) -{ - u16 status; - - status = cb710_read_port_16(slot, CB710_MMC_STATUS_PORT); - - if (status & CB710_MMC_S0_FIFO_UNDERFLOW) { - /* it is just a guess, so log it */ - dev_dbg(cb710_slot_dev(slot), - "CHECK : ignoring bit 6 in status %04X\n", status); - cb710_write_port_8(slot, CB710_MMC_STATUS0_PORT, - CB710_MMC_S0_FIFO_UNDERFLOW); - status &= ~CB710_MMC_S0_FIFO_UNDERFLOW; - } - - if (status & CB710_MMC_STATUS_ERROR_EVENTS) { - dev_dbg(cb710_slot_dev(slot), - "CHECK : returning EIO on status %04X\n", status); - cb710_write_port_8(slot, CB710_MMC_STATUS0_PORT, status & 0xFF); - cb710_write_port_8(slot, CB710_MMC_STATUS1_PORT, - CB710_MMC_S1_RESET); - return -EIO; - } - - /* 'what' is a bit in MMC_STATUS1 */ - if ((status >> 8) & what) { - cb710_write_port_8(slot, CB710_MMC_STATUS1_PORT, what); - return 1; - } - - return 0; -} - -static int cb710_wait_for_event(struct cb710_slot *slot, u8 what) -{ - int err = 0; - unsigned limit = 2000000; /* FIXME: real timeout */ - -#ifdef CONFIG_CB710_DEBUG - u32 e, x; - e = cb710_read_port_32(slot, CB710_MMC_STATUS_PORT); -#endif - - while (!(err = cb710_check_event(slot, what))) { - if (!--limit) { - cb710_dump_regs(cb710_slot_to_chip(slot), - CB710_DUMP_REGS_MMC); - err = -ETIMEDOUT; - break; - } - udelay(1); - } - -#ifdef CONFIG_CB710_DEBUG - x = cb710_read_port_32(slot, CB710_MMC_STATUS_PORT); - - limit = 2000000 - limit; - if (limit > 100) - dev_dbg(cb710_slot_dev(slot), - "WAIT10: waited %d loops, what %d, entry val %08X, exit val %08X\n", - limit, what, e, x); -#endif - return err < 0 ? err : 0; -} - - -static int cb710_wait_while_busy(struct cb710_slot *slot, uint8_t mask) -{ - unsigned limit = 500000; /* FIXME: real timeout */ - int err = 0; - -#ifdef CONFIG_CB710_DEBUG - u32 e, x; - e = cb710_read_port_32(slot, CB710_MMC_STATUS_PORT); -#endif - - while (cb710_read_port_8(slot, CB710_MMC_STATUS2_PORT) & mask) { - if (!--limit) { - cb710_dump_regs(cb710_slot_to_chip(slot), - CB710_DUMP_REGS_MMC); - err = -ETIMEDOUT; - break; - } - udelay(1); - } - -#ifdef CONFIG_CB710_DEBUG - x = cb710_read_port_32(slot, CB710_MMC_STATUS_PORT); - - limit = 500000 - limit; - if (limit > 100) - dev_dbg(cb710_slot_dev(slot), - "WAIT12: waited %d loops, mask %02X, entry val %08X, exit val %08X\n", - limit, mask, e, x); -#endif - return err; -} - -static void cb710_mmc_set_transfer_size(struct cb710_slot *slot, - size_t count, size_t blocksize) -{ - cb710_wait_while_busy(slot, CB710_MMC_S2_BUSY_20); - cb710_write_port_32(slot, CB710_MMC_TRANSFER_SIZE_PORT, - ((count - 1) << 16)|(blocksize - 1)); - - dev_vdbg(cb710_slot_dev(slot), "set up for %zu block%s of %zu bytes\n", - count, count == 1 ? "" : "s", blocksize); -} - -static void cb710_mmc_fifo_hack(struct cb710_slot *slot) -{ - /* without this, received data is prepended with 8-bytes of zeroes */ - u32 r1, r2; - int ok = 0; - - r1 = cb710_read_port_32(slot, CB710_MMC_DATA_PORT); - r2 = cb710_read_port_32(slot, CB710_MMC_DATA_PORT); - if (cb710_read_port_8(slot, CB710_MMC_STATUS0_PORT) - & CB710_MMC_S0_FIFO_UNDERFLOW) { - cb710_write_port_8(slot, CB710_MMC_STATUS0_PORT, - CB710_MMC_S0_FIFO_UNDERFLOW); - ok = 1; - } - - dev_dbg(cb710_slot_dev(slot), - "FIFO-read-hack: expected STATUS0 bit was %s\n", - ok ? "set." : "NOT SET!"); - dev_dbg(cb710_slot_dev(slot), - "FIFO-read-hack: dwords ignored: %08X %08X - %s\n", - r1, r2, (r1|r2) ? "BAD (NOT ZERO)!" : "ok"); -} - -static int cb710_mmc_receive_pio(struct cb710_slot *slot, - struct sg_mapping_iter *miter, size_t dw_count) -{ - if (!(cb710_read_port_8(slot, CB710_MMC_STATUS2_PORT) & CB710_MMC_S2_FIFO_READY)) { - int err = cb710_wait_for_event(slot, - CB710_MMC_S1_PIO_TRANSFER_DONE); - if (err) - return err; - } - - cb710_sg_dwiter_write_from_io(miter, - slot->iobase + CB710_MMC_DATA_PORT, dw_count); - - return 0; -} - -static bool cb710_is_transfer_size_supported(struct mmc_data *data) -{ - return !(data->blksz & 15 && (data->blocks != 1 || data->blksz != 8)); -} - -static int cb710_mmc_receive(struct cb710_slot *slot, struct mmc_data *data) -{ - struct sg_mapping_iter miter; - size_t len, blocks = data->blocks; - int err = 0; - - /* TODO: I don't know how/if the hardware handles non-16B-boundary blocks - * except single 8B block */ - if (unlikely(data->blksz & 15 && (data->blocks != 1 || data->blksz != 8))) - return -EINVAL; - - sg_miter_start(&miter, data->sg, data->sg_len, SG_MITER_TO_SG); - - cb710_modify_port_8(slot, CB710_MMC_CONFIG2_PORT, - 15, CB710_MMC_C2_READ_PIO_SIZE_MASK); - - cb710_mmc_fifo_hack(slot); - - while (blocks-- > 0) { - len = data->blksz; - - while (len >= 16) { - err = cb710_mmc_receive_pio(slot, &miter, 4); - if (err) - goto out; - len -= 16; - } - - if (!len) - continue; - - cb710_modify_port_8(slot, CB710_MMC_CONFIG2_PORT, - len - 1, CB710_MMC_C2_READ_PIO_SIZE_MASK); - - len = (len >= 8) ? 4 : 2; - err = cb710_mmc_receive_pio(slot, &miter, len); - if (err) - goto out; - } -out: - sg_miter_stop(&miter); - return err; -} - -static int cb710_mmc_send(struct cb710_slot *slot, struct mmc_data *data) -{ - struct sg_mapping_iter miter; - size_t len, blocks = data->blocks; - int err = 0; - - /* TODO: I don't know how/if the hardware handles multiple - * non-16B-boundary blocks */ - if (unlikely(data->blocks > 1 && data->blksz & 15)) - return -EINVAL; - - sg_miter_start(&miter, data->sg, data->sg_len, SG_MITER_FROM_SG); - - cb710_modify_port_8(slot, CB710_MMC_CONFIG2_PORT, - 0, CB710_MMC_C2_READ_PIO_SIZE_MASK); - - while (blocks-- > 0) { - len = (data->blksz + 15) >> 4; - do { - if (!(cb710_read_port_8(slot, CB710_MMC_STATUS2_PORT) - & CB710_MMC_S2_FIFO_EMPTY)) { - err = cb710_wait_for_event(slot, - CB710_MMC_S1_PIO_TRANSFER_DONE); - if (err) - goto out; - } - cb710_sg_dwiter_read_to_io(&miter, - slot->iobase + CB710_MMC_DATA_PORT, 4); - } while (--len); - } -out: - sg_miter_stop(&miter); - return err; -} - -static u16 cb710_encode_cmd_flags(struct cb710_mmc_reader *reader, - struct mmc_command *cmd) -{ - unsigned int flags = cmd->flags; - u16 cb_flags = 0; - - /* Windows driver returned 0 for commands for which no response - * is expected. It happened that there were only two such commands - * used: MMC_GO_IDLE_STATE and MMC_GO_INACTIVE_STATE so it might - * as well be a bug in that driver. - * - * Original driver set bit 14 for MMC/SD application - * commands. There's no difference 'on the wire' and - * it apparently works without it anyway. - */ - - switch (flags & MMC_CMD_MASK) { - case MMC_CMD_AC: cb_flags = CB710_MMC_CMD_AC; break; - case MMC_CMD_ADTC: cb_flags = CB710_MMC_CMD_ADTC; break; - case MMC_CMD_BC: cb_flags = CB710_MMC_CMD_BC; break; - case MMC_CMD_BCR: cb_flags = CB710_MMC_CMD_BCR; break; - } - - if (flags & MMC_RSP_BUSY) - cb_flags |= CB710_MMC_RSP_BUSY; - - cb_flags |= cmd->opcode << CB710_MMC_CMD_CODE_SHIFT; - - if (cmd->data && (cmd->data->flags & MMC_DATA_READ)) - cb_flags |= CB710_MMC_DATA_READ; - - if (flags & MMC_RSP_PRESENT) { - /* Windows driver set 01 at bits 4,3 except for - * MMC_SET_BLOCKLEN where it set 10. Maybe the - * hardware can do something special about this - * command? The original driver looks buggy/incomplete - * anyway so we ignore this for now. - * - * I assume that 00 here means no response is expected. - */ - cb_flags |= CB710_MMC_RSP_PRESENT; - - if (flags & MMC_RSP_136) - cb_flags |= CB710_MMC_RSP_136; - if (!(flags & MMC_RSP_CRC)) - cb_flags |= CB710_MMC_RSP_NO_CRC; - } - - return cb_flags; -} - -static void cb710_receive_response(struct cb710_slot *slot, - struct mmc_command *cmd) -{ - unsigned rsp_opcode, wanted_opcode; - - /* Looks like final byte with CRC is always stripped (same as SDHCI) */ - if (cmd->flags & MMC_RSP_136) { - u32 resp[4]; - - resp[0] = cb710_read_port_32(slot, CB710_MMC_RESPONSE3_PORT); - resp[1] = cb710_read_port_32(slot, CB710_MMC_RESPONSE2_PORT); - resp[2] = cb710_read_port_32(slot, CB710_MMC_RESPONSE1_PORT); - resp[3] = cb710_read_port_32(slot, CB710_MMC_RESPONSE0_PORT); - rsp_opcode = resp[0] >> 24; - - cmd->resp[0] = (resp[0] << 8)|(resp[1] >> 24); - cmd->resp[1] = (resp[1] << 8)|(resp[2] >> 24); - cmd->resp[2] = (resp[2] << 8)|(resp[3] >> 24); - cmd->resp[3] = (resp[3] << 8); - } else { - rsp_opcode = cb710_read_port_32(slot, CB710_MMC_RESPONSE1_PORT) & 0x3F; - cmd->resp[0] = cb710_read_port_32(slot, CB710_MMC_RESPONSE0_PORT); - } - - wanted_opcode = (cmd->flags & MMC_RSP_OPCODE) ? cmd->opcode : 0x3F; - if (rsp_opcode != wanted_opcode) - cmd->error = -EILSEQ; -} - -static int cb710_mmc_transfer_data(struct cb710_slot *slot, - struct mmc_data *data) -{ - int error, to; - - if (data->flags & MMC_DATA_READ) - error = cb710_mmc_receive(slot, data); - else - error = cb710_mmc_send(slot, data); - - to = cb710_wait_for_event(slot, CB710_MMC_S1_DATA_TRANSFER_DONE); - if (!error) - error = to; - - if (!error) - data->bytes_xfered = data->blksz * data->blocks; - return error; -} - -static int cb710_mmc_command(struct mmc_host *mmc, struct mmc_command *cmd) -{ - struct cb710_slot *slot = cb710_mmc_to_slot(mmc); - struct cb710_mmc_reader *reader = mmc_priv(mmc); - struct mmc_data *data = cmd->data; - - u16 cb_cmd = cb710_encode_cmd_flags(reader, cmd); - dev_dbg(cb710_slot_dev(slot), "cmd request: 0x%04X\n", cb_cmd); - - if (data) { - if (!cb710_is_transfer_size_supported(data)) { - data->error = -EINVAL; - return -1; - } - cb710_mmc_set_transfer_size(slot, data->blocks, data->blksz); - } - - cb710_wait_while_busy(slot, CB710_MMC_S2_BUSY_20|CB710_MMC_S2_BUSY_10); - cb710_write_port_16(slot, CB710_MMC_CMD_TYPE_PORT, cb_cmd); - cb710_wait_while_busy(slot, CB710_MMC_S2_BUSY_20); - cb710_write_port_32(slot, CB710_MMC_CMD_PARAM_PORT, cmd->arg); - cb710_mmc_reset_events(slot); - cb710_wait_while_busy(slot, CB710_MMC_S2_BUSY_20); - cb710_modify_port_8(slot, CB710_MMC_CONFIG0_PORT, 0x01, 0); - - cmd->error = cb710_wait_for_event(slot, CB710_MMC_S1_COMMAND_SENT); - if (cmd->error) - return -1; - - if (cmd->flags & MMC_RSP_PRESENT) { - cb710_receive_response(slot, cmd); - if (cmd->error) - return -1; - } - - if (data) - data->error = cb710_mmc_transfer_data(slot, data); - return 0; -} - -static void cb710_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq) -{ - struct cb710_slot *slot = cb710_mmc_to_slot(mmc); - struct cb710_mmc_reader *reader = mmc_priv(mmc); - - WARN_ON(reader->mrq != NULL); - - reader->mrq = mrq; - cb710_mmc_enable_irq(slot, CB710_MMC_IE_TEST_MASK, 0); - - if (!cb710_mmc_command(mmc, mrq->cmd) && mrq->stop) - cb710_mmc_command(mmc, mrq->stop); - - tasklet_schedule(&reader->finish_req_tasklet); -} - -static int cb710_mmc_powerup(struct cb710_slot *slot) -{ -#ifdef CONFIG_CB710_DEBUG - struct cb710_chip *chip = cb710_slot_to_chip(slot); -#endif - int err; - - /* a lot of magic for now */ - dev_dbg(cb710_slot_dev(slot), "bus powerup\n"); - cb710_dump_regs(chip, CB710_DUMP_REGS_MMC); - err = cb710_wait_while_busy(slot, CB710_MMC_S2_BUSY_20); - if (unlikely(err)) - return err; - cb710_modify_port_8(slot, CB710_MMC_CONFIG1_PORT, 0x80, 0); - cb710_modify_port_8(slot, CB710_MMC_CONFIG3_PORT, 0x80, 0); - cb710_dump_regs(chip, CB710_DUMP_REGS_MMC); - mdelay(1); - dev_dbg(cb710_slot_dev(slot), "after delay 1\n"); - cb710_dump_regs(chip, CB710_DUMP_REGS_MMC); - err = cb710_wait_while_busy(slot, CB710_MMC_S2_BUSY_20); - if (unlikely(err)) - return err; - cb710_modify_port_8(slot, CB710_MMC_CONFIG1_PORT, 0x09, 0); - cb710_dump_regs(chip, CB710_DUMP_REGS_MMC); - mdelay(1); - dev_dbg(cb710_slot_dev(slot), "after delay 2\n"); - cb710_dump_regs(chip, CB710_DUMP_REGS_MMC); - err = cb710_wait_while_busy(slot, CB710_MMC_S2_BUSY_20); - if (unlikely(err)) - return err; - cb710_modify_port_8(slot, CB710_MMC_CONFIG1_PORT, 0, 0x08); - cb710_dump_regs(chip, CB710_DUMP_REGS_MMC); - mdelay(2); - dev_dbg(cb710_slot_dev(slot), "after delay 3\n"); - cb710_dump_regs(chip, CB710_DUMP_REGS_MMC); - cb710_modify_port_8(slot, CB710_MMC_CONFIG0_PORT, 0x06, 0); - cb710_modify_port_8(slot, CB710_MMC_CONFIG1_PORT, 0x70, 0); - cb710_modify_port_8(slot, CB710_MMC_CONFIG2_PORT, 0x80, 0); - cb710_modify_port_8(slot, CB710_MMC_CONFIG3_PORT, 0x03, 0); - cb710_dump_regs(chip, CB710_DUMP_REGS_MMC); - err = cb710_wait_while_busy(slot, CB710_MMC_S2_BUSY_20); - if (unlikely(err)) - return err; - /* This port behaves weird: quick byte reads of 0x08,0x09 return - * 0xFF,0x00 after writing 0xFFFF to 0x08; it works correctly when - * read/written from userspace... What am I missing here? - * (it doesn't depend on write-to-read delay) */ - cb710_write_port_16(slot, CB710_MMC_CONFIGB_PORT, 0xFFFF); - cb710_modify_port_8(slot, CB710_MMC_CONFIG0_PORT, 0x06, 0); - cb710_dump_regs(chip, CB710_DUMP_REGS_MMC); - dev_dbg(cb710_slot_dev(slot), "bus powerup finished\n"); - - return cb710_check_event(slot, 0); -} - -static void cb710_mmc_powerdown(struct cb710_slot *slot) -{ - cb710_modify_port_8(slot, CB710_MMC_CONFIG1_PORT, 0, 0x81); - cb710_modify_port_8(slot, CB710_MMC_CONFIG3_PORT, 0, 0x80); -} - -static void cb710_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) -{ - struct cb710_slot *slot = cb710_mmc_to_slot(mmc); - struct cb710_mmc_reader *reader = mmc_priv(mmc); - int err; - - cb710_mmc_select_clock_divider(mmc, ios->clock); - - if (ios->power_mode != reader->last_power_mode) - switch (ios->power_mode) { - case MMC_POWER_ON: - err = cb710_mmc_powerup(slot); - if (err) { - dev_warn(cb710_slot_dev(slot), - "powerup failed (%d)- retrying\n", err); - cb710_mmc_powerdown(slot); - udelay(1); - err = cb710_mmc_powerup(slot); - if (err) - dev_warn(cb710_slot_dev(slot), - "powerup retry failed (%d) - expect errors\n", - err); - } - reader->last_power_mode = MMC_POWER_ON; - break; - case MMC_POWER_OFF: - cb710_mmc_powerdown(slot); - reader->last_power_mode = MMC_POWER_OFF; - break; - case MMC_POWER_UP: - default: - /* ignore */; - } - - cb710_mmc_enable_4bit_data(slot, ios->bus_width != MMC_BUS_WIDTH_1); - - cb710_mmc_enable_irq(slot, CB710_MMC_IE_TEST_MASK, 0); -} - -static int cb710_mmc_get_ro(struct mmc_host *mmc) -{ - struct cb710_slot *slot = cb710_mmc_to_slot(mmc); - - return cb710_read_port_8(slot, CB710_MMC_STATUS3_PORT) - & CB710_MMC_S3_WRITE_PROTECTED; -} - -static int cb710_mmc_get_cd(struct mmc_host *mmc) -{ - struct cb710_slot *slot = cb710_mmc_to_slot(mmc); - - return cb710_read_port_8(slot, CB710_MMC_STATUS3_PORT) - & CB710_MMC_S3_CARD_DETECTED; -} - -static int cb710_mmc_irq_handler(struct cb710_slot *slot) -{ - struct mmc_host *mmc = cb710_slot_to_mmc(slot); - struct cb710_mmc_reader *reader = mmc_priv(mmc); - u32 status, config1, config2, irqen; - - status = cb710_read_port_32(slot, CB710_MMC_STATUS_PORT); - irqen = cb710_read_port_32(slot, CB710_MMC_IRQ_ENABLE_PORT); - config2 = cb710_read_port_32(slot, CB710_MMC_CONFIGB_PORT); - config1 = cb710_read_port_32(slot, CB710_MMC_CONFIG_PORT); - - dev_dbg(cb710_slot_dev(slot), "interrupt; status: %08X, " - "ie: %08X, c2: %08X, c1: %08X\n", - status, irqen, config2, config1); - - if (status & (CB710_MMC_S1_CARD_CHANGED << 8)) { - /* ack the event */ - cb710_write_port_8(slot, CB710_MMC_STATUS1_PORT, - CB710_MMC_S1_CARD_CHANGED); - if ((irqen & CB710_MMC_IE_CISTATUS_MASK) - == CB710_MMC_IE_CISTATUS_MASK) - mmc_detect_change(mmc, HZ/5); - } else { - dev_dbg(cb710_slot_dev(slot), "unknown interrupt (test)\n"); - spin_lock(&reader->irq_lock); - __cb710_mmc_enable_irq(slot, 0, CB710_MMC_IE_TEST_MASK); - spin_unlock(&reader->irq_lock); - } - - return 1; -} - -static void cb710_mmc_finish_request_tasklet(unsigned long data) -{ - struct mmc_host *mmc = (void *)data; - struct cb710_mmc_reader *reader = mmc_priv(mmc); - struct mmc_request *mrq = reader->mrq; - - reader->mrq = NULL; - mmc_request_done(mmc, mrq); -} - -static const struct mmc_host_ops cb710_mmc_host = { - .request = cb710_mmc_request, - .set_ios = cb710_mmc_set_ios, - .get_ro = cb710_mmc_get_ro, - .get_cd = cb710_mmc_get_cd, -}; - -#ifdef CONFIG_PM - -static int cb710_mmc_suspend(struct platform_device *pdev, pm_message_t state) -{ - struct cb710_slot *slot = cb710_pdev_to_slot(pdev); - struct mmc_host *mmc = cb710_slot_to_mmc(slot); - int err; - - err = mmc_suspend_host(mmc); - if (err) - return err; - - cb710_mmc_enable_irq(slot, 0, ~0); - return 0; -} - -static int cb710_mmc_resume(struct platform_device *pdev) -{ - struct cb710_slot *slot = cb710_pdev_to_slot(pdev); - struct mmc_host *mmc = cb710_slot_to_mmc(slot); - - cb710_mmc_enable_irq(slot, 0, ~0); - - return mmc_resume_host(mmc); -} - -#endif /* CONFIG_PM */ - -static int __devinit cb710_mmc_init(struct platform_device *pdev) -{ - struct cb710_slot *slot = cb710_pdev_to_slot(pdev); - struct cb710_chip *chip = cb710_slot_to_chip(slot); - struct mmc_host *mmc; - struct cb710_mmc_reader *reader; - int err; - u32 val; - - mmc = mmc_alloc_host(sizeof(*reader), cb710_slot_dev(slot)); - if (!mmc) - return -ENOMEM; - - dev_set_drvdata(&pdev->dev, mmc); - - /* harmless (maybe) magic */ - pci_read_config_dword(chip->pdev, 0x48, &val); - val = cb710_src_freq_mhz[(val >> 16) & 0xF]; - dev_dbg(cb710_slot_dev(slot), "source frequency: %dMHz\n", val); - val *= 1000000; - - mmc->ops = &cb710_mmc_host; - mmc->f_max = val; - mmc->f_min = val >> cb710_clock_divider_log2[CB710_MAX_DIVIDER_IDX]; - mmc->ocr_avail = MMC_VDD_32_33|MMC_VDD_33_34; - mmc->caps = MMC_CAP_4_BIT_DATA; - - reader = mmc_priv(mmc); - - tasklet_init(&reader->finish_req_tasklet, - cb710_mmc_finish_request_tasklet, (unsigned long)mmc); - spin_lock_init(&reader->irq_lock); - cb710_dump_regs(chip, CB710_DUMP_REGS_MMC); - - cb710_mmc_enable_irq(slot, 0, ~0); - cb710_set_irq_handler(slot, cb710_mmc_irq_handler); - - err = mmc_add_host(mmc); - if (unlikely(err)) - goto err_free_mmc; - - dev_dbg(cb710_slot_dev(slot), "mmc_hostname is %s\n", - mmc_hostname(mmc)); - - cb710_mmc_enable_irq(slot, CB710_MMC_IE_CARD_INSERTION_STATUS, 0); - - return 0; - -err_free_mmc: - dev_dbg(cb710_slot_dev(slot), "mmc_add_host() failed: %d\n", err); - - cb710_set_irq_handler(slot, NULL); - mmc_free_host(mmc); - return err; -} - -static int __devexit cb710_mmc_exit(struct platform_device *pdev) -{ - struct cb710_slot *slot = cb710_pdev_to_slot(pdev); - struct mmc_host *mmc = cb710_slot_to_mmc(slot); - struct cb710_mmc_reader *reader = mmc_priv(mmc); - - cb710_mmc_enable_irq(slot, 0, CB710_MMC_IE_CARD_INSERTION_STATUS); - - mmc_remove_host(mmc); - - /* IRQs should be disabled now, but let's stay on the safe side */ - cb710_mmc_enable_irq(slot, 0, ~0); - cb710_set_irq_handler(slot, NULL); - - /* clear config ports - just in case */ - cb710_write_port_32(slot, CB710_MMC_CONFIG_PORT, 0); - cb710_write_port_16(slot, CB710_MMC_CONFIGB_PORT, 0); - - tasklet_kill(&reader->finish_req_tasklet); - - mmc_free_host(mmc); - return 0; -} - -static struct platform_driver cb710_mmc_driver = { - .driver.name = "cb710-mmc", - .probe = cb710_mmc_init, - .remove = __devexit_p(cb710_mmc_exit), -#ifdef CONFIG_PM - .suspend = cb710_mmc_suspend, - .resume = cb710_mmc_resume, -#endif -}; - -module_platform_driver(cb710_mmc_driver); - -MODULE_AUTHOR("Michał Mirosław <mirq-linux@rere.qmqm.pl>"); -MODULE_DESCRIPTION("ENE CB710 memory card reader driver - MMC/SD part"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:cb710-mmc"); diff --git a/ANDROID_3.4.5/drivers/mmc/host/cb710-mmc.h b/ANDROID_3.4.5/drivers/mmc/host/cb710-mmc.h deleted file mode 100644 index e845c776..00000000 --- a/ANDROID_3.4.5/drivers/mmc/host/cb710-mmc.h +++ /dev/null @@ -1,104 +0,0 @@ -/* - * cb710/cb710-mmc.h - * - * Copyright by Michał Mirosław, 2008-2009 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ -#ifndef LINUX_CB710_MMC_H -#define LINUX_CB710_MMC_H - -#include <linux/cb710.h> - -/* per-MMC-reader structure */ -struct cb710_mmc_reader { - struct tasklet_struct finish_req_tasklet; - struct mmc_request *mrq; - spinlock_t irq_lock; - unsigned char last_power_mode; -}; - -/* some device struct walking */ - -static inline struct mmc_host *cb710_slot_to_mmc(struct cb710_slot *slot) -{ - return dev_get_drvdata(&slot->pdev.dev); -} - -static inline struct cb710_slot *cb710_mmc_to_slot(struct mmc_host *mmc) -{ - struct platform_device *pdev = container_of(mmc_dev(mmc), - struct platform_device, dev); - return cb710_pdev_to_slot(pdev); -} - -/* registers (this might be all wrong ;) */ - -#define CB710_MMC_DATA_PORT 0x00 - -#define CB710_MMC_CONFIG_PORT 0x04 -#define CB710_MMC_CONFIG0_PORT 0x04 -#define CB710_MMC_CONFIG1_PORT 0x05 -#define CB710_MMC_C1_4BIT_DATA_BUS 0x40 -#define CB710_MMC_CONFIG2_PORT 0x06 -#define CB710_MMC_C2_READ_PIO_SIZE_MASK 0x0F /* N-1 */ -#define CB710_MMC_CONFIG3_PORT 0x07 - -#define CB710_MMC_CONFIGB_PORT 0x08 - -#define CB710_MMC_IRQ_ENABLE_PORT 0x0C -#define CB710_MMC_IE_TEST_MASK 0x00BF -#define CB710_MMC_IE_CARD_INSERTION_STATUS 0x1000 -#define CB710_MMC_IE_IRQ_ENABLE 0x8000 -#define CB710_MMC_IE_CISTATUS_MASK \ - (CB710_MMC_IE_CARD_INSERTION_STATUS|CB710_MMC_IE_IRQ_ENABLE) - -#define CB710_MMC_STATUS_PORT 0x10 -#define CB710_MMC_STATUS_ERROR_EVENTS 0x60FF -#define CB710_MMC_STATUS0_PORT 0x10 -#define CB710_MMC_S0_FIFO_UNDERFLOW 0x40 -#define CB710_MMC_STATUS1_PORT 0x11 -#define CB710_MMC_S1_COMMAND_SENT 0x01 -#define CB710_MMC_S1_DATA_TRANSFER_DONE 0x02 -#define CB710_MMC_S1_PIO_TRANSFER_DONE 0x04 -#define CB710_MMC_S1_CARD_CHANGED 0x10 -#define CB710_MMC_S1_RESET 0x20 -#define CB710_MMC_STATUS2_PORT 0x12 -#define CB710_MMC_S2_FIFO_READY 0x01 -#define CB710_MMC_S2_FIFO_EMPTY 0x02 -#define CB710_MMC_S2_BUSY_10 0x10 -#define CB710_MMC_S2_BUSY_20 0x20 -#define CB710_MMC_STATUS3_PORT 0x13 -#define CB710_MMC_S3_CARD_DETECTED 0x02 -#define CB710_MMC_S3_WRITE_PROTECTED 0x04 - -#define CB710_MMC_CMD_TYPE_PORT 0x14 -#define CB710_MMC_RSP_TYPE_MASK 0x0007 -#define CB710_MMC_RSP_R1 (0) -#define CB710_MMC_RSP_136 (5) -#define CB710_MMC_RSP_NO_CRC (2) -#define CB710_MMC_RSP_PRESENT_MASK 0x0018 -#define CB710_MMC_RSP_NONE (0 << 3) -#define CB710_MMC_RSP_PRESENT (1 << 3) -#define CB710_MMC_RSP_PRESENT_X (2 << 3) -#define CB710_MMC_CMD_TYPE_MASK 0x0060 -#define CB710_MMC_CMD_BC (0 << 5) -#define CB710_MMC_CMD_BCR (1 << 5) -#define CB710_MMC_CMD_AC (2 << 5) -#define CB710_MMC_CMD_ADTC (3 << 5) -#define CB710_MMC_DATA_READ 0x0080 -#define CB710_MMC_CMD_CODE_MASK 0x3F00 -#define CB710_MMC_CMD_CODE_SHIFT 8 -#define CB710_MMC_IS_APP_CMD 0x4000 -#define CB710_MMC_RSP_BUSY 0x8000 - -#define CB710_MMC_CMD_PARAM_PORT 0x18 -#define CB710_MMC_TRANSFER_SIZE_PORT 0x1C -#define CB710_MMC_RESPONSE0_PORT 0x20 -#define CB710_MMC_RESPONSE1_PORT 0x24 -#define CB710_MMC_RESPONSE2_PORT 0x28 -#define CB710_MMC_RESPONSE3_PORT 0x2C - -#endif /* LINUX_CB710_MMC_H */ diff --git a/ANDROID_3.4.5/drivers/mmc/host/davinci_mmc.c b/ANDROID_3.4.5/drivers/mmc/host/davinci_mmc.c deleted file mode 100644 index c1f3673a..00000000 --- a/ANDROID_3.4.5/drivers/mmc/host/davinci_mmc.c +++ /dev/null @@ -1,1536 +0,0 @@ -/* - * davinci_mmc.c - TI DaVinci MMC/SD/SDIO driver - * - * Copyright (C) 2006 Texas Instruments. - * Original author: Purushotam Kumar - * Copyright (C) 2009 David Brownell - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include <linux/module.h> -#include <linux/ioport.h> -#include <linux/platform_device.h> -#include <linux/clk.h> -#include <linux/err.h> -#include <linux/cpufreq.h> -#include <linux/mmc/host.h> -#include <linux/io.h> -#include <linux/irq.h> -#include <linux/delay.h> -#include <linux/dma-mapping.h> -#include <linux/mmc/mmc.h> - -#include <mach/mmc.h> -#include <mach/edma.h> - -/* - * Register Definitions - */ -#define DAVINCI_MMCCTL 0x00 /* Control Register */ -#define DAVINCI_MMCCLK 0x04 /* Memory Clock Control Register */ -#define DAVINCI_MMCST0 0x08 /* Status Register 0 */ -#define DAVINCI_MMCST1 0x0C /* Status Register 1 */ -#define DAVINCI_MMCIM 0x10 /* Interrupt Mask Register */ -#define DAVINCI_MMCTOR 0x14 /* Response Time-Out Register */ -#define DAVINCI_MMCTOD 0x18 /* Data Read Time-Out Register */ -#define DAVINCI_MMCBLEN 0x1C /* Block Length Register */ -#define DAVINCI_MMCNBLK 0x20 /* Number of Blocks Register */ -#define DAVINCI_MMCNBLC 0x24 /* Number of Blocks Counter Register */ -#define DAVINCI_MMCDRR 0x28 /* Data Receive Register */ -#define DAVINCI_MMCDXR 0x2C /* Data Transmit Register */ -#define DAVINCI_MMCCMD 0x30 /* Command Register */ -#define DAVINCI_MMCARGHL 0x34 /* Argument Register */ -#define DAVINCI_MMCRSP01 0x38 /* Response Register 0 and 1 */ -#define DAVINCI_MMCRSP23 0x3C /* Response Register 0 and 1 */ -#define DAVINCI_MMCRSP45 0x40 /* Response Register 0 and 1 */ -#define DAVINCI_MMCRSP67 0x44 /* Response Register 0 and 1 */ -#define DAVINCI_MMCDRSP 0x48 /* Data Response Register */ -#define DAVINCI_MMCETOK 0x4C -#define DAVINCI_MMCCIDX 0x50 /* Command Index Register */ -#define DAVINCI_MMCCKC 0x54 -#define DAVINCI_MMCTORC 0x58 -#define DAVINCI_MMCTODC 0x5C -#define DAVINCI_MMCBLNC 0x60 -#define DAVINCI_SDIOCTL 0x64 -#define DAVINCI_SDIOST0 0x68 -#define DAVINCI_SDIOIEN 0x6C -#define DAVINCI_SDIOIST 0x70 -#define DAVINCI_MMCFIFOCTL 0x74 /* FIFO Control Register */ - -/* DAVINCI_MMCCTL definitions */ -#define MMCCTL_DATRST (1 << 0) -#define MMCCTL_CMDRST (1 << 1) -#define MMCCTL_WIDTH_8_BIT (1 << 8) -#define MMCCTL_WIDTH_4_BIT (1 << 2) -#define MMCCTL_DATEG_DISABLED (0 << 6) -#define MMCCTL_DATEG_RISING (1 << 6) -#define MMCCTL_DATEG_FALLING (2 << 6) -#define MMCCTL_DATEG_BOTH (3 << 6) -#define MMCCTL_PERMDR_LE (0 << 9) -#define MMCCTL_PERMDR_BE (1 << 9) -#define MMCCTL_PERMDX_LE (0 << 10) -#define MMCCTL_PERMDX_BE (1 << 10) - -/* DAVINCI_MMCCLK definitions */ -#define MMCCLK_CLKEN (1 << 8) -#define MMCCLK_CLKRT_MASK (0xFF << 0) - -/* IRQ bit definitions, for DAVINCI_MMCST0 and DAVINCI_MMCIM */ -#define MMCST0_DATDNE BIT(0) /* data done */ -#define MMCST0_BSYDNE BIT(1) /* busy done */ -#define MMCST0_RSPDNE BIT(2) /* command done */ -#define MMCST0_TOUTRD BIT(3) /* data read timeout */ -#define MMCST0_TOUTRS BIT(4) /* command response timeout */ -#define MMCST0_CRCWR BIT(5) /* data write CRC error */ -#define MMCST0_CRCRD BIT(6) /* data read CRC error */ -#define MMCST0_CRCRS BIT(7) /* command response CRC error */ -#define MMCST0_DXRDY BIT(9) /* data transmit ready (fifo empty) */ -#define MMCST0_DRRDY BIT(10) /* data receive ready (data in fifo)*/ -#define MMCST0_DATED BIT(11) /* DAT3 edge detect */ -#define MMCST0_TRNDNE BIT(12) /* transfer done */ - -/* DAVINCI_MMCST1 definitions */ -#define MMCST1_BUSY (1 << 0) - -/* DAVINCI_MMCCMD definitions */ -#define MMCCMD_CMD_MASK (0x3F << 0) -#define MMCCMD_PPLEN (1 << 7) -#define MMCCMD_BSYEXP (1 << 8) -#define MMCCMD_RSPFMT_MASK (3 << 9) -#define MMCCMD_RSPFMT_NONE (0 << 9) -#define MMCCMD_RSPFMT_R1456 (1 << 9) -#define MMCCMD_RSPFMT_R2 (2 << 9) -#define MMCCMD_RSPFMT_R3 (3 << 9) -#define MMCCMD_DTRW (1 << 11) -#define MMCCMD_STRMTP (1 << 12) -#define MMCCMD_WDATX (1 << 13) -#define MMCCMD_INITCK (1 << 14) -#define MMCCMD_DCLR (1 << 15) -#define MMCCMD_DMATRIG (1 << 16) - -/* DAVINCI_MMCFIFOCTL definitions */ -#define MMCFIFOCTL_FIFORST (1 << 0) -#define MMCFIFOCTL_FIFODIR_WR (1 << 1) -#define MMCFIFOCTL_FIFODIR_RD (0 << 1) -#define MMCFIFOCTL_FIFOLEV (1 << 2) /* 0 = 128 bits, 1 = 256 bits */ -#define MMCFIFOCTL_ACCWD_4 (0 << 3) /* access width of 4 bytes */ -#define MMCFIFOCTL_ACCWD_3 (1 << 3) /* access width of 3 bytes */ -#define MMCFIFOCTL_ACCWD_2 (2 << 3) /* access width of 2 bytes */ -#define MMCFIFOCTL_ACCWD_1 (3 << 3) /* access width of 1 byte */ - -/* DAVINCI_SDIOST0 definitions */ -#define SDIOST0_DAT1_HI BIT(0) - -/* DAVINCI_SDIOIEN definitions */ -#define SDIOIEN_IOINTEN BIT(0) - -/* DAVINCI_SDIOIST definitions */ -#define SDIOIST_IOINT BIT(0) - -/* MMCSD Init clock in Hz in opendrain mode */ -#define MMCSD_INIT_CLOCK 200000 - -/* - * One scatterlist dma "segment" is at most MAX_CCNT rw_threshold units, - * and we handle up to MAX_NR_SG segments. MMC_BLOCK_BOUNCE kicks in only - * for drivers with max_segs == 1, making the segments bigger (64KB) - * than the page or two that's otherwise typical. nr_sg (passed from - * platform data) == 16 gives at least the same throughput boost, using - * EDMA transfer linkage instead of spending CPU time copying pages. - */ -#define MAX_CCNT ((1 << 16) - 1) - -#define MAX_NR_SG 16 - -static unsigned rw_threshold = 32; -module_param(rw_threshold, uint, S_IRUGO); -MODULE_PARM_DESC(rw_threshold, - "Read/Write threshold. Default = 32"); - -static unsigned poll_threshold = 128; -module_param(poll_threshold, uint, S_IRUGO); -MODULE_PARM_DESC(poll_threshold, - "Polling transaction size threshold. Default = 128"); - -static unsigned poll_loopcount = 32; -module_param(poll_loopcount, uint, S_IRUGO); -MODULE_PARM_DESC(poll_loopcount, - "Maximum polling loop count. Default = 32"); - -static unsigned __initdata use_dma = 1; -module_param(use_dma, uint, 0); -MODULE_PARM_DESC(use_dma, "Whether to use DMA or not. Default = 1"); - -struct mmc_davinci_host { - struct mmc_command *cmd; - struct mmc_data *data; - struct mmc_host *mmc; - struct clk *clk; - unsigned int mmc_input_clk; - void __iomem *base; - struct resource *mem_res; - int mmc_irq, sdio_irq; - unsigned char bus_mode; - -#define DAVINCI_MMC_DATADIR_NONE 0 -#define DAVINCI_MMC_DATADIR_READ 1 -#define DAVINCI_MMC_DATADIR_WRITE 2 - unsigned char data_dir; - unsigned char suspended; - - /* buffer is used during PIO of one scatterlist segment, and - * is updated along with buffer_bytes_left. bytes_left applies - * to all N blocks of the PIO transfer. - */ - u8 *buffer; - u32 buffer_bytes_left; - u32 bytes_left; - - u32 rxdma, txdma; - bool use_dma; - bool do_dma; - bool sdio_int; - bool active_request; - - /* Scatterlist DMA uses one or more parameter RAM entries: - * the main one (associated with rxdma or txdma) plus zero or - * more links. The entries for a given transfer differ only - * by memory buffer (address, length) and link field. - */ - struct edmacc_param tx_template; - struct edmacc_param rx_template; - unsigned n_link; - u32 links[MAX_NR_SG - 1]; - - /* For PIO we walk scatterlists one segment at a time. */ - unsigned int sg_len; - struct scatterlist *sg; - - /* Version of the MMC/SD controller */ - u8 version; - /* for ns in one cycle calculation */ - unsigned ns_in_one_cycle; - /* Number of sg segments */ - u8 nr_sg; -#ifdef CONFIG_CPU_FREQ - struct notifier_block freq_transition; -#endif -}; - -static irqreturn_t mmc_davinci_irq(int irq, void *dev_id); - -/* PIO only */ -static void mmc_davinci_sg_to_buf(struct mmc_davinci_host *host) -{ - host->buffer_bytes_left = sg_dma_len(host->sg); - host->buffer = sg_virt(host->sg); - if (host->buffer_bytes_left > host->bytes_left) - host->buffer_bytes_left = host->bytes_left; -} - -static void davinci_fifo_data_trans(struct mmc_davinci_host *host, - unsigned int n) -{ - u8 *p; - unsigned int i; - - if (host->buffer_bytes_left == 0) { - host->sg = sg_next(host->data->sg); - mmc_davinci_sg_to_buf(host); - } - - p = host->buffer; - if (n > host->buffer_bytes_left) - n = host->buffer_bytes_left; - host->buffer_bytes_left -= n; - host->bytes_left -= n; - - /* NOTE: we never transfer more than rw_threshold bytes - * to/from the fifo here; there's no I/O overlap. - * This also assumes that access width( i.e. ACCWD) is 4 bytes - */ - if (host->data_dir == DAVINCI_MMC_DATADIR_WRITE) { - for (i = 0; i < (n >> 2); i++) { - writel(*((u32 *)p), host->base + DAVINCI_MMCDXR); - p = p + 4; - } - if (n & 3) { - iowrite8_rep(host->base + DAVINCI_MMCDXR, p, (n & 3)); - p = p + (n & 3); - } - } else { - for (i = 0; i < (n >> 2); i++) { - *((u32 *)p) = readl(host->base + DAVINCI_MMCDRR); - p = p + 4; - } - if (n & 3) { - ioread8_rep(host->base + DAVINCI_MMCDRR, p, (n & 3)); - p = p + (n & 3); - } - } - host->buffer = p; -} - -static void mmc_davinci_start_command(struct mmc_davinci_host *host, - struct mmc_command *cmd) -{ - u32 cmd_reg = 0; - u32 im_val; - - dev_dbg(mmc_dev(host->mmc), "CMD%d, arg 0x%08x%s\n", - cmd->opcode, cmd->arg, - ({ char *s; - switch (mmc_resp_type(cmd)) { - case MMC_RSP_R1: - s = ", R1/R5/R6/R7 response"; - break; - case MMC_RSP_R1B: - s = ", R1b response"; - break; - case MMC_RSP_R2: - s = ", R2 response"; - break; - case MMC_RSP_R3: - s = ", R3/R4 response"; - break; - default: - s = ", (R? response)"; - break; - }; s; })); - host->cmd = cmd; - - switch (mmc_resp_type(cmd)) { - case MMC_RSP_R1B: - /* There's some spec confusion about when R1B is - * allowed, but if the card doesn't issue a BUSY - * then it's harmless for us to allow it. - */ - cmd_reg |= MMCCMD_BSYEXP; - /* FALLTHROUGH */ - case MMC_RSP_R1: /* 48 bits, CRC */ - cmd_reg |= MMCCMD_RSPFMT_R1456; - break; - case MMC_RSP_R2: /* 136 bits, CRC */ - cmd_reg |= MMCCMD_RSPFMT_R2; - break; - case MMC_RSP_R3: /* 48 bits, no CRC */ - cmd_reg |= MMCCMD_RSPFMT_R3; - break; - default: - cmd_reg |= MMCCMD_RSPFMT_NONE; - dev_dbg(mmc_dev(host->mmc), "unknown resp_type %04x\n", - mmc_resp_type(cmd)); - break; - } - - /* Set command index */ - cmd_reg |= cmd->opcode; - - /* Enable EDMA transfer triggers */ - if (host->do_dma) - cmd_reg |= MMCCMD_DMATRIG; - - if (host->version == MMC_CTLR_VERSION_2 && host->data != NULL && - host->data_dir == DAVINCI_MMC_DATADIR_READ) - cmd_reg |= MMCCMD_DMATRIG; - - /* Setting whether command involves data transfer or not */ - if (cmd->data) - cmd_reg |= MMCCMD_WDATX; - - /* Setting whether stream or block transfer */ - if (cmd->flags & MMC_DATA_STREAM) - cmd_reg |= MMCCMD_STRMTP; - - /* Setting whether data read or write */ - if (host->data_dir == DAVINCI_MMC_DATADIR_WRITE) - cmd_reg |= MMCCMD_DTRW; - - if (host->bus_mode == MMC_BUSMODE_PUSHPULL) - cmd_reg |= MMCCMD_PPLEN; - - /* set Command timeout */ - writel(0x1FFF, host->base + DAVINCI_MMCTOR); - - /* Enable interrupt (calculate here, defer until FIFO is stuffed). */ - im_val = MMCST0_RSPDNE | MMCST0_CRCRS | MMCST0_TOUTRS; - if (host->data_dir == DAVINCI_MMC_DATADIR_WRITE) { - im_val |= MMCST0_DATDNE | MMCST0_CRCWR; - - if (!host->do_dma) - im_val |= MMCST0_DXRDY; - } else if (host->data_dir == DAVINCI_MMC_DATADIR_READ) { - im_val |= MMCST0_DATDNE | MMCST0_CRCRD | MMCST0_TOUTRD; - - if (!host->do_dma) - im_val |= MMCST0_DRRDY; - } - - /* - * Before non-DMA WRITE commands the controller needs priming: - * FIFO should be populated with 32 bytes i.e. whatever is the FIFO size - */ - if (!host->do_dma && (host->data_dir == DAVINCI_MMC_DATADIR_WRITE)) - davinci_fifo_data_trans(host, rw_threshold); - - writel(cmd->arg, host->base + DAVINCI_MMCARGHL); - writel(cmd_reg, host->base + DAVINCI_MMCCMD); - - host->active_request = true; - - if (!host->do_dma && host->bytes_left <= poll_threshold) { - u32 count = poll_loopcount; - - while (host->active_request && count--) { - mmc_davinci_irq(0, host); - cpu_relax(); - } - } - - if (host->active_request) - writel(im_val, host->base + DAVINCI_MMCIM); -} - -/*----------------------------------------------------------------------*/ - -/* DMA infrastructure */ - -static void davinci_abort_dma(struct mmc_davinci_host *host) -{ - int sync_dev; - - if (host->data_dir == DAVINCI_MMC_DATADIR_READ) - sync_dev = host->rxdma; - else - sync_dev = host->txdma; - - edma_stop(sync_dev); - edma_clean_channel(sync_dev); -} - -static void -mmc_davinci_xfer_done(struct mmc_davinci_host *host, struct mmc_data *data); - -static void mmc_davinci_dma_cb(unsigned channel, u16 ch_status, void *data) -{ - if (DMA_COMPLETE != ch_status) { - struct mmc_davinci_host *host = data; - - /* Currently means: DMA Event Missed, or "null" transfer - * request was seen. In the future, TC errors (like bad - * addresses) might be presented too. - */ - dev_warn(mmc_dev(host->mmc), "DMA %s error\n", - (host->data->flags & MMC_DATA_WRITE) - ? "write" : "read"); - host->data->error = -EIO; - mmc_davinci_xfer_done(host, host->data); - } -} - -/* Set up tx or rx template, to be modified and updated later */ -static void __init mmc_davinci_dma_setup(struct mmc_davinci_host *host, - bool tx, struct edmacc_param *template) -{ - unsigned sync_dev; - const u16 acnt = 4; - const u16 bcnt = rw_threshold >> 2; - const u16 ccnt = 0; - u32 src_port = 0; - u32 dst_port = 0; - s16 src_bidx, dst_bidx; - s16 src_cidx, dst_cidx; - - /* - * A-B Sync transfer: each DMA request is for one "frame" of - * rw_threshold bytes, broken into "acnt"-size chunks repeated - * "bcnt" times. Each segment needs "ccnt" such frames; since - * we tell the block layer our mmc->max_seg_size limit, we can - * trust (later) that it's within bounds. - * - * The FIFOs are read/written in 4-byte chunks (acnt == 4) and - * EDMA will optimize memory operations to use larger bursts. - */ - if (tx) { - sync_dev = host->txdma; - - /* src_prt, ccnt, and link to be set up later */ - src_bidx = acnt; - src_cidx = acnt * bcnt; - - dst_port = host->mem_res->start + DAVINCI_MMCDXR; - dst_bidx = 0; - dst_cidx = 0; - } else { - sync_dev = host->rxdma; - - src_port = host->mem_res->start + DAVINCI_MMCDRR; - src_bidx = 0; - src_cidx = 0; - - /* dst_prt, ccnt, and link to be set up later */ - dst_bidx = acnt; - dst_cidx = acnt * bcnt; - } - - /* - * We can't use FIFO mode for the FIFOs because MMC FIFO addresses - * are not 256-bit (32-byte) aligned. So we use INCR, and the W8BIT - * parameter is ignored. - */ - edma_set_src(sync_dev, src_port, INCR, W8BIT); - edma_set_dest(sync_dev, dst_port, INCR, W8BIT); - - edma_set_src_index(sync_dev, src_bidx, src_cidx); - edma_set_dest_index(sync_dev, dst_bidx, dst_cidx); - - edma_set_transfer_params(sync_dev, acnt, bcnt, ccnt, 8, ABSYNC); - - edma_read_slot(sync_dev, template); - - /* don't bother with irqs or chaining */ - template->opt |= EDMA_CHAN_SLOT(sync_dev) << 12; -} - -static void mmc_davinci_send_dma_request(struct mmc_davinci_host *host, - struct mmc_data *data) -{ - struct edmacc_param *template; - int channel, slot; - unsigned link; - struct scatterlist *sg; - unsigned sg_len; - unsigned bytes_left = host->bytes_left; - const unsigned shift = ffs(rw_threshold) - 1; - - if (host->data_dir == DAVINCI_MMC_DATADIR_WRITE) { - template = &host->tx_template; - channel = host->txdma; - } else { - template = &host->rx_template; - channel = host->rxdma; - } - - /* We know sg_len and ccnt will never be out of range because - * we told the mmc layer which in turn tells the block layer - * to ensure that it only hands us one scatterlist segment - * per EDMA PARAM entry. Update the PARAM - * entries needed for each segment of this scatterlist. - */ - for (slot = channel, link = 0, sg = data->sg, sg_len = host->sg_len; - sg_len-- != 0 && bytes_left; - sg = sg_next(sg), slot = host->links[link++]) { - u32 buf = sg_dma_address(sg); - unsigned count = sg_dma_len(sg); - - template->link_bcntrld = sg_len - ? (EDMA_CHAN_SLOT(host->links[link]) << 5) - : 0xffff; - - if (count > bytes_left) - count = bytes_left; - bytes_left -= count; - - if (host->data_dir == DAVINCI_MMC_DATADIR_WRITE) - template->src = buf; - else - template->dst = buf; - template->ccnt = count >> shift; - - edma_write_slot(slot, template); - } - - if (host->version == MMC_CTLR_VERSION_2) - edma_clear_event(channel); - - edma_start(channel); -} - -static int mmc_davinci_start_dma_transfer(struct mmc_davinci_host *host, - struct mmc_data *data) -{ - int i; - int mask = rw_threshold - 1; - - host->sg_len = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len, - ((data->flags & MMC_DATA_WRITE) - ? DMA_TO_DEVICE - : DMA_FROM_DEVICE)); - - /* no individual DMA segment should need a partial FIFO */ - for (i = 0; i < host->sg_len; i++) { - if (sg_dma_len(data->sg + i) & mask) { - dma_unmap_sg(mmc_dev(host->mmc), - data->sg, data->sg_len, - (data->flags & MMC_DATA_WRITE) - ? DMA_TO_DEVICE - : DMA_FROM_DEVICE); - return -1; - } - } - - host->do_dma = 1; - mmc_davinci_send_dma_request(host, data); - - return 0; -} - -static void __init_or_module -davinci_release_dma_channels(struct mmc_davinci_host *host) -{ - unsigned i; - - if (!host->use_dma) - return; - - for (i = 0; i < host->n_link; i++) - edma_free_slot(host->links[i]); - - edma_free_channel(host->txdma); - edma_free_channel(host->rxdma); -} - -static int __init davinci_acquire_dma_channels(struct mmc_davinci_host *host) -{ - u32 link_size; - int r, i; - - /* Acquire master DMA write channel */ - r = edma_alloc_channel(host->txdma, mmc_davinci_dma_cb, host, - EVENTQ_DEFAULT); - if (r < 0) { - dev_warn(mmc_dev(host->mmc), "alloc %s channel err %d\n", - "tx", r); - return r; - } - mmc_davinci_dma_setup(host, true, &host->tx_template); - - /* Acquire master DMA read channel */ - r = edma_alloc_channel(host->rxdma, mmc_davinci_dma_cb, host, - EVENTQ_DEFAULT); - if (r < 0) { - dev_warn(mmc_dev(host->mmc), "alloc %s channel err %d\n", - "rx", r); - goto free_master_write; - } - mmc_davinci_dma_setup(host, false, &host->rx_template); - - /* Allocate parameter RAM slots, which will later be bound to a - * channel as needed to handle a scatterlist. - */ - link_size = min_t(unsigned, host->nr_sg, ARRAY_SIZE(host->links)); - for (i = 0; i < link_size; i++) { - r = edma_alloc_slot(EDMA_CTLR(host->txdma), EDMA_SLOT_ANY); - if (r < 0) { - dev_dbg(mmc_dev(host->mmc), "dma PaRAM alloc --> %d\n", - r); - break; - } - host->links[i] = r; - } - host->n_link = i; - - return 0; - -free_master_write: - edma_free_channel(host->txdma); - - return r; -} - -/*----------------------------------------------------------------------*/ - -static void -mmc_davinci_prepare_data(struct mmc_davinci_host *host, struct mmc_request *req) -{ - int fifo_lev = (rw_threshold == 32) ? MMCFIFOCTL_FIFOLEV : 0; - int timeout; - struct mmc_data *data = req->data; - - if (host->version == MMC_CTLR_VERSION_2) - fifo_lev = (rw_threshold == 64) ? MMCFIFOCTL_FIFOLEV : 0; - - host->data = data; - if (data == NULL) { - host->data_dir = DAVINCI_MMC_DATADIR_NONE; - writel(0, host->base + DAVINCI_MMCBLEN); - writel(0, host->base + DAVINCI_MMCNBLK); - return; - } - - dev_dbg(mmc_dev(host->mmc), "%s %s, %d blocks of %d bytes\n", - (data->flags & MMC_DATA_STREAM) ? "stream" : "block", - (data->flags & MMC_DATA_WRITE) ? "write" : "read", - data->blocks, data->blksz); - dev_dbg(mmc_dev(host->mmc), " DTO %d cycles + %d ns\n", - data->timeout_clks, data->timeout_ns); - timeout = data->timeout_clks + - (data->timeout_ns / host->ns_in_one_cycle); - if (timeout > 0xffff) - timeout = 0xffff; - - writel(timeout, host->base + DAVINCI_MMCTOD); - writel(data->blocks, host->base + DAVINCI_MMCNBLK); - writel(data->blksz, host->base + DAVINCI_MMCBLEN); - - /* Configure the FIFO */ - switch (data->flags & MMC_DATA_WRITE) { - case MMC_DATA_WRITE: - host->data_dir = DAVINCI_MMC_DATADIR_WRITE; - writel(fifo_lev | MMCFIFOCTL_FIFODIR_WR | MMCFIFOCTL_FIFORST, - host->base + DAVINCI_MMCFIFOCTL); - writel(fifo_lev | MMCFIFOCTL_FIFODIR_WR, - host->base + DAVINCI_MMCFIFOCTL); - break; - - default: - host->data_dir = DAVINCI_MMC_DATADIR_READ; - writel(fifo_lev | MMCFIFOCTL_FIFODIR_RD | MMCFIFOCTL_FIFORST, - host->base + DAVINCI_MMCFIFOCTL); - writel(fifo_lev | MMCFIFOCTL_FIFODIR_RD, - host->base + DAVINCI_MMCFIFOCTL); - break; - } - - host->buffer = NULL; - host->bytes_left = data->blocks * data->blksz; - - /* For now we try to use DMA whenever we won't need partial FIFO - * reads or writes, either for the whole transfer (as tested here) - * or for any individual scatterlist segment (tested when we call - * start_dma_transfer). - * - * While we *could* change that, unusual block sizes are rarely - * used. The occasional fallback to PIO should't hurt. - */ - if (host->use_dma && (host->bytes_left & (rw_threshold - 1)) == 0 - && mmc_davinci_start_dma_transfer(host, data) == 0) { - /* zero this to ensure we take no PIO paths */ - host->bytes_left = 0; - } else { - /* Revert to CPU Copy */ - host->sg_len = data->sg_len; - host->sg = host->data->sg; - mmc_davinci_sg_to_buf(host); - } -} - -static void mmc_davinci_request(struct mmc_host *mmc, struct mmc_request *req) -{ - struct mmc_davinci_host *host = mmc_priv(mmc); - unsigned long timeout = jiffies + msecs_to_jiffies(900); - u32 mmcst1 = 0; - - /* Card may still be sending BUSY after a previous operation, - * typically some kind of write. If so, we can't proceed yet. - */ - while (time_before(jiffies, timeout)) { - mmcst1 = readl(host->base + DAVINCI_MMCST1); - if (!(mmcst1 & MMCST1_BUSY)) - break; - cpu_relax(); - } - if (mmcst1 & MMCST1_BUSY) { - dev_err(mmc_dev(host->mmc), "still BUSY? bad ... \n"); - req->cmd->error = -ETIMEDOUT; - mmc_request_done(mmc, req); - return; - } - - host->do_dma = 0; - mmc_davinci_prepare_data(host, req); - mmc_davinci_start_command(host, req->cmd); -} - -static unsigned int calculate_freq_for_card(struct mmc_davinci_host *host, - unsigned int mmc_req_freq) -{ - unsigned int mmc_freq = 0, mmc_pclk = 0, mmc_push_pull_divisor = 0; - - mmc_pclk = host->mmc_input_clk; - if (mmc_req_freq && mmc_pclk > (2 * mmc_req_freq)) - mmc_push_pull_divisor = ((unsigned int)mmc_pclk - / (2 * mmc_req_freq)) - 1; - else - mmc_push_pull_divisor = 0; - - mmc_freq = (unsigned int)mmc_pclk - / (2 * (mmc_push_pull_divisor + 1)); - - if (mmc_freq > mmc_req_freq) - mmc_push_pull_divisor = mmc_push_pull_divisor + 1; - /* Convert ns to clock cycles */ - if (mmc_req_freq <= 400000) - host->ns_in_one_cycle = (1000000) / (((mmc_pclk - / (2 * (mmc_push_pull_divisor + 1)))/1000)); - else - host->ns_in_one_cycle = (1000000) / (((mmc_pclk - / (2 * (mmc_push_pull_divisor + 1)))/1000000)); - - return mmc_push_pull_divisor; -} - -static void calculate_clk_divider(struct mmc_host *mmc, struct mmc_ios *ios) -{ - unsigned int open_drain_freq = 0, mmc_pclk = 0; - unsigned int mmc_push_pull_freq = 0; - struct mmc_davinci_host *host = mmc_priv(mmc); - - if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN) { - u32 temp; - - /* Ignoring the init clock value passed for fixing the inter - * operability with different cards. - */ - open_drain_freq = ((unsigned int)mmc_pclk - / (2 * MMCSD_INIT_CLOCK)) - 1; - - if (open_drain_freq > 0xFF) - open_drain_freq = 0xFF; - - temp = readl(host->base + DAVINCI_MMCCLK) & ~MMCCLK_CLKRT_MASK; - temp |= open_drain_freq; - writel(temp, host->base + DAVINCI_MMCCLK); - - /* Convert ns to clock cycles */ - host->ns_in_one_cycle = (1000000) / (MMCSD_INIT_CLOCK/1000); - } else { - u32 temp; - mmc_push_pull_freq = calculate_freq_for_card(host, ios->clock); - - if (mmc_push_pull_freq > 0xFF) - mmc_push_pull_freq = 0xFF; - - temp = readl(host->base + DAVINCI_MMCCLK) & ~MMCCLK_CLKEN; - writel(temp, host->base + DAVINCI_MMCCLK); - - udelay(10); - - temp = readl(host->base + DAVINCI_MMCCLK) & ~MMCCLK_CLKRT_MASK; - temp |= mmc_push_pull_freq; - writel(temp, host->base + DAVINCI_MMCCLK); - - writel(temp | MMCCLK_CLKEN, host->base + DAVINCI_MMCCLK); - - udelay(10); - } -} - -static void mmc_davinci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) -{ - struct mmc_davinci_host *host = mmc_priv(mmc); - struct platform_device *pdev = to_platform_device(mmc->parent); - struct davinci_mmc_config *config = pdev->dev.platform_data; - - dev_dbg(mmc_dev(host->mmc), - "clock %dHz busmode %d powermode %d Vdd %04x\n", - ios->clock, ios->bus_mode, ios->power_mode, - ios->vdd); - - switch (ios->power_mode) { - case MMC_POWER_OFF: - if (config && config->set_power) - config->set_power(pdev->id, false); - break; - case MMC_POWER_UP: - if (config && config->set_power) - config->set_power(pdev->id, true); - break; - } - - switch (ios->bus_width) { - case MMC_BUS_WIDTH_8: - dev_dbg(mmc_dev(host->mmc), "Enabling 8 bit mode\n"); - writel((readl(host->base + DAVINCI_MMCCTL) & - ~MMCCTL_WIDTH_4_BIT) | MMCCTL_WIDTH_8_BIT, - host->base + DAVINCI_MMCCTL); - break; - case MMC_BUS_WIDTH_4: - dev_dbg(mmc_dev(host->mmc), "Enabling 4 bit mode\n"); - if (host->version == MMC_CTLR_VERSION_2) - writel((readl(host->base + DAVINCI_MMCCTL) & - ~MMCCTL_WIDTH_8_BIT) | MMCCTL_WIDTH_4_BIT, - host->base + DAVINCI_MMCCTL); - else - writel(readl(host->base + DAVINCI_MMCCTL) | - MMCCTL_WIDTH_4_BIT, - host->base + DAVINCI_MMCCTL); - break; - case MMC_BUS_WIDTH_1: - dev_dbg(mmc_dev(host->mmc), "Enabling 1 bit mode\n"); - if (host->version == MMC_CTLR_VERSION_2) - writel(readl(host->base + DAVINCI_MMCCTL) & - ~(MMCCTL_WIDTH_8_BIT | MMCCTL_WIDTH_4_BIT), - host->base + DAVINCI_MMCCTL); - else - writel(readl(host->base + DAVINCI_MMCCTL) & - ~MMCCTL_WIDTH_4_BIT, - host->base + DAVINCI_MMCCTL); - break; - } - - calculate_clk_divider(mmc, ios); - - host->bus_mode = ios->bus_mode; - if (ios->power_mode == MMC_POWER_UP) { - unsigned long timeout = jiffies + msecs_to_jiffies(50); - bool lose = true; - - /* Send clock cycles, poll completion */ - writel(0, host->base + DAVINCI_MMCARGHL); - writel(MMCCMD_INITCK, host->base + DAVINCI_MMCCMD); - while (time_before(jiffies, timeout)) { - u32 tmp = readl(host->base + DAVINCI_MMCST0); - - if (tmp & MMCST0_RSPDNE) { - lose = false; - break; - } - cpu_relax(); - } - if (lose) - dev_warn(mmc_dev(host->mmc), "powerup timeout\n"); - } - - /* FIXME on power OFF, reset things ... */ -} - -static void -mmc_davinci_xfer_done(struct mmc_davinci_host *host, struct mmc_data *data) -{ - host->data = NULL; - - if (host->mmc->caps & MMC_CAP_SDIO_IRQ) { - /* - * SDIO Interrupt Detection work-around as suggested by - * Davinci Errata (TMS320DM355 Silicon Revision 1.1 Errata - * 2.1.6): Signal SDIO interrupt only if it is enabled by core - */ - if (host->sdio_int && !(readl(host->base + DAVINCI_SDIOST0) & - SDIOST0_DAT1_HI)) { - writel(SDIOIST_IOINT, host->base + DAVINCI_SDIOIST); - mmc_signal_sdio_irq(host->mmc); - } - } - - if (host->do_dma) { - davinci_abort_dma(host); - - dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len, - (data->flags & MMC_DATA_WRITE) - ? DMA_TO_DEVICE - : DMA_FROM_DEVICE); - host->do_dma = false; - } - host->data_dir = DAVINCI_MMC_DATADIR_NONE; - - if (!data->stop || (host->cmd && host->cmd->error)) { - mmc_request_done(host->mmc, data->mrq); - writel(0, host->base + DAVINCI_MMCIM); - host->active_request = false; - } else - mmc_davinci_start_command(host, data->stop); -} - -static void mmc_davinci_cmd_done(struct mmc_davinci_host *host, - struct mmc_command *cmd) -{ - host->cmd = NULL; - - if (cmd->flags & MMC_RSP_PRESENT) { - if (cmd->flags & MMC_RSP_136) { - /* response type 2 */ - cmd->resp[3] = readl(host->base + DAVINCI_MMCRSP01); - cmd->resp[2] = readl(host->base + DAVINCI_MMCRSP23); - cmd->resp[1] = readl(host->base + DAVINCI_MMCRSP45); - cmd->resp[0] = readl(host->base + DAVINCI_MMCRSP67); - } else { - /* response types 1, 1b, 3, 4, 5, 6 */ - cmd->resp[0] = readl(host->base + DAVINCI_MMCRSP67); - } - } - - if (host->data == NULL || cmd->error) { - if (cmd->error == -ETIMEDOUT) - cmd->mrq->cmd->retries = 0; - mmc_request_done(host->mmc, cmd->mrq); - writel(0, host->base + DAVINCI_MMCIM); - host->active_request = false; - } -} - -static inline void mmc_davinci_reset_ctrl(struct mmc_davinci_host *host, - int val) -{ - u32 temp; - - temp = readl(host->base + DAVINCI_MMCCTL); - if (val) /* reset */ - temp |= MMCCTL_CMDRST | MMCCTL_DATRST; - else /* enable */ - temp &= ~(MMCCTL_CMDRST | MMCCTL_DATRST); - - writel(temp, host->base + DAVINCI_MMCCTL); - udelay(10); -} - -static void -davinci_abort_data(struct mmc_davinci_host *host, struct mmc_data *data) -{ - mmc_davinci_reset_ctrl(host, 1); - mmc_davinci_reset_ctrl(host, 0); -} - -static irqreturn_t mmc_davinci_sdio_irq(int irq, void *dev_id) -{ - struct mmc_davinci_host *host = dev_id; - unsigned int status; - - status = readl(host->base + DAVINCI_SDIOIST); - if (status & SDIOIST_IOINT) { - dev_dbg(mmc_dev(host->mmc), - "SDIO interrupt status %x\n", status); - writel(status | SDIOIST_IOINT, host->base + DAVINCI_SDIOIST); - mmc_signal_sdio_irq(host->mmc); - } - return IRQ_HANDLED; -} - -static irqreturn_t mmc_davinci_irq(int irq, void *dev_id) -{ - struct mmc_davinci_host *host = (struct mmc_davinci_host *)dev_id; - unsigned int status, qstatus; - int end_command = 0; - int end_transfer = 0; - struct mmc_data *data = host->data; - - if (host->cmd == NULL && host->data == NULL) { - status = readl(host->base + DAVINCI_MMCST0); - dev_dbg(mmc_dev(host->mmc), - "Spurious interrupt 0x%04x\n", status); - /* Disable the interrupt from mmcsd */ - writel(0, host->base + DAVINCI_MMCIM); - return IRQ_NONE; - } - - status = readl(host->base + DAVINCI_MMCST0); - qstatus = status; - - /* handle FIFO first when using PIO for data. - * bytes_left will decrease to zero as I/O progress and status will - * read zero over iteration because this controller status - * register(MMCST0) reports any status only once and it is cleared - * by read. So, it is not unbouned loop even in the case of - * non-dma. - */ - if (host->bytes_left && (status & (MMCST0_DXRDY | MMCST0_DRRDY))) { - unsigned long im_val; - - /* - * If interrupts fire during the following loop, they will be - * handled by the handler, but the PIC will still buffer these. - * As a result, the handler will be called again to serve these - * needlessly. In order to avoid these spurious interrupts, - * keep interrupts masked during the loop. - */ - im_val = readl(host->base + DAVINCI_MMCIM); - writel(0, host->base + DAVINCI_MMCIM); - - do { - davinci_fifo_data_trans(host, rw_threshold); - status = readl(host->base + DAVINCI_MMCST0); - qstatus |= status; - } while (host->bytes_left && - (status & (MMCST0_DXRDY | MMCST0_DRRDY))); - - /* - * If an interrupt is pending, it is assumed it will fire when - * it is unmasked. This assumption is also taken when the MMCIM - * is first set. Otherwise, writing to MMCIM after reading the - * status is race-prone. - */ - writel(im_val, host->base + DAVINCI_MMCIM); - } - - if (qstatus & MMCST0_DATDNE) { - /* All blocks sent/received, and CRC checks passed */ - if (data != NULL) { - if ((host->do_dma == 0) && (host->bytes_left > 0)) { - /* if datasize < rw_threshold - * no RX ints are generated - */ - davinci_fifo_data_trans(host, host->bytes_left); - } - end_transfer = 1; - data->bytes_xfered = data->blocks * data->blksz; - } else { - dev_err(mmc_dev(host->mmc), - "DATDNE with no host->data\n"); - } - } - - if (qstatus & MMCST0_TOUTRD) { - /* Read data timeout */ - data->error = -ETIMEDOUT; - end_transfer = 1; - - dev_dbg(mmc_dev(host->mmc), - "read data timeout, status %x\n", - qstatus); - - davinci_abort_data(host, data); - } - - if (qstatus & (MMCST0_CRCWR | MMCST0_CRCRD)) { - /* Data CRC error */ - data->error = -EILSEQ; - end_transfer = 1; - - /* NOTE: this controller uses CRCWR to report both CRC - * errors and timeouts (on writes). MMCDRSP values are - * only weakly documented, but 0x9f was clearly a timeout - * case and the two three-bit patterns in various SD specs - * (101, 010) aren't part of it ... - */ - if (qstatus & MMCST0_CRCWR) { - u32 temp = readb(host->base + DAVINCI_MMCDRSP); - - if (temp == 0x9f) - data->error = -ETIMEDOUT; - } - dev_dbg(mmc_dev(host->mmc), "data %s %s error\n", - (qstatus & MMCST0_CRCWR) ? "write" : "read", - (data->error == -ETIMEDOUT) ? "timeout" : "CRC"); - - davinci_abort_data(host, data); - } - - if (qstatus & MMCST0_TOUTRS) { - /* Command timeout */ - if (host->cmd) { - dev_dbg(mmc_dev(host->mmc), - "CMD%d timeout, status %x\n", - host->cmd->opcode, qstatus); - host->cmd->error = -ETIMEDOUT; - if (data) { - end_transfer = 1; - davinci_abort_data(host, data); - } else - end_command = 1; - } - } - - if (qstatus & MMCST0_CRCRS) { - /* Command CRC error */ - dev_dbg(mmc_dev(host->mmc), "Command CRC error\n"); - if (host->cmd) { - host->cmd->error = -EILSEQ; - end_command = 1; - } - } - - if (qstatus & MMCST0_RSPDNE) { - /* End of command phase */ - end_command = (int) host->cmd; - } - - if (end_command) - mmc_davinci_cmd_done(host, host->cmd); - if (end_transfer) - mmc_davinci_xfer_done(host, data); - return IRQ_HANDLED; -} - -static int mmc_davinci_get_cd(struct mmc_host *mmc) -{ - struct platform_device *pdev = to_platform_device(mmc->parent); - struct davinci_mmc_config *config = pdev->dev.platform_data; - - if (!config || !config->get_cd) - return -ENOSYS; - return config->get_cd(pdev->id); -} - -static int mmc_davinci_get_ro(struct mmc_host *mmc) -{ - struct platform_device *pdev = to_platform_device(mmc->parent); - struct davinci_mmc_config *config = pdev->dev.platform_data; - - if (!config || !config->get_ro) - return -ENOSYS; - return config->get_ro(pdev->id); -} - -static void mmc_davinci_enable_sdio_irq(struct mmc_host *mmc, int enable) -{ - struct mmc_davinci_host *host = mmc_priv(mmc); - - if (enable) { - if (!(readl(host->base + DAVINCI_SDIOST0) & SDIOST0_DAT1_HI)) { - writel(SDIOIST_IOINT, host->base + DAVINCI_SDIOIST); - mmc_signal_sdio_irq(host->mmc); - } else { - host->sdio_int = true; - writel(readl(host->base + DAVINCI_SDIOIEN) | - SDIOIEN_IOINTEN, host->base + DAVINCI_SDIOIEN); - } - } else { - host->sdio_int = false; - writel(readl(host->base + DAVINCI_SDIOIEN) & ~SDIOIEN_IOINTEN, - host->base + DAVINCI_SDIOIEN); - } -} - -static struct mmc_host_ops mmc_davinci_ops = { - .request = mmc_davinci_request, - .set_ios = mmc_davinci_set_ios, - .get_cd = mmc_davinci_get_cd, - .get_ro = mmc_davinci_get_ro, - .enable_sdio_irq = mmc_davinci_enable_sdio_irq, -}; - -/*----------------------------------------------------------------------*/ - -#ifdef CONFIG_CPU_FREQ -static int mmc_davinci_cpufreq_transition(struct notifier_block *nb, - unsigned long val, void *data) -{ - struct mmc_davinci_host *host; - unsigned int mmc_pclk; - struct mmc_host *mmc; - unsigned long flags; - - host = container_of(nb, struct mmc_davinci_host, freq_transition); - mmc = host->mmc; - mmc_pclk = clk_get_rate(host->clk); - - if (val == CPUFREQ_POSTCHANGE) { - spin_lock_irqsave(&mmc->lock, flags); - host->mmc_input_clk = mmc_pclk; - calculate_clk_divider(mmc, &mmc->ios); - spin_unlock_irqrestore(&mmc->lock, flags); - } - - return 0; -} - -static inline int mmc_davinci_cpufreq_register(struct mmc_davinci_host *host) -{ - host->freq_transition.notifier_call = mmc_davinci_cpufreq_transition; - - return cpufreq_register_notifier(&host->freq_transition, - CPUFREQ_TRANSITION_NOTIFIER); -} - -static inline void mmc_davinci_cpufreq_deregister(struct mmc_davinci_host *host) -{ - cpufreq_unregister_notifier(&host->freq_transition, - CPUFREQ_TRANSITION_NOTIFIER); -} -#else -static inline int mmc_davinci_cpufreq_register(struct mmc_davinci_host *host) -{ - return 0; -} - -static inline void mmc_davinci_cpufreq_deregister(struct mmc_davinci_host *host) -{ -} -#endif -static void __init init_mmcsd_host(struct mmc_davinci_host *host) -{ - - mmc_davinci_reset_ctrl(host, 1); - - writel(0, host->base + DAVINCI_MMCCLK); - writel(MMCCLK_CLKEN, host->base + DAVINCI_MMCCLK); - - writel(0x1FFF, host->base + DAVINCI_MMCTOR); - writel(0xFFFF, host->base + DAVINCI_MMCTOD); - - mmc_davinci_reset_ctrl(host, 0); -} - -static int __init davinci_mmcsd_probe(struct platform_device *pdev) -{ - struct davinci_mmc_config *pdata = pdev->dev.platform_data; - struct mmc_davinci_host *host = NULL; - struct mmc_host *mmc = NULL; - struct resource *r, *mem = NULL; - int ret = 0, irq = 0; - size_t mem_size; - - /* REVISIT: when we're fully converted, fail if pdata is NULL */ - - ret = -ENODEV; - r = platform_get_resource(pdev, IORESOURCE_MEM, 0); - irq = platform_get_irq(pdev, 0); - if (!r || irq == NO_IRQ) - goto out; - - ret = -EBUSY; - mem_size = resource_size(r); - mem = request_mem_region(r->start, mem_size, pdev->name); - if (!mem) - goto out; - - ret = -ENOMEM; - mmc = mmc_alloc_host(sizeof(struct mmc_davinci_host), &pdev->dev); - if (!mmc) - goto out; - - host = mmc_priv(mmc); - host->mmc = mmc; /* Important */ - - r = platform_get_resource(pdev, IORESOURCE_DMA, 0); - if (!r) - goto out; - host->rxdma = r->start; - - r = platform_get_resource(pdev, IORESOURCE_DMA, 1); - if (!r) - goto out; - host->txdma = r->start; - - host->mem_res = mem; - host->base = ioremap(mem->start, mem_size); - if (!host->base) - goto out; - - ret = -ENXIO; - host->clk = clk_get(&pdev->dev, "MMCSDCLK"); - if (IS_ERR(host->clk)) { - ret = PTR_ERR(host->clk); - goto out; - } - clk_enable(host->clk); - host->mmc_input_clk = clk_get_rate(host->clk); - - init_mmcsd_host(host); - - if (pdata->nr_sg) - host->nr_sg = pdata->nr_sg - 1; - - if (host->nr_sg > MAX_NR_SG || !host->nr_sg) - host->nr_sg = MAX_NR_SG; - - host->use_dma = use_dma; - host->mmc_irq = irq; - host->sdio_irq = platform_get_irq(pdev, 1); - - if (host->use_dma && davinci_acquire_dma_channels(host) != 0) - host->use_dma = 0; - - /* REVISIT: someday, support IRQ-driven card detection. */ - mmc->caps |= MMC_CAP_NEEDS_POLL; - mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY; - - if (pdata && (pdata->wires == 4 || pdata->wires == 0)) - mmc->caps |= MMC_CAP_4_BIT_DATA; - - if (pdata && (pdata->wires == 8)) - mmc->caps |= (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA); - - host->version = pdata->version; - - mmc->ops = &mmc_davinci_ops; - mmc->f_min = 312500; - mmc->f_max = 25000000; - if (pdata && pdata->max_freq) - mmc->f_max = pdata->max_freq; - if (pdata && pdata->caps) - mmc->caps |= pdata->caps; - mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; - - /* With no iommu coalescing pages, each phys_seg is a hw_seg. - * Each hw_seg uses one EDMA parameter RAM slot, always one - * channel and then usually some linked slots. - */ - mmc->max_segs = 1 + host->n_link; - - /* EDMA limit per hw segment (one or two MBytes) */ - mmc->max_seg_size = MAX_CCNT * rw_threshold; - - /* MMC/SD controller limits for multiblock requests */ - mmc->max_blk_size = 4095; /* BLEN is 12 bits */ - mmc->max_blk_count = 65535; /* NBLK is 16 bits */ - mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count; - - dev_dbg(mmc_dev(host->mmc), "max_segs=%d\n", mmc->max_segs); - dev_dbg(mmc_dev(host->mmc), "max_blk_size=%d\n", mmc->max_blk_size); - dev_dbg(mmc_dev(host->mmc), "max_req_size=%d\n", mmc->max_req_size); - dev_dbg(mmc_dev(host->mmc), "max_seg_size=%d\n", mmc->max_seg_size); - - platform_set_drvdata(pdev, host); - - ret = mmc_davinci_cpufreq_register(host); - if (ret) { - dev_err(&pdev->dev, "failed to register cpufreq\n"); - goto cpu_freq_fail; - } - - ret = mmc_add_host(mmc); - if (ret < 0) - goto out; - - ret = request_irq(irq, mmc_davinci_irq, 0, mmc_hostname(mmc), host); - if (ret) - goto out; - - if (host->sdio_irq >= 0) { - ret = request_irq(host->sdio_irq, mmc_davinci_sdio_irq, 0, - mmc_hostname(mmc), host); - if (!ret) - mmc->caps |= MMC_CAP_SDIO_IRQ; - } - - rename_region(mem, mmc_hostname(mmc)); - - dev_info(mmc_dev(host->mmc), "Using %s, %d-bit mode\n", - host->use_dma ? "DMA" : "PIO", - (mmc->caps & MMC_CAP_4_BIT_DATA) ? 4 : 1); - - return 0; - -out: - mmc_davinci_cpufreq_deregister(host); -cpu_freq_fail: - if (host) { - davinci_release_dma_channels(host); - - if (host->clk) { - clk_disable(host->clk); - clk_put(host->clk); - } - - if (host->base) - iounmap(host->base); - } - - if (mmc) - mmc_free_host(mmc); - - if (mem) - release_resource(mem); - - dev_dbg(&pdev->dev, "probe err %d\n", ret); - - return ret; -} - -static int __exit davinci_mmcsd_remove(struct platform_device *pdev) -{ - struct mmc_davinci_host *host = platform_get_drvdata(pdev); - - platform_set_drvdata(pdev, NULL); - if (host) { - mmc_davinci_cpufreq_deregister(host); - - mmc_remove_host(host->mmc); - free_irq(host->mmc_irq, host); - if (host->mmc->caps & MMC_CAP_SDIO_IRQ) - free_irq(host->sdio_irq, host); - - davinci_release_dma_channels(host); - - clk_disable(host->clk); - clk_put(host->clk); - - iounmap(host->base); - - release_resource(host->mem_res); - - mmc_free_host(host->mmc); - } - - return 0; -} - -#ifdef CONFIG_PM -static int davinci_mmcsd_suspend(struct device *dev) -{ - struct platform_device *pdev = to_platform_device(dev); - struct mmc_davinci_host *host = platform_get_drvdata(pdev); - int ret; - - ret = mmc_suspend_host(host->mmc); - if (!ret) { - writel(0, host->base + DAVINCI_MMCIM); - mmc_davinci_reset_ctrl(host, 1); - clk_disable(host->clk); - host->suspended = 1; - } else { - host->suspended = 0; - } - - return ret; -} - -static int davinci_mmcsd_resume(struct device *dev) -{ - struct platform_device *pdev = to_platform_device(dev); - struct mmc_davinci_host *host = platform_get_drvdata(pdev); - int ret; - - if (!host->suspended) - return 0; - - clk_enable(host->clk); - - mmc_davinci_reset_ctrl(host, 0); - ret = mmc_resume_host(host->mmc); - if (!ret) - host->suspended = 0; - - return ret; -} - -static const struct dev_pm_ops davinci_mmcsd_pm = { - .suspend = davinci_mmcsd_suspend, - .resume = davinci_mmcsd_resume, -}; - -#define davinci_mmcsd_pm_ops (&davinci_mmcsd_pm) -#else -#define davinci_mmcsd_pm_ops NULL -#endif - -static struct platform_driver davinci_mmcsd_driver = { - .driver = { - .name = "davinci_mmc", - .owner = THIS_MODULE, - .pm = davinci_mmcsd_pm_ops, - }, - .remove = __exit_p(davinci_mmcsd_remove), -}; - -static int __init davinci_mmcsd_init(void) -{ - return platform_driver_probe(&davinci_mmcsd_driver, - davinci_mmcsd_probe); -} -module_init(davinci_mmcsd_init); - -static void __exit davinci_mmcsd_exit(void) -{ - platform_driver_unregister(&davinci_mmcsd_driver); -} -module_exit(davinci_mmcsd_exit); - -MODULE_AUTHOR("Texas Instruments India"); -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("MMC/SD driver for Davinci MMC controller"); - diff --git a/ANDROID_3.4.5/drivers/mmc/host/dw_mmc-pci.c b/ANDROID_3.4.5/drivers/mmc/host/dw_mmc-pci.c deleted file mode 100644 index dc0d25a0..00000000 --- a/ANDROID_3.4.5/drivers/mmc/host/dw_mmc-pci.c +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Synopsys DesignWare Multimedia Card PCI Interface driver - * - * Copyright (C) 2012 Vayavya Labs Pvt. Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - -#include <linux/interrupt.h> -#include <linux/module.h> -#include <linux/io.h> -#include <linux/irq.h> -#include <linux/pci.h> -#include <linux/slab.h> -#include <linux/mmc/host.h> -#include <linux/mmc/mmc.h> -#include <linux/mmc/dw_mmc.h> -#include "dw_mmc.h" - -#define PCI_BAR_NO 2 -#define COMPLETE_BAR 0 -#define SYNOPSYS_DW_MCI_VENDOR_ID 0x700 -#define SYNOPSYS_DW_MCI_DEVICE_ID 0x1107 -/* Defining the Capabilities */ -#define DW_MCI_CAPABILITIES (MMC_CAP_4_BIT_DATA | MMC_CAP_MMC_HIGHSPEED |\ - MMC_CAP_SD_HIGHSPEED | MMC_CAP_8_BIT_DATA |\ - MMC_CAP_SDIO_IRQ) - -static struct dw_mci_board pci_board_data = { - .num_slots = 1, - .caps = DW_MCI_CAPABILITIES, - .bus_hz = 33 * 1000 * 1000, - .detect_delay_ms = 200, - .fifo_depth = 32, -}; - -static int __devinit dw_mci_pci_probe(struct pci_dev *pdev, - const struct pci_device_id *entries) -{ - struct dw_mci *host; - int ret; - - ret = pci_enable_device(pdev); - if (ret) - return ret; - if (pci_request_regions(pdev, "dw_mmc_pci")) { - ret = -ENODEV; - goto err_disable_dev; - } - - host = kzalloc(sizeof(struct dw_mci), GFP_KERNEL); - if (!host) { - ret = -ENOMEM; - goto err_release; - } - - host->irq = pdev->irq; - host->irq_flags = IRQF_SHARED; - host->dev = pdev->dev; - host->pdata = &pci_board_data; - - host->regs = pci_iomap(pdev, PCI_BAR_NO, COMPLETE_BAR); - if (!host->regs) { - ret = -EIO; - goto err_unmap; - } - - pci_set_drvdata(pdev, host); - ret = dw_mci_probe(host); - if (ret) - goto err_probe_failed; - return ret; - -err_probe_failed: - pci_iounmap(pdev, host->regs); -err_unmap: - kfree(host); -err_release: - pci_release_regions(pdev); -err_disable_dev: - pci_disable_device(pdev); - return ret; -} - -static void __devexit dw_mci_pci_remove(struct pci_dev *pdev) -{ - struct dw_mci *host = pci_get_drvdata(pdev); - - dw_mci_remove(host); - pci_set_drvdata(pdev, NULL); - pci_release_regions(pdev); - pci_iounmap(pdev, host->regs); - kfree(host); - pci_disable_device(pdev); -} - -#ifdef CONFIG_PM_SLEEP -static int dw_mci_pci_suspend(struct device *dev) -{ - int ret; - struct pci_dev *pdev = to_pci_dev(dev); - struct dw_mci *host = pci_get_drvdata(pdev); - - ret = dw_mci_suspend(host); - return ret; -} - -static int dw_mci_pci_resume(struct device *dev) -{ - int ret; - struct pci_dev *pdev = to_pci_dev(dev); - struct dw_mci *host = pci_get_drvdata(pdev); - - ret = dw_mci_resume(host); - return ret; -} -#else -#define dw_mci_pci_suspend NULL -#define dw_mci_pci_resume NULL -#endif /* CONFIG_PM_SLEEP */ - -static SIMPLE_DEV_PM_OPS(dw_mci_pci_pmops, dw_mci_pci_suspend, dw_mci_pci_resume); - -static DEFINE_PCI_DEVICE_TABLE(dw_mci_pci_id) = { - { PCI_DEVICE(SYNOPSYS_DW_MCI_VENDOR_ID, SYNOPSYS_DW_MCI_DEVICE_ID) }, - {} -}; -MODULE_DEVICE_TABLE(pci, dw_mci_pci_id); - -static struct pci_driver dw_mci_pci_driver = { - .name = "dw_mmc_pci", - .id_table = dw_mci_pci_id, - .probe = dw_mci_pci_probe, - .remove = dw_mci_pci_remove, - .driver = { - .pm = &dw_mci_pci_pmops - }, -}; - -static int __init dw_mci_init(void) -{ - return pci_register_driver(&dw_mci_pci_driver); -} - -static void __exit dw_mci_exit(void) -{ - pci_unregister_driver(&dw_mci_pci_driver); -} - -module_init(dw_mci_init); -module_exit(dw_mci_exit); - -MODULE_DESCRIPTION("DW Multimedia Card PCI Interface driver"); -MODULE_AUTHOR("Shashidhar Hiremath <shashidharh@vayavyalabs.com>"); -MODULE_LICENSE("GPL v2"); diff --git a/ANDROID_3.4.5/drivers/mmc/host/dw_mmc-pltfm.c b/ANDROID_3.4.5/drivers/mmc/host/dw_mmc-pltfm.c deleted file mode 100644 index 92ec3eb3..00000000 --- a/ANDROID_3.4.5/drivers/mmc/host/dw_mmc-pltfm.c +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Synopsys DesignWare Multimedia Card Interface driver - * - * Copyright (C) 2009 NXP Semiconductors - * Copyright (C) 2009, 2010 Imagination Technologies Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - -#include <linux/interrupt.h> -#include <linux/module.h> -#include <linux/io.h> -#include <linux/irq.h> -#include <linux/platform_device.h> -#include <linux/slab.h> -#include <linux/mmc/host.h> -#include <linux/mmc/mmc.h> -#include <linux/mmc/dw_mmc.h> -#include "dw_mmc.h" - -static int dw_mci_pltfm_probe(struct platform_device *pdev) -{ - struct dw_mci *host; - struct resource *regs; - int ret; - - host = kzalloc(sizeof(struct dw_mci), GFP_KERNEL); - if (!host) - return -ENOMEM; - - regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!regs) { - ret = -ENXIO; - goto err_free; - } - - host->irq = platform_get_irq(pdev, 0); - if (host->irq < 0) { - ret = host->irq; - goto err_free; - } - - host->dev = pdev->dev; - host->irq_flags = 0; - host->pdata = pdev->dev.platform_data; - ret = -ENOMEM; - host->regs = ioremap(regs->start, resource_size(regs)); - if (!host->regs) - goto err_free; - platform_set_drvdata(pdev, host); - ret = dw_mci_probe(host); - if (ret) - goto err_out; - return ret; -err_out: - iounmap(host->regs); -err_free: - kfree(host); - return ret; -} - -static int __exit dw_mci_pltfm_remove(struct platform_device *pdev) -{ - struct dw_mci *host = platform_get_drvdata(pdev); - - platform_set_drvdata(pdev, NULL); - dw_mci_remove(host); - iounmap(host->regs); - kfree(host); - return 0; -} - -#ifdef CONFIG_PM_SLEEP -/* - * TODO: we should probably disable the clock to the card in the suspend path. - */ -static int dw_mci_pltfm_suspend(struct device *dev) -{ - int ret; - struct dw_mci *host = dev_get_drvdata(dev); - - ret = dw_mci_suspend(host); - if (ret) - return ret; - - return 0; -} - -static int dw_mci_pltfm_resume(struct device *dev) -{ - int ret; - struct dw_mci *host = dev_get_drvdata(dev); - - ret = dw_mci_resume(host); - if (ret) - return ret; - - return 0; -} -#else -#define dw_mci_pltfm_suspend NULL -#define dw_mci_pltfm_resume NULL -#endif /* CONFIG_PM_SLEEP */ - -static SIMPLE_DEV_PM_OPS(dw_mci_pltfm_pmops, dw_mci_pltfm_suspend, dw_mci_pltfm_resume); - -static struct platform_driver dw_mci_pltfm_driver = { - .remove = __exit_p(dw_mci_pltfm_remove), - .driver = { - .name = "dw_mmc", - .pm = &dw_mci_pltfm_pmops, - }, -}; - -static int __init dw_mci_init(void) -{ - return platform_driver_probe(&dw_mci_pltfm_driver, dw_mci_pltfm_probe); -} - -static void __exit dw_mci_exit(void) -{ - platform_driver_unregister(&dw_mci_pltfm_driver); -} - -module_init(dw_mci_init); -module_exit(dw_mci_exit); - -MODULE_DESCRIPTION("DW Multimedia Card Interface driver"); -MODULE_AUTHOR("NXP Semiconductor VietNam"); -MODULE_AUTHOR("Imagination Technologies Ltd"); -MODULE_LICENSE("GPL v2"); diff --git a/ANDROID_3.4.5/drivers/mmc/host/dw_mmc.c b/ANDROID_3.4.5/drivers/mmc/host/dw_mmc.c deleted file mode 100644 index ab3fc461..00000000 --- a/ANDROID_3.4.5/drivers/mmc/host/dw_mmc.c +++ /dev/null @@ -1,2221 +0,0 @@ -/* - * Synopsys DesignWare Multimedia Card Interface driver - * (Based on NXP driver for lpc 31xx) - * - * Copyright (C) 2009 NXP Semiconductors - * Copyright (C) 2009, 2010 Imagination Technologies Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - -#include <linux/blkdev.h> -#include <linux/clk.h> -#include <linux/debugfs.h> -#include <linux/device.h> -#include <linux/dma-mapping.h> -#include <linux/err.h> -#include <linux/init.h> -#include <linux/interrupt.h> -#include <linux/ioport.h> -#include <linux/module.h> -#include <linux/platform_device.h> -#include <linux/seq_file.h> -#include <linux/slab.h> -#include <linux/stat.h> -#include <linux/delay.h> -#include <linux/irq.h> -#include <linux/mmc/host.h> -#include <linux/mmc/mmc.h> -#include <linux/mmc/dw_mmc.h> -#include <linux/bitops.h> -#include <linux/regulator/consumer.h> -#include <linux/workqueue.h> - -#include "dw_mmc.h" - -/* Common flag combinations */ -#define DW_MCI_DATA_ERROR_FLAGS (SDMMC_INT_DTO | SDMMC_INT_DCRC | \ - SDMMC_INT_HTO | SDMMC_INT_SBE | \ - SDMMC_INT_EBE) -#define DW_MCI_CMD_ERROR_FLAGS (SDMMC_INT_RTO | SDMMC_INT_RCRC | \ - SDMMC_INT_RESP_ERR) -#define DW_MCI_ERROR_FLAGS (DW_MCI_DATA_ERROR_FLAGS | \ - DW_MCI_CMD_ERROR_FLAGS | SDMMC_INT_HLE) -#define DW_MCI_SEND_STATUS 1 -#define DW_MCI_RECV_STATUS 2 -#define DW_MCI_DMA_THRESHOLD 16 - -#ifdef CONFIG_MMC_DW_IDMAC -struct idmac_desc { - u32 des0; /* Control Descriptor */ -#define IDMAC_DES0_DIC BIT(1) -#define IDMAC_DES0_LD BIT(2) -#define IDMAC_DES0_FD BIT(3) -#define IDMAC_DES0_CH BIT(4) -#define IDMAC_DES0_ER BIT(5) -#define IDMAC_DES0_CES BIT(30) -#define IDMAC_DES0_OWN BIT(31) - - u32 des1; /* Buffer sizes */ -#define IDMAC_SET_BUFFER1_SIZE(d, s) \ - ((d)->des1 = ((d)->des1 & 0x03ffe000) | ((s) & 0x1fff)) - - u32 des2; /* buffer 1 physical address */ - - u32 des3; /* buffer 2 physical address */ -}; -#endif /* CONFIG_MMC_DW_IDMAC */ - -/** - * struct dw_mci_slot - MMC slot state - * @mmc: The mmc_host representing this slot. - * @host: The MMC controller this slot is using. - * @ctype: Card type for this slot. - * @mrq: mmc_request currently being processed or waiting to be - * processed, or NULL when the slot is idle. - * @queue_node: List node for placing this node in the @queue list of - * &struct dw_mci. - * @clock: Clock rate configured by set_ios(). Protected by host->lock. - * @flags: Random state bits associated with the slot. - * @id: Number of this slot. - * @last_detect_state: Most recently observed card detect state. - */ -struct dw_mci_slot { - struct mmc_host *mmc; - struct dw_mci *host; - - u32 ctype; - - struct mmc_request *mrq; - struct list_head queue_node; - - unsigned int clock; - unsigned long flags; -#define DW_MMC_CARD_PRESENT 0 -#define DW_MMC_CARD_NEED_INIT 1 - int id; - int last_detect_state; -}; - -static struct workqueue_struct *dw_mci_card_workqueue; - -#if defined(CONFIG_DEBUG_FS) -static int dw_mci_req_show(struct seq_file *s, void *v) -{ - struct dw_mci_slot *slot = s->private; - struct mmc_request *mrq; - struct mmc_command *cmd; - struct mmc_command *stop; - struct mmc_data *data; - - /* Make sure we get a consistent snapshot */ - spin_lock_bh(&slot->host->lock); - mrq = slot->mrq; - - if (mrq) { - cmd = mrq->cmd; - data = mrq->data; - stop = mrq->stop; - - if (cmd) - seq_printf(s, - "CMD%u(0x%x) flg %x rsp %x %x %x %x err %d\n", - cmd->opcode, cmd->arg, cmd->flags, - cmd->resp[0], cmd->resp[1], cmd->resp[2], - cmd->resp[2], cmd->error); - if (data) - seq_printf(s, "DATA %u / %u * %u flg %x err %d\n", - data->bytes_xfered, data->blocks, - data->blksz, data->flags, data->error); - if (stop) - seq_printf(s, - "CMD%u(0x%x) flg %x rsp %x %x %x %x err %d\n", - stop->opcode, stop->arg, stop->flags, - stop->resp[0], stop->resp[1], stop->resp[2], - stop->resp[2], stop->error); - } - - spin_unlock_bh(&slot->host->lock); - - return 0; -} - -static int dw_mci_req_open(struct inode *inode, struct file *file) -{ - return single_open(file, dw_mci_req_show, inode->i_private); -} - -static const struct file_operations dw_mci_req_fops = { - .owner = THIS_MODULE, - .open = dw_mci_req_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static int dw_mci_regs_show(struct seq_file *s, void *v) -{ - seq_printf(s, "STATUS:\t0x%08x\n", SDMMC_STATUS); - seq_printf(s, "RINTSTS:\t0x%08x\n", SDMMC_RINTSTS); - seq_printf(s, "CMD:\t0x%08x\n", SDMMC_CMD); - seq_printf(s, "CTRL:\t0x%08x\n", SDMMC_CTRL); - seq_printf(s, "INTMASK:\t0x%08x\n", SDMMC_INTMASK); - seq_printf(s, "CLKENA:\t0x%08x\n", SDMMC_CLKENA); - - return 0; -} - -static int dw_mci_regs_open(struct inode *inode, struct file *file) -{ - return single_open(file, dw_mci_regs_show, inode->i_private); -} - -static const struct file_operations dw_mci_regs_fops = { - .owner = THIS_MODULE, - .open = dw_mci_regs_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static void dw_mci_init_debugfs(struct dw_mci_slot *slot) -{ - struct mmc_host *mmc = slot->mmc; - struct dw_mci *host = slot->host; - struct dentry *root; - struct dentry *node; - - root = mmc->debugfs_root; - if (!root) - return; - - node = debugfs_create_file("regs", S_IRUSR, root, host, - &dw_mci_regs_fops); - if (!node) - goto err; - - node = debugfs_create_file("req", S_IRUSR, root, slot, - &dw_mci_req_fops); - if (!node) - goto err; - - node = debugfs_create_u32("state", S_IRUSR, root, (u32 *)&host->state); - if (!node) - goto err; - - node = debugfs_create_x32("pending_events", S_IRUSR, root, - (u32 *)&host->pending_events); - if (!node) - goto err; - - node = debugfs_create_x32("completed_events", S_IRUSR, root, - (u32 *)&host->completed_events); - if (!node) - goto err; - - return; - -err: - dev_err(&mmc->class_dev, "failed to initialize debugfs for slot\n"); -} -#endif /* defined(CONFIG_DEBUG_FS) */ - -static void dw_mci_set_timeout(struct dw_mci *host) -{ - /* timeout (maximum) */ - mci_writel(host, TMOUT, 0xffffffff); -} - -static u32 dw_mci_prepare_command(struct mmc_host *mmc, struct mmc_command *cmd) -{ - struct mmc_data *data; - u32 cmdr; - cmd->error = -EINPROGRESS; - - cmdr = cmd->opcode; - - if (cmdr == MMC_STOP_TRANSMISSION) - cmdr |= SDMMC_CMD_STOP; - else - cmdr |= SDMMC_CMD_PRV_DAT_WAIT; - - if (cmd->flags & MMC_RSP_PRESENT) { - /* We expect a response, so set this bit */ - cmdr |= SDMMC_CMD_RESP_EXP; - if (cmd->flags & MMC_RSP_136) - cmdr |= SDMMC_CMD_RESP_LONG; - } - - if (cmd->flags & MMC_RSP_CRC) - cmdr |= SDMMC_CMD_RESP_CRC; - - data = cmd->data; - if (data) { - cmdr |= SDMMC_CMD_DAT_EXP; - if (data->flags & MMC_DATA_STREAM) - cmdr |= SDMMC_CMD_STRM_MODE; - if (data->flags & MMC_DATA_WRITE) - cmdr |= SDMMC_CMD_DAT_WR; - } - - return cmdr; -} - -static void dw_mci_start_command(struct dw_mci *host, - struct mmc_command *cmd, u32 cmd_flags) -{ - host->cmd = cmd; - dev_vdbg(&host->dev, - "start command: ARGR=0x%08x CMDR=0x%08x\n", - cmd->arg, cmd_flags); - - mci_writel(host, CMDARG, cmd->arg); - wmb(); - - mci_writel(host, CMD, cmd_flags | SDMMC_CMD_START); -} - -static void send_stop_cmd(struct dw_mci *host, struct mmc_data *data) -{ - dw_mci_start_command(host, data->stop, host->stop_cmdr); -} - -/* DMA interface functions */ -static void dw_mci_stop_dma(struct dw_mci *host) -{ - if (host->using_dma) { - host->dma_ops->stop(host); - host->dma_ops->cleanup(host); - } else { - /* Data transfer was stopped by the interrupt handler */ - set_bit(EVENT_XFER_COMPLETE, &host->pending_events); - } -} - -static int dw_mci_get_dma_dir(struct mmc_data *data) -{ - if (data->flags & MMC_DATA_WRITE) - return DMA_TO_DEVICE; - else - return DMA_FROM_DEVICE; -} - -#ifdef CONFIG_MMC_DW_IDMAC -static void dw_mci_dma_cleanup(struct dw_mci *host) -{ - struct mmc_data *data = host->data; - - if (data) - if (!data->host_cookie) - dma_unmap_sg(&host->dev, - data->sg, - data->sg_len, - dw_mci_get_dma_dir(data)); -} - -static void dw_mci_idmac_stop_dma(struct dw_mci *host) -{ - u32 temp; - - /* Disable and reset the IDMAC interface */ - temp = mci_readl(host, CTRL); - temp &= ~SDMMC_CTRL_USE_IDMAC; - temp |= SDMMC_CTRL_DMA_RESET; - mci_writel(host, CTRL, temp); - - /* Stop the IDMAC running */ - temp = mci_readl(host, BMOD); - temp &= ~(SDMMC_IDMAC_ENABLE | SDMMC_IDMAC_FB); - mci_writel(host, BMOD, temp); -} - -static void dw_mci_idmac_complete_dma(struct dw_mci *host) -{ - struct mmc_data *data = host->data; - - dev_vdbg(&host->dev, "DMA complete\n"); - - host->dma_ops->cleanup(host); - - /* - * If the card was removed, data will be NULL. No point in trying to - * send the stop command or waiting for NBUSY in this case. - */ - if (data) { - set_bit(EVENT_XFER_COMPLETE, &host->pending_events); - tasklet_schedule(&host->tasklet); - } -} - -static void dw_mci_translate_sglist(struct dw_mci *host, struct mmc_data *data, - unsigned int sg_len) -{ - int i; - struct idmac_desc *desc = host->sg_cpu; - - for (i = 0; i < sg_len; i++, desc++) { - unsigned int length = sg_dma_len(&data->sg[i]); - u32 mem_addr = sg_dma_address(&data->sg[i]); - - /* Set the OWN bit and disable interrupts for this descriptor */ - desc->des0 = IDMAC_DES0_OWN | IDMAC_DES0_DIC | IDMAC_DES0_CH; - - /* Buffer length */ - IDMAC_SET_BUFFER1_SIZE(desc, length); - - /* Physical address to DMA to/from */ - desc->des2 = mem_addr; - } - - /* Set first descriptor */ - desc = host->sg_cpu; - desc->des0 |= IDMAC_DES0_FD; - - /* Set last descriptor */ - desc = host->sg_cpu + (i - 1) * sizeof(struct idmac_desc); - desc->des0 &= ~(IDMAC_DES0_CH | IDMAC_DES0_DIC); - desc->des0 |= IDMAC_DES0_LD; - - wmb(); -} - -static void dw_mci_idmac_start_dma(struct dw_mci *host, unsigned int sg_len) -{ - u32 temp; - - dw_mci_translate_sglist(host, host->data, sg_len); - - /* Select IDMAC interface */ - temp = mci_readl(host, CTRL); - temp |= SDMMC_CTRL_USE_IDMAC; - mci_writel(host, CTRL, temp); - - wmb(); - - /* Enable the IDMAC */ - temp = mci_readl(host, BMOD); - temp |= SDMMC_IDMAC_ENABLE | SDMMC_IDMAC_FB; - mci_writel(host, BMOD, temp); - - /* Start it running */ - mci_writel(host, PLDMND, 1); -} - -static int dw_mci_idmac_init(struct dw_mci *host) -{ - struct idmac_desc *p; - int i; - - /* Number of descriptors in the ring buffer */ - host->ring_size = PAGE_SIZE / sizeof(struct idmac_desc); - - /* Forward link the descriptor list */ - for (i = 0, p = host->sg_cpu; i < host->ring_size - 1; i++, p++) - p->des3 = host->sg_dma + (sizeof(struct idmac_desc) * (i + 1)); - - /* Set the last descriptor as the end-of-ring descriptor */ - p->des3 = host->sg_dma; - p->des0 = IDMAC_DES0_ER; - - /* Mask out interrupts - get Tx & Rx complete only */ - mci_writel(host, IDINTEN, SDMMC_IDMAC_INT_NI | SDMMC_IDMAC_INT_RI | - SDMMC_IDMAC_INT_TI); - - /* Set the descriptor base address */ - mci_writel(host, DBADDR, host->sg_dma); - return 0; -} - -static struct dw_mci_dma_ops dw_mci_idmac_ops = { - .init = dw_mci_idmac_init, - .start = dw_mci_idmac_start_dma, - .stop = dw_mci_idmac_stop_dma, - .complete = dw_mci_idmac_complete_dma, - .cleanup = dw_mci_dma_cleanup, -}; -#endif /* CONFIG_MMC_DW_IDMAC */ - -static int dw_mci_pre_dma_transfer(struct dw_mci *host, - struct mmc_data *data, - bool next) -{ - struct scatterlist *sg; - unsigned int i, sg_len; - - if (!next && data->host_cookie) - return data->host_cookie; - - /* - * We don't do DMA on "complex" transfers, i.e. with - * non-word-aligned buffers or lengths. Also, we don't bother - * with all the DMA setup overhead for short transfers. - */ - if (data->blocks * data->blksz < DW_MCI_DMA_THRESHOLD) - return -EINVAL; - - if (data->blksz & 3) - return -EINVAL; - - for_each_sg(data->sg, sg, data->sg_len, i) { - if (sg->offset & 3 || sg->length & 3) - return -EINVAL; - } - - sg_len = dma_map_sg(&host->dev, - data->sg, - data->sg_len, - dw_mci_get_dma_dir(data)); - if (sg_len == 0) - return -EINVAL; - - if (next) - data->host_cookie = sg_len; - - return sg_len; -} - -static void dw_mci_pre_req(struct mmc_host *mmc, - struct mmc_request *mrq, - bool is_first_req) -{ - struct dw_mci_slot *slot = mmc_priv(mmc); - struct mmc_data *data = mrq->data; - - if (!slot->host->use_dma || !data) - return; - - if (data->host_cookie) { - data->host_cookie = 0; - return; - } - - if (dw_mci_pre_dma_transfer(slot->host, mrq->data, 1) < 0) - data->host_cookie = 0; -} - -static void dw_mci_post_req(struct mmc_host *mmc, - struct mmc_request *mrq, - int err) -{ - struct dw_mci_slot *slot = mmc_priv(mmc); - struct mmc_data *data = mrq->data; - - if (!slot->host->use_dma || !data) - return; - - if (data->host_cookie) - dma_unmap_sg(&slot->host->dev, - data->sg, - data->sg_len, - dw_mci_get_dma_dir(data)); - data->host_cookie = 0; -} - -static int dw_mci_submit_data_dma(struct dw_mci *host, struct mmc_data *data) -{ - int sg_len; - u32 temp; - - host->using_dma = 0; - - /* If we don't have a channel, we can't do DMA */ - if (!host->use_dma) - return -ENODEV; - - sg_len = dw_mci_pre_dma_transfer(host, data, 0); - if (sg_len < 0) { - host->dma_ops->stop(host); - return sg_len; - } - - host->using_dma = 1; - - dev_vdbg(&host->dev, - "sd sg_cpu: %#lx sg_dma: %#lx sg_len: %d\n", - (unsigned long)host->sg_cpu, (unsigned long)host->sg_dma, - sg_len); - - /* Enable the DMA interface */ - temp = mci_readl(host, CTRL); - temp |= SDMMC_CTRL_DMA_ENABLE; - mci_writel(host, CTRL, temp); - - /* Disable RX/TX IRQs, let DMA handle it */ - temp = mci_readl(host, INTMASK); - temp &= ~(SDMMC_INT_RXDR | SDMMC_INT_TXDR); - mci_writel(host, INTMASK, temp); - - host->dma_ops->start(host, sg_len); - - return 0; -} - -static void dw_mci_submit_data(struct dw_mci *host, struct mmc_data *data) -{ - u32 temp; - - data->error = -EINPROGRESS; - - WARN_ON(host->data); - host->sg = NULL; - host->data = data; - - if (data->flags & MMC_DATA_READ) - host->dir_status = DW_MCI_RECV_STATUS; - else - host->dir_status = DW_MCI_SEND_STATUS; - - if (dw_mci_submit_data_dma(host, data)) { - int flags = SG_MITER_ATOMIC; - if (host->data->flags & MMC_DATA_READ) - flags |= SG_MITER_TO_SG; - else - flags |= SG_MITER_FROM_SG; - - sg_miter_start(&host->sg_miter, data->sg, data->sg_len, flags); - host->sg = data->sg; - host->part_buf_start = 0; - host->part_buf_count = 0; - - mci_writel(host, RINTSTS, SDMMC_INT_TXDR | SDMMC_INT_RXDR); - temp = mci_readl(host, INTMASK); - temp |= SDMMC_INT_TXDR | SDMMC_INT_RXDR; - mci_writel(host, INTMASK, temp); - - temp = mci_readl(host, CTRL); - temp &= ~SDMMC_CTRL_DMA_ENABLE; - mci_writel(host, CTRL, temp); - } -} - -static void mci_send_cmd(struct dw_mci_slot *slot, u32 cmd, u32 arg) -{ - struct dw_mci *host = slot->host; - unsigned long timeout = jiffies + msecs_to_jiffies(500); - unsigned int cmd_status = 0; - - mci_writel(host, CMDARG, arg); - wmb(); - mci_writel(host, CMD, SDMMC_CMD_START | cmd); - - while (time_before(jiffies, timeout)) { - cmd_status = mci_readl(host, CMD); - if (!(cmd_status & SDMMC_CMD_START)) - return; - } - dev_err(&slot->mmc->class_dev, - "Timeout sending command (cmd %#x arg %#x status %#x)\n", - cmd, arg, cmd_status); -} - -static void dw_mci_setup_bus(struct dw_mci_slot *slot) -{ - struct dw_mci *host = slot->host; - u32 div; - - if (slot->clock != host->current_speed) { - if (host->bus_hz % slot->clock) - /* - * move the + 1 after the divide to prevent - * over-clocking the card. - */ - div = ((host->bus_hz / slot->clock) >> 1) + 1; - else - div = (host->bus_hz / slot->clock) >> 1; - - dev_info(&slot->mmc->class_dev, - "Bus speed (slot %d) = %dHz (slot req %dHz, actual %dHZ" - " div = %d)\n", slot->id, host->bus_hz, slot->clock, - div ? ((host->bus_hz / div) >> 1) : host->bus_hz, div); - - /* disable clock */ - mci_writel(host, CLKENA, 0); - mci_writel(host, CLKSRC, 0); - - /* inform CIU */ - mci_send_cmd(slot, - SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT, 0); - - /* set clock to desired speed */ - mci_writel(host, CLKDIV, div); - - /* inform CIU */ - mci_send_cmd(slot, - SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT, 0); - - /* enable clock */ - mci_writel(host, CLKENA, ((SDMMC_CLKEN_ENABLE | - SDMMC_CLKEN_LOW_PWR) << slot->id)); - - /* inform CIU */ - mci_send_cmd(slot, - SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT, 0); - - host->current_speed = slot->clock; - } - - /* Set the current slot bus width */ - mci_writel(host, CTYPE, (slot->ctype << slot->id)); -} - -static void __dw_mci_start_request(struct dw_mci *host, - struct dw_mci_slot *slot, - struct mmc_command *cmd) -{ - struct mmc_request *mrq; - struct mmc_data *data; - u32 cmdflags; - - mrq = slot->mrq; - if (host->pdata->select_slot) - host->pdata->select_slot(slot->id); - - /* Slot specific timing and width adjustment */ - dw_mci_setup_bus(slot); - - host->cur_slot = slot; - host->mrq = mrq; - - host->pending_events = 0; - host->completed_events = 0; - host->data_status = 0; - - data = cmd->data; - if (data) { - dw_mci_set_timeout(host); - mci_writel(host, BYTCNT, data->blksz*data->blocks); - mci_writel(host, BLKSIZ, data->blksz); - } - - cmdflags = dw_mci_prepare_command(slot->mmc, cmd); - - /* this is the first command, send the initialization clock */ - if (test_and_clear_bit(DW_MMC_CARD_NEED_INIT, &slot->flags)) - cmdflags |= SDMMC_CMD_INIT; - - if (data) { - dw_mci_submit_data(host, data); - wmb(); - } - - dw_mci_start_command(host, cmd, cmdflags); - - if (mrq->stop) - host->stop_cmdr = dw_mci_prepare_command(slot->mmc, mrq->stop); -} - -static void dw_mci_start_request(struct dw_mci *host, - struct dw_mci_slot *slot) -{ - struct mmc_request *mrq = slot->mrq; - struct mmc_command *cmd; - - cmd = mrq->sbc ? mrq->sbc : mrq->cmd; - __dw_mci_start_request(host, slot, cmd); -} - -/* must be called with host->lock held */ -static void dw_mci_queue_request(struct dw_mci *host, struct dw_mci_slot *slot, - struct mmc_request *mrq) -{ - dev_vdbg(&slot->mmc->class_dev, "queue request: state=%d\n", - host->state); - - slot->mrq = mrq; - - if (host->state == STATE_IDLE) { - host->state = STATE_SENDING_CMD; - dw_mci_start_request(host, slot); - } else { - list_add_tail(&slot->queue_node, &host->queue); - } -} - -static void dw_mci_request(struct mmc_host *mmc, struct mmc_request *mrq) -{ - struct dw_mci_slot *slot = mmc_priv(mmc); - struct dw_mci *host = slot->host; - - WARN_ON(slot->mrq); - - /* - * The check for card presence and queueing of the request must be - * atomic, otherwise the card could be removed in between and the - * request wouldn't fail until another card was inserted. - */ - spin_lock_bh(&host->lock); - - if (!test_bit(DW_MMC_CARD_PRESENT, &slot->flags)) { - spin_unlock_bh(&host->lock); - mrq->cmd->error = -ENOMEDIUM; - mmc_request_done(mmc, mrq); - return; - } - - dw_mci_queue_request(host, slot, mrq); - - spin_unlock_bh(&host->lock); -} - -static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) -{ - struct dw_mci_slot *slot = mmc_priv(mmc); - u32 regs; - - /* set default 1 bit mode */ - slot->ctype = SDMMC_CTYPE_1BIT; - - switch (ios->bus_width) { - case MMC_BUS_WIDTH_1: - slot->ctype = SDMMC_CTYPE_1BIT; - break; - case MMC_BUS_WIDTH_4: - slot->ctype = SDMMC_CTYPE_4BIT; - break; - case MMC_BUS_WIDTH_8: - slot->ctype = SDMMC_CTYPE_8BIT; - break; - } - - regs = mci_readl(slot->host, UHS_REG); - - /* DDR mode set */ - if (ios->timing == MMC_TIMING_UHS_DDR50) - regs |= (0x1 << slot->id) << 16; - else - regs &= ~(0x1 << slot->id) << 16; - - mci_writel(slot->host, UHS_REG, regs); - - if (ios->clock) { - /* - * Use mirror of ios->clock to prevent race with mmc - * core ios update when finding the minimum. - */ - slot->clock = ios->clock; - } - - switch (ios->power_mode) { - case MMC_POWER_UP: - set_bit(DW_MMC_CARD_NEED_INIT, &slot->flags); - break; - default: - break; - } -} - -static int dw_mci_get_ro(struct mmc_host *mmc) -{ - int read_only; - struct dw_mci_slot *slot = mmc_priv(mmc); - struct dw_mci_board *brd = slot->host->pdata; - - /* Use platform get_ro function, else try on board write protect */ - if (brd->get_ro) - read_only = brd->get_ro(slot->id); - else - read_only = - mci_readl(slot->host, WRTPRT) & (1 << slot->id) ? 1 : 0; - - dev_dbg(&mmc->class_dev, "card is %s\n", - read_only ? "read-only" : "read-write"); - - return read_only; -} - -static int dw_mci_get_cd(struct mmc_host *mmc) -{ - int present; - struct dw_mci_slot *slot = mmc_priv(mmc); - struct dw_mci_board *brd = slot->host->pdata; - - /* Use platform get_cd function, else try onboard card detect */ - if (brd->quirks & DW_MCI_QUIRK_BROKEN_CARD_DETECTION) - present = 1; - else if (brd->get_cd) - present = !brd->get_cd(slot->id); - else - present = (mci_readl(slot->host, CDETECT) & (1 << slot->id)) - == 0 ? 1 : 0; - - if (present) - dev_dbg(&mmc->class_dev, "card is present\n"); - else - dev_dbg(&mmc->class_dev, "card is not present\n"); - - return present; -} - -static void dw_mci_enable_sdio_irq(struct mmc_host *mmc, int enb) -{ - struct dw_mci_slot *slot = mmc_priv(mmc); - struct dw_mci *host = slot->host; - u32 int_mask; - - /* Enable/disable Slot Specific SDIO interrupt */ - int_mask = mci_readl(host, INTMASK); - if (enb) { - mci_writel(host, INTMASK, - (int_mask | (1 << SDMMC_INT_SDIO(slot->id)))); - } else { - mci_writel(host, INTMASK, - (int_mask & ~(1 << SDMMC_INT_SDIO(slot->id)))); - } -} - -static const struct mmc_host_ops dw_mci_ops = { - .request = dw_mci_request, - .pre_req = dw_mci_pre_req, - .post_req = dw_mci_post_req, - .set_ios = dw_mci_set_ios, - .get_ro = dw_mci_get_ro, - .get_cd = dw_mci_get_cd, - .enable_sdio_irq = dw_mci_enable_sdio_irq, -}; - -static void dw_mci_request_end(struct dw_mci *host, struct mmc_request *mrq) - __releases(&host->lock) - __acquires(&host->lock) -{ - struct dw_mci_slot *slot; - struct mmc_host *prev_mmc = host->cur_slot->mmc; - - WARN_ON(host->cmd || host->data); - - host->cur_slot->mrq = NULL; - host->mrq = NULL; - if (!list_empty(&host->queue)) { - slot = list_entry(host->queue.next, - struct dw_mci_slot, queue_node); - list_del(&slot->queue_node); - dev_vdbg(&host->dev, "list not empty: %s is next\n", - mmc_hostname(slot->mmc)); - host->state = STATE_SENDING_CMD; - dw_mci_start_request(host, slot); - } else { - dev_vdbg(&host->dev, "list empty\n"); - host->state = STATE_IDLE; - } - - spin_unlock(&host->lock); - mmc_request_done(prev_mmc, mrq); - spin_lock(&host->lock); -} - -static void dw_mci_command_complete(struct dw_mci *host, struct mmc_command *cmd) -{ - u32 status = host->cmd_status; - - host->cmd_status = 0; - - /* Read the response from the card (up to 16 bytes) */ - if (cmd->flags & MMC_RSP_PRESENT) { - if (cmd->flags & MMC_RSP_136) { - cmd->resp[3] = mci_readl(host, RESP0); - cmd->resp[2] = mci_readl(host, RESP1); - cmd->resp[1] = mci_readl(host, RESP2); - cmd->resp[0] = mci_readl(host, RESP3); - } else { - cmd->resp[0] = mci_readl(host, RESP0); - cmd->resp[1] = 0; - cmd->resp[2] = 0; - cmd->resp[3] = 0; - } - } - - if (status & SDMMC_INT_RTO) - cmd->error = -ETIMEDOUT; - else if ((cmd->flags & MMC_RSP_CRC) && (status & SDMMC_INT_RCRC)) - cmd->error = -EILSEQ; - else if (status & SDMMC_INT_RESP_ERR) - cmd->error = -EIO; - else - cmd->error = 0; - - if (cmd->error) { - /* newer ip versions need a delay between retries */ - if (host->quirks & DW_MCI_QUIRK_RETRY_DELAY) - mdelay(20); - - if (cmd->data) { - host->data = NULL; - dw_mci_stop_dma(host); - } - } -} - -static void dw_mci_tasklet_func(unsigned long priv) -{ - struct dw_mci *host = (struct dw_mci *)priv; - struct mmc_data *data; - struct mmc_command *cmd; - enum dw_mci_state state; - enum dw_mci_state prev_state; - u32 status, ctrl; - - spin_lock(&host->lock); - - state = host->state; - data = host->data; - - do { - prev_state = state; - - switch (state) { - case STATE_IDLE: - break; - - case STATE_SENDING_CMD: - if (!test_and_clear_bit(EVENT_CMD_COMPLETE, - &host->pending_events)) - break; - - cmd = host->cmd; - host->cmd = NULL; - set_bit(EVENT_CMD_COMPLETE, &host->completed_events); - dw_mci_command_complete(host, cmd); - if (cmd == host->mrq->sbc && !cmd->error) { - prev_state = state = STATE_SENDING_CMD; - __dw_mci_start_request(host, host->cur_slot, - host->mrq->cmd); - goto unlock; - } - - if (!host->mrq->data || cmd->error) { - dw_mci_request_end(host, host->mrq); - goto unlock; - } - - prev_state = state = STATE_SENDING_DATA; - /* fall through */ - - case STATE_SENDING_DATA: - if (test_and_clear_bit(EVENT_DATA_ERROR, - &host->pending_events)) { - dw_mci_stop_dma(host); - if (data->stop) - send_stop_cmd(host, data); - state = STATE_DATA_ERROR; - break; - } - - if (!test_and_clear_bit(EVENT_XFER_COMPLETE, - &host->pending_events)) - break; - - set_bit(EVENT_XFER_COMPLETE, &host->completed_events); - prev_state = state = STATE_DATA_BUSY; - /* fall through */ - - case STATE_DATA_BUSY: - if (!test_and_clear_bit(EVENT_DATA_COMPLETE, - &host->pending_events)) - break; - - host->data = NULL; - set_bit(EVENT_DATA_COMPLETE, &host->completed_events); - status = host->data_status; - - if (status & DW_MCI_DATA_ERROR_FLAGS) { - if (status & SDMMC_INT_DTO) { - data->error = -ETIMEDOUT; - } else if (status & SDMMC_INT_DCRC) { - data->error = -EILSEQ; - } else if (status & SDMMC_INT_EBE && - host->dir_status == - DW_MCI_SEND_STATUS) { - /* - * No data CRC status was returned. - * The number of bytes transferred will - * be exaggerated in PIO mode. - */ - data->bytes_xfered = 0; - data->error = -ETIMEDOUT; - } else { - dev_err(&host->dev, - "data FIFO error " - "(status=%08x)\n", - status); - data->error = -EIO; - } - /* - * After an error, there may be data lingering - * in the FIFO, so reset it - doing so - * generates a block interrupt, hence setting - * the scatter-gather pointer to NULL. - */ - sg_miter_stop(&host->sg_miter); - host->sg = NULL; - ctrl = mci_readl(host, CTRL); - ctrl |= SDMMC_CTRL_FIFO_RESET; - mci_writel(host, CTRL, ctrl); - } else { - data->bytes_xfered = data->blocks * data->blksz; - data->error = 0; - } - - if (!data->stop) { - dw_mci_request_end(host, host->mrq); - goto unlock; - } - - if (host->mrq->sbc && !data->error) { - data->stop->error = 0; - dw_mci_request_end(host, host->mrq); - goto unlock; - } - - prev_state = state = STATE_SENDING_STOP; - if (!data->error) - send_stop_cmd(host, data); - /* fall through */ - - case STATE_SENDING_STOP: - if (!test_and_clear_bit(EVENT_CMD_COMPLETE, - &host->pending_events)) - break; - - host->cmd = NULL; - dw_mci_command_complete(host, host->mrq->stop); - dw_mci_request_end(host, host->mrq); - goto unlock; - - case STATE_DATA_ERROR: - if (!test_and_clear_bit(EVENT_XFER_COMPLETE, - &host->pending_events)) - break; - - state = STATE_DATA_BUSY; - break; - } - } while (state != prev_state); - - host->state = state; -unlock: - spin_unlock(&host->lock); - -} - -/* push final bytes to part_buf, only use during push */ -static void dw_mci_set_part_bytes(struct dw_mci *host, void *buf, int cnt) -{ - memcpy((void *)&host->part_buf, buf, cnt); - host->part_buf_count = cnt; -} - -/* append bytes to part_buf, only use during push */ -static int dw_mci_push_part_bytes(struct dw_mci *host, void *buf, int cnt) -{ - cnt = min(cnt, (1 << host->data_shift) - host->part_buf_count); - memcpy((void *)&host->part_buf + host->part_buf_count, buf, cnt); - host->part_buf_count += cnt; - return cnt; -} - -/* pull first bytes from part_buf, only use during pull */ -static int dw_mci_pull_part_bytes(struct dw_mci *host, void *buf, int cnt) -{ - cnt = min(cnt, (int)host->part_buf_count); - if (cnt) { - memcpy(buf, (void *)&host->part_buf + host->part_buf_start, - cnt); - host->part_buf_count -= cnt; - host->part_buf_start += cnt; - } - return cnt; -} - -/* pull final bytes from the part_buf, assuming it's just been filled */ -static void dw_mci_pull_final_bytes(struct dw_mci *host, void *buf, int cnt) -{ - memcpy(buf, &host->part_buf, cnt); - host->part_buf_start = cnt; - host->part_buf_count = (1 << host->data_shift) - cnt; -} - -static void dw_mci_push_data16(struct dw_mci *host, void *buf, int cnt) -{ - /* try and push anything in the part_buf */ - if (unlikely(host->part_buf_count)) { - int len = dw_mci_push_part_bytes(host, buf, cnt); - buf += len; - cnt -= len; - if (!sg_next(host->sg) || host->part_buf_count == 2) { - mci_writew(host, DATA(host->data_offset), - host->part_buf16); - host->part_buf_count = 0; - } - } -#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS - if (unlikely((unsigned long)buf & 0x1)) { - while (cnt >= 2) { - u16 aligned_buf[64]; - int len = min(cnt & -2, (int)sizeof(aligned_buf)); - int items = len >> 1; - int i; - /* memcpy from input buffer into aligned buffer */ - memcpy(aligned_buf, buf, len); - buf += len; - cnt -= len; - /* push data from aligned buffer into fifo */ - for (i = 0; i < items; ++i) - mci_writew(host, DATA(host->data_offset), - aligned_buf[i]); - } - } else -#endif - { - u16 *pdata = buf; - for (; cnt >= 2; cnt -= 2) - mci_writew(host, DATA(host->data_offset), *pdata++); - buf = pdata; - } - /* put anything remaining in the part_buf */ - if (cnt) { - dw_mci_set_part_bytes(host, buf, cnt); - if (!sg_next(host->sg)) - mci_writew(host, DATA(host->data_offset), - host->part_buf16); - } -} - -static void dw_mci_pull_data16(struct dw_mci *host, void *buf, int cnt) -{ -#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS - if (unlikely((unsigned long)buf & 0x1)) { - while (cnt >= 2) { - /* pull data from fifo into aligned buffer */ - u16 aligned_buf[64]; - int len = min(cnt & -2, (int)sizeof(aligned_buf)); - int items = len >> 1; - int i; - for (i = 0; i < items; ++i) - aligned_buf[i] = mci_readw(host, - DATA(host->data_offset)); - /* memcpy from aligned buffer into output buffer */ - memcpy(buf, aligned_buf, len); - buf += len; - cnt -= len; - } - } else -#endif - { - u16 *pdata = buf; - for (; cnt >= 2; cnt -= 2) - *pdata++ = mci_readw(host, DATA(host->data_offset)); - buf = pdata; - } - if (cnt) { - host->part_buf16 = mci_readw(host, DATA(host->data_offset)); - dw_mci_pull_final_bytes(host, buf, cnt); - } -} - -static void dw_mci_push_data32(struct dw_mci *host, void *buf, int cnt) -{ - /* try and push anything in the part_buf */ - if (unlikely(host->part_buf_count)) { - int len = dw_mci_push_part_bytes(host, buf, cnt); - buf += len; - cnt -= len; - if (!sg_next(host->sg) || host->part_buf_count == 4) { - mci_writel(host, DATA(host->data_offset), - host->part_buf32); - host->part_buf_count = 0; - } - } -#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS - if (unlikely((unsigned long)buf & 0x3)) { - while (cnt >= 4) { - u32 aligned_buf[32]; - int len = min(cnt & -4, (int)sizeof(aligned_buf)); - int items = len >> 2; - int i; - /* memcpy from input buffer into aligned buffer */ - memcpy(aligned_buf, buf, len); - buf += len; - cnt -= len; - /* push data from aligned buffer into fifo */ - for (i = 0; i < items; ++i) - mci_writel(host, DATA(host->data_offset), - aligned_buf[i]); - } - } else -#endif - { - u32 *pdata = buf; - for (; cnt >= 4; cnt -= 4) - mci_writel(host, DATA(host->data_offset), *pdata++); - buf = pdata; - } - /* put anything remaining in the part_buf */ - if (cnt) { - dw_mci_set_part_bytes(host, buf, cnt); - if (!sg_next(host->sg)) - mci_writel(host, DATA(host->data_offset), - host->part_buf32); - } -} - -static void dw_mci_pull_data32(struct dw_mci *host, void *buf, int cnt) -{ -#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS - if (unlikely((unsigned long)buf & 0x3)) { - while (cnt >= 4) { - /* pull data from fifo into aligned buffer */ - u32 aligned_buf[32]; - int len = min(cnt & -4, (int)sizeof(aligned_buf)); - int items = len >> 2; - int i; - for (i = 0; i < items; ++i) - aligned_buf[i] = mci_readl(host, - DATA(host->data_offset)); - /* memcpy from aligned buffer into output buffer */ - memcpy(buf, aligned_buf, len); - buf += len; - cnt -= len; - } - } else -#endif - { - u32 *pdata = buf; - for (; cnt >= 4; cnt -= 4) - *pdata++ = mci_readl(host, DATA(host->data_offset)); - buf = pdata; - } - if (cnt) { - host->part_buf32 = mci_readl(host, DATA(host->data_offset)); - dw_mci_pull_final_bytes(host, buf, cnt); - } -} - -static void dw_mci_push_data64(struct dw_mci *host, void *buf, int cnt) -{ - /* try and push anything in the part_buf */ - if (unlikely(host->part_buf_count)) { - int len = dw_mci_push_part_bytes(host, buf, cnt); - buf += len; - cnt -= len; - if (!sg_next(host->sg) || host->part_buf_count == 8) { - mci_writew(host, DATA(host->data_offset), - host->part_buf); - host->part_buf_count = 0; - } - } -#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS - if (unlikely((unsigned long)buf & 0x7)) { - while (cnt >= 8) { - u64 aligned_buf[16]; - int len = min(cnt & -8, (int)sizeof(aligned_buf)); - int items = len >> 3; - int i; - /* memcpy from input buffer into aligned buffer */ - memcpy(aligned_buf, buf, len); - buf += len; - cnt -= len; - /* push data from aligned buffer into fifo */ - for (i = 0; i < items; ++i) - mci_writeq(host, DATA(host->data_offset), - aligned_buf[i]); - } - } else -#endif - { - u64 *pdata = buf; - for (; cnt >= 8; cnt -= 8) - mci_writeq(host, DATA(host->data_offset), *pdata++); - buf = pdata; - } - /* put anything remaining in the part_buf */ - if (cnt) { - dw_mci_set_part_bytes(host, buf, cnt); - if (!sg_next(host->sg)) - mci_writeq(host, DATA(host->data_offset), - host->part_buf); - } -} - -static void dw_mci_pull_data64(struct dw_mci *host, void *buf, int cnt) -{ -#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS - if (unlikely((unsigned long)buf & 0x7)) { - while (cnt >= 8) { - /* pull data from fifo into aligned buffer */ - u64 aligned_buf[16]; - int len = min(cnt & -8, (int)sizeof(aligned_buf)); - int items = len >> 3; - int i; - for (i = 0; i < items; ++i) - aligned_buf[i] = mci_readq(host, - DATA(host->data_offset)); - /* memcpy from aligned buffer into output buffer */ - memcpy(buf, aligned_buf, len); - buf += len; - cnt -= len; - } - } else -#endif - { - u64 *pdata = buf; - for (; cnt >= 8; cnt -= 8) - *pdata++ = mci_readq(host, DATA(host->data_offset)); - buf = pdata; - } - if (cnt) { - host->part_buf = mci_readq(host, DATA(host->data_offset)); - dw_mci_pull_final_bytes(host, buf, cnt); - } -} - -static void dw_mci_pull_data(struct dw_mci *host, void *buf, int cnt) -{ - int len; - - /* get remaining partial bytes */ - len = dw_mci_pull_part_bytes(host, buf, cnt); - if (unlikely(len == cnt)) - return; - buf += len; - cnt -= len; - - /* get the rest of the data */ - host->pull_data(host, buf, cnt); -} - -static void dw_mci_read_data_pio(struct dw_mci *host) -{ - struct sg_mapping_iter *sg_miter = &host->sg_miter; - void *buf; - unsigned int offset; - struct mmc_data *data = host->data; - int shift = host->data_shift; - u32 status; - unsigned int nbytes = 0, len; - unsigned int remain, fcnt; - - do { - if (!sg_miter_next(sg_miter)) - goto done; - - host->sg = sg_miter->__sg; - buf = sg_miter->addr; - remain = sg_miter->length; - offset = 0; - - do { - fcnt = (SDMMC_GET_FCNT(mci_readl(host, STATUS)) - << shift) + host->part_buf_count; - len = min(remain, fcnt); - if (!len) - break; - dw_mci_pull_data(host, (void *)(buf + offset), len); - offset += len; - nbytes += len; - remain -= len; - } while (remain); - sg_miter->consumed = offset; - - status = mci_readl(host, MINTSTS); - mci_writel(host, RINTSTS, SDMMC_INT_RXDR); - if (status & DW_MCI_DATA_ERROR_FLAGS) { - host->data_status = status; - data->bytes_xfered += nbytes; - sg_miter_stop(sg_miter); - host->sg = NULL; - smp_wmb(); - - set_bit(EVENT_DATA_ERROR, &host->pending_events); - - tasklet_schedule(&host->tasklet); - return; - } - } while (status & SDMMC_INT_RXDR); /*if the RXDR is ready read again*/ - data->bytes_xfered += nbytes; - - if (!remain) { - if (!sg_miter_next(sg_miter)) - goto done; - sg_miter->consumed = 0; - } - sg_miter_stop(sg_miter); - return; - -done: - data->bytes_xfered += nbytes; - sg_miter_stop(sg_miter); - host->sg = NULL; - smp_wmb(); - set_bit(EVENT_XFER_COMPLETE, &host->pending_events); -} - -static void dw_mci_write_data_pio(struct dw_mci *host) -{ - struct sg_mapping_iter *sg_miter = &host->sg_miter; - void *buf; - unsigned int offset; - struct mmc_data *data = host->data; - int shift = host->data_shift; - u32 status; - unsigned int nbytes = 0, len; - unsigned int fifo_depth = host->fifo_depth; - unsigned int remain, fcnt; - - do { - if (!sg_miter_next(sg_miter)) - goto done; - - host->sg = sg_miter->__sg; - buf = sg_miter->addr; - remain = sg_miter->length; - offset = 0; - - do { - fcnt = ((fifo_depth - - SDMMC_GET_FCNT(mci_readl(host, STATUS))) - << shift) - host->part_buf_count; - len = min(remain, fcnt); - if (!len) - break; - host->push_data(host, (void *)(buf + offset), len); - offset += len; - nbytes += len; - remain -= len; - } while (remain); - sg_miter->consumed = offset; - - status = mci_readl(host, MINTSTS); - mci_writel(host, RINTSTS, SDMMC_INT_TXDR); - if (status & DW_MCI_DATA_ERROR_FLAGS) { - host->data_status = status; - data->bytes_xfered += nbytes; - sg_miter_stop(sg_miter); - host->sg = NULL; - - smp_wmb(); - - set_bit(EVENT_DATA_ERROR, &host->pending_events); - - tasklet_schedule(&host->tasklet); - return; - } - } while (status & SDMMC_INT_TXDR); /* if TXDR write again */ - data->bytes_xfered += nbytes; - - if (!remain) { - if (!sg_miter_next(sg_miter)) - goto done; - sg_miter->consumed = 0; - } - sg_miter_stop(sg_miter); - return; - -done: - data->bytes_xfered += nbytes; - sg_miter_stop(sg_miter); - host->sg = NULL; - smp_wmb(); - set_bit(EVENT_XFER_COMPLETE, &host->pending_events); -} - -static void dw_mci_cmd_interrupt(struct dw_mci *host, u32 status) -{ - if (!host->cmd_status) - host->cmd_status = status; - - smp_wmb(); - - set_bit(EVENT_CMD_COMPLETE, &host->pending_events); - tasklet_schedule(&host->tasklet); -} - -static irqreturn_t dw_mci_interrupt(int irq, void *dev_id) -{ - struct dw_mci *host = dev_id; - u32 status, pending; - unsigned int pass_count = 0; - int i; - - do { - status = mci_readl(host, RINTSTS); - pending = mci_readl(host, MINTSTS); /* read-only mask reg */ - - /* - * DTO fix - version 2.10a and below, and only if internal DMA - * is configured. - */ - if (host->quirks & DW_MCI_QUIRK_IDMAC_DTO) { - if (!pending && - ((mci_readl(host, STATUS) >> 17) & 0x1fff)) - pending |= SDMMC_INT_DATA_OVER; - } - - if (!pending) - break; - - if (pending & DW_MCI_CMD_ERROR_FLAGS) { - mci_writel(host, RINTSTS, DW_MCI_CMD_ERROR_FLAGS); - host->cmd_status = status; - smp_wmb(); - set_bit(EVENT_CMD_COMPLETE, &host->pending_events); - } - - if (pending & DW_MCI_DATA_ERROR_FLAGS) { - /* if there is an error report DATA_ERROR */ - mci_writel(host, RINTSTS, DW_MCI_DATA_ERROR_FLAGS); - host->data_status = status; - smp_wmb(); - set_bit(EVENT_DATA_ERROR, &host->pending_events); - if (!(pending & (SDMMC_INT_DTO | SDMMC_INT_DCRC | - SDMMC_INT_SBE | SDMMC_INT_EBE))) - tasklet_schedule(&host->tasklet); - } - - if (pending & SDMMC_INT_DATA_OVER) { - mci_writel(host, RINTSTS, SDMMC_INT_DATA_OVER); - if (!host->data_status) - host->data_status = status; - smp_wmb(); - if (host->dir_status == DW_MCI_RECV_STATUS) { - if (host->sg != NULL) - dw_mci_read_data_pio(host); - } - set_bit(EVENT_DATA_COMPLETE, &host->pending_events); - tasklet_schedule(&host->tasklet); - } - - if (pending & SDMMC_INT_RXDR) { - mci_writel(host, RINTSTS, SDMMC_INT_RXDR); - if (host->dir_status == DW_MCI_RECV_STATUS && host->sg) - dw_mci_read_data_pio(host); - } - - if (pending & SDMMC_INT_TXDR) { - mci_writel(host, RINTSTS, SDMMC_INT_TXDR); - if (host->dir_status == DW_MCI_SEND_STATUS && host->sg) - dw_mci_write_data_pio(host); - } - - if (pending & SDMMC_INT_CMD_DONE) { - mci_writel(host, RINTSTS, SDMMC_INT_CMD_DONE); - dw_mci_cmd_interrupt(host, status); - } - - if (pending & SDMMC_INT_CD) { - mci_writel(host, RINTSTS, SDMMC_INT_CD); - queue_work(dw_mci_card_workqueue, &host->card_work); - } - - /* Handle SDIO Interrupts */ - for (i = 0; i < host->num_slots; i++) { - struct dw_mci_slot *slot = host->slot[i]; - if (pending & SDMMC_INT_SDIO(i)) { - mci_writel(host, RINTSTS, SDMMC_INT_SDIO(i)); - mmc_signal_sdio_irq(slot->mmc); - } - } - - } while (pass_count++ < 5); - -#ifdef CONFIG_MMC_DW_IDMAC - /* Handle DMA interrupts */ - pending = mci_readl(host, IDSTS); - if (pending & (SDMMC_IDMAC_INT_TI | SDMMC_IDMAC_INT_RI)) { - mci_writel(host, IDSTS, SDMMC_IDMAC_INT_TI | SDMMC_IDMAC_INT_RI); - mci_writel(host, IDSTS, SDMMC_IDMAC_INT_NI); - set_bit(EVENT_DATA_COMPLETE, &host->pending_events); - host->dma_ops->complete(host); - } -#endif - - return IRQ_HANDLED; -} - -static void dw_mci_work_routine_card(struct work_struct *work) -{ - struct dw_mci *host = container_of(work, struct dw_mci, card_work); - int i; - - for (i = 0; i < host->num_slots; i++) { - struct dw_mci_slot *slot = host->slot[i]; - struct mmc_host *mmc = slot->mmc; - struct mmc_request *mrq; - int present; - u32 ctrl; - - present = dw_mci_get_cd(mmc); - while (present != slot->last_detect_state) { - dev_dbg(&slot->mmc->class_dev, "card %s\n", - present ? "inserted" : "removed"); - - /* Power up slot (before spin_lock, may sleep) */ - if (present != 0 && host->pdata->setpower) - host->pdata->setpower(slot->id, mmc->ocr_avail); - - spin_lock_bh(&host->lock); - - /* Card change detected */ - slot->last_detect_state = present; - - /* Mark card as present if applicable */ - if (present != 0) - set_bit(DW_MMC_CARD_PRESENT, &slot->flags); - - /* Clean up queue if present */ - mrq = slot->mrq; - if (mrq) { - if (mrq == host->mrq) { - host->data = NULL; - host->cmd = NULL; - - switch (host->state) { - case STATE_IDLE: - break; - case STATE_SENDING_CMD: - mrq->cmd->error = -ENOMEDIUM; - if (!mrq->data) - break; - /* fall through */ - case STATE_SENDING_DATA: - mrq->data->error = -ENOMEDIUM; - dw_mci_stop_dma(host); - break; - case STATE_DATA_BUSY: - case STATE_DATA_ERROR: - if (mrq->data->error == -EINPROGRESS) - mrq->data->error = -ENOMEDIUM; - if (!mrq->stop) - break; - /* fall through */ - case STATE_SENDING_STOP: - mrq->stop->error = -ENOMEDIUM; - break; - } - - dw_mci_request_end(host, mrq); - } else { - list_del(&slot->queue_node); - mrq->cmd->error = -ENOMEDIUM; - if (mrq->data) - mrq->data->error = -ENOMEDIUM; - if (mrq->stop) - mrq->stop->error = -ENOMEDIUM; - - spin_unlock(&host->lock); - mmc_request_done(slot->mmc, mrq); - spin_lock(&host->lock); - } - } - - /* Power down slot */ - if (present == 0) { - clear_bit(DW_MMC_CARD_PRESENT, &slot->flags); - - /* - * Clear down the FIFO - doing so generates a - * block interrupt, hence setting the - * scatter-gather pointer to NULL. - */ - sg_miter_stop(&host->sg_miter); - host->sg = NULL; - - ctrl = mci_readl(host, CTRL); - ctrl |= SDMMC_CTRL_FIFO_RESET; - mci_writel(host, CTRL, ctrl); - -#ifdef CONFIG_MMC_DW_IDMAC - ctrl = mci_readl(host, BMOD); - ctrl |= 0x01; /* Software reset of DMA */ - mci_writel(host, BMOD, ctrl); -#endif - - } - - spin_unlock_bh(&host->lock); - - /* Power down slot (after spin_unlock, may sleep) */ - if (present == 0 && host->pdata->setpower) - host->pdata->setpower(slot->id, 0); - - present = dw_mci_get_cd(mmc); - } - - mmc_detect_change(slot->mmc, - msecs_to_jiffies(host->pdata->detect_delay_ms)); - } -} - -static int __init dw_mci_init_slot(struct dw_mci *host, unsigned int id) -{ - struct mmc_host *mmc; - struct dw_mci_slot *slot; - - mmc = mmc_alloc_host(sizeof(struct dw_mci_slot), &host->dev); - if (!mmc) - return -ENOMEM; - - slot = mmc_priv(mmc); - slot->id = id; - slot->mmc = mmc; - slot->host = host; - - mmc->ops = &dw_mci_ops; - mmc->f_min = DIV_ROUND_UP(host->bus_hz, 510); - mmc->f_max = host->bus_hz; - - if (host->pdata->get_ocr) - mmc->ocr_avail = host->pdata->get_ocr(id); - else - mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; - - /* - * Start with slot power disabled, it will be enabled when a card - * is detected. - */ - if (host->pdata->setpower) - host->pdata->setpower(id, 0); - - if (host->pdata->caps) - mmc->caps = host->pdata->caps; - - if (host->pdata->caps2) - mmc->caps2 = host->pdata->caps2; - - if (host->pdata->get_bus_wd) - if (host->pdata->get_bus_wd(slot->id) >= 4) - mmc->caps |= MMC_CAP_4_BIT_DATA; - - if (host->pdata->quirks & DW_MCI_QUIRK_HIGHSPEED) - mmc->caps |= MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED; - - if (mmc->caps2 & MMC_CAP2_POWEROFF_NOTIFY) - mmc->power_notify_type = MMC_HOST_PW_NOTIFY_SHORT; - else - mmc->power_notify_type = MMC_HOST_PW_NOTIFY_NONE; - - if (host->pdata->blk_settings) { - mmc->max_segs = host->pdata->blk_settings->max_segs; - mmc->max_blk_size = host->pdata->blk_settings->max_blk_size; - mmc->max_blk_count = host->pdata->blk_settings->max_blk_count; - mmc->max_req_size = host->pdata->blk_settings->max_req_size; - mmc->max_seg_size = host->pdata->blk_settings->max_seg_size; - } else { - /* Useful defaults if platform data is unset. */ -#ifdef CONFIG_MMC_DW_IDMAC - mmc->max_segs = host->ring_size; - mmc->max_blk_size = 65536; - mmc->max_blk_count = host->ring_size; - mmc->max_seg_size = 0x1000; - mmc->max_req_size = mmc->max_seg_size * mmc->max_blk_count; -#else - mmc->max_segs = 64; - mmc->max_blk_size = 65536; /* BLKSIZ is 16 bits */ - mmc->max_blk_count = 512; - mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count; - mmc->max_seg_size = mmc->max_req_size; -#endif /* CONFIG_MMC_DW_IDMAC */ - } - - host->vmmc = regulator_get(mmc_dev(mmc), "vmmc"); - if (IS_ERR(host->vmmc)) { - pr_info("%s: no vmmc regulator found\n", mmc_hostname(mmc)); - host->vmmc = NULL; - } else - regulator_enable(host->vmmc); - - if (dw_mci_get_cd(mmc)) - set_bit(DW_MMC_CARD_PRESENT, &slot->flags); - else - clear_bit(DW_MMC_CARD_PRESENT, &slot->flags); - - host->slot[id] = slot; - mmc_add_host(mmc); - -#if defined(CONFIG_DEBUG_FS) - dw_mci_init_debugfs(slot); -#endif - - /* Card initially undetected */ - slot->last_detect_state = 0; - - /* - * Card may have been plugged in prior to boot so we - * need to run the detect tasklet - */ - queue_work(dw_mci_card_workqueue, &host->card_work); - - return 0; -} - -static void dw_mci_cleanup_slot(struct dw_mci_slot *slot, unsigned int id) -{ - /* Shutdown detect IRQ */ - if (slot->host->pdata->exit) - slot->host->pdata->exit(id); - - /* Debugfs stuff is cleaned up by mmc core */ - mmc_remove_host(slot->mmc); - slot->host->slot[id] = NULL; - mmc_free_host(slot->mmc); -} - -static void dw_mci_init_dma(struct dw_mci *host) -{ - /* Alloc memory for sg translation */ - host->sg_cpu = dma_alloc_coherent(&host->dev, PAGE_SIZE, - &host->sg_dma, GFP_KERNEL); - if (!host->sg_cpu) { - dev_err(&host->dev, "%s: could not alloc DMA memory\n", - __func__); - goto no_dma; - } - - /* Determine which DMA interface to use */ -#ifdef CONFIG_MMC_DW_IDMAC - host->dma_ops = &dw_mci_idmac_ops; - dev_info(&host->dev, "Using internal DMA controller.\n"); -#endif - - if (!host->dma_ops) - goto no_dma; - - if (host->dma_ops->init && host->dma_ops->start && - host->dma_ops->stop && host->dma_ops->cleanup) { - if (host->dma_ops->init(host)) { - dev_err(&host->dev, "%s: Unable to initialize " - "DMA Controller.\n", __func__); - goto no_dma; - } - } else { - dev_err(&host->dev, "DMA initialization not found.\n"); - goto no_dma; - } - - host->use_dma = 1; - return; - -no_dma: - dev_info(&host->dev, "Using PIO mode.\n"); - host->use_dma = 0; - return; -} - -static bool mci_wait_reset(struct device *dev, struct dw_mci *host) -{ - unsigned long timeout = jiffies + msecs_to_jiffies(500); - unsigned int ctrl; - - mci_writel(host, CTRL, (SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET | - SDMMC_CTRL_DMA_RESET)); - - /* wait till resets clear */ - do { - ctrl = mci_readl(host, CTRL); - if (!(ctrl & (SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET | - SDMMC_CTRL_DMA_RESET))) - return true; - } while (time_before(jiffies, timeout)); - - dev_err(dev, "Timeout resetting block (ctrl %#x)\n", ctrl); - - return false; -} - -int dw_mci_probe(struct dw_mci *host) -{ - int width, i, ret = 0; - u32 fifo_size; - - if (!host->pdata || !host->pdata->init) { - dev_err(&host->dev, - "Platform data must supply init function\n"); - return -ENODEV; - } - - if (!host->pdata->select_slot && host->pdata->num_slots > 1) { - dev_err(&host->dev, - "Platform data must supply select_slot function\n"); - return -ENODEV; - } - - if (!host->pdata->bus_hz) { - dev_err(&host->dev, - "Platform data must supply bus speed\n"); - return -ENODEV; - } - - host->bus_hz = host->pdata->bus_hz; - host->quirks = host->pdata->quirks; - - spin_lock_init(&host->lock); - INIT_LIST_HEAD(&host->queue); - - - host->dma_ops = host->pdata->dma_ops; - dw_mci_init_dma(host); - - /* - * Get the host data width - this assumes that HCON has been set with - * the correct values. - */ - i = (mci_readl(host, HCON) >> 7) & 0x7; - if (!i) { - host->push_data = dw_mci_push_data16; - host->pull_data = dw_mci_pull_data16; - width = 16; - host->data_shift = 1; - } else if (i == 2) { - host->push_data = dw_mci_push_data64; - host->pull_data = dw_mci_pull_data64; - width = 64; - host->data_shift = 3; - } else { - /* Check for a reserved value, and warn if it is */ - WARN((i != 1), - "HCON reports a reserved host data width!\n" - "Defaulting to 32-bit access.\n"); - host->push_data = dw_mci_push_data32; - host->pull_data = dw_mci_pull_data32; - width = 32; - host->data_shift = 2; - } - - /* Reset all blocks */ - if (!mci_wait_reset(&host->dev, host)) { - ret = -ENODEV; - goto err_dmaunmap; - } - - /* Clear the interrupts for the host controller */ - mci_writel(host, RINTSTS, 0xFFFFFFFF); - mci_writel(host, INTMASK, 0); /* disable all mmc interrupt first */ - - /* Put in max timeout */ - mci_writel(host, TMOUT, 0xFFFFFFFF); - - /* - * FIFO threshold settings RxMark = fifo_size / 2 - 1, - * Tx Mark = fifo_size / 2 DMA Size = 8 - */ - if (!host->pdata->fifo_depth) { - /* - * Power-on value of RX_WMark is FIFO_DEPTH-1, but this may - * have been overwritten by the bootloader, just like we're - * about to do, so if you know the value for your hardware, you - * should put it in the platform data. - */ - fifo_size = mci_readl(host, FIFOTH); - fifo_size = 1 + ((fifo_size >> 16) & 0xfff); - } else { - fifo_size = host->pdata->fifo_depth; - } - host->fifo_depth = fifo_size; - host->fifoth_val = ((0x2 << 28) | ((fifo_size/2 - 1) << 16) | - ((fifo_size/2) << 0)); - mci_writel(host, FIFOTH, host->fifoth_val); - - /* disable clock to CIU */ - mci_writel(host, CLKENA, 0); - mci_writel(host, CLKSRC, 0); - - tasklet_init(&host->tasklet, dw_mci_tasklet_func, (unsigned long)host); - dw_mci_card_workqueue = alloc_workqueue("dw-mci-card", - WQ_MEM_RECLAIM | WQ_NON_REENTRANT, 1); - if (!dw_mci_card_workqueue) - goto err_dmaunmap; - INIT_WORK(&host->card_work, dw_mci_work_routine_card); - ret = request_irq(host->irq, dw_mci_interrupt, host->irq_flags, "dw-mci", host); - if (ret) - goto err_workqueue; - - if (host->pdata->num_slots) - host->num_slots = host->pdata->num_slots; - else - host->num_slots = ((mci_readl(host, HCON) >> 1) & 0x1F) + 1; - - /* We need at least one slot to succeed */ - for (i = 0; i < host->num_slots; i++) { - ret = dw_mci_init_slot(host, i); - if (ret) { - ret = -ENODEV; - goto err_init_slot; - } - } - - /* - * In 2.40a spec, Data offset is changed. - * Need to check the version-id and set data-offset for DATA register. - */ - host->verid = SDMMC_GET_VERID(mci_readl(host, VERID)); - dev_info(&host->dev, "Version ID is %04x\n", host->verid); - - if (host->verid < DW_MMC_240A) - host->data_offset = DATA_OFFSET; - else - host->data_offset = DATA_240A_OFFSET; - - /* - * Enable interrupts for command done, data over, data empty, card det, - * receive ready and error such as transmit, receive timeout, crc error - */ - mci_writel(host, RINTSTS, 0xFFFFFFFF); - mci_writel(host, INTMASK, SDMMC_INT_CMD_DONE | SDMMC_INT_DATA_OVER | - SDMMC_INT_TXDR | SDMMC_INT_RXDR | - DW_MCI_ERROR_FLAGS | SDMMC_INT_CD); - mci_writel(host, CTRL, SDMMC_CTRL_INT_ENABLE); /* Enable mci interrupt */ - - dev_info(&host->dev, "DW MMC controller at irq %d, " - "%d bit host data width, " - "%u deep fifo\n", - host->irq, width, fifo_size); - if (host->quirks & DW_MCI_QUIRK_IDMAC_DTO) - dev_info(&host->dev, "Internal DMAC interrupt fix enabled.\n"); - - return 0; - -err_init_slot: - /* De-init any initialized slots */ - while (i > 0) { - if (host->slot[i]) - dw_mci_cleanup_slot(host->slot[i], i); - i--; - } - free_irq(host->irq, host); - -err_workqueue: - destroy_workqueue(dw_mci_card_workqueue); - -err_dmaunmap: - if (host->use_dma && host->dma_ops->exit) - host->dma_ops->exit(host); - dma_free_coherent(&host->dev, PAGE_SIZE, - host->sg_cpu, host->sg_dma); - - if (host->vmmc) { - regulator_disable(host->vmmc); - regulator_put(host->vmmc); - } - return ret; -} -EXPORT_SYMBOL(dw_mci_probe); - -void dw_mci_remove(struct dw_mci *host) -{ - int i; - - mci_writel(host, RINTSTS, 0xFFFFFFFF); - mci_writel(host, INTMASK, 0); /* disable all mmc interrupt first */ - - for (i = 0; i < host->num_slots; i++) { - dev_dbg(&host->dev, "remove slot %d\n", i); - if (host->slot[i]) - dw_mci_cleanup_slot(host->slot[i], i); - } - - /* disable clock to CIU */ - mci_writel(host, CLKENA, 0); - mci_writel(host, CLKSRC, 0); - - free_irq(host->irq, host); - destroy_workqueue(dw_mci_card_workqueue); - dma_free_coherent(&host->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma); - - if (host->use_dma && host->dma_ops->exit) - host->dma_ops->exit(host); - - if (host->vmmc) { - regulator_disable(host->vmmc); - regulator_put(host->vmmc); - } - -} -EXPORT_SYMBOL(dw_mci_remove); - - - -#ifdef CONFIG_PM_SLEEP -/* - * TODO: we should probably disable the clock to the card in the suspend path. - */ -int dw_mci_suspend(struct dw_mci *host) -{ - int i, ret = 0; - - for (i = 0; i < host->num_slots; i++) { - struct dw_mci_slot *slot = host->slot[i]; - if (!slot) - continue; - ret = mmc_suspend_host(slot->mmc); - if (ret < 0) { - while (--i >= 0) { - slot = host->slot[i]; - if (slot) - mmc_resume_host(host->slot[i]->mmc); - } - return ret; - } - } - - if (host->vmmc) - regulator_disable(host->vmmc); - - return 0; -} -EXPORT_SYMBOL(dw_mci_suspend); - -int dw_mci_resume(struct dw_mci *host) -{ - int i, ret; - - if (host->vmmc) - regulator_enable(host->vmmc); - - if (host->dma_ops->init) - host->dma_ops->init(host); - - if (!mci_wait_reset(&host->dev, host)) { - ret = -ENODEV; - return ret; - } - - /* Restore the old value at FIFOTH register */ - mci_writel(host, FIFOTH, host->fifoth_val); - - mci_writel(host, RINTSTS, 0xFFFFFFFF); - mci_writel(host, INTMASK, SDMMC_INT_CMD_DONE | SDMMC_INT_DATA_OVER | - SDMMC_INT_TXDR | SDMMC_INT_RXDR | - DW_MCI_ERROR_FLAGS | SDMMC_INT_CD); - mci_writel(host, CTRL, SDMMC_CTRL_INT_ENABLE); - - for (i = 0; i < host->num_slots; i++) { - struct dw_mci_slot *slot = host->slot[i]; - if (!slot) - continue; - ret = mmc_resume_host(host->slot[i]->mmc); - if (ret < 0) - return ret; - } - return 0; -} -EXPORT_SYMBOL(dw_mci_resume); -#endif /* CONFIG_PM_SLEEP */ - -static int __init dw_mci_init(void) -{ - printk(KERN_INFO "Synopsys Designware Multimedia Card Interface Driver"); - return 0; -} - -static void __exit dw_mci_exit(void) -{ -} - -module_init(dw_mci_init); -module_exit(dw_mci_exit); - -MODULE_DESCRIPTION("DW Multimedia Card Interface driver"); -MODULE_AUTHOR("NXP Semiconductor VietNam"); -MODULE_AUTHOR("Imagination Technologies Ltd"); -MODULE_LICENSE("GPL v2"); diff --git a/ANDROID_3.4.5/drivers/mmc/host/dw_mmc.h b/ANDROID_3.4.5/drivers/mmc/host/dw_mmc.h deleted file mode 100644 index 15c27e17..00000000 --- a/ANDROID_3.4.5/drivers/mmc/host/dw_mmc.h +++ /dev/null @@ -1,185 +0,0 @@ -/* - * Synopsys DesignWare Multimedia Card Interface driver - * (Based on NXP driver for lpc 31xx) - * - * Copyright (C) 2009 NXP Semiconductors - * Copyright (C) 2009, 2010 Imagination Technologies Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - -#ifndef _DW_MMC_H_ -#define _DW_MMC_H_ - -#define DW_MMC_240A 0x240a - -#define SDMMC_CTRL 0x000 -#define SDMMC_PWREN 0x004 -#define SDMMC_CLKDIV 0x008 -#define SDMMC_CLKSRC 0x00c -#define SDMMC_CLKENA 0x010 -#define SDMMC_TMOUT 0x014 -#define SDMMC_CTYPE 0x018 -#define SDMMC_BLKSIZ 0x01c -#define SDMMC_BYTCNT 0x020 -#define SDMMC_INTMASK 0x024 -#define SDMMC_CMDARG 0x028 -#define SDMMC_CMD 0x02c -#define SDMMC_RESP0 0x030 -#define SDMMC_RESP1 0x034 -#define SDMMC_RESP2 0x038 -#define SDMMC_RESP3 0x03c -#define SDMMC_MINTSTS 0x040 -#define SDMMC_RINTSTS 0x044 -#define SDMMC_STATUS 0x048 -#define SDMMC_FIFOTH 0x04c -#define SDMMC_CDETECT 0x050 -#define SDMMC_WRTPRT 0x054 -#define SDMMC_GPIO 0x058 -#define SDMMC_TCBCNT 0x05c -#define SDMMC_TBBCNT 0x060 -#define SDMMC_DEBNCE 0x064 -#define SDMMC_USRID 0x068 -#define SDMMC_VERID 0x06c -#define SDMMC_HCON 0x070 -#define SDMMC_UHS_REG 0x074 -#define SDMMC_BMOD 0x080 -#define SDMMC_PLDMND 0x084 -#define SDMMC_DBADDR 0x088 -#define SDMMC_IDSTS 0x08c -#define SDMMC_IDINTEN 0x090 -#define SDMMC_DSCADDR 0x094 -#define SDMMC_BUFADDR 0x098 -#define SDMMC_DATA(x) (x) - -/* - * Data offset is difference according to Version - * Lower than 2.40a : data register offest is 0x100 - */ -#define DATA_OFFSET 0x100 -#define DATA_240A_OFFSET 0x200 - -/* shift bit field */ -#define _SBF(f, v) ((v) << (f)) - -/* Control register defines */ -#define SDMMC_CTRL_USE_IDMAC BIT(25) -#define SDMMC_CTRL_CEATA_INT_EN BIT(11) -#define SDMMC_CTRL_SEND_AS_CCSD BIT(10) -#define SDMMC_CTRL_SEND_CCSD BIT(9) -#define SDMMC_CTRL_ABRT_READ_DATA BIT(8) -#define SDMMC_CTRL_SEND_IRQ_RESP BIT(7) -#define SDMMC_CTRL_READ_WAIT BIT(6) -#define SDMMC_CTRL_DMA_ENABLE BIT(5) -#define SDMMC_CTRL_INT_ENABLE BIT(4) -#define SDMMC_CTRL_DMA_RESET BIT(2) -#define SDMMC_CTRL_FIFO_RESET BIT(1) -#define SDMMC_CTRL_RESET BIT(0) -/* Clock Enable register defines */ -#define SDMMC_CLKEN_LOW_PWR BIT(16) -#define SDMMC_CLKEN_ENABLE BIT(0) -/* time-out register defines */ -#define SDMMC_TMOUT_DATA(n) _SBF(8, (n)) -#define SDMMC_TMOUT_DATA_MSK 0xFFFFFF00 -#define SDMMC_TMOUT_RESP(n) ((n) & 0xFF) -#define SDMMC_TMOUT_RESP_MSK 0xFF -/* card-type register defines */ -#define SDMMC_CTYPE_8BIT BIT(16) -#define SDMMC_CTYPE_4BIT BIT(0) -#define SDMMC_CTYPE_1BIT 0 -/* Interrupt status & mask register defines */ -#define SDMMC_INT_SDIO(n) BIT(16 + (n)) -#define SDMMC_INT_EBE BIT(15) -#define SDMMC_INT_ACD BIT(14) -#define SDMMC_INT_SBE BIT(13) -#define SDMMC_INT_HLE BIT(12) -#define SDMMC_INT_FRUN BIT(11) -#define SDMMC_INT_HTO BIT(10) -#define SDMMC_INT_DTO BIT(9) -#define SDMMC_INT_RTO BIT(8) -#define SDMMC_INT_DCRC BIT(7) -#define SDMMC_INT_RCRC BIT(6) -#define SDMMC_INT_RXDR BIT(5) -#define SDMMC_INT_TXDR BIT(4) -#define SDMMC_INT_DATA_OVER BIT(3) -#define SDMMC_INT_CMD_DONE BIT(2) -#define SDMMC_INT_RESP_ERR BIT(1) -#define SDMMC_INT_CD BIT(0) -#define SDMMC_INT_ERROR 0xbfc2 -/* Command register defines */ -#define SDMMC_CMD_START BIT(31) -#define SDMMC_CMD_CCS_EXP BIT(23) -#define SDMMC_CMD_CEATA_RD BIT(22) -#define SDMMC_CMD_UPD_CLK BIT(21) -#define SDMMC_CMD_INIT BIT(15) -#define SDMMC_CMD_STOP BIT(14) -#define SDMMC_CMD_PRV_DAT_WAIT BIT(13) -#define SDMMC_CMD_SEND_STOP BIT(12) -#define SDMMC_CMD_STRM_MODE BIT(11) -#define SDMMC_CMD_DAT_WR BIT(10) -#define SDMMC_CMD_DAT_EXP BIT(9) -#define SDMMC_CMD_RESP_CRC BIT(8) -#define SDMMC_CMD_RESP_LONG BIT(7) -#define SDMMC_CMD_RESP_EXP BIT(6) -#define SDMMC_CMD_INDX(n) ((n) & 0x1F) -/* Status register defines */ -#define SDMMC_GET_FCNT(x) (((x)>>17) & 0x1FFF) -/* Internal DMAC interrupt defines */ -#define SDMMC_IDMAC_INT_AI BIT(9) -#define SDMMC_IDMAC_INT_NI BIT(8) -#define SDMMC_IDMAC_INT_CES BIT(5) -#define SDMMC_IDMAC_INT_DU BIT(4) -#define SDMMC_IDMAC_INT_FBE BIT(2) -#define SDMMC_IDMAC_INT_RI BIT(1) -#define SDMMC_IDMAC_INT_TI BIT(0) -/* Internal DMAC bus mode bits */ -#define SDMMC_IDMAC_ENABLE BIT(7) -#define SDMMC_IDMAC_FB BIT(1) -#define SDMMC_IDMAC_SWRESET BIT(0) -/* Version ID register define */ -#define SDMMC_GET_VERID(x) ((x) & 0xFFFF) - -/* Register access macros */ -#define mci_readl(dev, reg) \ - __raw_readl((dev)->regs + SDMMC_##reg) -#define mci_writel(dev, reg, value) \ - __raw_writel((value), (dev)->regs + SDMMC_##reg) - -/* 16-bit FIFO access macros */ -#define mci_readw(dev, reg) \ - __raw_readw((dev)->regs + SDMMC_##reg) -#define mci_writew(dev, reg, value) \ - __raw_writew((value), (dev)->regs + SDMMC_##reg) - -/* 64-bit FIFO access macros */ -#ifdef readq -#define mci_readq(dev, reg) \ - __raw_readq((dev)->regs + SDMMC_##reg) -#define mci_writeq(dev, reg, value) \ - __raw_writeq((value), (dev)->regs + SDMMC_##reg) -#else -/* - * Dummy readq implementation for architectures that don't define it. - * - * We would assume that none of these architectures would configure - * the IP block with a 64bit FIFO width, so this code will never be - * executed on those machines. Defining these macros here keeps the - * rest of the code free from ifdefs. - */ -#define mci_readq(dev, reg) \ - (*(volatile u64 __force *)((dev)->regs + SDMMC_##reg)) -#define mci_writeq(dev, reg, value) \ - (*(volatile u64 __force *)((dev)->regs + SDMMC_##reg) = (value)) -#endif - -extern int dw_mci_probe(struct dw_mci *host); -extern void dw_mci_remove(struct dw_mci *host); -#ifdef CONFIG_PM -extern int dw_mci_suspend(struct dw_mci *host); -extern int dw_mci_resume(struct dw_mci *host); -#endif - -#endif /* _DW_MMC_H_ */ diff --git a/ANDROID_3.4.5/drivers/mmc/host/imxmmc.c b/ANDROID_3.4.5/drivers/mmc/host/imxmmc.c deleted file mode 100644 index ea0f3ced..00000000 --- a/ANDROID_3.4.5/drivers/mmc/host/imxmmc.c +++ /dev/null @@ -1,1169 +0,0 @@ -/* - * linux/drivers/mmc/host/imxmmc.c - Motorola i.MX MMCI driver - * - * Copyright (C) 2004 Sascha Hauer, Pengutronix <sascha@saschahauer.de> - * Copyright (C) 2006 Pavel Pisa, PiKRON <ppisa@pikron.com> - * - * derived from pxamci.c by Russell King - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - */ - -#include <linux/module.h> -#include <linux/init.h> -#include <linux/ioport.h> -#include <linux/platform_device.h> -#include <linux/interrupt.h> -#include <linux/blkdev.h> -#include <linux/dma-mapping.h> -#include <linux/mmc/host.h> -#include <linux/mmc/card.h> -#include <linux/delay.h> -#include <linux/clk.h> -#include <linux/io.h> - -#include <asm/dma.h> -#include <asm/irq.h> -#include <asm/sizes.h> -#include <mach/mmc.h> -#include <mach/imx-dma.h> - -#include "imxmmc.h" - -#define DRIVER_NAME "imx-mmc" - -#define IMXMCI_INT_MASK_DEFAULT (INT_MASK_BUF_READY | INT_MASK_DATA_TRAN | \ - INT_MASK_WRITE_OP_DONE | INT_MASK_END_CMD_RES | \ - INT_MASK_AUTO_CARD_DETECT | INT_MASK_DAT0_EN | INT_MASK_SDIO) - -struct imxmci_host { - struct mmc_host *mmc; - spinlock_t lock; - struct resource *res; - void __iomem *base; - int irq; - imx_dmach_t dma; - volatile unsigned int imask; - unsigned int power_mode; - unsigned int present; - struct imxmmc_platform_data *pdata; - - struct mmc_request *req; - struct mmc_command *cmd; - struct mmc_data *data; - - struct timer_list timer; - struct tasklet_struct tasklet; - unsigned int status_reg; - unsigned long pending_events; - /* Next two fields are there for CPU driven transfers to overcome SDHC deficiencies */ - u16 *data_ptr; - unsigned int data_cnt; - atomic_t stuck_timeout; - - unsigned int dma_nents; - unsigned int dma_size; - unsigned int dma_dir; - int dma_allocated; - - unsigned char actual_bus_width; - - int prev_cmd_code; - - struct clk *clk; -}; - -#define IMXMCI_PEND_IRQ_b 0 -#define IMXMCI_PEND_DMA_END_b 1 -#define IMXMCI_PEND_DMA_ERR_b 2 -#define IMXMCI_PEND_WAIT_RESP_b 3 -#define IMXMCI_PEND_DMA_DATA_b 4 -#define IMXMCI_PEND_CPU_DATA_b 5 -#define IMXMCI_PEND_CARD_XCHG_b 6 -#define IMXMCI_PEND_SET_INIT_b 7 -#define IMXMCI_PEND_STARTED_b 8 - -#define IMXMCI_PEND_IRQ_m (1 << IMXMCI_PEND_IRQ_b) -#define IMXMCI_PEND_DMA_END_m (1 << IMXMCI_PEND_DMA_END_b) -#define IMXMCI_PEND_DMA_ERR_m (1 << IMXMCI_PEND_DMA_ERR_b) -#define IMXMCI_PEND_WAIT_RESP_m (1 << IMXMCI_PEND_WAIT_RESP_b) -#define IMXMCI_PEND_DMA_DATA_m (1 << IMXMCI_PEND_DMA_DATA_b) -#define IMXMCI_PEND_CPU_DATA_m (1 << IMXMCI_PEND_CPU_DATA_b) -#define IMXMCI_PEND_CARD_XCHG_m (1 << IMXMCI_PEND_CARD_XCHG_b) -#define IMXMCI_PEND_SET_INIT_m (1 << IMXMCI_PEND_SET_INIT_b) -#define IMXMCI_PEND_STARTED_m (1 << IMXMCI_PEND_STARTED_b) - -static void imxmci_stop_clock(struct imxmci_host *host) -{ - int i = 0; - u16 reg; - - reg = readw(host->base + MMC_REG_STR_STP_CLK); - writew(reg & ~STR_STP_CLK_START_CLK, host->base + MMC_REG_STR_STP_CLK); - while (i < 0x1000) { - if (!(i & 0x7f)) { - reg = readw(host->base + MMC_REG_STR_STP_CLK); - writew(reg | STR_STP_CLK_STOP_CLK, - host->base + MMC_REG_STR_STP_CLK); - } - - reg = readw(host->base + MMC_REG_STATUS); - if (!(reg & STATUS_CARD_BUS_CLK_RUN)) { - /* Check twice before cut */ - reg = readw(host->base + MMC_REG_STATUS); - if (!(reg & STATUS_CARD_BUS_CLK_RUN)) - return; - } - - i++; - } - dev_dbg(mmc_dev(host->mmc), "imxmci_stop_clock blocked, no luck\n"); -} - -static int imxmci_start_clock(struct imxmci_host *host) -{ - unsigned int trials = 0; - unsigned int delay_limit = 128; - unsigned long flags; - u16 reg; - - reg = readw(host->base + MMC_REG_STR_STP_CLK); - writew(reg & ~STR_STP_CLK_STOP_CLK, host->base + MMC_REG_STR_STP_CLK); - - clear_bit(IMXMCI_PEND_STARTED_b, &host->pending_events); - - /* - * Command start of the clock, this usually succeeds in less - * then 6 delay loops, but during card detection (low clockrate) - * it takes up to 5000 delay loops and sometimes fails for the first time - */ - reg = readw(host->base + MMC_REG_STR_STP_CLK); - writew(reg | STR_STP_CLK_START_CLK, host->base + MMC_REG_STR_STP_CLK); - - do { - unsigned int delay = delay_limit; - - while (delay--) { - reg = readw(host->base + MMC_REG_STATUS); - if (reg & STATUS_CARD_BUS_CLK_RUN) { - /* Check twice before cut */ - reg = readw(host->base + MMC_REG_STATUS); - if (reg & STATUS_CARD_BUS_CLK_RUN) - return 0; - } - - if (test_bit(IMXMCI_PEND_STARTED_b, &host->pending_events)) - return 0; - } - - local_irq_save(flags); - /* - * Ensure, that request is not doubled under all possible circumstances. - * It is possible, that cock running state is missed, because some other - * IRQ or schedule delays this function execution and the clocks has - * been already stopped by other means (response processing, SDHC HW) - */ - if (!test_bit(IMXMCI_PEND_STARTED_b, &host->pending_events)) { - reg = readw(host->base + MMC_REG_STR_STP_CLK); - writew(reg | STR_STP_CLK_START_CLK, - host->base + MMC_REG_STR_STP_CLK); - } - local_irq_restore(flags); - - } while (++trials < 256); - - dev_err(mmc_dev(host->mmc), "imxmci_start_clock blocked, no luck\n"); - - return -1; -} - -static void imxmci_softreset(struct imxmci_host *host) -{ - int i; - - /* reset sequence */ - writew(0x08, host->base + MMC_REG_STR_STP_CLK); - writew(0x0D, host->base + MMC_REG_STR_STP_CLK); - - for (i = 0; i < 8; i++) - writew(0x05, host->base + MMC_REG_STR_STP_CLK); - - writew(0xff, host->base + MMC_REG_RES_TO); - writew(512, host->base + MMC_REG_BLK_LEN); - writew(1, host->base + MMC_REG_NOB); -} - -static int imxmci_busy_wait_for_status(struct imxmci_host *host, - unsigned int *pstat, unsigned int stat_mask, - int timeout, const char *where) -{ - int loops = 0; - - while (!(*pstat & stat_mask)) { - loops += 2; - if (loops >= timeout) { - dev_dbg(mmc_dev(host->mmc), "busy wait timeout in %s, STATUS = 0x%x (0x%x)\n", - where, *pstat, stat_mask); - return -1; - } - udelay(2); - *pstat |= readw(host->base + MMC_REG_STATUS); - } - if (!loops) - return 0; - - /* The busy-wait is expected there for clock <8MHz due to SDHC hardware flaws */ - if (!(stat_mask & STATUS_END_CMD_RESP) || (host->mmc->ios.clock >= 8000000)) - dev_info(mmc_dev(host->mmc), "busy wait for %d usec in %s, STATUS = 0x%x (0x%x)\n", - loops, where, *pstat, stat_mask); - return loops; -} - -static void imxmci_setup_data(struct imxmci_host *host, struct mmc_data *data) -{ - unsigned int nob = data->blocks; - unsigned int blksz = data->blksz; - unsigned int datasz = nob * blksz; - int i; - - if (data->flags & MMC_DATA_STREAM) - nob = 0xffff; - - host->data = data; - data->bytes_xfered = 0; - - writew(nob, host->base + MMC_REG_NOB); - writew(blksz, host->base + MMC_REG_BLK_LEN); - - /* - * DMA cannot be used for small block sizes, we have to use CPU driven transfers otherwise. - * We are in big troubles for non-512 byte transfers according to note in the paragraph - * 20.6.7 of User Manual anyway, but we need to be able to transfer SCR at least. - * The situation is even more complex in reality. The SDHC in not able to handle wll - * partial FIFO fills and reads. The length has to be rounded up to burst size multiple. - * This is required for SCR read at least. - */ - if (datasz < 512) { - host->dma_size = datasz; - if (data->flags & MMC_DATA_READ) { - host->dma_dir = DMA_FROM_DEVICE; - - /* Hack to enable read SCR */ - writew(1, host->base + MMC_REG_NOB); - writew(512, host->base + MMC_REG_BLK_LEN); - } else { - host->dma_dir = DMA_TO_DEVICE; - } - - /* Convert back to virtual address */ - host->data_ptr = (u16 *)sg_virt(data->sg); - host->data_cnt = 0; - - clear_bit(IMXMCI_PEND_DMA_DATA_b, &host->pending_events); - set_bit(IMXMCI_PEND_CPU_DATA_b, &host->pending_events); - - return; - } - - if (data->flags & MMC_DATA_READ) { - host->dma_dir = DMA_FROM_DEVICE; - host->dma_nents = dma_map_sg(mmc_dev(host->mmc), data->sg, - data->sg_len, host->dma_dir); - - imx_dma_setup_sg(host->dma, data->sg, data->sg_len, datasz, - host->res->start + MMC_REG_BUFFER_ACCESS, - DMA_MODE_READ); - - /*imx_dma_setup_mem2dev_ccr(host->dma, DMA_MODE_READ, IMX_DMA_WIDTH_16, CCR_REN);*/ - CCR(host->dma) = CCR_DMOD_LINEAR | CCR_DSIZ_32 | CCR_SMOD_FIFO | CCR_SSIZ_16 | CCR_REN; - } else { - host->dma_dir = DMA_TO_DEVICE; - - host->dma_nents = dma_map_sg(mmc_dev(host->mmc), data->sg, - data->sg_len, host->dma_dir); - - imx_dma_setup_sg(host->dma, data->sg, data->sg_len, datasz, - host->res->start + MMC_REG_BUFFER_ACCESS, - DMA_MODE_WRITE); - - /*imx_dma_setup_mem2dev_ccr(host->dma, DMA_MODE_WRITE, IMX_DMA_WIDTH_16, CCR_REN);*/ - CCR(host->dma) = CCR_SMOD_LINEAR | CCR_SSIZ_32 | CCR_DMOD_FIFO | CCR_DSIZ_16 | CCR_REN; - } - -#if 1 /* This code is there only for consistency checking and can be disabled in future */ - host->dma_size = 0; - for (i = 0; i < host->dma_nents; i++) - host->dma_size += data->sg[i].length; - - if (datasz > host->dma_size) { - dev_err(mmc_dev(host->mmc), "imxmci_setup_data datasz 0x%x > 0x%x dm_size\n", - datasz, host->dma_size); - } -#endif - - host->dma_size = datasz; - - wmb(); - - set_bit(IMXMCI_PEND_DMA_DATA_b, &host->pending_events); - clear_bit(IMXMCI_PEND_CPU_DATA_b, &host->pending_events); - - /* start DMA engine for read, write is delayed after initial response */ - if (host->dma_dir == DMA_FROM_DEVICE) - imx_dma_enable(host->dma); -} - -static void imxmci_start_cmd(struct imxmci_host *host, struct mmc_command *cmd, unsigned int cmdat) -{ - unsigned long flags; - u32 imask; - - WARN_ON(host->cmd != NULL); - host->cmd = cmd; - - /* Ensure, that clock are stopped else command programming and start fails */ - imxmci_stop_clock(host); - - if (cmd->flags & MMC_RSP_BUSY) - cmdat |= CMD_DAT_CONT_BUSY; - - switch (mmc_resp_type(cmd)) { - case MMC_RSP_R1: /* short CRC, OPCODE */ - case MMC_RSP_R1B:/* short CRC, OPCODE, BUSY */ - cmdat |= CMD_DAT_CONT_RESPONSE_FORMAT_R1; - break; - case MMC_RSP_R2: /* long 136 bit + CRC */ - cmdat |= CMD_DAT_CONT_RESPONSE_FORMAT_R2; - break; - case MMC_RSP_R3: /* short */ - cmdat |= CMD_DAT_CONT_RESPONSE_FORMAT_R3; - break; - default: - break; - } - - if (test_and_clear_bit(IMXMCI_PEND_SET_INIT_b, &host->pending_events)) - cmdat |= CMD_DAT_CONT_INIT; /* This command needs init */ - - if (host->actual_bus_width == MMC_BUS_WIDTH_4) - cmdat |= CMD_DAT_CONT_BUS_WIDTH_4; - - writew(cmd->opcode, host->base + MMC_REG_CMD); - writew(cmd->arg >> 16, host->base + MMC_REG_ARGH); - writew(cmd->arg & 0xffff, host->base + MMC_REG_ARGL); - writew(cmdat, host->base + MMC_REG_CMD_DAT_CONT); - - atomic_set(&host->stuck_timeout, 0); - set_bit(IMXMCI_PEND_WAIT_RESP_b, &host->pending_events); - - - imask = IMXMCI_INT_MASK_DEFAULT; - imask &= ~INT_MASK_END_CMD_RES; - if (cmdat & CMD_DAT_CONT_DATA_ENABLE) { - /* imask &= ~INT_MASK_BUF_READY; */ - imask &= ~INT_MASK_DATA_TRAN; - if (cmdat & CMD_DAT_CONT_WRITE) - imask &= ~INT_MASK_WRITE_OP_DONE; - if (test_bit(IMXMCI_PEND_CPU_DATA_b, &host->pending_events)) - imask &= ~INT_MASK_BUF_READY; - } - - spin_lock_irqsave(&host->lock, flags); - host->imask = imask; - writew(host->imask, host->base + MMC_REG_INT_MASK); - spin_unlock_irqrestore(&host->lock, flags); - - dev_dbg(mmc_dev(host->mmc), "CMD%02d (0x%02x) mask set to 0x%04x\n", - cmd->opcode, cmd->opcode, imask); - - imxmci_start_clock(host); -} - -static void imxmci_finish_request(struct imxmci_host *host, struct mmc_request *req) -{ - unsigned long flags; - - spin_lock_irqsave(&host->lock, flags); - - host->pending_events &= ~(IMXMCI_PEND_WAIT_RESP_m | IMXMCI_PEND_DMA_END_m | - IMXMCI_PEND_DMA_DATA_m | IMXMCI_PEND_CPU_DATA_m); - - host->imask = IMXMCI_INT_MASK_DEFAULT; - writew(host->imask, host->base + MMC_REG_INT_MASK); - - spin_unlock_irqrestore(&host->lock, flags); - - if (req && req->cmd) - host->prev_cmd_code = req->cmd->opcode; - - host->req = NULL; - host->cmd = NULL; - host->data = NULL; - mmc_request_done(host->mmc, req); -} - -static int imxmci_finish_data(struct imxmci_host *host, unsigned int stat) -{ - struct mmc_data *data = host->data; - int data_error; - - if (test_and_clear_bit(IMXMCI_PEND_DMA_DATA_b, &host->pending_events)) { - imx_dma_disable(host->dma); - dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->dma_nents, - host->dma_dir); - } - - if (stat & STATUS_ERR_MASK) { - dev_dbg(mmc_dev(host->mmc), "request failed. status: 0x%08x\n", stat); - if (stat & (STATUS_CRC_READ_ERR | STATUS_CRC_WRITE_ERR)) - data->error = -EILSEQ; - else if (stat & STATUS_TIME_OUT_READ) - data->error = -ETIMEDOUT; - else - data->error = -EIO; - } else { - data->bytes_xfered = host->dma_size; - } - - data_error = data->error; - - host->data = NULL; - - return data_error; -} - -static int imxmci_cmd_done(struct imxmci_host *host, unsigned int stat) -{ - struct mmc_command *cmd = host->cmd; - int i; - u32 a, b, c; - struct mmc_data *data = host->data; - - if (!cmd) - return 0; - - host->cmd = NULL; - - if (stat & STATUS_TIME_OUT_RESP) { - dev_dbg(mmc_dev(host->mmc), "CMD TIMEOUT\n"); - cmd->error = -ETIMEDOUT; - } else if (stat & STATUS_RESP_CRC_ERR && cmd->flags & MMC_RSP_CRC) { - dev_dbg(mmc_dev(host->mmc), "cmd crc error\n"); - cmd->error = -EILSEQ; - } - - if (cmd->flags & MMC_RSP_PRESENT) { - if (cmd->flags & MMC_RSP_136) { - for (i = 0; i < 4; i++) { - a = readw(host->base + MMC_REG_RES_FIFO); - b = readw(host->base + MMC_REG_RES_FIFO); - cmd->resp[i] = a << 16 | b; - } - } else { - a = readw(host->base + MMC_REG_RES_FIFO); - b = readw(host->base + MMC_REG_RES_FIFO); - c = readw(host->base + MMC_REG_RES_FIFO); - cmd->resp[0] = a << 24 | b << 8 | c >> 8; - } - } - - dev_dbg(mmc_dev(host->mmc), "RESP 0x%08x, 0x%08x, 0x%08x, 0x%08x, error %d\n", - cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3], cmd->error); - - if (data && !cmd->error && !(stat & STATUS_ERR_MASK)) { - if (host->req->data->flags & MMC_DATA_WRITE) { - - /* Wait for FIFO to be empty before starting DMA write */ - - stat = readw(host->base + MMC_REG_STATUS); - if (imxmci_busy_wait_for_status(host, &stat, - STATUS_APPL_BUFF_FE, - 40, "imxmci_cmd_done DMA WR") < 0) { - cmd->error = -EIO; - imxmci_finish_data(host, stat); - if (host->req) - imxmci_finish_request(host, host->req); - dev_warn(mmc_dev(host->mmc), "STATUS = 0x%04x\n", - stat); - return 0; - } - - if (test_bit(IMXMCI_PEND_DMA_DATA_b, &host->pending_events)) - imx_dma_enable(host->dma); - } - } else { - struct mmc_request *req; - imxmci_stop_clock(host); - req = host->req; - - if (data) - imxmci_finish_data(host, stat); - - if (req) - imxmci_finish_request(host, req); - else - dev_warn(mmc_dev(host->mmc), "imxmci_cmd_done: no request to finish\n"); - } - - return 1; -} - -static int imxmci_data_done(struct imxmci_host *host, unsigned int stat) -{ - struct mmc_data *data = host->data; - int data_error; - - if (!data) - return 0; - - data_error = imxmci_finish_data(host, stat); - - if (host->req->stop) { - imxmci_stop_clock(host); - imxmci_start_cmd(host, host->req->stop, 0); - } else { - struct mmc_request *req; - req = host->req; - if (req) - imxmci_finish_request(host, req); - else - dev_warn(mmc_dev(host->mmc), "imxmci_data_done: no request to finish\n"); - } - - return 1; -} - -static int imxmci_cpu_driven_data(struct imxmci_host *host, unsigned int *pstat) -{ - int i; - int burst_len; - int trans_done = 0; - unsigned int stat = *pstat; - - if (host->actual_bus_width != MMC_BUS_WIDTH_4) - burst_len = 16; - else - burst_len = 64; - - /* This is unfortunately required */ - dev_dbg(mmc_dev(host->mmc), "imxmci_cpu_driven_data running STATUS = 0x%x\n", - stat); - - udelay(20); /* required for clocks < 8MHz*/ - - if (host->dma_dir == DMA_FROM_DEVICE) { - imxmci_busy_wait_for_status(host, &stat, - STATUS_APPL_BUFF_FF | STATUS_DATA_TRANS_DONE | - STATUS_TIME_OUT_READ, - 50, "imxmci_cpu_driven_data read"); - - while ((stat & (STATUS_APPL_BUFF_FF | STATUS_DATA_TRANS_DONE)) && - !(stat & STATUS_TIME_OUT_READ) && - (host->data_cnt < 512)) { - - udelay(20); /* required for clocks < 8MHz*/ - - for (i = burst_len; i >= 2 ; i -= 2) { - u16 data; - data = readw(host->base + MMC_REG_BUFFER_ACCESS); - udelay(10); /* required for clocks < 8MHz*/ - if (host->data_cnt+2 <= host->dma_size) { - *(host->data_ptr++) = data; - } else { - if (host->data_cnt < host->dma_size) - *(u8 *)(host->data_ptr) = data; - } - host->data_cnt += 2; - } - - stat = readw(host->base + MMC_REG_STATUS); - - dev_dbg(mmc_dev(host->mmc), "imxmci_cpu_driven_data read %d burst %d STATUS = 0x%x\n", - host->data_cnt, burst_len, stat); - } - - if ((stat & STATUS_DATA_TRANS_DONE) && (host->data_cnt >= 512)) - trans_done = 1; - - if (host->dma_size & 0x1ff) - stat &= ~STATUS_CRC_READ_ERR; - - if (stat & STATUS_TIME_OUT_READ) { - dev_dbg(mmc_dev(host->mmc), "imxmci_cpu_driven_data read timeout STATUS = 0x%x\n", - stat); - trans_done = -1; - } - - } else { - imxmci_busy_wait_for_status(host, &stat, - STATUS_APPL_BUFF_FE, - 20, "imxmci_cpu_driven_data write"); - - while ((stat & STATUS_APPL_BUFF_FE) && - (host->data_cnt < host->dma_size)) { - if (burst_len >= host->dma_size - host->data_cnt) { - burst_len = host->dma_size - host->data_cnt; - host->data_cnt = host->dma_size; - trans_done = 1; - } else { - host->data_cnt += burst_len; - } - - for (i = burst_len; i > 0 ; i -= 2) - writew(*(host->data_ptr++), host->base + MMC_REG_BUFFER_ACCESS); - - stat = readw(host->base + MMC_REG_STATUS); - - dev_dbg(mmc_dev(host->mmc), "imxmci_cpu_driven_data write burst %d STATUS = 0x%x\n", - burst_len, stat); - } - } - - *pstat = stat; - - return trans_done; -} - -static void imxmci_dma_irq(int dma, void *devid) -{ - struct imxmci_host *host = devid; - u32 stat = readw(host->base + MMC_REG_STATUS); - - atomic_set(&host->stuck_timeout, 0); - host->status_reg = stat; - set_bit(IMXMCI_PEND_DMA_END_b, &host->pending_events); - tasklet_schedule(&host->tasklet); -} - -static irqreturn_t imxmci_irq(int irq, void *devid) -{ - struct imxmci_host *host = devid; - u32 stat = readw(host->base + MMC_REG_STATUS); - int handled = 1; - - writew(host->imask | INT_MASK_SDIO | INT_MASK_AUTO_CARD_DETECT, - host->base + MMC_REG_INT_MASK); - - atomic_set(&host->stuck_timeout, 0); - host->status_reg = stat; - set_bit(IMXMCI_PEND_IRQ_b, &host->pending_events); - set_bit(IMXMCI_PEND_STARTED_b, &host->pending_events); - tasklet_schedule(&host->tasklet); - - return IRQ_RETVAL(handled); -} - -static void imxmci_tasklet_fnc(unsigned long data) -{ - struct imxmci_host *host = (struct imxmci_host *)data; - u32 stat; - unsigned int data_dir_mask = 0; /* STATUS_WR_CRC_ERROR_CODE_MASK */ - int timeout = 0; - - if (atomic_read(&host->stuck_timeout) > 4) { - char *what; - timeout = 1; - stat = readw(host->base + MMC_REG_STATUS); - host->status_reg = stat; - if (test_bit(IMXMCI_PEND_WAIT_RESP_b, &host->pending_events)) - if (test_bit(IMXMCI_PEND_DMA_DATA_b, &host->pending_events)) - what = "RESP+DMA"; - else - what = "RESP"; - else - if (test_bit(IMXMCI_PEND_DMA_DATA_b, &host->pending_events)) - if (test_bit(IMXMCI_PEND_DMA_END_b, &host->pending_events)) - what = "DATA"; - else - what = "DMA"; - else - what = "???"; - - dev_err(mmc_dev(host->mmc), - "%s TIMEOUT, hardware stucked STATUS = 0x%04x IMASK = 0x%04x\n", - what, stat, - readw(host->base + MMC_REG_INT_MASK)); - dev_err(mmc_dev(host->mmc), - "CMD_DAT_CONT = 0x%04x, MMC_BLK_LEN = 0x%04x, MMC_NOB = 0x%04x, DMA_CCR = 0x%08x\n", - readw(host->base + MMC_REG_CMD_DAT_CONT), - readw(host->base + MMC_REG_BLK_LEN), - readw(host->base + MMC_REG_NOB), - CCR(host->dma)); - dev_err(mmc_dev(host->mmc), "CMD%d, prevCMD%d, bus %d-bit, dma_size = 0x%x\n", - host->cmd ? host->cmd->opcode : 0, - host->prev_cmd_code, - 1 << host->actual_bus_width, host->dma_size); - } - - if (!host->present || timeout) - host->status_reg = STATUS_TIME_OUT_RESP | STATUS_TIME_OUT_READ | - STATUS_CRC_READ_ERR | STATUS_CRC_WRITE_ERR; - - if (test_bit(IMXMCI_PEND_IRQ_b, &host->pending_events) || timeout) { - clear_bit(IMXMCI_PEND_IRQ_b, &host->pending_events); - - stat = readw(host->base + MMC_REG_STATUS); - /* - * This is not required in theory, but there is chance to miss some flag - * which clears automatically by mask write, FreeScale original code keeps - * stat from IRQ time so do I - */ - stat |= host->status_reg; - - if (test_bit(IMXMCI_PEND_CPU_DATA_b, &host->pending_events)) - stat &= ~STATUS_CRC_READ_ERR; - - if (test_bit(IMXMCI_PEND_WAIT_RESP_b, &host->pending_events)) { - imxmci_busy_wait_for_status(host, &stat, - STATUS_END_CMD_RESP | STATUS_ERR_MASK, - 20, "imxmci_tasklet_fnc resp (ERRATUM #4)"); - } - - if (stat & (STATUS_END_CMD_RESP | STATUS_ERR_MASK)) { - if (test_and_clear_bit(IMXMCI_PEND_WAIT_RESP_b, &host->pending_events)) - imxmci_cmd_done(host, stat); - if (host->data && (stat & STATUS_ERR_MASK)) - imxmci_data_done(host, stat); - } - - if (test_bit(IMXMCI_PEND_CPU_DATA_b, &host->pending_events)) { - stat |= readw(host->base + MMC_REG_STATUS); - if (imxmci_cpu_driven_data(host, &stat)) { - if (test_and_clear_bit(IMXMCI_PEND_WAIT_RESP_b, &host->pending_events)) - imxmci_cmd_done(host, stat); - atomic_clear_mask(IMXMCI_PEND_IRQ_m|IMXMCI_PEND_CPU_DATA_m, - &host->pending_events); - imxmci_data_done(host, stat); - } - } - } - - if (test_bit(IMXMCI_PEND_DMA_END_b, &host->pending_events) && - !test_bit(IMXMCI_PEND_WAIT_RESP_b, &host->pending_events)) { - - stat = readw(host->base + MMC_REG_STATUS); - /* Same as above */ - stat |= host->status_reg; - - if (host->dma_dir == DMA_TO_DEVICE) - data_dir_mask = STATUS_WRITE_OP_DONE; - else - data_dir_mask = STATUS_DATA_TRANS_DONE; - - if (stat & data_dir_mask) { - clear_bit(IMXMCI_PEND_DMA_END_b, &host->pending_events); - imxmci_data_done(host, stat); - } - } - - if (test_and_clear_bit(IMXMCI_PEND_CARD_XCHG_b, &host->pending_events)) { - - if (host->cmd) - imxmci_cmd_done(host, STATUS_TIME_OUT_RESP); - - if (host->data) - imxmci_data_done(host, STATUS_TIME_OUT_READ | - STATUS_CRC_READ_ERR | STATUS_CRC_WRITE_ERR); - - if (host->req) - imxmci_finish_request(host, host->req); - - mmc_detect_change(host->mmc, msecs_to_jiffies(100)); - - } -} - -static void imxmci_request(struct mmc_host *mmc, struct mmc_request *req) -{ - struct imxmci_host *host = mmc_priv(mmc); - unsigned int cmdat; - - WARN_ON(host->req != NULL); - - host->req = req; - - cmdat = 0; - - if (req->data) { - imxmci_setup_data(host, req->data); - - cmdat |= CMD_DAT_CONT_DATA_ENABLE; - - if (req->data->flags & MMC_DATA_WRITE) - cmdat |= CMD_DAT_CONT_WRITE; - - if (req->data->flags & MMC_DATA_STREAM) - cmdat |= CMD_DAT_CONT_STREAM_BLOCK; - } - - imxmci_start_cmd(host, req->cmd, cmdat); -} - -#define CLK_RATE 19200000 - -static void imxmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) -{ - struct imxmci_host *host = mmc_priv(mmc); - int prescaler; - - if (ios->bus_width == MMC_BUS_WIDTH_4) { - host->actual_bus_width = MMC_BUS_WIDTH_4; - imx_gpio_mode(PB11_PF_SD_DAT3); - BLR(host->dma) = 0; /* burst 64 byte read/write */ - } else { - host->actual_bus_width = MMC_BUS_WIDTH_1; - imx_gpio_mode(GPIO_PORTB | GPIO_IN | GPIO_PUEN | 11); - BLR(host->dma) = 16; /* burst 16 byte read/write */ - } - - if (host->power_mode != ios->power_mode) { - switch (ios->power_mode) { - case MMC_POWER_OFF: - break; - case MMC_POWER_UP: - set_bit(IMXMCI_PEND_SET_INIT_b, &host->pending_events); - break; - case MMC_POWER_ON: - break; - } - host->power_mode = ios->power_mode; - } - - if (ios->clock) { - unsigned int clk; - u16 reg; - - /* The prescaler is 5 for PERCLK2 equal to 96MHz - * then 96MHz / 5 = 19.2 MHz - */ - clk = clk_get_rate(host->clk); - prescaler = (clk + (CLK_RATE * 7) / 8) / CLK_RATE; - switch (prescaler) { - case 0: - case 1: prescaler = 0; - break; - case 2: prescaler = 1; - break; - case 3: prescaler = 2; - break; - case 4: prescaler = 4; - break; - default: - case 5: prescaler = 5; - break; - } - - dev_dbg(mmc_dev(host->mmc), "PERCLK2 %d MHz -> prescaler %d\n", - clk, prescaler); - - for (clk = 0; clk < 8; clk++) { - int x; - x = CLK_RATE / (1 << clk); - if (x <= ios->clock) - break; - } - - /* enable controller */ - reg = readw(host->base + MMC_REG_STR_STP_CLK); - writew(reg | STR_STP_CLK_ENABLE, - host->base + MMC_REG_STR_STP_CLK); - - imxmci_stop_clock(host); - writew((prescaler << 3) | clk, host->base + MMC_REG_CLK_RATE); - /* - * Under my understanding, clock should not be started there, because it would - * initiate SDHC sequencer and send last or random command into card - */ - /* imxmci_start_clock(host); */ - - dev_dbg(mmc_dev(host->mmc), - "MMC_CLK_RATE: 0x%08x\n", - readw(host->base + MMC_REG_CLK_RATE)); - } else { - imxmci_stop_clock(host); - } -} - -static int imxmci_get_ro(struct mmc_host *mmc) -{ - struct imxmci_host *host = mmc_priv(mmc); - - if (host->pdata && host->pdata->get_ro) - return !!host->pdata->get_ro(mmc_dev(mmc)); - /* - * Board doesn't support read only detection; let the mmc core - * decide what to do. - */ - return -ENOSYS; -} - - -static const struct mmc_host_ops imxmci_ops = { - .request = imxmci_request, - .set_ios = imxmci_set_ios, - .get_ro = imxmci_get_ro, -}; - -static void imxmci_check_status(unsigned long data) -{ - struct imxmci_host *host = (struct imxmci_host *)data; - - if (host->pdata && host->pdata->card_present && - host->pdata->card_present(mmc_dev(host->mmc)) != host->present) { - host->present ^= 1; - dev_info(mmc_dev(host->mmc), "card %s\n", - host->present ? "inserted" : "removed"); - - set_bit(IMXMCI_PEND_CARD_XCHG_b, &host->pending_events); - tasklet_schedule(&host->tasklet); - } - - if (test_bit(IMXMCI_PEND_WAIT_RESP_b, &host->pending_events) || - test_bit(IMXMCI_PEND_DMA_DATA_b, &host->pending_events)) { - atomic_inc(&host->stuck_timeout); - if (atomic_read(&host->stuck_timeout) > 4) - tasklet_schedule(&host->tasklet); - } else { - atomic_set(&host->stuck_timeout, 0); - - } - - mod_timer(&host->timer, jiffies + (HZ>>1)); -} - -static int __init imxmci_probe(struct platform_device *pdev) -{ - struct mmc_host *mmc; - struct imxmci_host *host = NULL; - struct resource *r; - int ret = 0, irq; - u16 rev_no; - - pr_info("i.MX mmc driver\n"); - - r = platform_get_resource(pdev, IORESOURCE_MEM, 0); - irq = platform_get_irq(pdev, 0); - if (!r || irq < 0) - return -ENXIO; - - r = request_mem_region(r->start, resource_size(r), pdev->name); - if (!r) - return -EBUSY; - - mmc = mmc_alloc_host(sizeof(struct imxmci_host), &pdev->dev); - if (!mmc) { - ret = -ENOMEM; - goto out; - } - - mmc->ops = &imxmci_ops; - mmc->f_min = 150000; - mmc->f_max = CLK_RATE/2; - mmc->ocr_avail = MMC_VDD_32_33; - mmc->caps = MMC_CAP_4_BIT_DATA; - - /* MMC core transfer sizes tunable parameters */ - mmc->max_segs = 64; - mmc->max_seg_size = 64*512; /* default PAGE_CACHE_SIZE */ - mmc->max_req_size = 64*512; /* default PAGE_CACHE_SIZE */ - mmc->max_blk_size = 2048; - mmc->max_blk_count = 65535; - - host = mmc_priv(mmc); - host->base = ioremap(r->start, resource_size(r)); - if (!host->base) { - ret = -ENOMEM; - goto out; - } - - host->mmc = mmc; - host->dma_allocated = 0; - host->pdata = pdev->dev.platform_data; - if (!host->pdata) - dev_warn(&pdev->dev, "No platform data provided!\n"); - - spin_lock_init(&host->lock); - host->res = r; - host->irq = irq; - - host->clk = clk_get(&pdev->dev, "perclk2"); - if (IS_ERR(host->clk)) { - ret = PTR_ERR(host->clk); - goto out; - } - clk_enable(host->clk); - - imx_gpio_mode(PB8_PF_SD_DAT0); - imx_gpio_mode(PB9_PF_SD_DAT1); - imx_gpio_mode(PB10_PF_SD_DAT2); - /* Configured as GPIO with pull-up to ensure right MCC card mode */ - /* Switched to PB11_PF_SD_DAT3 if 4 bit bus is configured */ - imx_gpio_mode(GPIO_PORTB | GPIO_IN | GPIO_PUEN | 11); - /* imx_gpio_mode(PB11_PF_SD_DAT3); */ - imx_gpio_mode(PB12_PF_SD_CLK); - imx_gpio_mode(PB13_PF_SD_CMD); - - imxmci_softreset(host); - - rev_no = readw(host->base + MMC_REG_REV_NO); - if (rev_no != 0x390) { - dev_err(mmc_dev(host->mmc), "wrong rev.no. 0x%08x. aborting.\n", - readw(host->base + MMC_REG_REV_NO)); - goto out; - } - - /* recommended in data sheet */ - writew(0x2db4, host->base + MMC_REG_READ_TO); - - host->imask = IMXMCI_INT_MASK_DEFAULT; - writew(host->imask, host->base + MMC_REG_INT_MASK); - - host->dma = imx_dma_request_by_prio(DRIVER_NAME, DMA_PRIO_LOW); - if(host->dma < 0) { - dev_err(mmc_dev(host->mmc), "imx_dma_request_by_prio failed\n"); - ret = -EBUSY; - goto out; - } - host->dma_allocated = 1; - imx_dma_setup_handlers(host->dma, imxmci_dma_irq, NULL, host); - RSSR(host->dma) = DMA_REQ_SDHC; - - tasklet_init(&host->tasklet, imxmci_tasklet_fnc, (unsigned long)host); - host->status_reg=0; - host->pending_events=0; - - ret = request_irq(host->irq, imxmci_irq, 0, DRIVER_NAME, host); - if (ret) - goto out; - - if (host->pdata && host->pdata->card_present) - host->present = host->pdata->card_present(mmc_dev(mmc)); - else /* if there is no way to detect assume that card is present */ - host->present = 1; - - init_timer(&host->timer); - host->timer.data = (unsigned long)host; - host->timer.function = imxmci_check_status; - add_timer(&host->timer); - mod_timer(&host->timer, jiffies + (HZ >> 1)); - - platform_set_drvdata(pdev, mmc); - - mmc_add_host(mmc); - - return 0; - -out: - if (host) { - if (host->dma_allocated) { - imx_dma_free(host->dma); - host->dma_allocated = 0; - } - if (host->clk) { - clk_disable(host->clk); - clk_put(host->clk); - } - if (host->base) - iounmap(host->base); - } - if (mmc) - mmc_free_host(mmc); - release_mem_region(r->start, resource_size(r)); - return ret; -} - -static int __exit imxmci_remove(struct platform_device *pdev) -{ - struct mmc_host *mmc = platform_get_drvdata(pdev); - - platform_set_drvdata(pdev, NULL); - - if (mmc) { - struct imxmci_host *host = mmc_priv(mmc); - - tasklet_disable(&host->tasklet); - - del_timer_sync(&host->timer); - mmc_remove_host(mmc); - - free_irq(host->irq, host); - iounmap(host->base); - if (host->dma_allocated) { - imx_dma_free(host->dma); - host->dma_allocated = 0; - } - - tasklet_kill(&host->tasklet); - - clk_disable(host->clk); - clk_put(host->clk); - - release_mem_region(host->res->start, resource_size(host->res)); - - mmc_free_host(mmc); - } - return 0; -} - -#ifdef CONFIG_PM -static int imxmci_suspend(struct platform_device *dev, pm_message_t state) -{ - struct mmc_host *mmc = platform_get_drvdata(dev); - int ret = 0; - - if (mmc) - ret = mmc_suspend_host(mmc); - - return ret; -} - -static int imxmci_resume(struct platform_device *dev) -{ - struct mmc_host *mmc = platform_get_drvdata(dev); - struct imxmci_host *host; - int ret = 0; - - if (mmc) { - host = mmc_priv(mmc); - if (host) - set_bit(IMXMCI_PEND_SET_INIT_b, &host->pending_events); - ret = mmc_resume_host(mmc); - } - - return ret; -} -#else -#define imxmci_suspend NULL -#define imxmci_resume NULL -#endif /* CONFIG_PM */ - -static struct platform_driver imxmci_driver = { - .remove = __exit_p(imxmci_remove), - .suspend = imxmci_suspend, - .resume = imxmci_resume, - .driver = { - .name = DRIVER_NAME, - .owner = THIS_MODULE, - } -}; - -static int __init imxmci_init(void) -{ - return platform_driver_probe(&imxmci_driver, imxmci_probe); -} - -static void __exit imxmci_exit(void) -{ - platform_driver_unregister(&imxmci_driver); -} - -module_init(imxmci_init); -module_exit(imxmci_exit); - -MODULE_DESCRIPTION("i.MX Multimedia Card Interface Driver"); -MODULE_AUTHOR("Sascha Hauer, Pengutronix"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:imx-mmc"); diff --git a/ANDROID_3.4.5/drivers/mmc/host/imxmmc.h b/ANDROID_3.4.5/drivers/mmc/host/imxmmc.h deleted file mode 100644 index 09d5d4ee..00000000 --- a/ANDROID_3.4.5/drivers/mmc/host/imxmmc.h +++ /dev/null @@ -1,64 +0,0 @@ -#define MMC_REG_STR_STP_CLK 0x00 -#define MMC_REG_STATUS 0x04 -#define MMC_REG_CLK_RATE 0x08 -#define MMC_REG_CMD_DAT_CONT 0x0C -#define MMC_REG_RES_TO 0x10 -#define MMC_REG_READ_TO 0x14 -#define MMC_REG_BLK_LEN 0x18 -#define MMC_REG_NOB 0x1C -#define MMC_REG_REV_NO 0x20 -#define MMC_REG_INT_MASK 0x24 -#define MMC_REG_CMD 0x28 -#define MMC_REG_ARGH 0x2C -#define MMC_REG_ARGL 0x30 -#define MMC_REG_RES_FIFO 0x34 -#define MMC_REG_BUFFER_ACCESS 0x38 - -#define STR_STP_CLK_IPG_CLK_GATE_DIS (1<<15) -#define STR_STP_CLK_IPG_PERCLK_GATE_DIS (1<<14) -#define STR_STP_CLK_ENDIAN (1<<5) -#define STR_STP_CLK_RESET (1<<3) -#define STR_STP_CLK_ENABLE (1<<2) -#define STR_STP_CLK_START_CLK (1<<1) -#define STR_STP_CLK_STOP_CLK (1<<0) -#define STATUS_CARD_PRESENCE (1<<15) -#define STATUS_SDIO_INT_ACTIVE (1<<14) -#define STATUS_END_CMD_RESP (1<<13) -#define STATUS_WRITE_OP_DONE (1<<12) -#define STATUS_DATA_TRANS_DONE (1<<11) -#define STATUS_WR_CRC_ERROR_CODE_MASK (3<<10) -#define STATUS_CARD_BUS_CLK_RUN (1<<8) -#define STATUS_APPL_BUFF_FF (1<<7) -#define STATUS_APPL_BUFF_FE (1<<6) -#define STATUS_RESP_CRC_ERR (1<<5) -#define STATUS_CRC_READ_ERR (1<<3) -#define STATUS_CRC_WRITE_ERR (1<<2) -#define STATUS_TIME_OUT_RESP (1<<1) -#define STATUS_TIME_OUT_READ (1<<0) -#define STATUS_ERR_MASK 0x2f -#define CLK_RATE_PRESCALER(x) ((x) & 0x7) -#define CLK_RATE_CLK_RATE(x) (((x) & 0x7) << 3) -#define CMD_DAT_CONT_CMD_RESP_LONG_OFF (1<<12) -#define CMD_DAT_CONT_STOP_READWAIT (1<<11) -#define CMD_DAT_CONT_START_READWAIT (1<<10) -#define CMD_DAT_CONT_BUS_WIDTH_1 (0<<8) -#define CMD_DAT_CONT_BUS_WIDTH_4 (2<<8) -#define CMD_DAT_CONT_INIT (1<<7) -#define CMD_DAT_CONT_BUSY (1<<6) -#define CMD_DAT_CONT_STREAM_BLOCK (1<<5) -#define CMD_DAT_CONT_WRITE (1<<4) -#define CMD_DAT_CONT_DATA_ENABLE (1<<3) -#define CMD_DAT_CONT_RESPONSE_FORMAT_R1 (1) -#define CMD_DAT_CONT_RESPONSE_FORMAT_R2 (2) -#define CMD_DAT_CONT_RESPONSE_FORMAT_R3 (3) -#define CMD_DAT_CONT_RESPONSE_FORMAT_R4 (4) -#define CMD_DAT_CONT_RESPONSE_FORMAT_R5 (5) -#define CMD_DAT_CONT_RESPONSE_FORMAT_R6 (6) -#define INT_MASK_AUTO_CARD_DETECT (1<<6) -#define INT_MASK_DAT0_EN (1<<5) -#define INT_MASK_SDIO (1<<4) -#define INT_MASK_BUF_READY (1<<3) -#define INT_MASK_END_CMD_RES (1<<2) -#define INT_MASK_WRITE_OP_DONE (1<<1) -#define INT_MASK_DATA_TRAN (1<<0) -#define INT_ALL (0x7f) diff --git a/ANDROID_3.4.5/drivers/mmc/host/jz4740_mmc.c b/ANDROID_3.4.5/drivers/mmc/host/jz4740_mmc.c deleted file mode 100644 index c8852a81..00000000 --- a/ANDROID_3.4.5/drivers/mmc/host/jz4740_mmc.c +++ /dev/null @@ -1,1019 +0,0 @@ -/* - * Copyright (C) 2009-2010, Lars-Peter Clausen <lars@metafoo.de> - * JZ4740 SD/MMC controller driver - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#include <linux/mmc/host.h> -#include <linux/err.h> -#include <linux/io.h> -#include <linux/irq.h> -#include <linux/interrupt.h> -#include <linux/module.h> -#include <linux/platform_device.h> -#include <linux/delay.h> -#include <linux/scatterlist.h> -#include <linux/clk.h> - -#include <linux/bitops.h> -#include <linux/gpio.h> -#include <asm/mach-jz4740/gpio.h> -#include <asm/cacheflush.h> -#include <linux/dma-mapping.h> - -#include <asm/mach-jz4740/jz4740_mmc.h> - -#define JZ_REG_MMC_STRPCL 0x00 -#define JZ_REG_MMC_STATUS 0x04 -#define JZ_REG_MMC_CLKRT 0x08 -#define JZ_REG_MMC_CMDAT 0x0C -#define JZ_REG_MMC_RESTO 0x10 -#define JZ_REG_MMC_RDTO 0x14 -#define JZ_REG_MMC_BLKLEN 0x18 -#define JZ_REG_MMC_NOB 0x1C -#define JZ_REG_MMC_SNOB 0x20 -#define JZ_REG_MMC_IMASK 0x24 -#define JZ_REG_MMC_IREG 0x28 -#define JZ_REG_MMC_CMD 0x2C -#define JZ_REG_MMC_ARG 0x30 -#define JZ_REG_MMC_RESP_FIFO 0x34 -#define JZ_REG_MMC_RXFIFO 0x38 -#define JZ_REG_MMC_TXFIFO 0x3C - -#define JZ_MMC_STRPCL_EXIT_MULTIPLE BIT(7) -#define JZ_MMC_STRPCL_EXIT_TRANSFER BIT(6) -#define JZ_MMC_STRPCL_START_READWAIT BIT(5) -#define JZ_MMC_STRPCL_STOP_READWAIT BIT(4) -#define JZ_MMC_STRPCL_RESET BIT(3) -#define JZ_MMC_STRPCL_START_OP BIT(2) -#define JZ_MMC_STRPCL_CLOCK_CONTROL (BIT(1) | BIT(0)) -#define JZ_MMC_STRPCL_CLOCK_STOP BIT(0) -#define JZ_MMC_STRPCL_CLOCK_START BIT(1) - - -#define JZ_MMC_STATUS_IS_RESETTING BIT(15) -#define JZ_MMC_STATUS_SDIO_INT_ACTIVE BIT(14) -#define JZ_MMC_STATUS_PRG_DONE BIT(13) -#define JZ_MMC_STATUS_DATA_TRAN_DONE BIT(12) -#define JZ_MMC_STATUS_END_CMD_RES BIT(11) -#define JZ_MMC_STATUS_DATA_FIFO_AFULL BIT(10) -#define JZ_MMC_STATUS_IS_READWAIT BIT(9) -#define JZ_MMC_STATUS_CLK_EN BIT(8) -#define JZ_MMC_STATUS_DATA_FIFO_FULL BIT(7) -#define JZ_MMC_STATUS_DATA_FIFO_EMPTY BIT(6) -#define JZ_MMC_STATUS_CRC_RES_ERR BIT(5) -#define JZ_MMC_STATUS_CRC_READ_ERROR BIT(4) -#define JZ_MMC_STATUS_TIMEOUT_WRITE BIT(3) -#define JZ_MMC_STATUS_CRC_WRITE_ERROR BIT(2) -#define JZ_MMC_STATUS_TIMEOUT_RES BIT(1) -#define JZ_MMC_STATUS_TIMEOUT_READ BIT(0) - -#define JZ_MMC_STATUS_READ_ERROR_MASK (BIT(4) | BIT(0)) -#define JZ_MMC_STATUS_WRITE_ERROR_MASK (BIT(3) | BIT(2)) - - -#define JZ_MMC_CMDAT_IO_ABORT BIT(11) -#define JZ_MMC_CMDAT_BUS_WIDTH_4BIT BIT(10) -#define JZ_MMC_CMDAT_DMA_EN BIT(8) -#define JZ_MMC_CMDAT_INIT BIT(7) -#define JZ_MMC_CMDAT_BUSY BIT(6) -#define JZ_MMC_CMDAT_STREAM BIT(5) -#define JZ_MMC_CMDAT_WRITE BIT(4) -#define JZ_MMC_CMDAT_DATA_EN BIT(3) -#define JZ_MMC_CMDAT_RESPONSE_FORMAT (BIT(2) | BIT(1) | BIT(0)) -#define JZ_MMC_CMDAT_RSP_R1 1 -#define JZ_MMC_CMDAT_RSP_R2 2 -#define JZ_MMC_CMDAT_RSP_R3 3 - -#define JZ_MMC_IRQ_SDIO BIT(7) -#define JZ_MMC_IRQ_TXFIFO_WR_REQ BIT(6) -#define JZ_MMC_IRQ_RXFIFO_RD_REQ BIT(5) -#define JZ_MMC_IRQ_END_CMD_RES BIT(2) -#define JZ_MMC_IRQ_PRG_DONE BIT(1) -#define JZ_MMC_IRQ_DATA_TRAN_DONE BIT(0) - - -#define JZ_MMC_CLK_RATE 24000000 - -enum jz4740_mmc_state { - JZ4740_MMC_STATE_READ_RESPONSE, - JZ4740_MMC_STATE_TRANSFER_DATA, - JZ4740_MMC_STATE_SEND_STOP, - JZ4740_MMC_STATE_DONE, -}; - -struct jz4740_mmc_host { - struct mmc_host *mmc; - struct platform_device *pdev; - struct jz4740_mmc_platform_data *pdata; - struct clk *clk; - - int irq; - int card_detect_irq; - - struct resource *mem; - void __iomem *base; - struct mmc_request *req; - struct mmc_command *cmd; - - unsigned long waiting; - - uint32_t cmdat; - - uint16_t irq_mask; - - spinlock_t lock; - - struct timer_list timeout_timer; - struct sg_mapping_iter miter; - enum jz4740_mmc_state state; -}; - -static void jz4740_mmc_set_irq_enabled(struct jz4740_mmc_host *host, - unsigned int irq, bool enabled) -{ - unsigned long flags; - - spin_lock_irqsave(&host->lock, flags); - if (enabled) - host->irq_mask &= ~irq; - else - host->irq_mask |= irq; - spin_unlock_irqrestore(&host->lock, flags); - - writew(host->irq_mask, host->base + JZ_REG_MMC_IMASK); -} - -static void jz4740_mmc_clock_enable(struct jz4740_mmc_host *host, - bool start_transfer) -{ - uint16_t val = JZ_MMC_STRPCL_CLOCK_START; - - if (start_transfer) - val |= JZ_MMC_STRPCL_START_OP; - - writew(val, host->base + JZ_REG_MMC_STRPCL); -} - -static void jz4740_mmc_clock_disable(struct jz4740_mmc_host *host) -{ - uint32_t status; - unsigned int timeout = 1000; - - writew(JZ_MMC_STRPCL_CLOCK_STOP, host->base + JZ_REG_MMC_STRPCL); - do { - status = readl(host->base + JZ_REG_MMC_STATUS); - } while (status & JZ_MMC_STATUS_CLK_EN && --timeout); -} - -static void jz4740_mmc_reset(struct jz4740_mmc_host *host) -{ - uint32_t status; - unsigned int timeout = 1000; - - writew(JZ_MMC_STRPCL_RESET, host->base + JZ_REG_MMC_STRPCL); - udelay(10); - do { - status = readl(host->base + JZ_REG_MMC_STATUS); - } while (status & JZ_MMC_STATUS_IS_RESETTING && --timeout); -} - -static void jz4740_mmc_request_done(struct jz4740_mmc_host *host) -{ - struct mmc_request *req; - - req = host->req; - host->req = NULL; - - mmc_request_done(host->mmc, req); -} - -static unsigned int jz4740_mmc_poll_irq(struct jz4740_mmc_host *host, - unsigned int irq) -{ - unsigned int timeout = 0x800; - uint16_t status; - - do { - status = readw(host->base + JZ_REG_MMC_IREG); - } while (!(status & irq) && --timeout); - - if (timeout == 0) { - set_bit(0, &host->waiting); - mod_timer(&host->timeout_timer, jiffies + 5*HZ); - jz4740_mmc_set_irq_enabled(host, irq, true); - return true; - } - - return false; -} - -static void jz4740_mmc_transfer_check_state(struct jz4740_mmc_host *host, - struct mmc_data *data) -{ - int status; - - status = readl(host->base + JZ_REG_MMC_STATUS); - if (status & JZ_MMC_STATUS_WRITE_ERROR_MASK) { - if (status & (JZ_MMC_STATUS_TIMEOUT_WRITE)) { - host->req->cmd->error = -ETIMEDOUT; - data->error = -ETIMEDOUT; - } else { - host->req->cmd->error = -EIO; - data->error = -EIO; - } - } -} - -static bool jz4740_mmc_write_data(struct jz4740_mmc_host *host, - struct mmc_data *data) -{ - struct sg_mapping_iter *miter = &host->miter; - void __iomem *fifo_addr = host->base + JZ_REG_MMC_TXFIFO; - uint32_t *buf; - bool timeout; - size_t i, j; - - while (sg_miter_next(miter)) { - buf = miter->addr; - i = miter->length / 4; - j = i / 8; - i = i & 0x7; - while (j) { - timeout = jz4740_mmc_poll_irq(host, JZ_MMC_IRQ_TXFIFO_WR_REQ); - if (unlikely(timeout)) - goto poll_timeout; - - writel(buf[0], fifo_addr); - writel(buf[1], fifo_addr); - writel(buf[2], fifo_addr); - writel(buf[3], fifo_addr); - writel(buf[4], fifo_addr); - writel(buf[5], fifo_addr); - writel(buf[6], fifo_addr); - writel(buf[7], fifo_addr); - buf += 8; - --j; - } - if (unlikely(i)) { - timeout = jz4740_mmc_poll_irq(host, JZ_MMC_IRQ_TXFIFO_WR_REQ); - if (unlikely(timeout)) - goto poll_timeout; - - while (i) { - writel(*buf, fifo_addr); - ++buf; - --i; - } - } - data->bytes_xfered += miter->length; - } - sg_miter_stop(miter); - - return false; - -poll_timeout: - miter->consumed = (void *)buf - miter->addr; - data->bytes_xfered += miter->consumed; - sg_miter_stop(miter); - - return true; -} - -static bool jz4740_mmc_read_data(struct jz4740_mmc_host *host, - struct mmc_data *data) -{ - struct sg_mapping_iter *miter = &host->miter; - void __iomem *fifo_addr = host->base + JZ_REG_MMC_RXFIFO; - uint32_t *buf; - uint32_t d; - uint16_t status; - size_t i, j; - unsigned int timeout; - - while (sg_miter_next(miter)) { - buf = miter->addr; - i = miter->length; - j = i / 32; - i = i & 0x1f; - while (j) { - timeout = jz4740_mmc_poll_irq(host, JZ_MMC_IRQ_RXFIFO_RD_REQ); - if (unlikely(timeout)) - goto poll_timeout; - - buf[0] = readl(fifo_addr); - buf[1] = readl(fifo_addr); - buf[2] = readl(fifo_addr); - buf[3] = readl(fifo_addr); - buf[4] = readl(fifo_addr); - buf[5] = readl(fifo_addr); - buf[6] = readl(fifo_addr); - buf[7] = readl(fifo_addr); - - buf += 8; - --j; - } - - if (unlikely(i)) { - timeout = jz4740_mmc_poll_irq(host, JZ_MMC_IRQ_RXFIFO_RD_REQ); - if (unlikely(timeout)) - goto poll_timeout; - - while (i >= 4) { - *buf++ = readl(fifo_addr); - i -= 4; - } - if (unlikely(i > 0)) { - d = readl(fifo_addr); - memcpy(buf, &d, i); - } - } - data->bytes_xfered += miter->length; - - /* This can go away once MIPS implements - * flush_kernel_dcache_page */ - flush_dcache_page(miter->page); - } - sg_miter_stop(miter); - - /* For whatever reason there is sometime one word more in the fifo then - * requested */ - timeout = 1000; - status = readl(host->base + JZ_REG_MMC_STATUS); - while (!(status & JZ_MMC_STATUS_DATA_FIFO_EMPTY) && --timeout) { - d = readl(fifo_addr); - status = readl(host->base + JZ_REG_MMC_STATUS); - } - - return false; - -poll_timeout: - miter->consumed = (void *)buf - miter->addr; - data->bytes_xfered += miter->consumed; - sg_miter_stop(miter); - - return true; -} - -static void jz4740_mmc_timeout(unsigned long data) -{ - struct jz4740_mmc_host *host = (struct jz4740_mmc_host *)data; - - if (!test_and_clear_bit(0, &host->waiting)) - return; - - jz4740_mmc_set_irq_enabled(host, JZ_MMC_IRQ_END_CMD_RES, false); - - host->req->cmd->error = -ETIMEDOUT; - jz4740_mmc_request_done(host); -} - -static void jz4740_mmc_read_response(struct jz4740_mmc_host *host, - struct mmc_command *cmd) -{ - int i; - uint16_t tmp; - void __iomem *fifo_addr = host->base + JZ_REG_MMC_RESP_FIFO; - - if (cmd->flags & MMC_RSP_136) { - tmp = readw(fifo_addr); - for (i = 0; i < 4; ++i) { - cmd->resp[i] = tmp << 24; - tmp = readw(fifo_addr); - cmd->resp[i] |= tmp << 8; - tmp = readw(fifo_addr); - cmd->resp[i] |= tmp >> 8; - } - } else { - cmd->resp[0] = readw(fifo_addr) << 24; - cmd->resp[0] |= readw(fifo_addr) << 8; - cmd->resp[0] |= readw(fifo_addr) & 0xff; - } -} - -static void jz4740_mmc_send_command(struct jz4740_mmc_host *host, - struct mmc_command *cmd) -{ - uint32_t cmdat = host->cmdat; - - host->cmdat &= ~JZ_MMC_CMDAT_INIT; - jz4740_mmc_clock_disable(host); - - host->cmd = cmd; - - if (cmd->flags & MMC_RSP_BUSY) - cmdat |= JZ_MMC_CMDAT_BUSY; - - switch (mmc_resp_type(cmd)) { - case MMC_RSP_R1B: - case MMC_RSP_R1: - cmdat |= JZ_MMC_CMDAT_RSP_R1; - break; - case MMC_RSP_R2: - cmdat |= JZ_MMC_CMDAT_RSP_R2; - break; - case MMC_RSP_R3: - cmdat |= JZ_MMC_CMDAT_RSP_R3; - break; - default: - break; - } - - if (cmd->data) { - cmdat |= JZ_MMC_CMDAT_DATA_EN; - if (cmd->data->flags & MMC_DATA_WRITE) - cmdat |= JZ_MMC_CMDAT_WRITE; - if (cmd->data->flags & MMC_DATA_STREAM) - cmdat |= JZ_MMC_CMDAT_STREAM; - - writew(cmd->data->blksz, host->base + JZ_REG_MMC_BLKLEN); - writew(cmd->data->blocks, host->base + JZ_REG_MMC_NOB); - } - - writeb(cmd->opcode, host->base + JZ_REG_MMC_CMD); - writel(cmd->arg, host->base + JZ_REG_MMC_ARG); - writel(cmdat, host->base + JZ_REG_MMC_CMDAT); - - jz4740_mmc_clock_enable(host, 1); -} - -static void jz_mmc_prepare_data_transfer(struct jz4740_mmc_host *host) -{ - struct mmc_command *cmd = host->req->cmd; - struct mmc_data *data = cmd->data; - int direction; - - if (data->flags & MMC_DATA_READ) - direction = SG_MITER_TO_SG; - else - direction = SG_MITER_FROM_SG; - - sg_miter_start(&host->miter, data->sg, data->sg_len, direction); -} - - -static irqreturn_t jz_mmc_irq_worker(int irq, void *devid) -{ - struct jz4740_mmc_host *host = (struct jz4740_mmc_host *)devid; - struct mmc_command *cmd = host->req->cmd; - struct mmc_request *req = host->req; - bool timeout = false; - - if (cmd->error) - host->state = JZ4740_MMC_STATE_DONE; - - switch (host->state) { - case JZ4740_MMC_STATE_READ_RESPONSE: - if (cmd->flags & MMC_RSP_PRESENT) - jz4740_mmc_read_response(host, cmd); - - if (!cmd->data) - break; - - jz_mmc_prepare_data_transfer(host); - - case JZ4740_MMC_STATE_TRANSFER_DATA: - if (cmd->data->flags & MMC_DATA_READ) - timeout = jz4740_mmc_read_data(host, cmd->data); - else - timeout = jz4740_mmc_write_data(host, cmd->data); - - if (unlikely(timeout)) { - host->state = JZ4740_MMC_STATE_TRANSFER_DATA; - break; - } - - jz4740_mmc_transfer_check_state(host, cmd->data); - - timeout = jz4740_mmc_poll_irq(host, JZ_MMC_IRQ_DATA_TRAN_DONE); - if (unlikely(timeout)) { - host->state = JZ4740_MMC_STATE_SEND_STOP; - break; - } - writew(JZ_MMC_IRQ_DATA_TRAN_DONE, host->base + JZ_REG_MMC_IREG); - - case JZ4740_MMC_STATE_SEND_STOP: - if (!req->stop) - break; - - jz4740_mmc_send_command(host, req->stop); - - timeout = jz4740_mmc_poll_irq(host, JZ_MMC_IRQ_PRG_DONE); - if (timeout) { - host->state = JZ4740_MMC_STATE_DONE; - break; - } - case JZ4740_MMC_STATE_DONE: - break; - } - - if (!timeout) - jz4740_mmc_request_done(host); - - return IRQ_HANDLED; -} - -static irqreturn_t jz_mmc_irq(int irq, void *devid) -{ - struct jz4740_mmc_host *host = devid; - struct mmc_command *cmd = host->cmd; - uint16_t irq_reg, status, tmp; - - irq_reg = readw(host->base + JZ_REG_MMC_IREG); - - tmp = irq_reg; - irq_reg &= ~host->irq_mask; - - tmp &= ~(JZ_MMC_IRQ_TXFIFO_WR_REQ | JZ_MMC_IRQ_RXFIFO_RD_REQ | - JZ_MMC_IRQ_PRG_DONE | JZ_MMC_IRQ_DATA_TRAN_DONE); - - if (tmp != irq_reg) - writew(tmp & ~irq_reg, host->base + JZ_REG_MMC_IREG); - - if (irq_reg & JZ_MMC_IRQ_SDIO) { - writew(JZ_MMC_IRQ_SDIO, host->base + JZ_REG_MMC_IREG); - mmc_signal_sdio_irq(host->mmc); - irq_reg &= ~JZ_MMC_IRQ_SDIO; - } - - if (host->req && cmd && irq_reg) { - if (test_and_clear_bit(0, &host->waiting)) { - del_timer(&host->timeout_timer); - - status = readl(host->base + JZ_REG_MMC_STATUS); - - if (status & JZ_MMC_STATUS_TIMEOUT_RES) { - cmd->error = -ETIMEDOUT; - } else if (status & JZ_MMC_STATUS_CRC_RES_ERR) { - cmd->error = -EIO; - } else if (status & (JZ_MMC_STATUS_CRC_READ_ERROR | - JZ_MMC_STATUS_CRC_WRITE_ERROR)) { - if (cmd->data) - cmd->data->error = -EIO; - cmd->error = -EIO; - } else if (status & (JZ_MMC_STATUS_CRC_READ_ERROR | - JZ_MMC_STATUS_CRC_WRITE_ERROR)) { - if (cmd->data) - cmd->data->error = -EIO; - cmd->error = -EIO; - } - - jz4740_mmc_set_irq_enabled(host, irq_reg, false); - writew(irq_reg, host->base + JZ_REG_MMC_IREG); - - return IRQ_WAKE_THREAD; - } - } - - return IRQ_HANDLED; -} - -static int jz4740_mmc_set_clock_rate(struct jz4740_mmc_host *host, int rate) -{ - int div = 0; - int real_rate; - - jz4740_mmc_clock_disable(host); - clk_set_rate(host->clk, JZ_MMC_CLK_RATE); - - real_rate = clk_get_rate(host->clk); - - while (real_rate > rate && div < 7) { - ++div; - real_rate >>= 1; - } - - writew(div, host->base + JZ_REG_MMC_CLKRT); - return real_rate; -} - -static void jz4740_mmc_request(struct mmc_host *mmc, struct mmc_request *req) -{ - struct jz4740_mmc_host *host = mmc_priv(mmc); - - host->req = req; - - writew(0xffff, host->base + JZ_REG_MMC_IREG); - - writew(JZ_MMC_IRQ_END_CMD_RES, host->base + JZ_REG_MMC_IREG); - jz4740_mmc_set_irq_enabled(host, JZ_MMC_IRQ_END_CMD_RES, true); - - host->state = JZ4740_MMC_STATE_READ_RESPONSE; - set_bit(0, &host->waiting); - mod_timer(&host->timeout_timer, jiffies + 5*HZ); - jz4740_mmc_send_command(host, req->cmd); -} - -static void jz4740_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) -{ - struct jz4740_mmc_host *host = mmc_priv(mmc); - if (ios->clock) - jz4740_mmc_set_clock_rate(host, ios->clock); - - switch (ios->power_mode) { - case MMC_POWER_UP: - jz4740_mmc_reset(host); - if (gpio_is_valid(host->pdata->gpio_power)) - gpio_set_value(host->pdata->gpio_power, - !host->pdata->power_active_low); - host->cmdat |= JZ_MMC_CMDAT_INIT; - clk_enable(host->clk); - break; - case MMC_POWER_ON: - break; - default: - if (gpio_is_valid(host->pdata->gpio_power)) - gpio_set_value(host->pdata->gpio_power, - host->pdata->power_active_low); - clk_disable(host->clk); - break; - } - - switch (ios->bus_width) { - case MMC_BUS_WIDTH_1: - host->cmdat &= ~JZ_MMC_CMDAT_BUS_WIDTH_4BIT; - break; - case MMC_BUS_WIDTH_4: - host->cmdat |= JZ_MMC_CMDAT_BUS_WIDTH_4BIT; - break; - default: - break; - } -} - -static int jz4740_mmc_get_ro(struct mmc_host *mmc) -{ - struct jz4740_mmc_host *host = mmc_priv(mmc); - if (!gpio_is_valid(host->pdata->gpio_read_only)) - return -ENOSYS; - - return gpio_get_value(host->pdata->gpio_read_only) ^ - host->pdata->read_only_active_low; -} - -static int jz4740_mmc_get_cd(struct mmc_host *mmc) -{ - struct jz4740_mmc_host *host = mmc_priv(mmc); - if (!gpio_is_valid(host->pdata->gpio_card_detect)) - return -ENOSYS; - - return gpio_get_value(host->pdata->gpio_card_detect) ^ - host->pdata->card_detect_active_low; -} - -static irqreturn_t jz4740_mmc_card_detect_irq(int irq, void *devid) -{ - struct jz4740_mmc_host *host = devid; - - mmc_detect_change(host->mmc, HZ / 2); - - return IRQ_HANDLED; -} - -static void jz4740_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable) -{ - struct jz4740_mmc_host *host = mmc_priv(mmc); - jz4740_mmc_set_irq_enabled(host, JZ_MMC_IRQ_SDIO, enable); -} - -static const struct mmc_host_ops jz4740_mmc_ops = { - .request = jz4740_mmc_request, - .set_ios = jz4740_mmc_set_ios, - .get_ro = jz4740_mmc_get_ro, - .get_cd = jz4740_mmc_get_cd, - .enable_sdio_irq = jz4740_mmc_enable_sdio_irq, -}; - -static const struct jz_gpio_bulk_request jz4740_mmc_pins[] = { - JZ_GPIO_BULK_PIN(MSC_CMD), - JZ_GPIO_BULK_PIN(MSC_CLK), - JZ_GPIO_BULK_PIN(MSC_DATA0), - JZ_GPIO_BULK_PIN(MSC_DATA1), - JZ_GPIO_BULK_PIN(MSC_DATA2), - JZ_GPIO_BULK_PIN(MSC_DATA3), -}; - -static int __devinit jz4740_mmc_request_gpio(struct device *dev, int gpio, - const char *name, bool output, int value) -{ - int ret; - - if (!gpio_is_valid(gpio)) - return 0; - - ret = gpio_request(gpio, name); - if (ret) { - dev_err(dev, "Failed to request %s gpio: %d\n", name, ret); - return ret; - } - - if (output) - gpio_direction_output(gpio, value); - else - gpio_direction_input(gpio); - - return 0; -} - -static int __devinit jz4740_mmc_request_gpios(struct platform_device *pdev) -{ - int ret; - struct jz4740_mmc_platform_data *pdata = pdev->dev.platform_data; - - if (!pdata) - return 0; - - ret = jz4740_mmc_request_gpio(&pdev->dev, pdata->gpio_card_detect, - "MMC detect change", false, 0); - if (ret) - goto err; - - ret = jz4740_mmc_request_gpio(&pdev->dev, pdata->gpio_read_only, - "MMC read only", false, 0); - if (ret) - goto err_free_gpio_card_detect; - - ret = jz4740_mmc_request_gpio(&pdev->dev, pdata->gpio_power, - "MMC read only", true, pdata->power_active_low); - if (ret) - goto err_free_gpio_read_only; - - return 0; - -err_free_gpio_read_only: - if (gpio_is_valid(pdata->gpio_read_only)) - gpio_free(pdata->gpio_read_only); -err_free_gpio_card_detect: - if (gpio_is_valid(pdata->gpio_card_detect)) - gpio_free(pdata->gpio_card_detect); -err: - return ret; -} - -static int __devinit jz4740_mmc_request_cd_irq(struct platform_device *pdev, - struct jz4740_mmc_host *host) -{ - struct jz4740_mmc_platform_data *pdata = pdev->dev.platform_data; - - if (!gpio_is_valid(pdata->gpio_card_detect)) - return 0; - - host->card_detect_irq = gpio_to_irq(pdata->gpio_card_detect); - if (host->card_detect_irq < 0) { - dev_warn(&pdev->dev, "Failed to get card detect irq\n"); - return 0; - } - - return request_irq(host->card_detect_irq, jz4740_mmc_card_detect_irq, - IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, - "MMC card detect", host); -} - -static void jz4740_mmc_free_gpios(struct platform_device *pdev) -{ - struct jz4740_mmc_platform_data *pdata = pdev->dev.platform_data; - - if (!pdata) - return; - - if (gpio_is_valid(pdata->gpio_power)) - gpio_free(pdata->gpio_power); - if (gpio_is_valid(pdata->gpio_read_only)) - gpio_free(pdata->gpio_read_only); - if (gpio_is_valid(pdata->gpio_card_detect)) - gpio_free(pdata->gpio_card_detect); -} - -static inline size_t jz4740_mmc_num_pins(struct jz4740_mmc_host *host) -{ - size_t num_pins = ARRAY_SIZE(jz4740_mmc_pins); - if (host->pdata && host->pdata->data_1bit) - num_pins -= 3; - - return num_pins; -} - -static int __devinit jz4740_mmc_probe(struct platform_device* pdev) -{ - int ret; - struct mmc_host *mmc; - struct jz4740_mmc_host *host; - struct jz4740_mmc_platform_data *pdata; - - pdata = pdev->dev.platform_data; - - mmc = mmc_alloc_host(sizeof(struct jz4740_mmc_host), &pdev->dev); - if (!mmc) { - dev_err(&pdev->dev, "Failed to alloc mmc host structure\n"); - return -ENOMEM; - } - - host = mmc_priv(mmc); - host->pdata = pdata; - - host->irq = platform_get_irq(pdev, 0); - if (host->irq < 0) { - ret = host->irq; - dev_err(&pdev->dev, "Failed to get platform irq: %d\n", ret); - goto err_free_host; - } - - host->clk = clk_get(&pdev->dev, "mmc"); - if (IS_ERR(host->clk)) { - ret = PTR_ERR(host->clk); - dev_err(&pdev->dev, "Failed to get mmc clock\n"); - goto err_free_host; - } - - host->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!host->mem) { - ret = -ENOENT; - dev_err(&pdev->dev, "Failed to get base platform memory\n"); - goto err_clk_put; - } - - host->mem = request_mem_region(host->mem->start, - resource_size(host->mem), pdev->name); - if (!host->mem) { - ret = -EBUSY; - dev_err(&pdev->dev, "Failed to request base memory region\n"); - goto err_clk_put; - } - - host->base = ioremap_nocache(host->mem->start, resource_size(host->mem)); - if (!host->base) { - ret = -EBUSY; - dev_err(&pdev->dev, "Failed to ioremap base memory\n"); - goto err_release_mem_region; - } - - ret = jz_gpio_bulk_request(jz4740_mmc_pins, jz4740_mmc_num_pins(host)); - if (ret) { - dev_err(&pdev->dev, "Failed to request mmc pins: %d\n", ret); - goto err_iounmap; - } - - ret = jz4740_mmc_request_gpios(pdev); - if (ret) - goto err_gpio_bulk_free; - - mmc->ops = &jz4740_mmc_ops; - mmc->f_min = JZ_MMC_CLK_RATE / 128; - mmc->f_max = JZ_MMC_CLK_RATE; - mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; - mmc->caps = (pdata && pdata->data_1bit) ? 0 : MMC_CAP_4_BIT_DATA; - mmc->caps |= MMC_CAP_SDIO_IRQ; - - mmc->max_blk_size = (1 << 10) - 1; - mmc->max_blk_count = (1 << 15) - 1; - mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count; - - mmc->max_segs = 128; - mmc->max_seg_size = mmc->max_req_size; - - host->mmc = mmc; - host->pdev = pdev; - spin_lock_init(&host->lock); - host->irq_mask = 0xffff; - - ret = jz4740_mmc_request_cd_irq(pdev, host); - if (ret) { - dev_err(&pdev->dev, "Failed to request card detect irq\n"); - goto err_free_gpios; - } - - ret = request_threaded_irq(host->irq, jz_mmc_irq, jz_mmc_irq_worker, 0, - dev_name(&pdev->dev), host); - if (ret) { - dev_err(&pdev->dev, "Failed to request irq: %d\n", ret); - goto err_free_card_detect_irq; - } - - jz4740_mmc_reset(host); - jz4740_mmc_clock_disable(host); - setup_timer(&host->timeout_timer, jz4740_mmc_timeout, - (unsigned long)host); - /* It is not important when it times out, it just needs to timeout. */ - set_timer_slack(&host->timeout_timer, HZ); - - platform_set_drvdata(pdev, host); - ret = mmc_add_host(mmc); - - if (ret) { - dev_err(&pdev->dev, "Failed to add mmc host: %d\n", ret); - goto err_free_irq; - } - dev_info(&pdev->dev, "JZ SD/MMC card driver registered\n"); - - return 0; - -err_free_irq: - free_irq(host->irq, host); -err_free_card_detect_irq: - if (host->card_detect_irq >= 0) - free_irq(host->card_detect_irq, host); -err_free_gpios: - jz4740_mmc_free_gpios(pdev); -err_gpio_bulk_free: - jz_gpio_bulk_free(jz4740_mmc_pins, jz4740_mmc_num_pins(host)); -err_iounmap: - iounmap(host->base); -err_release_mem_region: - release_mem_region(host->mem->start, resource_size(host->mem)); -err_clk_put: - clk_put(host->clk); -err_free_host: - platform_set_drvdata(pdev, NULL); - mmc_free_host(mmc); - - return ret; -} - -static int __devexit jz4740_mmc_remove(struct platform_device *pdev) -{ - struct jz4740_mmc_host *host = platform_get_drvdata(pdev); - - del_timer_sync(&host->timeout_timer); - jz4740_mmc_set_irq_enabled(host, 0xff, false); - jz4740_mmc_reset(host); - - mmc_remove_host(host->mmc); - - free_irq(host->irq, host); - if (host->card_detect_irq >= 0) - free_irq(host->card_detect_irq, host); - - jz4740_mmc_free_gpios(pdev); - jz_gpio_bulk_free(jz4740_mmc_pins, jz4740_mmc_num_pins(host)); - - iounmap(host->base); - release_mem_region(host->mem->start, resource_size(host->mem)); - - clk_put(host->clk); - - platform_set_drvdata(pdev, NULL); - mmc_free_host(host->mmc); - - return 0; -} - -#ifdef CONFIG_PM - -static int jz4740_mmc_suspend(struct device *dev) -{ - struct jz4740_mmc_host *host = dev_get_drvdata(dev); - - mmc_suspend_host(host->mmc); - - jz_gpio_bulk_suspend(jz4740_mmc_pins, jz4740_mmc_num_pins(host)); - - return 0; -} - -static int jz4740_mmc_resume(struct device *dev) -{ - struct jz4740_mmc_host *host = dev_get_drvdata(dev); - - jz_gpio_bulk_resume(jz4740_mmc_pins, jz4740_mmc_num_pins(host)); - - mmc_resume_host(host->mmc); - - return 0; -} - -const struct dev_pm_ops jz4740_mmc_pm_ops = { - .suspend = jz4740_mmc_suspend, - .resume = jz4740_mmc_resume, - .poweroff = jz4740_mmc_suspend, - .restore = jz4740_mmc_resume, -}; - -#define JZ4740_MMC_PM_OPS (&jz4740_mmc_pm_ops) -#else -#define JZ4740_MMC_PM_OPS NULL -#endif - -static struct platform_driver jz4740_mmc_driver = { - .probe = jz4740_mmc_probe, - .remove = __devexit_p(jz4740_mmc_remove), - .driver = { - .name = "jz4740-mmc", - .owner = THIS_MODULE, - .pm = JZ4740_MMC_PM_OPS, - }, -}; - -module_platform_driver(jz4740_mmc_driver); - -MODULE_DESCRIPTION("JZ4740 SD/MMC controller driver"); -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); diff --git a/ANDROID_3.4.5/drivers/mmc/host/mmc_atsmb.c b/ANDROID_3.4.5/drivers/mmc/host/mmc_atsmb.c deleted file mode 100755 index 150b7b12..00000000 --- a/ANDROID_3.4.5/drivers/mmc/host/mmc_atsmb.c +++ /dev/null @@ -1,2837 +0,0 @@ -/*++ -linux/drivers/mmc/host/mmc_atsmb.c - -Copyright (c) 2008 WonderMedia Technologies, Inc. - -This program is free software: you can redistribute it and/or modify it under the -terms of the GNU General Public License as published by the Free Software Foundation, -either version 2 of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A -PARTICULAR PURPOSE. See the GNU General Public License for more details. -You should have received a copy of the GNU General Public License along with -this program. If not, see <http://www.gnu.org/licenses/>. - -WonderMedia Technologies, Inc. -10F, 529, Chung-Cheng Road, Hsin-Tien, Taipei 231, R.O.C. ---*/ - -//#include <linux/config.h> -#include <linux/module.h> -#include <linux/moduleparam.h> -#include <linux/init.h> -#include <linux/ioport.h> -#include <linux/device.h> -#include <linux/platform_device.h> -#include <linux/interrupt.h> -#include <linux/delay.h> -#include <linux/err.h> -#include <linux/interrupt.h> -#include <linux/blkdev.h> -#include <linux/mmc/host.h> -#include <linux/mmc/card.h> -#include <linux/mmc/sd.h> -#include <linux/mmc/mmc.h> -#include <linux/mmc/sdio.h> -#include <linux/completion.h> -#include <linux/pagemap.h> -#include <linux/dma-mapping.h> -#include <asm/dma.h> -#include <asm/io.h> -#include <asm/irq.h> -#include <asm/memory.h> -#include <mach/hardware.h> -#include <asm/scatterlist.h> -#include <asm/sizes.h> -#include "mmc_atsmb.h" -//#include <mach/multicard.h> -#include <mach/irqs.h> -#include <linux/regulator/consumer.h> - -#define mprintk - -#if 0 -#define DBG(host, fmt, args...) \ - printk("%s: %s: " fmt, mmc_hostname(host->mmc), __func__ , args) -#endif -#define ATSMB_TIMEOUT_TIME (HZ*2) - - -static struct delayed_work mmc_work; - -static int g_atsmb_regulator; -static struct regulator *atsmb_regulator; - - -//add by jay,for modules support -static u64 wmt_sdmmc_dma_mask = 0xffffffffUL; -static struct resource wmt_sdmmc_resources[] = { - [0] = { - .start = SD0_SDIO_MMC_BASE_ADDR, - .end = (SD0_SDIO_MMC_BASE_ADDR + 0x3FF), - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = IRQ_SDC0, - .end = IRQ_SDC0, - .flags = IORESOURCE_IRQ, - }, - [2] = { - .start = IRQ_SDC0_DMA, - .end = IRQ_SDC0_DMA, - .flags = IORESOURCE_IRQ, - }, - /*2008/10/6 RichardHsu-s*/ - [3] = { - .start = IRQ_PMC_WAKEUP, - .end = IRQ_PMC_WAKEUP, - .flags = IORESOURCE_IRQ, - }, - /*2008/10/6 RichardHsu-e*/ -}; - -struct kobject *atsmb_kobj; -struct mmc_host *mmc_host_attr = NULL; -// -static void atsmb_release(struct device * dev) {} - -/*#ifdef CONFIG_MMC_DEBUG*/ -#define MORE_INFO -#if 0 -#define DBG(x...) printk(KERN_ALERT x) -#define DBGR(x...) do { } while (0) -#else -#define DBG(x...) do { } while (0) -#define DBGR(x...) do { } while (0) -#endif - -/* when Read CRC error occur, and clear read CRC error by software reset.*/ -void atsmb_copy_reg(int direct) -{ - static u8 CTL, CMD_IDX, RSP_TYPE, BUS_MODE, INT_MASK_0, INT_MASK_1, SD_STS_0, SD_STS_1, SD_STS_2, SD_STS_3; - static u8 EXT_BUS_MODE, EXT_CTL_1, EXT_CTL_2, MAN_TUNE_VAL, SD_WRI_TUNE; - static u8 RSP_0, RSP_1, RSP_2, RSP_3, RSP_4, RSP_5, RSP_6, RSP_7; - static u8 RSP_8, RSP_9, RSP_10, RSP_11, RSP_12, RSP_13, RSP_14, RSP_15; - static u8 RSP_TOUT, CLK_SEL, EXT_CTL; - static u16 BLK_LEN, BLK_CNT, SHDW_BLKLEN, TIMER_VAL, CTL2; - static u32 CMD_ARG, CURBLK_CNT; - - /*direct 0: copy register to memory; 1: copy memory to register.*/ - if (direct == 0) { - CTL = *ATSMB0_CTL; - CMD_IDX = *ATSMB0_CMD_IDX; - RSP_TYPE = *ATSMB0_RSP_TYPE; - CMD_ARG = *ATSMB0_CMD_ARG; - BUS_MODE = *ATSMB0_BUS_MODE; - EXT_BUS_MODE = *ATSMB0_EXT_BUS_MODE; - CTL2 = *ATSMB0_CTL2; - BLK_LEN = *ATSMB0_BLK_LEN; - BLK_CNT = *ATSMB0_BLK_CNT; - RSP_0 = *ATSMB0_RSP_0; - RSP_1 = *ATSMB0_RSP_1; - RSP_2 = *ATSMB0_RSP_2; - RSP_3 = *ATSMB0_RSP_3; - RSP_4 = *ATSMB0_RSP_4; - RSP_5 = *ATSMB0_RSP_5; - RSP_6 = *ATSMB0_RSP_6; - RSP_7 = *ATSMB0_RSP_7; - RSP_8 = *ATSMB0_RSP_8; - RSP_9 = *ATSMB0_RSP_9; - RSP_10 = *ATSMB0_RSP_10; - RSP_11 = *ATSMB0_RSP_11; - RSP_12 = *ATSMB0_RSP_12; - RSP_13 = *ATSMB0_RSP_13; - RSP_14 = *ATSMB0_RSP_14; - RSP_15 = *ATSMB0_RSP_15; - CURBLK_CNT = *ATSMB0_CURBLK_CNT; - INT_MASK_0 = *ATSMB0_INT_MASK_0; - INT_MASK_1 = *ATSMB0_INT_MASK_1; - SD_STS_0 = *ATSMB0_SD_STS_0; - SD_STS_1 = *ATSMB0_SD_STS_1; - SD_STS_2 = *ATSMB0_SD_STS_2; - SD_STS_3 = *ATSMB0_SD_STS_3; - RSP_TOUT = *ATSMB0_RSP_TOUT; - CLK_SEL = *ATSMB0_CLK_SEL; - EXT_CTL = *ATSMB0_EXT_CTL; - EXT_CTL_1 = *ATSMB0_EXT_CTL_1; - EXT_CTL_2 = *ATSMB0_EXT_CTL_2; - SHDW_BLKLEN = *ATSMB0_SHDW_BLKLEN; - MAN_TUNE_VAL = *ATSMB0_MAN_TUNE_VAL; - SD_WRI_TUNE = *ATSMB0_SD_WRI_TUNE; - TIMER_VAL = *ATSMB0_TIMER_VAL; - } else { - *ATSMB0_CTL = CTL; - *ATSMB0_CMD_IDX = CMD_IDX; - *ATSMB0_RSP_TYPE = RSP_TYPE; - *ATSMB0_CMD_ARG = CMD_ARG; - *ATSMB0_BUS_MODE = BUS_MODE; - *ATSMB0_EXT_BUS_MODE = EXT_BUS_MODE; - *ATSMB0_CTL2 = CTL2; - *ATSMB0_BLK_LEN = BLK_LEN; - *ATSMB0_BLK_CNT = BLK_CNT; - *ATSMB0_RSP_0 = RSP_0; - *ATSMB0_RSP_1 = RSP_1; - *ATSMB0_RSP_2 = RSP_2; - *ATSMB0_RSP_3 = RSP_3; - *ATSMB0_RSP_4 = RSP_4; - *ATSMB0_RSP_5 = RSP_5; - *ATSMB0_RSP_6 = RSP_6; - *ATSMB0_RSP_7 = RSP_7; - *ATSMB0_RSP_8 = RSP_8; - *ATSMB0_RSP_9 = RSP_9; - *ATSMB0_RSP_10 = RSP_10; - *ATSMB0_RSP_11 = RSP_11; - *ATSMB0_RSP_12 = RSP_12; - *ATSMB0_RSP_13 = RSP_13; - *ATSMB0_RSP_14 = RSP_14; - *ATSMB0_RSP_15 = RSP_15; - *ATSMB0_CURBLK_CNT = CURBLK_CNT; - *ATSMB0_INT_MASK_0 = INT_MASK_0; - *ATSMB0_INT_MASK_1 = INT_MASK_1; - *ATSMB0_SD_STS_0 = SD_STS_0; - *ATSMB0_SD_STS_1 = SD_STS_1; - *ATSMB0_SD_STS_2 = SD_STS_2; - *ATSMB0_SD_STS_3 = SD_STS_3; - *ATSMB0_RSP_TOUT = RSP_TOUT; - *ATSMB0_CLK_SEL = CLK_SEL; - *ATSMB0_EXT_CTL = EXT_CTL; - *ATSMB0_EXT_CTL_1 = EXT_CTL_1; - *ATSMB0_EXT_CTL_2 = EXT_CTL_2; - *ATSMB0_SHDW_BLKLEN = SHDW_BLKLEN; - *ATSMB0_MAN_TUNE_VAL = MAN_TUNE_VAL; - *ATSMB0_SD_WRI_TUNE = SD_WRI_TUNE; - *ATSMB0_TIMER_VAL = TIMER_VAL; - } -} - -#if 0 -void atsmb_dump_reg(void) -{ - u8 CTL, CMD_IDX, RSP_TYPE, BUS_MODE, INT_MASK_0, INT_MASK_1, SD_STS_0, SD_STS_1, SD_STS_2, SD_STS_3; - u8 EXT_BUS_MODE, EXT_CTL_1, EXT_CTL_2, MAN_TUNE_VAL, SD_WRI_TUNE; - u8 RSP_0, RSP_1, RSP_2, RSP_3, RSP_4, RSP_5, RSP_6, RSP_7; - u8 RSP_8, RSP_9, RSP_10, RSP_11, RSP_12, RSP_13, RSP_14, RSP_15; - u8 RSP_TOUT, CLK_SEL, EXT_CTL; - u16 BLK_LEN, BLK_CNT, SHDW_BLKLEN, TIMER_VAL, CTL2; - u32 CMD_ARG, PDMA_GCR, PDMA_IER, PDMA_ISR, PDMA_DESPR, PDMA_RBR, PDMA_DAR, PDMA_BAR, PDMA_CPR, PDMA_CCR; - u32 CURBLK_CNT; - - CTL = *ATSMB0_CTL; - CMD_IDX = *ATSMB0_CMD_IDX; - RSP_TYPE = *ATSMB0_RSP_TYPE; - CMD_ARG = *ATSMB0_CMD_ARG; - BUS_MODE = *ATSMB0_BUS_MODE; - EXT_BUS_MODE = *ATSMB0_EXT_BUS_MODE; - CTL2 = *ATSMB0_CTL2; - BLK_LEN = *ATSMB0_BLK_LEN; - BLK_CNT = *ATSMB0_BLK_CNT; - RSP_0 = *ATSMB0_RSP_0; - RSP_1 = *ATSMB0_RSP_1; - RSP_2 = *ATSMB0_RSP_2; - RSP_3 = *ATSMB0_RSP_3; - RSP_4 = *ATSMB0_RSP_4; - RSP_5 = *ATSMB0_RSP_5; - RSP_6 = *ATSMB0_RSP_6; - RSP_7 = *ATSMB0_RSP_7; - RSP_8 = *ATSMB0_RSP_8; - RSP_9 = *ATSMB0_RSP_9; - RSP_10 = *ATSMB0_RSP_10; - RSP_11 = *ATSMB0_RSP_11; - RSP_12 = *ATSMB0_RSP_12; - RSP_13 = *ATSMB0_RSP_13; - RSP_14 = *ATSMB0_RSP_14; - RSP_15 = *ATSMB0_RSP_15; - CURBLK_CNT = *ATSMB0_CURBLK_CNT; - INT_MASK_0 = *ATSMB0_INT_MASK_0; - INT_MASK_1 = *ATSMB0_INT_MASK_1; - SD_STS_0 = *ATSMB0_SD_STS_0; - SD_STS_1 = *ATSMB0_SD_STS_1; - SD_STS_2 = *ATSMB0_SD_STS_2; - SD_STS_3 = *ATSMB0_SD_STS_3; - RSP_TOUT = *ATSMB0_RSP_TOUT; - CLK_SEL = *ATSMB0_CLK_SEL; - EXT_CTL = *ATSMB0_EXT_CTL; - EXT_CTL_1 = *ATSMB0_EXT_CTL_1; - EXT_CTL_2 = *ATSMB0_EXT_CTL_2; - SHDW_BLKLEN = *ATSMB0_SHDW_BLKLEN; - MAN_TUNE_VAL = *ATSMB0_MAN_TUNE_VAL; - SD_WRI_TUNE = *ATSMB0_SD_WRI_TUNE; - TIMER_VAL = *ATSMB0_TIMER_VAL; - - PDMA_GCR = *ATSMB0_PDMA_GCR; - PDMA_IER = *ATSMB0_PDMA_IER; - PDMA_ISR = *ATSMB0_PDMA_ISR; - PDMA_DESPR = *ATSMB0_PDMA_DESPR; - PDMA_RBR = *ATSMB0_PDMA_RBR; - PDMA_DAR = *ATSMB0_PDMA_DAR; - PDMA_BAR = *ATSMB0_PDMA_BAR; - PDMA_CPR = *ATSMB0_PDMA_CPR; - PDMA_CCR = *ATSMB0_PDMA_CCR; - - DBGR("\n+---------------------------Registers----------------------------+\n"); - - DBGR("%16s = 0x%8x |", "CTL", CTL); - DBGR("%16s = 0x%8x\n", "CMD_IDX", CMD_IDX); - - DBGR("%16s = 0x%8x |", "RSP_TYPE", RSP_TYPE); - DBGR("%16s = 0x%8x\n", "CMD_ARG", CMD_ARG); - - DBGR("%16s = 0x%8x |", "BUS_MODE", BUS_MODE); - DBGR("%16s = 0x%8x\n", "EXT_BUS_MODE", EXT_BUS_MODE); - - DBGR("%16s = 0x%8x |", "CTL2", CTL2); - DBGR("%16s = 0x%8x\n", "BLK_LEN", BLK_LEN); - - DBGR("%16s = 0x%8x |", "BLK_CNT", BLK_CNT); - DBGR("%16s = 0x%8x\n", "RSP_0", RSP_0); - - DBGR("%16s = 0x%8x |", "RSP_1", RSP_1); - DBGR("%16s = 0x%8x\n", "RSP_2", RSP_2); - - DBGR("%16s = 0x%8x |", "RSP_3", RSP_3); - DBGR("%16s = 0x%8x\n", "RSP_4", RSP_4); - - DBGR("%16s = 0x%8x |", "RSP_5", RSP_5); - DBGR("%16s = 0x%8x\n", "RSP_6", RSP_6); - - DBGR("%16s = 0x%8x |", "RSP_7", RSP_7); - DBGR("%16s = 0x%8x\n", "RSP_8", RSP_8); - - DBGR("%16s = 0x%8x |", "RSP_9", RSP_9); - DBGR("%16s = 0x%8x\n", "RSP_10", RSP_10); - - DBGR("%16s = 0x%8x |", "RSP_11", RSP_11); - DBGR("%16s = 0x%8x\n", "RSP_12", RSP_12); - - DBGR("%16s = 0x%8x |", "RSP_13", RSP_13); - DBGR("%16s = 0x%8x\n", "RSP_14", RSP_14); - - DBGR("%16s = 0x%8x\n", "RSP_15", RSP_15); - - DBGR("%16s = 0x%8x |", "CURBLK_CNT", CURBLK_CNT); - DBGR("%16s = 0x%8x\n", "INT_MASK_0", INT_MASK_0); - - DBGR("%16s = 0x%8x |", "INT_MASK_1", INT_MASK_1); - DBGR("%16s = 0x%8x\n", "SD_STS_0", SD_STS_0); - - DBGR("%16s = 0x%8x |", "SD_STS_1", SD_STS_1); - DBGR("%16s = 0x%8x\n", "SD_STS_2", SD_STS_2); - - DBGR("%16s = 0x%8x |", "SD_STS_3", SD_STS_3); - DBGR("%16s = 0x%8x\n", "RSP_TOUT", RSP_TOUT); - - DBGR("%16s = 0x%8x |", "CLK_SEL", CLK_SEL); - DBGR("%16s = 0x%8x\n", "EXT_CTL", EXT_CTL); - - DBGR("%16s = 0x%8x |", "EXT_CTL_1", EXT_CTL_1); - DBGR("%16s = 0x%8x\n", "EXT_CTL_2", EXT_CTL_2); - - DBGR("%16s = 0x%8x |", "SHDW_BLKLEN", SHDW_BLKLEN); - DBGR("%16s = 0x%8x\n", "MAN_TUNE_VAL", MAN_TUNE_VAL); - - DBGR("%16s = 0x%8x |", "SD_WRI_TUNE", SD_WRI_TUNE); - DBGR("%16s = 0x%8x\n", "TIMER_VAL", TIMER_VAL); - - DBGR("%16s = 0x%8x |", "PDMA_GCR", PDMA_GCR); - DBGR("%16s = 0x%8x\n", "PDMA_IER", PDMA_IER); - - DBGR("%16s = 0x%8x |", "PDMA_ISR", PDMA_ISR); - DBGR("%16s = 0x%8x\n", "PDMA_DESPR", PDMA_DESPR); - - DBGR("%16s = 0x%8x |", "PDMA_RBR", PDMA_RBR); - DBGR("%16s = 0x%8x\n", "PDMA_DAR", PDMA_DAR); - - DBGR("%16s = 0x%8x |", "PDMA_BAR", PDMA_BAR); - DBGR("%16s = 0x%8x\n", "PDMA_CPR", PDMA_CPR); - - DBGR("%16s = 0x%8x |", "PDMA_CCR", PDMA_CCR); - DBGR("\n+----------------------------------------------------------------+\n"); -} -#else -void atsmb_dump_reg(void) {} -#endif - -unsigned int fmax0 = 515633; -unsigned int MMC0_DRIVER_VERSION; -int SD0_function = 0; /*0: normal SD/MMC card reader , 1: internal SDIO wifi*/ -int SDXC0_function; -static int SD0_detect_pol = 0; -static int SD0_detect_pulldown = 0; -static int SD0_speed = 0; -//add by kevin guan -int SD0_ro_disable = 0; - -int SCC_ID(void){ - unsigned short val; - - val = REG16_VAL(SYSTEM_CFG_CTRL_BASE_ADDR + 0x2); - return val; -} - -int get_chip_version(void) /*2008/05/01 janshiue modify for A1 chip*/ -{ - u32 tmp; - - tmp = REG32_VAL(SYSTEM_CFG_CTRL_BASE_ADDR); - tmp = ((tmp & 0xF00) >> 4) + 0x90 + ((tmp & 0xFF) - 1); - return tmp; -} - -void get_driver_version(void) -{ - if (SCC_ID() == 0x3426) { - if (get_chip_version() < 0xA1) - MMC0_DRIVER_VERSION = MMC_DRV_3426_A0; - else if (get_chip_version() == 0xA1) - MMC0_DRIVER_VERSION = MMC_DRV_3426_A1; - else - MMC0_DRIVER_VERSION = MMC_DRV_3426_A2; - } else if (SCC_ID() == 0x3437) { - if (get_chip_version() < 0xA1) - MMC0_DRIVER_VERSION = MMC_DRV_3437_A0; - else - MMC0_DRIVER_VERSION = MMC_DRV_3437_A1; - } else if (SCC_ID() == 0x3429) { - MMC0_DRIVER_VERSION = MMC_DRV_3429; - } else if (SCC_ID() == 0x3451) { - if (get_chip_version() < 0xA1) - MMC0_DRIVER_VERSION = MMC_DRV_3451_A0; - } else if (SCC_ID() == 0x3465) { - MMC0_DRIVER_VERSION = MMC_DRV_3465; - } else if (SCC_ID() == 0x3445) { - MMC0_DRIVER_VERSION = MMC_DRV_3445; - } else if (SCC_ID() == 0x3481) { - MMC0_DRIVER_VERSION = MMC_DRV_3481; - } else if (SCC_ID() == 0x3498) { - MMC0_DRIVER_VERSION = MMC_DRV_3498; - } -} -/*2008/10/6 RichardHsu-e*/ - -/********************************************************************** -Name : atsmb_alloc_desc -Function : To config PDMA descriptor setting. -Calls : -Called by : -Parameter : -Author : Janshiue Wu -History : -***********************************************************************/ -static inline int atsmb_alloc_desc(struct atsmb_host *host, - unsigned int bytes) -{ - void *DescPool = NULL; - DBG("[%s] s\n",__func__); - - DescPool = dma_alloc_coherent(host->mmc->parent, bytes, &(host->DescPhyAddr), GFP_KERNEL); - if (!DescPool) { - DBG("can't allocal desc pool=%8X %8X\n", DescPool, host->DescPhyAddr); - DBG("[%s] e1\n",__func__); - return -1; - } - DBG("allocal desc pool=%8X %8X\n", DescPool, host->DescPhyAddr); - host->DescVirAddr = (unsigned long *)DescPool; - host->DescSize = bytes; - DBG("[%s] e2\n",__func__); - return 0; -} - -/********************************************************************** -Name : atsmb_config_desc -Function : To config PDMA descriptor setting. -Calls : -Called by : -Parameter : -Author : Janshiue Wu -History : -***********************************************************************/ -static inline void atsmb_config_desc(unsigned long *DescAddr, - unsigned long *BufferAddr, - unsigned long Blk_Cnt) -{ - - int i = 0 ; - unsigned long *CurDes = DescAddr; - DBG("[%s] s\n",__func__); - - /* the first Descriptor store for 1 Block data - * (512 bytes) - */ - for (i = 0 ; i < 3 ; i++) { - atsmb_init_short_desc(CurDes, 0x80, BufferAddr, 0); - BufferAddr += 0x20; - CurDes += sizeof(struct SD_PDMA_DESC_S)/4; - } - if (Blk_Cnt > 1) { - atsmb_init_long_desc(CurDes, 0x80, BufferAddr, CurDes + (sizeof(struct SD_PDMA_DESC_L)/4), 0); - BufferAddr += 0x20; - CurDes += sizeof(struct SD_PDMA_DESC_L)/4; - /* the following Descriptor store the rest Blocks data - * (Blk_Cnt - 1) * 512 bytes - */ - atsmb_init_long_desc(CurDes, (Blk_Cnt - 1) * 512, - BufferAddr, CurDes + (sizeof(struct SD_PDMA_DESC_L)/4), 1); - } else { - atsmb_init_long_desc(CurDes, 0x80, BufferAddr, CurDes + (sizeof(struct SD_PDMA_DESC_L)/4), 1); - } - DBG("[%s] e\n",__func__); -} -/********************************************************************** -Name : atsmb_config_dma -Function : To set des/src address, byte count to transfer, and DMA channel settings, - and DMA ctrl. register. -Calls : -Called by : -Parameter : -Author : Leo Lee -History : -***********************************************************************/ -static inline void atsmb_config_dma(unsigned long config_dir, - unsigned long dma_mask, - struct atsmb_host *host) -{ - - DBG("[%s] s\n",__func__); - /* Enable DMA */ - *ATSMB0_PDMA_GCR = SD_PDMA_GCR_DMA_EN; - *ATSMB0_PDMA_GCR = SD_PDMA_GCR_SOFTRESET; - *ATSMB0_PDMA_GCR = SD_PDMA_GCR_DMA_EN; - /*open interrupt*/ - *ATSMB0_PDMA_IER = SD_PDMA_IER_INT_EN; - /*Make sure host could co-work with DMA*/ - *ATSMB0_SD_STS_2 |= ATSMB_CLK_FREEZ_EN; - - /*Set timer timeout value*/ - /*If clock is 390KHz*/ - if (host->current_clock < 400000) - *ATSMB0_TIMER_VAL = 0x200; /*1024*512*(1/390K) second*/ - else - *ATSMB0_TIMER_VAL = 0x1fff; /*why not to be 0xffff?*/ - - /*clear all DMA INT status for safety*/ - *ATSMB0_PDMA_ISR |= SD_PDMA_IER_INT_STS; - - /* hook desc */ - *ATSMB0_PDMA_DESPR = host->DescPhyAddr; - if (config_dir == DMA_CFG_WRITE) - *ATSMB0_PDMA_CCR &= SD_PDMA_CCR_IF_to_peripheral; - else - *ATSMB0_PDMA_CCR |= SD_PDMA_CCR_peripheral_to_IF; - - host->DmaIntMask = dma_mask; /*save success event*/ - - *ATSMB0_PDMA_CCR |= SD_PDMA_CCR_RUN; - DBG("[%s] e\n",__func__); -} - -/********************************************************************** -Name : atsmb_set_dma_end -Function : To set all descriptor end bit for removing card when PDMA - don't transfer data done. let PDMA transfer done -Calls : -Called by : -Parameter : -Author : Eason Chien -History : 2013/05/16 -***********************************************************************/ -void atsmb_set_dma_end(unsigned long *DescAddr, unsigned int bytes) -{ - int i = 0; - struct SD_PDMA_DESC_S *CurDes_S; - CurDes_S = (struct SD_PDMA_DESC_S *) DescAddr; - DBG("[%s] s\n", __func__); - DBG("[%s] byte = %d, size of %d\n", __func__, bytes, sizeof(struct SD_PDMA_DESC_S)); - - CurDes_S += 255; - - for (i = 255; i >=0 ;i--) { - /* Set end bit of all descriptor and let PDMA finish as soon as possible */ - CurDes_S->end = 1; - DBG("[%s] %d CurDes 0x%x, 0x%x, e=%x\n", __func__, i, CurDes_S, *CurDes_S); - CurDes_S -= 1; - } - DBG("[%s] e\n", __func__); -} - -/********************************************************************** -Name : atsmb_prep_cmd -Function : -Calls : -Called by : -Parameter : -Author : Leo Lee -History : -***********************************************************************/ -static inline void atsmb_prep_cmd(struct atsmb_host *host, - u32 opcode, - u32 arg, - unsigned int flags, - u16 blk_len, - u16 blk_cnt, - unsigned char int_maks_0, - unsigned char int_mask_1, - unsigned char cmd_type, - unsigned char op) -{ - DBG("[%s] s\n",__func__); - DBG("[%s] s opcode = %u arg = 0x%x flags = 0x%x\n",__func__,opcode,arg,flags); - /*set cmd operation code and arguments.*/ - host->opcode = opcode; - *ATSMB0_CMD_IDX = opcode; /* host->opcode is set for further use in ISR.*/ - *ATSMB0_CMD_ARG = arg; - -#if 0 /* Fixme to support SPI mode, James Tian*/ - if ((flags && MMC_RSP_NONE) == MMC_RSP_NONE) - *ATSMB0_RSP_TYPE = ATMSB_TYPE_R0; - else if ((flags && MMC_RSP_R1) == MMC_RSP_R1) - *ATSMB0_RSP_TYPE = ATMSB_TYPE_R1; - else if ((flags && MMC_RSP_R1B) == MMC_RSP_R1B) - *ATSMB0_RSP_TYPE = ATMSB_TYPE_R1b; - else if ((flags && MMC_RSP_R2) == MMC_RSP_R2) - *ATSMB0_RSP_TYPE = ATMSB_TYPE_R2; - else if ((flags && MMC_RSP_R3) == MMC_RSP_R3) - *ATSMB0_RSP_TYPE = ATMSB_TYPE_R3; - else if ((flags && MMC_RSP_R6) == MMC_RSP_R6) - *ATSMB0_RSP_TYPE = ((opcode != SD_SEND_IF_COND) ? ATMSB_TYPE_R6 : ATMSB_TYPE_R7); - else - *ATSMB0_RSP_TYPE = ATMSB_TYPE_R0; -#endif - -#if 1 - /*set cmd response type*/ - switch (flags) { - case MMC_RSP_NONE | MMC_CMD_AC: - case MMC_RSP_NONE | MMC_CMD_BC: - *ATSMB0_RSP_TYPE = ATMSB_TYPE_R0; - break; - case MMC_RSP_R1 | MMC_CMD_ADTC: - case MMC_RSP_R1 | MMC_CMD_AC: - *ATSMB0_RSP_TYPE = ATMSB_TYPE_R1; - break; - case MMC_RSP_R1B | MMC_CMD_AC: - *ATSMB0_RSP_TYPE = ATMSB_TYPE_R1b; - break; - case MMC_RSP_R2 | MMC_CMD_BCR: - case MMC_RSP_R2 | MMC_CMD_AC: - *ATSMB0_RSP_TYPE = ATMSB_TYPE_R2; - break; - case MMC_RSP_R3 | MMC_CMD_BCR: - *ATSMB0_RSP_TYPE = ATMSB_TYPE_R3; - break; - case MMC_RSP_R6 | MMC_CMD_BCR: /*MMC_RSP_R6 = MMC_RSP_R7.*/ - *ATSMB0_RSP_TYPE = ((opcode != SD_SEND_IF_COND) ? - ATMSB_TYPE_R6 : ATMSB_TYPE_R7); - break; - case MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_AC: - case MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_ADTC: - *ATSMB0_RSP_TYPE = ATMSB_TYPE_R5; - break; - case MMC_RSP_SPI_R4 | MMC_RSP_R4 | MMC_CMD_BCR: - *ATSMB0_RSP_TYPE = ATMSB_TYPE_R4; - break; - default: - *ATSMB0_RSP_TYPE = ATMSB_TYPE_R0; - break; - } -#endif - /*SDIO cmd 52 , 53*/ - if ((opcode == SD_IO_RW_DIRECT) || - (opcode == SD_IO_RW_EXTENDED)) { - *ATSMB0_RSP_TYPE = ATMSB_TYPE_R5; - *ATSMB0_RSP_TYPE |= BIT6; - } - /*SDIO cmd 5*/ - if ((opcode == SD_IO_SEND_OP_COND) && - ((flags & (MMC_RSP_PRESENT| - MMC_RSP_136| - MMC_RSP_CRC| - MMC_RSP_BUSY| - MMC_RSP_OPCODE)) == MMC_RSP_R4)) { - *ATSMB0_RSP_TYPE = ATMSB_TYPE_R4; - *ATSMB0_RSP_TYPE |= BIT6; - } - - /*reset Response FIFO*/ - *ATSMB0_CTL |= 0x08; - - /* SD Host enable Clock */ - *ATSMB0_BUS_MODE |= ATSMB_CST; - - /*Set Cmd-Rsp Timeout to be maximum value.*/ - *ATSMB0_RSP_TOUT = 0xFE; - - /*clear all status registers for safety*/ - *ATSMB0_SD_STS_0 |= 0xff; - *ATSMB0_SD_STS_1 |= 0xff; - *ATSMB0_SD_STS_2 |= 0xff; - //*ATSMB0_SD_STS_2 |= 0x7f; - *ATSMB0_SD_STS_3 |= 0xff; - - //set block length and block count for cmd requesting data - *ATSMB0_BLK_LEN &=~(0x0fff); - *ATSMB0_BLK_LEN |= blk_len; - //*ATSMB0_SHDW_BLKLEN = blk_len; - *ATSMB0_BLK_CNT = blk_cnt; - - - *ATSMB0_INT_MASK_0 |= int_maks_0; - *ATSMB0_INT_MASK_1 |= int_mask_1; - - //Set Auto stop for Multi-block access - if(cmd_type == 3 || cmd_type == 4) { - //auto stop command set. - *ATSMB0_EXT_CTL |= 0x01; - -/* - * Enable transaction abort. - * When CRC error occurs, CMD 12 would be automatically issued. - * That is why we cannot enable R/W CRC error INTs. - * If we enable CRC error INT, we would handle this INT in ISR and then issue CMD 12 via software. - */ -/* Don't auto issue stop command when write command error, -* because auto stop command can freezs PDMA. msut let PDMA transfer done. -* 2013/05/15 by Eason -*/ - if (cmd_type == 4) - *ATSMB0_BLK_LEN |= 0x0800; - } - - /*Set read or write*/ - if (op == 1) - *ATSMB0_CTL &= ~(0x04); - else if (op == 2) - *ATSMB0_CTL |= 0x04; - - /*for Non data access command, command type is 0.*/ - *ATSMB0_CTL &= 0x0F; - *ATSMB0_CTL |= (cmd_type<<4); - DBG("[%s] e\n",__func__); -} - -static inline void atsmb_issue_cmd(void) -{ - *ATSMB0_CTL |= ATSMB_START; - wmb(); -} -/********************************************************************** -Name : atsmb_request_end -Function :. -Calls : -Called by : -Parameter : -Author : Leo Lee -History : -***********************************************************************/ -static void -atsmb_request_end(struct atsmb_host *host, struct mmc_request *mrq) -{ - DBG("[%s] s\n",__func__); - /* - * Need to drop the host lock here; mmc_request_done may call - * back into the driver... - */ - //kevin delete spin lock - //spin_unlock(&host->lock); - /*DBG("100");*/ - mmc_request_done(host->mmc, mrq); - /*DBG("101\n");*/ - //kevin delete spin lock - //spin_lock(&host->lock); - DBG("[%s] e\n",__func__); -} - -/********************************************************************** -Name : atsmb_data_done -Function : -Calls : -Called by : -Parameter : -Author : Leo Lee -History : -***********************************************************************/ -void atsmb_wait_done(void *data) -{ - struct atsmb_host *host = (struct atsmb_host *) data; - DBG("[%s] s\n",__func__); - - WARN_ON(host->done_data == NULL); - complete(host->done_data); - host->done_data = NULL; - host->done = NULL; - DBG("[%s] e\n",__func__); -} - -/********************************************************************** -Name : atsmb_start_data -Function : If we start data, there must be only four cases. -Calls : -Called by : -Parameter : -Author : Leo Lee -History : -***********************************************************************/ -static void atsmb_start_data(struct atsmb_host *host) -{ - DECLARE_COMPLETION(complete); - unsigned char cmd_type = 0; - unsigned char op = 0; /*0: non-operation; 1:read; 2: write*/ - unsigned char mask_0 = 0; - unsigned char mask_1 = 0; - unsigned long dma_mask = 0; - - struct mmc_data *data = host->data; - struct mmc_command *cmd = host->cmd; - - struct scatterlist *sg = NULL; - unsigned int sg_len = 0; - - unsigned int total_blks = 0; /*total block number to transfer*/ - u32 card_addr = 0; - unsigned long dma_len = 0; - unsigned long total_dma_len = 0; - dma_addr_t dma_phy = 0; /* physical address used for DMA*/ - unsigned int dma_times = 0; /*times dma need to transfer*/ - unsigned int dma_loop = 0; - unsigned int sg_num = 0; - int loop_cnt = 10000; - unsigned int sg_transfer_len = 0; /*record each time dma transfer sg length */ - - DBG("[%s] s\n",__func__); - data->bytes_xfered = 0; - cmd->error = 0; - data->error = 0; - - /*for loop*/ - sg = data->sg; - sg_len = data->sg_len; - - dma_times = (sg_len / MAX_DESC_NUM); - if (sg_len % MAX_DESC_NUM) - dma_times++; - DBG("dma_times = %d sg_len = %d sg = %x\n", dma_times, sg_len, sg); - card_addr = cmd->arg; /*may be it is block-addressed, or byte-addressed.*/ - total_blks = data->blocks; - dma_map_sg(&(host->mmc->class_dev), sg, sg_len, - ((data->flags)&MMC_DATA_READ) ? DMA_FROM_DEVICE : DMA_TO_DEVICE); - - - for (dma_loop = 1 ; dma_loop <= dma_times; dma_loop++, sg_len -= sg_transfer_len) { - DBG("dma_loop = %d sg_len = %d sg_transfer_len = %d\n", dma_loop, sg_len, sg_transfer_len); - if (dma_loop < dma_times) - sg_transfer_len = MAX_DESC_NUM; - else - sg_transfer_len = sg_len; - DBG("sg_transfer_len = %d\n", sg_transfer_len); - /* - *Firstly, check and wait till card is in the transfer state. - *For our hardware, we can not consider - *the card has successfully tranfered its state from data/rcv to trans, - *when auto stop INT occurs. - */ - loop_cnt = 10000; - do { - if (host->cmd->opcode == SD_IO_RW_EXTENDED) - break; - loop_cnt--; - WARN_ON(loop_cnt == 0); - host->done_data = &complete; - host->done = &atsmb_wait_done; - host->soft_timeout = 1; - atsmb_prep_cmd(host, - MMC_SEND_STATUS, - (host->mmc->card->rca)<<16, - MMC_RSP_R1 | MMC_CMD_AC, - 0, - 0, - 0, /*mask_0*/ - ATSMB_RSP_DONE_EN - |ATSMB_RSP_CRC_ERR_EN - |ATSMB_RSP_TIMEOUT_EN, - 0, /*cmd type*/ - 0); /*read or write*/ - atsmb_issue_cmd(); - DBG("%16s = 0x%8x |", "INT_MASK_1", *ATSMB0_INT_MASK_1); - DBG("%16s = 0x%8x \n", "SD_STS_1", *ATSMB0_SD_STS_1); - /*ISR would completes it.*/ - wait_for_completion_timeout(&complete, ATSMB_TIMEOUT_TIME); - - WARN_ON(host->soft_timeout == 1); - if (host->soft_timeout == 1) { - DBG("%s soft_timeout.\n", __func__); - atsmb_dump_reg(); - } - if (cmd->error != MMC_ERR_NONE) { - cmd->error = -EIO; //MMC_ERR_FAILED; - DBG("Getting Status failed.\n"); - goto end; - } - } while ((cmd->resp[0] & 0x1f00) != 0x900 && loop_cnt > 0); /*wait for trans state.*/ - - /* - * Now, we can safely issue read/write command. - * We can not consider this request as multi-block acess or single one via opcode, - * as request is splitted into sgs. - * Some sgs may be single one, some sgs may be multi one. - */ - - dma_phy = sg_dma_address(sg); - dma_len = sg_dma_len(sg); - DBG("dma_len = %d data->blksz = %d sg_len = %d\n", dma_len, data->blksz, sg_len); - /*SDIO read/write*/ - if (host->cmd->opcode == SD_IO_RW_EXTENDED) { - /*Single Block read/write*/ - if ((dma_len / (data->blksz)) == 1 && (sg_len == 1)) { - /* read operation*/ - if (data->flags & MMC_DATA_READ) { - host->opcode = SD_IO_RW_EXTENDED; - cmd_type = 2; - op = 1; - mask_0 = 0; /*BLOCK_XFER_DONE INT skipped, we use DMA TC INT*/ - mask_1 = (//ATSMB_SDIO_EN - ATSMB_READ_CRC_ERR_EN - |ATSMB_DATA_TIMEOUT_EN - /*Data Timeout and CRC error */ - |ATSMB_RSP_CRC_ERR_EN - |ATSMB_RSP_TIMEOUT_EN); - /*Resp Timeout and CRC error */ - dma_mask = SD_PDMA_CCR_Evt_success; - DBG("[%s]SR opcode = %d type = 0x%x op = 0x%x m_0 = 0x%x m_1 = 0x%x d_m = 0x%x\n", - __func__,host->opcode,cmd_type,op,mask_0,mask_1,dma_mask); - } else { - /* write operation*/ - host->opcode = SD_IO_RW_EXTENDED; - cmd_type = 1; - op = 2; - /*====That is what we want===== DMA TC INT skipped*/ - mask_0 = ATSMB_BLOCK_XFER_DONE_EN; - mask_1 = (//ATSMB_SDIO_EN - ATSMB_WRITE_CRC_ERR_EN - |ATSMB_DATA_TIMEOUT_EN - /*Data Timeout and CRC error */ - |ATSMB_RSP_CRC_ERR_EN - |ATSMB_RSP_TIMEOUT_EN); - /*Resp Timeout and CRC error */ - dma_mask = 0; - DBG("[%s]SW opcode = %d type = 0x%x op = 0x%x m_0 = 0x%x m_1 = 0x%x d_m = 0x%x\n", - __func__,host->opcode,cmd_type,op,mask_0,mask_1,dma_mask); - } - } else { - /*Multiple Block read/write*/ - /* read operation*/ - if (data->flags & MMC_DATA_READ) { - host->opcode = SD_IO_RW_EXTENDED; - cmd_type = 6; - op = 1; - mask_0 = 0; /*MULTI_XFER_DONE_EN skipped*/ - mask_1 = (//ATSMB_SDIO_EN /*====That is what we want=====*/ - ATSMB_READ_CRC_ERR_EN - |ATSMB_DATA_TIMEOUT_EN - /*Data Timeout and CRC error */ - |ATSMB_RSP_CRC_ERR_EN - |ATSMB_RSP_TIMEOUT_EN); - /*Resp Timeout and CRC error */ - dma_mask = SD_PDMA_CCR_Evt_success; - DBG("[%s]MR opcode = %d type = 0x%x op = 0x%x m_0 = 0x%x m_1 = 0x%x d_m = 0x%x\n", - __func__,host->opcode,cmd_type,op,mask_0,mask_1,dma_mask); - } else { - /* write operation*/ - host->opcode = SD_IO_RW_EXTENDED; - cmd_type = 5; - op = 2; - mask_0 = ATSMB_MULTI_XFER_DONE_EN;//ATSMB_BLOCK_XFER_DONE_EN; /*MULTI_XFER_DONE INT skipped*/ - mask_1 = (//ATSMB_SDIO_EN /*====That is what we want=====*/ - ATSMB_WRITE_CRC_ERR_EN - |ATSMB_DATA_TIMEOUT_EN - /*Data Timeout and CRC error */ - |ATSMB_RSP_CRC_ERR_EN - |ATSMB_RSP_TIMEOUT_EN); - /*Resp Timeout and CRC error */ - dma_mask = 0; - DBG("[%s]MR opcode = %d type = 0x%x op = 0x%x m_0 = 0x%x m_1 = 0x%x d_m = 0x%x\n", - __func__,host->opcode,cmd_type,op,mask_0,mask_1,dma_mask); - } - } - - } else { - if ((dma_len / (data->blksz)) == 1 && (sg_len == 1)) { - if (data->flags & MMC_DATA_READ) {/* read operation*/ - host->opcode = MMC_READ_SINGLE_BLOCK; - cmd_type = 2; - op = 1; - mask_0 = 0; /*BLOCK_XFER_DONE INT skipped, we use DMA TC INT*/ - mask_1 = (ATSMB_READ_CRC_ERR_EN - |ATSMB_DATA_TIMEOUT_EN - /*Data Timeout and CRC error */ - |ATSMB_RSP_CRC_ERR_EN - |ATSMB_RSP_TIMEOUT_EN); - /*Resp Timeout and CRC error */ - dma_mask = SD_PDMA_CCR_Evt_success; - } else {/*write operation*/ - host->opcode = MMC_WRITE_BLOCK; - cmd_type = 1; - op = 2; - /*====That is what we want===== DMA TC INT skipped*/ - mask_0 = ATSMB_BLOCK_XFER_DONE_EN; - mask_1 = (ATSMB_WRITE_CRC_ERR_EN - |ATSMB_DATA_TIMEOUT_EN - /*Data Timeout and CRC error */ - |ATSMB_RSP_CRC_ERR_EN - |ATSMB_RSP_TIMEOUT_EN); - /*Resp Timeout and CRC error */ - dma_mask = 0; - } - } else { /*more than one*/ - if (data->flags&MMC_DATA_READ) {/* read operation*/ - host->opcode = MMC_READ_MULTIPLE_BLOCK; - cmd_type = 4; - op = 1; - mask_0 = 0; /*MULTI_XFER_DONE_EN skipped*/ - mask_1 = (ATSMB_AUTO_STOP_EN /*====That is what we want=====*/ - |ATSMB_DATA_TIMEOUT_EN - /*Data Timeout and CRC error */ - |ATSMB_RSP_CRC_ERR_EN - |ATSMB_RSP_TIMEOUT_EN); - /*Resp Timeout and CRC error */ - dma_mask = 0; - } else {/*write operation*/ - host->opcode = MMC_WRITE_MULTIPLE_BLOCK; - cmd_type = 3; - op = 2; - mask_0 = 0; /*MULTI_XFER_DONE INT skipped*/ - mask_1 = (ATSMB_AUTO_STOP_EN /*====That is what we want=====*/ - |ATSMB_DATA_TIMEOUT_EN - /*Data Timeout and CRC error */ - |ATSMB_RSP_CRC_ERR_EN - |ATSMB_RSP_TIMEOUT_EN); - /*Resp Timeout and CRC error */ - dma_mask = 0; - } - } - } - /*To controller every sg done*/ - host->done_data = &complete; - host->done = &atsmb_wait_done; - /*sleep till ISR wakes us*/ - host->soft_timeout = 1; /*If INT comes early than software timer, it would be cleared.*/ - - total_dma_len = 0; - DBG("host->DescVirAddr = %x host->DescSize=%x\n", host->DescVirAddr, host->DescSize); - memset(host->DescVirAddr, 0, host->DescSize); - for (sg_num = 0 ; sg_num < sg_transfer_len ; sg++, sg_num++) { - - /* - * Now, we can safely issue read/write command. - * We can not consider this request as multi-block acess or single one via opcode, - * as request is splitted into sgs. - * Some sgs may be single one, some sgs may be multi one. - */ - - dma_phy = sg_dma_address(sg); - dma_len = sg_dma_len(sg); - total_dma_len = total_dma_len + dma_len; - DBG("sg_num=%d sg_transfer_len=%d sg=%x sg_len=%d total_dma_len=%d dma_len=%d\n", - sg_num, sg_transfer_len, sg, sg_len, total_dma_len, dma_len); - /*2009/01/15 janshiue add*/ - if (sg_num < sg_transfer_len - 1) { - /* means the last descporitor */ - atsmb_init_short_desc( - host->DescVirAddr + (sg_num * sizeof(struct SD_PDMA_DESC_S)/4), - dma_len, (unsigned long *)dma_phy, 0); - } else { - atsmb_init_short_desc( - host->DescVirAddr + (sg_num * sizeof(struct SD_PDMA_DESC_S)/4), - dma_len, (unsigned long *)dma_phy, 1); - } - /*2009/01/15 janshiue add*/ - - } - /*operate our hardware*/ - atsmb_prep_cmd(host, - host->opcode, - /*arg, may be byte addressed, may be block addressed.*/ - card_addr, - cmd->flags, - data->blksz - 1, /* in fact, it is useless.*/ - /* for single one, it is useless. but for multi one, */ - /* it would be used to tell auto stop function whether it is done.*/ - total_dma_len/(data->blksz), - mask_0, - mask_1, - cmd_type, - op); - - atsmb_config_dma((op == 1) ? DMA_CFG_READ : DMA_CFG_WRITE, - dma_mask, - host); - - atsmb_issue_cmd(); - wait_for_completion_timeout(&complete, - ATSMB_TIMEOUT_TIME*sg_transfer_len); /*ISR would completes it.*/ - - /* When the address of request plus length equal card bound, - * force this stop command response as pass. Eason 2012/4/20 */ - if (cmd->resp[0] == 0x80000b00) { - /*This caes used for SD2.0 and after MMC4.1 version*/ - if (card_addr+(total_dma_len/data->blksz) == host->mmc->card->csd.capacity) { - cmd->resp[0] = 0x00000b00; - /*printk("card_addr = %08X, card_length = %08X,card capacity = %08X\n", - card_addr,(total_dma_len/data->blksz),host->mmc->card->csd.capacity); - printk("card_resp[0]=%08X, addr = %08X\n",cmd->resp[0],cmd->resp);*/ - } - - /* This caes used for SD1.0 and before MMC 4.1 */ - if ((card_addr/data->blksz)+(total_dma_len/data->blksz) == host->mmc->card->csd.capacity) { - cmd->resp[0] = 0x00000b00; - /*printk("Eason test: cmd->arg = %08X, data->blksz = %08X, length = %08X\n", - card_addr,data->blksz,(total_dma_len/data->blksz));*/ - } - } - - if (host->soft_timeout == 1) { - atsmb_dump_reg(); - //*ATSMB0_BUS_MODE |= ATSMB_SFTRST; - *ATSMB0_PDMA_GCR = SD_PDMA_GCR_SOFTRESET; - /*disable INT */ - *ATSMB0_INT_MASK_0 &= ~(ATSMB_BLOCK_XFER_DONE_EN | ATSMB_MULTI_XFER_DONE_EN); - *ATSMB0_INT_MASK_1 &= ~(ATSMB_WRITE_CRC_ERR_EN|ATSMB_READ_CRC_ERR_EN|ATSMB_RSP_CRC_ERR_EN - |ATSMB_DATA_TIMEOUT_EN|ATSMB_AUTO_STOP_EN|ATSMB_RSP_TIMEOUT_EN|ATSMB_RSP_DONE_EN); - - cmd->error = -ETIMEDOUT; - data->error = -ETIMEDOUT; - } - - WARN_ON(host->soft_timeout == 1); - - /*check everything goes okay or not*/ - if (cmd->error != MMC_ERR_NONE - || data->error != MMC_ERR_NONE) { - DBG("CMD or Data failed error=%X DescVirAddr=%8X dma_phy=%8X dma_mask = %x\n", - cmd->error, host->DescVirAddr, dma_phy, host->DmaIntMask); - goto end; - } -// card_addr += total_dma_len>>(mmc_card_blockaddr(host->mmc->card_selected) ? 9 : 0); - card_addr += total_dma_len>>(mmc_card_blockaddr(host->mmc->card) ? 9 : 0); //zhf: modified by James Tian - data->bytes_xfered += total_dma_len; - - - } -// dma_unmap_sg(&(host->mmc->class_dev), data->sg, data->sg_len, -// ((data->flags)&MMC_DATA_READ) ? DMA_FROM_DEVICE : DMA_TO_DEVICE); - - WARN_ON(total_blks != (data->bytes_xfered / data->blksz)); - host->opcode = 0; -end: - dma_unmap_sg(&(host->mmc->class_dev), data->sg, data->sg_len, - ((data->flags)&MMC_DATA_READ) ? DMA_FROM_DEVICE : DMA_TO_DEVICE); - spin_lock(&host->lock); - atsmb_request_end(host, host->mrq); - spin_unlock(&host->lock); - DBG("[%s] e\n",__func__); -} - - -/********************************************************************** -Name : atsmb_cmd_with_data_back -Function : -Calls : -Called by : -Parameter : -Author : Leo Lee -History : -***********************************************************************/ -static void atsmb_cmd_with_data_back(struct atsmb_host *host) -{ - DECLARE_COMPLETION(complete); - - struct scatterlist *sg = NULL; - unsigned int sg_len = 0; - DBG("[%s] s\n",__func__); - /*for loop*/ - sg = host->data->sg; - sg_len = host->data->sg_len; - /*To controller every sg done*/ - host->done_data = &complete; - host->done = &atsmb_wait_done; - dma_map_sg(&(host->mmc->class_dev), sg, sg_len, DMA_FROM_DEVICE); - - /*2009/01/15 janshiue add*/ - memset(host->DescVirAddr, 0, host->DescSize); - atsmb_init_long_desc(host->DescVirAddr, sg_dma_len(sg), (unsigned long *)sg_dma_address(sg), 0, 1); - /*2009/01/15 janshiue add*/ - /*prepare for cmd*/ - atsmb_prep_cmd(host, /*host*/ - host->cmd->opcode, /*opcode*/ - host->cmd->arg, /*arg*/ - host->cmd->flags, /*flags*/ - sg_dma_len(sg)-1, /*block length*/ - 0, /*block size: It looks like useless*/ - 0, /*int_mask_0*/ - (ATSMB_RSP_CRC_ERR_EN|ATSMB_RSP_TIMEOUT_EN - |ATSMB_READ_CRC_ERR_EN |ATSMB_DATA_TIMEOUT_EN), /*int_mask_1*/ - 2, /*cmd_type*/ - 1); /*op*/ - - atsmb_config_dma(DMA_CFG_READ, - SD_PDMA_CCR_Evt_success, - host); - atsmb_issue_cmd(); - /*ISR would completes it.*/ - wait_for_completion_timeout(&complete, ATSMB_TIMEOUT_TIME); - - dma_unmap_sg(&(host->mmc->class_dev), host->data->sg, host->data->sg_len, - ((host->data->flags)&MMC_DATA_READ) ? DMA_FROM_DEVICE : DMA_TO_DEVICE); - spin_lock(&host->lock); - atsmb_request_end(host, host->mrq); - spin_unlock(&host->lock); - DBG("[%s] e\n",__func__); -} -/********************************************************************** -Name : atsmb_start_cmd -Function : -Calls : -Called by : -Parameter : -Author : Leo Lee -History : -***********************************************************************/ -static void atsmb_start_cmd(struct atsmb_host *host) -{ - unsigned char int_mask_0,int_mask_1; - int_mask_0 = 0; - int_mask_1 = ATSMB_RSP_DONE_EN|ATSMB_RSP_CRC_ERR_EN|ATSMB_RSP_TIMEOUT_EN; - - DBG("[%s] s\n",__func__); - - atsmb_prep_cmd(host, - host->cmd->opcode, - host->cmd->arg, - host->cmd->flags, - 0, /*useless*/ - 0, /*useless*/ - int_mask_0, /*mask_0*/ - int_mask_1, /*mask_1*/ - 0, /*cmd type*/ - 0); /*read or write*/ - atsmb_issue_cmd(); - DBG("[%s] e\n",__func__); -} -/********************************************************************** -Name : atsmb_fmt_check_rsp -Function : -Calls : -Called by : -Parameter : -Author : Leo Lee -History : -***********************************************************************/ -static inline void atsmb_fmt_check_rsp(struct atsmb_host *host) -{ - - u8 tmp_resp[4] = {0}; - int i, j, k; - DBG("[%s] s\n",__func__); - if (host->cmd->flags != (MMC_RSP_R2 | MMC_CMD_AC) - && host->cmd->flags != (MMC_RSP_R2 | MMC_CMD_BCR)) { - for (j = 0, k = 1; j < 4; j++, k++) - tmp_resp[j] = *(REG8_PTR(_RSP_0 + MMC_ATSMB0_BASE+k)); - - host->cmd->resp[0] = (tmp_resp[0] << 24) | - (tmp_resp[1]<<16) | (tmp_resp[2]<<8) | (tmp_resp[3]); - } else { - for (i = 0, k = 1; i < 4; i++) { /*R2 has 4 u32 response.*/ - for (j = 0; j < 4; j++) { - if (k < 16) - tmp_resp[j] = *(REG8_PTR(_RSP_0 + MMC_ATSMB0_BASE+k)); - else /* k =16*/ - tmp_resp[j] = *(ATSMB0_RSP_0); - k++; - } - host->cmd->resp[i] = (tmp_resp[0]<<24) | (tmp_resp[1]<<16) | - (tmp_resp[2]<<8) | (tmp_resp[3]); - } - } - - /* - * For the situation that we need response, - * but response registers give us all zeros, we consider this operation timeout. - */ - if (host->cmd->flags != (MMC_RSP_NONE | MMC_CMD_AC) - && host->cmd->flags != (MMC_RSP_NONE | MMC_CMD_BC)) { - if (host->cmd->resp[0] == 0 && host->cmd->resp[1] == 0 - && host->cmd->resp[2] == 0 && host->cmd->resp[3] == 0) { - host->cmd->error = -ETIMEDOUT; //zhf: modified by James Tian - } - } - DBG("[%s] e\n",__func__); -} -/********************************************************************** -Name : atsmb_get_slot_status -Function : Our host only supports one slot. -Calls : -Called by : -Parameter : -returns : 1: in slot; 0: not in slot. -Author : Leo Lee -History : -***********************************************************************/ -static int atsmb_get_slot_status(struct mmc_host *mmc) -{ -// struct atsmb_host *host = mmc_priv(mmc); - unsigned char status_0 = 0; -// unsigned long flags; - unsigned long ret = 0; - DBG("[%s] s\n",__func__); -// spin_lock_irqsave(&host->lock, flags); // Vincent Li mark out for CONFIG_PREEMPT_RT - status_0 = *ATSMB0_SD_STS_0; -// spin_unlock_irqrestore(&host->lock, flags); // Vincent Li mark out for CONFIG_PREEMPT_RT - /* after WM3400 A1 ATSMB_CARD_IN_SLOT_GPI = 1 means not in slot*/ - if (MMC0_DRIVER_VERSION >= MMC_DRV_3426_A0) { - if(SD0_detect_pol) - ret = ((status_0 & ATSMB_CARD_NOT_IN_SLOT_GPI) ? 1 : 0); - else - ret = ((status_0 & ATSMB_CARD_NOT_IN_SLOT_GPI) ? 0 : 1); - - DBG("[%s] e1\n",__func__); - return ret; - } else { - ret = ((status_0 & ATSMB_CARD_NOT_IN_SLOT_GPI) ? 1 : 0); - DBG("[%s] e2\n",__func__); - return ret; - } - DBG("[%s] e3\n",__func__); - return 0; -} - -/********************************************************************** -Name : atsmb_init_short_desc -Function : -Calls : -Called by : -Parameter : -Author : Janshiue Wu -History : -***********************************************************************/ -int atsmb_init_short_desc(unsigned long *DescAddr, unsigned int ReqCount, unsigned long *BufferAddr, int End) -{ - struct SD_PDMA_DESC_S *CurDes_S; - DBG("[%s] s\n",__func__); - CurDes_S = (struct SD_PDMA_DESC_S *) DescAddr; - CurDes_S->ReqCount = ReqCount; - CurDes_S->i = 0; - CurDes_S->format = 0; - CurDes_S->DataBufferAddr = BufferAddr; - if (End) { - CurDes_S->end = 1; - CurDes_S->i = 1; - } - DBG("[%s] e\n",__func__); - return 0; -} - -/********************************************************************** -Name : atsmb_init_long_desc -Function : -Calls : -Called by : -Parameter : -Author : Janshiue Wu -History : -***********************************************************************/ -int atsmb_init_long_desc(unsigned long *DescAddr, unsigned int ReqCount, - unsigned long *BufferAddr, unsigned long *BranchAddr, int End) -{ - struct SD_PDMA_DESC_L *CurDes_L; - DBG("[%s] s\n",__func__); - CurDes_L = (struct SD_PDMA_DESC_L *) DescAddr; - CurDes_L->ReqCount = ReqCount; - CurDes_L->i = 0; - CurDes_L->format = 1; - CurDes_L->DataBufferAddr = BufferAddr; - CurDes_L->BranchAddr = BranchAddr; - if (End) { - CurDes_L->end = 1; - CurDes_L->i = 1; - } - DBG("[%s] e\n",__func__); - return 0; -} - -/********************************************************************** -Name : atsmb_dma_isr -Function :. -Calls : -Called by : -Parameter : -Author : Leo Lee -History : -***********************************************************************/ -static irqreturn_t atsmb_dma_isr(int irq, void *dev_id) -{ - - struct atsmb_host *host = dev_id; - u8 status_0, status_1, status_2, status_3; - u32 pdma_event_code = 0; - DBG("[%s] s\n",__func__); - - disable_irq_nosync(irq); - spin_lock(&host->lock); - /*Get INT status*/ - status_0 = *ATSMB0_SD_STS_0; - status_1 = *ATSMB0_SD_STS_1; - status_2 = *ATSMB0_SD_STS_2; - status_3 = *ATSMB0_SD_STS_3; - /* after WM3426 A0 using PDMA */ - if (MMC0_DRIVER_VERSION >= MMC_DRV_3426_A0) { - - pdma_event_code = *ATSMB0_PDMA_CCR & SD_PDMA_CCR_EvtCode; - - /* clear INT status to notify HW clear EventCode*/ - *ATSMB0_PDMA_ISR |= SD_PDMA_IER_INT_STS; - - /*printk("dma_isr event code = %X\n", *ATSMB0_PDMA_CCR);*/ - /*We expect cmd with data sending back or read single block cmd run here.*/ - if (pdma_event_code == SD_PDMA_CCR_Evt_success) { - /*means need to update the data->error and cmd->error*/ - if (host->DmaIntMask == SD_PDMA_CCR_Evt_success) { - if (host->data != NULL) { - host->data->error = MMC_ERR_NONE; - host->cmd->error = MMC_ERR_NONE; - } else { - DBG("dma_isr host->data is NULL\n"); - /*disable INT*/ - *ATSMB0_PDMA_IER &= ~SD_PDMA_IER_INT_EN; - goto out; - } - } - /*else do nothing*/ - DBG("dma_isr PDMA OK\n"); - /*atsmb_dump_reg();*/ - } - /*But unluckily, we should also be prepare for all kinds of error situation.*/ - else { - host->data->error = -EIO; //MMC_ERR_FAILED; - host->cmd->error = -EIO; //MMC_ERR_FAILED; - DBG("** dma_isr PDMA fail** event code = %X\n", *ATSMB0_PDMA_CCR); - atsmb_dump_reg(); - } - - if (host->DmaIntMask == SD_PDMA_CCR_Evt_success) - atsmb_fmt_check_rsp(host); - - /*disable INT*/ - *ATSMB0_PDMA_IER &= ~SD_PDMA_IER_INT_EN; - } - - /*wake up some one who is sleeping.*/ - if ((pdma_event_code != SD_PDMA_CCR_Evt_success) || (host->DmaIntMask == SD_PDMA_CCR_Evt_success)) { - if (host->done_data) {/* We only use done_data when requesting data.*/ - host->soft_timeout = 0; - host->done(host); - } else - atsmb_request_end(host, host->mrq); /*for cmd with data sending back.*/ - } - -out: - spin_unlock(&host->lock); - enable_irq(irq); - DBG("[%s] e\n",__func__); - return IRQ_HANDLED; -} - -/********************************************************************** -Name : atsmb_regular_isr -Function :. -Calls : -Called by : -Parameter : -Author : Leo Lee -History : -***********************************************************************/ -//static irqreturn_t atsmb_regular_isr(int irq, void *dev_id, struct pt_regs *regs) -irqreturn_t atsmb_regular_isr(int irq, void *dev_id) -{ - - struct atsmb_host *host = dev_id; - u8 status_0, status_1, status_2, status_3,mask_0,mask_1; - u32 pdma_sts; - - DBG("[%s] s\n",__func__); - WARN_ON(host == NULL); - - disable_irq_nosync(irq); - spin_lock(&host->lock); - - /*Get INT status*/ - status_0 = *ATSMB0_SD_STS_0; - status_1 = *ATSMB0_SD_STS_1; - status_2 = *ATSMB0_SD_STS_2; - status_3 = *ATSMB0_SD_STS_3; - - mask_0 = *ATSMB0_INT_MASK_0; - mask_1 = *ATSMB0_INT_MASK_1; - /******************************************************* - card insert interrupt - ********************************************************/ - if ((status_0 & ATSMB_DEVICE_INSERT) /*Status Set and IRQ enabled*/ - /*To aviod the situation that we intentionally disable IRQ to do rescan.*/ - && (*ATSMB0_INT_MASK_0 & 0x80)) { - - if (host->mmc->ops->get_slot_status(host->mmc)) { - host->mmc->scan_retry = 3; - host->mmc->card_scan_status = false; - } else { - host->mmc->scan_retry = 0; - host->mmc->card_scan_status = false; - } - - mmc_detect_change(host->mmc, HZ/2); - /*Taipei Side Request: Disable INSERT IRQ when doing rescan.*/ - //*ATSMB0_INT_MASK_0 &= (~0x80);/* or 40?*/ //zhf: marked by James Tian - /*Then we clear the INT status*/ - //iowrite32(ATSMB_DEVICE_INSERT, host->base+_SD_STS_0); - *ATSMB0_SD_STS_0 |= ATSMB_DEVICE_INSERT; - spin_unlock(&host->lock); - enable_irq(irq); - DBG("[%s] e1\n",__func__); - return IRQ_HANDLED; - } - - if ((status_1 & mask_1)& ATSMB_SDIO_INT) { - spin_unlock(&host->lock); - mmc_signal_sdio_irq(host->mmc); - - if (((status_1 & mask_1) == ATSMB_SDIO_INT) && ((status_0 & mask_0) == 0)) { - - enable_irq(irq); - DBG("[%s] e2\n",__func__); - - return IRQ_HANDLED; - } - spin_lock(&host->lock); - } - pdma_sts = *ATSMB0_PDMA_CCR; - - if (((status_0 & mask_0) | (status_1 & mask_1)) == 0) { - spin_unlock(&host->lock); - enable_irq(irq); - DBG("[%s] e3\n",__func__); - return IRQ_HANDLED; - } - /******************************************************* - command interrupt. - *******************************************************/ - /*for write single block*/ - if (host->opcode == MMC_WRITE_BLOCK) { - if ((status_0 & ATSMB_BLOCK_XFER_DONE) - && (status_1 & ATSMB_RSP_DONE)) { - host->data->error = MMC_ERR_NONE; - host->cmd->error = MMC_ERR_NONE; - /* okay, what we want.*/ - } else { - host->data->error = -EIO; //MMC_ERR_FAILED; - host->cmd->error = -EIO; //MMC_ERR_FAILED; - DBG("[%s] err1\n",__func__); - atsmb_dump_reg(); - } - } else if (host->opcode == MMC_WRITE_MULTIPLE_BLOCK - || host->opcode == MMC_READ_MULTIPLE_BLOCK) { - if ((status_1 & (ATSMB_AUTO_STOP|ATSMB_RSP_DONE)) - && (status_0 & ATSMB_MULTI_XFER_DONE)) { - /*If CRC error occurs, I think this INT would not occrs.*/ - /*okay, that is what we want.*/ - host->data->error = MMC_ERR_NONE; - host->cmd->error = MMC_ERR_NONE; - } else { - host->data->error = -EIO; //MMC_ERR_FAILED; - host->cmd->error = -EIO; //MMC_ERR_FAILED; - DBG("[%s] err2\n",__func__); - atsmb_dump_reg(); - - } - } else if (host->opcode == MMC_READ_SINGLE_BLOCK) {/* we want DMA TC, run here, must be error.*/ - host->data->error = -EIO; //MMC_ERR_FAILED; - host->cmd->error = -EIO; //MMC_ERR_FAILED; - DBG("[%s] err3\n",__func__); - atsmb_dump_reg(); - } else if (host->opcode == SD_IO_RW_EXTENDED){ - /*Write operation*/ - if (*ATSMB0_CTL & BIT2) { - if ((*ATSMB0_CTL & 0xf0) == 0x10) { /*single block write*/ - if ((status_0 & ATSMB_BLOCK_XFER_DONE) - && (status_1 & ATSMB_RSP_DONE)) { - host->data->error = MMC_ERR_NONE; - host->cmd->error = MMC_ERR_NONE; - /* okay, what we want.*/ - } else { - host->data->error = -EIO; //MMC_ERR_FAILED; - host->cmd->error = -EIO; //MMC_ERR_FAILED; - DBG("[%s] err4 status_0 = %x status_1 = %x\n",__func__,status_0,status_1); - } - - } else if ((*ATSMB0_CTL & 0xf0) == 0x50) { - if ((status_0 & ATSMB_MULTI_XFER_DONE) - && (status_1 & ATSMB_RSP_DONE)) { - host->data->error = MMC_ERR_NONE; - host->cmd->error = MMC_ERR_NONE; - /* okay, what we want.*/ - } else { - host->data->error = -EIO; //MMC_ERR_FAILED; - host->cmd->error = -EIO; //MMC_ERR_FAILED; - DBG("[%s] err4-2 status_0 = %x status_1 = %x\n",__func__,status_0,status_1); - } - } else { - host->data->error = -EIO; //MMC_ERR_FAILED; - host->cmd->error = -EIO; //MMC_ERR_FAILED; - DBG("[%s] err4-3 status_0 = %x status_1 = %x\n",__func__,status_0,status_1); - } - } - else { - /*Read operation*/ - host->data->error = -EIO; //MMC_ERR_FAILED; - host->cmd->error = -EIO; //MMC_ERR_FAILED; - DBG("[%s] err5\n",__func__); - } - - - } else { -/* command, not request data*/ -/* the command which need data sending back,*/ -/* like switch_function, send_ext_csd, send_scr, send_num_wr_blocks.*/ -/* NOTICE: we also send status before reading or writing data, so SEND_STATUS should be excluded.*/ - if (host->data && host->opcode != MMC_SEND_STATUS) { - host->data->error = -EIO; //MMC_ERR_FAILED; - host->cmd->error = -EIO; //MMC_ERR_FAILED; - DBG("[%s] err6\n",__func__); - atsmb_dump_reg(); - } else { /* Just command, no need data sending back.*/ - if (status_1 & ATSMB_RSP_DONE) { - /*Firstly, check data-response is busy or not.*/ - if (host->cmd->flags == (MMC_RSP_R1B | MMC_CMD_AC)) { - int i = 10000; - - while (status_2 & ATSMB_RSP_BUSY) { - status_2 = *ATSMB0_SD_STS_2; - if (--i == 0) - break; - DBG(" IRQ:Status_2 = %d, busy!\n", status_2); - } - if (i == 0) - printk("[MMC driver] Error :SD data-response always busy!"); - } -#if 1 -/*for our host, even no card in slot, for SEND_STATUS also returns no error.*/ -/*The protocol layer depends on SEND_STATUS to check whether card is in slot or not.*/ -/*In fact, we can also avoid this situation by checking the response whether they are all zeros.*/ - if (!atsmb_get_slot_status(host->mmc) && host->opcode == MMC_SEND_STATUS) { - host->cmd->retries = 0; /* No retry.*/ -// host->cmd->error = MMC_ERR_INVALID; - host->cmd->error = -EINVAL; - } else -#endif - host->cmd->error = MMC_ERR_NONE; - } else { - if (status_1 & ATSMB_RSP_TIMEOUT) {/* RSP_Timeout .*/ -// host->cmd->error = MMC_ERR_TIMEOUT; - host->cmd->error = -ETIMEDOUT; - DBG("[%s] err7\n",__func__); - } else {/*or RSP CRC error*/ -// host->cmd->error = MMC_ERR_BADCRC; - host->cmd->error = -EILSEQ; - DBG("[%s] err8\n",__func__); - } - atsmb_dump_reg(); - } - } - } - atsmb_fmt_check_rsp(host); - - /*disable INT */ - *ATSMB0_INT_MASK_0 &= ~(ATSMB_BLOCK_XFER_DONE_EN | ATSMB_MULTI_XFER_DONE_EN); - *ATSMB0_INT_MASK_1 &= ~(ATSMB_WRITE_CRC_ERR_EN|ATSMB_READ_CRC_ERR_EN|ATSMB_RSP_CRC_ERR_EN - |ATSMB_DATA_TIMEOUT_EN|ATSMB_AUTO_STOP_EN|ATSMB_RSP_TIMEOUT_EN|ATSMB_RSP_DONE_EN); - - - /*clear INT status. In fact, we will clear again before issuing new command.*/ - *ATSMB0_SD_STS_0 |= status_0; - *ATSMB0_SD_STS_1 |= status_1; - - /* when read CRC error occur, and the status can't write one to clear. - * To clear read CRC error status , can do software reset. This is HW bug. 2013/3/21*/ - if ((*ATSMB0_SD_STS_1 & BIT6) == 0x40) { - DBG("[%s] host0 CMD%d Read CRC error occur\n",__func__,host->cmd->opcode); - /* Save SD card register */ - atsmb_copy_reg(0); - /* Software reset */ - *ATSMB0_BUS_MODE |= BIT7; - /* restore SD card register */ - atsmb_copy_reg(1); - } - - if (*ATSMB0_PDMA_ISR & SD_PDMA_IER_INT_STS) - *ATSMB0_PDMA_ISR |= SD_PDMA_IER_INT_STS; - - /*wake up some one who is sleeping.*/ - if (host->done_data) { /* We only use done_data when requesting data.*/ - host->soft_timeout = 0; - host->done(host); - } else - atsmb_request_end(host, host->mrq); /*for cmd without data.*/ - - spin_unlock(&host->lock); - enable_irq(irq); - DBG("[%s] e4\n",__func__); - return IRQ_HANDLED; -} -EXPORT_SYMBOL(atsmb_regular_isr); - -/********************************************************************** -Name : atsmb_get_ro -Function :. -Calls : -Called by : -Parameter : -returns : 0 : write protection is disabled. 1: write protection is enabled. -Author : Leo Lee -History : -***********************************************************************/ -int atsmb_get_ro(struct mmc_host *mmc) -{ - struct atsmb_host *host = mmc_priv(mmc); - unsigned char status_0 = 0; - unsigned long flags; - unsigned long ret = 0; - DBG("[%s] s\n",__func__); - //add by kevin guan - if(SD0_ro_disable) - return 0; - spin_lock_irqsave(&host->lock, flags); - status_0 = *ATSMB0_SD_STS_0; - spin_unlock_irqrestore(&host->lock, flags); - DBG("[%s]\nstatus_0 = 0x%x\n", __func__,status_0); - ret = ((status_0 & ATSMB_WRITE_PROTECT) ? 0 : 1); - DBG("[%s] e\n",__func__); - return ret; -} -/********************************************************************** -Name : atsmb_dump_host_regs -Function : -Calls : -Called by : -Parameter : -returns : -Author : Leo Lee -History : -***********************************************************************/ -void atsmb_dump_host_regs(struct mmc_host *mmc) -{ - DBG("[%s] s\n",__func__); - atsmb_dump_reg(); - DBG("[%s] e\n",__func__); -} -EXPORT_SYMBOL(atsmb_dump_host_regs); - -/********************************************************************** -Name : atsmb_enable_sdio_irq -Function : -Calls : -Called by : -Parameter : -returns : -Author : Tommy Huang -History : -***********************************************************************/ -static void atsmb_enable_sdio_irq(struct mmc_host *mmc, int enable) -{ - struct atsmb_host *host = mmc_priv(mmc); - unsigned long flags; - - DBG("[%s] s enable = %d *ATSMB0_INT_MASK_1 = %x\n",__func__,enable,*ATSMB0_INT_MASK_1); - spin_lock_irqsave(&host->lock, flags); - - if (enable) { - *ATSMB0_INT_MASK_1 |= ATSMB_SDIO_EN; - } else { - *ATSMB0_INT_MASK_1 &= ~ATSMB_SDIO_EN; - } - - spin_unlock_irqrestore(&host->lock, flags); - DBG("[%s] e\n",__func__); - -} -/********************************************************************** -Name : atsmb_request -Function :. -Calls : -Called by : -Parameter : -Author : Leo Lee -History : -***********************************************************************/ -static void atsmb_request(struct mmc_host *mmc, struct mmc_request *mrq) -{ - - struct atsmb_host *host = mmc_priv(mmc); - DBG("[%s] s\n",__func__); - - /* May retry process comes here.*/ - host->mrq = mrq; - host->data = mrq->data; - host->cmd = mrq->cmd; - host->done_data = NULL; - host->done = NULL; - - /*for data request*/ - if (host->data) { - if (host->cmd->opcode == MMC_WRITE_BLOCK - || host->cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK - || host->cmd->opcode == MMC_READ_SINGLE_BLOCK - || host->cmd->opcode == MMC_READ_MULTIPLE_BLOCK - || host->cmd->opcode == SD_IO_RW_EXTENDED) { - atsmb_start_data(host); - } else { - atsmb_cmd_with_data_back(host); - } - } else { - atsmb_start_cmd(host); - } - DBG("[%s] e\n",__func__); -} -/********************************************************************** -Name : atsmb_set_clock -Function :. -Calls : -Called by : -Parameter : -Author : Eason Chien -History :2012/7/19 -***********************************************************************/ -static int atsmb_set_clock(struct mmc_host *mmc, unsigned int clock) -{ - int clock_multiplier = 1; - DBG("clock = %u\n",clock); - - if (*ATSMB0_EXT_BUS_MODE & BIT4) /*Enable DDR50*/ - clock_multiplier = 2; - - if(SD0_speed){ - if (clock == mmc->f_min) { - DBG("[%s]ATSMB Host 390KHz\n", __func__); - if ((*ATSMB0_CTL2 & BIT3) == 0) { - DBG("[%s] 1.8V clock = %u\n",__func__,clock); - DBG("[%s] *ATSMB0_CTL2 = 0x%x \n", __func__, *ATSMB0_CTL2); - } - return auto_pll_divisor(DEV_SDMMC0, SET_DIV, 1, 390); - } - else if (clock >= 208000000) { - DBG("[%s]ATSMB Host 208MHz\n", __func__); - if ((*ATSMB0_CTL2 & BIT3) == 0) { - DBG("[%s] 1.8V clock = %u\n",__func__,clock); - - /*Set DPCTL 010 DNCTL 001*/ - SD0_DPCTL_4BYTE_VAL = (BIT1 | BIT4 | BIT7 | BIT10 | BIT13 | BIT16 | BIT19); - SD0_DNCTL_4BYTE_VAL = (BIT0 | BIT3 | BIT6 | BIT9 | BIT12 | BIT15 | BIT18); - - - DBG("[%s] *ATSMB0_CTL2 = 0x%x \n", __func__, *ATSMB0_CTL2); - DBG("[%s] *DPCTL = 0x%x DPCTL = 0x%x\n", - __func__, SD0_DPCTL_4BYTE_ADDR, SD0_DPCTL_4BYTE_VAL); - DBG("[%s] *DNCTL = 0x%x DNCTL = 0x%x\n", - __func__, SD0_DNCTL_4BYTE_ADDR, SD0_DNCTL_4BYTE_VAL); - } - return auto_pll_divisor(DEV_SDMMC0, SET_DIV, 2, 80); - } else if (clock >= 100000000) { - DBG("[%s]ATSMB Host 100MHz\n", __func__); - if ((*ATSMB0_CTL2 & BIT3) == 0) { - DBG("[%s] 1.8V clock = %u\n",__func__,clock); - - /*Set DPCTL 010 DNCTL 001*/ - SD0_DPCTL_4BYTE_VAL = (BIT1 | BIT4 | BIT7 | BIT10 | BIT13 | BIT16 | BIT19); - SD0_DNCTL_4BYTE_VAL = (BIT0 | BIT3 | BIT6 | BIT9 | BIT12 | BIT15 | BIT18); - - DBG("[%s] *ATSMB0_CTL2 = 0x%x \n", __func__, *ATSMB0_CTL2); - } - return auto_pll_divisor(DEV_SDMMC0, SET_DIV, 2, 80); - } else if (clock >= 50000000) { - DBG("[%s]ATSMB Host 50MHz\n", __func__); - if ((*ATSMB0_CTL2 & BIT3) == 0) { - DBG("[%s] 1.8V clock = %u\n",__func__,clock); - - /*Set DPCTL 010 DNCTL 001*/ - SD0_DPCTL_4BYTE_VAL = (BIT1 | BIT4 | BIT7 | BIT10 | BIT13 | BIT16 | BIT19); - SD0_DNCTL_4BYTE_VAL = (BIT0 | BIT3 | BIT6 | BIT9 | BIT12 | BIT15 | BIT18); - DBG("[%s] *ATSMB0_CTL2 = 0x%x \n", __func__, *ATSMB0_CTL2); - } - return auto_pll_divisor(DEV_SDMMC0, SET_DIV, 2, 45 * clock_multiplier); - } else if ((clock >= 25000000) && (clock < 50000000)) { - if ((*ATSMB0_CTL2 & BIT3) == 0) { - DBG("[%s] 1.8V clock = %u\n",__func__,clock); - - /*Set DPCTL 010 DNCTL 001*/ - SD0_DPCTL_4BYTE_VAL = (BIT1 | BIT4 | BIT7 | BIT10 | BIT13 | BIT16 | BIT19); - SD0_DNCTL_4BYTE_VAL = (BIT0 | BIT3 | BIT6 | BIT9 | BIT12 | BIT15 | BIT18); - DBG("[%s] *ATSMB0_CTL2 = 0x%x \n", __func__, *ATSMB0_CTL2); - } - DBG("[%s]ATSMB Host 25MHz\n", __func__); - return auto_pll_divisor(DEV_SDMMC0, SET_DIV, 2, 24 * clock_multiplier); - } else if ((clock >= 20000000) && (clock < 25000000)) { - DBG("[%s]ATSMB Host 20MHz\n", __func__); - if ((*ATSMB0_CTL2 & BIT3) == 0) { - DBG("[%s] 1.8V clock = %u\n",__func__,clock); - - /*Set DPCTL 010 DNCTL 001*/ - SD0_DPCTL_4BYTE_VAL = (BIT1 | BIT4 | BIT7 | BIT10 | BIT13 | BIT16 | BIT19); - SD0_DNCTL_4BYTE_VAL = (BIT0 | BIT3 | BIT6 | BIT9 | BIT12 | BIT15 | BIT18); - DBG("[%s] *ATSMB0_CTL2 = 0x%x \n", __func__, *ATSMB0_CTL2); - } - return auto_pll_divisor(DEV_SDMMC0, SET_DIV, 2, 20 * clock_multiplier); - } else { - DBG("[%s]ATSMB Host 390KHz\n", __func__); - if ((*ATSMB0_CTL2 & BIT3) == 0) { - DBG("[%s] 1.8V clock = %u\n",__func__,clock); - - /*Set DPCTL 010 DNCTL 001*/ - SD0_DPCTL_4BYTE_VAL = (BIT1 | BIT4 | BIT7 | BIT10 | BIT13 | BIT16 | BIT19); - SD0_DNCTL_4BYTE_VAL = (BIT0 | BIT3 | BIT6 | BIT9 | BIT12 | BIT15 | BIT18); - DBG("[%s] *ATSMB0_CTL2 = 0x%x \n", __func__, *ATSMB0_CTL2); - } - return auto_pll_divisor(DEV_SDMMC0, SET_DIV, 1, 390 * clock_multiplier); - } - }else{ - if (clock == mmc->f_min) { - DBG("[%s]ATSMB Host 390KHz\n", __func__); - if ((*ATSMB0_CTL2 & BIT3) == 0) { - DBG("[%s] 1.8V clock = %u\n",__func__,clock); - DBG("[%s] *ATSMB0_CTL2 = 0x%x \n", __func__, *ATSMB0_CTL2); - } - return auto_pll_divisor(DEV_SDMMC0, SET_DIV, 1, 390); - }else if (clock >= 25000000) { - if ((*ATSMB0_CTL2 & BIT3) == 0) { - DBG("[%s] 1.8V clock = %u\n",__func__,clock); - - /*Set DPCTL 010 DNCTL 001*/ - SD0_DPCTL_4BYTE_VAL = (BIT1 | BIT4 | BIT7 | BIT10 | BIT13 | BIT16 | BIT19); - SD0_DNCTL_4BYTE_VAL = (BIT0 | BIT3 | BIT6 | BIT9 | BIT12 | BIT15 | BIT18); - DBG("[%s] *ATSMB0_CTL2 = 0x%x \n", __func__, *ATSMB0_CTL2); - } - DBG("[%s]ATSMB Host 25MHz\n", __func__); - return auto_pll_divisor(DEV_SDMMC0, SET_DIV, 2, 24 * clock_multiplier); - } else if ((clock >= 20000000) && (clock < 25000000)) { - DBG("[%s]ATSMB Host 20MHz\n", __func__); - if ((*ATSMB0_CTL2 & BIT3) == 0) { - DBG("[%s] 1.8V clock = %u\n",__func__,clock); - - /*Set DPCTL 010 DNCTL 001*/ - SD0_DPCTL_4BYTE_VAL = (BIT1 | BIT4 | BIT7 | BIT10 | BIT13 | BIT16 | BIT19); - SD0_DNCTL_4BYTE_VAL = (BIT0 | BIT3 | BIT6 | BIT9 | BIT12 | BIT15 | BIT18); - DBG("[%s] *ATSMB0_CTL2 = 0x%x \n", __func__, *ATSMB0_CTL2); - } - return auto_pll_divisor(DEV_SDMMC0, SET_DIV, 2, 20 * clock_multiplier); - } else { - DBG("[%s]ATSMB Host 390KHz\n", __func__); - if ((*ATSMB0_CTL2 & BIT3) == 0) { - DBG("[%s] 1.8V clock = %u\n",__func__,clock); - - /*Set DPCTL 010 DNCTL 001*/ - SD0_DPCTL_4BYTE_VAL = (BIT1 | BIT4 | BIT7 | BIT10 | BIT13 | BIT16 | BIT19); - SD0_DNCTL_4BYTE_VAL = (BIT0 | BIT3 | BIT6 | BIT9 | BIT12 | BIT15 | BIT18); - DBG("[%s] *ATSMB0_CTL2 = 0x%x \n", __func__, *ATSMB0_CTL2); - } - return auto_pll_divisor(DEV_SDMMC0, SET_DIV, 1, 390 * clock_multiplier); - } - } -} - -static void atsmb_enable_power(struct atsmb_host *host, unsigned long flags) -{ - int result; - spin_unlock_irqrestore(&host->lock, flags); - if (g_atsmb_regulator) { - if (regulator_is_enabled(atsmb_regulator) == 0) { - DBG("[%s] Turn on power\n", __FUNCTION__); - result = regulator_enable(atsmb_regulator); - if (result != 0) - printk(KERN_ALERT "[%s] regulator_enable FAIL\n", __FUNCTION__); - } - } else { - GPIO_OD_GP13_SD0_BYTE_VAL &= ~GPIO_SD0_POWER; - } - spin_lock_irqsave(&host->lock, flags); -} - -static void atsmb_disable_power(struct atsmb_host *host, unsigned long flags) -{ - int result; - spin_unlock_irqrestore(&host->lock, flags); - if (g_atsmb_regulator) { - if (regulator_is_enabled(atsmb_regulator) == 1) { - DBG("[%s] Turn off power\n", __FUNCTION__); - result = regulator_disable(atsmb_regulator); - if (result != 0) - printk(KERN_ALERT "[%s] regulator_disable FAIL\n", __FUNCTION__); - } - } else { - GPIO_CTRL_GP13_SD0_BYTE_VAL |= GPIO_SD0_POWER; - GPIO_OC_GP13_SD0_BYTE_VAL |= GPIO_SD0_POWER; - /*set internal pull up*/ - PULL_CTRL_GP13_SD0_BYTE_VAL |= GPIO_SD0_POWER; - /*set internal pull enable*/ - PULL_EN_GP13_SD0_BYTE_VAL |= GPIO_SD0_POWER; - /*disable SD0 power*/ - GPIO_OD_GP13_SD0_BYTE_VAL |= GPIO_SD0_POWER; - } - spin_lock_irqsave(&host->lock, flags); -} - -/********************************************************************** -Name : atsmb_set_ios -Function :. -Calls : -Called by : -Parameter : -Author : Leo Lee -History : -***********************************************************************/ -static void atsmb_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) -{ - - struct atsmb_host *host = mmc_priv(mmc); - unsigned long flags; - DBG("[%s] s\n",__func__); - spin_lock_irqsave(&host->lock, flags); - - if (ios->power_mode == MMC_POWER_OFF) { - if (MMC0_DRIVER_VERSION == MMC_DRV_3498) { - /* set all descriptor end bit for removing card when - * PDMA don't transfer data done. let PDMA transfer done - */ - atsmb_set_dma_end(host->DescVirAddr, host->DescSize); - - /* stop SD output clock */ - *ATSMB0_BUS_MODE &= ~(ATSMB_CST); - - /* disable SD Card power */ - /*set SD0 power pin as GPO pin*/ - atsmb_disable_power(host, flags); - - /* Disable Pull up/down resister of SD Bus */ - /*GPIO_PULL_CTRL_GP13_XDIO_BYTE_VAL &= ~SD0_PIN; marked by eason 2012/3/29*/ - - /* Config SD0 to GPIO */ - GPIO_CTRL_GP13_SD0_BYTE_VAL |= SD0_PIN; - - /* SD0 all pins output low */ - GPIO_OD_GP13_SD0_BYTE_VAL &= ~SD0_PIN; - - /* Config SD0 to GPO */ - GPIO_OC_GP13_SD0_BYTE_VAL |= SD0_PIN; - - } - - } else if (ios->power_mode == MMC_POWER_UP) { - if (MMC0_DRIVER_VERSION == MMC_DRV_3498) { - /* disable SD Card power */ - /*set SD0 power pin as GPO pin*/ - GPIO_CTRL_GP13_SD0_BYTE_VAL |= GPIO_SD0_POWER; - GPIO_OC_GP13_SD0_BYTE_VAL |= GPIO_SD0_POWER; - - /*set internal pull up*/ - PULL_CTRL_GP13_SD0_BYTE_VAL |= GPIO_SD0_POWER; - /*set internal pull enable*/ - PULL_EN_GP13_SD0_BYTE_VAL |= GPIO_SD0_POWER; - /*disable SD0 power*/ - GPIO_OD_GP13_SD0_BYTE_VAL |= GPIO_SD0_POWER; - - /* Config SD PIN share, WM3498 SD0 no share pin */ - /*PIN_SHARING_SEL_4BYTE_VAL &= ~GPIO_SD0_PinShare; */ - - /* do not config GPIO_SD0_CD because ISR has already run, - * config card detect will issue ISR storm. - */ - /* - GPIO_OD_GP12_SPI_BYTE_VAL |= GPIO_SD0_18SEL; - GPIO_OC_GP12_SPI_BYTE_VAL |= GPIO_SD0_18SEL; - GPIO_CTRL_GP12_SPI_BYTE_VAL |= GPIO_SD0_18SEL; - */ - *ATSMB0_CTL2 |= BIT3; /*Set 3.3V*/ - *ATSMB0_EXT_CTL &= ~BIT7; /*Disable High Speed Mode*/ - *ATSMB0_CTL2 &= ~(BIT0 | BIT1 | BIT2); - *ATSMB0_EXT_BUS_MODE &= ~BIT4; /*Disable DDR50*/ - - /*Set 18SEL as function pin*/ - GPIO_CTRL_GP12_SPI_BYTE_VAL &= ~GPIO_SD0_18SEL; - - - /* Config SD to GPIO */ - GPIO_CTRL_GP13_SD0_BYTE_VAL |= SD0_PIN; - - /* SD all pins output low */ - GPIO_OD_GP13_SD0_BYTE_VAL &= ~SD0_PIN; - - /* Config SD to GPO */ - GPIO_OC_GP13_SD0_BYTE_VAL |= SD0_PIN; - - /* Pull up/down resister of SD Bus */ - /*Disable Clock & CMD Pull enable*/ - PULL_EN_GP13_SD0_BYTE_VAL &= ~(GPIO_SD0_Clock | GPIO_SD0_Command); - - /*Set CD ,WP ,DATA pin pull up*/ - if (SD0_detect_pulldown) - PULL_CTRL_GP63_SD02_BYTE_VAL &= ~GPIO_SD0_CD; - else - PULL_CTRL_GP63_SD02_BYTE_VAL |= GPIO_SD0_CD; - PULL_CTRL_GP13_SD0_BYTE_VAL |= (GPIO_SD0_Data | GPIO_SD0_WriteProtect); - - /*Enable CD ,WP ,DATA internal pull*/ - PULL_EN_GP63_SD02_BYTE_VAL |= GPIO_SD0_CD; - PULL_EN_GP13_SD0_BYTE_VAL |= (GPIO_SD0_Data | GPIO_SD0_WriteProtect); - - /*Set SD0 PAD signal drive strength as 0*/ - SD0_DPCTL_4BYTE_VAL = 0; - SD0_DNCTL_4BYTE_VAL = 0; - - spin_unlock_irqrestore(&host->lock, flags); - msleep(100); - spin_lock_irqsave(&host->lock, flags); - - /* enable SD Card Power */ - atsmb_enable_power(host, flags); - - /* enable SD output clock */ - *ATSMB0_BUS_MODE |= ATSMB_CST; - - spin_unlock_irqrestore(&host->lock, flags); - msleep(10); - spin_lock_irqsave(&host->lock, flags); - - /* Config SD0 back to function */ - GPIO_CTRL_GP13_SD0_BYTE_VAL &= ~SD0_PIN; - GPIO_CTRL_GP63_SD02CD_BYTE_VAL &= ~GPIO_SD0_CD; - } - } else { - /*nothing to do when powering on.*/ - } - - host->current_clock = atsmb_set_clock(mmc,ios->clock); - - if (ios->bus_width == MMC_BUS_WIDTH_8) { - *ATSMB0_EXT_CTL |= BIT2; - } else if (ios->bus_width == MMC_BUS_WIDTH_4) { - *ATSMB0_BUS_MODE |= ATSMB_BUS_WIDTH_4; - *ATSMB0_EXT_CTL &= ~BIT2; - } else { - *ATSMB0_BUS_MODE &= ~(ATSMB_BUS_WIDTH_4); - *ATSMB0_EXT_CTL &= ~BIT2; - } - -/* -#define MMC_TIMING_LEGACY 0 -#define MMC_TIMING_MMC_HS 1 -#define MMC_TIMING_SD_HS 2 -#define MMC_TIMING_UHS_SDR12 MMC_TIMING_LEGACY -#define MMC_TIMING_UHS_SDR25 MMC_TIMING_SD_HS -#define MMC_TIMING_UHS_SDR50 3 -#define MMC_TIMING_UHS_SDR104 4 -#define MMC_TIMING_UHS_DDR50 5 -#define MMC_TIMING_MMC_HS200 6 -*/ - DBG("[%s]timing = 0x%x clock = %u\n", __func__, ios->timing, ios->clock); - - if (ios->timing == MMC_TIMING_LEGACY) { - *ATSMB0_EXT_CTL &= ~BIT7; /*Disable High Speed Mode*/ - *ATSMB0_CTL2 &= ~(BIT0 | BIT1 | BIT2); - } else if (ios->timing == MMC_TIMING_MMC_HS) { - *ATSMB0_EXT_CTL &= ~BIT7; /*Disable High Speed Mode*/ - *ATSMB0_CTL2 &= ~(BIT0 | BIT1 | BIT2); - } else if (ios->timing == MMC_TIMING_SD_HS) { - *ATSMB0_EXT_CTL |= BIT7; /*HIGH SPEED MODE*/ - *ATSMB0_CTL2 &= ~(BIT0 | BIT1 | BIT2); - } else if (ios->timing == MMC_TIMING_UHS_SDR12) { - *ATSMB0_EXT_CTL &= ~BIT7; /*Disable High Speed Mode*/ - /*UHS Mode Select = 000 SDR12*/ - *ATSMB0_CTL2 &= ~(BIT0 | BIT1 | BIT2); - } else if (ios->timing == MMC_TIMING_UHS_SDR25) { - *ATSMB0_EXT_CTL &= ~BIT7; /*Disable High Speed Mode*/ - /*UHS Mode Select = 001 SDR25*/ - *ATSMB0_CTL2 |= BIT0; - *ATSMB0_CTL2 &= ~(BIT1 | BIT2); - } else if (ios->timing == MMC_TIMING_UHS_SDR50) { - *ATSMB0_EXT_CTL &= ~BIT7; /*Disable High Speed Mode*/ - /*UHS Mode Select = 010 SDR50*/ - *ATSMB0_CTL2 |= BIT1; - *ATSMB0_CTL2 &= ~(BIT0 | BIT2); - } else if (ios->timing == MMC_TIMING_UHS_SDR104) { - *ATSMB0_EXT_CTL &= ~BIT7; /*Disable High Speed Mode*/ - /*UHS Mode Select = 011 SDR104*/ - *ATSMB0_CTL2 |= (BIT0 | BIT1); - *ATSMB0_CTL2 &= ~BIT2; - } else if (ios->timing == MMC_TIMING_UHS_DDR50) { - *ATSMB0_EXT_CTL &= ~BIT7; /*Disable High Speed Mode*/ - /*UHS Mode Select = 100 DDR50*/ - *ATSMB0_CTL2 |= BIT2; - *ATSMB0_CTL2 &= ~(BIT0 | BIT1); - *ATSMB0_EXT_BUS_MODE |= BIT4; /*Enable DDR50*/ - /* enable SD output clock */ - *ATSMB0_BUS_MODE &= ~ATSMB_CST; - spin_unlock_irqrestore(&host->lock, flags); - msleep(1); - spin_lock_irqsave(&host->lock, flags); - - *ATSMB0_EXT_BUS_MODE |= BIT4; /*Enable DDR50*/ - /* enable SD output clock */ - *ATSMB0_BUS_MODE |= ATSMB_CST; - } else - *ATSMB0_EXT_CTL &= ~BIT7; /*Disable High Speed Mode*/ - -/* spin_unlock_irqrestore(&host->lock, flags); - msleep(100); - spin_lock_irqsave(&host->lock, flags); */ - - DBG("[%s] *ATSMB0_CTL2 = 0x%x *ATSMB0_EXT_CTL = 0x%x *ATSMB0_EXT_BUS_MODE = 0x%x\n", - __func__, *ATSMB0_CTL2, *ATSMB0_EXT_CTL, *ATSMB0_EXT_BUS_MODE); - spin_unlock_irqrestore(&host->lock, flags); - DBG("[%s] e\n",__func__); -} - -int atsmb_start_signal_voltage_switch(struct mmc_host *host, struct mmc_ios *ios) -{ - DBG("[%s] s\n",__func__); - - if(ios->signal_voltage == MMC_SIGNAL_VOLTAGE_180) { - /*Set CMD ,DATA0~3 pin as GPO low*/ - /* SD0 all pins output low */ - GPIO_OD_GP13_SD0_BYTE_VAL &= ~(GPIO_SD0_Command | GPIO_SD0_Data); - /* Config SD0 to GPO */ - GPIO_OC_GP13_SD0_BYTE_VAL |= (GPIO_SD0_Command | GPIO_SD0_Data);; - /* Config SD0 to GPIO */ - GPIO_CTRL_GP13_SD0_BYTE_VAL |= (GPIO_SD0_Command | GPIO_SD0_Data); - - - /*Wait for 1ms*/ - msleep(1); - - /*Stop Clock*/ - *ATSMB0_BUS_MODE &= ~(ATSMB_CST); - - - /*Enable clock & Set 1.8V*/ - *ATSMB0_CTL2 &= ~BIT3; - - /*Wait for 10ms*/ - msleep(100); - - /*Enable Clock*/ - *ATSMB0_BUS_MODE |= ATSMB_CST; - - - /*Set CMD DATA0~3 pin as function pin*/ - GPIO_CTRL_GP13_SD0_BYTE_VAL &= ~GPIO_SD0_Command; - GPIO_CTRL_GP13_SD0_BYTE_VAL &= ~GPIO_SD0_Data; - - - DBG("Set SD0 1.8v = 0x%x\n",ios->signal_voltage); - - return 0; - } else if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330){ - *ATSMB0_CTL2 |= BIT3; - DBG("Set SD0 3.3v = 0x%x\n",ios->signal_voltage); - return 0; - } - - printk("Set voltage error = 0x%x\n",ios->signal_voltage); - return -EIO; - DBG("[%s] e\n",__func__); -} - -static const struct mmc_host_ops atsmb_ops = { - .request = atsmb_request, - .set_ios = atsmb_set_ios, - .get_ro = atsmb_get_ro, - .get_slot_status = atsmb_get_slot_status, - .dump_host_regs = atsmb_dump_host_regs, - .enable_sdio_irq = atsmb_enable_sdio_irq, - .start_signal_voltage_switch = atsmb_start_signal_voltage_switch, -}; - -extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen); - -/********************************************************************** -Name :atsmb_probe -Function :. -Calls : -Called by : -Parameter : -Author : Leo Lee -History : -***********************************************************************/ -static int __init atsmb_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct mmc_host *mmc_host = NULL; - struct atsmb_host *atsmb_host = NULL; - struct resource *resource = NULL; - int irq[2] = {0}; - int ret = 0; - - DBG("[%s] s\n",__func__); - if (!pdev) { - ret = -EINVAL; /* Invalid argument */ - goto the_end; - } - - /*Enable SD host clock*/ - auto_pll_divisor(DEV_SDMMC0, CLK_ENABLE, 0, 0); - - if (MMC0_DRIVER_VERSION == MMC_DRV_3498) { - /* Pull up/down resister of SD CD */ - if(SD0_detect_pulldown) - PULL_CTRL_GP63_SD02_BYTE_VAL &= ~GPIO_SD0_CD; /*pull down CD*/ - else - PULL_CTRL_GP63_SD02_BYTE_VAL |= GPIO_SD0_CD; /*pull up CD*/ - PULL_EN_GP63_SD02_BYTE_VAL |= GPIO_SD0_CD; - - /* config CardDetect pin to SD function */ - GPIO_CTRL_GP63_SD02CD_BYTE_VAL &= ~GPIO_SD0_CD; - } - - - resource = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!resource) { - ret = -ENXIO; /* No such device or address */ - printk(KERN_ALERT "[MMC/SD driver] Getting platform resources failed!\n"); - goto the_end; - } -#if 0 - if (!request_mem_region(resource->start, SZ_1K, MMC0_DRIVER_NAME)) { - ret = -EBUSY; - printk(KERN_ALERT "[MMC/SD driver] Request memory region failed!\n"); - goto the_end ; - } -#endif - irq[0] = platform_get_irq(pdev, 0); /*get IRQ for device*/; - irq[1] = platform_get_irq(pdev, 1); /*get IRQ for dma*/; - - if (irq[0] == NO_IRQ || irq[1] == NO_IRQ) { - ret = -ENXIO;/* No such device or address */ - printk(KERN_ALERT "[MMC/SD driver] Get platform IRQ failed!\n"); - goto rls_region; - } - - /*allocate a standard msp_host structure attached with a atsmb structure*/ - mmc_host = mmc_alloc_host(sizeof(struct atsmb_host), dev); - if (!mmc_host) { - ret = -ENOMEM; - printk(KERN_ALERT "[MMC/SD driver] Allocating driver's data failed!\n"); - goto rls_region; - } - mmc_host->wmt_host_index = 0; /*to identify host number*/ - - dev_set_drvdata(dev, (void *)mmc_host); /* mmc_host is driver data for the atsmb dev.*/ - atsmb_host = mmc_priv(mmc_host); - - mmc_host->ops = &atsmb_ops; - - mmc_host->ocr_avail = MMC_VDD_32_33|MMC_VDD_33_34; - - mmc_host->f_min = 390425; /*390.425Hz = 400MHz/64/16*/ - mmc_host->f_max = 100000000; /* Set max frequency 100MHz*/ - - if (SDXC0_function == 1) { - mmc_host->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SDIO_IRQ - | MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 | MMC_CAP_UHS_DDR50 | MMC_CAP_1_8V_DDR; - /* |MMC_CAP_8_BIT_DATA;*/ //zhf: marked by James Tian - } else { - mmc_host->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SDIO_IRQ; - /* |MMC_CAP_8_BIT_DATA;*/ //zhf: marked by James Tian - } - - mmc_host->max_segs = 128; /*we use software sg. so we could manage even larger number.*/ - - /*1MB per each request */ - /*we have a 16 bit block number register, and block length is 512 bytes.*/ - mmc_host->max_req_size = 16*512*(mmc_host->max_segs); - mmc_host->max_seg_size = 65024; /* 0x7F*512 PDMA one descriptor can transfer 64K-1 byte*/ - mmc_host->max_blk_size = 2048; /* our block length register is 11 bits.*/ - mmc_host->max_blk_count = (mmc_host->max_req_size)/512; - - /*set the specified host -- ATSMB*/ -#ifdef CONFIG_MMC_UNSAFE_RESUME - mmc_host->card_attath_status = card_attach_status_unchange; -#endif - sema_init(&mmc_host->req_sema,1); /*initial request semaphore*/ -#if 0 - atsmb_host->base = ioremap(resource->start, SZ_1K); - if (!atsmb_host->base) { - printk(KERN_ALERT "[MMC/SD driver] IO remap failed!\n"); - ret = -ENOMEM; - goto fr_host; - } -#endif - atsmb_host->base = (void *)resource->start; - atsmb_host->mmc = mmc_host; - spin_lock_init(&atsmb_host->lock); - atsmb_host->res = resource;/* for atsmb_remove*/ - - /*disable all interrupt and clear status by resetting controller.*/ - *ATSMB0_BUS_MODE |= ATSMB_SFTRST; - *ATSMB0_BLK_LEN &= ~(0xa000); - *ATSMB0_SD_STS_0 |= 0xff; - *ATSMB0_SD_STS_1 |= 0xff; - - /* WM3437 A0 default not output clock, after SFTRST need to enable SD clock */ - //if (MMC0_DRIVER_VERSION >= MMC_DRV_3437_A0) /* including 3429 */ - *ATSMB0_BUS_MODE |= ATSMB_CST; - - atsmb_host->regular_irq = irq[0]; - atsmb_host->dma_irq = irq[1]; - - ret = request_irq(atsmb_host->regular_irq, - atsmb_regular_isr, - IRQF_SHARED, //SA_SHIRQ, /*SA_INTERRUPT, * that is okay?*/ //zhf: modified by James Tian, should be IRQF_SHARED? - MMC0_DRIVER_NAME, - (void *)atsmb_host); - if (ret) { - printk(KERN_ALERT "[MMC/SD driver] Failed to register regular ISR!\n"); - goto unmap; - } - - ret = request_irq(atsmb_host->dma_irq, - atsmb_dma_isr, - IRQF_DISABLED, // SA_INTERRUPT, //zhf: modified by James Tian - MMC0_DRIVER_NAME, - (void *)atsmb_host); - if (ret) { - printk(KERN_ALERT "[MMC/SD driver] Failed to register DMA ISR!\n"); - goto fr_regular_isr; - } - - /* config CardDetect pin to SD function */ - /*GPIO_CTRL_GP63_SD02CD_BYTE_VAL &= ~GPIO_SD0_CD; add by eason 2012/3/29*/ - - /*wait card detect status change*/ - //msleep(10); - - /*enable card insertion interrupt and enable DMA and its Global INT*/ - *ATSMB0_BLK_LEN |= (0xa000); /* also, we enable GPIO to detect card.*/ - *ATSMB0_SD_STS_0 |= 0xff; - *ATSMB0_INT_MASK_0 |= 0x80; /*or 0x40?*/ - - /*allocation dma descriptor*/ - ret = atsmb_alloc_desc(atsmb_host, sizeof(struct SD_PDMA_DESC_S) * MAX_DESC_NUM); - if (ret == -1) { - printk(KERN_ALERT "[MMC/SD driver] Failed to allocate DMA descriptor!\n"); - goto fr_dma_isr; - } - printk(KERN_INFO "WMT ATSMB (AHB To SD/MMC Bus) controller registered!\n"); - - if (SD0_function == SDIO_WIFI) - mmc_add_host(mmc_host,false); - else - mmc_add_host(mmc_host,true); - - mmc_host_attr = mmc_host; - - DBG("[%s] e1\n",__func__); - return 0; - -fr_dma_isr: - free_irq(atsmb_host->dma_irq, atsmb_host); -fr_regular_isr: - free_irq(atsmb_host->regular_irq, atsmb_host); -unmap: - //iounmap(atsmb_host->base); -//fr_host: - dev_set_drvdata(dev, NULL); - mmc_free_host(mmc_host); -rls_region: - //release_mem_region(resource->start, SZ_1K); -the_end: - printk(KERN_ALERT "[MMC/SD driver] ATSMB0 probe Failed!\n") ; - DBG("[%s] e2\n",__func__); - return ret; -} -/********************************************************************** -Name : atsmb_remove -Function :. -Calls : -Called by : -Parameter : -Author : Leo Lee -History : -***********************************************************************/ -static int atsmb_remove(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct mmc_host *mmc_host = (struct mmc_host *)dev_get_drvdata(dev); - struct atsmb_host *atsmb_host; - - DBG("[%s] s\n",__func__); - atsmb_host = mmc_priv(mmc_host); - if (!mmc_host || !atsmb_host) { - printk(KERN_ALERT "[MMC/SD driver] ATSMB0 remove method failed!\n"); - DBG("[%s] e1\n",__func__); - return -ENXIO; - } - mmc_remove_host(mmc_host); - - /*disable interrupt by resetting controller -- for safey*/ - *ATSMB0_BUS_MODE |= ATSMB_SFTRST; - *ATSMB0_BLK_LEN &= ~(0xa000); - *ATSMB0_SD_STS_0 |= 0xff; - *ATSMB0_SD_STS_1 |= 0xff; - - (void)free_irq(atsmb_host->regular_irq, atsmb_host); - (void)free_irq(atsmb_host->dma_irq, atsmb_host); - (void)iounmap(atsmb_host->base); - (void)release_mem_region(atsmb_host->res->start, SZ_1K); - dev_set_drvdata(dev, NULL); - /*free dma descriptor*/ - dma_free_coherent(atsmb_host->mmc->parent, atsmb_host->DescSize, - atsmb_host->DescVirAddr, atsmb_host->DescPhyAddr); - (void)mmc_free_host(mmc_host);/* also free atsmb_host.*/ - DBG("[%s] e2\n",__func__); - return 0; -} - -/********************************************************************** -Name : atsmb_shutdown -Function :. -Calls : -Called by : -Parameter : -Author : Tommy Huang -History : -***********************************************************************/ -static void atsmb_shutdown(struct platform_device *pdev) -{ - /*atsmb_shutdown don't be used now.*/ - /*struct device *dev = &pdev->dev; - struct mmc_host *mmc_host = (struct mmc_host *)dev_get_drvdata(dev);*/ - - DBG("[%s] s\n",__func__); - if (SD0_function != SDIO_WIFI) { - /*Disable card detect interrupt*/ - *ATSMB0_INT_MASK_0 &= ~0x80; - } - DBG("[%s] e\n",__func__); - -} - -/********************************************************************** -Name : atsmb_suspend -Function :. -Calls : -Called by : -Parameter : -Author : Leo Lee -History : -***********************************************************************/ -#ifdef CONFIG_PM -static int atsmb_suspend(struct platform_device *pdev, pm_message_t state) -{ - struct device *dev = &pdev->dev; - struct mmc_host *mmc = (struct mmc_host *)dev_get_drvdata(dev); - int ret = 0; - DBG("[%s] s\n",__func__); - - if (mmc) { - /*struct atsmb_host *host = mmc_priv(mmc);*/ - ret = mmc_suspend_host(mmc); - if (ret == 0) { - /*disable all interrupt and clear status by resetting controller. */ - *ATSMB0_BUS_MODE |= ATSMB_SFTRST; - *ATSMB0_BLK_LEN &= ~(0xa000); - *ATSMB0_SD_STS_0 |= 0xff; - *ATSMB0_SD_STS_1 |= 0xff; - - } - /*disable source clock*/ - auto_pll_divisor(DEV_SDMMC0, CLK_DISABLE, 0, 0); -#ifdef CONFIG_MMC_UNSAFE_RESUME - /*clean SD card attatch status change*/ - PMCWS_VAL |= BIT19; - mmc->card_attath_status = card_attach_status_unchange; -#endif - } - - DBG("[%s] e\n",__func__); - return ret; -} -/********************************************************************** -Name : atsmb_resume -Function :. -Calls : -Called by : -Parameter : -Author : Leo Lee -History : -***********************************************************************/ -static int atsmb_resume(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct mmc_host *mmc = (struct mmc_host *)dev_get_drvdata(dev); - int ret = 0; - DBG("[%s] s\n",__func__); - - /* - * enable interrupt, DMA, etc. - * Supply power to slot. - */ - if (mmc) { - /*enable source clock*/ - auto_pll_divisor(DEV_SDMMC0, CLK_ENABLE, 0, 0); - - udelay(1); - /*enable card insertion interrupt and enable DMA and its Global INT*/ - *ATSMB0_BUS_MODE |= ATSMB_SFTRST; - *ATSMB0_BLK_LEN |= (0xa000); - *ATSMB0_INT_MASK_0 |= 0x80; /* or 40?*/ -#ifdef CONFIG_MMC_UNSAFE_RESUME - /*modify SD card attatch status change*/ - if ((PMCWS_VAL & BIT19) && !mmc->bus_dead) { - /*card change when suspend mode*/ - mmc->card_attath_status = card_attach_status_change; - /*clean SD card attatch status change*/ - PMCWS_VAL |= BIT19; - } -#endif - ret = mmc_resume_host(mmc); - } - - DBG("[%s] e\n",__func__); - return ret; -} -#else -#define atsmb_suspend NULL -#define atsmb_resume NULL -#endif - -static struct platform_driver atsmb_driver = { - .driver.name = "sdmmc", - //.probe = atsmb_probe, - .remove = atsmb_remove, - .shutdown = atsmb_shutdown, - .suspend = atsmb_suspend, - .resume = atsmb_resume, -}; - -static struct platform_device wmt_sdmmc_device = { - .name = "sdmmc", - .id = 0, - .dev = { - .dma_mask = &wmt_sdmmc_dma_mask, - .coherent_dma_mask = ~0, - .release = atsmb_release, - }, - .num_resources = ARRAY_SIZE(wmt_sdmmc_resources), - .resource = wmt_sdmmc_resources, -}; - - -static ssize_t atsmb_state_show(struct kobject *kobj, struct kobj_attribute *attr, - char *buf) -{ - int ret = 0; - int card_state; - - DBG("[%s] s\n",__func__); - if (mmc_host_attr->card != NULL) - card_state = 1; - else - card_state = 0; - DBG("[%s]card_state = %d\n",__func__,card_state); - ret = sprintf(buf, "%d\n", card_state); - DBG("[%s] e\n",__func__); - return ret; -} - -static ssize_t atsmb_state_store(struct kobject *kobj, struct kobj_attribute *attr, - const char *buf, size_t n) -{ - int val; - DBG("[%s] s\n",__func__); - if (sscanf(buf, "%d", &val) == 1) { - DBG("[%s] val = %d\n",__func__,val); - if ((val == 1) && (mmc_host_attr->card == NULL)) { - DBG("[%s]add card\n",__func__); - mmc_detect_change(mmc_host_attr, 0); - msleep(500); - } else if ((val == 0) && (mmc_host_attr->card != NULL)) { - DBG("[%s]remove card\n",__func__); - mmc_force_remove_card(mmc_host_attr); - } - DBG("[%s] e1\n",__func__); - return n; - } - DBG("[%s] e2\n",__func__); - return -EINVAL; -} - -static struct kobj_attribute atsmb_state_attr = { \ - .attr = { \ - .name = __stringify(state), \ - .mode = 0755, \ - }, \ - .show = atsmb_state_show, \ - .store = atsmb_state_store, \ -}; - -static struct attribute * g[] = { - &atsmb_state_attr.attr, - NULL, -}; - -static struct attribute_group attr_group = { - .attrs = g, -}; - //kevin add to check tf card stats every 1 sec - -static void wmt_mmc_work(struct work_struct *work) -{ - - static int card_state_save = -1; - if(mmc_host_attr!=NULL){ - struct atsmb_host *host = mmc_priv(mmc_host_attr); - int card_state; - if (mmc_host_attr->card != NULL) - card_state = 1; - else - card_state = 0; - - - //printk("check %d %d\n",atsmb_get_slot_status(host->mmc),card_state); - if(atsmb_get_slot_status(host->mmc)!=card_state){ - //the second time error,goto detect or remove card - if(card_state_save == card_state){ - - //printk("xxxxxxxxxxxxxxxxxxxxxxxxcatch error %dxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n",card_state); - mmc_detect_change(mmc_host_attr, 0); - - } - //mark status error - card_state_save =card_state; - }else - card_state_save = -1; - - } - schedule_delayed_work(&mmc_work, 1*HZ); -} -static int __init atsmb_init(void) -{ - int ret; - - int retval; - unsigned char buf[80]; - int varlen = 80; - char *varname = "wmt.sd0.param"; - int temp = 0, sd_enable = 1; /*0 :disable 1:enable*/ - unsigned char colon; - DBG("[%s] s\n",__func__); - -#ifdef CONFIG_MTD_WMT_SF - /*Read system param to identify host function 0: SD/MMC 1:SDIO wifi*/ - retval = wmt_getsyspara(varname, buf, &varlen); - if (retval == 0) { - sscanf(buf,"%x%c%d%c%d%c%d%c%d", &temp, &colon, &SD0_function,&colon,&SD0_detect_pol,&colon,&SD0_detect_pulldown,&colon,&SD0_speed); - printk(KERN_ALERT "wmt.sd0.param = %x%c%d%c%d%c%d%c%d\n", temp, colon, SD0_function,colon,SD0_detect_pol,colon,SD0_detect_pulldown,colon,SD0_speed); - sd_enable = temp & 0xf; - SDXC0_function = (temp >> 4) & 0xf; - printk(KERN_ALERT "SD0 ebable = %x, SDXC = %x, function = %x\n", - sd_enable, SDXC0_function, SD0_function); - - if (SD0_function < 0 || SD0_function >= SD_MAX_FUN) { - sd_enable = 1; - SD0_function = 0; - printk(KERN_ALERT "wmt.sd0.param func err\n"); - } - if (colon != ':') { - sd_enable = 1; - printk(KERN_ALERT "wmt.sd0.param colon err\n"); - } - - } else { - printk(KERN_ALERT "Default wmt.sd0.param = %x:%d\n", temp, SD0_function); - } - - //add by kevin guan - retval = wmt_getsyspara("wmt.sd0.ro.disable", buf, &varlen); - if (retval == 0) { - sscanf(buf,"%d", &SD0_ro_disable); - printk(KERN_ALERT "SD0_ro_disable %d\n",SD0_ro_disable); - } - -#endif - /*SD function disable*/ - if (sd_enable != 1) { - return -ENODEV; - } - - - get_driver_version(); - - if (platform_device_register(&wmt_sdmmc_device))//add by jay,for modules support - return -1; - //ret = platform_driver_register(&atsmb_driver); - - /* Register regulator for SD host power switch */ - atsmb_regulator = regulator_get(NULL, "ldo4"); - if (IS_ERR(atsmb_regulator)) - g_atsmb_regulator = 0; - else - g_atsmb_regulator = 1; - printk("[SD/MMC]use_regulator = %d\n", g_atsmb_regulator); - - /* Force to disable ldo4 regulator, because Power switch is turned on, default */ - if (g_atsmb_regulator) { - ret = regulator_force_disable(atsmb_regulator); - if (ret != 0) - printk(KERN_ALERT "[%s] get regulator Fail, ret = %d\n", __FUNCTION__, ret); - } - - ret = platform_driver_probe(&atsmb_driver, atsmb_probe); - - atsmb_kobj = kobject_create_and_add("mmc0", NULL); - if (!atsmb_kobj) - return -ENOMEM; - - - { - //add by kevin guan - int detect_disable = 0; - retval = wmt_getsyspara("wmt.sd0.detect.disable", buf, &varlen); - if (retval == 0) { - sscanf(buf,"%d", &detect_disable); - printk(KERN_ALERT "detect_disable %d\n",detect_disable); - } - - if(detect_disable){ - //tf slot without detect pin. - //do nothing; - }else{ - //kevin add to check tf card stats every 1 sec - INIT_DELAYED_WORK(&mmc_work, wmt_mmc_work); - schedule_delayed_work(&mmc_work, 1*HZ); - } - } - - return sysfs_create_group(atsmb_kobj, &attr_group); - - DBG("[%s] e\n",__func__); - return ret; -} - -static void __exit atsmb_exit(void) -{ - DBG("[%s] s\n",__func__); - (void)platform_driver_unregister(&atsmb_driver); - (void)platform_device_unregister(&wmt_sdmmc_device);//add by jay,for modules support - DBG("[%s] e\n",__func__); -} - -module_init(atsmb_init); -module_exit(atsmb_exit); -module_param(fmax0, uint, 0444); - -MODULE_AUTHOR("WonderMedia Technologies, Inc."); -MODULE_DESCRIPTION("WMT [AHB to SD/MMC Bridge] driver"); -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/mmc/host/mmc_atsmb.h b/ANDROID_3.4.5/drivers/mmc/host/mmc_atsmb.h deleted file mode 100755 index 845b1116..00000000 --- a/ANDROID_3.4.5/drivers/mmc/host/mmc_atsmb.h +++ /dev/null @@ -1,691 +0,0 @@ -/*++ -linux/drivers/mmc/host/mmc_atsmb.h - -Copyright (c) 2008 WonderMedia Technologies, Inc. - -This program is free software: you can redistribute it and/or modify it under the -terms of the GNU General Public License as published by the Free Software Foundation, -either version 2 of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A -PARTICULAR PURPOSE. See the GNU General Public License for more details. -You should have received a copy of the GNU General Public License along with -this program. If not, see <http://www.gnu.org/licenses/>. - -WonderMedia Technologies, Inc. -10F, 529, Chung-Cheng Road, Hsin-Tien, Taipei 231, R.O.C. ---*/ - - - -#ifndef __MMC_ATSMB_H -#define __MMC_ATSMB_H - -#define MMC0_DRIVER_NAME "sdmmc" -#define MMC1_DRIVER_NAME "sdmmc1" -#define MMC2_DRIVER_NAME "sdmmc2" - - - -#define MMC_ERR_NONE 0 /* Only for Android kernel 2.6.29, in MVL5, this variable is defined in mmc.h */ -#define MMC_ERR_FAILED 4 /* Only for Android kernel 2.6.29, in MVL5, this variable is defined in mmc.h */ -/***************Driver version****************/ -#define MMC_DRV_3357_A0_A3 0 -#define MMC_DRV_3357_A4_A7 1 -#define MMC_DRV_3358 2 -#define MMC_DRV_3359 3 -#define MMC_DRV_3400_A0 4 -#define MMC_DRV_3400_A1 5 -#define MMC_DRV_3426_A0 6 -#define MMC_DRV_3426_A1 7 -#define MMC_DRV_3426_A2 8 -#define MMC_DRV_3437_A0 9 -#define MMC_DRV_3437_A1 10 -#define MMC_DRV_3429 11 -#define MMC_DRV_3451_A0 12 -#define MMC_DRV_3465 13 -#define MMC_DRV_3445 14 -#define MMC_DRV_3481 15 -#define MMC_DRV_3498 16 -/************** INT and Base address*****************/ -/*special settings for each one*/ - -#define MMC_ATSMB0_BASE SD0_SDIO_MMC_BASE_ADDR -#define MMC_ATMSB0_END (SD0_SDIO_MMC_BASE_ADDR + 0x3FF) - -#define MMC_ATSMB1_BASE SD1_SDIO_MMC_BASE_ADDR -#define MMC_ATMSB1_END (SD1_SDIO_MMC_BASE_ADDR + 0x3FF) - -#define MMC_ATSMB2_BASE SD2_SDIO_MMC_BASE_ADDR -#define MMC_ATMSB2_END (SD2_SDIO_MMC_BASE_ADDR + 0x3FF) - - -/************** INT and Base address*****************/ - -/* SD0 pin */ -#define GPIO_SD0_CD BIT4 -#define GPIO_SD0_Data (BIT6 | BIT5 | BIT4 | BIT3) -#define GPIO_SD0_WriteProtect BIT2 -#define GPIO_SD0_Command BIT1 -#define GPIO_SD0_Clock BIT0 -#define GPIO_SD0_POWER BIT7 -#define GPIO_SD0_18SEL BIT4 - -/* SD1 pin */ -#define GPIO_SD1_Data (BIT7 | BIT6 | BIT5 | BIT4 | BIT3 | BIT2 | BIT1 | BIT0) -#define GPIO_SD1_Command BIT1 -#define GPIO_SD1_Clock BIT0 -#define GPIO_SD1_CD BIT6 -#define GPIO_SD1_WriteProtect BIT5 -#define GPIO_SD1_POWER BIT4 -#define GPIO_SD1_RSTN BIT3 - -/* SD2 pin */ -#define GPIO_SD2_Data (BIT3 | BIT2 | BIT1 | BIT0) -#define GPIO_SD2_Command BIT4 -#define GPIO_SD2_Clock BIT5 -#define GPIO_SD2_CD BIT0 -#define GPIO_SD2_WriteProtect BIT7 -#define GPIO_SD2_POWER BIT6 - -/* SDIO Power pin */ -#define SDIO_WIFI_PWR BIT2 -#define SDIO_WIFI_INT BIT3 -#define SOIO_WIFI_WAKE_FUN BIT27 - -#define SD0_PIN (GPIO_SD0_Clock | GPIO_SD0_Command | GPIO_SD0_WriteProtect | GPIO_SD0_Data) -#define SD1_PIN (GPIO_SD1_Clock | GPIO_SD1_Command | GPIO_SD1_WriteProtect | GPIO_SD1_RSTN) -#define SD2_PIN (GPIO_SD2_Clock | GPIO_SD2_Command | GPIO_SD2_WriteProtect | GPIO_SD2_Data) - -/* PIN share switch */ -#define GPIO_SD1_PinShare BIT11 -#define GPIO_SD2_PinShare BIT28 - -#define SD0_CARD_PWR BIT1 -#define SD1_CARD_PWR BIT2 -#define SD2_CARD_PWR BIT3 - -/* IO Deive Strength and Slew Rate*/ -#define SD0_IO_Slew_Rate BIT1 -#define SD0_IO_Drive_Strength BIT0 - - - -/*common settings*/ - -#define NR_SG 128 - -/*=============================================*/ -/* WMT ATSMB Register Offset*/ -/*=============================================*/ -#define _CTL 0x00 /* 1 byte*/ -#define _CMD_IDX 0x01 /* 1 byte*/ -#define _RSP_TYPE 0x02 /* 1 byte*/ - -#define _CMD_ARG 0x04 /* 4 bytes*/ -#define _BUS_MODE 0x08 /* 1 byte*/ -#define _EXT_BUS_MODE 0x09 /* 1 byte*/ -#define _CTL2 0x0a /* 2 bytes*/ -#define _BLK_LEN 0x0c /* 2 bytes*/ -#define _BLK_CNT 0x0e /* 2 bytes*/ -#define _RSP_0 0x10 /* 1 bytes*/ -#define _RSP_1 0x11 /* 1 bytes*/ -#define _RSP_2 0x12 /* 1 bytes*/ -#define _RSP_3 0x13 /* 1 bytes*/ -#define _RSP_4 0x14 /* 1 bytes*/ -#define _RSP_5 0x15 /* 1 bytes*/ -#define _RSP_6 0x16 /* 1 bytes*/ -#define _RSP_7 0x17 /* 1 bytes*/ -#define _RSP_8 0x18 /* 1 bytes*/ -#define _RSP_9 0x19 /* 1 bytes*/ -#define _RSP_10 0x1a /* 1 bytes*/ -#define _RSP_11 0x1b /* 1 bytes*/ -#define _RSP_12 0x1c /* 1 bytes*/ -#define _RSP_13 0x1d /* 1 bytes*/ -#define _RSP_14 0x1e /* 1 bytes*/ -#define _RSP_15 0x1f /* 1 bytes*/ - -#define _CURBLK_CNT 0x20 /* 4 bytes*/ -#define _INT_MASK_0 0x24 /* 1 byte*/ -#define _INT_MASK_1 0x25 /* 1 byte*/ - -#define _SD_STS_0 0x28 /* 1 byte*/ -#define _SD_STS_1 0x29 /* 1 byte*/ -#define _SD_STS_2 0x2a /* 1 byte*/ -#define _SD_STS_3 0x2b /* 1 byte*/ -#define _RSP_TOUT 0x2c /* 1 byte*/ - -#define _CLK_SEL 0x30 /* 1 byte*/ /*Not used*/ - -#define _EXT_CTL 0x34 /* 1 byte*/ -#define _EXT_CTL_1 0x35 /* 1 byte*/ -#define _EXT_CTL_2 0x36 /* 1 byte*/ - -#define _SHDW_BLKLEN 0x38 /* 2 bytes*/ -#define _MAN_TUNE_VAL 0x3a /* 1 byte*/ -#define _SD_WRI_TUNE 0x3b /* 1 byte*/ -#define _TIMER_VAL 0x3c /* 2 bytes*/ - - -#define _PDMA_GCR 0x100 -#define _PDMA_IER 0x104 -#define _PDMA_ISR 0x108 -#define _PDMA_DESPR 0x10C -#define _PDMA_RBR 0x110 -#define _PDMA_DAR 0x114 -#define _PDMA_BAR 0x118 -#define _PDMA_CPR 0x11C -#define _PDMA_CCR 0X120 - - -/*=========================================*/ -/* SD0 PDMA related Registers */ -/*=========================================*/ -#define ATSMB0_PDMA_GCR (REG32_PTR(_PDMA_GCR + MMC_ATSMB0_BASE)) -#define ATSMB0_PDMA_IER (REG32_PTR(_PDMA_IER + MMC_ATSMB0_BASE)) -#define ATSMB0_PDMA_ISR (REG32_PTR(_PDMA_ISR + MMC_ATSMB0_BASE)) -#define ATSMB0_PDMA_DESPR (REG32_PTR(_PDMA_DESPR + MMC_ATSMB0_BASE)) -#define ATSMB0_PDMA_RBR (REG32_PTR(_PDMA_RBR + MMC_ATSMB0_BASE)) -#define ATSMB0_PDMA_DAR (REG32_PTR(_PDMA_DAR + MMC_ATSMB0_BASE)) -#define ATSMB0_PDMA_BAR (REG32_PTR(_PDMA_BAR + MMC_ATSMB0_BASE)) -#define ATSMB0_PDMA_CPR (REG32_PTR(_PDMA_CPR + MMC_ATSMB0_BASE)) -#define ATSMB0_PDMA_CCR (REG32_PTR(_PDMA_CCR + MMC_ATSMB0_BASE)) - - -/*=========================================*/ -/* SD0 Register pointer. */ -/*=========================================*/ -#define ATSMB0_CTL (REG8_PTR(_CTL + MMC_ATSMB0_BASE)) -#define ATSMB0_CMD_IDX (REG8_PTR(_CMD_IDX + MMC_ATSMB0_BASE)) -#define ATSMB0_RSP_TYPE (REG8_PTR(_RSP_TYPE + MMC_ATSMB0_BASE)) -#define ATSMB0_CMD_ARG (REG32_PTR(_CMD_ARG + MMC_ATSMB0_BASE)) -#define ATSMB0_BUS_MODE (REG8_PTR(_BUS_MODE + MMC_ATSMB0_BASE)) -#define ATSMB0_EXT_BUS_MODE (REG8_PTR(_EXT_BUS_MODE + MMC_ATSMB0_BASE)) -#define ATSMB0_CTL2 (REG16_PTR(_CTL2 + MMC_ATSMB0_BASE)) -#define ATSMB0_BLK_LEN (REG16_PTR(_BLK_LEN + MMC_ATSMB0_BASE)) -#define ATSMB0_BLK_CNT (REG16_PTR(_BLK_CNT + MMC_ATSMB0_BASE)) -#define ATSMB0_RSP_0 (REG8_PTR(_RSP_0 + MMC_ATSMB0_BASE)) -#define ATSMB0_RSP_1 (REG8_PTR(_RSP_1 + MMC_ATSMB0_BASE)) -#define ATSMB0_RSP_2 (REG8_PTR(_RSP_2 + MMC_ATSMB0_BASE)) -#define ATSMB0_RSP_3 (REG8_PTR(_RSP_3 + MMC_ATSMB0_BASE)) -#define ATSMB0_RSP_4 (REG8_PTR(_RSP_4 + MMC_ATSMB0_BASE)) -#define ATSMB0_RSP_5 (REG8_PTR(_RSP_5 + MMC_ATSMB0_BASE)) -#define ATSMB0_RSP_6 (REG8_PTR(_RSP_6 + MMC_ATSMB0_BASE)) -#define ATSMB0_RSP_7 (REG8_PTR(_RSP_7 + MMC_ATSMB0_BASE)) -#define ATSMB0_RSP_8 (REG8_PTR(_RSP_8 + MMC_ATSMB0_BASE)) -#define ATSMB0_RSP_9 (REG8_PTR(_RSP_9 + MMC_ATSMB0_BASE)) -#define ATSMB0_RSP_10 (REG8_PTR(_RSP_10 + MMC_ATSMB0_BASE)) -#define ATSMB0_RSP_11 (REG8_PTR(_RSP_11 + MMC_ATSMB0_BASE)) -#define ATSMB0_RSP_12 (REG8_PTR(_RSP_12 + MMC_ATSMB0_BASE)) -#define ATSMB0_RSP_13 (REG8_PTR(_RSP_13 + MMC_ATSMB0_BASE)) -#define ATSMB0_RSP_14 (REG8_PTR(_RSP_14 + MMC_ATSMB0_BASE)) -#define ATSMB0_RSP_15 (REG8_PTR(_RSP_15 + MMC_ATSMB0_BASE)) - -#define ATSMB0_CURBLK_CNT (REG32_PTR(_CURBLK_CNT + MMC_ATSMB0_BASE)) -#define ATSMB0_INT_MASK_0 (REG8_PTR(_INT_MASK_0 + MMC_ATSMB0_BASE)) -#define ATSMB0_INT_MASK_1 (REG8_PTR(_INT_MASK_1 + MMC_ATSMB0_BASE)) -#define ATSMB0_SD_STS_0 (REG8_PTR(_SD_STS_0 + MMC_ATSMB0_BASE)) -#define ATSMB0_SD_STS_1 (REG8_PTR(_SD_STS_1 + MMC_ATSMB0_BASE)) -#define ATSMB0_SD_STS_2 (REG8_PTR(_SD_STS_2 + MMC_ATSMB0_BASE)) -#define ATSMB0_SD_STS_3 (REG8_PTR(_SD_STS_3 + MMC_ATSMB0_BASE)) - -#define ATSMB0_RSP_TOUT (REG8_PTR(_RSP_TOUT + MMC_ATSMB0_BASE)) -#define ATSMB0_CLK_SEL (REG8_PTR(_CLK_SEL + MMC_ATSMB0_BASE)) -#define ATSMB0_EXT_CTL (REG8_PTR(_EXT_CTL + MMC_ATSMB0_BASE)) -#define ATSMB0_EXT_CTL_1 (REG8_PTR(_EXT_CTL_1 + MMC_ATSMB0_BASE)) -#define ATSMB0_EXT_CTL_2 (REG8_PTR(_EXT_CTL_2 + MMC_ATSMB0_BASE)) - -#define ATSMB0_SHDW_BLKLEN (REG16_PTR(_SHDW_BLKLEN + MMC_ATSMB0_BASE)) -#define ATSMB0_MAN_TUNE_VAL (REG8_PTR(_MAN_TUNE_VAL + MMC_ATSMB0_BASE)) -#define ATSMB0_SD_WRI_TUNE (REG8_PTR(_SD_WRI_TUNE+ MMC_ATSMB0_BASE)) -#define ATSMB0_TIMER_VAL (REG16_PTR(_TIMER_VAL + MMC_ATSMB0_BASE)) - -//#define ATSMB0_INT (REG8_PTR(0xd8140056)) - - - - -/*=========================================*/ -/* SD1 PDMA related Registers */ -/*=========================================*/ -#define ATSMB1_PDMA_GCR (REG32_PTR(_PDMA_GCR + MMC_ATSMB1_BASE)) -#define ATSMB1_PDMA_IER (REG32_PTR(_PDMA_IER + MMC_ATSMB1_BASE)) -#define ATSMB1_PDMA_ISR (REG32_PTR(_PDMA_ISR + MMC_ATSMB1_BASE)) -#define ATSMB1_PDMA_DESPR (REG32_PTR(_PDMA_DESPR + MMC_ATSMB1_BASE)) -#define ATSMB1_PDMA_RBR (REG32_PTR(_PDMA_RBR + MMC_ATSMB1_BASE)) -#define ATSMB1_PDMA_DAR (REG32_PTR(_PDMA_DAR + MMC_ATSMB1_BASE)) -#define ATSMB1_PDMA_BAR (REG32_PTR(_PDMA_BAR + MMC_ATSMB1_BASE)) -#define ATSMB1_PDMA_CPR (REG32_PTR(_PDMA_CPR + MMC_ATSMB1_BASE)) -#define ATSMB1_PDMA_CCR (REG32_PTR(_PDMA_CCR + MMC_ATSMB1_BASE)) - - -/*=========================================*/ -/* SD1 Register pointer. */ -/*=========================================*/ -#define ATSMB1_CTL (REG8_PTR(_CTL + MMC_ATSMB1_BASE)) -#define ATSMB1_CMD_IDX (REG8_PTR(_CMD_IDX + MMC_ATSMB1_BASE)) -#define ATSMB1_RSP_TYPE (REG8_PTR(_RSP_TYPE + MMC_ATSMB1_BASE)) -#define ATSMB1_CMD_ARG (REG32_PTR(_CMD_ARG + MMC_ATSMB1_BASE)) -#define ATSMB1_BUS_MODE (REG8_PTR(_BUS_MODE + MMC_ATSMB1_BASE)) -#define ATSMB1_EXT_BUS_MODE (REG8_PTR(_EXT_BUS_MODE + MMC_ATSMB1_BASE)) -#define ATSMB1_CTL2 (REG16_PTR(_CTL2 + MMC_ATSMB1_BASE)) -#define ATSMB1_BLK_LEN (REG16_PTR(_BLK_LEN + MMC_ATSMB1_BASE)) -#define ATSMB1_BLK_CNT (REG16_PTR(_BLK_CNT + MMC_ATSMB1_BASE)) -#define ATSMB1_RSP_0 (REG8_PTR(_RSP_0 + MMC_ATSMB1_BASE)) -#define ATSMB1_RSP_1 (REG8_PTR(_RSP_1 + MMC_ATSMB1_BASE)) -#define ATSMB1_RSP_2 (REG8_PTR(_RSP_2 + MMC_ATSMB1_BASE)) -#define ATSMB1_RSP_3 (REG8_PTR(_RSP_3 + MMC_ATSMB1_BASE)) -#define ATSMB1_RSP_4 (REG8_PTR(_RSP_4 + MMC_ATSMB1_BASE)) -#define ATSMB1_RSP_5 (REG8_PTR(_RSP_5 + MMC_ATSMB1_BASE)) -#define ATSMB1_RSP_6 (REG8_PTR(_RSP_6 + MMC_ATSMB1_BASE)) -#define ATSMB1_RSP_7 (REG8_PTR(_RSP_7 + MMC_ATSMB1_BASE)) -#define ATSMB1_RSP_8 (REG8_PTR(_RSP_8 + MMC_ATSMB1_BASE)) -#define ATSMB1_RSP_9 (REG8_PTR(_RSP_9 + MMC_ATSMB1_BASE)) -#define ATSMB1_RSP_10 (REG8_PTR(_RSP_10 + MMC_ATSMB1_BASE)) -#define ATSMB1_RSP_11 (REG8_PTR(_RSP_11 + MMC_ATSMB1_BASE)) -#define ATSMB1_RSP_12 (REG8_PTR(_RSP_12 + MMC_ATSMB1_BASE)) -#define ATSMB1_RSP_13 (REG8_PTR(_RSP_13 + MMC_ATSMB1_BASE)) -#define ATSMB1_RSP_14 (REG8_PTR(_RSP_14 + MMC_ATSMB1_BASE)) -#define ATSMB1_RSP_15 (REG8_PTR(_RSP_15 + MMC_ATSMB1_BASE)) - -#define ATSMB1_CURBLK_CNT (REG32_PTR(_CURBLK_CNT + MMC_ATSMB1_BASE)) -#define ATSMB1_INT_MASK_0 (REG8_PTR(_INT_MASK_0 + MMC_ATSMB1_BASE)) -#define ATSMB1_INT_MASK_1 (REG8_PTR(_INT_MASK_1 + MMC_ATSMB1_BASE)) -#define ATSMB1_SD_STS_0 (REG8_PTR(_SD_STS_0 + MMC_ATSMB1_BASE)) -#define ATSMB1_SD_STS_1 (REG8_PTR(_SD_STS_1 + MMC_ATSMB1_BASE)) -#define ATSMB1_SD_STS_2 (REG8_PTR(_SD_STS_2 + MMC_ATSMB1_BASE)) -#define ATSMB1_SD_STS_3 (REG8_PTR(_SD_STS_3 + MMC_ATSMB1_BASE)) - -#define ATSMB1_RSP_TOUT (REG8_PTR(_RSP_TOUT + MMC_ATSMB1_BASE)) -#define ATSMB1_CLK_SEL (REG8_PTR(_CLK_SEL + MMC_ATSMB1_BASE)) -#define ATSMB1_EXT_CTL (REG8_PTR(_EXT_CTL + MMC_ATSMB1_BASE)) -#define ATSMB1_EXT_CTL_1 (REG8_PTR(_EXT_CTL_1 + MMC_ATSMB1_BASE)) -#define ATSMB1_EXT_CTL_2 (REG8_PTR(_EXT_CTL_2 + MMC_ATSMB1_BASE)) - -#define ATSMB1_SHDW_BLKLEN (REG16_PTR(_SHDW_BLKLEN + MMC_ATSMB1_BASE)) -#define ATSMB1_MAN_TUNE_VAL (REG8_PTR(_MAN_TUNE_VAL + MMC_ATSMB1_BASE)) -#define ATSMB1_SD_WRI_TUNE (REG8_PTR(_SD_WRI_TUNE+ MMC_ATSMB1_BASE)) -#define ATSMB1_TIMER_VAL (REG16_PTR(_TIMER_VAL + MMC_ATSMB1_BASE)) - - - -/*=========================================*/ -/* SD2 PDMA related Registers */ -/*=========================================*/ -#define ATSMB2_PDMA_GCR (REG32_PTR(_PDMA_GCR + MMC_ATSMB2_BASE)) -#define ATSMB2_PDMA_IER (REG32_PTR(_PDMA_IER + MMC_ATSMB2_BASE)) -#define ATSMB2_PDMA_ISR (REG32_PTR(_PDMA_ISR + MMC_ATSMB2_BASE)) -#define ATSMB2_PDMA_DESPR (REG32_PTR(_PDMA_DESPR + MMC_ATSMB2_BASE)) -#define ATSMB2_PDMA_RBR (REG32_PTR(_PDMA_RBR + MMC_ATSMB2_BASE)) -#define ATSMB2_PDMA_DAR (REG32_PTR(_PDMA_DAR + MMC_ATSMB2_BASE)) -#define ATSMB2_PDMA_BAR (REG32_PTR(_PDMA_BAR + MMC_ATSMB2_BASE)) -#define ATSMB2_PDMA_CPR (REG32_PTR(_PDMA_CPR + MMC_ATSMB2_BASE)) -#define ATSMB2_PDMA_CCR (REG32_PTR(_PDMA_CCR + MMC_ATSMB2_BASE)) - - -/*=========================================*/ -/* SD2 Register pointer. */ -/*=========================================*/ -#define ATSMB2_CTL (REG8_PTR(_CTL + MMC_ATSMB2_BASE)) -#define ATSMB2_CMD_IDX (REG8_PTR(_CMD_IDX + MMC_ATSMB2_BASE)) -#define ATSMB2_RSP_TYPE (REG8_PTR(_RSP_TYPE + MMC_ATSMB2_BASE)) -#define ATSMB2_CMD_ARG (REG32_PTR(_CMD_ARG + MMC_ATSMB2_BASE)) -#define ATSMB2_BUS_MODE (REG8_PTR(_BUS_MODE + MMC_ATSMB2_BASE)) -#define ATSMB2_EXT_BUS_MODE (REG8_PTR(_EXT_BUS_MODE + MMC_ATSMB2_BASE)) -#define ATSMB2_CTL2 (REG16_PTR(_CTL2 + MMC_ATSMB2_BASE)) -#define ATSMB2_BLK_LEN (REG16_PTR(_BLK_LEN + MMC_ATSMB2_BASE)) -#define ATSMB2_BLK_CNT (REG16_PTR(_BLK_CNT + MMC_ATSMB2_BASE)) -#define ATSMB2_RSP_0 (REG8_PTR(_RSP_0 + MMC_ATSMB2_BASE)) -#define ATSMB2_RSP_1 (REG8_PTR(_RSP_1 + MMC_ATSMB2_BASE)) -#define ATSMB2_RSP_2 (REG8_PTR(_RSP_2 + MMC_ATSMB2_BASE)) -#define ATSMB2_RSP_3 (REG8_PTR(_RSP_3 + MMC_ATSMB2_BASE)) -#define ATSMB2_RSP_4 (REG8_PTR(_RSP_4 + MMC_ATSMB2_BASE)) -#define ATSMB2_RSP_5 (REG8_PTR(_RSP_5 + MMC_ATSMB2_BASE)) -#define ATSMB2_RSP_6 (REG8_PTR(_RSP_6 + MMC_ATSMB2_BASE)) -#define ATSMB2_RSP_7 (REG8_PTR(_RSP_7 + MMC_ATSMB2_BASE)) -#define ATSMB2_RSP_8 (REG8_PTR(_RSP_8 + MMC_ATSMB2_BASE)) -#define ATSMB2_RSP_9 (REG8_PTR(_RSP_9 + MMC_ATSMB2_BASE)) -#define ATSMB2_RSP_10 (REG8_PTR(_RSP_10 + MMC_ATSMB2_BASE)) -#define ATSMB2_RSP_11 (REG8_PTR(_RSP_11 + MMC_ATSMB2_BASE)) -#define ATSMB2_RSP_12 (REG8_PTR(_RSP_12 + MMC_ATSMB2_BASE)) -#define ATSMB2_RSP_13 (REG8_PTR(_RSP_13 + MMC_ATSMB2_BASE)) -#define ATSMB2_RSP_14 (REG8_PTR(_RSP_14 + MMC_ATSMB2_BASE)) -#define ATSMB2_RSP_15 (REG8_PTR(_RSP_15 + MMC_ATSMB2_BASE)) - -#define ATSMB2_CURBLK_CNT (REG32_PTR(_CURBLK_CNT + MMC_ATSMB2_BASE)) -#define ATSMB2_INT_MASK_0 (REG8_PTR(_INT_MASK_0 + MMC_ATSMB2_BASE)) -#define ATSMB2_INT_MASK_1 (REG8_PTR(_INT_MASK_1 + MMC_ATSMB2_BASE)) -#define ATSMB2_SD_STS_0 (REG8_PTR(_SD_STS_0 + MMC_ATSMB2_BASE)) -#define ATSMB2_SD_STS_1 (REG8_PTR(_SD_STS_1 + MMC_ATSMB2_BASE)) -#define ATSMB2_SD_STS_2 (REG8_PTR(_SD_STS_2 + MMC_ATSMB2_BASE)) -#define ATSMB2_SD_STS_3 (REG8_PTR(_SD_STS_3 + MMC_ATSMB2_BASE)) - -#define ATSMB2_RSP_TOUT (REG8_PTR(_RSP_TOUT + MMC_ATSMB2_BASE)) -#define ATSMB2_CLK_SEL (REG8_PTR(_CLK_SEL + MMC_ATSMB2_BASE)) -#define ATSMB2_EXT_CTL (REG8_PTR(_EXT_CTL + MMC_ATSMB2_BASE)) -#define ATSMB2_EXT_CTL_1 (REG8_PTR(_EXT_CTL_1 + MMC_ATSMB2_BASE)) -#define ATSMB2_EXT_CTL_2 (REG8_PTR(_EXT_CTL_2 + MMC_ATSMB2_BASE)) - -#define ATSMB2_SHDW_BLKLEN (REG16_PTR(_SHDW_BLKLEN + MMC_ATSMB2_BASE)) -#define ATSMB2_MAN_TUNE_VAL (REG8_PTR(_MAN_TUNE_VAL + MMC_ATSMB2_BASE)) -#define ATSMB2_SD_WRI_TUNE (REG8_PTR(_SD_WRI_TUNE+ MMC_ATSMB2_BASE)) -#define ATSMB2_TIMER_VAL (REG16_PTR(_TIMER_VAL + MMC_ATSMB2_BASE)) - - -/*=========================================*/ -/* Register usage const*/ -/*=========================================*/ -/*================================================================================*/ -/**/ -/* SD Host Register Bit Fields*/ -/**/ -/*================================================================================*/ -/**/ -/* Control Register*/ -#define ATSMB_START 0x1 -#define ATSMB_SPISTP BIT1 -#define ATSMB_RXTX BIT2 -#define ATSMB_FFRST BIT3 -#define ATSMB_CT (BIT4|BIT5|BIT6|BIT7) -/**/ -/* Command Index Register*/ - -/**/ -/*Response Type Register*/ -#define ATSMB_RT (BIT0|BIT1|BIT2|BIT3) -#define ATSMB_RY BIT4 - -/**/ -/* Command Argument Register 0,1,2,3*/ - -/**/ -/* Bus Mode Register*/ -#define ATSMB_SPI BIT0 -#define ATSMB_BUS_WIDTH_4 BIT1 -#define ATSMB_RW BIT2 -#define ATSMB_SPICRC BIT3 -#define ATSMB_CST BIT4 -#define ATSMB_SPICS BIT5 -#define ATSMB_SDPWR BIT6 -#define ATSMB_SFTRST BIT7 - -/**/ -/* Block Length Register 0,1*/ -#define ATSMB_BS_L (BIT0|BIT1|BIT2|BIT3|BIT4|BIT5|BIT6|BIT7) -#define ATSMB_BS_H (BIT8|BIT9|BIT10) -#define ATSMB_CFD BIT4 -#define ATSMB_INTEN BIT7 - -/**/ -/* Block Count Register 0,1*/ - -/**/ -/* Response Register*/ - -/**/ -/* Data Register*/ - -/**/ -/* Interrupt Mask Register 0*/ -#define ATSMB_THIE BIT0 -#define ATSMB_TEIE BIT1 -#define ATSMB_TAIE BIT2 -#define ATSMB_RHIE BIT3 -#define ATSMB_MULTI_XFER_DONE_EN BIT4 -#define ATSMB_BLOCK_XFER_DONE_EN BIT5 -#define ATSMB_CDIE BIT6 -#define ATSMB_DEVICE_INSERT_EN BIT7 - -/**/ -/* Interrupt Mask Register 1*/ -#define ATSMB_SDIO_EN BIT0 -#define ATSMB_RSP_DONE_EN BIT1 -#define ATSMB_RSP_TIMEOUT_EN BIT2 -#define ATSMB_AUTO_STOP_EN BIT3 -#define ATSMB_DATA_TIMEOUT_EN BIT4 -#define ATSMB_RSP_CRC_ERR_EN BIT5 -#define ATSMB_READ_CRC_ERR_EN BIT6 -#define ATSMB_WRITE_CRC_ERR_EN BIT7 - -/**/ -/* SD Status Register 0*/ -#define ATSMB_TH BIT0 -#define ATSMB_WRITE_PROTECT BIT1 /* 1. write protected is disabled.*/ -#define ATSMB_CARD_NOT_IN_SLOT BIT2 -#define ATSMB_CARD_NOT_IN_SLOT_GPI BIT3 -#define ATSMB_MULTI_XFER_DONE BIT4 -#define ATSMB_BLOCK_XFER_DONE BIT5 -#define ATSMB_SD_CD BIT6 /* what is its purpose?*/ -#define ATSMB_DEVICE_INSERT BIT7 - -/**/ -/* SD Status Register 1*/ -#define ATSMB_SDIO_INT BIT0 -#define ATSMB_RSP_DONE BIT1 -#define ATSMB_RSP_TIMEOUT BIT2 -#define ATSMB_AUTO_STOP BIT3 -#define ATSMB_DATA_TIMEOUT BIT4 -#define ATSMB_RSP_CRC_ERR BIT5 -#define ATSMB_READ_CRC_ERR BIT6 -#define ATSMB_WRITE_CRC_ERR BIT7 - -/**/ -/* SD Status Register 2*/ -#define ATSMB_RSP_BUSY BIT5 -#define ATSMB_CLK_FREEZ_STS BIT6 -#define ATSMB_CLK_FREEZ_EN BIT7 - - -/* SD Response types*/ -#define ATMSB_TYPE_R0 0 /* NONE response*/ -#define ATMSB_TYPE_R1 1 /* Basic response format*/ -#define ATMSB_TYPE_R2 2 /* R2 response. Used by ALL_SEND_CID(CMD2),*/ -/* SEND_CID(CMD10) and SEND_CSD(CMD9)*/ -#define ATMSB_TYPE_R3 3 /* R3 response. Used by SEND_APP_OP_COND(ACMD41)*/ -#define ATMSB_TYPE_R6 6 /* R6 response. Used by SEND_RELATIVE_ADDR(CMD3)*/ -#define ATMSB_TYPE_R7 7 /* R6 response. Used by SEND_RELATIVE_ADDR(CMD3)*/ -#define ATMSB_TYPE_R1b 9 -#define ATMSB_TYPE_R5 5 -#define ATMSB_TYPE_R4 4 - -/* - * SD PDMA - */ -struct SD_PDMA_REG { - unsigned long DMA_GCR; /* Rx00 */ - unsigned long DMA_IER; /* Rx04 */ - unsigned long DMA_ISR; /* Rx08 */ - unsigned long *DMA_DESPR; /* Rx0C */ - unsigned long DMA_RBR; /* Rx10 */ - unsigned long DMA_DAR; /* Rx14 */ - unsigned long DMA_BAR; /* Rx18 */ - unsigned long DMA_CPR; /* Rx1C */ - unsigned long DMA_CCR; /* RX20 */ - unsigned long resv[5]; /* RX2C-3C */ -}; -/* - * SD PDMA - DMA_GCR : DMA Global Control Register - */ -#define SD_PDMA_GCR_DMA_EN 0x00000001 /* [0] -- DMA controller enable*/ -#define SD_PDMA_GCR_SOFTRESET 0x00000100 /* [8] -- Software rest*/ - -/* - * SD PDMA - DMA_IER : DMA Interrupt Enable Register - */ -#define SD_PDMA_IER_INT_EN 0x00000001 /* [0] --DMA interrupt enable */ -/* - * SD PDMA - DMA_ISR : DMA Interrupt Status Register - */ -#define SD_PDMA_IER_INT_STS 0x00000001 /* [0] -- DMA interrupt status */ -/* - * SD PDMA - DMA_DESPR : DMA Descriptor base address Pointer Register - */ - -/* - * SD PDMA - DMA_RBR : DMA Residual Bytes Register - */ -#define SD_PDMA_RBR_End 0x80000000 /* [0] -- DMA interrupt status */ -#define SD_PDMA_RBR_Format 0x40000000 /* [0] -- DMA interrupt status */ -/* - * SD PDMA - DMA_DAR : DMA Data Address Register - */ - -/* - * SD PDMA - DMA_BAR : DMA Rbanch Address Register - */ - -/* - * SD PDMA - DMA_CPR : DMA Command Pointer Register - */ - -/* - * SD PDMA - DMA_CCR : DMAContext Control Register for Channel 0 - */ -#define SD_PDMA_READ 0x00 -#define SD_PDMA_WRITE 0x01 -#define SD_PDMA_CCR_RUN 0x00000080 -#define SD_PDMA_CCR_IF_to_peripheral 0x00000000 -#define SD_PDMA_CCR_peripheral_to_IF 0x00400000 -#define SD_PDMA_CCR_EvtCode 0x0000000f -#define SD_PDMA_CCR_Evt_no_status 0x00000000 -#define SD_PDMA_CCR_Evt_ff_underrun 0x00000001 -#define SD_PDMA_CCR_Evt_ff_overrun 0x00000002 -#define SD_PDMA_CCR_Evt_desp_read 0x00000003 -#define SD_PDMA_CCR_Evt_data_rw 0x00000004 -#define SD_PDMA_CCR_Evt_early_end 0x00000005 -#define SD_PDMA_CCR_Evt_success 0x0000000f - -/* - * PDMA Descriptor short - */ -struct SD_PDMA_DESC_S{ - unsigned long volatile ReqCount : 16; /* bit 0 -15 -Request count */ - unsigned long volatile i : 1; /* bit 16 -interrupt */ - unsigned long volatile reserve : 13; /* bit 17-29 -reserved */ - unsigned long volatile format : 1; /* bit 30 -The descriptor format */ - unsigned long volatile end : 1; /* bit 31 -End flag of descriptor list*/ - unsigned long volatile *DataBufferAddr; /* bit 31 -Data Buffer address */ -} ; - -/* - * PDMA Descriptor long - */ -struct SD_PDMA_DESC_L{ - unsigned long volatile ReqCount:16; /* bit 0-15-Request count */ - unsigned long volatile i:1; /* bit 16 -interrupt*/ - unsigned long volatile reserve:13; /* bit 17-29-reserved*/ - unsigned long volatile format:1; /* bit 30-The descriptor format */ - unsigned long volatile end:1; /* bit 31 -End flag of descriptor list*/ - unsigned long volatile *DataBufferAddr; /* bit 31-0 -Data Buffer address*/ - unsigned long volatile *BranchAddr; /* bit 31-2-Descriptor Branch address*/ - unsigned long volatile reserve0; /* bit 31-0-reserved*/ -}; - - -/**/ -/* DMA usage const for Rx08[Config]*/ -/**/ -#define DMA_CFG_WRITE 0x0 -#define DMA_CFG_READ 0x10000 -/* -#define DMA_CFG_8B 0x00 -#define DMA_CFG_16B 0x01 -#define DMA_CFG_32B 0x02 - -#define DMA_CFG_SINGLE 0x00 -#define DMA_CFG_INC4 0x10 -#define DMA_CFG_INC8 0x20 - -#define DMA_CFG_DATA 0x100 -#define DMA_CFG_PRIVILEDGE 0x200 -#define DMA_CFG_BUFFER 0x400 -#define DMA_CFG_CACHE 0x800 - -#define DMA_CFG_INC 0x1000 -#define DMA_CFG_READ 0x10000 -#define DMA_CFG_WRITE 0x0 - -#define DMA_CFG_NOINT 0x0 -#define DMA_CFG_ENTCINT 0x100000 -#define DMA_CFG_ENXFERINT 0x200000 -#define DMA_CFG_ENERRINT 0x400000 -#define DMA_CFG_ENFIFOINT 0x800000 - -// -// DMA usage const for RxC[Control] -// -#define DMA_CTL_ENABLE 0x1 -#define DMA_CTL_SOFTREQ 0x10 - -// -// DMA usage const for Rx10[Status] -// -#define DMA_STS_TC 0x1 -#define DMA_STS_AHB_ERROR 0x4 -#define DMA_STS_FIFO_EMPTY 0x8 -#define DMA_STS_BULK_COMPLETE 0x2 -*/ -/*=========================================*/ -/* structure definition.*/ -/*=========================================*/ -struct atsmb_host { - struct mmc_host *mmc; - spinlock_t lock; - struct resource *res; - void *base; - int regular_irq; - int dma_irq; - /* 2009/01/13 janshiue-s */ - unsigned long *DescVirAddr; - dma_addr_t DescPhyAddr; - unsigned int DescSize; - unsigned long *BufVirAddr; - dma_addr_t BufPhyAddr; - unsigned long DmaIntMask; - /* 2009/01/13 janshiue-s */ - struct mmc_request *mrq; - struct mmc_command *cmd; - struct mmc_data *data; - u32 pwr; - struct mmc_platform_data *plat; - unsigned int sg_len; - /* pio stuff */ - struct scatterlist *sg_ptr; - unsigned int sg_off; - unsigned int size; - /* to support sg, we need little loops when requesting data*/ - u32 opcode; - /*this code may different from the one in command. Eg. When we are accessing data*/ - unsigned char soft_timeout; - void *done_data; /* completion data */ - void (*done)(void *data);/* completion function */ - int current_clock; - -}; - -#define MAX_DESC_NUM 256 - -enum WMT_SD_FUN { - SD_MMC, - SDIO_WIFI, - SD_MAX_FUN -}; - -int atsmb_init_short_desc(unsigned long *DescAddr, unsigned int ReqCount, - unsigned long *BufferAddr, int End); -int atsmb_init_long_desc(unsigned long *DescAddr, unsigned int ReqCount, - unsigned long *BufferAddr, unsigned long *BranchAddr, int End); - -int atsmb1_init_short_desc(unsigned long *DescAddr, unsigned int ReqCount, - unsigned long *BufferAddr, int End); -int atsmb1_init_long_desc(unsigned long *DescAddr, unsigned int ReqCount, - unsigned long *BufferAddr, unsigned long *BranchAddr, int End); - -int atsmb2_init_short_desc(unsigned long *DescAddr, unsigned int ReqCount, - unsigned long *BufferAddr, int End); -int atsmb2_init_long_desc(unsigned long *DescAddr, unsigned int ReqCount, - unsigned long *BufferAddr, unsigned long *BranchAddr, int End); - - -#endif /* __MMC_ATSMB_H */ diff --git a/ANDROID_3.4.5/drivers/mmc/host/mmc_atsmb1.c b/ANDROID_3.4.5/drivers/mmc/host/mmc_atsmb1.c deleted file mode 100755 index 2cfefbcd..00000000 --- a/ANDROID_3.4.5/drivers/mmc/host/mmc_atsmb1.c +++ /dev/null @@ -1,2405 +0,0 @@ -/*++ -linux/drivers/mmc/host/mmc_atsmb1.c - -Copyright (c) 2008 WonderMedia Technologies, Inc. - -This program is free software: you can redistribute it and/or modify it under the -terms of the GNU General Public License as published by the Free Software Foundation, -either version 2 of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A -PARTICULAR PURPOSE. See the GNU General Public License for more details. -You should have received a copy of the GNU General Public License along with -this program. If not, see <http://www.gnu.org/licenses/>. - -WonderMedia Technologies, Inc. -10F, 529, Chung-Cheng Road, Hsin-Tien, Taipei 231, R.O.C. ---*/ - -//#include <linux/config.h> -#include <linux/module.h> -#include <linux/moduleparam.h> -#include <linux/init.h> -#include <linux/ioport.h> -#include <linux/device.h> -#include <linux/platform_device.h> -#include <linux/interrupt.h> -#include <linux/delay.h> -#include <linux/err.h> -#include <linux/interrupt.h> -#include <linux/blkdev.h> -#include <linux/mmc/host.h> -#include <linux/mmc/card.h> -#include <linux/mmc/sd.h> -#include <linux/mmc/mmc.h> -#include <linux/mmc/sdio.h> -#include <linux/completion.h> -#include <linux/pagemap.h> -#include <linux/dma-mapping.h> -#include <asm/dma.h> -#include <asm/io.h> -#include <asm/irq.h> -#include <asm/memory.h> -#include <mach/hardware.h> -#include <asm/scatterlist.h> -#include <asm/sizes.h> -#include "mmc_atsmb.h" -//#include <mach/multicard.h> -#include <mach/irqs.h> - -#define mprintk - -/* chcek emmc card is fist boot, 1:fisrt boot, 0:suspend/resume */ -int atsmb1_first_boot; -#if 0 -#define DBG(host, fmt, args...) \ - pr_debug("%s: %s: " fmt, mmc_hostname(host->mmc), __func__ , args) -#endif -#define ATSMB_TIMEOUT_TIME (HZ*2) - -//add by jay,for modules support -static u64 wmt_sdmmc1_dma_mask = 0xffffffffUL; -static struct resource wmt_sdmmc1_resources[] = { - [0] = { - .start = SD1_SDIO_MMC_BASE_ADDR, - .end = (SD1_SDIO_MMC_BASE_ADDR + 0x3FF), - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = IRQ_SDC1, - .end = IRQ_SDC1, - .flags = IORESOURCE_IRQ, - }, - [2] = { - .start = IRQ_SDC1_DMA, - .end = IRQ_SDC1_DMA, - .flags = IORESOURCE_IRQ, - }, - /*2008/10/6 RichardHsu-s*/ - [3] = { - .start = IRQ_PMC_WAKEUP, - .end = IRQ_PMC_WAKEUP, - .flags = IORESOURCE_IRQ, - }, - /*2008/10/6 RichardHsu-e*/ -}; - - -// -static void atsmb1_release(struct device * dev) {} - -/*#ifdef CONFIG_MMC_DEBUG*/ -#define MORE_INFO -#if 0 -#define DBG(x...) printk(KERN_ALERT x) -#define DBGR(x...) printk(KERN_ALERT x) -#else -#define DBG(x...) do { } while (0) -#define DBGR(x...) do { } while (0) -#endif - -/* when Read CRC error occur, and clear read CRC error by software reset.*/ -void atsmb1_copy_reg(int direct) -{ - static u8 CTL, CMD_IDX, RSP_TYPE, BUS_MODE, INT_MASK_0, INT_MASK_1, SD_STS_0, SD_STS_1, SD_STS_2, SD_STS_3; - static u8 EXT_BUS_MODE, EXT_CTL_1, EXT_CTL_2, MAN_TUNE_VAL, SD_WRI_TUNE; - static u8 RSP_0, RSP_1, RSP_2, RSP_3, RSP_4, RSP_5, RSP_6, RSP_7; - static u8 RSP_8, RSP_9, RSP_10, RSP_11, RSP_12, RSP_13, RSP_14, RSP_15; - static u8 RSP_TOUT, CLK_SEL, EXT_CTL; - static u16 BLK_LEN, BLK_CNT, SHDW_BLKLEN, TIMER_VAL, CTL2; - static u32 CMD_ARG, CURBLK_CNT; - - /*direct 0: copy register to memory; 1: copy memory to register.*/ - if (direct == 0) { - CTL = *ATSMB1_CTL; - CMD_IDX = *ATSMB1_CMD_IDX; - RSP_TYPE = *ATSMB1_RSP_TYPE; - CMD_ARG = *ATSMB1_CMD_ARG; - BUS_MODE = *ATSMB1_BUS_MODE; - EXT_BUS_MODE = *ATSMB1_EXT_BUS_MODE; - CTL2 = *ATSMB1_CTL2; - BLK_LEN = *ATSMB1_BLK_LEN; - BLK_CNT = *ATSMB1_BLK_CNT; - RSP_0 = *ATSMB1_RSP_0; - RSP_1 = *ATSMB1_RSP_1; - RSP_2 = *ATSMB1_RSP_2; - RSP_3 = *ATSMB1_RSP_3; - RSP_4 = *ATSMB1_RSP_4; - RSP_5 = *ATSMB1_RSP_5; - RSP_6 = *ATSMB1_RSP_6; - RSP_7 = *ATSMB1_RSP_7; - RSP_8 = *ATSMB1_RSP_8; - RSP_9 = *ATSMB1_RSP_9; - RSP_10 = *ATSMB1_RSP_10; - RSP_11 = *ATSMB1_RSP_11; - RSP_12 = *ATSMB1_RSP_12; - RSP_13 = *ATSMB1_RSP_13; - RSP_14 = *ATSMB1_RSP_14; - RSP_15 = *ATSMB1_RSP_15; - CURBLK_CNT = *ATSMB1_CURBLK_CNT; - INT_MASK_0 = *ATSMB1_INT_MASK_0; - INT_MASK_1 = *ATSMB1_INT_MASK_1; - SD_STS_0 = *ATSMB1_SD_STS_0; - SD_STS_1 = *ATSMB1_SD_STS_1; - SD_STS_2 = *ATSMB1_SD_STS_2; - SD_STS_3 = *ATSMB1_SD_STS_3; - RSP_TOUT = *ATSMB1_RSP_TOUT; - CLK_SEL = *ATSMB1_CLK_SEL; - EXT_CTL = *ATSMB1_EXT_CTL; - EXT_CTL_1 = *ATSMB1_EXT_CTL_1; - EXT_CTL_2 = *ATSMB1_EXT_CTL_2; - SHDW_BLKLEN = *ATSMB1_SHDW_BLKLEN; - MAN_TUNE_VAL = *ATSMB1_MAN_TUNE_VAL; - SD_WRI_TUNE = *ATSMB1_SD_WRI_TUNE; - TIMER_VAL = *ATSMB1_TIMER_VAL; - } else { - *ATSMB1_CTL = CTL; - *ATSMB1_CMD_IDX = CMD_IDX; - *ATSMB1_RSP_TYPE = RSP_TYPE; - *ATSMB1_CMD_ARG = CMD_ARG; - *ATSMB1_BUS_MODE = BUS_MODE; - *ATSMB1_EXT_BUS_MODE = EXT_BUS_MODE; - *ATSMB1_CTL2 = CTL2; - *ATSMB1_BLK_LEN = BLK_LEN; - *ATSMB1_BLK_CNT = BLK_CNT; - *ATSMB1_RSP_0 = RSP_0; - *ATSMB1_RSP_1 = RSP_1; - *ATSMB1_RSP_2 = RSP_2; - *ATSMB1_RSP_3 = RSP_3; - *ATSMB1_RSP_4 = RSP_4; - *ATSMB1_RSP_5 = RSP_5; - *ATSMB1_RSP_6 = RSP_6; - *ATSMB1_RSP_7 = RSP_7; - *ATSMB1_RSP_8 = RSP_8; - *ATSMB1_RSP_9 = RSP_9; - *ATSMB1_RSP_10 = RSP_10; - *ATSMB1_RSP_11 = RSP_11; - *ATSMB1_RSP_12 = RSP_12; - *ATSMB1_RSP_13 = RSP_13; - *ATSMB1_RSP_14 = RSP_14; - *ATSMB1_RSP_15 = RSP_15; - *ATSMB1_CURBLK_CNT = CURBLK_CNT; - *ATSMB1_INT_MASK_0 = INT_MASK_0; - *ATSMB1_INT_MASK_1 = INT_MASK_1; - *ATSMB1_SD_STS_0 = SD_STS_0; - *ATSMB1_SD_STS_1 = SD_STS_1; - *ATSMB1_SD_STS_2 = SD_STS_2; - *ATSMB1_SD_STS_3 = SD_STS_3; - *ATSMB1_RSP_TOUT = RSP_TOUT; - *ATSMB1_CLK_SEL = CLK_SEL; - *ATSMB1_EXT_CTL = EXT_CTL; - *ATSMB1_EXT_CTL_1 = EXT_CTL_1; - *ATSMB1_EXT_CTL_2 = EXT_CTL_2; - *ATSMB1_SHDW_BLKLEN = SHDW_BLKLEN; - *ATSMB1_MAN_TUNE_VAL = MAN_TUNE_VAL; - *ATSMB1_SD_WRI_TUNE = SD_WRI_TUNE; - *ATSMB1_TIMER_VAL = TIMER_VAL; - } -} - -#if 0 -void atsmb1_dump_reg(struct atsmb_host *host) -{ - u8 CTL, CMD_IDX, RSP_TYPE, BUS_MODE, INT_MASK_0, INT_MASK_1, SD_STS_0, SD_STS_1, SD_STS_2, SD_STS_3; - u8 EXT_BUS_MODE, EXT_CTL_1, EXT_CTL_2, MAN_TUNE_VAL, SD_WRI_TUNE; - u8 RSP_0, RSP_1, RSP_2, RSP_3, RSP_4, RSP_5, RSP_6, RSP_7; - u8 RSP_8, RSP_9, RSP_10, RSP_11, RSP_12, RSP_13, RSP_14, RSP_15; - u8 RSP_TOUT, CLK_SEL, EXT_CTL; - u16 BLK_LEN, BLK_CNT, SHDW_BLKLEN, TIMER_VAL, CTL2; - u32 CMD_ARG, PDMA_GCR, PDMA_IER, PDMA_ISR, PDMA_DESPR, PDMA_RBR, PDMA_DAR, PDMA_BAR, PDMA_CPR, PDMA_CCR; - u32 CURBLK_CNT; - - CTL = *ATSMB1_CTL; - CMD_IDX = *ATSMB1_CMD_IDX; - RSP_TYPE = *ATSMB1_RSP_TYPE; - CMD_ARG = *ATSMB1_CMD_ARG; - BUS_MODE = *ATSMB1_BUS_MODE; - EXT_BUS_MODE = *ATSMB1_EXT_BUS_MODE; - CTL2 = *ATSMB1_CTL2; - BLK_LEN = *ATSMB1_BLK_LEN; - BLK_CNT = *ATSMB1_BLK_CNT; - RSP_0 = *ATSMB1_RSP_0; - RSP_1 = *ATSMB1_RSP_1; - RSP_2 = *ATSMB1_RSP_2; - RSP_3 = *ATSMB1_RSP_3; - RSP_4 = *ATSMB1_RSP_4; - RSP_5 = *ATSMB1_RSP_5; - RSP_6 = *ATSMB1_RSP_6; - RSP_7 = *ATSMB1_RSP_7; - RSP_8 = *ATSMB1_RSP_8; - RSP_9 = *ATSMB1_RSP_9; - RSP_10 = *ATSMB1_RSP_10; - RSP_11 = *ATSMB1_RSP_11; - RSP_12 = *ATSMB1_RSP_12; - RSP_13 = *ATSMB1_RSP_13; - RSP_14 = *ATSMB1_RSP_14; - RSP_15 = *ATSMB1_RSP_15; - CURBLK_CNT = *ATSMB1_CURBLK_CNT; - INT_MASK_0 = *ATSMB1_INT_MASK_0; - INT_MASK_1 = *ATSMB1_INT_MASK_1; - SD_STS_0 = *ATSMB1_SD_STS_0; - SD_STS_1 = *ATSMB1_SD_STS_1; - SD_STS_2 = *ATSMB1_SD_STS_2; - SD_STS_3 = *ATSMB1_SD_STS_3; - RSP_TOUT = *ATSMB1_RSP_TOUT; - CLK_SEL = *ATSMB1_CLK_SEL; - EXT_CTL = *ATSMB1_EXT_CTL; - EXT_CTL_1 = *ATSMB1_EXT_CTL_1; - EXT_CTL_2 = *ATSMB1_EXT_CTL_2; - SHDW_BLKLEN = *ATSMB1_SHDW_BLKLEN; - MAN_TUNE_VAL = *ATSMB1_MAN_TUNE_VAL; - SD_WRI_TUNE = *ATSMB1_SD_WRI_TUNE; - TIMER_VAL = *ATSMB1_TIMER_VAL; - - PDMA_GCR = *ATSMB1_PDMA_GCR; - PDMA_IER = *ATSMB1_PDMA_IER; - PDMA_ISR = *ATSMB1_PDMA_ISR; - PDMA_DESPR = *ATSMB1_PDMA_DESPR; - PDMA_RBR = *ATSMB1_PDMA_RBR; - PDMA_DAR = *ATSMB1_PDMA_DAR; - PDMA_BAR = *ATSMB1_PDMA_BAR; - PDMA_CPR = *ATSMB1_PDMA_CPR; - PDMA_CCR = *ATSMB1_PDMA_CCR; - - DBGR("\n+---------------------------Registers----------------------------+\n"); - - DBGR("%16s = 0x%8x |", "CTL", CTL); - DBGR("%16s = 0x%8x\n", "CMD_IDX", CMD_IDX); - - DBGR("%16s = 0x%8x |", "RSP_TYPE", RSP_TYPE); - DBGR("%16s = 0x%8x\n", "CMD_ARG", CMD_ARG); - - DBGR("%16s = 0x%8x |", "BUS_MODE", BUS_MODE); - DBGR("%16s = 0x%8x\n", "EXT_BUS_MODE", EXT_BUS_MODE); - - DBGR("%16s = 0x%8x |", "CTL2", CTL2); - DBGR("%16s = 0x%8x\n", "BLK_LEN", BLK_LEN); - - DBGR("%16s = 0x%8x |", "BLK_CNT", BLK_CNT); - DBGR("%16s = 0x%8x\n", "RSP_0", RSP_0); - - DBGR("%16s = 0x%8x |", "RSP_1", RSP_1); - DBGR("%16s = 0x%8x\n", "RSP_2", RSP_2); - - DBGR("%16s = 0x%8x |", "RSP_3", RSP_3); - DBGR("%16s = 0x%8x\n", "RSP_4", RSP_4); - - DBGR("%16s = 0x%8x |", "RSP_5", RSP_5); - DBGR("%16s = 0x%8x\n", "RSP_6", RSP_6); - - DBGR("%16s = 0x%8x |", "RSP_7", RSP_7); - DBGR("%16s = 0x%8x\n", "RSP_8", RSP_8); - - DBGR("%16s = 0x%8x |", "RSP_9", RSP_9); - DBGR("%16s = 0x%8x\n", "RSP_10", RSP_10); - - DBGR("%16s = 0x%8x |", "RSP_11", RSP_11); - DBGR("%16s = 0x%8x\n", "RSP_12", RSP_12); - - DBGR("%16s = 0x%8x |", "RSP_13", RSP_13); - DBGR("%16s = 0x%8x\n", "RSP_14", RSP_14); - - DBGR("%16s = 0x%8x\n", "RSP_15", RSP_15); - - DBGR("%16s = 0x%8x |", "CURBLK_CNT", CURBLK_CNT); - DBGR("%16s = 0x%8x\n", "INT_MASK_0", INT_MASK_0); - - DBGR("%16s = 0x%8x |", "INT_MASK_1", INT_MASK_1); - DBGR("%16s = 0x%8x\n", "SD_STS_0", SD_STS_0); - - DBGR("%16s = 0x%8x |", "SD_STS_1", SD_STS_1); - DBGR("%16s = 0x%8x\n", "SD_STS_2", SD_STS_2); - - DBGR("%16s = 0x%8x |", "SD_STS_3", SD_STS_3); - DBGR("%16s = 0x%8x\n", "RSP_TOUT", RSP_TOUT); - - DBGR("%16s = 0x%8x |", "CLK_SEL", CLK_SEL); - DBGR("%16s = 0x%8x\n", "EXT_CTL", EXT_CTL); - - DBGR("%16s = 0x%8x |", "EXT_CTL_1", EXT_CTL_1); - DBGR("%16s = 0x%8x\n", "EXT_CTL_2", EXT_CTL_2); - - DBGR("%16s = 0x%8x |", "SHDW_BLKLEN", SHDW_BLKLEN); - DBGR("%16s = 0x%8x\n", "MAN_TUNE_VAL", MAN_TUNE_VAL); - - DBGR("%16s = 0x%8x |", "SD_WRI_TUNE", SD_WRI_TUNE); - DBGR("%16s = 0x%8x\n", "TIMER_VAL", TIMER_VAL); - - DBGR("%16s = 0x%8x |", "PDMA_GCR", PDMA_GCR); - DBGR("%16s = 0x%8x\n", "PDMA_IER", PDMA_IER); - - DBGR("%16s = 0x%8x |", "PDMA_ISR", PDMA_ISR); - DBGR("%16s = 0x%8x\n", "PDMA_DESPR", PDMA_DESPR); - - DBGR("%16s = 0x%8x |", "PDMA_RBR", PDMA_RBR); - DBGR("%16s = 0x%8x\n", "PDMA_DAR", PDMA_DAR); - - DBGR("%16s = 0x%8x |", "PDMA_BAR", PDMA_BAR); - DBGR("%16s = 0x%8x\n", "PDMA_CPR", PDMA_CPR); - - DBGR("%16s = 0x%8x |", "PDMA_CCR", PDMA_CCR); - DBGR("\n+----------------------------------------------------------------+\n"); -} -#else -void atsmb1_dump_reg(struct atsmb_host *host) {} -#endif - -unsigned int fmax1 = 515633; -unsigned int MMC1_DRIVER_VERSION; -int SD1_function = 0; /*0: normal SD/MMC card reader*/ -int SDXC1_function; - - -int SCC1_ID(void){ - unsigned short val; - - val = REG16_VAL(SYSTEM_CFG_CTRL_BASE_ADDR + 0x2); - return val; -} - -int get_chip_version1(void) /*2008/05/01 janshiue modify for A1 chip*/ -{ - u32 tmp; - - tmp = REG32_VAL(SYSTEM_CFG_CTRL_BASE_ADDR); - tmp = ((tmp & 0xF00) >> 4) + 0x90 + ((tmp & 0xFF) - 1); - return tmp; -} - -void get_driver_version1(void) -{ - if (SCC1_ID() == 0x3426) { - if (get_chip_version1() < 0xA1) - MMC1_DRIVER_VERSION = MMC_DRV_3426_A0; - else if (get_chip_version1() == 0xA1) - MMC1_DRIVER_VERSION = MMC_DRV_3426_A1; - else - MMC1_DRIVER_VERSION = MMC_DRV_3426_A2; - } else if (SCC1_ID() == 0x3437) { - if (get_chip_version1() < 0xA1) - MMC1_DRIVER_VERSION = MMC_DRV_3437_A0; - else - MMC1_DRIVER_VERSION = MMC_DRV_3437_A1; - } else if (SCC1_ID() == 0x3429) { - MMC1_DRIVER_VERSION = MMC_DRV_3429; - } else if (SCC1_ID() == 0x3451) { - if (get_chip_version1() < 0xA1) - MMC1_DRIVER_VERSION = MMC_DRV_3451_A0; - } else if (SCC1_ID() == 0x3465) { - MMC1_DRIVER_VERSION = MMC_DRV_3465; - } else if (SCC1_ID() == 0x3445) { - MMC1_DRIVER_VERSION = MMC_DRV_3445; - } else if (SCC1_ID() == 0x3481) { - MMC1_DRIVER_VERSION = MMC_DRV_3481; - } else if (SCC1_ID() == 0x3498) { - MMC1_DRIVER_VERSION = MMC_DRV_3498; - } -} -/*2008/10/6 RichardHsu-e*/ - -/********************************************************************** -Name : atsmb1_alloc_desc -Function : To config PDMA descriptor setting. -Calls : -Called by : -Parameter : -Author : Janshiue Wu -History : -***********************************************************************/ -static inline int atsmb1_alloc_desc(struct atsmb_host *host, - unsigned int bytes) -{ - void *DescPool = NULL; - DBG("[%s] s\n",__func__); - - DescPool = dma_alloc_coherent(host->mmc->parent, bytes, &(host->DescPhyAddr), GFP_KERNEL); - if (!DescPool) { - DBG("can't allocal desc pool=%8X %8X\n", DescPool, host->DescPhyAddr); - DBG("[%s] e1\n",__func__); - return -1; - } - DBG("allocal desc pool=%8X %8X\n", DescPool, host->DescPhyAddr); - host->DescVirAddr = (unsigned long *)DescPool; - host->DescSize = bytes; - DBG("[%s] e2\n",__func__); - return 0; -} - -/********************************************************************** -Name : atsmb1_config_desc -Function : To config PDMA descriptor setting. -Calls : -Called by : -Parameter : -Author : Janshiue Wu -History : -***********************************************************************/ -static inline void atsmb1_config_desc(unsigned long *DescAddr, - unsigned long *BufferAddr, - unsigned long Blk_Cnt) -{ - - int i = 0 ; - unsigned long *CurDes = DescAddr; - DBG("[%s] s\n",__func__); - - /* the first Descriptor store for 1 Block data - * (512 bytes) - */ - for (i = 0 ; i < 3 ; i++) { - atsmb1_init_short_desc(CurDes, 0x80, BufferAddr, 0); - BufferAddr += 0x20; - CurDes += sizeof(struct SD_PDMA_DESC_S)/4; - } - if (Blk_Cnt > 1) { - atsmb1_init_long_desc(CurDes, 0x80, BufferAddr, CurDes + (sizeof(struct SD_PDMA_DESC_L)/4), 0); - BufferAddr += 0x20; - CurDes += sizeof(struct SD_PDMA_DESC_L)/4; - /* the following Descriptor store the rest Blocks data - * (Blk_Cnt - 1) * 512 bytes - */ - atsmb1_init_long_desc(CurDes, (Blk_Cnt - 1) * 512, - BufferAddr, CurDes + (sizeof(struct SD_PDMA_DESC_L)/4), 1); - } else { - atsmb1_init_long_desc(CurDes, 0x80, BufferAddr, CurDes + (sizeof(struct SD_PDMA_DESC_L)/4), 1); - } - DBG("[%s] e\n",__func__); -} -/********************************************************************** -Name : atsmb1_config_dma -Function : To set des/src address, byte count to transfer, and DMA channel settings, - and DMA ctrl. register. -Calls : -Called by : -Parameter : -Author : Leo Lee -History : -***********************************************************************/ -static inline void atsmb1_config_dma(unsigned long config_dir, - unsigned long dma_mask, - struct atsmb_host *host) -{ - DBG("[%s] s\n",__func__); - - /* Enable DMA */ - *ATSMB1_PDMA_GCR = SD_PDMA_GCR_DMA_EN; - *ATSMB1_PDMA_GCR = SD_PDMA_GCR_SOFTRESET; - *ATSMB1_PDMA_GCR = SD_PDMA_GCR_DMA_EN; - /*open interrupt*/ - *ATSMB1_PDMA_IER = SD_PDMA_IER_INT_EN; - /*Make sure host could co-work with DMA*/ - *ATSMB1_SD_STS_2 |= ATSMB_CLK_FREEZ_EN; - /*Set timer timeout value*/ - - /*If clock is 390KHz*/ - if (host->current_clock < 400000) - *ATSMB1_TIMER_VAL = 0x200; /*1024*512*(1/390K) second*/ - else - *ATSMB1_TIMER_VAL = 0x1fff; /*why not to be 0xffff?*/ - - /*clear all DMA INT status for safety*/ - *ATSMB1_PDMA_ISR |= SD_PDMA_IER_INT_STS; - - /* hook desc */ - *ATSMB1_PDMA_DESPR = host->DescPhyAddr; - if (config_dir == DMA_CFG_WRITE) - *ATSMB1_PDMA_CCR &= SD_PDMA_CCR_IF_to_peripheral; - else - *ATSMB1_PDMA_CCR |= SD_PDMA_CCR_peripheral_to_IF; - - host->DmaIntMask = dma_mask; /*save success event*/ - - *ATSMB1_PDMA_CCR |= SD_PDMA_CCR_RUN; - DBG("[%s] e\n",__func__); -} - -/********************************************************************** -Name : atsmb1_prep_cmd -Function : -Calls : -Called by : -Parameter : -Author : Leo Lee -History : -***********************************************************************/ -static inline void atsmb1_prep_cmd(struct atsmb_host *host, - u32 opcode, - u32 arg, - unsigned int flags, - u16 blk_len, - u16 blk_cnt, - unsigned char int_maks_0, - unsigned char int_mask_1, - unsigned char cmd_type, - unsigned char op) -{ - DBG("[%s] s\n",__func__); - - /*set cmd operation code and arguments.*/ - host->opcode = opcode; - *ATSMB1_CMD_IDX = opcode; /* host->opcode is set for further use in ISR.*/ - *ATSMB1_CMD_ARG = arg; - -#if 0 /* Fixme to support SPI mode, James Tian*/ - if ((flags && MMC_RSP_NONE) == MMC_RSP_NONE) - *ATSMB1_RSP_TYPE = ATMSB_TYPE_R0; - else if ((flags && MMC_RSP_R1) == MMC_RSP_R1) - *ATSMB1_RSP_TYPE = ATMSB_TYPE_R1; - else if ((flags && MMC_RSP_R1B) == MMC_RSP_R1B) - *ATSMB1_RSP_TYPE = ATMSB_TYPE_R1b; - else if ((flags && MMC_RSP_R2) == MMC_RSP_R2) - *ATSMB1_RSP_TYPE = ATMSB_TYPE_R2; - else if ((flags && MMC_RSP_R3) == MMC_RSP_R3) - *ATSMB1_RSP_TYPE = ATMSB_TYPE_R3; - else if ((flags && MMC_RSP_R6) == MMC_RSP_R6) - *ATSMB1_RSP_TYPE = ((opcode != SD_SEND_IF_COND) ? ATMSB_TYPE_R6 : ATMSB_TYPE_R7); - else - *ATSMB1_RSP_TYPE = ATMSB_TYPE_R0; -#endif - -#if 1 - /*set cmd response type*/ - switch (flags) { - case MMC_RSP_NONE | MMC_CMD_AC: - case MMC_RSP_NONE | MMC_CMD_BC: - *ATSMB1_RSP_TYPE = ATMSB_TYPE_R0; - break; - case MMC_RSP_R1 | MMC_CMD_ADTC: - case MMC_RSP_R1 | MMC_CMD_AC: - *ATSMB1_RSP_TYPE = ATMSB_TYPE_R1; - break; - case MMC_RSP_R1B | MMC_CMD_AC: - *ATSMB1_RSP_TYPE = ATMSB_TYPE_R1b; - break; - case MMC_RSP_R2 | MMC_CMD_BCR: - case MMC_RSP_R2 | MMC_CMD_AC: - *ATSMB1_RSP_TYPE = ATMSB_TYPE_R2; - break; - case MMC_RSP_R3 | MMC_CMD_BCR: - *ATSMB1_RSP_TYPE = ATMSB_TYPE_R3; - break; - case MMC_RSP_R6 | MMC_CMD_BCR: /*MMC_RSP_R6 = MMC_RSP_R7.*/ - *ATSMB1_RSP_TYPE = ((opcode != SD_SEND_IF_COND) ? - ATMSB_TYPE_R6 : ATMSB_TYPE_R7); - break; - case MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_AC: - case MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_ADTC: - *ATSMB1_RSP_TYPE = ATMSB_TYPE_R5; - break; - case MMC_RSP_SPI_R4 | MMC_RSP_R4 | MMC_CMD_BCR: - *ATSMB1_RSP_TYPE = ATMSB_TYPE_R4; - break; - default: - *ATSMB1_RSP_TYPE = ATMSB_TYPE_R0; - break; - } -#endif - /*SDIO cmd 52 , 53*/ - if ((opcode == SD_IO_RW_DIRECT) || - (opcode == SD_IO_RW_EXTENDED)) { - *ATSMB1_RSP_TYPE = ATMSB_TYPE_R5; - *ATSMB1_RSP_TYPE |= BIT6; - } - /*SDIO cmd 5*/ - if ((opcode == SD_IO_SEND_OP_COND) && - ((flags & (MMC_RSP_PRESENT| - MMC_RSP_136| - MMC_RSP_CRC| - MMC_RSP_BUSY| - MMC_RSP_OPCODE)) == MMC_RSP_R4)) { - *ATSMB1_RSP_TYPE = ATMSB_TYPE_R4; - *ATSMB1_RSP_TYPE |= BIT6; - } - - /*reset Response FIFO*/ - *ATSMB1_CTL |= 0x08; - - /* SD Host enable Clock */ - *ATSMB1_BUS_MODE |= ATSMB_CST; - - /*Set Cmd-Rsp Timeout to be maximum value.*/ - *ATSMB1_RSP_TOUT = 0xFE; - - /*clear all status registers for safety*/ - *ATSMB1_SD_STS_0 |= 0xff; - *ATSMB1_SD_STS_1 |= 0xff; - *ATSMB1_SD_STS_2 |= 0xff; - //*ATSMB1_SD_STS_2 |= 0x7f; - *ATSMB1_SD_STS_3 |= 0xff; - - //set block length and block count for cmd requesting data - *ATSMB1_BLK_LEN &=~(0x07ff); - *ATSMB1_BLK_LEN |= blk_len; - //*ATSMB1_SHDW_BLKLEN = blk_len; - *ATSMB1_BLK_CNT = blk_cnt; - - - *ATSMB1_INT_MASK_0 |= int_maks_0; - *ATSMB1_INT_MASK_1 |= int_mask_1; - - //Set Auto stop for Multi-block access - if(cmd_type == 3 || cmd_type == 4) - { - //auto stop command set. - *ATSMB1_EXT_CTL |= 0x01; - -/* - * Enable transaction abort. - * When CRC error occurs, CMD 12 would be automatically issued. - * That is why we cannot enable R/W CRC error INTs. - * If we enable CRC error INT, we would handle this INT in ISR and then issue CMD 12 via software. - */ - *ATSMB1_BLK_LEN |= 0x0800; - } - - /*Set read or write*/ - if (op == 1) - *ATSMB1_CTL &= ~(0x04); - else if (op == 2) - *ATSMB1_CTL |= 0x04; - - /*for Non data access command, command type is 0.*/ - *ATSMB1_CTL &= 0x0F; - *ATSMB1_CTL |= (cmd_type<<4); - DBG("[%s] e\n",__func__); -} - -static inline void atsmb1_issue_cmd(void) -{ - *ATSMB1_CTL |= ATSMB_START; - wmb(); -} -/********************************************************************** -Name : atsmb1_request_end -Function :. -Calls : -Called by : -Parameter : -Author : Leo Lee -History : -***********************************************************************/ -static void -atsmb1_request_end(struct atsmb_host *host, struct mmc_request *mrq) -{ - DBG("[%s] s\n",__func__); - /* - * Need to drop the host lock here; mmc_request_done may call - * back into the driver... - */ - spin_unlock(&host->lock); - /*DBG("100");*/ - mmc_request_done(host->mmc, mrq); - /*DBG("101\n");*/ - spin_lock(&host->lock); - DBG("[%s] e\n",__func__); -} - -/********************************************************************** -Name : atsmb1_data_done -Function : -Calls : -Called by : -Parameter : -Author : Leo Lee -History : -***********************************************************************/ -void atsmb1_wait_done(void *data) -{ - struct atsmb_host *host = (struct atsmb_host *) data; - DBG("[%s] s\n",__func__); - - WARN_ON(host->done_data == NULL); - complete(host->done_data); - host->done_data = NULL; - host->done = NULL; - DBG("[%s] e\n",__func__); -} - -/********************************************************************** -Name : atsmb1_start_data -Function : If we start data, there must be only four cases. -Calls : -Called by : -Parameter : -Author : Leo Lee -History : -***********************************************************************/ -static void atsmb1_start_data(struct atsmb_host *host) -{ - DECLARE_COMPLETION(complete); - unsigned char cmd_type = 0; - unsigned char op = 0; /*0: non-operation; 1:read; 2: write*/ - unsigned char mask_0 = 0; - unsigned char mask_1 = 0; - unsigned long dma_mask = 0; - - struct mmc_data *data = host->data; - struct mmc_command *cmd = host->cmd; - - struct scatterlist *sg = NULL; - unsigned int sg_len = 0; - - unsigned int total_blks = 0; /*total block number to transfer*/ - u32 card_addr = 0; - unsigned long dma_len = 0; - unsigned long total_dma_len = 0; - dma_addr_t dma_phy = 0; /* physical address used for DMA*/ - unsigned int dma_times = 0; /*times dma need to transfer*/ - unsigned int dma_loop = 0; - unsigned int sg_num = 0; - int loop_cnt = 10000; - unsigned int sg_transfer_len = 0; /*record each time dma transfer sg length */ - - DBG("[%s] s\n",__func__); - data->bytes_xfered = 0; - cmd->error = 0; - data->error = 0; - - /*for loop*/ - sg = data->sg; - sg_len = data->sg_len; - - dma_times = (sg_len / MAX_DESC_NUM); - if (sg_len % MAX_DESC_NUM) - dma_times++; - DBG("dma_times = %d sg_len = %d sg = %x\n", dma_times, sg_len, sg); - card_addr = cmd->arg; /*may be it is block-addressed, or byte-addressed.*/ - total_blks = data->blocks; - dma_map_sg(&(host->mmc->class_dev), sg, sg_len, - ((data->flags)&MMC_DATA_READ) ? DMA_FROM_DEVICE : DMA_TO_DEVICE); - - - for (dma_loop = 1 ; dma_loop <= dma_times; dma_loop++, sg_len -= sg_transfer_len) { - DBG("dma_loop = %d sg_len = %d sg_transfer_len = %d\n", dma_loop, sg_len, sg_transfer_len); - if (dma_loop < dma_times) - sg_transfer_len = MAX_DESC_NUM; - else - sg_transfer_len = sg_len; - DBG("sg_transfer_len = %d\n", sg_transfer_len); - /* - *Firstly, check and wait till card is in the transfer state. - *For our hardware, we can not consider - *the card has successfully tranfered its state from data/rcv to trans, - *when auto stop INT occurs. - */ - loop_cnt = 10000; - do { - if (host->cmd->opcode == SD_IO_RW_EXTENDED) - break; - loop_cnt--; - WARN_ON(loop_cnt == 0); - host->done_data = &complete; - host->done = &atsmb1_wait_done; - host->soft_timeout = 1; - atsmb1_prep_cmd(host, - MMC_SEND_STATUS, - (host->mmc->card->rca)<<16, - MMC_RSP_R1 | MMC_CMD_AC, - 0, - 0, - 0, /*mask_0*/ - ATSMB_RSP_DONE_EN - |ATSMB_RSP_CRC_ERR_EN - |ATSMB_RSP_TIMEOUT_EN, - 0, /*cmd type*/ - 0); /*read or write*/ - atsmb1_issue_cmd(); - DBG("%16s = 0x%8x |", "INT_MASK_1", *ATSMB1_INT_MASK_1); - DBG("%16s = 0x%8x \n", "SD_STS_1", *ATSMB1_SD_STS_1); - /*ISR would completes it.*/ - wait_for_completion_timeout(&complete, ATSMB_TIMEOUT_TIME); - - WARN_ON(host->soft_timeout == 1); - if (host->soft_timeout == 1) { - DBG("%s soft_timeout.\n", __func__); - atsmb1_dump_reg(host); - } - if (cmd->error != MMC_ERR_NONE) { - cmd->error = -EIO; //MMC_ERR_FAILED; - DBG("Getting Status failed.\n"); - goto end; - } - } while ((cmd->resp[0] & 0x1f00) != 0x900 && loop_cnt > 0); /*wait for trans state.*/ - - /* - * Now, we can safely issue read/write command. - * We can not consider this request as multi-block acess or single one via opcode, - * as request is splitted into sgs. - * Some sgs may be single one, some sgs may be multi one. - */ - - dma_phy = sg_dma_address(sg); - dma_len = sg_dma_len(sg); - DBG("dma_len = %d data->blksz = %d sg_len = %d\n", dma_len, data->blksz, sg_len); - /*SDIO read/write*/ - if (host->cmd->opcode == SD_IO_RW_EXTENDED) { - /*Single Block read/write*/ - if ((dma_len / (data->blksz)) == 1 && (sg_len == 1)) { - /* read operation*/ - if (data->flags & MMC_DATA_READ) { - host->opcode = SD_IO_RW_EXTENDED; - cmd_type = 2; - op = 1; - mask_0 = 0; /*BLOCK_XFER_DONE INT skipped, we use DMA TC INT*/ - mask_1 = (//ATSMB_SDIO_EN - ATSMB_READ_CRC_ERR_EN - |ATSMB_DATA_TIMEOUT_EN - /*Data Timeout and CRC error */ - |ATSMB_RSP_CRC_ERR_EN - |ATSMB_RSP_TIMEOUT_EN); - /*Resp Timeout and CRC error */ - dma_mask = SD_PDMA_CCR_Evt_success; - DBG("[%s]SR opcode = %d type = 0x%x op = 0x%x m_0 = 0x%x m_1 = 0x%x d_m = 0x%x\n", - __func__,host->opcode,cmd_type,op,mask_0,mask_1,dma_mask); - } else { - /* write operation*/ - host->opcode = SD_IO_RW_EXTENDED; - cmd_type = 1; - op = 2; - /*====That is what we want===== DMA TC INT skipped*/ - mask_0 = ATSMB_BLOCK_XFER_DONE_EN; - mask_1 = (//ATSMB_SDIO_EN - ATSMB_WRITE_CRC_ERR_EN - |ATSMB_DATA_TIMEOUT_EN - /*Data Timeout and CRC error */ - |ATSMB_RSP_CRC_ERR_EN - |ATSMB_RSP_TIMEOUT_EN); - /*Resp Timeout and CRC error */ - dma_mask = 0; - DBG("[%s]SW opcode = %d type = 0x%x op = 0x%x m_0 = 0x%x m_1 = 0x%x d_m = 0x%x\n", - __func__,host->opcode,cmd_type,op,mask_0,mask_1,dma_mask); - } - } else { - /*Multiple Block read/write*/ - /* read operation*/ - if (data->flags & MMC_DATA_READ) { - host->opcode = SD_IO_RW_EXTENDED; - cmd_type = 6; - op = 1; - mask_0 = 0; /*MULTI_XFER_DONE_EN skipped*/ - mask_1 = (//ATSMB_SDIO_EN /*====That is what we want=====*/ - ATSMB_READ_CRC_ERR_EN - |ATSMB_DATA_TIMEOUT_EN - /*Data Timeout and CRC error */ - |ATSMB_RSP_CRC_ERR_EN - |ATSMB_RSP_TIMEOUT_EN); - /*Resp Timeout and CRC error */ - dma_mask = SD_PDMA_CCR_Evt_success; - DBG("[%s]MR opcode = %d type = 0x%x op = 0x%x m_0 = 0x%x m_1 = 0x%x d_m = 0x%x\n", - __func__,host->opcode,cmd_type,op,mask_0,mask_1,dma_mask); - } else { - /* write operation*/ - host->opcode = SD_IO_RW_EXTENDED; - cmd_type = 5; - op = 2; - mask_0 = ATSMB_MULTI_XFER_DONE_EN;//ATSMB_BLOCK_XFER_DONE_EN; /*MULTI_XFER_DONE INT skipped*/ - mask_1 = (//ATSMB_SDIO_EN /*====That is what we want=====*/ - ATSMB_WRITE_CRC_ERR_EN - |ATSMB_DATA_TIMEOUT_EN - /*Data Timeout and CRC error */ - |ATSMB_RSP_CRC_ERR_EN - |ATSMB_RSP_TIMEOUT_EN); - /*Resp Timeout and CRC error */ - dma_mask = 0; - DBG("[%s]MR opcode = %d type = 0x%x op = 0x%x m_0 = 0x%x m_1 = 0x%x d_m = 0x%x\n", - __func__,host->opcode,cmd_type,op,mask_0,mask_1,dma_mask); - } - } - - } else { - if ((dma_len / (data->blksz)) == 1 && (sg_len == 1)) { - if (data->flags & MMC_DATA_READ) {/* read operation*/ - host->opcode = MMC_READ_SINGLE_BLOCK; - cmd_type = 2; - op = 1; - mask_0 = 0; /*BLOCK_XFER_DONE INT skipped, we use DMA TC INT*/ - mask_1 = (ATSMB_READ_CRC_ERR_EN - |ATSMB_DATA_TIMEOUT_EN - /*Data Timeout and CRC error */ - |ATSMB_RSP_CRC_ERR_EN - |ATSMB_RSP_TIMEOUT_EN); - /*Resp Timeout and CRC error */ - dma_mask = SD_PDMA_CCR_Evt_success; - } else {/*write operation*/ - host->opcode = MMC_WRITE_BLOCK; - cmd_type = 1; - op = 2; - /*====That is what we want===== DMA TC INT skipped*/ - mask_0 = ATSMB_BLOCK_XFER_DONE_EN; - mask_1 = (ATSMB_WRITE_CRC_ERR_EN - |ATSMB_DATA_TIMEOUT_EN - /*Data Timeout and CRC error */ - |ATSMB_RSP_CRC_ERR_EN - |ATSMB_RSP_TIMEOUT_EN); - /*Resp Timeout and CRC error */ - dma_mask = 0; - } - } else { /*more than one*/ - if (data->flags&MMC_DATA_READ) {/* read operation*/ - host->opcode = MMC_READ_MULTIPLE_BLOCK; - cmd_type = 4; - op = 1; - mask_0 = 0; /*MULTI_XFER_DONE_EN skipped*/ - mask_1 = (ATSMB_AUTO_STOP_EN /*====That is what we want=====*/ - |ATSMB_DATA_TIMEOUT_EN - /*Data Timeout and CRC error */ - |ATSMB_RSP_CRC_ERR_EN - |ATSMB_RSP_TIMEOUT_EN); - /*Resp Timeout and CRC error */ - dma_mask = 0; - } else {/*write operation*/ - host->opcode = MMC_WRITE_MULTIPLE_BLOCK; - cmd_type = 3; - op = 2; - mask_0 = 0; /*MULTI_XFER_DONE INT skipped*/ - mask_1 = (ATSMB_AUTO_STOP_EN /*====That is what we want=====*/ - |ATSMB_DATA_TIMEOUT_EN - /*Data Timeout and CRC error */ - |ATSMB_RSP_CRC_ERR_EN - |ATSMB_RSP_TIMEOUT_EN); - /*Resp Timeout and CRC error */ - dma_mask = 0; - } - } - } - /*To controller every sg done*/ - host->done_data = &complete; - host->done = &atsmb1_wait_done; - /*sleep till ISR wakes us*/ - host->soft_timeout = 1; /*If INT comes early than software timer, it would be cleared.*/ - - total_dma_len = 0; - DBG("host->DescVirAddr = %x host->DescSize=%x\n", host->DescVirAddr, host->DescSize); - memset(host->DescVirAddr, 0, host->DescSize); - for (sg_num = 0 ; sg_num < sg_transfer_len ; sg++, sg_num++) { - - /* - * Now, we can safely issue read/write command. - * We can not consider this request as multi-block acess or single one via opcode, - * as request is splitted into sgs. - * Some sgs may be single one, some sgs may be multi one. - */ - - dma_phy = sg_dma_address(sg); - dma_len = sg_dma_len(sg); - total_dma_len = total_dma_len + dma_len; - DBG("sg_num=%d sg_transfer_len=%d sg=%x sg_len=%d total_dma_len=%d dma_len=%d\n", - sg_num, sg_transfer_len, sg, sg_len, total_dma_len, dma_len); - /*2009/01/15 janshiue add*/ - if (sg_num < sg_transfer_len - 1) { - /* means the last descporitor */ - atsmb1_init_short_desc( - host->DescVirAddr + (sg_num * sizeof(struct SD_PDMA_DESC_S)/4), - dma_len, (unsigned long *)dma_phy, 0); - } else { - atsmb1_init_short_desc( - host->DescVirAddr + (sg_num * sizeof(struct SD_PDMA_DESC_S)/4), - dma_len, (unsigned long *)dma_phy, 1); - } - /*2009/01/15 janshiue add*/ - - } - /*operate our hardware*/ - atsmb1_prep_cmd(host, - host->opcode, - /*arg, may be byte addressed, may be block addressed.*/ - card_addr, - cmd->flags, - data->blksz - 1, /* in fact, it is useless.*/ - /* for single one, it is useless. but for multi one, */ - /* it would be used to tell auto stop function whether it is done.*/ - total_dma_len/(data->blksz), - mask_0, - mask_1, - cmd_type, - op); - - atsmb1_config_dma((op == 1) ? DMA_CFG_READ : DMA_CFG_WRITE, - dma_mask, - host); - - atsmb1_issue_cmd(); - wait_for_completion_timeout(&complete, - ATSMB_TIMEOUT_TIME*sg_transfer_len); /*ISR would completes it.*/ - - /* When the address of request plus length equal card bound, - * force this stop command response as pass. Eason 2012/4/20 */ - if (cmd->resp[0] == 0x80000b00) { - /*This caes used for SD2.0 and after MMC4.1 version*/ - if (card_addr+(total_dma_len/data->blksz) == host->mmc->card->csd.capacity) { - cmd->resp[0] = 0x00000b00; - /*printk("card_addr = %08X, card_length = %08X,card capacity = %08X\n", - card_addr,(total_dma_len/data->blksz),host->mmc->card->csd.capacity); - printk("card_resp[0]=%08X, addr = %08X\n",cmd->resp[0],cmd->resp);*/ - } - - /* This caes used for SD1.0 and before MMC 4.1 */ - if ((card_addr/data->blksz)+(total_dma_len/data->blksz) == host->mmc->card->csd.capacity) { - cmd->resp[0] = 0x00000b00; - /*printk("Eason test: cmd->arg = %08X, data->blksz = %08X, length = %08X\n", - card_addr,data->blksz,(total_dma_len/data->blksz));*/ - } - } - - if (host->soft_timeout == 1) { - atsmb1_dump_reg(host); - //*ATSMB1_BUS_MODE |= ATSMB_SFTRST; - *ATSMB1_PDMA_GCR = SD_PDMA_GCR_SOFTRESET; - /*disable INT */ - *ATSMB1_INT_MASK_0 &= ~(ATSMB_BLOCK_XFER_DONE_EN | ATSMB_MULTI_XFER_DONE_EN); - *ATSMB1_INT_MASK_1 &= ~(ATSMB_WRITE_CRC_ERR_EN|ATSMB_READ_CRC_ERR_EN|ATSMB_RSP_CRC_ERR_EN - |ATSMB_DATA_TIMEOUT_EN|ATSMB_AUTO_STOP_EN|ATSMB_RSP_TIMEOUT_EN|ATSMB_RSP_DONE_EN); - - cmd->error = -ETIMEDOUT; - data->error = -ETIMEDOUT; - } - - WARN_ON(host->soft_timeout == 1); - - /*check everything goes okay or not*/ - if (cmd->error != MMC_ERR_NONE - || data->error != MMC_ERR_NONE) { - DBG("CMD or Data failed error=%X DescVirAddr=%8X dma_phy=%8X dma_mask = %x\n", - cmd->error, host->DescVirAddr, dma_phy, host->DmaIntMask); - goto end; - } -// card_addr += total_dma_len>>(mmc_card_blockaddr(host->mmc->card_selected) ? 9 : 0); - card_addr += total_dma_len>>(mmc_card_blockaddr(host->mmc->card) ? 9 : 0); //zhf: modified by James Tian - data->bytes_xfered += total_dma_len; - - - } -// dma_unmap_sg(&(host->mmc->class_dev), data->sg, data->sg_len, -// ((data->flags)&MMC_DATA_READ) ? DMA_FROM_DEVICE : DMA_TO_DEVICE); - WARN_ON(total_blks != (data->bytes_xfered / data->blksz)); - host->opcode = 0; -end: - dma_unmap_sg(&(host->mmc->class_dev), data->sg, data->sg_len, - ((data->flags)&MMC_DATA_READ) ? DMA_FROM_DEVICE : DMA_TO_DEVICE); - spin_lock(&host->lock); - atsmb1_request_end(host, host->mrq); - spin_unlock(&host->lock); - DBG("[%s] e\n",__func__); -} - - -/********************************************************************** -Name : atsmb1_cmd_with_data_back -Function : -Calls : -Called by : -Parameter : -Author : Leo Lee -History : -***********************************************************************/ -static void atsmb1_cmd_with_data_back(struct atsmb_host *host) -{ - DECLARE_COMPLETION(complete); - - struct scatterlist *sg = NULL; - unsigned int sg_len = 0; - DBG("[%s] s\n",__func__); - /*for loop*/ - sg = host->data->sg; - sg_len = host->data->sg_len; - /*To controller every sg done*/ - host->done_data = &complete; - host->done = &atsmb1_wait_done; - dma_map_sg(&(host->mmc->class_dev), sg, sg_len, DMA_FROM_DEVICE); - - /*2009/01/15 janshiue add*/ - memset(host->DescVirAddr, 0, host->DescSize); - atsmb1_init_long_desc(host->DescVirAddr, sg_dma_len(sg), (unsigned long *)sg_dma_address(sg), 0, 1); - /*2009/01/15 janshiue add*/ - /*prepare for cmd*/ - atsmb1_prep_cmd(host, /*host*/ - host->cmd->opcode, /*opcode*/ - host->cmd->arg, /*arg*/ - host->cmd->flags, /*flags*/ - sg_dma_len(sg)-1, /*block length*/ - 0, /*block size: It looks like useless*/ - 0, /*int_mask_0*/ - (ATSMB_RSP_CRC_ERR_EN|ATSMB_RSP_TIMEOUT_EN - |ATSMB_READ_CRC_ERR_EN |ATSMB_DATA_TIMEOUT_EN), /*int_mask_1*/ - 2, /*cmd_type*/ - 1); /*op*/ - - atsmb1_config_dma(DMA_CFG_READ, - SD_PDMA_CCR_Evt_success, - host); - atsmb1_issue_cmd(); - /*ISR would completes it.*/ - wait_for_completion_timeout(&complete, ATSMB_TIMEOUT_TIME); - - dma_unmap_sg(&(host->mmc->class_dev), host->data->sg, host->data->sg_len, - ((host->data->flags)&MMC_DATA_READ) ? DMA_FROM_DEVICE : DMA_TO_DEVICE); - - spin_lock(&host->lock); - atsmb1_request_end(host, host->mrq); - spin_unlock(&host->lock); - DBG("[%s] e\n",__func__); -} -/********************************************************************** -Name : atsmb1_start_cmd -Function : -Calls : -Called by : -Parameter : -Author : Leo Lee -History : -***********************************************************************/ -static void atsmb1_start_cmd(struct atsmb_host *host) -{ - unsigned char int_mask_0,int_mask_1; - int_mask_0 = 0; - int_mask_1 = ATSMB_RSP_DONE_EN|ATSMB_RSP_CRC_ERR_EN|ATSMB_RSP_TIMEOUT_EN; - - DBG("[%s] s\n",__func__); - - atsmb1_prep_cmd(host, - host->cmd->opcode, - host->cmd->arg, - host->cmd->flags, - 0, /*useless*/ - 0, /*useless*/ - int_mask_0, /*mask_0*/ - int_mask_1, /*mask_1*/ - 0, /*cmd type*/ - 0); /*read or write*/ - atsmb1_issue_cmd(); - DBG("[%s] e\n",__func__); -} -/********************************************************************** -Name : atsmb1_fmt_check_rsp -Function : -Calls : -Called by : -Parameter : -Author : Leo Lee -History : -***********************************************************************/ -static inline void atsmb1_fmt_check_rsp(struct atsmb_host *host) -{ - - u8 tmp_resp[4] = {0}; - int i, j, k; - DBG("[%s] s\n",__func__); - if (host->cmd->flags != (MMC_RSP_R2 | MMC_CMD_AC) - && host->cmd->flags != (MMC_RSP_R2 | MMC_CMD_BCR)) { - for (j = 0, k = 1; j < 4; j++, k++) - tmp_resp[j] = *(REG8_PTR(_RSP_0 + MMC_ATSMB1_BASE+k)); - - host->cmd->resp[0] = (tmp_resp[0] << 24) | - (tmp_resp[1]<<16) | (tmp_resp[2]<<8) | (tmp_resp[3]); - } else { - for (i = 0, k = 1; i < 4; i++) { /*R2 has 4 u32 response.*/ - for (j = 0; j < 4; j++) { - if (k < 16) - tmp_resp[j] = *(REG8_PTR(_RSP_0 + MMC_ATSMB1_BASE+k)); - else /* k =16*/ - tmp_resp[j] = *(ATSMB1_RSP_0); - k++; - } - host->cmd->resp[i] = (tmp_resp[0]<<24) | (tmp_resp[1]<<16) | - (tmp_resp[2]<<8) | (tmp_resp[3]); - } - } - - /* - * For the situation that we need response, - * but response registers give us all zeros, we consider this operation timeout. - */ - if (host->cmd->flags != (MMC_RSP_NONE | MMC_CMD_AC) - && host->cmd->flags != (MMC_RSP_NONE | MMC_CMD_BC)) { - if (host->cmd->resp[0] == 0 && host->cmd->resp[1] == 0 - && host->cmd->resp[2] == 0 && host->cmd->resp[3] == 0) { - host->cmd->error = -ETIMEDOUT; //zhf: modified by James Tian - } - } - DBG("[%s] e\n",__func__); -} -/********************************************************************** -Name : atsmb1_get_slot_status -Function : Our host only supports one slot. -Calls : -Called by : -Parameter : -returns : 1: in slot; 0: not in slot. -Author : Leo Lee -History : -***********************************************************************/ -static int atsmb1_get_slot_status(struct mmc_host *mmc) -{ -// struct atsmb_host *host = mmc_priv(mmc); - unsigned char status_0 = 0; -// unsigned long flags; - unsigned long ret = 0; - DBG("[%s] s\n",__func__); -// spin_lock_irqsave(&host->lock, flags); // Vincent Li mark out for CONFIG_PREEMPT_RT - status_0 = *ATSMB1_SD_STS_0; -// spin_unlock_irqrestore(&host->lock, flags); // Vincent Li mark out for CONFIG_PREEMPT_RT - /* after WM3400 A1 ATSMB_CARD_IN_SLOT_GPI = 1 means not in slot*/ - if (MMC1_DRIVER_VERSION >= MMC_DRV_3426_A0) { - ret = ((status_0 & ATSMB_CARD_NOT_IN_SLOT_GPI) ? 0 : 1); - DBG("[%s] e1\n",__func__); - return ret; - } else { - ret = ((status_0 & ATSMB_CARD_NOT_IN_SLOT_GPI) ? 1 : 0); - DBG("[%s] e2\n",__func__); - return ret; - } - DBG("[%s] e3\n",__func__); - return 0; -} - -/********************************************************************** -Name : atsmb1_init_short_desc -Function : -Calls : -Called by : -Parameter : -Author : Janshiue Wu -History : -***********************************************************************/ -int atsmb1_init_short_desc(unsigned long *DescAddr, unsigned int ReqCount, unsigned long *BufferAddr, int End) -{ - struct SD_PDMA_DESC_S *CurDes_S; - DBG("[%s] s\n",__func__); - CurDes_S = (struct SD_PDMA_DESC_S *) DescAddr; - CurDes_S->ReqCount = ReqCount; - CurDes_S->i = 0; - CurDes_S->format = 0; - CurDes_S->DataBufferAddr = BufferAddr; - if (End) { - CurDes_S->end = 1; - CurDes_S->i = 1; - } - DBG("[%s] e\n",__func__); - return 0; -} - -/********************************************************************** -Name : atsmb_init_long_desc -Function : -Calls : -Called by : -Parameter : -Author : Janshiue Wu -History : -***********************************************************************/ -int atsmb1_init_long_desc(unsigned long *DescAddr, unsigned int ReqCount, - unsigned long *BufferAddr, unsigned long *BranchAddr, int End) -{ - struct SD_PDMA_DESC_L *CurDes_L; - DBG("[%s] s\n",__func__); - CurDes_L = (struct SD_PDMA_DESC_L *) DescAddr; - CurDes_L->ReqCount = ReqCount; - CurDes_L->i = 0; - CurDes_L->format = 1; - CurDes_L->DataBufferAddr = BufferAddr; - CurDes_L->BranchAddr = BranchAddr; - if (End) { - CurDes_L->end = 1; - CurDes_L->i = 1; - } - DBG("[%s] e\n",__func__); - return 0; -} - -/********************************************************************** -Name : atsmb1_dma_isr -Function :. -Calls : -Called by : -Parameter : -Author : Leo Lee -History : -***********************************************************************/ -static irqreturn_t atsmb1_dma_isr(int irq, void *dev_id) -{ - - struct atsmb_host *host = dev_id; - u8 status_0, status_1, status_2, status_3; - u32 pdma_event_code = 0; - DBG("[%s] s\n",__func__); - - disable_irq_nosync(irq); - spin_lock(&host->lock); - /*Get INT status*/ - status_0 = *ATSMB1_SD_STS_0; - status_1 = *ATSMB1_SD_STS_1; - status_2 = *ATSMB1_SD_STS_2; - status_3 = *ATSMB1_SD_STS_3; - /* after WM3426 A0 using PDMA */ - if (MMC1_DRIVER_VERSION >= MMC_DRV_3426_A0) { - - pdma_event_code = *ATSMB1_PDMA_CCR & SD_PDMA_CCR_EvtCode; - - /* clear INT status to notify HW clear EventCode*/ - *ATSMB1_PDMA_ISR |= SD_PDMA_IER_INT_STS; - - /*printk("dma_isr event code = %X\n", *ATSMB1_PDMA_CCR);*/ - /*We expect cmd with data sending back or read single block cmd run here.*/ - if (pdma_event_code == SD_PDMA_CCR_Evt_success) { - /*means need to update the data->error and cmd->error*/ - if (host->DmaIntMask == SD_PDMA_CCR_Evt_success) { - if ( host->data != NULL) { - host->data->error = MMC_ERR_NONE; - host->cmd->error = MMC_ERR_NONE; - } else { - DBG("dma_isr1 host->data is NULL\n"); - /*disable INT*/ - *ATSMB1_PDMA_IER &= ~SD_PDMA_IER_INT_EN; - goto out; - } - } - /*else do nothing*/ - DBG("dma_isr PDMA OK\n"); - /*atsmb1_dump_reg(host);*/ - } - /*But unluckily, we should also be prepare for all kinds of error situation.*/ - else { - host->data->error = -EIO; //MMC_ERR_FAILED; - host->cmd->error = -EIO; //MMC_ERR_FAILED; - DBGR("** dma_isr PDMA fail** event code = %X\n", *ATSMB1_PDMA_CCR); - atsmb1_dump_reg(host); - } - if (host->DmaIntMask == SD_PDMA_CCR_Evt_success) - atsmb1_fmt_check_rsp(host); - - /*disable INT*/ - *ATSMB1_PDMA_IER &= ~SD_PDMA_IER_INT_EN; - } - - /*wake up some one who is sleeping.*/ - if ((pdma_event_code != SD_PDMA_CCR_Evt_success) || (host->DmaIntMask == SD_PDMA_CCR_Evt_success)) { - if (host->done_data) {/* We only use done_data when requesting data.*/ - host->soft_timeout = 0; - host->done(host); - } else - atsmb1_request_end(host, host->mrq); /*for cmd with data sending back.*/ - } - -out: - spin_unlock(&host->lock); - enable_irq(irq); - DBG("[%s] e\n",__func__); - return IRQ_HANDLED; -} - -/********************************************************************** -Name : atsmb1_regular_isr -Function :. -Calls : -Called by : -Parameter : -Author : Leo Lee -History : -***********************************************************************/ -//static irqreturn_t atsmb_regular_isr(int irq, void *dev_id, struct pt_regs *regs) -irqreturn_t atsmb1_regular_isr(int irq, void *dev_id) -{ - - struct atsmb_host *host = dev_id; - u8 status_0, status_1, status_2, status_3,mask_0,mask_1; - u32 pdma_sts; - - DBG("[%s] s\n",__func__); - WARN_ON(host == NULL); - - disable_irq_nosync(irq); - spin_lock(&host->lock); - - /*Get INT status*/ - status_0 = *ATSMB1_SD_STS_0; - status_1 = *ATSMB1_SD_STS_1; - status_2 = *ATSMB1_SD_STS_2; - status_3 = *ATSMB1_SD_STS_3; - - mask_0 = *ATSMB1_INT_MASK_0; - mask_1 = *ATSMB1_INT_MASK_1; - /******************************************************* - card insert interrupt - ********************************************************/ - if ((status_0 & ATSMB_DEVICE_INSERT) /*Status Set and IRQ enabled*/ - /*To aviod the situation that we intentionally disable IRQ to do rescan.*/ - && (*ATSMB1_INT_MASK_0 & 0x80)) { - - if (host->mmc->ops->get_slot_status(host->mmc)) { - host->mmc->scan_retry = 3; - host->mmc->card_scan_status = false; - } else { - host->mmc->scan_retry = 0; - host->mmc->card_scan_status = false; - } - - mmc_detect_change(host->mmc, HZ/2); - /*Taipei Side Request: Disable INSERT IRQ when doing rescan.*/ - //*ATSMB1_INT_MASK_0 &= (~0x80);/* or 40?*/ //zhf: marked by James Tian - /*Then we clear the INT status*/ - //iowrite32(ATSMB_DEVICE_INSERT, host->base+_SD_STS_0); - *ATSMB1_SD_STS_0 |= ATSMB_DEVICE_INSERT; - spin_unlock(&host->lock); - enable_irq(irq); - DBG("[%s] e1\n",__func__); - return IRQ_HANDLED; - } - - if ((status_1 & mask_1)& ATSMB_SDIO_INT) { - spin_unlock(&host->lock); - mmc_signal_sdio_irq(host->mmc); - - if (((status_1 & mask_1) == ATSMB_SDIO_INT) && ((status_0 & mask_0) == 0)) { - - enable_irq(irq); - DBG("[%s] e2\n",__func__); - - return IRQ_HANDLED; - } - spin_lock(&host->lock); - } - pdma_sts = *ATSMB1_PDMA_CCR; - - if (((status_0 & mask_0) | (status_1 & mask_1)) == 0) { - spin_unlock(&host->lock); - enable_irq(irq); - DBG("[%s] e3\n",__func__); - return IRQ_HANDLED; - } - /******************************************************* - command interrupt. - *******************************************************/ - /*for write single block*/ - if (host->opcode == MMC_WRITE_BLOCK) { - if ((status_0 & ATSMB_BLOCK_XFER_DONE) - && (status_1 & ATSMB_RSP_DONE)) { - host->data->error = MMC_ERR_NONE; - host->cmd->error = MMC_ERR_NONE; - /* okay, what we want.*/ - } else { - host->data->error = -EIO; //MMC_ERR_FAILED; - host->cmd->error = -EIO; //MMC_ERR_FAILED; - DBG("[%s] err1\n",__func__); - atsmb1_dump_reg(host); - } - } else if (host->opcode == MMC_WRITE_MULTIPLE_BLOCK - || host->opcode == MMC_READ_MULTIPLE_BLOCK) { - if ((status_1 & (ATSMB_AUTO_STOP|ATSMB_RSP_DONE)) - && (status_0 & ATSMB_MULTI_XFER_DONE)) { - /*If CRC error occurs, I think this INT would not occrs.*/ - /*okay, that is what we want.*/ - host->data->error = MMC_ERR_NONE; - host->cmd->error = MMC_ERR_NONE; - } else { - host->data->error = -EIO; //MMC_ERR_FAILED; - host->cmd->error = -EIO; //MMC_ERR_FAILED; - DBG("[%s] err2\n",__func__); - atsmb1_dump_reg(host); - - } - } else if (host->opcode == MMC_READ_SINGLE_BLOCK) {/* we want DMA TC, run here, must be error.*/ - host->data->error = -EIO; //MMC_ERR_FAILED; - host->cmd->error = -EIO; //MMC_ERR_FAILED; - DBG("[%s] err3\n",__func__); - atsmb1_dump_reg(host); - } else if (host->opcode == SD_IO_RW_EXTENDED){ - /*Write operation*/ - if (*ATSMB1_CTL & BIT2) { - if ((*ATSMB1_CTL & 0xf0) == 0x10) { /*single block write*/ - if ((status_0 & ATSMB_BLOCK_XFER_DONE) - && (status_1 & ATSMB_RSP_DONE)) { - host->data->error = MMC_ERR_NONE; - host->cmd->error = MMC_ERR_NONE; - /* okay, what we want.*/ - } else { - host->data->error = -EIO; //MMC_ERR_FAILED; - host->cmd->error = -EIO; //MMC_ERR_FAILED; - DBG("[%s] err4 status_0 = %x status_1 = %x\n",__func__,status_0,status_1); - } - - } else if ((*ATSMB1_CTL & 0xf0) == 0x50) { - if ((status_0 & ATSMB_MULTI_XFER_DONE) - && (status_1 & ATSMB_RSP_DONE)) { - host->data->error = MMC_ERR_NONE; - host->cmd->error = MMC_ERR_NONE; - /* okay, what we want.*/ - } else { - host->data->error = -EIO; //MMC_ERR_FAILED; - host->cmd->error = -EIO; //MMC_ERR_FAILED; - DBG("[%s] err4-2 status_0 = %x status_1 = %x\n",__func__,status_0,status_1); - } - } else { - host->data->error = -EIO; //MMC_ERR_FAILED; - host->cmd->error = -EIO; //MMC_ERR_FAILED; - DBG("[%s] err4-3 status_0 = %x status_1 = %x\n",__func__,status_0,status_1); - } - } - else { - /*Read operation*/ - host->data->error = -EIO; //MMC_ERR_FAILED; - host->cmd->error = -EIO; //MMC_ERR_FAILED; - DBG("[%s] err5\n",__func__); - } - - - } else { -/* command, not request data*/ -/* the command which need data sending back,*/ -/* like switch_function, send_ext_csd, send_scr, send_num_wr_blocks.*/ -/* NOTICE: we also send status before reading or writing data, so SEND_STATUS should be excluded.*/ - if (host->data && host->opcode != MMC_SEND_STATUS) { - host->data->error = -EIO; //MMC_ERR_FAILED; - host->cmd->error = -EIO; //MMC_ERR_FAILED; - DBG("[%s] err6\n",__func__); - atsmb1_dump_reg(host); - } else { /* Just command, no need data sending back.*/ - if (status_1 & ATSMB_RSP_DONE) { - /*Firstly, check data-response is busy or not.*/ - if (host->cmd->flags == (MMC_RSP_R1B | MMC_CMD_AC)) { - int i = 10000; - - while (status_2 & ATSMB_RSP_BUSY) { - status_2 = *ATSMB1_SD_STS_2; - if (--i == 0) - break; - DBG(" IRQ:Status_2 = %d, busy!\n", status_2); - } - if (i == 0) - printk("[MMC driver] Error :SD data-response always busy!"); - } -#if 1 -/*for our host, even no card in slot, for SEND_STATUS also returns no error.*/ -/*The protocol layer depends on SEND_STATUS to check whether card is in slot or not.*/ -/*In fact, we can also avoid this situation by checking the response whether they are all zeros.*/ - if (!atsmb1_get_slot_status(host->mmc) && host->opcode == MMC_SEND_STATUS) { - host->cmd->retries = 0; /* No retry.*/ -// host->cmd->error = MMC_ERR_INVALID; - host->cmd->error = -EINVAL; - } else -#endif - host->cmd->error = MMC_ERR_NONE; - } else { - if (status_1 & ATSMB_RSP_TIMEOUT) {/* RSP_Timeout .*/ -// host->cmd->error = MMC_ERR_TIMEOUT; - host->cmd->error = -ETIMEDOUT; - DBG("[%s] err7\n",__func__); - } else {/*or RSP CRC error*/ -// host->cmd->error = MMC_ERR_BADCRC; - host->cmd->error = -EILSEQ; - DBG("[%s] err8\n",__func__); - } - atsmb1_dump_reg(host); - } - } - } - atsmb1_fmt_check_rsp(host); - - /*disable INT */ - *ATSMB1_INT_MASK_0 &= ~(ATSMB_BLOCK_XFER_DONE_EN | ATSMB_MULTI_XFER_DONE_EN); - *ATSMB1_INT_MASK_1 &= ~(ATSMB_WRITE_CRC_ERR_EN|ATSMB_READ_CRC_ERR_EN|ATSMB_RSP_CRC_ERR_EN - |ATSMB_DATA_TIMEOUT_EN|ATSMB_AUTO_STOP_EN|ATSMB_RSP_TIMEOUT_EN|ATSMB_RSP_DONE_EN); - - - /*clear INT status. In fact, we will clear again before issuing new command.*/ - *ATSMB1_SD_STS_0 |= status_0; - *ATSMB1_SD_STS_1 |= status_1; - - /* when read CRC error occur, and the status can't write one to clear. - * To clear read CRC error status , can do software reset. This is HW bug. 2013/3/21*/ - if ((*ATSMB1_SD_STS_1 & BIT6) == 0x40) { - DBG("[%s] host1 CMD%d Read CRC error occur\n",__func__,host->cmd->opcode); - /* Save SD card register */ - atsmb1_copy_reg(0); - /* Software reset */ - *ATSMB1_BUS_MODE |= BIT7; - /* restore SD card register */ - atsmb1_copy_reg(1); - } - - if (*ATSMB1_PDMA_ISR & SD_PDMA_IER_INT_STS) - *ATSMB1_PDMA_ISR |= SD_PDMA_IER_INT_STS; - - /*wake up some one who is sleeping.*/ - if (host->done_data) { /* We only use done_data when requesting data.*/ - host->soft_timeout = 0; - host->done(host); - } else - atsmb1_request_end(host, host->mrq); /*for cmd without data.*/ - - spin_unlock(&host->lock); - enable_irq(irq); - DBG("[%s] e4\n",__func__); - return IRQ_HANDLED; -} -EXPORT_SYMBOL(atsmb1_regular_isr); - -/********************************************************************** -Name : atsmb1_get_ro -Function :. -Calls : -Called by : -Parameter : -returns : 0 : write protection is disabled. 1: write protection is enabled. -Author : Leo Lee -History : -***********************************************************************/ -int atsmb1_get_ro(struct mmc_host *mmc) -{ - struct atsmb_host *host = mmc_priv(mmc); - unsigned char status_0 = 0; - unsigned long flags; - unsigned long ret = 0; - DBG("[%s] s\n",__func__); - spin_lock_irqsave(&host->lock, flags); - status_0 = *ATSMB1_SD_STS_0; - spin_unlock_irqrestore(&host->lock, flags); - DBG("[%s]\nstatus_0 = 0x%x\n", __func__,status_0); - ret = ((status_0 & ATSMB_WRITE_PROTECT) ? 0 : 1); - DBG("[%s] e\n",__func__); - return ret; -} -/********************************************************************** -Name : atsmb1_dump_host_regs -Function : -Calls : -Called by : -Parameter : -returns : -Author : Leo Lee -History : -***********************************************************************/ -void atsmb1_dump_host_regs(struct mmc_host *mmc) -{ - struct atsmb_host *host = mmc_priv(mmc); - DBG("[%s] s\n",__func__); - atsmb1_dump_reg(host); - DBG("[%s] e\n",__func__); -} -EXPORT_SYMBOL(atsmb1_dump_host_regs); - -/********************************************************************** -Name : atsmb_enable_sdio_irq -Function : -Calls : -Called by : -Parameter : -returns : -Author : Tommy Huang -History : -***********************************************************************/ -static void atsmb1_enable_sdio_irq(struct mmc_host *mmc, int enable) -{ - struct atsmb_host *host = mmc_priv(mmc); - unsigned long flags; - - DBG("[%s] s enable = %d *ATSMB1_INT_MASK_1 = %x\n",__func__,enable,*ATSMB1_INT_MASK_1); - spin_lock_irqsave(&host->lock, flags); - - if (enable) { - *ATSMB1_INT_MASK_1 |= ATSMB_SDIO_EN; - } else { - *ATSMB1_INT_MASK_1 &= ~ATSMB_SDIO_EN; - } - - spin_unlock_irqrestore(&host->lock, flags); - DBG("[%s] e\n",__func__); - -} -/********************************************************************** -Name : atsmb_request -Function :. -Calls : -Called by : -Parameter : -Author : Leo Lee -History : -***********************************************************************/ -static void atsmb1_request(struct mmc_host *mmc, struct mmc_request *mrq) -{ - - struct atsmb_host *host = mmc_priv(mmc); - DBG("[%s] s\n",__func__); - - /* May retry process comes here.*/ - host->mrq = mrq; - host->data = mrq->data; - host->cmd = mrq->cmd; - host->done_data = NULL; - host->done = NULL; - - /*for data request*/ - if (host->data) { - if (host->cmd->opcode == MMC_WRITE_BLOCK - || host->cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK - || host->cmd->opcode == MMC_READ_SINGLE_BLOCK - || host->cmd->opcode == MMC_READ_MULTIPLE_BLOCK - || host->cmd->opcode == SD_IO_RW_EXTENDED) { - atsmb1_start_data(host); - } else { - atsmb1_cmd_with_data_back(host); - } - } else { - atsmb1_start_cmd(host); - } - DBG("[%s] e\n",__func__); -} -/********************************************************************** -Name : atsmb1_set_clock -Function :. -Calls : -Called by : -Parameter : -Author : Eason Chien -History :2012/7/19 -***********************************************************************/ -static int atsmb1_set_clock(struct mmc_host *mmc, unsigned int clock) -{ - int clock_multiplier = 1; - DBG("clock = %u\n",clock); - - if (*ATSMB1_EXT_BUS_MODE & BIT4) /*Enable DDR50*/ - clock_multiplier = 2; - - if (clock == mmc->f_min) { - DBG("[%s]ATSMB1 Host 400KHz\n", __func__); - return auto_pll_divisor(DEV_SDMMC1, SET_DIV, 1, 390 * clock_multiplier); - } else if (clock >= 50000000) { - DBG("[%s]ATSMB1 Host 50MHz\n", __func__); - return auto_pll_divisor(DEV_SDMMC1, SET_DIV, 2, 45 * clock_multiplier); - } else if ((clock >= 25000000) && (clock < 50000000)) { - DBG("[%s]ATSMB1 Host 25MHz\n", __func__); - return auto_pll_divisor(DEV_SDMMC1, SET_DIV, 2, 24 * clock_multiplier); - } else if ((clock >= 20000000) && (clock < 25000000)) { - DBG("[%s]ATSMB1 Host 20MHz\n", __func__); - return auto_pll_divisor(DEV_SDMMC1, SET_DIV, 2, 20 * clock_multiplier); - } else { - DBG("[%s]ATSMB1 Host 390KHz\n", __func__); - return auto_pll_divisor(DEV_SDMMC1, SET_DIV, 1, 390 * clock_multiplier); - } -} - -/********************************************************************** -Name : atsmb1_set_ios -Function :. -Calls : -Called by : -Parameter : -Author : Leo Lee -History : -***********************************************************************/ -static void atsmb1_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) -{ - - struct atsmb_host *host = mmc_priv(mmc); - unsigned long flags; - unsigned int strapping; - - DBG("[%s] s\n",__func__); - spin_lock_irqsave(&host->lock, flags); - - if (ios->power_mode == MMC_POWER_OFF) { - if (MMC1_DRIVER_VERSION == MMC_DRV_3498) { - if (atsmb1_first_boot) { - /*nothing to do for GPIO setting when first boot.*/ - } else { - /* stop SD output clock */ - *ATSMB1_BUS_MODE &= ~(ATSMB_CST); - - /* disable SD1 Card power */ - /*set SD1 power pin as GPO pin*/ - GPIO_CTRL_GP14_NAND_SD1_BYTE_VAL |= GPIO_SD1_POWER; - GPIO_OC_GP14_NAND_SD1_BYTE_VAL |= GPIO_SD1_POWER; - /*set internal pull up*/ - PULL_CTRL_GP14_NAND_BYTE_VAL |= GPIO_SD1_POWER; - /*set internal pull enable*/ - PULL_EN_GP14_NAND_BYTE_VAL |= GPIO_SD1_POWER; - /*disable SD1 power*/ - GPIO_OD_GP14_NAND_SD1_BYTE_VAL |= GPIO_SD1_POWER; - - /* Config SD1 to GPIO */ - GPIO_CTRL_GP16_NAND_SD1_BYTE_VAL |= GPIO_SD1_Data; - GPIO_CTRL_GP14_NAND_SD1_BYTE_VAL |= SD1_PIN; - - /* SD1 all pins output low */ - GPIO_OD_GP16_NAND_SD1_BYTE_VAL &= ~GPIO_SD1_Data; - GPIO_OD_GP14_NAND_SD1_BYTE_VAL &= ~SD1_PIN; - - /* Config SD1 to GPIO */ - GPIO_OC_GP16_NAND_SD1_BYTE_VAL |= GPIO_SD1_Data; - GPIO_OC_GP14_NAND_SD1_BYTE_VAL |= SD1_PIN; - - /*Set SD1 CMD pin pull low because SD1CMD has no gpio pin, check with Jim*/ - /*PULL_CTRL_GP14_NAND_BYTE_VAL &= ~GPIO_SD1_Command; - PULL_EN_GP14_NAND_BYTE_VAL |= GPIO_SD1_Command;*/ - } - } - } else if (ios->power_mode == MMC_POWER_UP) { - if (MMC1_DRIVER_VERSION == MMC_DRV_3498) { - if (atsmb1_first_boot) { - /*nothing to do for GPIO setting when first boot.*/ - } else { - /* disable SD Card power */ - /*set SD1 power pin as GPO pin*/ - GPIO_CTRL_GP14_NAND_SD1_BYTE_VAL |= GPIO_SD1_POWER; - GPIO_OC_GP14_NAND_SD1_BYTE_VAL |= GPIO_SD1_POWER; - /*set internal pull up*/ - PULL_CTRL_GP14_NAND_BYTE_VAL |= GPIO_SD1_POWER; - /*set internal pull enable*/ - PULL_EN_GP14_NAND_BYTE_VAL |= GPIO_SD1_POWER; - /*disable SD1 power*/ - GPIO_OD_GP14_NAND_SD1_BYTE_VAL |= GPIO_SD1_POWER; - - /* enable SD1 PIN share */ - PIN_SHARING_SEL_4BYTE_VAL |= GPIO_SD1_PinShare; - - /* do not config GPIO_SD1_CD because ISR has already run, - * config card detect will issue ISR storm. - */ - /* Config SD to GPIO */ - GPIO_CTRL_GP16_NAND_SD1_BYTE_VAL |= GPIO_SD1_Data; - GPIO_CTRL_GP14_NAND_SD1_BYTE_VAL |= SD1_PIN; - - /* SD all pins output low */ - GPIO_OD_GP16_NAND_SD1_BYTE_VAL &= ~GPIO_SD1_Data; - GPIO_OD_GP14_NAND_SD1_BYTE_VAL &= ~SD1_PIN; - - /* Config SD to GPO */ - GPIO_OC_GP16_NAND_SD1_BYTE_VAL |= GPIO_SD1_Data; - GPIO_OC_GP14_NAND_SD1_BYTE_VAL |= SD1_PIN; - - /* stop SD output clock */ - *ATSMB1_BUS_MODE &= ~ATSMB_CST; - - /* Pull up/down resister of SD Bus */ - /*Disable Clock & CMD Pull enable*/ - PULL_EN_GP14_NAND_BYTE_VAL &= ~(GPIO_SD1_Clock | GPIO_SD1_Command); - - /*Set CD ,WP ,DATA pin pull up*/ - PULL_CTRL_GP16_NANDIO_BYTE_VAL |= GPIO_SD1_Data; - PULL_CTRL_GP14_NAND_BYTE_VAL |= (GPIO_SD1_WriteProtect | GPIO_SD1_CD); - - /*Enable CD ,WP ,DATA internal pull*/ - PULL_EN_GP16_NANDIO_BYTE_VAL |= GPIO_SD1_Data; - PULL_EN_GP14_NAND_BYTE_VAL |= (GPIO_SD1_WriteProtect | GPIO_SD1_CD); - - spin_unlock_irqrestore(&host->lock, flags); - msleep(1); - spin_lock_irqsave(&host->lock, flags); - - /* enable SD1 power */ - GPIO_OD_GP14_NAND_SD1_BYTE_VAL &= ~GPIO_SD1_POWER; - - /* enable SD output clock */ - *ATSMB1_BUS_MODE |= ATSMB_CST; - - spin_unlock_irqrestore(&host->lock, flags); - msleep(1); - spin_lock_irqsave(&host->lock, flags); - - /* Config SD1 back to function */ - GPIO_CTRL_GP16_NAND_SD1_BYTE_VAL &= ~GPIO_SD1_Data; - GPIO_CTRL_GP14_NAND_SD1_BYTE_VAL &= ~SD1_PIN; - GPIO_CTRL_GP14_NAND_SD1_BYTE_VAL &= ~GPIO_SD1_CD; - - /* terminate emmc boot mode */ - DBG("[%s] STRAP_STATUS_VAL = 0x%x\n", __func__, STRAP_STATUS_VAL); - strapping = STRAP_STATUS_VAL & 0xE; - if (strapping == 0x2) { - printk("[%s] strapping = 0x%x, terminate boot mode\n", __func__, strapping); - *ATSMB1_EXT_BUS_MODE &= ~BIT0; - *ATSMB1_BUS_MODE &= ~BIT4; - *ATSMB1_BUS_MODE |= BIT4; - } - } - } - } else { - /*nothing to do when powering on.*/ - } - - host->current_clock = atsmb1_set_clock(mmc,ios->clock); - - if (ios->bus_width == MMC_BUS_WIDTH_8) { - *ATSMB1_EXT_CTL |= (0x04); - } else if (ios->bus_width == MMC_BUS_WIDTH_4) { - *ATSMB1_BUS_MODE |= ATSMB_BUS_WIDTH_4; - *ATSMB1_EXT_CTL &= ~(0x04); - } else { - *ATSMB1_BUS_MODE &= ~(ATSMB_BUS_WIDTH_4); - *ATSMB1_EXT_CTL &= ~(0x04); - } - -#if 1 - if (ios->timing == MMC_TIMING_SD_HS) - *ATSMB1_EXT_CTL &= ~0x80; /*HIGH SPEED MODE hsot1 H_S must be off for wm3498*/ - else if (ios->timing == MMC_TIMING_MMC_HS) - *ATSMB1_EXT_CTL &= ~0x80; - else if (ios->timing == MMC_TIMING_UHS_DDR50) { - /* enable emmc DDR mode */ - *ATSMB1_EXT_BUS_MODE |= BIT4; /*Enable DDR50*/ - /* enable SD output clock */ - *ATSMB1_BUS_MODE &= ~ATSMB_CST; - spin_unlock_irqrestore(&host->lock, flags); - msleep(1); - spin_lock_irqsave(&host->lock, flags); - - *ATSMB1_EXT_BUS_MODE |= BIT4; /*Enable DDR50*/ - /* enable SD output clock */ - *ATSMB0_BUS_MODE |= ATSMB_CST; - /*BIT4~7: PMOS driver strength, BIT8~11: NMOS driver strength */ - DRV_SPI_NAND_4BYTE_VAL |= (BIT4 |BIT5 | BIT6 | BIT7 | BIT8 | BIT9 | BIT10 | BIT11); - } -#endif -#if 0 //zhf: marked by James Tian - if (ios->ins_en == MMC_INSERT_IRQ_EN) - *ATSMB1_INT_MASK_0 |= (0x80);/* or 40?*/ - else - *ATSMB1_INT_MASK_0 &= (~0x80);/* or 40?*/ -#endif - - spin_unlock_irqrestore(&host->lock, flags); - DBG("[%s] e\n",__func__); -} - - -static const struct mmc_host_ops atsmb1_ops = { - .request = atsmb1_request, - .set_ios = atsmb1_set_ios, - .get_ro = atsmb1_get_ro, - .get_slot_status = atsmb1_get_slot_status, - .dump_host_regs = atsmb1_dump_host_regs, - .enable_sdio_irq = atsmb1_enable_sdio_irq, -}; - -extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen); - -/********************************************************************** -Name :atsmb1_probe -Function :. -Calls : -Called by : -Parameter : -Author : Leo Lee -History : -***********************************************************************/ -static int __init atsmb1_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct mmc_host *mmc_host = NULL; - struct atsmb_host *atsmb_host = NULL; - struct resource *resource = NULL; - int irq[2] = {0}; - int ret = 0; - DBG("[%s] s\n",__func__); - if (!pdev) { - ret = -EINVAL; /* Invalid argument */ - goto the_end; - } - - - /*Enable SD host clock*/ - auto_pll_divisor(DEV_SDMMC1, CLK_ENABLE, 0, 0); - - if (MMC1_DRIVER_VERSION == MMC_DRV_3498) { - /* enable SD1 PIN share */ - PIN_SHARING_SEL_4BYTE_VAL |= GPIO_SD1_PinShare; - - /* Pull up/down resister of SD CD */ - PULL_CTRL_GP14_NAND_BYTE_VAL |= GPIO_SD1_CD; - PULL_EN_GP14_NAND_BYTE_VAL |= GPIO_SD1_CD; - - /* config CardDetect pin to SD function */ - GPIO_CTRL_GP14_NAND_SD1_BYTE_VAL &= ~GPIO_SD1_CD; - } - - /* support emmc fisrt boot don't setting GPIO*/ - atsmb1_first_boot = 1; //1:first boot, 0: suspend/resume - - resource = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!resource) { - ret = -ENXIO; /* No such device or address */ - printk(KERN_ALERT "[MMC/SD driver] Getting platform resources failed!\n"); - goto the_end; - } -#if 0 - if (!request_mem_region(resource->start, SZ_1K, MMC1_DRIVER_NAME)) { - ret = -EBUSY; - printk(KERN_ALERT "[MMC/SD driver] Request memory region failed!\n"); - goto the_end ; - } -#endif - irq[0] = platform_get_irq(pdev, 0); /*get IRQ for device*/; - irq[1] = platform_get_irq(pdev, 1); /*get IRQ for dma*/; - - if (irq[0] == NO_IRQ || irq[1] == NO_IRQ) { - ret = -ENXIO;/* No such device or address */ - printk(KERN_ALERT "[MMC/SD driver] Get platform IRQ failed!\n"); - goto rls_region; - } - - /*allocate a standard msp_host structure attached with a atsmb structure*/ - mmc_host = mmc_alloc_host(sizeof(struct atsmb_host), dev); - if (!mmc_host) { - ret = -ENOMEM; - printk(KERN_ALERT "[MMC/SD driver] Allocating driver's data failed!\n"); - goto rls_region; - } - mmc_host->wmt_host_index = 1; /*to identify host number*/ - - dev_set_drvdata(dev, (void *)mmc_host); /* mmc_host is driver data for the atsmb dev.*/ - atsmb_host = mmc_priv(mmc_host); - - mmc_host->ops = &atsmb1_ops; - - mmc_host->ocr_avail = MMC_VDD_32_33|MMC_VDD_33_34; - - mmc_host->f_min = 390425; /*390.425Hz = 400MHz/64/16*/ - mmc_host->f_max = 50000000; /* in fact, the max frequency is 400MHz( = 400MHz/1/1)*/ - - if (SDXC1_function == 1) { - mmc_host->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ - | MMC_CAP_MMC_HIGHSPEED | MMC_CAP_8_BIT_DATA | MMC_CAP_1_8V_DDR | MMC_CAP_UHS_DDR50; - } else if (SDXC1_function == 0) { - mmc_host->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ - | MMC_CAP_MMC_HIGHSPEED | MMC_CAP_8_BIT_DATA; /* */ //zhf: marked by James Tian - } - - mmc_host->max_segs = 128; /*we use software sg. so we could manage even larger number.*/ - - /*1MB per each request */ - /*we have a 16 bit block number register, and block length is 512 bytes.*/ - mmc_host->max_req_size = 16*512*(mmc_host->max_segs); - mmc_host->max_seg_size = 65024; /* 0x7F*512 PDMA one descriptor can transfer 64K-1 byte*/ - mmc_host->max_blk_size = 2048; /* our block length register is 11 bits.*/ - mmc_host->max_blk_count = (mmc_host->max_req_size)/512; - - /*set the specified host -- ATSMB*/ -#ifdef CONFIG_MMC_UNSAFE_RESUME - mmc_host->card_attath_status = card_attach_status_unchange; -#endif - sema_init(&mmc_host->req_sema,1); /*initial request semaphore*/ -#if 0 - atsmb_host->base = ioremap(resource->start, SZ_1K); - if (!atsmb_host->base) { - printk(KERN_ALERT "[MMC/SD driver] IO remap failed!\n"); - ret = -ENOMEM; - goto fr_host; - } -#endif - atsmb_host->base = (void *)resource->start; - atsmb_host->mmc = mmc_host; - spin_lock_init(&atsmb_host->lock); - atsmb_host->res = resource;/* for atsmb_remove*/ - - /*disable all interrupt and clear status by resetting controller.*/ - //*ATSMB1_BUS_MODE |= ATSMB_SFTRST; //emmc card don't execute SW reset. because uboot is done. - *ATSMB1_BLK_LEN &= ~(0xa000); - *ATSMB1_SD_STS_0 |= 0xff; - *ATSMB1_SD_STS_1 |= 0xff; - - /* WM3437 A0 default not output clock, after SFTRST need to enable SD clock */ - //if (MMC1_DRIVER_VERSION >= MMC_DRV_3437_A0) /* including 3429 */ - *ATSMB1_BUS_MODE |= ATSMB_CST; - - atsmb_host->regular_irq = irq[0]; - atsmb_host->dma_irq = irq[1]; - - ret = request_irq(atsmb_host->regular_irq, - atsmb1_regular_isr, - IRQF_SHARED, //SA_SHIRQ, /*SA_INTERRUPT, * that is okay?*/ //zhf: modified by James Tian, should be IRQF_SHARED? - MMC1_DRIVER_NAME, - (void *)atsmb_host); - if (ret) { - printk(KERN_ALERT "[MMC/SD driver] Failed to register regular ISR!\n"); - goto unmap; - } - - ret = request_irq(atsmb_host->dma_irq, - atsmb1_dma_isr, - IRQF_DISABLED, // SA_INTERRUPT, //zhf: modified by James Tian - MMC1_DRIVER_NAME, - (void *)atsmb_host); - if (ret) { - printk(KERN_ALERT "[MMC/SD driver] Failed to register DMA ISR!\n"); - goto fr_regular_isr; - } - - - - /*wait card detect status change*/ - //msleep(10); - /*enable card insertion interrupt and enable DMA and its Global INT*/ - *ATSMB1_BLK_LEN |= (0xa000); /* also, we enable GPIO to detect card.*/ - *ATSMB1_SD_STS_0 |= 0xff; - *ATSMB1_INT_MASK_0 |= 0x80; /*or 0x40?*/ - - /*allocation dma descriptor*/ - ret = atsmb1_alloc_desc(atsmb_host, sizeof(struct SD_PDMA_DESC_S) * MAX_DESC_NUM); - if (ret == -1) { - printk(KERN_ALERT "[MMC/SD driver] Failed to allocate DMA descriptor!\n"); - goto fr_dma_isr; - } - printk(KERN_INFO "WMT ATSMB1 (AHB To SD/MMC1 Bus) controller registered!\n"); - mmc_add_host(mmc_host,true); - - DBG("[%s] e1\n",__func__); - return 0; - -fr_dma_isr: - free_irq(atsmb_host->dma_irq, atsmb_host); -fr_regular_isr: - free_irq(atsmb_host->regular_irq, atsmb_host); -unmap: - //iounmap(atsmb_host->base); -//fr_host: - dev_set_drvdata(dev, NULL); - mmc_free_host(mmc_host); -rls_region: - //release_mem_region(resource->start, SZ_1K); -the_end: - printk(KERN_ALERT "[MMC/SD driver] ATSMB1 probe Failed!\n") ; - DBG("[%s] e2\n",__func__); - return ret; -} -/********************************************************************** -Name : atsmb1_remove -Function :. -Calls : -Called by : -Parameter : -Author : Leo Lee -History : -***********************************************************************/ -static int atsmb1_remove(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct mmc_host *mmc_host = (struct mmc_host *)dev_get_drvdata(dev); - struct atsmb_host *atsmb_host; - - DBG("[%s] s\n",__func__); - atsmb_host = mmc_priv(mmc_host); - if (!mmc_host || !atsmb_host) { - printk(KERN_ALERT "[MMC/SD driver] ATSMB1 remove method failed!\n"); - DBG("[%s] e1\n",__func__); - return -ENXIO; - } - mmc_remove_host(mmc_host); - - /*disable interrupt by resetting controller -- for safey*/ - *ATSMB1_BUS_MODE |= ATSMB_SFTRST; - *ATSMB1_BLK_LEN &= ~(0xa000); - *ATSMB1_SD_STS_0 |= 0xff; - *ATSMB1_SD_STS_1 |= 0xff; - - (void)free_irq(atsmb_host->regular_irq, atsmb_host); - (void)free_irq(atsmb_host->dma_irq, atsmb_host); - (void)iounmap(atsmb_host->base); - (void)release_mem_region(atsmb_host->res->start, SZ_1K); - dev_set_drvdata(dev, NULL); - /*free dma descriptor*/ - dma_free_coherent(atsmb_host->mmc->parent, atsmb_host->DescSize, - atsmb_host->DescVirAddr, atsmb_host->DescPhyAddr); - (void)mmc_free_host(mmc_host);/* also free atsmb_host.*/ - DBG("[%s] e2\n",__func__); - return 0; -} - -/********************************************************************** -Name : atsmb_shutdown -Function :. -Calls : -Called by : -Parameter : -Author : Tommy Huang -History : -***********************************************************************/ -static void atsmb1_shutdown(struct platform_device *pdev) -{ - /*atsmb1_shutdown don't be used now.*/ - /*struct device *dev = &pdev->dev; - struct mmc_host *mmc_host = (struct mmc_host *)dev_get_drvdata(dev);*/ - - DBG("[%s] s\n",__func__); - - /* turn off clock before emmc card shutdown. */ - *ATSMB1_BUS_MODE &= ~(ATSMB_CST); - - /*Disable card detect interrupt*/ - *ATSMB1_INT_MASK_0 &= ~0x80; - DBG("[%s] e\n",__func__); - -} - -/********************************************************************** -Name : atsmb_suspend -Function :. -Calls : -Called by : -Parameter : -Author : Leo Lee -History : -***********************************************************************/ -#ifdef CONFIG_PM -static int atsmb1_suspend(struct platform_device *pdev, pm_message_t state) -{ - struct device *dev = &pdev->dev; - struct mmc_host *mmc = (struct mmc_host *)dev_get_drvdata(dev); - int ret = 0; - DBG("[%s] s\n",__func__); - - /* after suspend/resume, it isn't first boot*/ - atsmb1_first_boot = 0; - - if (mmc) { - /*struct atsmb_host *host = mmc_priv(mmc);*/ - ret = mmc_suspend_host(mmc); - if (ret == 0) { - /*disable all interrupt and clear status by resetting controller. */ - *ATSMB1_BUS_MODE |= ATSMB_SFTRST; - *ATSMB1_BLK_LEN &= ~(0xa000); - *ATSMB1_SD_STS_0 |= 0xff; - *ATSMB1_SD_STS_1 |= 0xff; - - } - /*disable source clock*/ - //TODO: SD1 clock en or dis - auto_pll_divisor(DEV_SDMMC1, CLK_DISABLE, 0, 0); -#ifdef CONFIG_MMC_UNSAFE_RESUME - /*clean SD card attatch status change*/ - PMCWS_VAL |= BIT20; - mmc->card_attath_status = card_attach_status_unchange; -#endif - } - - DBG("[%s] e\n",__func__); - return ret; -} -/********************************************************************** -Name : atsmb_resume -Function :. -Calls : -Called by : -Parameter : -Author : Leo Lee -History : -***********************************************************************/ -static int atsmb1_resume(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct mmc_host *mmc = (struct mmc_host *)dev_get_drvdata(dev); - int ret = 0; - DBG("[%s] s\n",__func__); - - /* - * enable interrupt, DMA, etc. - * Supply power to slot. - */ - if (mmc) { - /*enable source clock*/ - auto_pll_divisor(DEV_SDMMC1, CLK_ENABLE, 0, 0); - - udelay(1); - /*enable card insertion interrupt and enable DMA and its Global INT*/ - *ATSMB1_BUS_MODE |= ATSMB_SFTRST; - *ATSMB1_BLK_LEN |= (0xa000); - *ATSMB1_INT_MASK_0 |= 0x80; /* or 40?*/ -#ifdef CONFIG_MMC_UNSAFE_RESUME - /*modify SD card attatch status change*/ - if ((PMCWS_VAL & BIT20) && !mmc->bus_dead) { - /*card change when suspend mode*/ - mmc->card_attath_status = card_attach_status_change; - /*clean SD card attatch status change*/ - PMCWS_VAL |= BIT20; - } -#endif - ret = mmc_resume_host(mmc); - } - - DBG("[%s] e\n",__func__); - return ret; -} -#else -#define atsmb1_suspend NULL -#define atsmb1_resume NULL -#endif - -static struct platform_driver atsmb1_driver = { - .driver.name = "sdmmc1", - //.probe = atsmb1_probe, - .remove = atsmb1_remove, - .shutdown = atsmb1_shutdown, - .suspend = atsmb1_suspend, - .resume = atsmb1_resume, -}; - -static struct platform_device wmt_sdmmc1_device = { - .name = "sdmmc1", - .id = 0, - .dev = { - .dma_mask = &wmt_sdmmc1_dma_mask, - .coherent_dma_mask = ~0, - .release = atsmb1_release, - }, - .num_resources = ARRAY_SIZE(wmt_sdmmc1_resources), - .resource = wmt_sdmmc1_resources, -}; - - -static int __init atsmb1_init(void) -{ - int ret; - int retval; - unsigned char buf[80]; - int varlen = 80; - char *varname = "wmt.sd1.param"; - int temp = 0, sd_enable = 0; /*0 :disable 1:enable*/ - - DBG("[%s] s\n",__func__); - -#ifdef CONFIG_MTD_WMT_SF - /*Read system param to identify host function 0: SD/MMC 1:SDIO wifi*/ - retval = wmt_getsyspara(varname, buf, &varlen); - if (retval == 0) { - sscanf(buf,"%x:%d", &temp, &SD1_function); - printk(KERN_ALERT "wmt.sd1.param = %x:%d\n", temp, SD1_function); - sd_enable = temp & 0xf; - SDXC1_function = (temp >> 4) & 0xf; - printk(KERN_ALERT "SD1 ebable = %x, SDXC = %x, function = %x\n", - sd_enable, SDXC1_function, SD1_function); - - if (SD1_function < 0 || SD1_function >= SD_MAX_FUN) - return -ENODEV; - } else { - printk(KERN_ALERT "Default wmt.sd1.param = %x:%d\n", temp, SD1_function); - } -#endif - /*SD function disable*/ - if (sd_enable != 1) - return -ENODEV; - - get_driver_version1(); - - if (platform_device_register(&wmt_sdmmc1_device))//add by jay,for modules support - return -1; - //ret = platform_driver_register(&atsmb1_driver); - ret = platform_driver_probe(&atsmb1_driver, atsmb1_probe); - - DBG("[%s] e\n",__func__); - return ret; -} - -static void __exit atsmb1_exit(void) -{ - DBG("[%s] s\n",__func__); - (void)platform_driver_unregister(&atsmb1_driver); - (void)platform_device_unregister(&wmt_sdmmc1_device);//add by jay,for modules support - DBG("[%s] e\n",__func__); -} - -module_init(atsmb1_init); -module_exit(atsmb1_exit); -module_param(fmax1, uint, 0444); - -MODULE_AUTHOR("WonderMedia Technologies, Inc."); -MODULE_DESCRIPTION("WMT [AHB to SD/MMC1 Bridge] driver"); -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/mmc/host/mmc_atsmb2.c b/ANDROID_3.4.5/drivers/mmc/host/mmc_atsmb2.c deleted file mode 100755 index 944e3cc4..00000000 --- a/ANDROID_3.4.5/drivers/mmc/host/mmc_atsmb2.c +++ /dev/null @@ -1,2855 +0,0 @@ -/*++ -linux/drivers/mmc/host/mmc_atsmb.c - -Copyright (c) 2008 WonderMedia Technologies, Inc. - -This program is free software: you can redistribute it and/or modify it under the -terms of the GNU General Public License as published by the Free Software Foundation, -either version 2 of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A -PARTICULAR PURPOSE. See the GNU General Public License for more details. -You should have received a copy of the GNU General Public License along with -this program. If not, see <http://www.gnu.org/licenses/>. - -WonderMedia Technologies, Inc. -10F, 529, Chung-Cheng Road, Hsin-Tien, Taipei 231, R.O.C. ---*/ - -//#include <linux/config.h> -#include <linux/module.h> -#include <linux/moduleparam.h> -#include <linux/init.h> -#include <linux/ioport.h> -#include <linux/device.h> -#include <linux/platform_device.h> -#include <linux/interrupt.h> -#include <linux/delay.h> -#include <linux/err.h> -#include <linux/interrupt.h> -#include <linux/blkdev.h> -#include <linux/mmc/host.h> -#include <linux/mmc/card.h> -#include <linux/mmc/sd.h> -#include <linux/mmc/mmc.h> -#include <linux/mmc/sdio.h> -#include <linux/completion.h> -#include <linux/pagemap.h> -#include <linux/dma-mapping.h> -#include <asm/dma.h> -#include <asm/io.h> -#include <asm/irq.h> -#include <asm/memory.h> -#include <mach/hardware.h> -#include <asm/scatterlist.h> -#include <asm/sizes.h> -#include "mmc_atsmb.h" -//#include <mach/multicard.h> -#include <mach/irqs.h> -#include <linux/mmc/sdio.h> -#include <linux/gpio.h> -#include <mach/wmt_iomux.h> - -int enable_wifi_irq = 1; - -#define MMC2_SDIO_EXT_IRQ (1) /* use sdio ext irq or not */ - -#if MMC2_SDIO_EXT_IRQ -static int is_mtk6620 = 0; -static unsigned int mmc2_sdio_ext_irq = 0; -static unsigned long mmc2_sdio_ext_irq_flags = 0; -enum ext_irq_flag { - IN_SUSPEND = 0, - IRQ_IN_SUSPEND = 1, -}; -int wmt_mtk6620_intr=0xf; //gpio 15 -#endif - - -static int is_nmc1000 = 0x0; -static int is_ap6330 = 0; -int set_bus_dead = 1; -#define mprintk - -#if 0 -#define DBG(host, fmt, args...) \ - pr_debug("%s: %s: " fmt, mmc_hostname(host->mmc), __func__ , args) -#endif -#define ATSMB_TIMEOUT_TIME (HZ*2) - -//add by jay,for modules support -static u64 wmt_sdmmc2_dma_mask = 0xffffffffUL; -static struct resource wmt_sdmmc2_resources[] = { - [0] = { - .start = SD2_SDIO_MMC_BASE_ADDR, - .end = (SD2_SDIO_MMC_BASE_ADDR + 0x3FF), - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = IRQ_SDC2, - .end = IRQ_SDC2, - .flags = IORESOURCE_IRQ, - }, - [2] = { - .start = IRQ_SDC2_DMA, - .end = IRQ_SDC2_DMA, - .flags = IORESOURCE_IRQ, - }, - /*2008/10/6 RichardHsu-s*/ - [3] = { - .start = IRQ_PMC_WAKEUP, - .end = IRQ_PMC_WAKEUP, - .flags = IORESOURCE_IRQ, - }, - /*2008/10/6 RichardHsu-e*/ -}; - -struct kobject *atsmb2_kobj; -struct mmc_host *mmc2_host_attr = NULL; -// -static void atsmb2_release(struct device * dev) {} - -/*#ifdef CONFIG_MMC_DEBUG*/ -#define MORE_INFO -#if 0 -#define DBG(x...) printk(KERN_ALERT x) -#define DBGR(x...) printk(KERN_ALERT x) -#else -#define DBG(x...) do { } while (0) -#define DBGR(x...) do { } while (0) -#endif - -/* when Read CRC error occur, and clear read CRC error by software reset.*/ -void atsmb2_copy_reg(int direct) -{ - static u8 CTL, CMD_IDX, RSP_TYPE, BUS_MODE, INT_MASK_0, INT_MASK_1, SD_STS_0, SD_STS_1, SD_STS_2, SD_STS_3; - static u8 EXT_BUS_MODE, EXT_CTL_1, EXT_CTL_2, MAN_TUNE_VAL, SD_WRI_TUNE; - static u8 RSP_0, RSP_1, RSP_2, RSP_3, RSP_4, RSP_5, RSP_6, RSP_7; - static u8 RSP_8, RSP_9, RSP_10, RSP_11, RSP_12, RSP_13, RSP_14, RSP_15; - static u8 RSP_TOUT, CLK_SEL, EXT_CTL; - static u16 BLK_LEN, BLK_CNT, SHDW_BLKLEN, TIMER_VAL, CTL2; - static u32 CMD_ARG, CURBLK_CNT; - - /*direct 0: copy register to memory; 1: copy memory to register.*/ - if (direct == 0) { - CTL = *ATSMB2_CTL; - CMD_IDX = *ATSMB2_CMD_IDX; - RSP_TYPE = *ATSMB2_RSP_TYPE; - CMD_ARG = *ATSMB2_CMD_ARG; - BUS_MODE = *ATSMB2_BUS_MODE; - EXT_BUS_MODE = *ATSMB2_EXT_BUS_MODE; - CTL2 = *ATSMB2_CTL2; - BLK_LEN = *ATSMB2_BLK_LEN; - BLK_CNT = *ATSMB2_BLK_CNT; - RSP_0 = *ATSMB2_RSP_0; - RSP_1 = *ATSMB2_RSP_1; - RSP_2 = *ATSMB2_RSP_2; - RSP_3 = *ATSMB2_RSP_3; - RSP_4 = *ATSMB2_RSP_4; - RSP_5 = *ATSMB2_RSP_5; - RSP_6 = *ATSMB2_RSP_6; - RSP_7 = *ATSMB2_RSP_7; - RSP_8 = *ATSMB2_RSP_8; - RSP_9 = *ATSMB2_RSP_9; - RSP_10 = *ATSMB2_RSP_10; - RSP_11 = *ATSMB2_RSP_11; - RSP_12 = *ATSMB2_RSP_12; - RSP_13 = *ATSMB2_RSP_13; - RSP_14 = *ATSMB2_RSP_14; - RSP_15 = *ATSMB2_RSP_15; - CURBLK_CNT = *ATSMB2_CURBLK_CNT; - INT_MASK_0 = *ATSMB2_INT_MASK_0; - INT_MASK_1 = *ATSMB2_INT_MASK_1; - SD_STS_0 = *ATSMB2_SD_STS_0; - SD_STS_1 = *ATSMB2_SD_STS_1; - SD_STS_2 = *ATSMB2_SD_STS_2; - SD_STS_3 = *ATSMB2_SD_STS_3; - RSP_TOUT = *ATSMB2_RSP_TOUT; - CLK_SEL = *ATSMB2_CLK_SEL; - EXT_CTL = *ATSMB2_EXT_CTL; - EXT_CTL_1 = *ATSMB2_EXT_CTL_1; - EXT_CTL_2 = *ATSMB2_EXT_CTL_2; - SHDW_BLKLEN = *ATSMB2_SHDW_BLKLEN; - MAN_TUNE_VAL = *ATSMB2_MAN_TUNE_VAL; - SD_WRI_TUNE = *ATSMB2_SD_WRI_TUNE; - TIMER_VAL = *ATSMB2_TIMER_VAL; - } else { - *ATSMB2_CTL = CTL; - *ATSMB2_CMD_IDX = CMD_IDX; - *ATSMB2_RSP_TYPE = RSP_TYPE; - *ATSMB2_CMD_ARG = CMD_ARG; - *ATSMB2_BUS_MODE = BUS_MODE; - *ATSMB2_EXT_BUS_MODE = EXT_BUS_MODE; - *ATSMB2_CTL2 = CTL2; - *ATSMB2_BLK_LEN = BLK_LEN; - *ATSMB2_BLK_CNT = BLK_CNT; - *ATSMB2_RSP_0 = RSP_0; - *ATSMB2_RSP_1 = RSP_1; - *ATSMB2_RSP_2 = RSP_2; - *ATSMB2_RSP_3 = RSP_3; - *ATSMB2_RSP_4 = RSP_4; - *ATSMB2_RSP_5 = RSP_5; - *ATSMB2_RSP_6 = RSP_6; - *ATSMB2_RSP_7 = RSP_7; - *ATSMB2_RSP_8 = RSP_8; - *ATSMB2_RSP_9 = RSP_9; - *ATSMB2_RSP_10 = RSP_10; - *ATSMB2_RSP_11 = RSP_11; - *ATSMB2_RSP_12 = RSP_12; - *ATSMB2_RSP_13 = RSP_13; - *ATSMB2_RSP_14 = RSP_14; - *ATSMB2_RSP_15 = RSP_15; - *ATSMB2_CURBLK_CNT = CURBLK_CNT; - *ATSMB2_INT_MASK_0 = INT_MASK_0; - *ATSMB2_INT_MASK_1 = INT_MASK_1; - *ATSMB2_SD_STS_0 = SD_STS_0; - *ATSMB2_SD_STS_1 = SD_STS_1; - *ATSMB2_SD_STS_2 = SD_STS_2; - *ATSMB2_SD_STS_3 = SD_STS_3; - *ATSMB2_RSP_TOUT = RSP_TOUT; - *ATSMB2_CLK_SEL = CLK_SEL; - *ATSMB2_EXT_CTL = EXT_CTL; - *ATSMB2_EXT_CTL_1 = EXT_CTL_1; - *ATSMB2_EXT_CTL_2 = EXT_CTL_2; - *ATSMB2_SHDW_BLKLEN = SHDW_BLKLEN; - *ATSMB2_MAN_TUNE_VAL = MAN_TUNE_VAL; - *ATSMB2_SD_WRI_TUNE = SD_WRI_TUNE; - *ATSMB2_TIMER_VAL = TIMER_VAL; - } -} - -#if 0 -void atsmb2_dump_reg(struct atsmb_host *host) -{ - u8 CTL, CMD_IDX, RSP_TYPE, BUS_MODE, INT_MASK_0, INT_MASK_1, SD_STS_0, SD_STS_1, SD_STS_2, SD_STS_3; - u8 EXT_BUS_MODE, EXT_CTL_1, EXT_CTL_2, MAN_TUNE_VAL, SD_WRI_TUNE; - u8 RSP_0, RSP_1, RSP_2, RSP_3, RSP_4, RSP_5, RSP_6, RSP_7; - u8 RSP_8, RSP_9, RSP_10, RSP_11, RSP_12, RSP_13, RSP_14, RSP_15; - u8 RSP_TOUT, CLK_SEL, EXT_CTL; - u16 BLK_LEN, BLK_CNT, SHDW_BLKLEN, TIMER_VAL, CTL2; - u32 CMD_ARG, PDMA_GCR, PDMA_IER, PDMA_ISR, PDMA_DESPR, PDMA_RBR, PDMA_DAR, PDMA_BAR, PDMA_CPR, PDMA_CCR; - u32 CURBLK_CNT; - - CTL = *ATSMB2_CTL; - CMD_IDX = *ATSMB2_CMD_IDX; - RSP_TYPE = *ATSMB2_RSP_TYPE; - CMD_ARG = *ATSMB2_CMD_ARG; - BUS_MODE = *ATSMB2_BUS_MODE; - EXT_BUS_MODE = *ATSMB2_EXT_BUS_MODE; - CTL2 = *ATSMB2_CTL2; - BLK_LEN = *ATSMB2_BLK_LEN; - BLK_CNT = *ATSMB2_BLK_CNT; - RSP_0 = *ATSMB2_RSP_0; - RSP_1 = *ATSMB2_RSP_1; - RSP_2 = *ATSMB2_RSP_2; - RSP_3 = *ATSMB2_RSP_3; - RSP_4 = *ATSMB2_RSP_4; - RSP_5 = *ATSMB2_RSP_5; - RSP_6 = *ATSMB2_RSP_6; - RSP_7 = *ATSMB2_RSP_7; - RSP_8 = *ATSMB2_RSP_8; - RSP_9 = *ATSMB2_RSP_9; - RSP_10 = *ATSMB2_RSP_10; - RSP_11 = *ATSMB2_RSP_11; - RSP_12 = *ATSMB2_RSP_12; - RSP_13 = *ATSMB2_RSP_13; - RSP_14 = *ATSMB2_RSP_14; - RSP_15 = *ATSMB2_RSP_15; - CURBLK_CNT = *ATSMB2_CURBLK_CNT; - INT_MASK_0 = *ATSMB2_INT_MASK_0; - INT_MASK_1 = *ATSMB2_INT_MASK_1; - SD_STS_0 = *ATSMB2_SD_STS_0; - SD_STS_1 = *ATSMB2_SD_STS_1; - SD_STS_2 = *ATSMB2_SD_STS_2; - SD_STS_3 = *ATSMB2_SD_STS_3; - RSP_TOUT = *ATSMB2_RSP_TOUT; - CLK_SEL = *ATSMB2_CLK_SEL; - EXT_CTL = *ATSMB2_EXT_CTL; - EXT_CTL_1 = *ATSMB2_EXT_CTL_1; - EXT_CTL_2 = *ATSMB2_EXT_CTL_2; - SHDW_BLKLEN = *ATSMB2_SHDW_BLKLEN; - MAN_TUNE_VAL = *ATSMB2_MAN_TUNE_VAL; - SD_WRI_TUNE = *ATSMB2_SD_WRI_TUNE; - TIMER_VAL = *ATSMB2_TIMER_VAL; - - PDMA_GCR = *ATSMB2_PDMA_GCR; - PDMA_IER = *ATSMB2_PDMA_IER; - PDMA_ISR = *ATSMB2_PDMA_ISR; - PDMA_DESPR = *ATSMB2_PDMA_DESPR; - PDMA_RBR = *ATSMB2_PDMA_RBR; - PDMA_DAR = *ATSMB2_PDMA_DAR; - PDMA_BAR = *ATSMB2_PDMA_BAR; - PDMA_CPR = *ATSMB2_PDMA_CPR; - PDMA_CCR = *ATSMB2_PDMA_CCR; - - DBGR("\n+---------------------------Registers----------------------------+\n"); - - DBGR("%16s = 0x%8x |", "CTL", CTL); - DBGR("%16s = 0x%8x\n", "CMD_IDX", CMD_IDX); - - DBGR("%16s = 0x%8x |", "RSP_TYPE", RSP_TYPE); - DBGR("%16s = 0x%8x\n", "CMD_ARG", CMD_ARG); - - DBGR("%16s = 0x%8x |", "BUS_MODE", BUS_MODE); - DBGR("%16s = 0x%8x\n", "EXT_BUS_MODE", EXT_BUS_MODE); - - DBGR("%16s = 0x%8x |", "CTL2", CTL2); - DBGR("%16s = 0x%8x\n", "BLK_LEN", BLK_LEN); - - DBGR("%16s = 0x%8x |", "BLK_CNT", BLK_CNT); - DBGR("%16s = 0x%8x\n", "RSP_0", RSP_0); - - DBGR("%16s = 0x%8x |", "RSP_1", RSP_1); - DBGR("%16s = 0x%8x\n", "RSP_2", RSP_2); - - DBGR("%16s = 0x%8x |", "RSP_3", RSP_3); - DBGR("%16s = 0x%8x\n", "RSP_4", RSP_4); - - DBGR("%16s = 0x%8x |", "RSP_5", RSP_5); - DBGR("%16s = 0x%8x\n", "RSP_6", RSP_6); - - DBGR("%16s = 0x%8x |", "RSP_7", RSP_7); - DBGR("%16s = 0x%8x\n", "RSP_8", RSP_8); - - DBGR("%16s = 0x%8x |", "RSP_9", RSP_9); - DBGR("%16s = 0x%8x\n", "RSP_10", RSP_10); - - DBGR("%16s = 0x%8x |", "RSP_11", RSP_11); - DBGR("%16s = 0x%8x\n", "RSP_12", RSP_12); - - DBGR("%16s = 0x%8x |", "RSP_13", RSP_13); - DBGR("%16s = 0x%8x\n", "RSP_14", RSP_14); - - DBGR("%16s = 0x%8x\n", "RSP_15", RSP_15); - - DBGR("%16s = 0x%8x |", "CURBLK_CNT", CURBLK_CNT); - DBGR("%16s = 0x%8x\n", "INT_MASK_0", INT_MASK_0); - - DBGR("%16s = 0x%8x |", "INT_MASK_1", INT_MASK_1); - DBGR("%16s = 0x%8x\n", "SD_STS_0", SD_STS_0); - - DBGR("%16s = 0x%8x |", "SD_STS_1", SD_STS_1); - DBGR("%16s = 0x%8x\n", "SD_STS_2", SD_STS_2); - - DBGR("%16s = 0x%8x |", "SD_STS_3", SD_STS_3); - DBGR("%16s = 0x%8x\n", "RSP_TOUT", RSP_TOUT); - - DBGR("%16s = 0x%8x |", "CLK_SEL", CLK_SEL); - DBGR("%16s = 0x%8x\n", "EXT_CTL", EXT_CTL); - - DBGR("%16s = 0x%8x |", "EXT_CTL_1", EXT_CTL_1); - DBGR("%16s = 0x%8x\n", "EXT_CTL_2", EXT_CTL_2); - - DBGR("%16s = 0x%8x |", "SHDW_BLKLEN", SHDW_BLKLEN); - DBGR("%16s = 0x%8x\n", "MAN_TUNE_VAL", MAN_TUNE_VAL); - - DBGR("%16s = 0x%8x |", "SD_WRI_TUNE", SD_WRI_TUNE); - DBGR("%16s = 0x%8x\n", "TIMER_VAL", TIMER_VAL); - - DBGR("%16s = 0x%8x |", "PDMA_GCR", PDMA_GCR); - DBGR("%16s = 0x%8x\n", "PDMA_IER", PDMA_IER); - - DBGR("%16s = 0x%8x |", "PDMA_ISR", PDMA_ISR); - DBGR("%16s = 0x%8x\n", "PDMA_DESPR", PDMA_DESPR); - - DBGR("%16s = 0x%8x |", "PDMA_RBR", PDMA_RBR); - DBGR("%16s = 0x%8x\n", "PDMA_DAR", PDMA_DAR); - - DBGR("%16s = 0x%8x |", "PDMA_BAR", PDMA_BAR); - DBGR("%16s = 0x%8x\n", "PDMA_CPR", PDMA_CPR); - - DBGR("%16s = 0x%8x |", "PDMA_CCR", PDMA_CCR); - DBGR("\n+----------------------------------------------------------------+\n"); -} -#else -void atsmb2_dump_reg(struct atsmb_host *host) {} -#endif - -unsigned int fmax2 = 515633; -unsigned int MMC2_DRIVER_VERSION; -int SD2_function = 0; /*0: normal SD/MMC card reader , 1: internal SDIO wifi*/ -int SDXC2_function; - -int SCC2_ID(void){ - unsigned short val; - - val = REG16_VAL(SYSTEM_CFG_CTRL_BASE_ADDR + 0x2); - return val; -} - -int get_chip_version2(void) /*2008/05/01 janshiue modify for A1 chip*/ -{ - u32 tmp; - - tmp = REG32_VAL(SYSTEM_CFG_CTRL_BASE_ADDR); - tmp = ((tmp & 0xF00) >> 4) + 0x90 + ((tmp & 0xFF) - 1); - return tmp; -} - -void get_driver_version2(void) -{ - if (SCC2_ID() == 0x3426) { - if (get_chip_version2() < 0xA1) - MMC2_DRIVER_VERSION = MMC_DRV_3426_A0; - else if (get_chip_version2() == 0xA1) - MMC2_DRIVER_VERSION = MMC_DRV_3426_A1; - else - MMC2_DRIVER_VERSION = MMC_DRV_3426_A2; - } else if (SCC2_ID() == 0x3437) { - if (get_chip_version2() < 0xA1) - MMC2_DRIVER_VERSION = MMC_DRV_3437_A0; - else - MMC2_DRIVER_VERSION = MMC_DRV_3437_A1; - } else if (SCC2_ID() == 0x3429) { - MMC2_DRIVER_VERSION = MMC_DRV_3429; - } else if (SCC2_ID() == 0x3451) { - if (get_chip_version2() < 0xA1) - MMC2_DRIVER_VERSION = MMC_DRV_3451_A0; - } else if (SCC2_ID() == 0x3465) { - MMC2_DRIVER_VERSION = MMC_DRV_3465; - } else if (SCC2_ID() == 0x3445) { - MMC2_DRIVER_VERSION = MMC_DRV_3445; - } else if (SCC2_ID() == 0x3481) { - MMC2_DRIVER_VERSION = MMC_DRV_3481; - } else if (SCC2_ID() == 0x3498) { - MMC2_DRIVER_VERSION = MMC_DRV_3498; - } -} -/*2008/10/6 RichardHsu-e*/ - -/********************************************************************** -Name : atsmb2_alloc_desc -Function : To config PDMA descriptor setting. -Calls : -Called by : -Parameter : -Author : Janshiue Wu -History : -***********************************************************************/ -static inline int atsmb2_alloc_desc(struct atsmb_host *host, - unsigned int bytes) -{ - void *DescPool = NULL; - DBG("[%s] s\n",__func__); - - DescPool = dma_alloc_coherent(host->mmc->parent, bytes, &(host->DescPhyAddr), GFP_KERNEL); - if (!DescPool) { - DBG("can't allocal desc pool=%8X %8X\n", DescPool, host->DescPhyAddr); - DBG("[%s] e1\n",__func__); - return -1; - } - DBG("allocal desc pool=%8X %8X\n", DescPool, host->DescPhyAddr); - host->DescVirAddr = (unsigned long *)DescPool; - host->DescSize = bytes; - DBG("[%s] e2\n",__func__); - return 0; -} - -/********************************************************************** -Name : atsmb2_config_desc -Function : To config PDMA descriptor setting. -Calls : -Called by : -Parameter : -Author : Janshiue Wu -History : -***********************************************************************/ -static inline void atsmb2_config_desc(unsigned long *DescAddr, - unsigned long *BufferAddr, - unsigned long Blk_Cnt) -{ - - int i = 0 ; - unsigned long *CurDes = DescAddr; - DBG("[%s] s\n",__func__); - - /* the first Descriptor store for 1 Block data - * (512 bytes) - */ - for (i = 0 ; i < 3 ; i++) { - atsmb2_init_short_desc(CurDes, 0x80, BufferAddr, 0); - BufferAddr += 0x20; - CurDes += sizeof(struct SD_PDMA_DESC_S)/4; - } - if (Blk_Cnt > 1) { - atsmb2_init_long_desc(CurDes, 0x80, BufferAddr, CurDes + (sizeof(struct SD_PDMA_DESC_L)/4), 0); - BufferAddr += 0x20; - CurDes += sizeof(struct SD_PDMA_DESC_L)/4; - /* the following Descriptor store the rest Blocks data - * (Blk_Cnt - 1) * 512 bytes - */ - atsmb2_init_long_desc(CurDes, (Blk_Cnt - 1) * 512, - BufferAddr, CurDes + (sizeof(struct SD_PDMA_DESC_L)/4), 1); - } else { - atsmb2_init_long_desc(CurDes, 0x80, BufferAddr, CurDes + (sizeof(struct SD_PDMA_DESC_L)/4), 1); - } - DBG("[%s] e\n",__func__); -} -/********************************************************************** -Name : atsmb2_config_dma -Function : To set des/src address, byte count to transfer, and DMA channel settings, - and DMA ctrl. register. -Calls : -Called by : -Parameter : -Author : Leo Lee -History : -***********************************************************************/ -static inline void atsmb2_config_dma(unsigned long config_dir, - unsigned long dma_mask, - struct atsmb_host *host) -{ - - DBG("[%s] s\n",__func__); - /* Enable DMA */ - *ATSMB2_PDMA_GCR = SD_PDMA_GCR_DMA_EN; - *ATSMB2_PDMA_GCR = SD_PDMA_GCR_SOFTRESET; - *ATSMB2_PDMA_GCR = SD_PDMA_GCR_DMA_EN; - /*open interrupt*/ - *ATSMB2_PDMA_IER = SD_PDMA_IER_INT_EN; - /*Make sure host could co-work with DMA*/ - *ATSMB2_SD_STS_2 |= ATSMB_CLK_FREEZ_EN; - - /*Set timer timeout value*/ - /*If clock is 390KHz*/ - if (host->current_clock < 400000) - *ATSMB2_TIMER_VAL = 0x200; /*1024*512*(1/390K) second*/ - else - *ATSMB2_TIMER_VAL = 0x1fff; /*why not to be 0xffff?*/ - - /*clear all DMA INT status for safety*/ - *ATSMB2_PDMA_ISR |= SD_PDMA_IER_INT_STS; - - /* hook desc */ - *ATSMB2_PDMA_DESPR = host->DescPhyAddr; - if (config_dir == DMA_CFG_WRITE) - *ATSMB2_PDMA_CCR &= SD_PDMA_CCR_IF_to_peripheral; - else - *ATSMB2_PDMA_CCR |= SD_PDMA_CCR_peripheral_to_IF; - - host->DmaIntMask = dma_mask; /*save success event*/ - - *ATSMB2_PDMA_CCR |= SD_PDMA_CCR_RUN; - DBG("[%s] e\n",__func__); -} - -/********************************************************************** -Name : atsmb2_prep_cmd -Function : -Calls : -Called by : -Parameter : -Author : Leo Lee -History : -***********************************************************************/ -static inline void atsmb2_prep_cmd(struct atsmb_host *host, - u32 opcode, - u32 arg, - unsigned int flags, - u16 blk_len, - u16 blk_cnt, - unsigned char int_maks_0, - unsigned char int_mask_1, - unsigned char cmd_type, - unsigned char op) -{ - unsigned long spl_flags; /* add by th */ - DBG("[%s] s\n",__func__); - - /*set cmd operation code and arguments.*/ - host->opcode = opcode; - *ATSMB2_CMD_IDX = opcode; /* host->opcode is set for further use in ISR.*/ - *ATSMB2_CMD_ARG = arg; - -#if 0 /* Fixme to support SPI mode, James Tian*/ - if ((flags && MMC_RSP_NONE) == MMC_RSP_NONE) - *ATSMB2_RSP_TYPE = ATMSB_TYPE_R0; - else if ((flags && MMC_RSP_R1) == MMC_RSP_R1) - *ATSMB2_RSP_TYPE = ATMSB_TYPE_R1; - else if ((flags && MMC_RSP_R1B) == MMC_RSP_R1B) - *ATSMB2_RSP_TYPE = ATMSB_TYPE_R1b; - else if ((flags && MMC_RSP_R2) == MMC_RSP_R2) - *ATSMB2_RSP_TYPE = ATMSB_TYPE_R2; - else if ((flags && MMC_RSP_R3) == MMC_RSP_R3) - *ATSMB2_RSP_TYPE = ATMSB_TYPE_R3; - else if ((flags && MMC_RSP_R6) == MMC_RSP_R6) - *ATSMB2_RSP_TYPE = ((opcode != SD_SEND_IF_COND) ? ATMSB_TYPE_R6 : ATMSB_TYPE_R7); - else - *ATSMB2_RSP_TYPE = ATMSB_TYPE_R0; -#endif - -#if 1 - /*set cmd response type*/ - switch (flags) { - case MMC_RSP_NONE | MMC_CMD_AC: - case MMC_RSP_NONE | MMC_CMD_BC: - *ATSMB2_RSP_TYPE = ATMSB_TYPE_R0; - break; - case MMC_RSP_R1 | MMC_CMD_ADTC: - case MMC_RSP_R1 | MMC_CMD_AC: - *ATSMB2_RSP_TYPE = ATMSB_TYPE_R1; - break; - case MMC_RSP_R1B | MMC_CMD_AC: - *ATSMB2_RSP_TYPE = ATMSB_TYPE_R1b; - break; - case MMC_RSP_R2 | MMC_CMD_BCR: - case MMC_RSP_R2 | MMC_CMD_AC: - *ATSMB2_RSP_TYPE = ATMSB_TYPE_R2; - break; - case MMC_RSP_R3 | MMC_CMD_BCR: - *ATSMB2_RSP_TYPE = ATMSB_TYPE_R3; - break; - case MMC_RSP_R6 | MMC_CMD_BCR: /*MMC_RSP_R6 = MMC_RSP_R7.*/ - *ATSMB2_RSP_TYPE = ((opcode != SD_SEND_IF_COND) ? - ATMSB_TYPE_R6 : ATMSB_TYPE_R7); - break; - case MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_AC: - case MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_ADTC: - *ATSMB2_RSP_TYPE = ATMSB_TYPE_R5; - break; - case MMC_RSP_SPI_R4 | MMC_RSP_R4 | MMC_CMD_BCR: - *ATSMB2_RSP_TYPE = ATMSB_TYPE_R4; - break; - default: - *ATSMB2_RSP_TYPE = ATMSB_TYPE_R0; - break; - } -#endif - /*SDIO cmd 52 , 53*/ - if ((opcode == SD_IO_RW_DIRECT) || - (opcode == SD_IO_RW_EXTENDED)) { - *ATSMB2_RSP_TYPE = ATMSB_TYPE_R5; - *ATSMB2_RSP_TYPE |= BIT6; - } - /*SDIO cmd 5*/ - if ((opcode == SD_IO_SEND_OP_COND) && - ((flags & (MMC_RSP_PRESENT| - MMC_RSP_136| - MMC_RSP_CRC| - MMC_RSP_BUSY| - MMC_RSP_OPCODE)) == MMC_RSP_R4)) { - *ATSMB2_RSP_TYPE = ATMSB_TYPE_R4; - *ATSMB2_RSP_TYPE |= BIT6; - } - - /*reset Response FIFO*/ - *ATSMB2_CTL |= 0x08; - - /* SD Host enable Clock */ - *ATSMB2_BUS_MODE |= ATSMB_CST; - - /*Set Cmd-Rsp Timeout to be maximum value.*/ - *ATSMB2_RSP_TOUT = 0xFE; - - /*clear all status registers for safety*/ - *ATSMB2_SD_STS_0 |= 0xff; - *ATSMB2_SD_STS_1 |= 0xff; - *ATSMB2_SD_STS_2 |= 0xff; - //*ATSMB2_SD_STS_2 |= 0x7f; - *ATSMB2_SD_STS_3 |= 0xff; - - //set block length and block count for cmd requesting data - *ATSMB2_BLK_LEN &=~(0x07ff); - *ATSMB2_BLK_LEN |= blk_len; - //*ATSMB2_SHDW_BLKLEN = blk_len; - *ATSMB2_BLK_CNT = blk_cnt; - - - *ATSMB2_INT_MASK_0 |= int_maks_0; - - /* spin_lock add by th for fix sdio irq*/ - spin_lock_irqsave(&host->lock, spl_flags); - *ATSMB2_INT_MASK_1 |= int_mask_1; - spin_unlock_irqrestore(&host->lock, spl_flags); - - //Set Auto stop for Multi-block access - if(cmd_type == 3 || cmd_type == 4) - { - //auto stop command set. - *ATSMB2_EXT_CTL |= 0x01; - -/* - * Enable transaction abort. - * When CRC error occurs, CMD 12 would be automatically issued. - * That is why we cannot enable R/W CRC error INTs. - * If we enable CRC error INT, we would handle this INT in ISR and then issue CMD 12 via software. - */ - *ATSMB2_BLK_LEN |= 0x0800; - } - - /*Set read or write*/ - if (op == 1) - *ATSMB2_CTL &= ~(0x04); - else if (op == 2) - *ATSMB2_CTL |= 0x04; - - /*for Non data access command, command type is 0.*/ - *ATSMB2_CTL &= 0x0F; - *ATSMB2_CTL |= (cmd_type<<4); - DBG("[%s] e\n",__func__); -} - -static inline void atsmb2_issue_cmd(void) -{ - *ATSMB2_CTL |= ATSMB_START; - wmb(); -} -/********************************************************************** -Name : atsmb2_request_end -Function :. -Calls : -Called by : -Parameter : -Author : Leo Lee -History : -***********************************************************************/ -static void -atsmb2_request_end(struct atsmb_host *host, struct mmc_request *mrq) -{ - DBG("[%s] s\n",__func__); - /* - * Need to drop the host lock here; mmc_request_done may call - * back into the driver... - */ - //kevin delete spin lock - //spin_unlock(&host->lock); - /*DBG("100");*/ - mmc_request_done(host->mmc, mrq); - /*DBG("101\n");*/ - //spin_lock(&host->lock); - DBG("[%s] e\n",__func__); -} - -/********************************************************************** -Name : atsmb2_data_done -Function : -Calls : -Called by : -Parameter : -Author : Leo Lee -History : -***********************************************************************/ -void atsmb2_wait_done(void *data) -{ - struct atsmb_host *host = (struct atsmb_host *) data; - DBG("[%s] s\n",__func__); - - WARN_ON(host->done_data == NULL); - complete(host->done_data); - host->done_data = NULL; - host->done = NULL; - DBG("[%s] e\n",__func__); -} - -/********************************************************************** -wait_data_busy -waiting for previous data transfer done -**********************************************************************/ -void wait_data_busy(struct mmc_command *cmd) -{ - int wait_count = 500000; - - switch(cmd->opcode) { - case MMC_GO_IDLE_STATE: - case MMC_STOP_TRANSMISSION: - case MMC_SEND_STATUS: - case MMC_GO_INACTIVE_STATE: - break; - default: - do { - if (*ATSMB2_CURBLK_CNT & (0x01<<24)) - break; - - udelay(1); - - } while (--wait_count); - } - -} -/********************************************************************** -Name : atsmb2_start_data -Function : If we start data, there must be only four cases. -Calls : -Called by : -Parameter : -Author : Leo Lee -History : -***********************************************************************/ -static void atsmb2_start_data(struct atsmb_host *host) -{ - DECLARE_COMPLETION(complete); - unsigned char cmd_type = 0; - unsigned char op = 0; /*0: non-operation; 1:read; 2: write*/ - unsigned char mask_0 = 0; - unsigned char mask_1 = 0; - unsigned long dma_mask = 0; - - struct mmc_data *data = host->data; - struct mmc_command *cmd = host->cmd; - - struct scatterlist *sg = NULL; - unsigned int sg_len = 0; - - unsigned int total_blks = 0; /*total block number to transfer*/ - u32 card_addr = 0; - unsigned long dma_len = 0; - unsigned long total_dma_len = 0; - dma_addr_t dma_phy = 0; /* physical address used for DMA*/ - unsigned int dma_times = 0; /*times dma need to transfer*/ - unsigned int dma_loop = 0; - unsigned int sg_num = 0; - int loop_cnt = 10000; - unsigned int sg_transfer_len = 0; /*record each time dma transfer sg length */ - - DBG("[%s] s\n",__func__); - data->bytes_xfered = 0; - cmd->error = 0; - data->error = 0; - - /*for loop*/ - sg = data->sg; - sg_len = data->sg_len; - - dma_times = (sg_len / MAX_DESC_NUM); - if (sg_len % MAX_DESC_NUM) - dma_times++; - DBG("dma_times = %d sg_len = %d sg = %x\n", dma_times, sg_len, sg); - card_addr = cmd->arg; /*may be it is block-addressed, or byte-addressed.*/ - total_blks = data->blocks; - dma_map_sg(&(host->mmc->class_dev), sg, sg_len, - ((data->flags)&MMC_DATA_READ) ? DMA_FROM_DEVICE : DMA_TO_DEVICE); - - - for (dma_loop = 1 ; dma_loop <= dma_times; dma_loop++, sg_len -= sg_transfer_len) { - DBG("dma_loop = %d sg_len = %d sg_transfer_len = %d\n", dma_loop, sg_len, sg_transfer_len); - if (dma_loop < dma_times) - sg_transfer_len = MAX_DESC_NUM; - else - sg_transfer_len = sg_len; - DBG("sg_transfer_len = %d\n", sg_transfer_len); - /* - *Firstly, check and wait till card is in the transfer state. - *For our hardware, we can not consider - *the card has successfully tranfered its state from data/rcv to trans, - *when auto stop INT occurs. - */ - loop_cnt = 10000; - do { - if (host->cmd->opcode == SD_IO_RW_EXTENDED) - break; - loop_cnt--; - WARN_ON(loop_cnt == 0); - host->done_data = &complete; - host->done = &atsmb2_wait_done; - host->soft_timeout = 1; - atsmb2_prep_cmd(host, - MMC_SEND_STATUS, - (host->mmc->card->rca)<<16, - MMC_RSP_R1 | MMC_CMD_AC, - 0, - 0, - 0, /*mask_0*/ - ATSMB_RSP_DONE_EN - |ATSMB_RSP_CRC_ERR_EN - |ATSMB_RSP_TIMEOUT_EN, - 0, /*cmd type*/ - 0); /*read or write*/ - atsmb2_issue_cmd(); - DBG("%16s = 0x%8x |", "INT_MASK_1", *ATSMB2_INT_MASK_1); - DBG("%16s = 0x%8x \n", "SD_STS_1", *ATSMB2_SD_STS_1); - /*ISR would completes it.*/ - wait_for_completion_timeout(&complete, ATSMB_TIMEOUT_TIME); - - WARN_ON(host->soft_timeout == 1); - if (host->soft_timeout == 1) { - DBG("%s soft_timeout.\n", __func__); - atsmb2_dump_reg(host); - } - if (cmd->error != MMC_ERR_NONE) { - cmd->error = -EIO; //MMC_ERR_FAILED; - DBG("Getting Status failed.\n"); - goto end; - } - } while ((cmd->resp[0] & 0x1f00) != 0x900 && loop_cnt > 0); /*wait for trans state.*/ - - /* - * Now, we can safely issue read/write command. - * We can not consider this request as multi-block acess or single one via opcode, - * as request is splitted into sgs. - * Some sgs may be single one, some sgs may be multi one. - */ - - dma_phy = sg_dma_address(sg); - dma_len = sg_dma_len(sg); - DBG("dma_len = %d data->blksz = %d sg_len = %d\n", dma_len, data->blksz, sg_len); - /*SDIO read/write*/ - if (host->cmd->opcode == SD_IO_RW_EXTENDED) { - /*Single Block read/write*/ - if ((dma_len / (data->blksz)) == 1 && (sg_len == 1)) { - /* read operation*/ - if (data->flags & MMC_DATA_READ) { - host->opcode = SD_IO_RW_EXTENDED; - cmd_type = 2; - op = 1; - mask_0 = 0; /*BLOCK_XFER_DONE INT skipped, we use DMA TC INT*/ - mask_1 = (//ATSMB_SDIO_EN - ATSMB_READ_CRC_ERR_EN - |ATSMB_DATA_TIMEOUT_EN - /*Data Timeout and CRC error */ - |ATSMB_RSP_CRC_ERR_EN - |ATSMB_RSP_TIMEOUT_EN); - /*Resp Timeout and CRC error */ - dma_mask = SD_PDMA_CCR_Evt_success; - DBG("[%s]SR opcode = %d type = 0x%x op = 0x%x m_0 = 0x%x m_1 = 0x%x d_m = 0x%x\n", - __func__,host->opcode,cmd_type,op,mask_0,mask_1,dma_mask); - } else { - /* write operation*/ - host->opcode = SD_IO_RW_EXTENDED; - cmd_type = 1; - op = 2; - /*====That is what we want===== DMA TC INT skipped*/ - mask_0 = ATSMB_BLOCK_XFER_DONE_EN; - mask_1 = (//ATSMB_SDIO_EN - ATSMB_WRITE_CRC_ERR_EN - |ATSMB_DATA_TIMEOUT_EN - /*Data Timeout and CRC error */ - |ATSMB_RSP_CRC_ERR_EN - |ATSMB_RSP_TIMEOUT_EN); - /*Resp Timeout and CRC error */ - dma_mask = 0; - DBG("[%s]SW opcode = %d type = 0x%x op = 0x%x m_0 = 0x%x m_1 = 0x%x d_m = 0x%x\n", - __func__,host->opcode,cmd_type,op,mask_0,mask_1,dma_mask); - } - } else { - /*Multiple Block read/write*/ - /* read operation*/ - if (data->flags & MMC_DATA_READ) { - host->opcode = SD_IO_RW_EXTENDED; - cmd_type = 6; - op = 1; - mask_0 = 0; /*MULTI_XFER_DONE_EN skipped*/ - mask_1 = (//ATSMB_SDIO_EN /*====That is what we want=====*/ - ATSMB_READ_CRC_ERR_EN - |ATSMB_DATA_TIMEOUT_EN - /*Data Timeout and CRC error */ - |ATSMB_RSP_CRC_ERR_EN - |ATSMB_RSP_TIMEOUT_EN); - /*Resp Timeout and CRC error */ - dma_mask = SD_PDMA_CCR_Evt_success; - DBG("[%s]MR opcode = %d type = 0x%x op = 0x%x m_0 = 0x%x m_1 = 0x%x d_m = 0x%x\n", - __func__,host->opcode,cmd_type,op,mask_0,mask_1,dma_mask); - } else { - /* write operation*/ - host->opcode = SD_IO_RW_EXTENDED; - cmd_type = 5; - op = 2; - mask_0 = ATSMB_MULTI_XFER_DONE_EN;//ATSMB_BLOCK_XFER_DONE_EN; /*MULTI_XFER_DONE INT skipped*/ - mask_1 = (//ATSMB_SDIO_EN /*====That is what we want=====*/ - ATSMB_WRITE_CRC_ERR_EN - |ATSMB_DATA_TIMEOUT_EN - /*Data Timeout and CRC error */ - |ATSMB_RSP_CRC_ERR_EN - |ATSMB_RSP_TIMEOUT_EN); - /*Resp Timeout and CRC error */ - dma_mask = 0; - DBG("[%s]MR opcode = %d type = 0x%x op = 0x%x m_0 = 0x%x m_1 = 0x%x d_m = 0x%x\n", - __func__,host->opcode,cmd_type,op,mask_0,mask_1,dma_mask); - } - } - - } else { - if ((dma_len / (data->blksz)) == 1 && (sg_len == 1)) { - if (data->flags & MMC_DATA_READ) {/* read operation*/ - host->opcode = MMC_READ_SINGLE_BLOCK; - cmd_type = 2; - op = 1; - mask_0 = 0; /*BLOCK_XFER_DONE INT skipped, we use DMA TC INT*/ - mask_1 = (ATSMB_READ_CRC_ERR_EN - |ATSMB_DATA_TIMEOUT_EN - /*Data Timeout and CRC error */ - |ATSMB_RSP_CRC_ERR_EN - |ATSMB_RSP_TIMEOUT_EN); - /*Resp Timeout and CRC error */ - dma_mask = SD_PDMA_CCR_Evt_success; - } else {/*write operation*/ - host->opcode = MMC_WRITE_BLOCK; - cmd_type = 1; - op = 2; - /*====That is what we want===== DMA TC INT skipped*/ - mask_0 = ATSMB_BLOCK_XFER_DONE_EN; - mask_1 = (ATSMB_WRITE_CRC_ERR_EN - |ATSMB_DATA_TIMEOUT_EN - /*Data Timeout and CRC error */ - |ATSMB_RSP_CRC_ERR_EN - |ATSMB_RSP_TIMEOUT_EN); - /*Resp Timeout and CRC error */ - dma_mask = 0; - } - } else { /*more than one*/ - if (data->flags&MMC_DATA_READ) {/* read operation*/ - host->opcode = MMC_READ_MULTIPLE_BLOCK; - cmd_type = 4; - op = 1; - mask_0 = 0; /*MULTI_XFER_DONE_EN skipped*/ - mask_1 = (ATSMB_AUTO_STOP_EN /*====That is what we want=====*/ - |ATSMB_DATA_TIMEOUT_EN - /*Data Timeout and CRC error */ - |ATSMB_RSP_CRC_ERR_EN - |ATSMB_RSP_TIMEOUT_EN); - /*Resp Timeout and CRC error */ - dma_mask = 0; - } else {/*write operation*/ - host->opcode = MMC_WRITE_MULTIPLE_BLOCK; - cmd_type = 3; - op = 2; - mask_0 = 0; /*MULTI_XFER_DONE INT skipped*/ - mask_1 = (ATSMB_AUTO_STOP_EN /*====That is what we want=====*/ - |ATSMB_DATA_TIMEOUT_EN - /*Data Timeout and CRC error */ - |ATSMB_RSP_CRC_ERR_EN - |ATSMB_RSP_TIMEOUT_EN); - /*Resp Timeout and CRC error */ - dma_mask = 0; - } - } - } - /*To controller every sg done*/ - host->done_data = &complete; - host->done = &atsmb2_wait_done; - /*sleep till ISR wakes us*/ - host->soft_timeout = 1; /*If INT comes early than software timer, it would be cleared.*/ - - total_dma_len = 0; - DBG("host->DescVirAddr = %x host->DescSize=%x\n", host->DescVirAddr, host->DescSize); - memset(host->DescVirAddr, 0, host->DescSize); - for (sg_num = 0 ; sg_num < sg_transfer_len ; sg++, sg_num++) { - - /* - * Now, we can safely issue read/write command. - * We can not consider this request as multi-block acess or single one via opcode, - * as request is splitted into sgs. - * Some sgs may be single one, some sgs may be multi one. - */ - - dma_phy = sg_dma_address(sg); - dma_len = sg_dma_len(sg); - total_dma_len = total_dma_len + dma_len; - DBG("sg_num=%d sg_transfer_len=%d sg=%x sg_len=%d total_dma_len=%d dma_len=%d\n", - sg_num, sg_transfer_len, sg, sg_len, total_dma_len, dma_len); - /*2009/01/15 janshiue add*/ - if (sg_num < sg_transfer_len - 1) { - /* means the last descporitor */ - atsmb2_init_short_desc( - host->DescVirAddr + (sg_num * sizeof(struct SD_PDMA_DESC_S)/4), - dma_len, (unsigned long *)dma_phy, 0); - } else { - atsmb2_init_short_desc( - host->DescVirAddr + (sg_num * sizeof(struct SD_PDMA_DESC_S)/4), - dma_len, (unsigned long *)dma_phy, 1); - } - /*2009/01/15 janshiue add*/ - - } - /*operate our hardware*/ - atsmb2_prep_cmd(host, - host->opcode, - /*arg, may be byte addressed, may be block addressed.*/ - card_addr, - cmd->flags, - data->blksz - 1, /* in fact, it is useless.*/ - /* for single one, it is useless. but for multi one, */ - /* it would be used to tell auto stop function whether it is done.*/ - total_dma_len/(data->blksz), - mask_0, - mask_1, - cmd_type, - op); - - atsmb2_config_dma((op == 1) ? DMA_CFG_READ : DMA_CFG_WRITE, - dma_mask, - host); - - wait_data_busy(cmd); - //sync from tp,fix broadcom 6181 wifi dongle crash. - //udelay(10); - atsmb2_issue_cmd(); - wait_for_completion_timeout(&complete, - ATSMB_TIMEOUT_TIME*sg_transfer_len); /*ISR would completes it.*/ - - /* When the address of request plus length equal card bound, - * force this stop command response as pass. Eason 2012/4/20 */ - if (cmd->resp[0] == 0x80000b00) { - /*This caes used for SD2.0 and after MMC4.1 version*/ - if (card_addr+(total_dma_len/data->blksz) == host->mmc->card->csd.capacity) { - cmd->resp[0] = 0x00000b00; - /*printk("card_addr = %08X, card_length = %08X,card capacity = %08X\n", - card_addr,(total_dma_len/data->blksz),host->mmc->card->csd.capacity); - printk("card_resp[0]=%08X, addr = %08X\n",cmd->resp[0],cmd->resp);*/ - } - - /* This caes used for SD1.0 and before MMC 4.1 */ - if ((card_addr/data->blksz)+(total_dma_len/data->blksz) == host->mmc->card->csd.capacity) { - cmd->resp[0] = 0x00000b00; - /*printk("Eason test: cmd->arg = %08X, data->blksz = %08X, length = %08X\n", - card_addr,data->blksz,(total_dma_len/data->blksz));*/ - } - } - - if (host->soft_timeout == 1) { - atsmb2_dump_reg(host); - //*ATSMB2_BUS_MODE |= ATSMB_SFTRST; - *ATSMB2_PDMA_GCR = SD_PDMA_GCR_SOFTRESET; - /*disable INT */ - *ATSMB2_INT_MASK_0 &= ~(ATSMB_BLOCK_XFER_DONE_EN | ATSMB_MULTI_XFER_DONE_EN); - *ATSMB2_INT_MASK_1 &= ~(ATSMB_WRITE_CRC_ERR_EN|ATSMB_READ_CRC_ERR_EN|ATSMB_RSP_CRC_ERR_EN - |ATSMB_DATA_TIMEOUT_EN|ATSMB_AUTO_STOP_EN|ATSMB_RSP_TIMEOUT_EN|ATSMB_RSP_DONE_EN); - - cmd->error = -ETIMEDOUT; - data->error = -ETIMEDOUT; - } - - WARN_ON(host->soft_timeout == 1); - - /*check everything goes okay or not*/ - if (cmd->error != MMC_ERR_NONE - || data->error != MMC_ERR_NONE) { - DBG("CMD or Data failed error=%X DescVirAddr=%8X dma_phy=%8X dma_mask = %x\n", - cmd->error, host->DescVirAddr, dma_phy, host->DmaIntMask); - goto end; - } -// card_addr += total_dma_len>>(mmc_card_blockaddr(host->mmc->card_selected) ? 9 : 0); - card_addr += total_dma_len>>(mmc_card_blockaddr(host->mmc->card) ? 9 : 0); //zhf: modified by James Tian - data->bytes_xfered += total_dma_len; - - - } -// dma_unmap_sg(&(host->mmc->class_dev), data->sg, data->sg_len, -// ((data->flags)&MMC_DATA_READ) ? DMA_FROM_DEVICE : DMA_TO_DEVICE); - WARN_ON(total_blks != (data->bytes_xfered / data->blksz)); - host->opcode = 0; -end: - dma_unmap_sg(&(host->mmc->class_dev), data->sg, data->sg_len, - ((data->flags)&MMC_DATA_READ) ? DMA_FROM_DEVICE : DMA_TO_DEVICE); - //kevin delete spin lock - //spin_lock(&host->lock); - atsmb2_request_end(host, host->mrq); - //spin_unlock(&host->lock); - DBG("[%s] e\n",__func__); -} - - -/********************************************************************** -Name : atsmb2_cmd_with_data_back -Function : -Calls : -Called by : -Parameter : -Author : Leo Lee -History : -***********************************************************************/ -static void atsmb2_cmd_with_data_back(struct atsmb_host *host) -{ - DECLARE_COMPLETION(complete); - - struct scatterlist *sg = NULL; - unsigned int sg_len = 0; - DBG("[%s] s\n",__func__); - /*for loop*/ - sg = host->data->sg; - sg_len = host->data->sg_len; - /*To controller every sg done*/ - host->done_data = &complete; - host->done = &atsmb2_wait_done; - dma_map_sg(&(host->mmc->class_dev), sg, sg_len, DMA_FROM_DEVICE); - - /*2009/01/15 janshiue add*/ - memset(host->DescVirAddr, 0, host->DescSize); - atsmb2_init_long_desc(host->DescVirAddr, sg_dma_len(sg), (unsigned long *)sg_dma_address(sg), 0, 1); - /*2009/01/15 janshiue add*/ - /*prepare for cmd*/ - atsmb2_prep_cmd(host, /*host*/ - host->cmd->opcode, /*opcode*/ - host->cmd->arg, /*arg*/ - host->cmd->flags, /*flags*/ - sg_dma_len(sg)-1, /*block length*/ - 0, /*block size: It looks like useless*/ - 0, /*int_mask_0*/ - (ATSMB_RSP_CRC_ERR_EN|ATSMB_RSP_TIMEOUT_EN - |ATSMB_READ_CRC_ERR_EN |ATSMB_DATA_TIMEOUT_EN), /*int_mask_1*/ - 2, /*cmd_type*/ - 1); /*op*/ - - atsmb2_config_dma(DMA_CFG_READ, - SD_PDMA_CCR_Evt_success, - host); - atsmb2_issue_cmd(); - /*ISR would completes it.*/ - wait_for_completion_timeout(&complete, ATSMB_TIMEOUT_TIME); - - dma_unmap_sg(&(host->mmc->class_dev), host->data->sg, host->data->sg_len, - ((host->data->flags)&MMC_DATA_READ) ? DMA_FROM_DEVICE : DMA_TO_DEVICE); - spin_lock(&host->lock); - atsmb2_request_end(host, host->mrq); - spin_unlock(&host->lock); - DBG("[%s] e\n",__func__); -} -/********************************************************************** -Name : atsmb2_start_cmd -Function : -Calls : -Called by : -Parameter : -Author : Leo Lee -History : -***********************************************************************/ -static void atsmb2_start_cmd(struct atsmb_host *host) -{ - unsigned char int_mask_0,int_mask_1; - int_mask_0 = 0; - int_mask_1 = ATSMB_RSP_DONE_EN|ATSMB_RSP_CRC_ERR_EN|ATSMB_RSP_TIMEOUT_EN; - - DBG("[%s] s\n",__func__); - - atsmb2_prep_cmd(host, - host->cmd->opcode, - host->cmd->arg, - host->cmd->flags, - 0, /*useless*/ - 0, /*useless*/ - int_mask_0, /*mask_0*/ - int_mask_1, /*mask_1*/ - 0, /*cmd type*/ - 0); /*read or write*/ - atsmb2_issue_cmd(); - DBG("[%s] e\n",__func__); -} -/********************************************************************** -Name : atsmb2_fmt_check_rsp -Function : -Calls : -Called by : -Parameter : -Author : Leo Lee -History : -***********************************************************************/ -static inline void atsmb2_fmt_check_rsp(struct atsmb_host *host) -{ - - u8 tmp_resp[4] = {0}; - int i, j, k; - DBG("[%s] s\n",__func__); - if (host->cmd->flags != (MMC_RSP_R2 | MMC_CMD_AC) - && host->cmd->flags != (MMC_RSP_R2 | MMC_CMD_BCR)) { - for (j = 0, k = 1; j < 4; j++, k++) - tmp_resp[j] = *(REG8_PTR(_RSP_0 + MMC_ATSMB2_BASE+k)); - - host->cmd->resp[0] = (tmp_resp[0] << 24) | - (tmp_resp[1]<<16) | (tmp_resp[2]<<8) | (tmp_resp[3]); - } else { - for (i = 0, k = 1; i < 4; i++) { /*R2 has 4 u32 response.*/ - for (j = 0; j < 4; j++) { - if (k < 16) - tmp_resp[j] = *(REG8_PTR(_RSP_0 + MMC_ATSMB2_BASE+k)); - else /* k =16*/ - tmp_resp[j] = *(ATSMB2_RSP_0); - k++; - } - host->cmd->resp[i] = (tmp_resp[0]<<24) | (tmp_resp[1]<<16) | - (tmp_resp[2]<<8) | (tmp_resp[3]); - } - } - - /* - * For the situation that we need response, - * but response registers give us all zeros, we consider this operation timeout. - */ - if (host->cmd->flags != (MMC_RSP_NONE | MMC_CMD_AC) - && host->cmd->flags != (MMC_RSP_NONE | MMC_CMD_BC)) { - if (host->cmd->resp[0] == 0 && host->cmd->resp[1] == 0 - && host->cmd->resp[2] == 0 && host->cmd->resp[3] == 0) { - host->cmd->error = -ETIMEDOUT; //zhf: modified by James Tian - } - } - DBG("[%s] e\n",__func__); -} -/********************************************************************** -Name : atsmb2_get_slot_status -Function : Our host only supports one slot. -Calls : -Called by : -Parameter : -returns : 1: in slot; 0: not in slot. -Author : Leo Lee -History : -***********************************************************************/ -static int atsmb2_get_slot_status(struct mmc_host *mmc) -{ -// struct atsmb_host *host = mmc_priv(mmc); - unsigned char status_0 = 0; -// unsigned long flags; - unsigned long ret = 0; - DBG("[%s] s\n",__func__); -// spin_lock_irqsave(&host->lock, flags); // Vincent Li mark out for CONFIG_PREEMPT_RT - status_0 = *ATSMB2_SD_STS_0; -// spin_unlock_irqrestore(&host->lock, flags); // Vincent Li mark out for CONFIG_PREEMPT_RT - /* after WM3400 A1 ATSMB_CARD_IN_SLOT_GPI = 1 means not in slot*/ - if (MMC2_DRIVER_VERSION >= MMC_DRV_3426_A0) { - ret = ((status_0 & ATSMB_CARD_NOT_IN_SLOT_GPI) ? 0 : 1); - DBG("[%s] e1\n",__func__); - return ret; - } else { - ret = ((status_0 & ATSMB_CARD_NOT_IN_SLOT_GPI) ? 1 : 0); - DBG("[%s] e2\n",__func__); - return ret; - } - DBG("[%s] e3\n",__func__); - return 0; -} - -/********************************************************************** -Name : atsmb2_init_short_desc -Function : -Calls : -Called by : -Parameter : -Author : Janshiue Wu -History : -***********************************************************************/ -int atsmb2_init_short_desc(unsigned long *DescAddr, unsigned int ReqCount, unsigned long *BufferAddr, int End) -{ - struct SD_PDMA_DESC_S *CurDes_S; - DBG("[%s] s\n",__func__); - CurDes_S = (struct SD_PDMA_DESC_S *) DescAddr; - CurDes_S->ReqCount = ReqCount; - CurDes_S->i = 0; - CurDes_S->format = 0; - CurDes_S->DataBufferAddr = BufferAddr; - if (End) { - CurDes_S->end = 1; - CurDes_S->i = 1; - } - DBG("[%s] e\n",__func__); - return 0; -} - -/********************************************************************** -Name : atsmb2_init_long_desc -Function : -Calls : -Called by : -Parameter : -Author : Janshiue Wu -History : -***********************************************************************/ -int atsmb2_init_long_desc(unsigned long *DescAddr, unsigned int ReqCount, - unsigned long *BufferAddr, unsigned long *BranchAddr, int End) -{ - struct SD_PDMA_DESC_L *CurDes_L; - DBG("[%s] s\n",__func__); - CurDes_L = (struct SD_PDMA_DESC_L *) DescAddr; - CurDes_L->ReqCount = ReqCount; - CurDes_L->i = 0; - CurDes_L->format = 1; - CurDes_L->DataBufferAddr = BufferAddr; - CurDes_L->BranchAddr = BranchAddr; - if (End) { - CurDes_L->end = 1; - CurDes_L->i = 1; - } - DBG("[%s] e\n",__func__); - return 0; -} - -/********************************************************************** -Name : atsmb2_dma_isr -Function :. -Calls : -Called by : -Parameter : -Author : Leo Lee -History : -***********************************************************************/ -static irqreturn_t atsmb2_dma_isr(int irq, void *dev_id) -{ - - struct atsmb_host *host = dev_id; - u8 status_0, status_1, status_2, status_3; - u32 pdma_event_code = 0; - DBG("[%s] s\n",__func__); - - disable_irq_nosync(irq); - spin_lock(&host->lock); - /*Get INT status*/ - status_0 = *ATSMB2_SD_STS_0; - status_1 = *ATSMB2_SD_STS_1; - status_2 = *ATSMB2_SD_STS_2; - status_3 = *ATSMB2_SD_STS_3; - /* after WM3426 A0 using PDMA */ - if (MMC2_DRIVER_VERSION >= MMC_DRV_3426_A0) { - - pdma_event_code = *ATSMB2_PDMA_CCR & SD_PDMA_CCR_EvtCode; - - /* clear INT status to notify HW clear EventCode*/ - *ATSMB2_PDMA_ISR |= SD_PDMA_IER_INT_STS; - - /*printk("dma_isr event code = %X\n", *ATSMB2_PDMA_CCR);*/ - /*We expect cmd with data sending back or read single block cmd run here.*/ - if (pdma_event_code == SD_PDMA_CCR_Evt_success) { - /*means need to update the data->error and cmd->error*/ - if (host->DmaIntMask == SD_PDMA_CCR_Evt_success) { - if (host->data != NULL) { - host->data->error = MMC_ERR_NONE; - host->cmd->error = MMC_ERR_NONE; - } else { - DBG("dma_isr2 hodt->data is NULL\n"); - /*disable INT*/ - *ATSMB2_PDMA_IER &= ~SD_PDMA_IER_INT_EN; - goto out; - } - } - /*else do nothing*/ - DBG("dma_isr PDMA OK\n"); - /*atsmb2_dump_reg(host);*/ - } - /*But unluckily, we should also be prepare for all kinds of error situation.*/ - else { - host->data->error = -EIO; //MMC_ERR_FAILED; - host->cmd->error = -EIO; //MMC_ERR_FAILED; - DBGR("** dma_isr PDMA fail** event code = %X\n", *ATSMB2_PDMA_CCR); - atsmb2_dump_reg(host); - } - - if (host->DmaIntMask == SD_PDMA_CCR_Evt_success) - atsmb2_fmt_check_rsp(host); - - /*disable INT*/ - *ATSMB2_PDMA_IER &= ~SD_PDMA_IER_INT_EN; - } - - /*wake up some one who is sleeping.*/ - if ((pdma_event_code != SD_PDMA_CCR_Evt_success) || (host->DmaIntMask == SD_PDMA_CCR_Evt_success)) { - if (host->done_data) {/* We only use done_data when requesting data.*/ - host->soft_timeout = 0; - host->done(host); - } else - atsmb2_request_end(host, host->mrq); /*for cmd with data sending back.*/ - } - -out: - spin_unlock(&host->lock); - enable_irq(irq); - DBG("[%s] e\n",__func__); - return IRQ_HANDLED; -} - -/* add by th for ack interrupt */ -void eagle_ack_interrupt(void) -{ - *ATSMB2_SD_STS_1 |= ATSMB_SDIO_INT; -} -EXPORT_SYMBOL(eagle_ack_interrupt); - -/********************************************************************** -Name : atsmb2_regular_isr -Function :. -Calls : -Called by : -Parameter : -Author : Leo Lee -History : -***********************************************************************/ -//static irqreturn_t atsmb2_regular_isr(int irq, void *dev_id, struct pt_regs *regs) -irqreturn_t atsmb2_regular_isr(int irq, void *dev_id) -{ - - struct atsmb_host *host = dev_id; - u8 status_0, status_1, status_2, status_3,mask_0,mask_1; - u32 pdma_sts; - - DBG("[%s] s\n",__func__); - WARN_ON(host == NULL); - - disable_irq_nosync(irq); - spin_lock(&host->lock); - - /*Get INT status*/ - status_0 = *ATSMB2_SD_STS_0; - status_1 = *ATSMB2_SD_STS_1; - status_2 = *ATSMB2_SD_STS_2; - status_3 = *ATSMB2_SD_STS_3; - - mask_0 = *ATSMB2_INT_MASK_0; - mask_1 = *ATSMB2_INT_MASK_1; - /******************************************************* - card insert interrupt - ********************************************************/ - if ((status_0 & ATSMB_DEVICE_INSERT) /*Status Set and IRQ enabled*/ - /*To aviod the situation that we intentionally disable IRQ to do rescan.*/ - && (*ATSMB2_INT_MASK_0 & 0x80)) { - - if (host->mmc->ops->get_slot_status(host->mmc)) { - host->mmc->scan_retry = 3; - host->mmc->card_scan_status = false; - } else { - host->mmc->scan_retry = 0; - host->mmc->card_scan_status = false; - } - - mmc_detect_change(host->mmc, HZ/2); - /*Taipei Side Request: Disable INSERT IRQ when doing rescan.*/ - //*ATSMB2_INT_MASK_0 &= (~0x80);/* or 40?*/ //zhf: marked by James Tian - /*Then we clear the INT status*/ - //iowrite32(ATSMB_DEVICE_INSERT, host->base+_SD_STS_0); - *ATSMB2_SD_STS_0 |= ATSMB_DEVICE_INSERT; - spin_unlock(&host->lock); - enable_irq(irq); - DBG("[%s] e1\n",__func__); - return IRQ_HANDLED; - } - - if ((status_1 & mask_1)& ATSMB_SDIO_INT) { - spin_unlock(&host->lock); - mmc_signal_sdio_irq(host->mmc); - - if (((status_1 & mask_1) == ATSMB_SDIO_INT) && ((status_0 & mask_0) == 0)) { - - enable_irq(irq); - DBG("[%s] e2\n",__func__); - - return IRQ_HANDLED; - } - spin_lock(&host->lock); - } - pdma_sts = *ATSMB2_PDMA_CCR; - - if (((status_0 & mask_0) | (status_1 & mask_1)) == 0) { - spin_unlock(&host->lock); - enable_irq(irq); - DBG("[%s] e3\n",__func__); - return IRQ_HANDLED; - } - /******************************************************* - command interrupt. - *******************************************************/ - /*for write single block*/ - if (host->opcode == MMC_WRITE_BLOCK) { - if ((status_0 & ATSMB_BLOCK_XFER_DONE) - && (status_1 & ATSMB_RSP_DONE)) { - host->data->error = MMC_ERR_NONE; - host->cmd->error = MMC_ERR_NONE; - /* okay, what we want.*/ - } else { - host->data->error = -EIO; //MMC_ERR_FAILED; - host->cmd->error = -EIO; //MMC_ERR_FAILED; - DBG("[%s] err1\n",__func__); - atsmb2_dump_reg(host); - } - } else if (host->opcode == MMC_WRITE_MULTIPLE_BLOCK - || host->opcode == MMC_READ_MULTIPLE_BLOCK) { - if ((status_1 & (ATSMB_AUTO_STOP|ATSMB_RSP_DONE)) - && (status_0 & ATSMB_MULTI_XFER_DONE)) { - /*If CRC error occurs, I think this INT would not occrs.*/ - /*okay, that is what we want.*/ - host->data->error = MMC_ERR_NONE; - host->cmd->error = MMC_ERR_NONE; - } else { - host->data->error = -EIO; //MMC_ERR_FAILED; - host->cmd->error = -EIO; //MMC_ERR_FAILED; - DBG("[%s] err2\n",__func__); - atsmb2_dump_reg(host); - - } - } else if (host->opcode == MMC_READ_SINGLE_BLOCK) {/* we want DMA TC, run here, must be error.*/ - host->data->error = -EIO; //MMC_ERR_FAILED; - host->cmd->error = -EIO; //MMC_ERR_FAILED; - DBG("[%s] err3\n",__func__); - atsmb2_dump_reg(host); - } else if (host->opcode == SD_IO_RW_EXTENDED){ - /*Write operation*/ - if (*ATSMB2_CTL & BIT2) { - if ((*ATSMB2_CTL & 0xf0) == 0x10) { /*single block write*/ - if ((status_0 & ATSMB_BLOCK_XFER_DONE) - && (status_1 & ATSMB_RSP_DONE)) { - host->data->error = MMC_ERR_NONE; - host->cmd->error = MMC_ERR_NONE; - /* okay, what we want.*/ - } else { - host->data->error = -EIO; //MMC_ERR_FAILED; - host->cmd->error = -EIO; //MMC_ERR_FAILED; - DBG("[%s] err4 status_0 = %x status_1 = %x\n",__func__,status_0,status_1); - } - - } else if ((*ATSMB2_CTL & 0xf0) == 0x50) { - if ((status_0 & ATSMB_MULTI_XFER_DONE) - && (status_1 & ATSMB_RSP_DONE)) { - host->data->error = MMC_ERR_NONE; - host->cmd->error = MMC_ERR_NONE; - /* okay, what we want.*/ - } else { - host->data->error = -EIO; //MMC_ERR_FAILED; - host->cmd->error = -EIO; //MMC_ERR_FAILED; - DBG("[%s] err4-2 status_0 = %x status_1 = %x\n",__func__,status_0,status_1); - } - } else { - host->data->error = -EIO; //MMC_ERR_FAILED; - host->cmd->error = -EIO; //MMC_ERR_FAILED; - DBG("[%s] err4-3 status_0 = %x status_1 = %x\n",__func__,status_0,status_1); - } - } - else { - /*Read operation*/ - host->data->error = -EIO; //MMC_ERR_FAILED; - host->cmd->error = -EIO; //MMC_ERR_FAILED; - DBG("[%s] err5\n",__func__); - } - - - } else { -/* command, not request data*/ -/* the command which need data sending back,*/ -/* like switch_function, send_ext_csd, send_scr, send_num_wr_blocks.*/ -/* NOTICE: we also send status before reading or writing data, so SEND_STATUS should be excluded.*/ - if (host->data && host->opcode != MMC_SEND_STATUS) { - host->data->error = -EIO; //MMC_ERR_FAILED; - host->cmd->error = -EIO; //MMC_ERR_FAILED; - DBG("[%s] err6\n",__func__); - atsmb2_dump_reg(host); - } else { /* Just command, no need data sending back.*/ - if (status_1 & ATSMB_RSP_DONE) { - /*Firstly, check data-response is busy or not.*/ - if (host->cmd->flags == (MMC_RSP_R1B | MMC_CMD_AC)) { - int i = 10000; - - while (status_2 & ATSMB_RSP_BUSY) { - status_2 = *ATSMB2_SD_STS_2; - if (--i == 0) - break; - DBG(" IRQ:Status_2 = %d, busy!\n", status_2); - } - if (i == 0) - printk("[MMC driver] Error :SD data-response always busy!"); - } -#if 1 -/*for our host, even no card in slot, for SEND_STATUS also returns no error.*/ -/*The protocol layer depends on SEND_STATUS to check whether card is in slot or not.*/ -/*In fact, we can also avoid this situation by checking the response whether they are all zeros.*/ - if (!atsmb2_get_slot_status(host->mmc) && host->opcode == MMC_SEND_STATUS) { - host->cmd->retries = 0; /* No retry.*/ -// host->cmd->error = MMC_ERR_INVALID; - host->cmd->error = -EINVAL; - } else -#endif - host->cmd->error = MMC_ERR_NONE; - } else { - if (status_1 & ATSMB_RSP_TIMEOUT) {/* RSP_Timeout .*/ -// host->cmd->error = MMC_ERR_TIMEOUT; - host->cmd->error = -ETIMEDOUT; - DBG("[%s] err7\n",__func__); - } else {/*or RSP CRC error*/ -// host->cmd->error = MMC_ERR_BADCRC; - host->cmd->error = -EILSEQ; - DBG("[%s] err8\n",__func__); - } - atsmb2_dump_reg(host); - } - } - } - atsmb2_fmt_check_rsp(host); - - /*disable INT */ - *ATSMB2_INT_MASK_0 &= ~(ATSMB_BLOCK_XFER_DONE_EN | ATSMB_MULTI_XFER_DONE_EN); - *ATSMB2_INT_MASK_1 &= ~(ATSMB_WRITE_CRC_ERR_EN|ATSMB_READ_CRC_ERR_EN|ATSMB_RSP_CRC_ERR_EN - |ATSMB_DATA_TIMEOUT_EN|ATSMB_AUTO_STOP_EN|ATSMB_RSP_TIMEOUT_EN|ATSMB_RSP_DONE_EN); - - - /*clear INT status. In fact, we will clear again before issuing new command.*/ - *ATSMB2_SD_STS_0 |= status_0; - *ATSMB2_SD_STS_1 |= status_1; - //*ATSMB2_SD_STS_1 |= ((status_1 & mask_1) | (status_1 & (~ATSMB_SDIO_INT))); - - /* when read CRC error occur, and the status can't write one to clear. - * To clear read CRC error status , can do software reset. This is HW bug. 2013/3/21*/ - if ((*ATSMB2_SD_STS_1 & BIT6) == 0x40) { - DBG("[%s] host2 CMD%d Read CRC error occur\n",__func__,host->cmd->opcode); - /* Save SD card register */ - atsmb2_copy_reg(0); - /* Software reset */ - *ATSMB2_BUS_MODE |= BIT7; - /* restore SD card register */ - atsmb2_copy_reg(1); - } - - if (*ATSMB2_PDMA_ISR & SD_PDMA_IER_INT_STS) - *ATSMB2_PDMA_ISR |= SD_PDMA_IER_INT_STS; - - /*wake up some one who is sleeping.*/ - if (host->done_data) { /* We only use done_data when requesting data.*/ - host->soft_timeout = 0; - host->done(host); - } else - atsmb2_request_end(host, host->mrq); /*for cmd without data.*/ - - spin_unlock(&host->lock); - enable_irq(irq); - DBG("[%s] e4\n",__func__); - return IRQ_HANDLED; -} -EXPORT_SYMBOL(atsmb2_regular_isr); - -/********************************************************************** -Name : atsmb2_get_ro -Function :. -Calls : -Called by : -Parameter : -returns : 0 : write protection is disabled. 1: write protection is enabled. -Author : Leo Lee -History : -***********************************************************************/ -int atsmb2_get_ro(struct mmc_host *mmc) -{ - struct atsmb_host *host = mmc_priv(mmc); - unsigned char status_0 = 0; - unsigned long flags; - unsigned long ret = 0; - DBG("[%s] s\n",__func__); - spin_lock_irqsave(&host->lock, flags); - status_0 = *ATSMB2_SD_STS_0; - spin_unlock_irqrestore(&host->lock, flags); - DBG("[%s]\nstatus_0 = 0x%x\n", __func__,status_0); - ret = ((status_0 & ATSMB_WRITE_PROTECT) ? 0 : 1); - DBG("[%s] e\n",__func__); - return ret; -} -/********************************************************************** -Name : atsmb2_dump_host_regs -Function : -Calls : -Called by : -Parameter : -returns : -Author : Leo Lee -History : -***********************************************************************/ -void atsmb2_dump_host_regs(struct mmc_host *mmc) -{ - struct atsmb_host *host = mmc_priv(mmc); - DBG("[%s] s\n",__func__); - atsmb2_dump_reg(host); - DBG("[%s] e\n",__func__); -} -EXPORT_SYMBOL(atsmb2_dump_host_regs); - - - - -#if MMC2_SDIO_EXT_IRQ -static irqreturn_t mtk6620_sdio_ext_irq (int irq, void *dev_id) -{ - struct mmc_host *mmc = dev_id; - - if(!is_gpio_irqenable(wmt_mtk6620_intr) || !gpio_irqstatus(wmt_mtk6620_intr)) - return IRQ_NONE; - - smp_rmb(); - if (unlikely(test_bit(IN_SUSPEND, &mmc2_sdio_ext_irq_flags))) { - //disable_irq_nosync(mmc2_sdio_ext_irq); - wmt_gpio_mask_irq(wmt_mtk6620_intr); - - set_bit(IRQ_IN_SUSPEND, &mmc2_sdio_ext_irq_flags); - smp_wmb(); - - printk( "%s: irq in suspend, defer & disable_irq(%d)\n", - mmc_hostname(mmc), mmc2_sdio_ext_irq); - wmt_gpio_ack_irq(wmt_mtk6620_intr); - return IRQ_HANDLED; - } - //printk( "%s: irq happen, call mmc_signal_sdio_irq\n", mmc_hostname(mmc)); - mmc_signal_sdio_irq(mmc); - wmt_gpio_ack_irq(wmt_mtk6620_intr); - return IRQ_HANDLED; -} - -static void mtk6620_setup_sdio_ext_irq (struct mmc_host *mmc) -{ - int ret; - printk(KERN_WARNING "setup sdio ext irq but mmc2_sdio_ext_irq(%d) != 0!\n", mmc2_sdio_ext_irq); - - if (0 != mmc2_sdio_ext_irq) { - return; - } - - wmt_gpio_setpull(wmt_mtk6620_intr,WMT_GPIO_PULL_UP); - -// s3c_gpio_setpull(MMC2_SDIO_EINT_PIN, S3C_GPIO_PULL_NONE); -// s3c_gpio_cfgpin(MMC2_SDIO_EINT_PIN, S3C_GPIO_SFN(0xF)); - - mmc2_sdio_ext_irq = 1;//gpio_to_irq(MMC2_SDIO_EINT_PIN); - - wmt_gpio_mask_irq(wmt_mtk6620_intr); - //clear_gpio26_irq_state(); - wmt_gpio_ack_irq(wmt_mtk6620_intr); - - - ret = request_irq(IRQ_GPIO, mtk6620_sdio_ext_irq, IRQF_SHARED,"mmc2_sdio_ext_irq", mmc); - if (ret) { - printk( "request_irq(%d, 0x%p, IRQF_TRIGGER_LOW) fail(%d)!!\n", - mmc2_sdio_ext_irq, mtk6620_sdio_ext_irq, ret); - mmc2_sdio_ext_irq = 0; - return; - } - - /*clear int status register before enable this int pin*/ - wmt_gpio_ack_irq(wmt_mtk6620_intr); - /*enable this int pin*/ - wmt_gpio_unmask_irq(wmt_mtk6620_intr); - -// enable_irq_wake(mmc2_sdio_ext_irq); - printk("%s: using sdio_ext_irq and enable_irq_wake(%d) gpio(%d) IRQ_EINT(%d)\n", - mmc_hostname(mmc), mmc2_sdio_ext_irq, wmt_mtk6620_intr, - (IRQ_GPIO)); - return; -} -#endif /* MMC2_SDIO_EXT_IRQ */ - - - - -/********************************************************************** -Name : atsmb2_enable_sdio_irq -Function : -Calls : -Called by : -Parameter : -returns : -Author : Tommy Huang -History : -***********************************************************************/ -static void atsmb2_enable_sdio_irq(struct mmc_host *mmc, int enable) -{ - struct atsmb_host *host = mmc_priv(mmc); - unsigned long flags; - - DBG("[%s] s enable = %d *ATSMB2_INT_MASK_1 = %x\n",__func__,enable,*ATSMB2_INT_MASK_1); - spin_lock_irqsave(&host->lock, flags); - - -#if MMC2_SDIO_EXT_IRQ - if (is_mtk6620) { - if (enable&&enable_wifi_irq) { - if (likely(0 != mmc2_sdio_ext_irq)) { - //enable_irq(mmc2_sdio_ext_irq); - wmt_gpio_unmask_irq(wmt_mtk6620_intr); - } - else { - mtk6620_setup_sdio_ext_irq(mmc); - } - } - else { - smp_rmb(); - if (unlikely(test_and_clear_bit(IRQ_IN_SUSPEND, &mmc2_sdio_ext_irq_flags))) { - smp_wmb(); - printk("%s: irq already disabled when being deferred(%d)\n", - mmc_hostname(host->mmc), mmc2_sdio_ext_irq); - /* do nothing */ - } - else { - //disable_irq_nosync(mmc2_sdio_ext_irq); - wmt_gpio_mask_irq(wmt_mtk6620_intr); - } - } - goto out; - } -#endif /* MMC2_SDIO_EXT_IRQ */ - - - - if (enable) { - *ATSMB2_INT_MASK_1 |= ATSMB_SDIO_EN; - } else { - *ATSMB2_INT_MASK_1 &= ~ATSMB_SDIO_EN; - } -out: - spin_unlock_irqrestore(&host->lock, flags); - DBG("[%s] e\n",__func__); - -} -void wmt_detect_sdio2(void){ - - if(mmc2_host_attr!=NULL){ - - struct atsmb_host *host = mmc_priv(mmc2_host_attr); - - mmc_detect_change(host->mmc, HZ/2); - } -} - - -void force_remove_sdio2(void) -{ - if(mmc2_host_attr!=NULL) - mmc_force_remove_card(mmc2_host_attr); -} - -void rda_mci_enable_sdio_irq(struct mmc_host *mmc, int enable) -{ - enable_wifi_irq = (unsigned int )enable; - atsmb2_enable_sdio_irq(mmc, enable); -} - -EXPORT_SYMBOL(rda_mci_enable_sdio_irq); - -EXPORT_SYMBOL(wmt_detect_sdio2); -EXPORT_SYMBOL(force_remove_sdio2); -/********************************************************************** -Name : atsmb2_request -Function :. -Calls : -Called by : -Parameter : -Author : Leo Lee -History : -***********************************************************************/ -static void atsmb2_request(struct mmc_host *mmc, struct mmc_request *mrq) -{ - - struct atsmb_host *host = mmc_priv(mmc); - DBG("[%s] s\n",__func__); - - /* May retry process comes here.*/ - host->mrq = mrq; - host->data = mrq->data; - host->cmd = mrq->cmd; - host->done_data = NULL; - host->done = NULL; - - /*for data request*/ - if (host->data) { - if (host->cmd->opcode == MMC_WRITE_BLOCK - || host->cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK - || host->cmd->opcode == MMC_READ_SINGLE_BLOCK - || host->cmd->opcode == MMC_READ_MULTIPLE_BLOCK - || host->cmd->opcode == SD_IO_RW_EXTENDED) { - atsmb2_start_data(host); - } else { - atsmb2_cmd_with_data_back(host); - } - } else { - atsmb2_start_cmd(host); - } - DBG("[%s] e\n",__func__); -} -/********************************************************************** -Name : atsmb2_set_clock -Function :. -Calls : -Called by : -Parameter : -Author : Eason Chien -History :2012/7/19 -***********************************************************************/ -static int atsmb2_set_clock(struct mmc_host *mmc, unsigned int clock) -{ - if (clock == mmc->f_min) { - DBG("[%s]ATSMB2 Host 400KHz\n", __func__); - return auto_pll_divisor(DEV_SDMMC2, SET_DIV, 1, 390); - } else if (clock >= 50000000) { - DBG("[%s]ATSMB2 Host 50MHz\n", __func__); - return auto_pll_divisor(DEV_SDMMC2, SET_DIV, 2, 45); - } else if ((clock >= 25000000) && (clock < 50000000)) { - DBG("[%s]ATSMB2 Host 25MHz\n", __func__); - return auto_pll_divisor(DEV_SDMMC2, SET_DIV, 2, 24); - } else if ((clock >= 20000000) && (clock < 25000000)) { - DBG("[%s]ATSMB2 Host 20MHz\n", __func__); - return auto_pll_divisor(DEV_SDMMC2, SET_DIV, 2, 20); - } else { - DBG("[%s]ATSMB2 Host 390KHz\n", __func__); - return auto_pll_divisor(DEV_SDMMC2, SET_DIV, 1, 390); - } -} - -/********************************************************************** -Name : atsmb2_set_ios -Function :. -Calls : -Called by : -Parameter : -Author : Leo Lee -History : -***********************************************************************/ -static void atsmb2_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) -{ - - struct atsmb_host *host = mmc_priv(mmc); - unsigned long flags; - DBG("[%s] s\n",__func__); - spin_lock_irqsave(&host->lock, flags); -#if MMC2_SDIO_EXT_IRQ - if(is_mtk6620){ - if ((ios->power_mode == MMC_POWER_OFF)) { - if (0 != mmc2_sdio_ext_irq) { - printk("%s: set mmc2 MMC_POWER_OFF disable_irq_wake & free_irq(%d)!\n", __func__, mmc2_sdio_ext_irq); - //disable_irq_wake(mmc2_sdio_ext_irq); - wmt_gpio_mask_irq(wmt_mtk6620_intr); - free_irq(IRQ_GPIO, host->mmc); - mmc2_sdio_ext_irq = 0; - } - } - } -#endif /* MMC2_SDIO_EXT_IRQ */ - - - if (ios->power_mode == MMC_POWER_OFF) { - if (MMC2_DRIVER_VERSION == MMC_DRV_3498) { - /* stop SD output clock */ - *ATSMB2_BUS_MODE &= ~(ATSMB_CST); - - /* disable SD Card power */ - /*set SD2 power pin as GPO pin*/ - if (SD2_function == SDIO_WIFI) - ;//GPIO_OC_GP0_BYTE_VAL |= BIT6; - else { - GPIO_CTRL_GP19_SD2_BYTE_VAL |= GPIO_SD2_POWER; - GPIO_OC_GP19_SD2_BYTE_VAL|= GPIO_SD2_POWER; - } - - /*set internal pull up*/ - PULL_CTRL_GP19_SD2_BYTE_VAL |= GPIO_SD2_POWER; - /*set internal pull enable*/ - PULL_EN_GP19_SD2_BYTE_VAL |= GPIO_SD2_POWER; - /*disable SD2 power*/ - if (SD2_function == SDIO_WIFI) - GPIO_OD_GP0_BYTE_VAL &= ~BIT6; - else - GPIO_OD_GP19_SD2_BYTE_VAL |= GPIO_SD2_POWER; - - /* Disable Pull up/down resister of SD Bus */ - PULL_CTRL_GP19_SD2_BYTE_VAL &= ~SD2_PIN; - - /* Config SD2 to GPIO */ - GPIO_CTRL_GP19_SD2_BYTE_VAL |= SD2_PIN; - - /* SD2 all pins output low */ - GPIO_OD_GP19_SD2_BYTE_VAL &= ~SD2_PIN; - - /* Config SD2 to GPIO */ - GPIO_OC_GP19_SD2_BYTE_VAL |= SD2_PIN; - } - } else if (ios->power_mode == MMC_POWER_UP) { - if (MMC2_DRIVER_VERSION == MMC_DRV_3498) { - /* disable SD Card power */ - /*set SD2 power pin as GPO pin*/ - if (SD2_function == SDIO_WIFI) - ;//GPIO_OC_GP0_BYTE_VAL |= BIT6; - else { - GPIO_CTRL_GP19_SD2_BYTE_VAL |= GPIO_SD2_POWER; - GPIO_OC_GP19_SD2_BYTE_VAL |= GPIO_SD2_POWER; - } - - /*set internal pull up*/ - PULL_CTRL_GP19_SD2_BYTE_VAL |= GPIO_SD2_POWER; - /*set internal pull enable*/ - PULL_EN_GP19_SD2_BYTE_VAL |= GPIO_SD2_POWER; - /*disable SD2 power*/ - if (SD2_function == SDIO_WIFI) - GPIO_OD_GP0_BYTE_VAL &= ~BIT6; - else - GPIO_OD_GP19_SD2_BYTE_VAL |= GPIO_SD2_POWER; - - /* Config SD PIN share */ - //kevin delete for dvfs - //PIN_SHARING_SEL_4BYTE_VAL |= GPIO_SD2_PinShare; - - /* do not config GPIO_SD2_CD because ISR has already run, - * config card detect will issue ISR storm. - */ - /* Config SD to GPIO */ - GPIO_CTRL_GP19_SD2_BYTE_VAL |= SD2_PIN; - - /* SD all pins output low */ - GPIO_OD_GP19_SD2_BYTE_VAL &= ~SD2_PIN; - - /* Config SD to GPO */ - GPIO_OC_GP19_SD2_BYTE_VAL |= SD2_PIN; - - /* Pull up/down resister of SD Bus */ - /*Disable Clock & CMD Pull enable*/ - PULL_EN_GP19_SD2_BYTE_VAL &= ~(GPIO_SD2_Clock ); - - /*Set CD ,WP ,DATA pin pull up*/ - if (SD2_function == SDIO_WIFI) { - PULL_CTRL_GP23_I2C3_BYTE_VAL &= ~GPIO_SD2_CD; /*pull down card always in slot*/ - PULL_CTRL_GP19_SD2_BYTE_VAL |= (GPIO_SD2_Data | GPIO_SD2_WriteProtect|GPIO_SD2_Command); - } else { - PULL_CTRL_GP23_I2C3_BYTE_VAL |= GPIO_SD2_CD; - PULL_CTRL_GP19_SD2_BYTE_VAL |= (GPIO_SD2_Data | GPIO_SD2_WriteProtect|GPIO_SD2_Command); - } - - /*Enable CD ,WP ,DATA internal pull*/ - PULL_EN_GP23_I2C3_BYTE_VAL |= GPIO_SD2_CD; - PULL_EN_GP19_SD2_BYTE_VAL |= (GPIO_SD2_Data | GPIO_SD2_WriteProtect|GPIO_SD2_Command); - - spin_unlock_irqrestore(&host->lock, flags); - msleep(100); - spin_lock_irqsave(&host->lock, flags); - - /* enable SD Card Power */ - if (SD2_function == SDIO_WIFI) - GPIO_OD_GP0_BYTE_VAL |= BIT6; - else - GPIO_OD_GP19_SD2_BYTE_VAL &= ~GPIO_SD2_POWER; - - /* enable SD output clock */ - *ATSMB2_BUS_MODE |= ATSMB_CST; - - spin_unlock_irqrestore(&host->lock, flags); - msleep(10); - spin_lock_irqsave(&host->lock, flags); - - /* Config SD0 back to function */ - GPIO_CTRL_GP23_I2C3_BYTE_VAL &= ~GPIO_SD2_CD; - GPIO_CTRL_GP19_SD2_BYTE_VAL &= ~SD2_PIN; - } - } else { - /*nothing to do when powering on.*/ - } - - host->current_clock = atsmb2_set_clock(mmc,ios->clock); - - if (ios->bus_width == MMC_BUS_WIDTH_8) { - *ATSMB2_EXT_CTL |= (0x04); - } else if (ios->bus_width == MMC_BUS_WIDTH_4) { - *ATSMB2_BUS_MODE |= ATSMB_BUS_WIDTH_4; - *ATSMB2_EXT_CTL &= ~(0x04); - } else { - *ATSMB2_BUS_MODE &= ~(ATSMB_BUS_WIDTH_4); - *ATSMB2_EXT_CTL &= ~(0x04); - } -#if 1 - if (ios->timing == MMC_TIMING_SD_HS) - *ATSMB2_EXT_CTL |= 0x80; /*HIGH SPEED MODE*/ - else - *ATSMB2_EXT_CTL &= ~(0x80); -#endif -#if 0 //zhf: marked by James Tian - if (ios->ins_en == MMC_INSERT_IRQ_EN) - *ATSMB2_INT_MASK_0 |= (0x80);/* or 40?*/ - else - *ATSMB2_INT_MASK_0 &= (~0x80);/* or 40?*/ -#endif - - spin_unlock_irqrestore(&host->lock, flags); - DBG("[%s] e\n",__func__); -} - - -static const struct mmc_host_ops atsmb2_ops = { - .request = atsmb2_request, - .set_ios = atsmb2_set_ios, - .get_ro = atsmb2_get_ro, - .get_slot_status = atsmb2_get_slot_status, - .dump_host_regs = atsmb2_dump_host_regs, - .enable_sdio_irq = atsmb2_enable_sdio_irq, -}; - -extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen); - -/********************************************************************** -Name :atsmb2_probe -Function :. -Calls : -Called by : -Parameter : -Author : Leo Lee -History : -***********************************************************************/ -static int __init atsmb2_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct mmc_host *mmc_host = NULL; - struct atsmb_host *atsmb_host = NULL; - struct resource *resource = NULL; - int irq[2] = {0}; - int ret = 0; - - DBG("[%s] s\n",__func__); - if (!pdev) { - ret = -EINVAL; /* Invalid argument */ - goto the_end; - } - - /*Enable SD host clock*/ - auto_pll_divisor(DEV_SDMMC2, CLK_ENABLE, 0, 0); - - if (MMC2_DRIVER_VERSION == MMC_DRV_3498) { - /* enable SD1 PIN share */ - //kevin delete for dvfs - //PIN_SHARING_SEL_4BYTE_VAL |= GPIO_SD2_PinShare; - - /* Pull up/down resister of SD CD */ - if (SD2_function == SDIO_WIFI) { - PULL_CTRL_GP23_I2C3_BYTE_VAL &= ~GPIO_SD2_CD; /*pull down CD*/ - } else { - PULL_CTRL_GP23_I2C3_BYTE_VAL |= GPIO_SD2_CD; /*pull up CD*/ - } - PULL_EN_GP23_I2C3_BYTE_VAL |= GPIO_SD2_CD; - - /* config CardDetect pin to SD function */ - GPIO_CTRL_GP23_I2C3_BYTE_VAL &= ~GPIO_SD2_CD; - } - - - resource = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!resource) { - ret = -ENXIO; /* No such device or address */ - printk(KERN_ALERT "[MMC/SD driver] Getting platform resources failed!\n"); - goto the_end; - } -#if 0 - if (!request_mem_region(resource->start, SZ_1K, MMC2_DRIVER_NAME)) { - ret = -EBUSY; - printk(KERN_ALERT "[MMC/SD driver] Request memory region failed!\n"); - goto the_end ; - } -#endif - irq[0] = platform_get_irq(pdev, 0); /*get IRQ for device*/; - irq[1] = platform_get_irq(pdev, 1); /*get IRQ for dma*/; - - if (irq[0] == NO_IRQ || irq[1] == NO_IRQ) { - ret = -ENXIO;/* No such device or address */ - printk(KERN_ALERT "[MMC/SD driver] Get platform IRQ failed!\n"); - goto rls_region; - } - - /*allocate a standard msp_host structure attached with a atsmb structure*/ - mmc_host = mmc_alloc_host(sizeof(struct atsmb_host), dev); - if (!mmc_host) { - ret = -ENOMEM; - printk(KERN_ALERT "[MMC/SD driver] Allocating driver's data failed!\n"); - goto rls_region; - } - mmc_host->wmt_host_index = 2; /*to identify host number*/ - - dev_set_drvdata(dev, (void *)mmc_host); /* mmc_host is driver data for the atsmb dev.*/ - atsmb_host = mmc_priv(mmc_host); - - mmc_host->ops = &atsmb2_ops; - - mmc_host->ocr_avail = MMC_VDD_32_33|MMC_VDD_33_34; - - mmc_host->f_min = 390425; /*390.425Hz = 400MHz/64/16*/ - mmc_host->f_max = 50000000; /* in fact, the max frequency is 400MHz( = 400MHz/1/1)*/ - - if(!is_nmc1000){ - mmc_host->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SDIO_IRQ| MMC_CAP_NONREMOVABLE; - }else{ - mmc_host->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SDIO_IRQ| MMC_CAP_NONREMOVABLE; - } - /* |MMC_CAP_8_BIT_DATA;*/ //zhf: marked by James Tian - mmc_host->pm_caps |= MMC_PM_KEEP_POWER; - mmc_host->pm_caps |= MMC_PM_WAKE_SDIO_IRQ;//add by kevinguan for mtk6620 - - mmc_host->max_segs = 128; /*we use software sg. so we could manage even larger number.*/ - - /*1MB per each request */ - /*we have a 16 bit block number register, and block length is 512 bytes.*/ - mmc_host->max_req_size = 16*512*(mmc_host->max_segs); - mmc_host->max_seg_size = 65024; /* 0x7F*512 PDMA one descriptor can transfer 64K-1 byte*/ - mmc_host->max_blk_size = 2048; /* our block length register is 11 bits.*/ - mmc_host->max_blk_count = (mmc_host->max_req_size)/512; - - /*set the specified host -- ATSMB*/ -#ifdef CONFIG_MMC_UNSAFE_RESUME - mmc_host->card_attath_status = card_attach_status_unchange; -#endif - sema_init(&mmc_host->req_sema,1); /*initial request semaphore*/ -#if 0 - atsmb_host->base = ioremap(resource->start, SZ_1K); - if (!atsmb_host->base) { - printk(KERN_ALERT "[MMC/SD driver] IO remap failed!\n"); - ret = -ENOMEM; - goto fr_host; - } -#endif - atsmb_host->base = (void *)resource->start; - atsmb_host->mmc = mmc_host; - spin_lock_init(&atsmb_host->lock); - atsmb_host->res = resource;/* for atsmb2_remove*/ - - /*disable all interrupt and clear status by resetting controller.*/ - *ATSMB2_BUS_MODE |= ATSMB_SFTRST; - *ATSMB2_BLK_LEN &= ~(0xa000); - *ATSMB2_SD_STS_0 |= 0xff; - *ATSMB2_SD_STS_1 |= 0xff; - - /* WM3437 A0 default not output clock, after SFTRST need to enable SD clock */ - //if (MMC2_DRIVER_VERSION >= MMC_DRV_3437_A0) /* including 3429 */ - *ATSMB2_BUS_MODE |= ATSMB_CST; - - atsmb_host->regular_irq = irq[0]; - atsmb_host->dma_irq = irq[1]; - - ret = request_irq(atsmb_host->regular_irq, - atsmb2_regular_isr, - IRQF_SHARED, //SA_SHIRQ, /*SA_INTERRUPT, * that is okay?*/ //zhf: modified by James Tian, should be IRQF_SHARED? - MMC2_DRIVER_NAME, - (void *)atsmb_host); - if (ret) { - printk(KERN_ALERT "[MMC/SD driver] Failed to register regular ISR!\n"); - goto unmap; - } - - ret = request_irq(atsmb_host->dma_irq, - atsmb2_dma_isr, - IRQF_DISABLED, // SA_INTERRUPT, //zhf: modified by James Tian - MMC2_DRIVER_NAME, - (void *)atsmb_host); - if (ret) { - printk(KERN_ALERT "[MMC/SD driver] Failed to register DMA ISR!\n"); - goto fr_regular_isr; - } - - - /*wait card detect status change*/ - //msleep(10); - - /*enable card insertion interrupt and enable DMA and its Global INT*/ - *ATSMB2_BLK_LEN |= (0xa000); /* also, we enable GPIO to detect card.*/ - *ATSMB2_SD_STS_0 |= 0xff; - *ATSMB2_INT_MASK_0 |= 0x80; /*or 0x40?*/ - - /*allocation dma descriptor*/ - ret = atsmb2_alloc_desc(atsmb_host, sizeof(struct SD_PDMA_DESC_S) * MAX_DESC_NUM); - if (ret == -1) { - printk(KERN_ALERT "[MMC/SD driver] Failed to allocate DMA descriptor!\n"); - goto fr_dma_isr; - } - printk(KERN_INFO "WMT ATSMB2 (AHB To SD/MMC2 Bus) controller registered!\n"); - - if (SD2_function == SDIO_WIFI){ - if(set_bus_dead){ - mmc_host->bus_dead = 1; //fix this problem: mmc1: error -110 during resume (card was removed?) - }else - printk("dont set bus dead in probe function\n"); - mmc_add_host(mmc_host,false); - }else - mmc_add_host(mmc_host,true); - - mmc2_host_attr = mmc_host; - DBG("[%s] e1\n",__func__); - return 0; - -fr_dma_isr: - free_irq(atsmb_host->dma_irq, atsmb_host); -fr_regular_isr: - free_irq(atsmb_host->regular_irq, atsmb_host); -unmap: - //iounmap(atsmb_host->base); -//fr_host: - dev_set_drvdata(dev, NULL); - mmc_free_host(mmc_host); -rls_region: - //release_mem_region(resource->start, SZ_1K); -the_end: - printk(KERN_ALERT "[MMC/SD driver] ATSMB2 probe Failed!\n") ; - DBG("[%s] e2\n",__func__); - return ret; -} -/********************************************************************** -Name : atsmb2_remove -Function :. -Calls : -Called by : -Parameter : -Author : Leo Lee -History : -***********************************************************************/ -static int atsmb2_remove(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct mmc_host *mmc_host = (struct mmc_host *)dev_get_drvdata(dev); - struct atsmb_host *atsmb_host; - - DBG("[%s] s\n",__func__); - atsmb_host = mmc_priv(mmc_host); - if (!mmc_host || !atsmb_host) { - printk(KERN_ALERT "[MMC/SD driver] ATSMB2 remove method failed!\n"); - DBG("[%s] e1\n",__func__); - return -ENXIO; - } - mmc_remove_host(mmc_host); - - /*disable interrupt by resetting controller -- for safey*/ - *ATSMB2_BUS_MODE |= ATSMB_SFTRST; - *ATSMB2_BLK_LEN &= ~(0xa000); - *ATSMB2_SD_STS_0 |= 0xff; - *ATSMB2_SD_STS_1 |= 0xff; - - (void)free_irq(atsmb_host->regular_irq, atsmb_host); - (void)free_irq(atsmb_host->dma_irq, atsmb_host); - (void)iounmap(atsmb_host->base); - (void)release_mem_region(atsmb_host->res->start, SZ_1K); - dev_set_drvdata(dev, NULL); - /*free dma descriptor*/ - dma_free_coherent(atsmb_host->mmc->parent, atsmb_host->DescSize, - atsmb_host->DescVirAddr, atsmb_host->DescPhyAddr); - (void)mmc_free_host(mmc_host);/* also free atsmb_host.*/ - DBG("[%s] e2\n",__func__); - return 0; -} - -/********************************************************************** -Name : atsmb2_shutdown -Function :. -Calls : -Called by : -Parameter : -Author : Tommy Huang -History : -***********************************************************************/ -static void atsmb2_shutdown(struct platform_device *pdev) -{ - /*atsmb2_shutdown don't be used now.*/ - /*struct device *dev = &pdev->dev; - struct mmc_host *mmc_host = (struct mmc_host *)dev_get_drvdata(dev);*/ - - DBG("[%s] s\n",__func__); - if (SD2_function != SDIO_WIFI) { - /*Disable card detect interrupt*/ - *ATSMB2_INT_MASK_0 &= ~0x80; - } - DBG("[%s] e\n",__func__); - -} - -/********************************************************************** -Name : atsmb2_suspend -Function :. -Calls : -Called by : -Parameter : -Author : Leo Lee -History : -***********************************************************************/ -int SD2_card_state = 0; /*0: card remove >=1: card enable*/ - -#ifdef CONFIG_PM -static int atsmb2_suspend(struct platform_device *pdev, pm_message_t state) -{ - struct device *dev = &pdev->dev; - struct mmc_host *mmc = (struct mmc_host *)dev_get_drvdata(dev); - int ret = 0; - DBG("[%s] s\n",__func__); - - if (mmc) { - - if (SD2_function == SDIO_WIFI) { - if (SD2_card_state > 0) - mmc_force_remove_card(mmc2_host_attr); - } -#if MMC2_SDIO_EXT_IRQ - if (is_mtk6620) { - if (0 != mmc2_sdio_ext_irq) { - //if (mmc_try_claim_host(host->mmc)) { - if(true){ - set_bit(IN_SUSPEND, &mmc2_sdio_ext_irq_flags); - printk(KERN_INFO "%s:in_suspend++\n", mmc_hostname(mmc)); - } - else { - printk(KERN_INFO "%s:claim host fail in suspend, return -EBUSY\n", mmc_hostname(mmc)); - return -EBUSY; - } - } - } -#endif /* MMC2_SDIO_EXT_IRQ */ - - /*struct atsmb_host *host = mmc_priv(mmc);*/ - ret = mmc_suspend_host(mmc); - -#if MMC2_SDIO_EXT_IRQ - if (is_mtk6620) { - if (ret) { - printk("\n\n\n\n\n\n%s:mmc_suspend_host fail(%d)\n\n\n\n\n\n", - mmc_hostname(mmc), ret); - if (0 != mmc2_sdio_ext_irq) { - clear_bit(IN_SUSPEND, &mmc2_sdio_ext_irq_flags); - //mmc_release_host(host->mmc); - - } - return ret; - } - - } -#endif - - - if (ret == 0) { - /*disable all interrupt and clear status by resetting controller. */ - *ATSMB2_BUS_MODE |= ATSMB_SFTRST; - *ATSMB2_BLK_LEN &= ~(0xa000); - *ATSMB2_SD_STS_0 |= 0xff; - *ATSMB2_SD_STS_1 |= 0xff; - - } - /*disable source clock*/ - auto_pll_divisor(DEV_SDMMC2, CLK_DISABLE, 0, 0); -#ifdef CONFIG_MMC_UNSAFE_RESUME - /*clean SD card attatch status change*/ - //PMCWS_VAL |= BIT19; - mmc->card_attath_status = card_attach_status_unchange; -#endif - } - - DBG("[%s] e\n",__func__); - return ret; -} -/********************************************************************** -Name : atsmb2_resume -Function :. -Calls : -Called by : -Parameter : -Author : Leo Lee -History : -***********************************************************************/ -static int atsmb2_resume(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct mmc_host *mmc = (struct mmc_host *)dev_get_drvdata(dev); - int ret = 0; - DBG("[%s] s\n",__func__); - - /* - * enable interrupt, DMA, etc. - * Supply power to slot. - */ - if (mmc) { - /*enable source clock*/ - auto_pll_divisor(DEV_SDMMC2, CLK_ENABLE, 0, 0); - - udelay(1); - /*enable card insertion interrupt and enable DMA and its Global INT*/ - *ATSMB2_BUS_MODE |= ATSMB_SFTRST; - *ATSMB2_BLK_LEN |= (0xa000); - *ATSMB2_INT_MASK_0 |= 0x80; /* or 40?*/ -#ifdef CONFIG_MMC_UNSAFE_RESUME - /*modify SD card attatch status change*/ - //if ((PMCWS_VAL & BIT19) && !mmc->bus_dead) { - /*card change when suspend mode*/ - mmc->card_attath_status = card_attach_status_change; - /*clean SD card attatch status change*/ - // PMCWS_VAL |= BIT19; - //} -#endif - if (SD2_function == SDIO_WIFI) { - PULL_CTRL_GP23_I2C3_BYTE_VAL &= ~GPIO_SD2_CD; /*pull down CD*/ - PULL_EN_GP23_I2C3_BYTE_VAL |= GPIO_SD2_CD; - - //kevin add for suspend&resume - PULL_CTRL_GP19_SD2_BYTE_VAL |= GPIO_SD2_Data | GPIO_SD2_Command; - PULL_CTRL_GP19_SD2_BYTE_VAL &= ~GPIO_SD2_WriteProtect; - PULL_EN_GP19_SD2_BYTE_VAL |= (GPIO_SD2_Data | GPIO_SD2_WriteProtect|GPIO_SD2_Command); - PULL_EN_GP19_SD2_BYTE_VAL &= ~GPIO_SD2_Clock; - GPIO_CTRL_GP19_SD2_BYTE_VAL &= ~(GPIO_SD2_Data | GPIO_SD2_WriteProtect | GPIO_SD2_Command | GPIO_SD2_Clock); - *ATSMB2_BUS_MODE |= ATSMB_CST; - msleep(20); - - - if (SD2_card_state > 0) { - printk("[%s] mmc_resume_host s\n",__func__); - mmc_detect_change(mmc2_host_attr, 1*HZ/2); - printk("[%s] mmc_resume_host e\n",__func__); - } - - -#if MMC2_SDIO_EXT_IRQ - if (is_mtk6620) { - if (0 != mmc2_sdio_ext_irq) { - /* sdhc goes back to normal working mode, after mtk6620_init() */ - clear_bit(IN_SUSPEND, &mmc2_sdio_ext_irq_flags); - //mmc_release_host(host->mmc); - printk(KERN_INFO "%s:in_suspend--\n", mmc_hostname(mmc)); - } - } -#endif /* MMC2_SDIO_EXT_IRQ */ - - - - //kevin add for suspend&resume - ret = mmc_resume_host(mmc); - - -#if MMC2_SDIO_EXT_IRQ - /* after mmc_resume_host(), sdio_func is also resumed */ - if (is_mtk6620) { - if (0 != mmc2_sdio_ext_irq) { - /* signal deferred irq if any */ - smp_rmb(); - if (unlikely(test_bit(IRQ_IN_SUSPEND, &mmc2_sdio_ext_irq_flags))) { - printk(KERN_INFO "%s: signal deferred irq(%d)\n", - mmc_hostname(mmc), mmc2_sdio_ext_irq); - /* signal the deferred irq */ - mmc_signal_sdio_irq(mmc); - } - } - } -#endif - - } else { - ret = mmc_resume_host(mmc); - } - } - - DBG("[%s] e\n",__func__); - return ret; -} -#else -#define atsmb2_suspend NULL -#define atsmb2_resume NULL -#endif - -static struct platform_driver atsmb2_driver = { - .driver.name = "sdmmc2", - //.probe = atsmb2_probe, - .remove = atsmb2_remove, - .shutdown = atsmb2_shutdown, - .suspend = atsmb2_suspend, - .resume = atsmb2_resume, -}; - -static struct platform_device wmt_sdmmc2_device = { - .name = "sdmmc2", - .id = 0, - .dev = { - .dma_mask = &wmt_sdmmc2_dma_mask, - .coherent_dma_mask = ~0, - .release = atsmb2_release, - }, - .num_resources = ARRAY_SIZE(wmt_sdmmc2_resources), - .resource = wmt_sdmmc2_resources, -}; - -static DEFINE_MUTEX(SD2_state_lock); - -static ssize_t atsmb2_state_show(struct kobject *kobj, struct kobj_attribute *attr, - char *buf) -{ - int ret = 0; - - DBG("[%s] s\n",__func__); - - ret = sprintf(buf, "%d\n", SD2_card_state); - DBG("[%s]SD2_card_state = %d\n",__func__,SD2_card_state); - DBG("[%s] e\n",__func__); - return ret; -} - -static ssize_t atsmb2_state_store(struct kobject *kobj, struct kobj_attribute *attr, - const char *buf, size_t n) -{ - int val; - DBG("[%s] s\n",__func__); - - mutex_lock(&SD2_state_lock); - if (sscanf(buf, "%d", &val) == 1) { - DBG("[%s] val = %d\n",__func__,val); - if (val == 1) { - SD2_card_state++; - DBG("[%s] add state SD2_card_state = %d\n",__func__,SD2_card_state); - if ((SD2_card_state == 1) && (mmc2_host_attr->card == NULL)) { - DBG("[%s]add card\n",__func__); - mmc_detect_change(mmc2_host_attr, 0); - msleep(1000); - } else { - msleep(1000); /*to prevent the card not init ready*/ - } - } else if (val == 0) { - SD2_card_state--; - printk("[%s] sub state SD2_card_state = %d\n",__func__,SD2_card_state); - if (SD2_card_state < 0) { - SD2_card_state = 0; - printk("[%s] set 0 SD2_card_state = %d\n",__func__,SD2_card_state); - } - - if ((SD2_card_state == 0) && (mmc2_host_attr->card != NULL)) { - DBG("[%s]remove card\n",__func__); - mmc_force_remove_card(mmc2_host_attr); - } - } - - DBG("[%s] e1\n",__func__); - mutex_unlock(&SD2_state_lock); - return n; - } - - mutex_unlock(&SD2_state_lock); - DBG("[%s] e2\n",__func__); - return -EINVAL; -} - -static struct kobj_attribute atsmb2_state_attr = { \ - .attr = { \ - .name = __stringify(state), \ - .mode = 0755, \ - }, \ - .show = atsmb2_state_show, \ - .store = atsmb2_state_store, \ -}; - -#if MMC2_SDIO_EXT_IRQ - -static ssize_t atsmb2_intr_show(struct kobject *kobj, struct kobj_attribute *attr, - char *buf) -{ - int ret = 0; - - - ret = sprintf(buf, "%d\n", is_mtk6620); - printk("[%s]is_mtk6620 = %d\n",__func__,is_mtk6620); - return ret; -} - -static ssize_t atsmb2_intr_store(struct kobject *kobj, struct kobj_attribute *attr, - const char *buf, size_t n) -{ - int val; - if (sscanf(buf, "%d", &val) == 1) { - printk("[%s] val = %d\n",__func__,val); - if (val == 1) { - if (gpio_request(wmt_mtk6620_intr, "mtk6620_wifi_intr") < 0) { - printk("gpio(%d) mtk6620_wifi_intr gpio request fail\n", wmt_mtk6620_intr); - is_mtk6620 = 0; - return -1; - } - } else if (val == 0) { - - gpio_free(wmt_mtk6620_intr); - - } - is_mtk6620 = val; - - return n; - } - return -EINVAL; -} - -static struct kobj_attribute atsmb2_intr_attr = { \ - .attr = { \ - .name = __stringify(intr), \ - .mode = 0755, \ - }, \ - .show = atsmb2_intr_show, \ - .store = atsmb2_intr_store, \ -}; -#endif - - -static struct attribute * g2[] = { - &atsmb2_state_attr.attr, -#if MMC2_SDIO_EXT_IRQ - &atsmb2_intr_attr.attr, -#endif - NULL, -}; - -static struct attribute_group attr2_group = { - .attrs = g2, -}; - -static int __init atsmb2_init(void) -{ - int ret; - - int retval; - unsigned char buf[80]; - unsigned char buf1[80]; - int varlen = 80; - char *varname = "wmt.sd2.param"; - int temp = 0, sd_enable = 0; /*0 :disable 1:enable*/ - - DBG("[%s] s\n",__func__); - -#ifdef CONFIG_MTD_WMT_SF - /*Read system param to identify host function 0: SD/MMC 1:SDIO wifi*/ - retval = wmt_getsyspara(varname, buf, &varlen); - if (retval == 0) { - sscanf(buf,"%x:%d", &temp, &SD2_function); - printk(KERN_ALERT "wmt.sd2.param = %x:%d\n", temp, SD2_function); - sd_enable = temp & 0xf; - SDXC2_function = (temp >> 4) & 0xf; - printk(KERN_ALERT "SD2 ebable = %x, SDXC = %x, function = %x\n", - sd_enable, SDXC2_function, SD2_function); - - if (SD2_function < 0 || SD2_function >= SD_MAX_FUN) - return -ENODEV; - } else { - //default is enable sdio wifi - temp = sd_enable = 1; - SD2_function = 1; - printk(KERN_ALERT "Default wmt.sd2.param = %x:%d\n", temp, SD2_function); - - } - memset(buf,0,sizeof(buf)); - varlen = 80; - retval = wmt_getsyspara("wmt.init.rc", buf, &varlen); - if (retval == 0) { - printk(KERN_ALERT"wmt.init.rc:%s\n",buf); - if(!strcmp(buf,"init_nmc1000.rc")){ - is_nmc1000 = 0x01; - printk("is_nmc1000:%d",is_nmc1000); - } - if (!strcmp(buf, "init.bcm6330.rc")) - { - is_ap6330 = 1; - printk("is_ap6330:%d\n", is_ap6330); - } - if (!strcmp(buf, "init.rda5991.rc")) - { - printk("is rda5991\n"); - set_bus_dead = 0; - } - if (!strcmp(buf, "init.mtk6620.rc")) - { - printk("is mtk6620\n"); - set_bus_dead = 0; - } - } else { - printk(KERN_ALERT "wmt.init.rc do not exit\n"); - } -#endif - /*SD function disable*/ - if (sd_enable != 1) - return -ENODEV; - - get_driver_version2(); - - if (platform_device_register(&wmt_sdmmc2_device))//add by jay,for modules support - return -1; - //ret = platform_driver_register(&atsmb2_driver); - ret = platform_driver_probe(&atsmb2_driver, atsmb2_probe); - - atsmb2_kobj = kobject_create_and_add("mmc2", NULL); - if (!atsmb2_kobj) - return -ENOMEM; - return sysfs_create_group(atsmb2_kobj, &attr2_group); - - DBG("[%s] e\n",__func__); - return ret; -} - -static void __exit atsmb2_exit(void) -{ - DBG("[%s] s\n",__func__); - (void)platform_driver_unregister(&atsmb2_driver); - (void)platform_device_unregister(&wmt_sdmmc2_device);//add by jay,for modules support - DBG("[%s] e\n",__func__); -} - -module_init(atsmb2_init); -module_exit(atsmb2_exit); -module_param(fmax2, uint, 0444); - -MODULE_AUTHOR("WonderMedia Technologies, Inc."); -MODULE_DESCRIPTION("WMT [AHB to SD/MMC2 Bridge] driver"); -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/mmc/host/mmc_spi.c b/ANDROID_3.4.5/drivers/mmc/host/mmc_spi.c deleted file mode 100644 index 273306c6..00000000 --- a/ANDROID_3.4.5/drivers/mmc/host/mmc_spi.c +++ /dev/null @@ -1,1554 +0,0 @@ -/* - * mmc_spi.c - Access SD/MMC cards through SPI master controllers - * - * (C) Copyright 2005, Intec Automation, - * Mike Lavender (mike@steroidmicros) - * (C) Copyright 2006-2007, David Brownell - * (C) Copyright 2007, Axis Communications, - * Hans-Peter Nilsson (hp@axis.com) - * (C) Copyright 2007, ATRON electronic GmbH, - * Jan Nikitenko <jan.nikitenko@gmail.com> - * - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ -#include <linux/sched.h> -#include <linux/delay.h> -#include <linux/slab.h> -#include <linux/module.h> -#include <linux/bio.h> -#include <linux/dma-mapping.h> -#include <linux/crc7.h> -#include <linux/crc-itu-t.h> -#include <linux/scatterlist.h> - -#include <linux/mmc/host.h> -#include <linux/mmc/mmc.h> /* for R1_SPI_* bit values */ - -#include <linux/spi/spi.h> -#include <linux/spi/mmc_spi.h> - -#include <asm/unaligned.h> - - -/* NOTES: - * - * - For now, we won't try to interoperate with a real mmc/sd/sdio - * controller, although some of them do have hardware support for - * SPI protocol. The main reason for such configs would be mmc-ish - * cards like DataFlash, which don't support that "native" protocol. - * - * We don't have a "DataFlash/MMC/SD/SDIO card slot" abstraction to - * switch between driver stacks, and in any case if "native" mode - * is available, it will be faster and hence preferable. - * - * - MMC depends on a different chipselect management policy than the - * SPI interface currently supports for shared bus segments: it needs - * to issue multiple spi_message requests with the chipselect active, - * using the results of one message to decide the next one to issue. - * - * Pending updates to the programming interface, this driver expects - * that it not share the bus with other drivers (precluding conflicts). - * - * - We tell the controller to keep the chipselect active from the - * beginning of an mmc_host_ops.request until the end. So beware - * of SPI controller drivers that mis-handle the cs_change flag! - * - * However, many cards seem OK with chipselect flapping up/down - * during that time ... at least on unshared bus segments. - */ - - -/* - * Local protocol constants, internal to data block protocols. - */ - -/* Response tokens used to ack each block written: */ -#define SPI_MMC_RESPONSE_CODE(x) ((x) & 0x1f) -#define SPI_RESPONSE_ACCEPTED ((2 << 1)|1) -#define SPI_RESPONSE_CRC_ERR ((5 << 1)|1) -#define SPI_RESPONSE_WRITE_ERR ((6 << 1)|1) - -/* Read and write blocks start with these tokens and end with crc; - * on error, read tokens act like a subset of R2_SPI_* values. - */ -#define SPI_TOKEN_SINGLE 0xfe /* single block r/w, multiblock read */ -#define SPI_TOKEN_MULTI_WRITE 0xfc /* multiblock write */ -#define SPI_TOKEN_STOP_TRAN 0xfd /* terminate multiblock write */ - -#define MMC_SPI_BLOCKSIZE 512 - - -/* These fixed timeouts come from the latest SD specs, which say to ignore - * the CSD values. The R1B value is for card erase (e.g. the "I forgot the - * card's password" scenario); it's mostly applied to STOP_TRANSMISSION after - * reads which takes nowhere near that long. Older cards may be able to use - * shorter timeouts ... but why bother? - */ -#define r1b_timeout (HZ * 3) - -/* One of the critical speed parameters is the amount of data which may - * be transferred in one command. If this value is too low, the SD card - * controller has to do multiple partial block writes (argggh!). With - * today (2008) SD cards there is little speed gain if we transfer more - * than 64 KBytes at a time. So use this value until there is any indication - * that we should do more here. - */ -#define MMC_SPI_BLOCKSATONCE 128 - -/****************************************************************************/ - -/* - * Local Data Structures - */ - -/* "scratch" is per-{command,block} data exchanged with the card */ -struct scratch { - u8 status[29]; - u8 data_token; - __be16 crc_val; -}; - -struct mmc_spi_host { - struct mmc_host *mmc; - struct spi_device *spi; - - unsigned char power_mode; - u16 powerup_msecs; - - struct mmc_spi_platform_data *pdata; - - /* for bulk data transfers */ - struct spi_transfer token, t, crc, early_status; - struct spi_message m; - - /* for status readback */ - struct spi_transfer status; - struct spi_message readback; - - /* underlying DMA-aware controller, or null */ - struct device *dma_dev; - - /* buffer used for commands and for message "overhead" */ - struct scratch *data; - dma_addr_t data_dma; - - /* Specs say to write ones most of the time, even when the card - * has no need to read its input data; and many cards won't care. - * This is our source of those ones. - */ - void *ones; - dma_addr_t ones_dma; -}; - - -/****************************************************************************/ - -/* - * MMC-over-SPI protocol glue, used by the MMC stack interface - */ - -static inline int mmc_cs_off(struct mmc_spi_host *host) -{ - /* chipselect will always be inactive after setup() */ - return spi_setup(host->spi); -} - -static int -mmc_spi_readbytes(struct mmc_spi_host *host, unsigned len) -{ - int status; - - if (len > sizeof(*host->data)) { - WARN_ON(1); - return -EIO; - } - - host->status.len = len; - - if (host->dma_dev) - dma_sync_single_for_device(host->dma_dev, - host->data_dma, sizeof(*host->data), - DMA_FROM_DEVICE); - - status = spi_sync_locked(host->spi, &host->readback); - - if (host->dma_dev) - dma_sync_single_for_cpu(host->dma_dev, - host->data_dma, sizeof(*host->data), - DMA_FROM_DEVICE); - - return status; -} - -static int mmc_spi_skip(struct mmc_spi_host *host, unsigned long timeout, - unsigned n, u8 byte) -{ - u8 *cp = host->data->status; - unsigned long start = jiffies; - - while (1) { - int status; - unsigned i; - - status = mmc_spi_readbytes(host, n); - if (status < 0) - return status; - - for (i = 0; i < n; i++) { - if (cp[i] != byte) - return cp[i]; - } - - if (time_is_before_jiffies(start + timeout)) - break; - - /* If we need long timeouts, we may release the CPU. - * We use jiffies here because we want to have a relation - * between elapsed time and the blocking of the scheduler. - */ - if (time_is_before_jiffies(start+1)) - schedule(); - } - return -ETIMEDOUT; -} - -static inline int -mmc_spi_wait_unbusy(struct mmc_spi_host *host, unsigned long timeout) -{ - return mmc_spi_skip(host, timeout, sizeof(host->data->status), 0); -} - -static int mmc_spi_readtoken(struct mmc_spi_host *host, unsigned long timeout) -{ - return mmc_spi_skip(host, timeout, 1, 0xff); -} - - -/* - * Note that for SPI, cmd->resp[0] is not the same data as "native" protocol - * hosts return! The low byte holds R1_SPI bits. The next byte may hold - * R2_SPI bits ... for SEND_STATUS, or after data read errors. - * - * cmd->resp[1] holds any four-byte response, for R3 (READ_OCR) and on - * newer cards R7 (IF_COND). - */ - -static char *maptype(struct mmc_command *cmd) -{ - switch (mmc_spi_resp_type(cmd)) { - case MMC_RSP_SPI_R1: return "R1"; - case MMC_RSP_SPI_R1B: return "R1B"; - case MMC_RSP_SPI_R2: return "R2/R5"; - case MMC_RSP_SPI_R3: return "R3/R4/R7"; - default: return "?"; - } -} - -/* return zero, else negative errno after setting cmd->error */ -static int mmc_spi_response_get(struct mmc_spi_host *host, - struct mmc_command *cmd, int cs_on) -{ - u8 *cp = host->data->status; - u8 *end = cp + host->t.len; - int value = 0; - int bitshift; - u8 leftover = 0; - unsigned short rotator; - int i; - char tag[32]; - - snprintf(tag, sizeof(tag), " ... CMD%d response SPI_%s", - cmd->opcode, maptype(cmd)); - - /* Except for data block reads, the whole response will already - * be stored in the scratch buffer. It's somewhere after the - * command and the first byte we read after it. We ignore that - * first byte. After STOP_TRANSMISSION command it may include - * two data bits, but otherwise it's all ones. - */ - cp += 8; - while (cp < end && *cp == 0xff) - cp++; - - /* Data block reads (R1 response types) may need more data... */ - if (cp == end) { - cp = host->data->status; - end = cp+1; - - /* Card sends N(CR) (== 1..8) bytes of all-ones then one - * status byte ... and we already scanned 2 bytes. - * - * REVISIT block read paths use nasty byte-at-a-time I/O - * so it can always DMA directly into the target buffer. - * It'd probably be better to memcpy() the first chunk and - * avoid extra i/o calls... - * - * Note we check for more than 8 bytes, because in practice, - * some SD cards are slow... - */ - for (i = 2; i < 16; i++) { - value = mmc_spi_readbytes(host, 1); - if (value < 0) - goto done; - if (*cp != 0xff) - goto checkstatus; - } - value = -ETIMEDOUT; - goto done; - } - -checkstatus: - bitshift = 0; - if (*cp & 0x80) { - /* Houston, we have an ugly card with a bit-shifted response */ - rotator = *cp++ << 8; - /* read the next byte */ - if (cp == end) { - value = mmc_spi_readbytes(host, 1); - if (value < 0) - goto done; - cp = host->data->status; - end = cp+1; - } - rotator |= *cp++; - while (rotator & 0x8000) { - bitshift++; - rotator <<= 1; - } - cmd->resp[0] = rotator >> 8; - leftover = rotator; - } else { - cmd->resp[0] = *cp++; - } - cmd->error = 0; - - /* Status byte: the entire seven-bit R1 response. */ - if (cmd->resp[0] != 0) { - if ((R1_SPI_PARAMETER | R1_SPI_ADDRESS) - & cmd->resp[0]) - value = -EFAULT; /* Bad address */ - else if (R1_SPI_ILLEGAL_COMMAND & cmd->resp[0]) - value = -ENOSYS; /* Function not implemented */ - else if (R1_SPI_COM_CRC & cmd->resp[0]) - value = -EILSEQ; /* Illegal byte sequence */ - else if ((R1_SPI_ERASE_SEQ | R1_SPI_ERASE_RESET) - & cmd->resp[0]) - value = -EIO; /* I/O error */ - /* else R1_SPI_IDLE, "it's resetting" */ - } - - switch (mmc_spi_resp_type(cmd)) { - - /* SPI R1B == R1 + busy; STOP_TRANSMISSION (for multiblock reads) - * and less-common stuff like various erase operations. - */ - case MMC_RSP_SPI_R1B: - /* maybe we read all the busy tokens already */ - while (cp < end && *cp == 0) - cp++; - if (cp == end) - mmc_spi_wait_unbusy(host, r1b_timeout); - break; - - /* SPI R2 == R1 + second status byte; SEND_STATUS - * SPI R5 == R1 + data byte; IO_RW_DIRECT - */ - case MMC_RSP_SPI_R2: - /* read the next byte */ - if (cp == end) { - value = mmc_spi_readbytes(host, 1); - if (value < 0) - goto done; - cp = host->data->status; - end = cp+1; - } - if (bitshift) { - rotator = leftover << 8; - rotator |= *cp << bitshift; - cmd->resp[0] |= (rotator & 0xFF00); - } else { - cmd->resp[0] |= *cp << 8; - } - break; - - /* SPI R3, R4, or R7 == R1 + 4 bytes */ - case MMC_RSP_SPI_R3: - rotator = leftover << 8; - cmd->resp[1] = 0; - for (i = 0; i < 4; i++) { - cmd->resp[1] <<= 8; - /* read the next byte */ - if (cp == end) { - value = mmc_spi_readbytes(host, 1); - if (value < 0) - goto done; - cp = host->data->status; - end = cp+1; - } - if (bitshift) { - rotator |= *cp++ << bitshift; - cmd->resp[1] |= (rotator >> 8); - rotator <<= 8; - } else { - cmd->resp[1] |= *cp++; - } - } - break; - - /* SPI R1 == just one status byte */ - case MMC_RSP_SPI_R1: - break; - - default: - dev_dbg(&host->spi->dev, "bad response type %04x\n", - mmc_spi_resp_type(cmd)); - if (value >= 0) - value = -EINVAL; - goto done; - } - - if (value < 0) - dev_dbg(&host->spi->dev, "%s: resp %04x %08x\n", - tag, cmd->resp[0], cmd->resp[1]); - - /* disable chipselect on errors and some success cases */ - if (value >= 0 && cs_on) - return value; -done: - if (value < 0) - cmd->error = value; - mmc_cs_off(host); - return value; -} - -/* Issue command and read its response. - * Returns zero on success, negative for error. - * - * On error, caller must cope with mmc core retry mechanism. That - * means immediate low-level resubmit, which affects the bus lock... - */ -static int -mmc_spi_command_send(struct mmc_spi_host *host, - struct mmc_request *mrq, - struct mmc_command *cmd, int cs_on) -{ - struct scratch *data = host->data; - u8 *cp = data->status; - u32 arg = cmd->arg; - int status; - struct spi_transfer *t; - - /* We can handle most commands (except block reads) in one full - * duplex I/O operation before either starting the next transfer - * (data block or command) or else deselecting the card. - * - * First, write 7 bytes: - * - an all-ones byte to ensure the card is ready - * - opcode byte (plus start and transmission bits) - * - four bytes of big-endian argument - * - crc7 (plus end bit) ... always computed, it's cheap - * - * We init the whole buffer to all-ones, which is what we need - * to write while we're reading (later) response data. - */ - memset(cp++, 0xff, sizeof(data->status)); - - *cp++ = 0x40 | cmd->opcode; - *cp++ = (u8)(arg >> 24); - *cp++ = (u8)(arg >> 16); - *cp++ = (u8)(arg >> 8); - *cp++ = (u8)arg; - *cp++ = (crc7(0, &data->status[1], 5) << 1) | 0x01; - - /* Then, read up to 13 bytes (while writing all-ones): - * - N(CR) (== 1..8) bytes of all-ones - * - status byte (for all response types) - * - the rest of the response, either: - * + nothing, for R1 or R1B responses - * + second status byte, for R2 responses - * + four data bytes, for R3 and R7 responses - * - * Finally, read some more bytes ... in the nice cases we know in - * advance how many, and reading 1 more is always OK: - * - N(EC) (== 0..N) bytes of all-ones, before deselect/finish - * - N(RC) (== 1..N) bytes of all-ones, before next command - * - N(WR) (== 1..N) bytes of all-ones, before data write - * - * So in those cases one full duplex I/O of at most 21 bytes will - * handle the whole command, leaving the card ready to receive a - * data block or new command. We do that whenever we can, shaving - * CPU and IRQ costs (especially when using DMA or FIFOs). - * - * There are two other cases, where it's not generally practical - * to rely on a single I/O: - * - * - R1B responses need at least N(EC) bytes of all-zeroes. - * - * In this case we can *try* to fit it into one I/O, then - * maybe read more data later. - * - * - Data block reads are more troublesome, since a variable - * number of padding bytes precede the token and data. - * + N(CX) (== 0..8) bytes of all-ones, before CSD or CID - * + N(AC) (== 1..many) bytes of all-ones - * - * In this case we currently only have minimal speedups here: - * when N(CR) == 1 we can avoid I/O in response_get(). - */ - if (cs_on && (mrq->data->flags & MMC_DATA_READ)) { - cp += 2; /* min(N(CR)) + status */ - /* R1 */ - } else { - cp += 10; /* max(N(CR)) + status + min(N(RC),N(WR)) */ - if (cmd->flags & MMC_RSP_SPI_S2) /* R2/R5 */ - cp++; - else if (cmd->flags & MMC_RSP_SPI_B4) /* R3/R4/R7 */ - cp += 4; - else if (cmd->flags & MMC_RSP_BUSY) /* R1B */ - cp = data->status + sizeof(data->status); - /* else: R1 (most commands) */ - } - - dev_dbg(&host->spi->dev, " mmc_spi: CMD%d, resp %s\n", - cmd->opcode, maptype(cmd)); - - /* send command, leaving chipselect active */ - spi_message_init(&host->m); - - t = &host->t; - memset(t, 0, sizeof(*t)); - t->tx_buf = t->rx_buf = data->status; - t->tx_dma = t->rx_dma = host->data_dma; - t->len = cp - data->status; - t->cs_change = 1; - spi_message_add_tail(t, &host->m); - - if (host->dma_dev) { - host->m.is_dma_mapped = 1; - dma_sync_single_for_device(host->dma_dev, - host->data_dma, sizeof(*host->data), - DMA_BIDIRECTIONAL); - } - status = spi_sync_locked(host->spi, &host->m); - - if (host->dma_dev) - dma_sync_single_for_cpu(host->dma_dev, - host->data_dma, sizeof(*host->data), - DMA_BIDIRECTIONAL); - if (status < 0) { - dev_dbg(&host->spi->dev, " ... write returned %d\n", status); - cmd->error = status; - return status; - } - - /* after no-data commands and STOP_TRANSMISSION, chipselect off */ - return mmc_spi_response_get(host, cmd, cs_on); -} - -/* Build data message with up to four separate transfers. For TX, we - * start by writing the data token. And in most cases, we finish with - * a status transfer. - * - * We always provide TX data for data and CRC. The MMC/SD protocol - * requires us to write ones; but Linux defaults to writing zeroes; - * so we explicitly initialize it to all ones on RX paths. - * - * We also handle DMA mapping, so the underlying SPI controller does - * not need to (re)do it for each message. - */ -static void -mmc_spi_setup_data_message( - struct mmc_spi_host *host, - int multiple, - enum dma_data_direction direction) -{ - struct spi_transfer *t; - struct scratch *scratch = host->data; - dma_addr_t dma = host->data_dma; - - spi_message_init(&host->m); - if (dma) - host->m.is_dma_mapped = 1; - - /* for reads, readblock() skips 0xff bytes before finding - * the token; for writes, this transfer issues that token. - */ - if (direction == DMA_TO_DEVICE) { - t = &host->token; - memset(t, 0, sizeof(*t)); - t->len = 1; - if (multiple) - scratch->data_token = SPI_TOKEN_MULTI_WRITE; - else - scratch->data_token = SPI_TOKEN_SINGLE; - t->tx_buf = &scratch->data_token; - if (dma) - t->tx_dma = dma + offsetof(struct scratch, data_token); - spi_message_add_tail(t, &host->m); - } - - /* Body of transfer is buffer, then CRC ... - * either TX-only, or RX with TX-ones. - */ - t = &host->t; - memset(t, 0, sizeof(*t)); - t->tx_buf = host->ones; - t->tx_dma = host->ones_dma; - /* length and actual buffer info are written later */ - spi_message_add_tail(t, &host->m); - - t = &host->crc; - memset(t, 0, sizeof(*t)); - t->len = 2; - if (direction == DMA_TO_DEVICE) { - /* the actual CRC may get written later */ - t->tx_buf = &scratch->crc_val; - if (dma) - t->tx_dma = dma + offsetof(struct scratch, crc_val); - } else { - t->tx_buf = host->ones; - t->tx_dma = host->ones_dma; - t->rx_buf = &scratch->crc_val; - if (dma) - t->rx_dma = dma + offsetof(struct scratch, crc_val); - } - spi_message_add_tail(t, &host->m); - - /* - * A single block read is followed by N(EC) [0+] all-ones bytes - * before deselect ... don't bother. - * - * Multiblock reads are followed by N(AC) [1+] all-ones bytes before - * the next block is read, or a STOP_TRANSMISSION is issued. We'll - * collect that single byte, so readblock() doesn't need to. - * - * For a write, the one-byte data response follows immediately, then - * come zero or more busy bytes, then N(WR) [1+] all-ones bytes. - * Then single block reads may deselect, and multiblock ones issue - * the next token (next data block, or STOP_TRAN). We can try to - * minimize I/O ops by using a single read to collect end-of-busy. - */ - if (multiple || direction == DMA_TO_DEVICE) { - t = &host->early_status; - memset(t, 0, sizeof(*t)); - t->len = (direction == DMA_TO_DEVICE) - ? sizeof(scratch->status) - : 1; - t->tx_buf = host->ones; - t->tx_dma = host->ones_dma; - t->rx_buf = scratch->status; - if (dma) - t->rx_dma = dma + offsetof(struct scratch, status); - t->cs_change = 1; - spi_message_add_tail(t, &host->m); - } -} - -/* - * Write one block: - * - caller handled preceding N(WR) [1+] all-ones bytes - * - data block - * + token - * + data bytes - * + crc16 - * - an all-ones byte ... card writes a data-response byte - * - followed by N(EC) [0+] all-ones bytes, card writes zero/'busy' - * - * Return negative errno, else success. - */ -static int -mmc_spi_writeblock(struct mmc_spi_host *host, struct spi_transfer *t, - unsigned long timeout) -{ - struct spi_device *spi = host->spi; - int status, i; - struct scratch *scratch = host->data; - u32 pattern; - - if (host->mmc->use_spi_crc) - scratch->crc_val = cpu_to_be16( - crc_itu_t(0, t->tx_buf, t->len)); - if (host->dma_dev) - dma_sync_single_for_device(host->dma_dev, - host->data_dma, sizeof(*scratch), - DMA_BIDIRECTIONAL); - - status = spi_sync_locked(spi, &host->m); - - if (status != 0) { - dev_dbg(&spi->dev, "write error (%d)\n", status); - return status; - } - - if (host->dma_dev) - dma_sync_single_for_cpu(host->dma_dev, - host->data_dma, sizeof(*scratch), - DMA_BIDIRECTIONAL); - - /* - * Get the transmission data-response reply. It must follow - * immediately after the data block we transferred. This reply - * doesn't necessarily tell whether the write operation succeeded; - * it just says if the transmission was ok and whether *earlier* - * writes succeeded; see the standard. - * - * In practice, there are (even modern SDHC-)cards which are late - * in sending the response, and miss the time frame by a few bits, - * so we have to cope with this situation and check the response - * bit-by-bit. Arggh!!! - */ - pattern = scratch->status[0] << 24; - pattern |= scratch->status[1] << 16; - pattern |= scratch->status[2] << 8; - pattern |= scratch->status[3]; - - /* First 3 bit of pattern are undefined */ - pattern |= 0xE0000000; - - /* left-adjust to leading 0 bit */ - while (pattern & 0x80000000) - pattern <<= 1; - /* right-adjust for pattern matching. Code is in bit 4..0 now. */ - pattern >>= 27; - - switch (pattern) { - case SPI_RESPONSE_ACCEPTED: - status = 0; - break; - case SPI_RESPONSE_CRC_ERR: - /* host shall then issue MMC_STOP_TRANSMISSION */ - status = -EILSEQ; - break; - case SPI_RESPONSE_WRITE_ERR: - /* host shall then issue MMC_STOP_TRANSMISSION, - * and should MMC_SEND_STATUS to sort it out - */ - status = -EIO; - break; - default: - status = -EPROTO; - break; - } - if (status != 0) { - dev_dbg(&spi->dev, "write error %02x (%d)\n", - scratch->status[0], status); - return status; - } - - t->tx_buf += t->len; - if (host->dma_dev) - t->tx_dma += t->len; - - /* Return when not busy. If we didn't collect that status yet, - * we'll need some more I/O. - */ - for (i = 4; i < sizeof(scratch->status); i++) { - /* card is non-busy if the most recent bit is 1 */ - if (scratch->status[i] & 0x01) - return 0; - } - return mmc_spi_wait_unbusy(host, timeout); -} - -/* - * Read one block: - * - skip leading all-ones bytes ... either - * + N(AC) [1..f(clock,CSD)] usually, else - * + N(CX) [0..8] when reading CSD or CID - * - data block - * + token ... if error token, no data or crc - * + data bytes - * + crc16 - * - * After single block reads, we're done; N(EC) [0+] all-ones bytes follow - * before dropping chipselect. - * - * For multiblock reads, caller either reads the next block or issues a - * STOP_TRANSMISSION command. - */ -static int -mmc_spi_readblock(struct mmc_spi_host *host, struct spi_transfer *t, - unsigned long timeout) -{ - struct spi_device *spi = host->spi; - int status; - struct scratch *scratch = host->data; - unsigned int bitshift; - u8 leftover; - - /* At least one SD card sends an all-zeroes byte when N(CX) - * applies, before the all-ones bytes ... just cope with that. - */ - status = mmc_spi_readbytes(host, 1); - if (status < 0) - return status; - status = scratch->status[0]; - if (status == 0xff || status == 0) - status = mmc_spi_readtoken(host, timeout); - - if (status < 0) { - dev_dbg(&spi->dev, "read error %02x (%d)\n", status, status); - return status; - } - - /* The token may be bit-shifted... - * the first 0-bit precedes the data stream. - */ - bitshift = 7; - while (status & 0x80) { - status <<= 1; - bitshift--; - } - leftover = status << 1; - - if (host->dma_dev) { - dma_sync_single_for_device(host->dma_dev, - host->data_dma, sizeof(*scratch), - DMA_BIDIRECTIONAL); - dma_sync_single_for_device(host->dma_dev, - t->rx_dma, t->len, - DMA_FROM_DEVICE); - } - - status = spi_sync_locked(spi, &host->m); - - if (host->dma_dev) { - dma_sync_single_for_cpu(host->dma_dev, - host->data_dma, sizeof(*scratch), - DMA_BIDIRECTIONAL); - dma_sync_single_for_cpu(host->dma_dev, - t->rx_dma, t->len, - DMA_FROM_DEVICE); - } - - if (bitshift) { - /* Walk through the data and the crc and do - * all the magic to get byte-aligned data. - */ - u8 *cp = t->rx_buf; - unsigned int len; - unsigned int bitright = 8 - bitshift; - u8 temp; - for (len = t->len; len; len--) { - temp = *cp; - *cp++ = leftover | (temp >> bitshift); - leftover = temp << bitright; - } - cp = (u8 *) &scratch->crc_val; - temp = *cp; - *cp++ = leftover | (temp >> bitshift); - leftover = temp << bitright; - temp = *cp; - *cp = leftover | (temp >> bitshift); - } - - if (host->mmc->use_spi_crc) { - u16 crc = crc_itu_t(0, t->rx_buf, t->len); - - be16_to_cpus(&scratch->crc_val); - if (scratch->crc_val != crc) { - dev_dbg(&spi->dev, "read - crc error: crc_val=0x%04x, " - "computed=0x%04x len=%d\n", - scratch->crc_val, crc, t->len); - return -EILSEQ; - } - } - - t->rx_buf += t->len; - if (host->dma_dev) - t->rx_dma += t->len; - - return 0; -} - -/* - * An MMC/SD data stage includes one or more blocks, optional CRCs, - * and inline handshaking. That handhaking makes it unlike most - * other SPI protocol stacks. - */ -static void -mmc_spi_data_do(struct mmc_spi_host *host, struct mmc_command *cmd, - struct mmc_data *data, u32 blk_size) -{ - struct spi_device *spi = host->spi; - struct device *dma_dev = host->dma_dev; - struct spi_transfer *t; - enum dma_data_direction direction; - struct scatterlist *sg; - unsigned n_sg; - int multiple = (data->blocks > 1); - u32 clock_rate; - unsigned long timeout; - - if (data->flags & MMC_DATA_READ) - direction = DMA_FROM_DEVICE; - else - direction = DMA_TO_DEVICE; - mmc_spi_setup_data_message(host, multiple, direction); - t = &host->t; - - if (t->speed_hz) - clock_rate = t->speed_hz; - else - clock_rate = spi->max_speed_hz; - - timeout = data->timeout_ns + - data->timeout_clks * 1000000 / clock_rate; - timeout = usecs_to_jiffies((unsigned int)(timeout / 1000)) + 1; - - /* Handle scatterlist segments one at a time, with synch for - * each 512-byte block - */ - for (sg = data->sg, n_sg = data->sg_len; n_sg; n_sg--, sg++) { - int status = 0; - dma_addr_t dma_addr = 0; - void *kmap_addr; - unsigned length = sg->length; - enum dma_data_direction dir = direction; - - /* set up dma mapping for controller drivers that might - * use DMA ... though they may fall back to PIO - */ - if (dma_dev) { - /* never invalidate whole *shared* pages ... */ - if ((sg->offset != 0 || length != PAGE_SIZE) - && dir == DMA_FROM_DEVICE) - dir = DMA_BIDIRECTIONAL; - - dma_addr = dma_map_page(dma_dev, sg_page(sg), 0, - PAGE_SIZE, dir); - if (direction == DMA_TO_DEVICE) - t->tx_dma = dma_addr + sg->offset; - else - t->rx_dma = dma_addr + sg->offset; - } - - /* allow pio too; we don't allow highmem */ - kmap_addr = kmap(sg_page(sg)); - if (direction == DMA_TO_DEVICE) - t->tx_buf = kmap_addr + sg->offset; - else - t->rx_buf = kmap_addr + sg->offset; - - /* transfer each block, and update request status */ - while (length) { - t->len = min(length, blk_size); - - dev_dbg(&host->spi->dev, - " mmc_spi: %s block, %d bytes\n", - (direction == DMA_TO_DEVICE) - ? "write" - : "read", - t->len); - - if (direction == DMA_TO_DEVICE) - status = mmc_spi_writeblock(host, t, timeout); - else - status = mmc_spi_readblock(host, t, timeout); - if (status < 0) - break; - - data->bytes_xfered += t->len; - length -= t->len; - - if (!multiple) - break; - } - - /* discard mappings */ - if (direction == DMA_FROM_DEVICE) - flush_kernel_dcache_page(sg_page(sg)); - kunmap(sg_page(sg)); - if (dma_dev) - dma_unmap_page(dma_dev, dma_addr, PAGE_SIZE, dir); - - if (status < 0) { - data->error = status; - dev_dbg(&spi->dev, "%s status %d\n", - (direction == DMA_TO_DEVICE) - ? "write" : "read", - status); - break; - } - } - - /* NOTE some docs describe an MMC-only SET_BLOCK_COUNT (CMD23) that - * can be issued before multiblock writes. Unlike its more widely - * documented analogue for SD cards (SET_WR_BLK_ERASE_COUNT, ACMD23), - * that can affect the STOP_TRAN logic. Complete (and current) - * MMC specs should sort that out before Linux starts using CMD23. - */ - if (direction == DMA_TO_DEVICE && multiple) { - struct scratch *scratch = host->data; - int tmp; - const unsigned statlen = sizeof(scratch->status); - - dev_dbg(&spi->dev, " mmc_spi: STOP_TRAN\n"); - - /* Tweak the per-block message we set up earlier by morphing - * it to hold single buffer with the token followed by some - * all-ones bytes ... skip N(BR) (0..1), scan the rest for - * "not busy any longer" status, and leave chip selected. - */ - INIT_LIST_HEAD(&host->m.transfers); - list_add(&host->early_status.transfer_list, - &host->m.transfers); - - memset(scratch->status, 0xff, statlen); - scratch->status[0] = SPI_TOKEN_STOP_TRAN; - - host->early_status.tx_buf = host->early_status.rx_buf; - host->early_status.tx_dma = host->early_status.rx_dma; - host->early_status.len = statlen; - - if (host->dma_dev) - dma_sync_single_for_device(host->dma_dev, - host->data_dma, sizeof(*scratch), - DMA_BIDIRECTIONAL); - - tmp = spi_sync_locked(spi, &host->m); - - if (host->dma_dev) - dma_sync_single_for_cpu(host->dma_dev, - host->data_dma, sizeof(*scratch), - DMA_BIDIRECTIONAL); - - if (tmp < 0) { - if (!data->error) - data->error = tmp; - return; - } - - /* Ideally we collected "not busy" status with one I/O, - * avoiding wasteful byte-at-a-time scanning... but more - * I/O is often needed. - */ - for (tmp = 2; tmp < statlen; tmp++) { - if (scratch->status[tmp] != 0) - return; - } - tmp = mmc_spi_wait_unbusy(host, timeout); - if (tmp < 0 && !data->error) - data->error = tmp; - } -} - -/****************************************************************************/ - -/* - * MMC driver implementation -- the interface to the MMC stack - */ - -static void mmc_spi_request(struct mmc_host *mmc, struct mmc_request *mrq) -{ - struct mmc_spi_host *host = mmc_priv(mmc); - int status = -EINVAL; - int crc_retry = 5; - struct mmc_command stop; - -#ifdef DEBUG - /* MMC core and layered drivers *MUST* issue SPI-aware commands */ - { - struct mmc_command *cmd; - int invalid = 0; - - cmd = mrq->cmd; - if (!mmc_spi_resp_type(cmd)) { - dev_dbg(&host->spi->dev, "bogus command\n"); - cmd->error = -EINVAL; - invalid = 1; - } - - cmd = mrq->stop; - if (cmd && !mmc_spi_resp_type(cmd)) { - dev_dbg(&host->spi->dev, "bogus STOP command\n"); - cmd->error = -EINVAL; - invalid = 1; - } - - if (invalid) { - dump_stack(); - mmc_request_done(host->mmc, mrq); - return; - } - } -#endif - - /* request exclusive bus access */ - spi_bus_lock(host->spi->master); - -crc_recover: - /* issue command; then optionally data and stop */ - status = mmc_spi_command_send(host, mrq, mrq->cmd, mrq->data != NULL); - if (status == 0 && mrq->data) { - mmc_spi_data_do(host, mrq->cmd, mrq->data, mrq->data->blksz); - - /* - * The SPI bus is not always reliable for large data transfers. - * If an occasional crc error is reported by the SD device with - * data read/write over SPI, it may be recovered by repeating - * the last SD command again. The retry count is set to 5 to - * ensure the driver passes stress tests. - */ - if (mrq->data->error == -EILSEQ && crc_retry) { - stop.opcode = MMC_STOP_TRANSMISSION; - stop.arg = 0; - stop.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC; - status = mmc_spi_command_send(host, mrq, &stop, 0); - crc_retry--; - mrq->data->error = 0; - goto crc_recover; - } - - if (mrq->stop) - status = mmc_spi_command_send(host, mrq, mrq->stop, 0); - else - mmc_cs_off(host); - } - - /* release the bus */ - spi_bus_unlock(host->spi->master); - - mmc_request_done(host->mmc, mrq); -} - -/* See Section 6.4.1, in SD "Simplified Physical Layer Specification 2.0" - * - * NOTE that here we can't know that the card has just been powered up; - * not all MMC/SD sockets support power switching. - * - * FIXME when the card is still in SPI mode, e.g. from a previous kernel, - * this doesn't seem to do the right thing at all... - */ -static void mmc_spi_initsequence(struct mmc_spi_host *host) -{ - /* Try to be very sure any previous command has completed; - * wait till not-busy, skip debris from any old commands. - */ - mmc_spi_wait_unbusy(host, r1b_timeout); - mmc_spi_readbytes(host, 10); - - /* - * Do a burst with chipselect active-high. We need to do this to - * meet the requirement of 74 clock cycles with both chipselect - * and CMD (MOSI) high before CMD0 ... after the card has been - * powered up to Vdd(min), and so is ready to take commands. - * - * Some cards are particularly needy of this (e.g. Viking "SD256") - * while most others don't seem to care. - * - * Note that this is one of the places MMC/SD plays games with the - * SPI protocol. Another is that when chipselect is released while - * the card returns BUSY status, the clock must issue several cycles - * with chipselect high before the card will stop driving its output. - */ - host->spi->mode |= SPI_CS_HIGH; - if (spi_setup(host->spi) != 0) { - /* Just warn; most cards work without it. */ - dev_warn(&host->spi->dev, - "can't change chip-select polarity\n"); - host->spi->mode &= ~SPI_CS_HIGH; - } else { - mmc_spi_readbytes(host, 18); - - host->spi->mode &= ~SPI_CS_HIGH; - if (spi_setup(host->spi) != 0) { - /* Wot, we can't get the same setup we had before? */ - dev_err(&host->spi->dev, - "can't restore chip-select polarity\n"); - } - } -} - -static char *mmc_powerstring(u8 power_mode) -{ - switch (power_mode) { - case MMC_POWER_OFF: return "off"; - case MMC_POWER_UP: return "up"; - case MMC_POWER_ON: return "on"; - } - return "?"; -} - -static void mmc_spi_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) -{ - struct mmc_spi_host *host = mmc_priv(mmc); - - if (host->power_mode != ios->power_mode) { - int canpower; - - canpower = host->pdata && host->pdata->setpower; - - dev_dbg(&host->spi->dev, "mmc_spi: power %s (%d)%s\n", - mmc_powerstring(ios->power_mode), - ios->vdd, - canpower ? ", can switch" : ""); - - /* switch power on/off if possible, accounting for - * max 250msec powerup time if needed. - */ - if (canpower) { - switch (ios->power_mode) { - case MMC_POWER_OFF: - case MMC_POWER_UP: - host->pdata->setpower(&host->spi->dev, - ios->vdd); - if (ios->power_mode == MMC_POWER_UP) - msleep(host->powerup_msecs); - } - } - - /* See 6.4.1 in the simplified SD card physical spec 2.0 */ - if (ios->power_mode == MMC_POWER_ON) - mmc_spi_initsequence(host); - - /* If powering down, ground all card inputs to avoid power - * delivery from data lines! On a shared SPI bus, this - * will probably be temporary; 6.4.2 of the simplified SD - * spec says this must last at least 1msec. - * - * - Clock low means CPOL 0, e.g. mode 0 - * - MOSI low comes from writing zero - * - Chipselect is usually active low... - */ - if (canpower && ios->power_mode == MMC_POWER_OFF) { - int mres; - u8 nullbyte = 0; - - host->spi->mode &= ~(SPI_CPOL|SPI_CPHA); - mres = spi_setup(host->spi); - if (mres < 0) - dev_dbg(&host->spi->dev, - "switch to SPI mode 0 failed\n"); - - if (spi_write(host->spi, &nullbyte, 1) < 0) - dev_dbg(&host->spi->dev, - "put spi signals to low failed\n"); - - /* - * Now clock should be low due to spi mode 0; - * MOSI should be low because of written 0x00; - * chipselect should be low (it is active low) - * power supply is off, so now MMC is off too! - * - * FIXME no, chipselect can be high since the - * device is inactive and SPI_CS_HIGH is clear... - */ - msleep(10); - if (mres == 0) { - host->spi->mode |= (SPI_CPOL|SPI_CPHA); - mres = spi_setup(host->spi); - if (mres < 0) - dev_dbg(&host->spi->dev, - "switch back to SPI mode 3" - " failed\n"); - } - } - - host->power_mode = ios->power_mode; - } - - if (host->spi->max_speed_hz != ios->clock && ios->clock != 0) { - int status; - - host->spi->max_speed_hz = ios->clock; - status = spi_setup(host->spi); - dev_dbg(&host->spi->dev, - "mmc_spi: clock to %d Hz, %d\n", - host->spi->max_speed_hz, status); - } -} - -static int mmc_spi_get_ro(struct mmc_host *mmc) -{ - struct mmc_spi_host *host = mmc_priv(mmc); - - if (host->pdata && host->pdata->get_ro) - return !!host->pdata->get_ro(mmc->parent); - /* - * Board doesn't support read only detection; let the mmc core - * decide what to do. - */ - return -ENOSYS; -} - -static int mmc_spi_get_cd(struct mmc_host *mmc) -{ - struct mmc_spi_host *host = mmc_priv(mmc); - - if (host->pdata && host->pdata->get_cd) - return !!host->pdata->get_cd(mmc->parent); - return -ENOSYS; -} - -static const struct mmc_host_ops mmc_spi_ops = { - .request = mmc_spi_request, - .set_ios = mmc_spi_set_ios, - .get_ro = mmc_spi_get_ro, - .get_cd = mmc_spi_get_cd, -}; - - -/****************************************************************************/ - -/* - * SPI driver implementation - */ - -static irqreturn_t -mmc_spi_detect_irq(int irq, void *mmc) -{ - struct mmc_spi_host *host = mmc_priv(mmc); - u16 delay_msec = max(host->pdata->detect_delay, (u16)100); - - mmc_detect_change(mmc, msecs_to_jiffies(delay_msec)); - return IRQ_HANDLED; -} - -static int mmc_spi_probe(struct spi_device *spi) -{ - void *ones; - struct mmc_host *mmc; - struct mmc_spi_host *host; - int status; - - /* We rely on full duplex transfers, mostly to reduce - * per-transfer overheads (by making fewer transfers). - */ - if (spi->master->flags & SPI_MASTER_HALF_DUPLEX) - return -EINVAL; - - /* MMC and SD specs only seem to care that sampling is on the - * rising edge ... meaning SPI modes 0 or 3. So either SPI mode - * should be legit. We'll use mode 0 since the steady state is 0, - * which is appropriate for hotplugging, unless the platform data - * specify mode 3 (if hardware is not compatible to mode 0). - */ - if (spi->mode != SPI_MODE_3) - spi->mode = SPI_MODE_0; - spi->bits_per_word = 8; - - status = spi_setup(spi); - if (status < 0) { - dev_dbg(&spi->dev, "needs SPI mode %02x, %d KHz; %d\n", - spi->mode, spi->max_speed_hz / 1000, - status); - return status; - } - - /* We need a supply of ones to transmit. This is the only time - * the CPU touches these, so cache coherency isn't a concern. - * - * NOTE if many systems use more than one MMC-over-SPI connector - * it'd save some memory to share this. That's evidently rare. - */ - status = -ENOMEM; - ones = kmalloc(MMC_SPI_BLOCKSIZE, GFP_KERNEL); - if (!ones) - goto nomem; - memset(ones, 0xff, MMC_SPI_BLOCKSIZE); - - mmc = mmc_alloc_host(sizeof(*host), &spi->dev); - if (!mmc) - goto nomem; - - mmc->ops = &mmc_spi_ops; - mmc->max_blk_size = MMC_SPI_BLOCKSIZE; - mmc->max_segs = MMC_SPI_BLOCKSATONCE; - mmc->max_req_size = MMC_SPI_BLOCKSATONCE * MMC_SPI_BLOCKSIZE; - mmc->max_blk_count = MMC_SPI_BLOCKSATONCE; - - mmc->caps = MMC_CAP_SPI; - - /* SPI doesn't need the lowspeed device identification thing for - * MMC or SD cards, since it never comes up in open drain mode. - * That's good; some SPI masters can't handle very low speeds! - * - * However, low speed SDIO cards need not handle over 400 KHz; - * that's the only reason not to use a few MHz for f_min (until - * the upper layer reads the target frequency from the CSD). - */ - mmc->f_min = 400000; - mmc->f_max = spi->max_speed_hz; - - host = mmc_priv(mmc); - host->mmc = mmc; - host->spi = spi; - - host->ones = ones; - - /* Platform data is used to hook up things like card sensing - * and power switching gpios. - */ - host->pdata = mmc_spi_get_pdata(spi); - if (host->pdata) - mmc->ocr_avail = host->pdata->ocr_mask; - if (!mmc->ocr_avail) { - dev_warn(&spi->dev, "ASSUMING 3.2-3.4 V slot power\n"); - mmc->ocr_avail = MMC_VDD_32_33|MMC_VDD_33_34; - } - if (host->pdata && host->pdata->setpower) { - host->powerup_msecs = host->pdata->powerup_msecs; - if (!host->powerup_msecs || host->powerup_msecs > 250) - host->powerup_msecs = 250; - } - - dev_set_drvdata(&spi->dev, mmc); - - /* preallocate dma buffers */ - host->data = kmalloc(sizeof(*host->data), GFP_KERNEL); - if (!host->data) - goto fail_nobuf1; - - if (spi->master->dev.parent->dma_mask) { - struct device *dev = spi->master->dev.parent; - - host->dma_dev = dev; - host->ones_dma = dma_map_single(dev, ones, - MMC_SPI_BLOCKSIZE, DMA_TO_DEVICE); - host->data_dma = dma_map_single(dev, host->data, - sizeof(*host->data), DMA_BIDIRECTIONAL); - - /* REVISIT in theory those map operations can fail... */ - - dma_sync_single_for_cpu(host->dma_dev, - host->data_dma, sizeof(*host->data), - DMA_BIDIRECTIONAL); - } - - /* setup message for status/busy readback */ - spi_message_init(&host->readback); - host->readback.is_dma_mapped = (host->dma_dev != NULL); - - spi_message_add_tail(&host->status, &host->readback); - host->status.tx_buf = host->ones; - host->status.tx_dma = host->ones_dma; - host->status.rx_buf = &host->data->status; - host->status.rx_dma = host->data_dma + offsetof(struct scratch, status); - host->status.cs_change = 1; - - /* register card detect irq */ - if (host->pdata && host->pdata->init) { - status = host->pdata->init(&spi->dev, mmc_spi_detect_irq, mmc); - if (status != 0) - goto fail_glue_init; - } - - /* pass platform capabilities, if any */ - if (host->pdata) - mmc->caps |= host->pdata->caps; - - status = mmc_add_host(mmc); - if (status != 0) - goto fail_add_host; - - dev_info(&spi->dev, "SD/MMC host %s%s%s%s%s\n", - dev_name(&mmc->class_dev), - host->dma_dev ? "" : ", no DMA", - (host->pdata && host->pdata->get_ro) - ? "" : ", no WP", - (host->pdata && host->pdata->setpower) - ? "" : ", no poweroff", - (mmc->caps & MMC_CAP_NEEDS_POLL) - ? ", cd polling" : ""); - return 0; - -fail_add_host: - mmc_remove_host (mmc); -fail_glue_init: - if (host->dma_dev) - dma_unmap_single(host->dma_dev, host->data_dma, - sizeof(*host->data), DMA_BIDIRECTIONAL); - kfree(host->data); - -fail_nobuf1: - mmc_free_host(mmc); - mmc_spi_put_pdata(spi); - dev_set_drvdata(&spi->dev, NULL); - -nomem: - kfree(ones); - return status; -} - - -static int __devexit mmc_spi_remove(struct spi_device *spi) -{ - struct mmc_host *mmc = dev_get_drvdata(&spi->dev); - struct mmc_spi_host *host; - - if (mmc) { - host = mmc_priv(mmc); - - /* prevent new mmc_detect_change() calls */ - if (host->pdata && host->pdata->exit) - host->pdata->exit(&spi->dev, mmc); - - mmc_remove_host(mmc); - - if (host->dma_dev) { - dma_unmap_single(host->dma_dev, host->ones_dma, - MMC_SPI_BLOCKSIZE, DMA_TO_DEVICE); - dma_unmap_single(host->dma_dev, host->data_dma, - sizeof(*host->data), DMA_BIDIRECTIONAL); - } - - kfree(host->data); - kfree(host->ones); - - spi->max_speed_hz = mmc->f_max; - mmc_free_host(mmc); - mmc_spi_put_pdata(spi); - dev_set_drvdata(&spi->dev, NULL); - } - return 0; -} - -static struct of_device_id mmc_spi_of_match_table[] __devinitdata = { - { .compatible = "mmc-spi-slot", }, - {}, -}; - -static struct spi_driver mmc_spi_driver = { - .driver = { - .name = "mmc_spi", - .owner = THIS_MODULE, - .of_match_table = mmc_spi_of_match_table, - }, - .probe = mmc_spi_probe, - .remove = __devexit_p(mmc_spi_remove), -}; - - -static int __init mmc_spi_init(void) -{ - return spi_register_driver(&mmc_spi_driver); -} -module_init(mmc_spi_init); - - -static void __exit mmc_spi_exit(void) -{ - spi_unregister_driver(&mmc_spi_driver); -} -module_exit(mmc_spi_exit); - - -MODULE_AUTHOR("Mike Lavender, David Brownell, " - "Hans-Peter Nilsson, Jan Nikitenko"); -MODULE_DESCRIPTION("SPI SD/MMC host driver"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("spi:mmc_spi"); diff --git a/ANDROID_3.4.5/drivers/mmc/host/mmci.c b/ANDROID_3.4.5/drivers/mmc/host/mmci.c deleted file mode 100644 index 032b8479..00000000 --- a/ANDROID_3.4.5/drivers/mmc/host/mmci.c +++ /dev/null @@ -1,1606 +0,0 @@ -/* - * linux/drivers/mmc/host/mmci.c - ARM PrimeCell MMCI PL180/1 driver - * - * Copyright (C) 2003 Deep Blue Solutions, Ltd, All Rights Reserved. - * Copyright (C) 2010 ST-Ericsson SA - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ -#include <linux/module.h> -#include <linux/moduleparam.h> -#include <linux/init.h> -#include <linux/ioport.h> -#include <linux/device.h> -#include <linux/interrupt.h> -#include <linux/kernel.h> -#include <linux/delay.h> -#include <linux/err.h> -#include <linux/highmem.h> -#include <linux/log2.h> -#include <linux/mmc/host.h> -#include <linux/mmc/card.h> -#include <linux/amba/bus.h> -#include <linux/clk.h> -#include <linux/scatterlist.h> -#include <linux/gpio.h> -#include <linux/regulator/consumer.h> -#include <linux/dmaengine.h> -#include <linux/dma-mapping.h> -#include <linux/amba/mmci.h> -#include <linux/pm_runtime.h> -#include <linux/types.h> - -#include <asm/div64.h> -#include <asm/io.h> -#include <asm/sizes.h> - -#include "mmci.h" - -#define DRIVER_NAME "mmci-pl18x" - -static unsigned int fmax = 515633; - -/** - * struct variant_data - MMCI variant-specific quirks - * @clkreg: default value for MCICLOCK register - * @clkreg_enable: enable value for MMCICLOCK register - * @datalength_bits: number of bits in the MMCIDATALENGTH register - * @fifosize: number of bytes that can be written when MMCI_TXFIFOEMPTY - * is asserted (likewise for RX) - * @fifohalfsize: number of bytes that can be written when MCI_TXFIFOHALFEMPTY - * is asserted (likewise for RX) - * @sdio: variant supports SDIO - * @st_clkdiv: true if using a ST-specific clock divider algorithm - * @blksz_datactrl16: true if Block size is at b16..b30 position in datactrl register - * @pwrreg_powerup: power up value for MMCIPOWER register - * @signal_direction: input/out direction of bus signals can be indicated - */ -struct variant_data { - unsigned int clkreg; - unsigned int clkreg_enable; - unsigned int datalength_bits; - unsigned int fifosize; - unsigned int fifohalfsize; - bool sdio; - bool st_clkdiv; - bool blksz_datactrl16; - u32 pwrreg_powerup; - bool signal_direction; -}; - -static struct variant_data variant_arm = { - .fifosize = 16 * 4, - .fifohalfsize = 8 * 4, - .datalength_bits = 16, - .pwrreg_powerup = MCI_PWR_UP, -}; - -static struct variant_data variant_arm_extended_fifo = { - .fifosize = 128 * 4, - .fifohalfsize = 64 * 4, - .datalength_bits = 16, - .pwrreg_powerup = MCI_PWR_UP, -}; - -static struct variant_data variant_u300 = { - .fifosize = 16 * 4, - .fifohalfsize = 8 * 4, - .clkreg_enable = MCI_ST_U300_HWFCEN, - .datalength_bits = 16, - .sdio = true, - .pwrreg_powerup = MCI_PWR_ON, - .signal_direction = true, -}; - -static struct variant_data variant_ux500 = { - .fifosize = 30 * 4, - .fifohalfsize = 8 * 4, - .clkreg = MCI_CLK_ENABLE, - .clkreg_enable = MCI_ST_UX500_HWFCEN, - .datalength_bits = 24, - .sdio = true, - .st_clkdiv = true, - .pwrreg_powerup = MCI_PWR_ON, - .signal_direction = true, -}; - -static struct variant_data variant_ux500v2 = { - .fifosize = 30 * 4, - .fifohalfsize = 8 * 4, - .clkreg = MCI_CLK_ENABLE, - .clkreg_enable = MCI_ST_UX500_HWFCEN, - .datalength_bits = 24, - .sdio = true, - .st_clkdiv = true, - .blksz_datactrl16 = true, - .pwrreg_powerup = MCI_PWR_ON, - .signal_direction = true, -}; - -/* - * This must be called with host->lock held - */ -static void mmci_write_clkreg(struct mmci_host *host, u32 clk) -{ - if (host->clk_reg != clk) { - host->clk_reg = clk; - writel(clk, host->base + MMCICLOCK); - } -} - -/* - * This must be called with host->lock held - */ -static void mmci_write_pwrreg(struct mmci_host *host, u32 pwr) -{ - if (host->pwr_reg != pwr) { - host->pwr_reg = pwr; - writel(pwr, host->base + MMCIPOWER); - } -} - -/* - * This must be called with host->lock held - */ -static void mmci_set_clkreg(struct mmci_host *host, unsigned int desired) -{ - struct variant_data *variant = host->variant; - u32 clk = variant->clkreg; - - if (desired) { - if (desired >= host->mclk) { - clk = MCI_CLK_BYPASS; - if (variant->st_clkdiv) - clk |= MCI_ST_UX500_NEG_EDGE; - host->cclk = host->mclk; - } else if (variant->st_clkdiv) { - /* - * DB8500 TRM says f = mclk / (clkdiv + 2) - * => clkdiv = (mclk / f) - 2 - * Round the divider up so we don't exceed the max - * frequency - */ - clk = DIV_ROUND_UP(host->mclk, desired) - 2; - if (clk >= 256) - clk = 255; - host->cclk = host->mclk / (clk + 2); - } else { - /* - * PL180 TRM says f = mclk / (2 * (clkdiv + 1)) - * => clkdiv = mclk / (2 * f) - 1 - */ - clk = host->mclk / (2 * desired) - 1; - if (clk >= 256) - clk = 255; - host->cclk = host->mclk / (2 * (clk + 1)); - } - - clk |= variant->clkreg_enable; - clk |= MCI_CLK_ENABLE; - /* This hasn't proven to be worthwhile */ - /* clk |= MCI_CLK_PWRSAVE; */ - } - - if (host->mmc->ios.bus_width == MMC_BUS_WIDTH_4) - clk |= MCI_4BIT_BUS; - if (host->mmc->ios.bus_width == MMC_BUS_WIDTH_8) - clk |= MCI_ST_8BIT_BUS; - - mmci_write_clkreg(host, clk); -} - -static void -mmci_request_end(struct mmci_host *host, struct mmc_request *mrq) -{ - writel(0, host->base + MMCICOMMAND); - - BUG_ON(host->data); - - host->mrq = NULL; - host->cmd = NULL; - - mmc_request_done(host->mmc, mrq); - - pm_runtime_mark_last_busy(mmc_dev(host->mmc)); - pm_runtime_put_autosuspend(mmc_dev(host->mmc)); -} - -static void mmci_set_mask1(struct mmci_host *host, unsigned int mask) -{ - void __iomem *base = host->base; - - if (host->singleirq) { - unsigned int mask0 = readl(base + MMCIMASK0); - - mask0 &= ~MCI_IRQ1MASK; - mask0 |= mask; - - writel(mask0, base + MMCIMASK0); - } - - writel(mask, base + MMCIMASK1); -} - -static void mmci_stop_data(struct mmci_host *host) -{ - writel(0, host->base + MMCIDATACTRL); - mmci_set_mask1(host, 0); - host->data = NULL; -} - -static void mmci_init_sg(struct mmci_host *host, struct mmc_data *data) -{ - unsigned int flags = SG_MITER_ATOMIC; - - if (data->flags & MMC_DATA_READ) - flags |= SG_MITER_TO_SG; - else - flags |= SG_MITER_FROM_SG; - - sg_miter_start(&host->sg_miter, data->sg, data->sg_len, flags); -} - -/* - * All the DMA operation mode stuff goes inside this ifdef. - * This assumes that you have a generic DMA device interface, - * no custom DMA interfaces are supported. - */ -#ifdef CONFIG_DMA_ENGINE -static void __devinit mmci_dma_setup(struct mmci_host *host) -{ - struct mmci_platform_data *plat = host->plat; - const char *rxname, *txname; - dma_cap_mask_t mask; - - if (!plat || !plat->dma_filter) { - dev_info(mmc_dev(host->mmc), "no DMA platform data\n"); - return; - } - - /* initialize pre request cookie */ - host->next_data.cookie = 1; - - /* Try to acquire a generic DMA engine slave channel */ - dma_cap_zero(mask); - dma_cap_set(DMA_SLAVE, mask); - - /* - * If only an RX channel is specified, the driver will - * attempt to use it bidirectionally, however if it is - * is specified but cannot be located, DMA will be disabled. - */ - if (plat->dma_rx_param) { - host->dma_rx_channel = dma_request_channel(mask, - plat->dma_filter, - plat->dma_rx_param); - /* E.g if no DMA hardware is present */ - if (!host->dma_rx_channel) - dev_err(mmc_dev(host->mmc), "no RX DMA channel\n"); - } - - if (plat->dma_tx_param) { - host->dma_tx_channel = dma_request_channel(mask, - plat->dma_filter, - plat->dma_tx_param); - if (!host->dma_tx_channel) - dev_warn(mmc_dev(host->mmc), "no TX DMA channel\n"); - } else { - host->dma_tx_channel = host->dma_rx_channel; - } - - if (host->dma_rx_channel) - rxname = dma_chan_name(host->dma_rx_channel); - else - rxname = "none"; - - if (host->dma_tx_channel) - txname = dma_chan_name(host->dma_tx_channel); - else - txname = "none"; - - dev_info(mmc_dev(host->mmc), "DMA channels RX %s, TX %s\n", - rxname, txname); - - /* - * Limit the maximum segment size in any SG entry according to - * the parameters of the DMA engine device. - */ - if (host->dma_tx_channel) { - struct device *dev = host->dma_tx_channel->device->dev; - unsigned int max_seg_size = dma_get_max_seg_size(dev); - - if (max_seg_size < host->mmc->max_seg_size) - host->mmc->max_seg_size = max_seg_size; - } - if (host->dma_rx_channel) { - struct device *dev = host->dma_rx_channel->device->dev; - unsigned int max_seg_size = dma_get_max_seg_size(dev); - - if (max_seg_size < host->mmc->max_seg_size) - host->mmc->max_seg_size = max_seg_size; - } -} - -/* - * This is used in __devinit or __devexit so inline it - * so it can be discarded. - */ -static inline void mmci_dma_release(struct mmci_host *host) -{ - struct mmci_platform_data *plat = host->plat; - - if (host->dma_rx_channel) - dma_release_channel(host->dma_rx_channel); - if (host->dma_tx_channel && plat->dma_tx_param) - dma_release_channel(host->dma_tx_channel); - host->dma_rx_channel = host->dma_tx_channel = NULL; -} - -static void mmci_dma_unmap(struct mmci_host *host, struct mmc_data *data) -{ - struct dma_chan *chan = host->dma_current; - enum dma_data_direction dir; - u32 status; - int i; - - /* Wait up to 1ms for the DMA to complete */ - for (i = 0; ; i++) { - status = readl(host->base + MMCISTATUS); - if (!(status & MCI_RXDATAAVLBLMASK) || i >= 100) - break; - udelay(10); - } - - /* - * Check to see whether we still have some data left in the FIFO - - * this catches DMA controllers which are unable to monitor the - * DMALBREQ and DMALSREQ signals while allowing us to DMA to non- - * contiguous buffers. On TX, we'll get a FIFO underrun error. - */ - if (status & MCI_RXDATAAVLBLMASK) { - dmaengine_terminate_all(chan); - if (!data->error) - data->error = -EIO; - } - - if (data->flags & MMC_DATA_WRITE) { - dir = DMA_TO_DEVICE; - } else { - dir = DMA_FROM_DEVICE; - } - - if (!data->host_cookie) - dma_unmap_sg(chan->device->dev, data->sg, data->sg_len, dir); - - /* - * Use of DMA with scatter-gather is impossible. - * Give up with DMA and switch back to PIO mode. - */ - if (status & MCI_RXDATAAVLBLMASK) { - dev_err(mmc_dev(host->mmc), "buggy DMA detected. Taking evasive action.\n"); - mmci_dma_release(host); - } -} - -static void mmci_dma_data_error(struct mmci_host *host) -{ - dev_err(mmc_dev(host->mmc), "error during DMA transfer!\n"); - dmaengine_terminate_all(host->dma_current); -} - -static int mmci_dma_prep_data(struct mmci_host *host, struct mmc_data *data, - struct mmci_host_next *next) -{ - struct variant_data *variant = host->variant; - struct dma_slave_config conf = { - .src_addr = host->phybase + MMCIFIFO, - .dst_addr = host->phybase + MMCIFIFO, - .src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES, - .dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES, - .src_maxburst = variant->fifohalfsize >> 2, /* # of words */ - .dst_maxburst = variant->fifohalfsize >> 2, /* # of words */ - .device_fc = false, - }; - struct dma_chan *chan; - struct dma_device *device; - struct dma_async_tx_descriptor *desc; - enum dma_data_direction buffer_dirn; - int nr_sg; - - /* Check if next job is already prepared */ - if (data->host_cookie && !next && - host->dma_current && host->dma_desc_current) - return 0; - - if (!next) { - host->dma_current = NULL; - host->dma_desc_current = NULL; - } - - if (data->flags & MMC_DATA_READ) { - conf.direction = DMA_DEV_TO_MEM; - buffer_dirn = DMA_FROM_DEVICE; - chan = host->dma_rx_channel; - } else { - conf.direction = DMA_MEM_TO_DEV; - buffer_dirn = DMA_TO_DEVICE; - chan = host->dma_tx_channel; - } - - /* If there's no DMA channel, fall back to PIO */ - if (!chan) - return -EINVAL; - - /* If less than or equal to the fifo size, don't bother with DMA */ - if (data->blksz * data->blocks <= variant->fifosize) - return -EINVAL; - - device = chan->device; - nr_sg = dma_map_sg(device->dev, data->sg, data->sg_len, buffer_dirn); - if (nr_sg == 0) - return -EINVAL; - - dmaengine_slave_config(chan, &conf); - desc = dmaengine_prep_slave_sg(chan, data->sg, nr_sg, - conf.direction, DMA_CTRL_ACK); - if (!desc) - goto unmap_exit; - - if (next) { - next->dma_chan = chan; - next->dma_desc = desc; - } else { - host->dma_current = chan; - host->dma_desc_current = desc; - } - - return 0; - - unmap_exit: - if (!next) - dmaengine_terminate_all(chan); - dma_unmap_sg(device->dev, data->sg, data->sg_len, buffer_dirn); - return -ENOMEM; -} - -static int mmci_dma_start_data(struct mmci_host *host, unsigned int datactrl) -{ - int ret; - struct mmc_data *data = host->data; - - ret = mmci_dma_prep_data(host, host->data, NULL); - if (ret) - return ret; - - /* Okay, go for it. */ - dev_vdbg(mmc_dev(host->mmc), - "Submit MMCI DMA job, sglen %d blksz %04x blks %04x flags %08x\n", - data->sg_len, data->blksz, data->blocks, data->flags); - dmaengine_submit(host->dma_desc_current); - dma_async_issue_pending(host->dma_current); - - datactrl |= MCI_DPSM_DMAENABLE; - - /* Trigger the DMA transfer */ - writel(datactrl, host->base + MMCIDATACTRL); - - /* - * Let the MMCI say when the data is ended and it's time - * to fire next DMA request. When that happens, MMCI will - * call mmci_data_end() - */ - writel(readl(host->base + MMCIMASK0) | MCI_DATAENDMASK, - host->base + MMCIMASK0); - return 0; -} - -static void mmci_get_next_data(struct mmci_host *host, struct mmc_data *data) -{ - struct mmci_host_next *next = &host->next_data; - - if (data->host_cookie && data->host_cookie != next->cookie) { - pr_warning("[%s] invalid cookie: data->host_cookie %d" - " host->next_data.cookie %d\n", - __func__, data->host_cookie, host->next_data.cookie); - data->host_cookie = 0; - } - - if (!data->host_cookie) - return; - - host->dma_desc_current = next->dma_desc; - host->dma_current = next->dma_chan; - - next->dma_desc = NULL; - next->dma_chan = NULL; -} - -static void mmci_pre_request(struct mmc_host *mmc, struct mmc_request *mrq, - bool is_first_req) -{ - struct mmci_host *host = mmc_priv(mmc); - struct mmc_data *data = mrq->data; - struct mmci_host_next *nd = &host->next_data; - - if (!data) - return; - - if (data->host_cookie) { - data->host_cookie = 0; - return; - } - - /* if config for dma */ - if (((data->flags & MMC_DATA_WRITE) && host->dma_tx_channel) || - ((data->flags & MMC_DATA_READ) && host->dma_rx_channel)) { - if (mmci_dma_prep_data(host, data, nd)) - data->host_cookie = 0; - else - data->host_cookie = ++nd->cookie < 0 ? 1 : nd->cookie; - } -} - -static void mmci_post_request(struct mmc_host *mmc, struct mmc_request *mrq, - int err) -{ - struct mmci_host *host = mmc_priv(mmc); - struct mmc_data *data = mrq->data; - struct dma_chan *chan; - enum dma_data_direction dir; - - if (!data) - return; - - if (data->flags & MMC_DATA_READ) { - dir = DMA_FROM_DEVICE; - chan = host->dma_rx_channel; - } else { - dir = DMA_TO_DEVICE; - chan = host->dma_tx_channel; - } - - - /* if config for dma */ - if (chan) { - if (err) - dmaengine_terminate_all(chan); - if (data->host_cookie) - dma_unmap_sg(mmc_dev(host->mmc), data->sg, - data->sg_len, dir); - mrq->data->host_cookie = 0; - } -} - -#else -/* Blank functions if the DMA engine is not available */ -static void mmci_get_next_data(struct mmci_host *host, struct mmc_data *data) -{ -} -static inline void mmci_dma_setup(struct mmci_host *host) -{ -} - -static inline void mmci_dma_release(struct mmci_host *host) -{ -} - -static inline void mmci_dma_unmap(struct mmci_host *host, struct mmc_data *data) -{ -} - -static inline void mmci_dma_data_error(struct mmci_host *host) -{ -} - -static inline int mmci_dma_start_data(struct mmci_host *host, unsigned int datactrl) -{ - return -ENOSYS; -} - -#define mmci_pre_request NULL -#define mmci_post_request NULL - -#endif - -static void mmci_start_data(struct mmci_host *host, struct mmc_data *data) -{ - struct variant_data *variant = host->variant; - unsigned int datactrl, timeout, irqmask; - unsigned long long clks; - void __iomem *base; - int blksz_bits; - - dev_dbg(mmc_dev(host->mmc), "blksz %04x blks %04x flags %08x\n", - data->blksz, data->blocks, data->flags); - - host->data = data; - host->size = data->blksz * data->blocks; - data->bytes_xfered = 0; - - clks = (unsigned long long)data->timeout_ns * host->cclk; - do_div(clks, 1000000000UL); - - timeout = data->timeout_clks + (unsigned int)clks; - - base = host->base; - writel(timeout, base + MMCIDATATIMER); - writel(host->size, base + MMCIDATALENGTH); - - blksz_bits = ffs(data->blksz) - 1; - BUG_ON(1 << blksz_bits != data->blksz); - - if (variant->blksz_datactrl16) - datactrl = MCI_DPSM_ENABLE | (data->blksz << 16); - else - datactrl = MCI_DPSM_ENABLE | blksz_bits << 4; - - if (data->flags & MMC_DATA_READ) - datactrl |= MCI_DPSM_DIRECTION; - - /* The ST Micro variants has a special bit to enable SDIO */ - if (variant->sdio && host->mmc->card) - if (mmc_card_sdio(host->mmc->card)) - datactrl |= MCI_ST_DPSM_SDIOEN; - - /* - * Attempt to use DMA operation mode, if this - * should fail, fall back to PIO mode - */ - if (!mmci_dma_start_data(host, datactrl)) - return; - - /* IRQ mode, map the SG list for CPU reading/writing */ - mmci_init_sg(host, data); - - if (data->flags & MMC_DATA_READ) { - irqmask = MCI_RXFIFOHALFFULLMASK; - - /* - * If we have less than the fifo 'half-full' threshold to - * transfer, trigger a PIO interrupt as soon as any data - * is available. - */ - if (host->size < variant->fifohalfsize) - irqmask |= MCI_RXDATAAVLBLMASK; - } else { - /* - * We don't actually need to include "FIFO empty" here - * since its implicit in "FIFO half empty". - */ - irqmask = MCI_TXFIFOHALFEMPTYMASK; - } - - writel(datactrl, base + MMCIDATACTRL); - writel(readl(base + MMCIMASK0) & ~MCI_DATAENDMASK, base + MMCIMASK0); - mmci_set_mask1(host, irqmask); -} - -static void -mmci_start_command(struct mmci_host *host, struct mmc_command *cmd, u32 c) -{ - void __iomem *base = host->base; - - dev_dbg(mmc_dev(host->mmc), "op %02x arg %08x flags %08x\n", - cmd->opcode, cmd->arg, cmd->flags); - - if (readl(base + MMCICOMMAND) & MCI_CPSM_ENABLE) { - writel(0, base + MMCICOMMAND); - udelay(1); - } - - c |= cmd->opcode | MCI_CPSM_ENABLE; - if (cmd->flags & MMC_RSP_PRESENT) { - if (cmd->flags & MMC_RSP_136) - c |= MCI_CPSM_LONGRSP; - c |= MCI_CPSM_RESPONSE; - } - if (/*interrupt*/0) - c |= MCI_CPSM_INTERRUPT; - - host->cmd = cmd; - - writel(cmd->arg, base + MMCIARGUMENT); - writel(c, base + MMCICOMMAND); -} - -static void -mmci_data_irq(struct mmci_host *host, struct mmc_data *data, - unsigned int status) -{ - /* First check for errors */ - if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_STARTBITERR| - MCI_TXUNDERRUN|MCI_RXOVERRUN)) { - u32 remain, success; - - /* Terminate the DMA transfer */ - if (dma_inprogress(host)) - mmci_dma_data_error(host); - - /* - * Calculate how far we are into the transfer. Note that - * the data counter gives the number of bytes transferred - * on the MMC bus, not on the host side. On reads, this - * can be as much as a FIFO-worth of data ahead. This - * matters for FIFO overruns only. - */ - remain = readl(host->base + MMCIDATACNT); - success = data->blksz * data->blocks - remain; - - dev_dbg(mmc_dev(host->mmc), "MCI ERROR IRQ, status 0x%08x at 0x%08x\n", - status, success); - if (status & MCI_DATACRCFAIL) { - /* Last block was not successful */ - success -= 1; - data->error = -EILSEQ; - } else if (status & MCI_DATATIMEOUT) { - data->error = -ETIMEDOUT; - } else if (status & MCI_STARTBITERR) { - data->error = -ECOMM; - } else if (status & MCI_TXUNDERRUN) { - data->error = -EIO; - } else if (status & MCI_RXOVERRUN) { - if (success > host->variant->fifosize) - success -= host->variant->fifosize; - else - success = 0; - data->error = -EIO; - } - data->bytes_xfered = round_down(success, data->blksz); - } - - if (status & MCI_DATABLOCKEND) - dev_err(mmc_dev(host->mmc), "stray MCI_DATABLOCKEND interrupt\n"); - - if (status & MCI_DATAEND || data->error) { - if (dma_inprogress(host)) - mmci_dma_unmap(host, data); - mmci_stop_data(host); - - if (!data->error) - /* The error clause is handled above, success! */ - data->bytes_xfered = data->blksz * data->blocks; - - if (!data->stop) { - mmci_request_end(host, data->mrq); - } else { - mmci_start_command(host, data->stop, 0); - } - } -} - -static void -mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd, - unsigned int status) -{ - void __iomem *base = host->base; - - host->cmd = NULL; - - if (status & MCI_CMDTIMEOUT) { - cmd->error = -ETIMEDOUT; - } else if (status & MCI_CMDCRCFAIL && cmd->flags & MMC_RSP_CRC) { - cmd->error = -EILSEQ; - } else { - cmd->resp[0] = readl(base + MMCIRESPONSE0); - cmd->resp[1] = readl(base + MMCIRESPONSE1); - cmd->resp[2] = readl(base + MMCIRESPONSE2); - cmd->resp[3] = readl(base + MMCIRESPONSE3); - } - - if (!cmd->data || cmd->error) { - if (host->data) { - /* Terminate the DMA transfer */ - if (dma_inprogress(host)) - mmci_dma_data_error(host); - mmci_stop_data(host); - } - mmci_request_end(host, cmd->mrq); - } else if (!(cmd->data->flags & MMC_DATA_READ)) { - mmci_start_data(host, cmd->data); - } -} - -static int mmci_pio_read(struct mmci_host *host, char *buffer, unsigned int remain) -{ - void __iomem *base = host->base; - char *ptr = buffer; - u32 status; - int host_remain = host->size; - - do { - int count = host_remain - (readl(base + MMCIFIFOCNT) << 2); - - if (count > remain) - count = remain; - - if (count <= 0) - break; - - /* - * SDIO especially may want to send something that is - * not divisible by 4 (as opposed to card sectors - * etc). Therefore make sure to always read the last bytes - * while only doing full 32-bit reads towards the FIFO. - */ - if (unlikely(count & 0x3)) { - if (count < 4) { - unsigned char buf[4]; - readsl(base + MMCIFIFO, buf, 1); - memcpy(ptr, buf, count); - } else { - readsl(base + MMCIFIFO, ptr, count >> 2); - count &= ~0x3; - } - } else { - readsl(base + MMCIFIFO, ptr, count >> 2); - } - - ptr += count; - remain -= count; - host_remain -= count; - - if (remain == 0) - break; - - status = readl(base + MMCISTATUS); - } while (status & MCI_RXDATAAVLBL); - - return ptr - buffer; -} - -static int mmci_pio_write(struct mmci_host *host, char *buffer, unsigned int remain, u32 status) -{ - struct variant_data *variant = host->variant; - void __iomem *base = host->base; - char *ptr = buffer; - - do { - unsigned int count, maxcnt; - - maxcnt = status & MCI_TXFIFOEMPTY ? - variant->fifosize : variant->fifohalfsize; - count = min(remain, maxcnt); - - /* - * The ST Micro variant for SDIO transfer sizes - * less then 8 bytes should have clock H/W flow - * control disabled. - */ - if (variant->sdio && - mmc_card_sdio(host->mmc->card)) { - u32 clk; - if (count < 8) - clk = host->clk_reg & ~variant->clkreg_enable; - else - clk = host->clk_reg | variant->clkreg_enable; - - mmci_write_clkreg(host, clk); - } - - /* - * SDIO especially may want to send something that is - * not divisible by 4 (as opposed to card sectors - * etc), and the FIFO only accept full 32-bit writes. - * So compensate by adding +3 on the count, a single - * byte become a 32bit write, 7 bytes will be two - * 32bit writes etc. - */ - writesl(base + MMCIFIFO, ptr, (count + 3) >> 2); - - ptr += count; - remain -= count; - - if (remain == 0) - break; - - status = readl(base + MMCISTATUS); - } while (status & MCI_TXFIFOHALFEMPTY); - - return ptr - buffer; -} - -/* - * PIO data transfer IRQ handler. - */ -static irqreturn_t mmci_pio_irq(int irq, void *dev_id) -{ - struct mmci_host *host = dev_id; - struct sg_mapping_iter *sg_miter = &host->sg_miter; - struct variant_data *variant = host->variant; - void __iomem *base = host->base; - unsigned long flags; - u32 status; - - status = readl(base + MMCISTATUS); - - dev_dbg(mmc_dev(host->mmc), "irq1 (pio) %08x\n", status); - - local_irq_save(flags); - - do { - unsigned int remain, len; - char *buffer; - - /* - * For write, we only need to test the half-empty flag - * here - if the FIFO is completely empty, then by - * definition it is more than half empty. - * - * For read, check for data available. - */ - if (!(status & (MCI_TXFIFOHALFEMPTY|MCI_RXDATAAVLBL))) - break; - - if (!sg_miter_next(sg_miter)) - break; - - buffer = sg_miter->addr; - remain = sg_miter->length; - - len = 0; - if (status & MCI_RXACTIVE) - len = mmci_pio_read(host, buffer, remain); - if (status & MCI_TXACTIVE) - len = mmci_pio_write(host, buffer, remain, status); - - sg_miter->consumed = len; - - host->size -= len; - remain -= len; - - if (remain) - break; - - status = readl(base + MMCISTATUS); - } while (1); - - sg_miter_stop(sg_miter); - - local_irq_restore(flags); - - /* - * If we have less than the fifo 'half-full' threshold to transfer, - * trigger a PIO interrupt as soon as any data is available. - */ - if (status & MCI_RXACTIVE && host->size < variant->fifohalfsize) - mmci_set_mask1(host, MCI_RXDATAAVLBLMASK); - - /* - * If we run out of data, disable the data IRQs; this - * prevents a race where the FIFO becomes empty before - * the chip itself has disabled the data path, and - * stops us racing with our data end IRQ. - */ - if (host->size == 0) { - mmci_set_mask1(host, 0); - writel(readl(base + MMCIMASK0) | MCI_DATAENDMASK, base + MMCIMASK0); - } - - return IRQ_HANDLED; -} - -/* - * Handle completion of command and data transfers. - */ -static irqreturn_t mmci_irq(int irq, void *dev_id) -{ - struct mmci_host *host = dev_id; - u32 status; - int ret = 0; - - spin_lock(&host->lock); - - do { - struct mmc_command *cmd; - struct mmc_data *data; - - status = readl(host->base + MMCISTATUS); - - if (host->singleirq) { - if (status & readl(host->base + MMCIMASK1)) - mmci_pio_irq(irq, dev_id); - - status &= ~MCI_IRQ1MASK; - } - - status &= readl(host->base + MMCIMASK0); - writel(status, host->base + MMCICLEAR); - - dev_dbg(mmc_dev(host->mmc), "irq0 (data+cmd) %08x\n", status); - - data = host->data; - if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_STARTBITERR| - MCI_TXUNDERRUN|MCI_RXOVERRUN|MCI_DATAEND| - MCI_DATABLOCKEND) && data) - mmci_data_irq(host, data, status); - - cmd = host->cmd; - if (status & (MCI_CMDCRCFAIL|MCI_CMDTIMEOUT|MCI_CMDSENT|MCI_CMDRESPEND) && cmd) - mmci_cmd_irq(host, cmd, status); - - ret = 1; - } while (status); - - spin_unlock(&host->lock); - - return IRQ_RETVAL(ret); -} - -static void mmci_request(struct mmc_host *mmc, struct mmc_request *mrq) -{ - struct mmci_host *host = mmc_priv(mmc); - unsigned long flags; - - WARN_ON(host->mrq != NULL); - - if (mrq->data && !is_power_of_2(mrq->data->blksz)) { - dev_err(mmc_dev(mmc), "unsupported block size (%d bytes)\n", - mrq->data->blksz); - mrq->cmd->error = -EINVAL; - mmc_request_done(mmc, mrq); - return; - } - - pm_runtime_get_sync(mmc_dev(mmc)); - - spin_lock_irqsave(&host->lock, flags); - - host->mrq = mrq; - - if (mrq->data) - mmci_get_next_data(host, mrq->data); - - if (mrq->data && mrq->data->flags & MMC_DATA_READ) - mmci_start_data(host, mrq->data); - - mmci_start_command(host, mrq->cmd, 0); - - spin_unlock_irqrestore(&host->lock, flags); -} - -static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) -{ - struct mmci_host *host = mmc_priv(mmc); - struct variant_data *variant = host->variant; - u32 pwr = 0; - unsigned long flags; - int ret; - - pm_runtime_get_sync(mmc_dev(mmc)); - - if (host->plat->ios_handler && - host->plat->ios_handler(mmc_dev(mmc), ios)) - dev_err(mmc_dev(mmc), "platform ios_handler failed\n"); - - switch (ios->power_mode) { - case MMC_POWER_OFF: - if (host->vcc) - ret = mmc_regulator_set_ocr(mmc, host->vcc, 0); - break; - case MMC_POWER_UP: - if (host->vcc) { - ret = mmc_regulator_set_ocr(mmc, host->vcc, ios->vdd); - if (ret) { - dev_err(mmc_dev(mmc), "unable to set OCR\n"); - /* - * The .set_ios() function in the mmc_host_ops - * struct return void, and failing to set the - * power should be rare so we print an error - * and return here. - */ - goto out; - } - } - /* - * The ST Micro variant doesn't have the PL180s MCI_PWR_UP - * and instead uses MCI_PWR_ON so apply whatever value is - * configured in the variant data. - */ - pwr |= variant->pwrreg_powerup; - - break; - case MMC_POWER_ON: - pwr |= MCI_PWR_ON; - break; - } - - if (variant->signal_direction && ios->power_mode != MMC_POWER_OFF) { - /* - * The ST Micro variant has some additional bits - * indicating signal direction for the signals in - * the SD/MMC bus and feedback-clock usage. - */ - pwr |= host->plat->sigdir; - - if (ios->bus_width == MMC_BUS_WIDTH_4) - pwr &= ~MCI_ST_DATA74DIREN; - else if (ios->bus_width == MMC_BUS_WIDTH_1) - pwr &= (~MCI_ST_DATA74DIREN & - ~MCI_ST_DATA31DIREN & - ~MCI_ST_DATA2DIREN); - } - - if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN) { - if (host->hw_designer != AMBA_VENDOR_ST) - pwr |= MCI_ROD; - else { - /* - * The ST Micro variant use the ROD bit for something - * else and only has OD (Open Drain). - */ - pwr |= MCI_OD; - } - } - - spin_lock_irqsave(&host->lock, flags); - - mmci_set_clkreg(host, ios->clock); - mmci_write_pwrreg(host, pwr); - - spin_unlock_irqrestore(&host->lock, flags); - - out: - pm_runtime_mark_last_busy(mmc_dev(mmc)); - pm_runtime_put_autosuspend(mmc_dev(mmc)); -} - -static int mmci_get_ro(struct mmc_host *mmc) -{ - struct mmci_host *host = mmc_priv(mmc); - - if (host->gpio_wp == -ENOSYS) - return -ENOSYS; - - return gpio_get_value_cansleep(host->gpio_wp); -} - -static int mmci_get_cd(struct mmc_host *mmc) -{ - struct mmci_host *host = mmc_priv(mmc); - struct mmci_platform_data *plat = host->plat; - unsigned int status; - - if (host->gpio_cd == -ENOSYS) { - if (!plat->status) - return 1; /* Assume always present */ - - status = plat->status(mmc_dev(host->mmc)); - } else - status = !!gpio_get_value_cansleep(host->gpio_cd) - ^ plat->cd_invert; - - /* - * Use positive logic throughout - status is zero for no card, - * non-zero for card inserted. - */ - return status; -} - -static irqreturn_t mmci_cd_irq(int irq, void *dev_id) -{ - struct mmci_host *host = dev_id; - - mmc_detect_change(host->mmc, msecs_to_jiffies(500)); - - return IRQ_HANDLED; -} - -static const struct mmc_host_ops mmci_ops = { - .request = mmci_request, - .pre_req = mmci_pre_request, - .post_req = mmci_post_request, - .set_ios = mmci_set_ios, - .get_ro = mmci_get_ro, - .get_cd = mmci_get_cd, -}; - -static int __devinit mmci_probe(struct amba_device *dev, - const struct amba_id *id) -{ - struct mmci_platform_data *plat = dev->dev.platform_data; - struct variant_data *variant = id->data; - struct mmci_host *host; - struct mmc_host *mmc; - int ret; - - /* must have platform data */ - if (!plat) { - ret = -EINVAL; - goto out; - } - - ret = amba_request_regions(dev, DRIVER_NAME); - if (ret) - goto out; - - mmc = mmc_alloc_host(sizeof(struct mmci_host), &dev->dev); - if (!mmc) { - ret = -ENOMEM; - goto rel_regions; - } - - host = mmc_priv(mmc); - host->mmc = mmc; - - host->gpio_wp = -ENOSYS; - host->gpio_cd = -ENOSYS; - host->gpio_cd_irq = -1; - - host->hw_designer = amba_manf(dev); - host->hw_revision = amba_rev(dev); - dev_dbg(mmc_dev(mmc), "designer ID = 0x%02x\n", host->hw_designer); - dev_dbg(mmc_dev(mmc), "revision = 0x%01x\n", host->hw_revision); - - host->clk = clk_get(&dev->dev, NULL); - if (IS_ERR(host->clk)) { - ret = PTR_ERR(host->clk); - host->clk = NULL; - goto host_free; - } - - ret = clk_prepare(host->clk); - if (ret) - goto clk_free; - - ret = clk_enable(host->clk); - if (ret) - goto clk_unprep; - - host->plat = plat; - host->variant = variant; - host->mclk = clk_get_rate(host->clk); - /* - * According to the spec, mclk is max 100 MHz, - * so we try to adjust the clock down to this, - * (if possible). - */ - if (host->mclk > 100000000) { - ret = clk_set_rate(host->clk, 100000000); - if (ret < 0) - goto clk_disable; - host->mclk = clk_get_rate(host->clk); - dev_dbg(mmc_dev(mmc), "eventual mclk rate: %u Hz\n", - host->mclk); - } - host->phybase = dev->res.start; - host->base = ioremap(dev->res.start, resource_size(&dev->res)); - if (!host->base) { - ret = -ENOMEM; - goto clk_disable; - } - - mmc->ops = &mmci_ops; - /* - * The ARM and ST versions of the block have slightly different - * clock divider equations which means that the minimum divider - * differs too. - */ - if (variant->st_clkdiv) - mmc->f_min = DIV_ROUND_UP(host->mclk, 257); - else - mmc->f_min = DIV_ROUND_UP(host->mclk, 512); - /* - * If the platform data supplies a maximum operating - * frequency, this takes precedence. Else, we fall back - * to using the module parameter, which has a (low) - * default value in case it is not specified. Either - * value must not exceed the clock rate into the block, - * of course. - */ - if (plat->f_max) - mmc->f_max = min(host->mclk, plat->f_max); - else - mmc->f_max = min(host->mclk, fmax); - dev_dbg(mmc_dev(mmc), "clocking block at %u Hz\n", mmc->f_max); - -#ifdef CONFIG_REGULATOR - /* If we're using the regulator framework, try to fetch a regulator */ - host->vcc = regulator_get(&dev->dev, "vmmc"); - if (IS_ERR(host->vcc)) - host->vcc = NULL; - else { - int mask = mmc_regulator_get_ocrmask(host->vcc); - - if (mask < 0) - dev_err(&dev->dev, "error getting OCR mask (%d)\n", - mask); - else { - host->mmc->ocr_avail = (u32) mask; - if (plat->ocr_mask) - dev_warn(&dev->dev, - "Provided ocr_mask/setpower will not be used " - "(using regulator instead)\n"); - } - } -#endif - /* Fall back to platform data if no regulator is found */ - if (host->vcc == NULL) - mmc->ocr_avail = plat->ocr_mask; - mmc->caps = plat->capabilities; - mmc->caps2 = plat->capabilities2; - - /* - * We can do SGIO - */ - mmc->max_segs = NR_SG; - - /* - * Since only a certain number of bits are valid in the data length - * register, we must ensure that we don't exceed 2^num-1 bytes in a - * single request. - */ - mmc->max_req_size = (1 << variant->datalength_bits) - 1; - - /* - * Set the maximum segment size. Since we aren't doing DMA - * (yet) we are only limited by the data length register. - */ - mmc->max_seg_size = mmc->max_req_size; - - /* - * Block size can be up to 2048 bytes, but must be a power of two. - */ - mmc->max_blk_size = 1 << 11; - - /* - * Limit the number of blocks transferred so that we don't overflow - * the maximum request size. - */ - mmc->max_blk_count = mmc->max_req_size >> 11; - - spin_lock_init(&host->lock); - - writel(0, host->base + MMCIMASK0); - writel(0, host->base + MMCIMASK1); - writel(0xfff, host->base + MMCICLEAR); - - if (gpio_is_valid(plat->gpio_cd)) { - ret = gpio_request(plat->gpio_cd, DRIVER_NAME " (cd)"); - if (ret == 0) - ret = gpio_direction_input(plat->gpio_cd); - if (ret == 0) - host->gpio_cd = plat->gpio_cd; - else if (ret != -ENOSYS) - goto err_gpio_cd; - - /* - * A gpio pin that will detect cards when inserted and removed - * will most likely want to trigger on the edges if it is - * 0 when ejected and 1 when inserted (or mutatis mutandis - * for the inverted case) so we request triggers on both - * edges. - */ - ret = request_any_context_irq(gpio_to_irq(plat->gpio_cd), - mmci_cd_irq, - IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, - DRIVER_NAME " (cd)", host); - if (ret >= 0) - host->gpio_cd_irq = gpio_to_irq(plat->gpio_cd); - } - if (gpio_is_valid(plat->gpio_wp)) { - ret = gpio_request(plat->gpio_wp, DRIVER_NAME " (wp)"); - if (ret == 0) - ret = gpio_direction_input(plat->gpio_wp); - if (ret == 0) - host->gpio_wp = plat->gpio_wp; - else if (ret != -ENOSYS) - goto err_gpio_wp; - } - - if ((host->plat->status || host->gpio_cd != -ENOSYS) - && host->gpio_cd_irq < 0) - mmc->caps |= MMC_CAP_NEEDS_POLL; - - ret = request_irq(dev->irq[0], mmci_irq, IRQF_SHARED, DRIVER_NAME " (cmd)", host); - if (ret) - goto unmap; - - if (dev->irq[1] == NO_IRQ || !dev->irq[1]) - host->singleirq = true; - else { - ret = request_irq(dev->irq[1], mmci_pio_irq, IRQF_SHARED, - DRIVER_NAME " (pio)", host); - if (ret) - goto irq0_free; - } - - writel(MCI_IRQENABLE, host->base + MMCIMASK0); - - amba_set_drvdata(dev, mmc); - - dev_info(&dev->dev, "%s: PL%03x manf %x rev%u at 0x%08llx irq %d,%d (pio)\n", - mmc_hostname(mmc), amba_part(dev), amba_manf(dev), - amba_rev(dev), (unsigned long long)dev->res.start, - dev->irq[0], dev->irq[1]); - - mmci_dma_setup(host); - - pm_runtime_set_autosuspend_delay(&dev->dev, 50); - pm_runtime_use_autosuspend(&dev->dev); - pm_runtime_put(&dev->dev); - - mmc_add_host(mmc); - - return 0; - - irq0_free: - free_irq(dev->irq[0], host); - unmap: - if (host->gpio_wp != -ENOSYS) - gpio_free(host->gpio_wp); - err_gpio_wp: - if (host->gpio_cd_irq >= 0) - free_irq(host->gpio_cd_irq, host); - if (host->gpio_cd != -ENOSYS) - gpio_free(host->gpio_cd); - err_gpio_cd: - iounmap(host->base); - clk_disable: - clk_disable(host->clk); - clk_unprep: - clk_unprepare(host->clk); - clk_free: - clk_put(host->clk); - host_free: - mmc_free_host(mmc); - rel_regions: - amba_release_regions(dev); - out: - return ret; -} - -static int __devexit mmci_remove(struct amba_device *dev) -{ - struct mmc_host *mmc = amba_get_drvdata(dev); - - amba_set_drvdata(dev, NULL); - - if (mmc) { - struct mmci_host *host = mmc_priv(mmc); - - /* - * Undo pm_runtime_put() in probe. We use the _sync - * version here so that we can access the primecell. - */ - pm_runtime_get_sync(&dev->dev); - - mmc_remove_host(mmc); - - writel(0, host->base + MMCIMASK0); - writel(0, host->base + MMCIMASK1); - - writel(0, host->base + MMCICOMMAND); - writel(0, host->base + MMCIDATACTRL); - - mmci_dma_release(host); - free_irq(dev->irq[0], host); - if (!host->singleirq) - free_irq(dev->irq[1], host); - - if (host->gpio_wp != -ENOSYS) - gpio_free(host->gpio_wp); - if (host->gpio_cd_irq >= 0) - free_irq(host->gpio_cd_irq, host); - if (host->gpio_cd != -ENOSYS) - gpio_free(host->gpio_cd); - - iounmap(host->base); - clk_disable(host->clk); - clk_unprepare(host->clk); - clk_put(host->clk); - - if (host->vcc) - mmc_regulator_set_ocr(mmc, host->vcc, 0); - regulator_put(host->vcc); - - mmc_free_host(mmc); - - amba_release_regions(dev); - } - - return 0; -} - -#ifdef CONFIG_SUSPEND -static int mmci_suspend(struct device *dev) -{ - struct amba_device *adev = to_amba_device(dev); - struct mmc_host *mmc = amba_get_drvdata(adev); - int ret = 0; - - if (mmc) { - struct mmci_host *host = mmc_priv(mmc); - - ret = mmc_suspend_host(mmc); - if (ret == 0) { - pm_runtime_get_sync(dev); - writel(0, host->base + MMCIMASK0); - } - } - - return ret; -} - -static int mmci_resume(struct device *dev) -{ - struct amba_device *adev = to_amba_device(dev); - struct mmc_host *mmc = amba_get_drvdata(adev); - int ret = 0; - - if (mmc) { - struct mmci_host *host = mmc_priv(mmc); - - writel(MCI_IRQENABLE, host->base + MMCIMASK0); - pm_runtime_put(dev); - - ret = mmc_resume_host(mmc); - } - - return ret; -} -#endif - -static const struct dev_pm_ops mmci_dev_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(mmci_suspend, mmci_resume) -}; - -static struct amba_id mmci_ids[] = { - { - .id = 0x00041180, - .mask = 0xff0fffff, - .data = &variant_arm, - }, - { - .id = 0x01041180, - .mask = 0xff0fffff, - .data = &variant_arm_extended_fifo, - }, - { - .id = 0x00041181, - .mask = 0x000fffff, - .data = &variant_arm, - }, - /* ST Micro variants */ - { - .id = 0x00180180, - .mask = 0x00ffffff, - .data = &variant_u300, - }, - { - .id = 0x00280180, - .mask = 0x00ffffff, - .data = &variant_u300, - }, - { - .id = 0x00480180, - .mask = 0xf0ffffff, - .data = &variant_ux500, - }, - { - .id = 0x10480180, - .mask = 0xf0ffffff, - .data = &variant_ux500v2, - }, - { 0, 0 }, -}; - -MODULE_DEVICE_TABLE(amba, mmci_ids); - -static struct amba_driver mmci_driver = { - .drv = { - .name = DRIVER_NAME, - .pm = &mmci_dev_pm_ops, - }, - .probe = mmci_probe, - .remove = __devexit_p(mmci_remove), - .id_table = mmci_ids, -}; - -module_amba_driver(mmci_driver); - -module_param(fmax, uint, 0444); - -MODULE_DESCRIPTION("ARM PrimeCell PL180/181 Multimedia Card Interface driver"); -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/mmc/host/mmci.h b/ANDROID_3.4.5/drivers/mmc/host/mmci.h deleted file mode 100644 index d437ccf6..00000000 --- a/ANDROID_3.4.5/drivers/mmc/host/mmci.h +++ /dev/null @@ -1,211 +0,0 @@ -/* - * linux/drivers/mmc/host/mmci.h - ARM PrimeCell MMCI PL180/1 driver - * - * Copyright (C) 2003 Deep Blue Solutions, Ltd, All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ -#define MMCIPOWER 0x000 -#define MCI_PWR_OFF 0x00 -#define MCI_PWR_UP 0x02 -#define MCI_PWR_ON 0x03 -#define MCI_OD (1 << 6) -#define MCI_ROD (1 << 7) - -#define MMCICLOCK 0x004 -#define MCI_CLK_ENABLE (1 << 8) -#define MCI_CLK_PWRSAVE (1 << 9) -#define MCI_CLK_BYPASS (1 << 10) -#define MCI_4BIT_BUS (1 << 11) -/* - * 8bit wide buses, hardware flow contronl, negative edges and clock inversion - * supported in ST Micro U300 and Ux500 versions - */ -#define MCI_ST_8BIT_BUS (1 << 12) -#define MCI_ST_U300_HWFCEN (1 << 13) -#define MCI_ST_UX500_NEG_EDGE (1 << 13) -#define MCI_ST_UX500_HWFCEN (1 << 14) -#define MCI_ST_UX500_CLK_INV (1 << 15) - -#define MMCIARGUMENT 0x008 -#define MMCICOMMAND 0x00c -#define MCI_CPSM_RESPONSE (1 << 6) -#define MCI_CPSM_LONGRSP (1 << 7) -#define MCI_CPSM_INTERRUPT (1 << 8) -#define MCI_CPSM_PENDING (1 << 9) -#define MCI_CPSM_ENABLE (1 << 10) -#define MCI_SDIO_SUSP (1 << 11) -#define MCI_ENCMD_COMPL (1 << 12) -#define MCI_NIEN (1 << 13) -#define MCI_CE_ATACMD (1 << 14) - -#define MMCIRESPCMD 0x010 -#define MMCIRESPONSE0 0x014 -#define MMCIRESPONSE1 0x018 -#define MMCIRESPONSE2 0x01c -#define MMCIRESPONSE3 0x020 -#define MMCIDATATIMER 0x024 -#define MMCIDATALENGTH 0x028 -#define MMCIDATACTRL 0x02c -#define MCI_DPSM_ENABLE (1 << 0) -#define MCI_DPSM_DIRECTION (1 << 1) -#define MCI_DPSM_MODE (1 << 2) -#define MCI_DPSM_DMAENABLE (1 << 3) -#define MCI_DPSM_BLOCKSIZE (1 << 4) -/* Control register extensions in the ST Micro U300 and Ux500 versions */ -#define MCI_ST_DPSM_RWSTART (1 << 8) -#define MCI_ST_DPSM_RWSTOP (1 << 9) -#define MCI_ST_DPSM_RWMOD (1 << 10) -#define MCI_ST_DPSM_SDIOEN (1 << 11) -/* Control register extensions in the ST Micro Ux500 versions */ -#define MCI_ST_DPSM_DMAREQCTL (1 << 12) -#define MCI_ST_DPSM_DBOOTMODEEN (1 << 13) -#define MCI_ST_DPSM_BUSYMODE (1 << 14) -#define MCI_ST_DPSM_DDRMODE (1 << 15) - -#define MMCIDATACNT 0x030 -#define MMCISTATUS 0x034 -#define MCI_CMDCRCFAIL (1 << 0) -#define MCI_DATACRCFAIL (1 << 1) -#define MCI_CMDTIMEOUT (1 << 2) -#define MCI_DATATIMEOUT (1 << 3) -#define MCI_TXUNDERRUN (1 << 4) -#define MCI_RXOVERRUN (1 << 5) -#define MCI_CMDRESPEND (1 << 6) -#define MCI_CMDSENT (1 << 7) -#define MCI_DATAEND (1 << 8) -#define MCI_STARTBITERR (1 << 9) -#define MCI_DATABLOCKEND (1 << 10) -#define MCI_CMDACTIVE (1 << 11) -#define MCI_TXACTIVE (1 << 12) -#define MCI_RXACTIVE (1 << 13) -#define MCI_TXFIFOHALFEMPTY (1 << 14) -#define MCI_RXFIFOHALFFULL (1 << 15) -#define MCI_TXFIFOFULL (1 << 16) -#define MCI_RXFIFOFULL (1 << 17) -#define MCI_TXFIFOEMPTY (1 << 18) -#define MCI_RXFIFOEMPTY (1 << 19) -#define MCI_TXDATAAVLBL (1 << 20) -#define MCI_RXDATAAVLBL (1 << 21) -/* Extended status bits for the ST Micro variants */ -#define MCI_ST_SDIOIT (1 << 22) -#define MCI_ST_CEATAEND (1 << 23) - -#define MMCICLEAR 0x038 -#define MCI_CMDCRCFAILCLR (1 << 0) -#define MCI_DATACRCFAILCLR (1 << 1) -#define MCI_CMDTIMEOUTCLR (1 << 2) -#define MCI_DATATIMEOUTCLR (1 << 3) -#define MCI_TXUNDERRUNCLR (1 << 4) -#define MCI_RXOVERRUNCLR (1 << 5) -#define MCI_CMDRESPENDCLR (1 << 6) -#define MCI_CMDSENTCLR (1 << 7) -#define MCI_DATAENDCLR (1 << 8) -#define MCI_STARTBITERRCLR (1 << 9) -#define MCI_DATABLOCKENDCLR (1 << 10) -/* Extended status bits for the ST Micro variants */ -#define MCI_ST_SDIOITC (1 << 22) -#define MCI_ST_CEATAENDC (1 << 23) - -#define MMCIMASK0 0x03c -#define MCI_CMDCRCFAILMASK (1 << 0) -#define MCI_DATACRCFAILMASK (1 << 1) -#define MCI_CMDTIMEOUTMASK (1 << 2) -#define MCI_DATATIMEOUTMASK (1 << 3) -#define MCI_TXUNDERRUNMASK (1 << 4) -#define MCI_RXOVERRUNMASK (1 << 5) -#define MCI_CMDRESPENDMASK (1 << 6) -#define MCI_CMDSENTMASK (1 << 7) -#define MCI_DATAENDMASK (1 << 8) -#define MCI_STARTBITERRMASK (1 << 9) -#define MCI_DATABLOCKENDMASK (1 << 10) -#define MCI_CMDACTIVEMASK (1 << 11) -#define MCI_TXACTIVEMASK (1 << 12) -#define MCI_RXACTIVEMASK (1 << 13) -#define MCI_TXFIFOHALFEMPTYMASK (1 << 14) -#define MCI_RXFIFOHALFFULLMASK (1 << 15) -#define MCI_TXFIFOFULLMASK (1 << 16) -#define MCI_RXFIFOFULLMASK (1 << 17) -#define MCI_TXFIFOEMPTYMASK (1 << 18) -#define MCI_RXFIFOEMPTYMASK (1 << 19) -#define MCI_TXDATAAVLBLMASK (1 << 20) -#define MCI_RXDATAAVLBLMASK (1 << 21) -/* Extended status bits for the ST Micro variants */ -#define MCI_ST_SDIOITMASK (1 << 22) -#define MCI_ST_CEATAENDMASK (1 << 23) - -#define MMCIMASK1 0x040 -#define MMCIFIFOCNT 0x048 -#define MMCIFIFO 0x080 /* to 0x0bc */ - -#define MCI_IRQENABLE \ - (MCI_CMDCRCFAILMASK|MCI_DATACRCFAILMASK|MCI_CMDTIMEOUTMASK| \ - MCI_DATATIMEOUTMASK|MCI_TXUNDERRUNMASK|MCI_RXOVERRUNMASK| \ - MCI_CMDRESPENDMASK|MCI_CMDSENTMASK|MCI_STARTBITERRMASK) - -/* These interrupts are directed to IRQ1 when two IRQ lines are available */ -#define MCI_IRQ1MASK \ - (MCI_RXFIFOHALFFULLMASK | MCI_RXDATAAVLBLMASK | \ - MCI_TXFIFOHALFEMPTYMASK) - -#define NR_SG 128 - -struct clk; -struct variant_data; -struct dma_chan; - -struct mmci_host_next { - struct dma_async_tx_descriptor *dma_desc; - struct dma_chan *dma_chan; - s32 cookie; -}; - -struct mmci_host { - phys_addr_t phybase; - void __iomem *base; - struct mmc_request *mrq; - struct mmc_command *cmd; - struct mmc_data *data; - struct mmc_host *mmc; - struct clk *clk; - int gpio_cd; - int gpio_wp; - int gpio_cd_irq; - bool singleirq; - - spinlock_t lock; - - unsigned int mclk; - unsigned int cclk; - u32 pwr_reg; - u32 clk_reg; - struct mmci_platform_data *plat; - struct variant_data *variant; - - u8 hw_designer; - u8 hw_revision:4; - - struct timer_list timer; - unsigned int oldstat; - - /* pio stuff */ - struct sg_mapping_iter sg_miter; - unsigned int size; - struct regulator *vcc; - -#ifdef CONFIG_DMA_ENGINE - /* DMA stuff */ - struct dma_chan *dma_current; - struct dma_chan *dma_rx_channel; - struct dma_chan *dma_tx_channel; - struct dma_async_tx_descriptor *dma_desc_current; - struct mmci_host_next next_data; - -#define dma_inprogress(host) ((host)->dma_current) -#else -#define dma_inprogress(host) (0) -#endif -}; - diff --git a/ANDROID_3.4.5/drivers/mmc/host/msm_sdcc.c b/ANDROID_3.4.5/drivers/mmc/host/msm_sdcc.c deleted file mode 100644 index 1d14cda9..00000000 --- a/ANDROID_3.4.5/drivers/mmc/host/msm_sdcc.c +++ /dev/null @@ -1,1486 +0,0 @@ -/* - * linux/drivers/mmc/host/msm_sdcc.c - Qualcomm MSM 7X00A SDCC Driver - * - * Copyright (C) 2007 Google Inc, - * Copyright (C) 2003 Deep Blue Solutions, Ltd, All Rights Reserved. - * Copyright (C) 2009, Code Aurora Forum. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Based on mmci.c - * - * Author: San Mehat (san@android.com) - * - */ - -#include <linux/module.h> -#include <linux/moduleparam.h> -#include <linux/init.h> -#include <linux/ioport.h> -#include <linux/device.h> -#include <linux/interrupt.h> -#include <linux/delay.h> -#include <linux/err.h> -#include <linux/highmem.h> -#include <linux/log2.h> -#include <linux/mmc/host.h> -#include <linux/mmc/card.h> -#include <linux/mmc/sdio.h> -#include <linux/clk.h> -#include <linux/scatterlist.h> -#include <linux/platform_device.h> -#include <linux/dma-mapping.h> -#include <linux/debugfs.h> -#include <linux/io.h> -#include <linux/memory.h> -#include <linux/gfp.h> -#include <linux/gpio.h> - -#include <asm/cacheflush.h> -#include <asm/div64.h> -#include <asm/sizes.h> - -#include <mach/mmc.h> -#include <mach/msm_iomap.h> -#include <mach/dma.h> -#include <mach/clk.h> - -#include "msm_sdcc.h" - -#define DRIVER_NAME "msm-sdcc" - -#define BUSCLK_PWRSAVE 1 -#define BUSCLK_TIMEOUT (HZ) -static unsigned int msmsdcc_fmin = 144000; -static unsigned int msmsdcc_fmax = 50000000; -static unsigned int msmsdcc_4bit = 1; -static unsigned int msmsdcc_pwrsave = 1; -static unsigned int msmsdcc_piopoll = 1; -static unsigned int msmsdcc_sdioirq; - -#define PIO_SPINMAX 30 -#define CMD_SPINMAX 20 - - -static inline void -msmsdcc_disable_clocks(struct msmsdcc_host *host, int deferr) -{ - WARN_ON(!host->clks_on); - - BUG_ON(host->curr.mrq); - - if (deferr) { - mod_timer(&host->busclk_timer, jiffies + BUSCLK_TIMEOUT); - } else { - del_timer_sync(&host->busclk_timer); - /* Need to check clks_on again in case the busclk - * timer fired - */ - if (host->clks_on) { - clk_disable(host->clk); - clk_disable(host->pclk); - host->clks_on = 0; - } - } -} - -static inline int -msmsdcc_enable_clocks(struct msmsdcc_host *host) -{ - int rc; - - del_timer_sync(&host->busclk_timer); - - if (!host->clks_on) { - rc = clk_enable(host->pclk); - if (rc) - return rc; - rc = clk_enable(host->clk); - if (rc) { - clk_disable(host->pclk); - return rc; - } - udelay(1 + ((3 * USEC_PER_SEC) / - (host->clk_rate ? host->clk_rate : msmsdcc_fmin))); - host->clks_on = 1; - } - return 0; -} - -static inline unsigned int -msmsdcc_readl(struct msmsdcc_host *host, unsigned int reg) -{ - return readl(host->base + reg); -} - -static inline void -msmsdcc_writel(struct msmsdcc_host *host, u32 data, unsigned int reg) -{ - writel(data, host->base + reg); - /* 3 clk delay required! */ - udelay(1 + ((3 * USEC_PER_SEC) / - (host->clk_rate ? host->clk_rate : msmsdcc_fmin))); -} - -static void -msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, - u32 c); - -static void msmsdcc_reset_and_restore(struct msmsdcc_host *host) -{ - u32 mci_clk = 0; - u32 mci_mask0 = 0; - int ret = 0; - - /* Save the controller state */ - mci_clk = readl(host->base + MMCICLOCK); - mci_mask0 = readl(host->base + MMCIMASK0); - - /* Reset the controller */ - ret = clk_reset(host->clk, CLK_RESET_ASSERT); - if (ret) - pr_err("%s: Clock assert failed at %u Hz with err %d\n", - mmc_hostname(host->mmc), host->clk_rate, ret); - - ret = clk_reset(host->clk, CLK_RESET_DEASSERT); - if (ret) - pr_err("%s: Clock deassert failed at %u Hz with err %d\n", - mmc_hostname(host->mmc), host->clk_rate, ret); - - pr_info("%s: Controller has been re-initialiazed\n", - mmc_hostname(host->mmc)); - - /* Restore the contoller state */ - writel(host->pwr, host->base + MMCIPOWER); - writel(mci_clk, host->base + MMCICLOCK); - writel(mci_mask0, host->base + MMCIMASK0); - ret = clk_set_rate(host->clk, host->clk_rate); - if (ret) - pr_err("%s: Failed to set clk rate %u Hz (%d)\n", - mmc_hostname(host->mmc), host->clk_rate, ret); -} - -static void -msmsdcc_request_end(struct msmsdcc_host *host, struct mmc_request *mrq) -{ - BUG_ON(host->curr.data); - - host->curr.mrq = NULL; - host->curr.cmd = NULL; - - if (mrq->data) - mrq->data->bytes_xfered = host->curr.data_xfered; - if (mrq->cmd->error == -ETIMEDOUT) - mdelay(5); - -#if BUSCLK_PWRSAVE - msmsdcc_disable_clocks(host, 1); -#endif - /* - * Need to drop the host lock here; mmc_request_done may call - * back into the driver... - */ - spin_unlock(&host->lock); - mmc_request_done(host->mmc, mrq); - spin_lock(&host->lock); -} - -static void -msmsdcc_stop_data(struct msmsdcc_host *host) -{ - host->curr.data = NULL; - host->curr.got_dataend = 0; -} - -uint32_t msmsdcc_fifo_addr(struct msmsdcc_host *host) -{ - return host->memres->start + MMCIFIFO; -} - -static inline void -msmsdcc_start_command_exec(struct msmsdcc_host *host, u32 arg, u32 c) { - msmsdcc_writel(host, arg, MMCIARGUMENT); - msmsdcc_writel(host, c, MMCICOMMAND); -} - -static void -msmsdcc_dma_exec_func(struct msm_dmov_cmd *cmd) -{ - struct msmsdcc_host *host = (struct msmsdcc_host *)cmd->data; - - msmsdcc_writel(host, host->cmd_timeout, MMCIDATATIMER); - msmsdcc_writel(host, (unsigned int)host->curr.xfer_size, - MMCIDATALENGTH); - msmsdcc_writel(host, (msmsdcc_readl(host, MMCIMASK0) & - (~MCI_IRQ_PIO)) | host->cmd_pio_irqmask, MMCIMASK0); - msmsdcc_writel(host, host->cmd_datactrl, MMCIDATACTRL); - - if (host->cmd_cmd) { - msmsdcc_start_command_exec(host, - (u32) host->cmd_cmd->arg, - (u32) host->cmd_c); - } - host->dma.active = 1; -} - -static void -msmsdcc_dma_complete_tlet(unsigned long data) -{ - struct msmsdcc_host *host = (struct msmsdcc_host *)data; - unsigned long flags; - struct mmc_request *mrq; - struct msm_dmov_errdata err; - - spin_lock_irqsave(&host->lock, flags); - host->dma.active = 0; - - err = host->dma.err; - mrq = host->curr.mrq; - BUG_ON(!mrq); - WARN_ON(!mrq->data); - - if (!(host->dma.result & DMOV_RSLT_VALID)) { - pr_err("msmsdcc: Invalid DataMover result\n"); - goto out; - } - - if (host->dma.result & DMOV_RSLT_DONE) { - host->curr.data_xfered = host->curr.xfer_size; - } else { - /* Error or flush */ - if (host->dma.result & DMOV_RSLT_ERROR) - pr_err("%s: DMA error (0x%.8x)\n", - mmc_hostname(host->mmc), host->dma.result); - if (host->dma.result & DMOV_RSLT_FLUSH) - pr_err("%s: DMA channel flushed (0x%.8x)\n", - mmc_hostname(host->mmc), host->dma.result); - - pr_err("Flush data: %.8x %.8x %.8x %.8x %.8x %.8x\n", - err.flush[0], err.flush[1], err.flush[2], - err.flush[3], err.flush[4], err.flush[5]); - - msmsdcc_reset_and_restore(host); - if (!mrq->data->error) - mrq->data->error = -EIO; - } - dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg, host->dma.num_ents, - host->dma.dir); - - host->dma.sg = NULL; - host->dma.busy = 0; - - if (host->curr.got_dataend || mrq->data->error) { - - /* - * If we've already gotten our DATAEND / DATABLKEND - * for this request, then complete it through here. - */ - msmsdcc_stop_data(host); - - if (!mrq->data->error) - host->curr.data_xfered = host->curr.xfer_size; - if (!mrq->data->stop || mrq->cmd->error) { - host->curr.mrq = NULL; - host->curr.cmd = NULL; - mrq->data->bytes_xfered = host->curr.data_xfered; - - spin_unlock_irqrestore(&host->lock, flags); -#if BUSCLK_PWRSAVE - msmsdcc_disable_clocks(host, 1); -#endif - mmc_request_done(host->mmc, mrq); - return; - } else - msmsdcc_start_command(host, mrq->data->stop, 0); - } - -out: - spin_unlock_irqrestore(&host->lock, flags); - return; -} - -static void -msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd, - unsigned int result, - struct msm_dmov_errdata *err) -{ - struct msmsdcc_dma_data *dma_data = - container_of(cmd, struct msmsdcc_dma_data, hdr); - struct msmsdcc_host *host = dma_data->host; - - dma_data->result = result; - if (err) - memcpy(&dma_data->err, err, sizeof(struct msm_dmov_errdata)); - - tasklet_schedule(&host->dma_tlet); -} - -static int validate_dma(struct msmsdcc_host *host, struct mmc_data *data) -{ - if (host->dma.channel == -1) - return -ENOENT; - - if ((data->blksz * data->blocks) < MCI_FIFOSIZE) - return -EINVAL; - if ((data->blksz * data->blocks) % MCI_FIFOSIZE) - return -EINVAL; - return 0; -} - -static int msmsdcc_config_dma(struct msmsdcc_host *host, struct mmc_data *data) -{ - struct msmsdcc_nc_dmadata *nc; - dmov_box *box; - uint32_t rows; - uint32_t crci; - unsigned int n; - int i, rc; - struct scatterlist *sg = data->sg; - - rc = validate_dma(host, data); - if (rc) - return rc; - - host->dma.sg = data->sg; - host->dma.num_ents = data->sg_len; - - BUG_ON(host->dma.num_ents > NR_SG); /* Prevent memory corruption */ - - nc = host->dma.nc; - - switch (host->pdev_id) { - case 1: - crci = MSMSDCC_CRCI_SDC1; - break; - case 2: - crci = MSMSDCC_CRCI_SDC2; - break; - case 3: - crci = MSMSDCC_CRCI_SDC3; - break; - case 4: - crci = MSMSDCC_CRCI_SDC4; - break; - default: - host->dma.sg = NULL; - host->dma.num_ents = 0; - return -ENOENT; - } - - if (data->flags & MMC_DATA_READ) - host->dma.dir = DMA_FROM_DEVICE; - else - host->dma.dir = DMA_TO_DEVICE; - - host->curr.user_pages = 0; - - box = &nc->cmd[0]; - - /* location of command block must be 64 bit aligned */ - BUG_ON(host->dma.cmd_busaddr & 0x07); - - nc->cmdptr = (host->dma.cmd_busaddr >> 3) | CMD_PTR_LP; - host->dma.hdr.cmdptr = DMOV_CMD_PTR_LIST | - DMOV_CMD_ADDR(host->dma.cmdptr_busaddr); - host->dma.hdr.complete_func = msmsdcc_dma_complete_func; - - n = dma_map_sg(mmc_dev(host->mmc), host->dma.sg, - host->dma.num_ents, host->dma.dir); - if (n == 0) { - pr_err("%s: Unable to map in all sg elements\n", - mmc_hostname(host->mmc)); - host->dma.sg = NULL; - host->dma.num_ents = 0; - return -ENOMEM; - } - - for_each_sg(host->dma.sg, sg, n, i) { - - box->cmd = CMD_MODE_BOX; - - if (i == n - 1) - box->cmd |= CMD_LC; - rows = (sg_dma_len(sg) % MCI_FIFOSIZE) ? - (sg_dma_len(sg) / MCI_FIFOSIZE) + 1 : - (sg_dma_len(sg) / MCI_FIFOSIZE) ; - - if (data->flags & MMC_DATA_READ) { - box->src_row_addr = msmsdcc_fifo_addr(host); - box->dst_row_addr = sg_dma_address(sg); - - box->src_dst_len = (MCI_FIFOSIZE << 16) | - (MCI_FIFOSIZE); - box->row_offset = MCI_FIFOSIZE; - - box->num_rows = rows * ((1 << 16) + 1); - box->cmd |= CMD_SRC_CRCI(crci); - } else { - box->src_row_addr = sg_dma_address(sg); - box->dst_row_addr = msmsdcc_fifo_addr(host); - - box->src_dst_len = (MCI_FIFOSIZE << 16) | - (MCI_FIFOSIZE); - box->row_offset = (MCI_FIFOSIZE << 16); - - box->num_rows = rows * ((1 << 16) + 1); - box->cmd |= CMD_DST_CRCI(crci); - } - box++; - } - - return 0; -} - -static int -snoop_cccr_abort(struct mmc_command *cmd) -{ - if ((cmd->opcode == 52) && - (cmd->arg & 0x80000000) && - (((cmd->arg >> 9) & 0x1ffff) == SDIO_CCCR_ABORT)) - return 1; - return 0; -} - -static void -msmsdcc_start_command_deferred(struct msmsdcc_host *host, - struct mmc_command *cmd, u32 *c) -{ - *c |= (cmd->opcode | MCI_CPSM_ENABLE); - - if (cmd->flags & MMC_RSP_PRESENT) { - if (cmd->flags & MMC_RSP_136) - *c |= MCI_CPSM_LONGRSP; - *c |= MCI_CPSM_RESPONSE; - } - - if (/*interrupt*/0) - *c |= MCI_CPSM_INTERRUPT; - - if ((((cmd->opcode == 17) || (cmd->opcode == 18)) || - ((cmd->opcode == 24) || (cmd->opcode == 25))) || - (cmd->opcode == 53)) - *c |= MCI_CSPM_DATCMD; - - if (host->prog_scan && (cmd->opcode == 12)) { - *c |= MCI_CPSM_PROGENA; - host->prog_enable = true; - } - - if (cmd == cmd->mrq->stop) - *c |= MCI_CSPM_MCIABORT; - - if (snoop_cccr_abort(cmd)) - *c |= MCI_CSPM_MCIABORT; - - if (host->curr.cmd != NULL) { - pr_err("%s: Overlapping command requests\n", - mmc_hostname(host->mmc)); - } - host->curr.cmd = cmd; -} - -static void -msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data, - struct mmc_command *cmd, u32 c) -{ - unsigned int datactrl, timeout; - unsigned long long clks; - unsigned int pio_irqmask = 0; - - host->curr.data = data; - host->curr.xfer_size = data->blksz * data->blocks; - host->curr.xfer_remain = host->curr.xfer_size; - host->curr.data_xfered = 0; - host->curr.got_dataend = 0; - - memset(&host->pio, 0, sizeof(host->pio)); - - datactrl = MCI_DPSM_ENABLE | (data->blksz << 4); - - if (!msmsdcc_config_dma(host, data)) - datactrl |= MCI_DPSM_DMAENABLE; - else { - host->pio.sg = data->sg; - host->pio.sg_len = data->sg_len; - host->pio.sg_off = 0; - - if (data->flags & MMC_DATA_READ) { - pio_irqmask = MCI_RXFIFOHALFFULLMASK; - if (host->curr.xfer_remain < MCI_FIFOSIZE) - pio_irqmask |= MCI_RXDATAAVLBLMASK; - } else - pio_irqmask = MCI_TXFIFOHALFEMPTYMASK; - } - - if (data->flags & MMC_DATA_READ) - datactrl |= MCI_DPSM_DIRECTION; - - clks = (unsigned long long)data->timeout_ns * host->clk_rate; - do_div(clks, NSEC_PER_SEC); - timeout = data->timeout_clks + (unsigned int)clks*2 ; - - if (datactrl & MCI_DPSM_DMAENABLE) { - /* Save parameters for the exec function */ - host->cmd_timeout = timeout; - host->cmd_pio_irqmask = pio_irqmask; - host->cmd_datactrl = datactrl; - host->cmd_cmd = cmd; - - host->dma.hdr.execute_func = msmsdcc_dma_exec_func; - host->dma.hdr.data = (void *)host; - host->dma.busy = 1; - - if (cmd) { - msmsdcc_start_command_deferred(host, cmd, &c); - host->cmd_c = c; - } - msm_dmov_enqueue_cmd(host->dma.channel, &host->dma.hdr); - if (data->flags & MMC_DATA_WRITE) - host->prog_scan = true; - } else { - msmsdcc_writel(host, timeout, MMCIDATATIMER); - - msmsdcc_writel(host, host->curr.xfer_size, MMCIDATALENGTH); - - msmsdcc_writel(host, (msmsdcc_readl(host, MMCIMASK0) & - (~MCI_IRQ_PIO)) | pio_irqmask, MMCIMASK0); - - msmsdcc_writel(host, datactrl, MMCIDATACTRL); - - if (cmd) { - /* Daisy-chain the command if requested */ - msmsdcc_start_command(host, cmd, c); - } - } -} - -static void -msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, u32 c) -{ - if (cmd == cmd->mrq->stop) - c |= MCI_CSPM_MCIABORT; - - host->stats.cmds++; - - msmsdcc_start_command_deferred(host, cmd, &c); - msmsdcc_start_command_exec(host, cmd->arg, c); -} - -static void -msmsdcc_data_err(struct msmsdcc_host *host, struct mmc_data *data, - unsigned int status) -{ - if (status & MCI_DATACRCFAIL) { - pr_err("%s: Data CRC error\n", mmc_hostname(host->mmc)); - pr_err("%s: opcode 0x%.8x\n", __func__, - data->mrq->cmd->opcode); - pr_err("%s: blksz %d, blocks %d\n", __func__, - data->blksz, data->blocks); - data->error = -EILSEQ; - } else if (status & MCI_DATATIMEOUT) { - pr_err("%s: Data timeout\n", mmc_hostname(host->mmc)); - data->error = -ETIMEDOUT; - } else if (status & MCI_RXOVERRUN) { - pr_err("%s: RX overrun\n", mmc_hostname(host->mmc)); - data->error = -EIO; - } else if (status & MCI_TXUNDERRUN) { - pr_err("%s: TX underrun\n", mmc_hostname(host->mmc)); - data->error = -EIO; - } else { - pr_err("%s: Unknown error (0x%.8x)\n", - mmc_hostname(host->mmc), status); - data->error = -EIO; - } -} - - -static int -msmsdcc_pio_read(struct msmsdcc_host *host, char *buffer, unsigned int remain) -{ - uint32_t *ptr = (uint32_t *) buffer; - int count = 0; - - if (remain % 4) - remain = ((remain >> 2) + 1) << 2; - - while (msmsdcc_readl(host, MMCISTATUS) & MCI_RXDATAAVLBL) { - *ptr = msmsdcc_readl(host, MMCIFIFO + (count % MCI_FIFOSIZE)); - ptr++; - count += sizeof(uint32_t); - - remain -= sizeof(uint32_t); - if (remain == 0) - break; - } - return count; -} - -static int -msmsdcc_pio_write(struct msmsdcc_host *host, char *buffer, - unsigned int remain, u32 status) -{ - void __iomem *base = host->base; - char *ptr = buffer; - - do { - unsigned int count, maxcnt, sz; - - maxcnt = status & MCI_TXFIFOEMPTY ? MCI_FIFOSIZE : - MCI_FIFOHALFSIZE; - count = min(remain, maxcnt); - - sz = count % 4 ? (count >> 2) + 1 : (count >> 2); - writesl(base + MMCIFIFO, ptr, sz); - ptr += count; - remain -= count; - - if (remain == 0) - break; - - status = msmsdcc_readl(host, MMCISTATUS); - } while (status & MCI_TXFIFOHALFEMPTY); - - return ptr - buffer; -} - -static int -msmsdcc_spin_on_status(struct msmsdcc_host *host, uint32_t mask, int maxspin) -{ - while (maxspin) { - if ((msmsdcc_readl(host, MMCISTATUS) & mask)) - return 0; - udelay(1); - --maxspin; - } - return -ETIMEDOUT; -} - -static irqreturn_t -msmsdcc_pio_irq(int irq, void *dev_id) -{ - struct msmsdcc_host *host = dev_id; - uint32_t status; - u32 mci_mask0; - - status = msmsdcc_readl(host, MMCISTATUS); - mci_mask0 = msmsdcc_readl(host, MMCIMASK0); - - if (((mci_mask0 & status) & MCI_IRQ_PIO) == 0) - return IRQ_NONE; - - do { - unsigned long flags; - unsigned int remain, len; - char *buffer; - - if (!(status & (MCI_TXFIFOHALFEMPTY | MCI_RXDATAAVLBL))) { - if (host->curr.xfer_remain == 0 || !msmsdcc_piopoll) - break; - - if (msmsdcc_spin_on_status(host, - (MCI_TXFIFOHALFEMPTY | - MCI_RXDATAAVLBL), - PIO_SPINMAX)) { - break; - } - } - - /* Map the current scatter buffer */ - local_irq_save(flags); - buffer = kmap_atomic(sg_page(host->pio.sg)) - + host->pio.sg->offset; - buffer += host->pio.sg_off; - remain = host->pio.sg->length - host->pio.sg_off; - len = 0; - if (status & MCI_RXACTIVE) - len = msmsdcc_pio_read(host, buffer, remain); - if (status & MCI_TXACTIVE) - len = msmsdcc_pio_write(host, buffer, remain, status); - - /* Unmap the buffer */ - kunmap_atomic(buffer); - local_irq_restore(flags); - - host->pio.sg_off += len; - host->curr.xfer_remain -= len; - host->curr.data_xfered += len; - remain -= len; - - if (remain == 0) { - /* This sg page is full - do some housekeeping */ - if (status & MCI_RXACTIVE && host->curr.user_pages) - flush_dcache_page(sg_page(host->pio.sg)); - - if (!--host->pio.sg_len) { - memset(&host->pio, 0, sizeof(host->pio)); - break; - } - - /* Advance to next sg */ - host->pio.sg++; - host->pio.sg_off = 0; - } - - status = msmsdcc_readl(host, MMCISTATUS); - } while (1); - - if (status & MCI_RXACTIVE && host->curr.xfer_remain < MCI_FIFOSIZE) - msmsdcc_writel(host, (mci_mask0 & (~MCI_IRQ_PIO)) | - MCI_RXDATAAVLBLMASK, MMCIMASK0); - - if (!host->curr.xfer_remain) - msmsdcc_writel(host, (mci_mask0 & (~MCI_IRQ_PIO)) | 0, - MMCIMASK0); - - return IRQ_HANDLED; -} - -static void msmsdcc_do_cmdirq(struct msmsdcc_host *host, uint32_t status) -{ - struct mmc_command *cmd = host->curr.cmd; - - host->curr.cmd = NULL; - cmd->resp[0] = msmsdcc_readl(host, MMCIRESPONSE0); - cmd->resp[1] = msmsdcc_readl(host, MMCIRESPONSE1); - cmd->resp[2] = msmsdcc_readl(host, MMCIRESPONSE2); - cmd->resp[3] = msmsdcc_readl(host, MMCIRESPONSE3); - - if (status & MCI_CMDTIMEOUT) { - cmd->error = -ETIMEDOUT; - } else if (status & MCI_CMDCRCFAIL && - cmd->flags & MMC_RSP_CRC) { - pr_err("%s: Command CRC error\n", mmc_hostname(host->mmc)); - cmd->error = -EILSEQ; - } - - if (!cmd->data || cmd->error) { - if (host->curr.data && host->dma.sg) - msm_dmov_stop_cmd(host->dma.channel, - &host->dma.hdr, 0); - else if (host->curr.data) { /* Non DMA */ - msmsdcc_reset_and_restore(host); - msmsdcc_stop_data(host); - msmsdcc_request_end(host, cmd->mrq); - } else { /* host->data == NULL */ - if (!cmd->error && host->prog_enable) { - if (status & MCI_PROGDONE) { - host->prog_scan = false; - host->prog_enable = false; - msmsdcc_request_end(host, cmd->mrq); - } else { - host->curr.cmd = cmd; - } - } else { - if (host->prog_enable) { - host->prog_scan = false; - host->prog_enable = false; - } - msmsdcc_request_end(host, cmd->mrq); - } - } - } else if (cmd->data) - if (!(cmd->data->flags & MMC_DATA_READ)) - msmsdcc_start_data(host, cmd->data, - NULL, 0); -} - -static void -msmsdcc_handle_irq_data(struct msmsdcc_host *host, u32 status, - void __iomem *base) -{ - struct mmc_data *data = host->curr.data; - - if (status & (MCI_CMDSENT | MCI_CMDRESPEND | MCI_CMDCRCFAIL | - MCI_CMDTIMEOUT | MCI_PROGDONE) && host->curr.cmd) { - msmsdcc_do_cmdirq(host, status); - } - - if (!data) - return; - - /* Check for data errors */ - if (status & (MCI_DATACRCFAIL | MCI_DATATIMEOUT | - MCI_TXUNDERRUN | MCI_RXOVERRUN)) { - msmsdcc_data_err(host, data, status); - host->curr.data_xfered = 0; - if (host->dma.sg) - msm_dmov_stop_cmd(host->dma.channel, - &host->dma.hdr, 0); - else { - msmsdcc_reset_and_restore(host); - if (host->curr.data) - msmsdcc_stop_data(host); - if (!data->stop) - msmsdcc_request_end(host, data->mrq); - else - msmsdcc_start_command(host, data->stop, 0); - } - } - - /* Check for data done */ - if (!host->curr.got_dataend && (status & MCI_DATAEND)) - host->curr.got_dataend = 1; - - /* - * If DMA is still in progress, we complete via the completion handler - */ - if (host->curr.got_dataend && !host->dma.busy) { - /* - * There appears to be an issue in the controller where - * if you request a small block transfer (< fifo size), - * you may get your DATAEND/DATABLKEND irq without the - * PIO data irq. - * - * Check to see if there is still data to be read, - * and simulate a PIO irq. - */ - if (readl(base + MMCISTATUS) & MCI_RXDATAAVLBL) - msmsdcc_pio_irq(1, host); - - msmsdcc_stop_data(host); - if (!data->error) - host->curr.data_xfered = host->curr.xfer_size; - - if (!data->stop) - msmsdcc_request_end(host, data->mrq); - else - msmsdcc_start_command(host, data->stop, 0); - } -} - -static irqreturn_t -msmsdcc_irq(int irq, void *dev_id) -{ - struct msmsdcc_host *host = dev_id; - void __iomem *base = host->base; - u32 status; - int ret = 0; - int cardint = 0; - - spin_lock(&host->lock); - - do { - status = msmsdcc_readl(host, MMCISTATUS); - status &= msmsdcc_readl(host, MMCIMASK0); - if ((status & (~MCI_IRQ_PIO)) == 0) - break; - msmsdcc_writel(host, status, MMCICLEAR); - - if (status & MCI_SDIOINTR) - status &= ~MCI_SDIOINTR; - - if (!status) - break; - - msmsdcc_handle_irq_data(host, status, base); - - if (status & MCI_SDIOINTOPER) { - cardint = 1; - status &= ~MCI_SDIOINTOPER; - } - ret = 1; - } while (status); - - spin_unlock(&host->lock); - - /* - * We have to delay handling the card interrupt as it calls - * back into the driver. - */ - if (cardint) - mmc_signal_sdio_irq(host->mmc); - - return IRQ_RETVAL(ret); -} - -static void -msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq) -{ - struct msmsdcc_host *host = mmc_priv(mmc); - unsigned long flags; - - WARN_ON(host->curr.mrq != NULL); - WARN_ON(host->pwr == 0); - - spin_lock_irqsave(&host->lock, flags); - - host->stats.reqs++; - - if (host->eject) { - if (mrq->data && !(mrq->data->flags & MMC_DATA_READ)) { - mrq->cmd->error = 0; - mrq->data->bytes_xfered = mrq->data->blksz * - mrq->data->blocks; - } else - mrq->cmd->error = -ENOMEDIUM; - - spin_unlock_irqrestore(&host->lock, flags); - mmc_request_done(mmc, mrq); - return; - } - - msmsdcc_enable_clocks(host); - - host->curr.mrq = mrq; - - if (mrq->data && mrq->data->flags & MMC_DATA_READ) - /* Queue/read data, daisy-chain command when data starts */ - msmsdcc_start_data(host, mrq->data, mrq->cmd, 0); - else - msmsdcc_start_command(host, mrq->cmd, 0); - - if (host->cmdpoll && !msmsdcc_spin_on_status(host, - MCI_CMDRESPEND|MCI_CMDCRCFAIL|MCI_CMDTIMEOUT, - CMD_SPINMAX)) { - uint32_t status = msmsdcc_readl(host, MMCISTATUS); - msmsdcc_do_cmdirq(host, status); - msmsdcc_writel(host, - MCI_CMDRESPEND | MCI_CMDCRCFAIL | MCI_CMDTIMEOUT, - MMCICLEAR); - host->stats.cmdpoll_hits++; - } else { - host->stats.cmdpoll_misses++; - } - spin_unlock_irqrestore(&host->lock, flags); -} - -static void msmsdcc_setup_gpio(struct msmsdcc_host *host, bool enable) -{ - struct msm_mmc_gpio_data *curr; - int i, rc = 0; - - if (!host->plat->gpio_data || host->gpio_config_status == enable) - return; - - curr = host->plat->gpio_data; - for (i = 0; i < curr->size; i++) { - if (enable) { - rc = gpio_request(curr->gpio[i].no, - curr->gpio[i].name); - if (rc) { - pr_err("%s: gpio_request(%d, %s) failed %d\n", - mmc_hostname(host->mmc), - curr->gpio[i].no, - curr->gpio[i].name, rc); - goto free_gpios; - } - } else { - gpio_free(curr->gpio[i].no); - } - } - host->gpio_config_status = enable; - return; - -free_gpios: - for (; i >= 0; i--) - gpio_free(curr->gpio[i].no); -} - -static void -msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) -{ - struct msmsdcc_host *host = mmc_priv(mmc); - u32 clk = 0, pwr = 0; - int rc; - unsigned long flags; - - spin_lock_irqsave(&host->lock, flags); - - msmsdcc_enable_clocks(host); - - spin_unlock_irqrestore(&host->lock, flags); - - if (ios->clock) { - if (ios->clock != host->clk_rate) { - rc = clk_set_rate(host->clk, ios->clock); - if (rc < 0) - pr_err("%s: Error setting clock rate (%d)\n", - mmc_hostname(host->mmc), rc); - else - host->clk_rate = ios->clock; - } - clk |= MCI_CLK_ENABLE; - } - - if (ios->bus_width == MMC_BUS_WIDTH_4) - clk |= (2 << 10); /* Set WIDEBUS */ - - if (ios->clock > 400000 && msmsdcc_pwrsave) - clk |= (1 << 9); /* PWRSAVE */ - - clk |= (1 << 12); /* FLOW_ENA */ - clk |= (1 << 15); /* feedback clock */ - - if (host->plat->translate_vdd) - pwr |= host->plat->translate_vdd(mmc_dev(mmc), ios->vdd); - - switch (ios->power_mode) { - case MMC_POWER_OFF: - msmsdcc_setup_gpio(host, false); - break; - case MMC_POWER_UP: - pwr |= MCI_PWR_UP; - msmsdcc_setup_gpio(host, true); - break; - case MMC_POWER_ON: - pwr |= MCI_PWR_ON; - break; - } - - if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN) - pwr |= MCI_OD; - - msmsdcc_writel(host, clk, MMCICLOCK); - - if (host->pwr != pwr) { - host->pwr = pwr; - msmsdcc_writel(host, pwr, MMCIPOWER); - } -#if BUSCLK_PWRSAVE - spin_lock_irqsave(&host->lock, flags); - msmsdcc_disable_clocks(host, 1); - spin_unlock_irqrestore(&host->lock, flags); -#endif -} - -static void msmsdcc_enable_sdio_irq(struct mmc_host *mmc, int enable) -{ - struct msmsdcc_host *host = mmc_priv(mmc); - unsigned long flags; - u32 status; - - spin_lock_irqsave(&host->lock, flags); - if (msmsdcc_sdioirq == 1) { - status = msmsdcc_readl(host, MMCIMASK0); - if (enable) - status |= MCI_SDIOINTOPERMASK; - else - status &= ~MCI_SDIOINTOPERMASK; - host->saved_irq0mask = status; - msmsdcc_writel(host, status, MMCIMASK0); - } - spin_unlock_irqrestore(&host->lock, flags); -} - -static void msmsdcc_init_card(struct mmc_host *mmc, struct mmc_card *card) -{ - struct msmsdcc_host *host = mmc_priv(mmc); - - if (host->plat->init_card) - host->plat->init_card(card); -} - -static const struct mmc_host_ops msmsdcc_ops = { - .request = msmsdcc_request, - .set_ios = msmsdcc_set_ios, - .enable_sdio_irq = msmsdcc_enable_sdio_irq, - .init_card = msmsdcc_init_card, -}; - -static void -msmsdcc_check_status(unsigned long data) -{ - struct msmsdcc_host *host = (struct msmsdcc_host *)data; - unsigned int status; - - if (!host->plat->status) { - mmc_detect_change(host->mmc, 0); - goto out; - } - - status = host->plat->status(mmc_dev(host->mmc)); - host->eject = !status; - if (status ^ host->oldstat) { - pr_info("%s: Slot status change detected (%d -> %d)\n", - mmc_hostname(host->mmc), host->oldstat, status); - if (status) - mmc_detect_change(host->mmc, (5 * HZ) / 2); - else - mmc_detect_change(host->mmc, 0); - } - - host->oldstat = status; - -out: - if (host->timer.function) - mod_timer(&host->timer, jiffies + HZ); -} - -static irqreturn_t -msmsdcc_platform_status_irq(int irq, void *dev_id) -{ - struct msmsdcc_host *host = dev_id; - - pr_debug("%s: %d\n", __func__, irq); - msmsdcc_check_status((unsigned long) host); - return IRQ_HANDLED; -} - -static void -msmsdcc_status_notify_cb(int card_present, void *dev_id) -{ - struct msmsdcc_host *host = dev_id; - - pr_debug("%s: card_present %d\n", mmc_hostname(host->mmc), - card_present); - msmsdcc_check_status((unsigned long) host); -} - -static void -msmsdcc_busclk_expired(unsigned long _data) -{ - struct msmsdcc_host *host = (struct msmsdcc_host *) _data; - - if (host->clks_on) - msmsdcc_disable_clocks(host, 0); -} - -static int -msmsdcc_init_dma(struct msmsdcc_host *host) -{ - memset(&host->dma, 0, sizeof(struct msmsdcc_dma_data)); - host->dma.host = host; - host->dma.channel = -1; - - if (!host->dmares) - return -ENODEV; - - host->dma.nc = dma_alloc_coherent(NULL, - sizeof(struct msmsdcc_nc_dmadata), - &host->dma.nc_busaddr, - GFP_KERNEL); - if (host->dma.nc == NULL) { - pr_err("Unable to allocate DMA buffer\n"); - return -ENOMEM; - } - memset(host->dma.nc, 0x00, sizeof(struct msmsdcc_nc_dmadata)); - host->dma.cmd_busaddr = host->dma.nc_busaddr; - host->dma.cmdptr_busaddr = host->dma.nc_busaddr + - offsetof(struct msmsdcc_nc_dmadata, cmdptr); - host->dma.channel = host->dmares->start; - - return 0; -} - -static int -msmsdcc_probe(struct platform_device *pdev) -{ - struct msm_mmc_platform_data *plat = pdev->dev.platform_data; - struct msmsdcc_host *host; - struct mmc_host *mmc; - struct resource *cmd_irqres = NULL; - struct resource *stat_irqres = NULL; - struct resource *memres = NULL; - struct resource *dmares = NULL; - int ret; - - /* must have platform data */ - if (!plat) { - pr_err("%s: Platform data not available\n", __func__); - ret = -EINVAL; - goto out; - } - - if (pdev->id < 1 || pdev->id > 4) - return -EINVAL; - - if (pdev->resource == NULL || pdev->num_resources < 2) { - pr_err("%s: Invalid resource\n", __func__); - return -ENXIO; - } - - memres = platform_get_resource(pdev, IORESOURCE_MEM, 0); - dmares = platform_get_resource(pdev, IORESOURCE_DMA, 0); - cmd_irqres = platform_get_resource_byname(pdev, IORESOURCE_IRQ, - "cmd_irq"); - stat_irqres = platform_get_resource_byname(pdev, IORESOURCE_IRQ, - "status_irq"); - - if (!cmd_irqres || !memres) { - pr_err("%s: Invalid resource\n", __func__); - return -ENXIO; - } - - /* - * Setup our host structure - */ - - mmc = mmc_alloc_host(sizeof(struct msmsdcc_host), &pdev->dev); - if (!mmc) { - ret = -ENOMEM; - goto out; - } - - host = mmc_priv(mmc); - host->pdev_id = pdev->id; - host->plat = plat; - host->mmc = mmc; - host->curr.cmd = NULL; - init_timer(&host->busclk_timer); - host->busclk_timer.data = (unsigned long) host; - host->busclk_timer.function = msmsdcc_busclk_expired; - - - host->cmdpoll = 1; - - host->base = ioremap(memres->start, PAGE_SIZE); - if (!host->base) { - ret = -ENOMEM; - goto host_free; - } - - host->cmd_irqres = cmd_irqres; - host->memres = memres; - host->dmares = dmares; - spin_lock_init(&host->lock); - - tasklet_init(&host->dma_tlet, msmsdcc_dma_complete_tlet, - (unsigned long)host); - - /* - * Setup DMA - */ - if (host->dmares) { - ret = msmsdcc_init_dma(host); - if (ret) - goto ioremap_free; - } else { - host->dma.channel = -1; - } - - /* Get our clocks */ - host->pclk = clk_get(&pdev->dev, "sdc_pclk"); - if (IS_ERR(host->pclk)) { - ret = PTR_ERR(host->pclk); - goto dma_free; - } - - host->clk = clk_get(&pdev->dev, "sdc_clk"); - if (IS_ERR(host->clk)) { - ret = PTR_ERR(host->clk); - goto pclk_put; - } - - ret = clk_set_rate(host->clk, msmsdcc_fmin); - if (ret) { - pr_err("%s: Clock rate set failed (%d)\n", __func__, ret); - goto clk_put; - } - - /* Enable clocks */ - ret = msmsdcc_enable_clocks(host); - if (ret) - goto clk_put; - - host->pclk_rate = clk_get_rate(host->pclk); - host->clk_rate = clk_get_rate(host->clk); - - /* - * Setup MMC host structure - */ - mmc->ops = &msmsdcc_ops; - mmc->f_min = msmsdcc_fmin; - mmc->f_max = msmsdcc_fmax; - mmc->ocr_avail = plat->ocr_mask; - - if (msmsdcc_4bit) - mmc->caps |= MMC_CAP_4_BIT_DATA; - if (msmsdcc_sdioirq) - mmc->caps |= MMC_CAP_SDIO_IRQ; - mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED; - - mmc->max_segs = NR_SG; - mmc->max_blk_size = 4096; /* MCI_DATA_CTL BLOCKSIZE up to 4096 */ - mmc->max_blk_count = 65536; - - mmc->max_req_size = 33554432; /* MCI_DATA_LENGTH is 25 bits */ - mmc->max_seg_size = mmc->max_req_size; - - msmsdcc_writel(host, 0, MMCIMASK0); - msmsdcc_writel(host, 0x5e007ff, MMCICLEAR); - - msmsdcc_writel(host, MCI_IRQENABLE, MMCIMASK0); - host->saved_irq0mask = MCI_IRQENABLE; - - /* - * Setup card detect change - */ - - memset(&host->timer, 0, sizeof(host->timer)); - - if (stat_irqres && !(stat_irqres->flags & IORESOURCE_DISABLED)) { - unsigned long irqflags = IRQF_SHARED | - (stat_irqres->flags & IRQF_TRIGGER_MASK); - - host->stat_irq = stat_irqres->start; - ret = request_irq(host->stat_irq, - msmsdcc_platform_status_irq, - irqflags, - DRIVER_NAME " (slot)", - host); - if (ret) { - pr_err("%s: Unable to get slot IRQ %d (%d)\n", - mmc_hostname(mmc), host->stat_irq, ret); - goto clk_disable; - } - } else if (plat->register_status_notify) { - plat->register_status_notify(msmsdcc_status_notify_cb, host); - } else if (!plat->status) - pr_err("%s: No card detect facilities available\n", - mmc_hostname(mmc)); - else { - init_timer(&host->timer); - host->timer.data = (unsigned long)host; - host->timer.function = msmsdcc_check_status; - host->timer.expires = jiffies + HZ; - add_timer(&host->timer); - } - - if (plat->status) { - host->oldstat = host->plat->status(mmc_dev(host->mmc)); - host->eject = !host->oldstat; - } - - ret = request_irq(cmd_irqres->start, msmsdcc_irq, IRQF_SHARED, - DRIVER_NAME " (cmd)", host); - if (ret) - goto stat_irq_free; - - ret = request_irq(cmd_irqres->start, msmsdcc_pio_irq, IRQF_SHARED, - DRIVER_NAME " (pio)", host); - if (ret) - goto cmd_irq_free; - - mmc_set_drvdata(pdev, mmc); - mmc_add_host(mmc); - - pr_info("%s: Qualcomm MSM SDCC at 0x%016llx irq %d,%d dma %d\n", - mmc_hostname(mmc), (unsigned long long)memres->start, - (unsigned int) cmd_irqres->start, - (unsigned int) host->stat_irq, host->dma.channel); - pr_info("%s: 4 bit data mode %s\n", mmc_hostname(mmc), - (mmc->caps & MMC_CAP_4_BIT_DATA ? "enabled" : "disabled")); - pr_info("%s: MMC clock %u -> %u Hz, PCLK %u Hz\n", - mmc_hostname(mmc), msmsdcc_fmin, msmsdcc_fmax, host->pclk_rate); - pr_info("%s: Slot eject status = %d\n", mmc_hostname(mmc), host->eject); - pr_info("%s: Power save feature enable = %d\n", - mmc_hostname(mmc), msmsdcc_pwrsave); - - if (host->dma.channel != -1) { - pr_info("%s: DM non-cached buffer at %p, dma_addr 0x%.8x\n", - mmc_hostname(mmc), host->dma.nc, host->dma.nc_busaddr); - pr_info("%s: DM cmd busaddr 0x%.8x, cmdptr busaddr 0x%.8x\n", - mmc_hostname(mmc), host->dma.cmd_busaddr, - host->dma.cmdptr_busaddr); - } else - pr_info("%s: PIO transfer enabled\n", mmc_hostname(mmc)); - if (host->timer.function) - pr_info("%s: Polling status mode enabled\n", mmc_hostname(mmc)); - - return 0; - cmd_irq_free: - free_irq(cmd_irqres->start, host); - stat_irq_free: - if (host->stat_irq) - free_irq(host->stat_irq, host); - clk_disable: - msmsdcc_disable_clocks(host, 0); - clk_put: - clk_put(host->clk); - pclk_put: - clk_put(host->pclk); -dma_free: - if (host->dmares) - dma_free_coherent(NULL, sizeof(struct msmsdcc_nc_dmadata), - host->dma.nc, host->dma.nc_busaddr); -ioremap_free: - tasklet_kill(&host->dma_tlet); - iounmap(host->base); - host_free: - mmc_free_host(mmc); - out: - return ret; -} - -#ifdef CONFIG_PM -#ifdef CONFIG_MMC_MSM7X00A_RESUME_IN_WQ -static void -do_resume_work(struct work_struct *work) -{ - struct msmsdcc_host *host = - container_of(work, struct msmsdcc_host, resume_task); - struct mmc_host *mmc = host->mmc; - - if (mmc) { - mmc_resume_host(mmc); - if (host->stat_irq) - enable_irq(host->stat_irq); - } -} -#endif - - -static int -msmsdcc_suspend(struct platform_device *dev, pm_message_t state) -{ - struct mmc_host *mmc = mmc_get_drvdata(dev); - int rc = 0; - - if (mmc) { - struct msmsdcc_host *host = mmc_priv(mmc); - - if (host->stat_irq) - disable_irq(host->stat_irq); - - if (mmc->card && mmc->card->type != MMC_TYPE_SDIO) - rc = mmc_suspend_host(mmc); - if (!rc) - msmsdcc_writel(host, 0, MMCIMASK0); - if (host->clks_on) - msmsdcc_disable_clocks(host, 0); - } - return rc; -} - -static int -msmsdcc_resume(struct platform_device *dev) -{ - struct mmc_host *mmc = mmc_get_drvdata(dev); - - if (mmc) { - struct msmsdcc_host *host = mmc_priv(mmc); - - msmsdcc_enable_clocks(host); - - msmsdcc_writel(host, host->saved_irq0mask, MMCIMASK0); - - if (mmc->card && mmc->card->type != MMC_TYPE_SDIO) - mmc_resume_host(mmc); - if (host->stat_irq) - enable_irq(host->stat_irq); -#if BUSCLK_PWRSAVE - msmsdcc_disable_clocks(host, 1); -#endif - } - return 0; -} -#else -#define msmsdcc_suspend 0 -#define msmsdcc_resume 0 -#endif - -static struct platform_driver msmsdcc_driver = { - .probe = msmsdcc_probe, - .suspend = msmsdcc_suspend, - .resume = msmsdcc_resume, - .driver = { - .name = "msm_sdcc", - }, -}; - -module_platform_driver(msmsdcc_driver); - -MODULE_DESCRIPTION("Qualcomm MSM 7X00A Multimedia Card Interface driver"); -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/mmc/host/msm_sdcc.h b/ANDROID_3.4.5/drivers/mmc/host/msm_sdcc.h deleted file mode 100644 index 402028d1..00000000 --- a/ANDROID_3.4.5/drivers/mmc/host/msm_sdcc.h +++ /dev/null @@ -1,256 +0,0 @@ -/* - * linux/drivers/mmc/host/msmsdcc.h - QCT MSM7K SDC Controller - * - * Copyright (C) 2008 Google, All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * - Based on mmci.h - */ - -#ifndef _MSM_SDCC_H -#define _MSM_SDCC_H - -#define MSMSDCC_CRCI_SDC1 6 -#define MSMSDCC_CRCI_SDC2 7 -#define MSMSDCC_CRCI_SDC3 12 -#define MSMSDCC_CRCI_SDC4 13 - -#define MMCIPOWER 0x000 -#define MCI_PWR_OFF 0x00 -#define MCI_PWR_UP 0x02 -#define MCI_PWR_ON 0x03 -#define MCI_OD (1 << 6) - -#define MMCICLOCK 0x004 -#define MCI_CLK_ENABLE (1 << 8) -#define MCI_CLK_PWRSAVE (1 << 9) -#define MCI_CLK_WIDEBUS (1 << 10) -#define MCI_CLK_FLOWENA (1 << 12) -#define MCI_CLK_INVERTOUT (1 << 13) -#define MCI_CLK_SELECTIN (1 << 14) - -#define MMCIARGUMENT 0x008 -#define MMCICOMMAND 0x00c -#define MCI_CPSM_RESPONSE (1 << 6) -#define MCI_CPSM_LONGRSP (1 << 7) -#define MCI_CPSM_INTERRUPT (1 << 8) -#define MCI_CPSM_PENDING (1 << 9) -#define MCI_CPSM_ENABLE (1 << 10) -#define MCI_CPSM_PROGENA (1 << 11) -#define MCI_CSPM_DATCMD (1 << 12) -#define MCI_CSPM_MCIABORT (1 << 13) -#define MCI_CSPM_CCSENABLE (1 << 14) -#define MCI_CSPM_CCSDISABLE (1 << 15) - - -#define MMCIRESPCMD 0x010 -#define MMCIRESPONSE0 0x014 -#define MMCIRESPONSE1 0x018 -#define MMCIRESPONSE2 0x01c -#define MMCIRESPONSE3 0x020 -#define MMCIDATATIMER 0x024 -#define MMCIDATALENGTH 0x028 - -#define MMCIDATACTRL 0x02c -#define MCI_DPSM_ENABLE (1 << 0) -#define MCI_DPSM_DIRECTION (1 << 1) -#define MCI_DPSM_MODE (1 << 2) -#define MCI_DPSM_DMAENABLE (1 << 3) - -#define MMCIDATACNT 0x030 -#define MMCISTATUS 0x034 -#define MCI_CMDCRCFAIL (1 << 0) -#define MCI_DATACRCFAIL (1 << 1) -#define MCI_CMDTIMEOUT (1 << 2) -#define MCI_DATATIMEOUT (1 << 3) -#define MCI_TXUNDERRUN (1 << 4) -#define MCI_RXOVERRUN (1 << 5) -#define MCI_CMDRESPEND (1 << 6) -#define MCI_CMDSENT (1 << 7) -#define MCI_DATAEND (1 << 8) -#define MCI_DATABLOCKEND (1 << 10) -#define MCI_CMDACTIVE (1 << 11) -#define MCI_TXACTIVE (1 << 12) -#define MCI_RXACTIVE (1 << 13) -#define MCI_TXFIFOHALFEMPTY (1 << 14) -#define MCI_RXFIFOHALFFULL (1 << 15) -#define MCI_TXFIFOFULL (1 << 16) -#define MCI_RXFIFOFULL (1 << 17) -#define MCI_TXFIFOEMPTY (1 << 18) -#define MCI_RXFIFOEMPTY (1 << 19) -#define MCI_TXDATAAVLBL (1 << 20) -#define MCI_RXDATAAVLBL (1 << 21) -#define MCI_SDIOINTR (1 << 22) -#define MCI_PROGDONE (1 << 23) -#define MCI_ATACMDCOMPL (1 << 24) -#define MCI_SDIOINTOPER (1 << 25) -#define MCI_CCSTIMEOUT (1 << 26) - -#define MMCICLEAR 0x038 -#define MCI_CMDCRCFAILCLR (1 << 0) -#define MCI_DATACRCFAILCLR (1 << 1) -#define MCI_CMDTIMEOUTCLR (1 << 2) -#define MCI_DATATIMEOUTCLR (1 << 3) -#define MCI_TXUNDERRUNCLR (1 << 4) -#define MCI_RXOVERRUNCLR (1 << 5) -#define MCI_CMDRESPENDCLR (1 << 6) -#define MCI_CMDSENTCLR (1 << 7) -#define MCI_DATAENDCLR (1 << 8) -#define MCI_DATABLOCKENDCLR (1 << 10) - -#define MMCIMASK0 0x03c -#define MCI_CMDCRCFAILMASK (1 << 0) -#define MCI_DATACRCFAILMASK (1 << 1) -#define MCI_CMDTIMEOUTMASK (1 << 2) -#define MCI_DATATIMEOUTMASK (1 << 3) -#define MCI_TXUNDERRUNMASK (1 << 4) -#define MCI_RXOVERRUNMASK (1 << 5) -#define MCI_CMDRESPENDMASK (1 << 6) -#define MCI_CMDSENTMASK (1 << 7) -#define MCI_DATAENDMASK (1 << 8) -#define MCI_DATABLOCKENDMASK (1 << 10) -#define MCI_CMDACTIVEMASK (1 << 11) -#define MCI_TXACTIVEMASK (1 << 12) -#define MCI_RXACTIVEMASK (1 << 13) -#define MCI_TXFIFOHALFEMPTYMASK (1 << 14) -#define MCI_RXFIFOHALFFULLMASK (1 << 15) -#define MCI_TXFIFOFULLMASK (1 << 16) -#define MCI_RXFIFOFULLMASK (1 << 17) -#define MCI_TXFIFOEMPTYMASK (1 << 18) -#define MCI_RXFIFOEMPTYMASK (1 << 19) -#define MCI_TXDATAAVLBLMASK (1 << 20) -#define MCI_RXDATAAVLBLMASK (1 << 21) -#define MCI_SDIOINTMASK (1 << 22) -#define MCI_PROGDONEMASK (1 << 23) -#define MCI_ATACMDCOMPLMASK (1 << 24) -#define MCI_SDIOINTOPERMASK (1 << 25) -#define MCI_CCSTIMEOUTMASK (1 << 26) - -#define MMCIMASK1 0x040 -#define MMCIFIFOCNT 0x044 -#define MCICCSTIMER 0x058 - -#define MMCIFIFO 0x080 /* to 0x0bc */ - -#define MCI_IRQENABLE \ - (MCI_CMDCRCFAILMASK|MCI_DATACRCFAILMASK|MCI_CMDTIMEOUTMASK| \ - MCI_DATATIMEOUTMASK|MCI_TXUNDERRUNMASK|MCI_RXOVERRUNMASK| \ - MCI_CMDRESPENDMASK|MCI_CMDSENTMASK|MCI_DATAENDMASK|MCI_PROGDONEMASK) - -#define MCI_IRQ_PIO \ - (MCI_RXDATAAVLBLMASK | MCI_TXDATAAVLBLMASK | MCI_RXFIFOEMPTYMASK | \ - MCI_TXFIFOEMPTYMASK | MCI_RXFIFOFULLMASK | MCI_TXFIFOFULLMASK | \ - MCI_RXFIFOHALFFULLMASK | MCI_TXFIFOHALFEMPTYMASK | \ - MCI_RXACTIVEMASK | MCI_TXACTIVEMASK) -/* - * The size of the FIFO in bytes. - */ -#define MCI_FIFOSIZE (16*4) - -#define MCI_FIFOHALFSIZE (MCI_FIFOSIZE / 2) - -#define NR_SG 32 - -struct clk; - -struct msmsdcc_nc_dmadata { - dmov_box cmd[NR_SG]; - uint32_t cmdptr; -}; - -struct msmsdcc_dma_data { - struct msmsdcc_nc_dmadata *nc; - dma_addr_t nc_busaddr; - dma_addr_t cmd_busaddr; - dma_addr_t cmdptr_busaddr; - - struct msm_dmov_cmd hdr; - enum dma_data_direction dir; - - struct scatterlist *sg; - int num_ents; - - int channel; - struct msmsdcc_host *host; - int busy; /* Set if DM is busy */ - int active; - unsigned int result; - struct msm_dmov_errdata err; -}; - -struct msmsdcc_pio_data { - struct scatterlist *sg; - unsigned int sg_len; - unsigned int sg_off; -}; - -struct msmsdcc_curr_req { - struct mmc_request *mrq; - struct mmc_command *cmd; - struct mmc_data *data; - unsigned int xfer_size; /* Total data size */ - unsigned int xfer_remain; /* Bytes remaining to send */ - unsigned int data_xfered; /* Bytes acked by BLKEND irq */ - int got_dataend; - int user_pages; -}; - -struct msmsdcc_stats { - unsigned int reqs; - unsigned int cmds; - unsigned int cmdpoll_hits; - unsigned int cmdpoll_misses; -}; - -struct msmsdcc_host { - struct resource *cmd_irqres; - struct resource *memres; - struct resource *dmares; - void __iomem *base; - int pdev_id; - unsigned int stat_irq; - - struct msmsdcc_curr_req curr; - - struct mmc_host *mmc; - struct clk *clk; /* main MMC bus clock */ - struct clk *pclk; /* SDCC peripheral bus clock */ - unsigned int clks_on; /* set if clocks are enabled */ - struct timer_list busclk_timer; - - unsigned int eject; /* eject state */ - - spinlock_t lock; - - unsigned int clk_rate; /* Current clock rate */ - unsigned int pclk_rate; - - u32 pwr; - u32 saved_irq0mask; /* MMCIMASK0 reg value */ - struct msm_mmc_platform_data *plat; - - struct timer_list timer; - unsigned int oldstat; - - struct msmsdcc_dma_data dma; - struct msmsdcc_pio_data pio; - int cmdpoll; - struct msmsdcc_stats stats; - - struct tasklet_struct dma_tlet; - /* Command parameters */ - unsigned int cmd_timeout; - unsigned int cmd_pio_irqmask; - unsigned int cmd_datactrl; - struct mmc_command *cmd_cmd; - u32 cmd_c; - bool gpio_config_status; - - bool prog_scan; - bool prog_enable; -}; - -#endif diff --git a/ANDROID_3.4.5/drivers/mmc/host/mvsdio.c b/ANDROID_3.4.5/drivers/mmc/host/mvsdio.c deleted file mode 100644 index eeb8cd12..00000000 --- a/ANDROID_3.4.5/drivers/mmc/host/mvsdio.c +++ /dev/null @@ -1,921 +0,0 @@ -/* - * Marvell MMC/SD/SDIO driver - * - * Authors: Maen Suleiman, Nicolas Pitre - * Copyright (C) 2008-2009 Marvell Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include <linux/module.h> -#include <linux/init.h> -#include <linux/io.h> -#include <linux/platform_device.h> -#include <linux/mbus.h> -#include <linux/delay.h> -#include <linux/interrupt.h> -#include <linux/dma-mapping.h> -#include <linux/scatterlist.h> -#include <linux/irq.h> -#include <linux/gpio.h> -#include <linux/mmc/host.h> - -#include <asm/sizes.h> -#include <asm/unaligned.h> -#include <plat/mvsdio.h> - -#include "mvsdio.h" - -#define DRIVER_NAME "mvsdio" - -static int maxfreq = MVSD_CLOCKRATE_MAX; -static int nodma; - -struct mvsd_host { - void __iomem *base; - struct mmc_request *mrq; - spinlock_t lock; - unsigned int xfer_mode; - unsigned int intr_en; - unsigned int ctrl; - unsigned int pio_size; - void *pio_ptr; - unsigned int sg_frags; - unsigned int ns_per_clk; - unsigned int clock; - unsigned int base_clock; - struct timer_list timer; - struct mmc_host *mmc; - struct device *dev; - struct resource *res; - int irq; - int gpio_card_detect; - int gpio_write_protect; -}; - -#define mvsd_write(offs, val) writel(val, iobase + (offs)) -#define mvsd_read(offs) readl(iobase + (offs)) - -static int mvsd_setup_data(struct mvsd_host *host, struct mmc_data *data) -{ - void __iomem *iobase = host->base; - unsigned int tmout; - int tmout_index; - - /* - * Hardware weirdness. The FIFO_EMPTY bit of the HW_STATE - * register is sometimes not set before a while when some - * "unusual" data block sizes are used (such as with the SWITCH - * command), even despite the fact that the XFER_DONE interrupt - * was raised. And if another data transfer starts before - * this bit comes to good sense (which eventually happens by - * itself) then the new transfer simply fails with a timeout. - */ - if (!(mvsd_read(MVSD_HW_STATE) & (1 << 13))) { - unsigned long t = jiffies + HZ; - unsigned int hw_state, count = 0; - do { - if (time_after(jiffies, t)) { - dev_warn(host->dev, "FIFO_EMPTY bit missing\n"); - break; - } - hw_state = mvsd_read(MVSD_HW_STATE); - count++; - } while (!(hw_state & (1 << 13))); - dev_dbg(host->dev, "*** wait for FIFO_EMPTY bit " - "(hw=0x%04x, count=%d, jiffies=%ld)\n", - hw_state, count, jiffies - (t - HZ)); - } - - /* If timeout=0 then maximum timeout index is used. */ - tmout = DIV_ROUND_UP(data->timeout_ns, host->ns_per_clk); - tmout += data->timeout_clks; - tmout_index = fls(tmout - 1) - 12; - if (tmout_index < 0) - tmout_index = 0; - if (tmout_index > MVSD_HOST_CTRL_TMOUT_MAX) - tmout_index = MVSD_HOST_CTRL_TMOUT_MAX; - - dev_dbg(host->dev, "data %s at 0x%08x: blocks=%d blksz=%d tmout=%u (%d)\n", - (data->flags & MMC_DATA_READ) ? "read" : "write", - (u32)sg_virt(data->sg), data->blocks, data->blksz, - tmout, tmout_index); - - host->ctrl &= ~MVSD_HOST_CTRL_TMOUT_MASK; - host->ctrl |= MVSD_HOST_CTRL_TMOUT(tmout_index); - mvsd_write(MVSD_HOST_CTRL, host->ctrl); - mvsd_write(MVSD_BLK_COUNT, data->blocks); - mvsd_write(MVSD_BLK_SIZE, data->blksz); - - if (nodma || (data->blksz | data->sg->offset) & 3) { - /* - * We cannot do DMA on a buffer which offset or size - * is not aligned on a 4-byte boundary. - */ - host->pio_size = data->blocks * data->blksz; - host->pio_ptr = sg_virt(data->sg); - if (!nodma) - pr_debug("%s: fallback to PIO for data " - "at 0x%p size %d\n", - mmc_hostname(host->mmc), - host->pio_ptr, host->pio_size); - return 1; - } else { - dma_addr_t phys_addr; - int dma_dir = (data->flags & MMC_DATA_READ) ? - DMA_FROM_DEVICE : DMA_TO_DEVICE; - host->sg_frags = dma_map_sg(mmc_dev(host->mmc), data->sg, - data->sg_len, dma_dir); - phys_addr = sg_dma_address(data->sg); - mvsd_write(MVSD_SYS_ADDR_LOW, (u32)phys_addr & 0xffff); - mvsd_write(MVSD_SYS_ADDR_HI, (u32)phys_addr >> 16); - return 0; - } -} - -static void mvsd_request(struct mmc_host *mmc, struct mmc_request *mrq) -{ - struct mvsd_host *host = mmc_priv(mmc); - void __iomem *iobase = host->base; - struct mmc_command *cmd = mrq->cmd; - u32 cmdreg = 0, xfer = 0, intr = 0; - unsigned long flags; - - BUG_ON(host->mrq != NULL); - host->mrq = mrq; - - dev_dbg(host->dev, "cmd %d (hw state 0x%04x)\n", - cmd->opcode, mvsd_read(MVSD_HW_STATE)); - - cmdreg = MVSD_CMD_INDEX(cmd->opcode); - - if (cmd->flags & MMC_RSP_BUSY) - cmdreg |= MVSD_CMD_RSP_48BUSY; - else if (cmd->flags & MMC_RSP_136) - cmdreg |= MVSD_CMD_RSP_136; - else if (cmd->flags & MMC_RSP_PRESENT) - cmdreg |= MVSD_CMD_RSP_48; - else - cmdreg |= MVSD_CMD_RSP_NONE; - - if (cmd->flags & MMC_RSP_CRC) - cmdreg |= MVSD_CMD_CHECK_CMDCRC; - - if (cmd->flags & MMC_RSP_OPCODE) - cmdreg |= MVSD_CMD_INDX_CHECK; - - if (cmd->flags & MMC_RSP_PRESENT) { - cmdreg |= MVSD_UNEXPECTED_RESP; - intr |= MVSD_NOR_UNEXP_RSP; - } - - if (mrq->data) { - struct mmc_data *data = mrq->data; - int pio; - - cmdreg |= MVSD_CMD_DATA_PRESENT | MVSD_CMD_CHECK_DATACRC16; - xfer |= MVSD_XFER_MODE_HW_WR_DATA_EN; - if (data->flags & MMC_DATA_READ) - xfer |= MVSD_XFER_MODE_TO_HOST; - - pio = mvsd_setup_data(host, data); - if (pio) { - xfer |= MVSD_XFER_MODE_PIO; - /* PIO section of mvsd_irq has comments on those bits */ - if (data->flags & MMC_DATA_WRITE) - intr |= MVSD_NOR_TX_AVAIL; - else if (host->pio_size > 32) - intr |= MVSD_NOR_RX_FIFO_8W; - else - intr |= MVSD_NOR_RX_READY; - } - - if (data->stop) { - struct mmc_command *stop = data->stop; - u32 cmd12reg = 0; - - mvsd_write(MVSD_AUTOCMD12_ARG_LOW, stop->arg & 0xffff); - mvsd_write(MVSD_AUTOCMD12_ARG_HI, stop->arg >> 16); - - if (stop->flags & MMC_RSP_BUSY) - cmd12reg |= MVSD_AUTOCMD12_BUSY; - if (stop->flags & MMC_RSP_OPCODE) - cmd12reg |= MVSD_AUTOCMD12_INDX_CHECK; - cmd12reg |= MVSD_AUTOCMD12_INDEX(stop->opcode); - mvsd_write(MVSD_AUTOCMD12_CMD, cmd12reg); - - xfer |= MVSD_XFER_MODE_AUTO_CMD12; - intr |= MVSD_NOR_AUTOCMD12_DONE; - } else { - intr |= MVSD_NOR_XFER_DONE; - } - } else { - intr |= MVSD_NOR_CMD_DONE; - } - - mvsd_write(MVSD_ARG_LOW, cmd->arg & 0xffff); - mvsd_write(MVSD_ARG_HI, cmd->arg >> 16); - - spin_lock_irqsave(&host->lock, flags); - - host->xfer_mode &= MVSD_XFER_MODE_INT_CHK_EN; - host->xfer_mode |= xfer; - mvsd_write(MVSD_XFER_MODE, host->xfer_mode); - - mvsd_write(MVSD_NOR_INTR_STATUS, ~MVSD_NOR_CARD_INT); - mvsd_write(MVSD_ERR_INTR_STATUS, 0xffff); - mvsd_write(MVSD_CMD, cmdreg); - - host->intr_en &= MVSD_NOR_CARD_INT; - host->intr_en |= intr | MVSD_NOR_ERROR; - mvsd_write(MVSD_NOR_INTR_EN, host->intr_en); - mvsd_write(MVSD_ERR_INTR_EN, 0xffff); - - mod_timer(&host->timer, jiffies + 5 * HZ); - - spin_unlock_irqrestore(&host->lock, flags); -} - -static u32 mvsd_finish_cmd(struct mvsd_host *host, struct mmc_command *cmd, - u32 err_status) -{ - void __iomem *iobase = host->base; - - if (cmd->flags & MMC_RSP_136) { - unsigned int response[8], i; - for (i = 0; i < 8; i++) - response[i] = mvsd_read(MVSD_RSP(i)); - cmd->resp[0] = ((response[0] & 0x03ff) << 22) | - ((response[1] & 0xffff) << 6) | - ((response[2] & 0xfc00) >> 10); - cmd->resp[1] = ((response[2] & 0x03ff) << 22) | - ((response[3] & 0xffff) << 6) | - ((response[4] & 0xfc00) >> 10); - cmd->resp[2] = ((response[4] & 0x03ff) << 22) | - ((response[5] & 0xffff) << 6) | - ((response[6] & 0xfc00) >> 10); - cmd->resp[3] = ((response[6] & 0x03ff) << 22) | - ((response[7] & 0x3fff) << 8); - } else if (cmd->flags & MMC_RSP_PRESENT) { - unsigned int response[3], i; - for (i = 0; i < 3; i++) - response[i] = mvsd_read(MVSD_RSP(i)); - cmd->resp[0] = ((response[2] & 0x003f) << (8 - 8)) | - ((response[1] & 0xffff) << (14 - 8)) | - ((response[0] & 0x03ff) << (30 - 8)); - cmd->resp[1] = ((response[0] & 0xfc00) >> 10); - cmd->resp[2] = 0; - cmd->resp[3] = 0; - } - - if (err_status & MVSD_ERR_CMD_TIMEOUT) { - cmd->error = -ETIMEDOUT; - } else if (err_status & (MVSD_ERR_CMD_CRC | MVSD_ERR_CMD_ENDBIT | - MVSD_ERR_CMD_INDEX | MVSD_ERR_CMD_STARTBIT)) { - cmd->error = -EILSEQ; - } - err_status &= ~(MVSD_ERR_CMD_TIMEOUT | MVSD_ERR_CMD_CRC | - MVSD_ERR_CMD_ENDBIT | MVSD_ERR_CMD_INDEX | - MVSD_ERR_CMD_STARTBIT); - - return err_status; -} - -static u32 mvsd_finish_data(struct mvsd_host *host, struct mmc_data *data, - u32 err_status) -{ - void __iomem *iobase = host->base; - - if (host->pio_ptr) { - host->pio_ptr = NULL; - host->pio_size = 0; - } else { - dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->sg_frags, - (data->flags & MMC_DATA_READ) ? - DMA_FROM_DEVICE : DMA_TO_DEVICE); - } - - if (err_status & MVSD_ERR_DATA_TIMEOUT) - data->error = -ETIMEDOUT; - else if (err_status & (MVSD_ERR_DATA_CRC | MVSD_ERR_DATA_ENDBIT)) - data->error = -EILSEQ; - else if (err_status & MVSD_ERR_XFER_SIZE) - data->error = -EBADE; - err_status &= ~(MVSD_ERR_DATA_TIMEOUT | MVSD_ERR_DATA_CRC | - MVSD_ERR_DATA_ENDBIT | MVSD_ERR_XFER_SIZE); - - dev_dbg(host->dev, "data done: blocks_left=%d, bytes_left=%d\n", - mvsd_read(MVSD_CURR_BLK_LEFT), mvsd_read(MVSD_CURR_BYTE_LEFT)); - data->bytes_xfered = - (data->blocks - mvsd_read(MVSD_CURR_BLK_LEFT)) * data->blksz; - /* We can't be sure about the last block when errors are detected */ - if (data->bytes_xfered && data->error) - data->bytes_xfered -= data->blksz; - - /* Handle Auto cmd 12 response */ - if (data->stop) { - unsigned int response[3], i; - for (i = 0; i < 3; i++) - response[i] = mvsd_read(MVSD_AUTO_RSP(i)); - data->stop->resp[0] = ((response[2] & 0x003f) << (8 - 8)) | - ((response[1] & 0xffff) << (14 - 8)) | - ((response[0] & 0x03ff) << (30 - 8)); - data->stop->resp[1] = ((response[0] & 0xfc00) >> 10); - data->stop->resp[2] = 0; - data->stop->resp[3] = 0; - - if (err_status & MVSD_ERR_AUTOCMD12) { - u32 err_cmd12 = mvsd_read(MVSD_AUTOCMD12_ERR_STATUS); - dev_dbg(host->dev, "c12err 0x%04x\n", err_cmd12); - if (err_cmd12 & MVSD_AUTOCMD12_ERR_NOTEXE) - data->stop->error = -ENOEXEC; - else if (err_cmd12 & MVSD_AUTOCMD12_ERR_TIMEOUT) - data->stop->error = -ETIMEDOUT; - else if (err_cmd12) - data->stop->error = -EILSEQ; - err_status &= ~MVSD_ERR_AUTOCMD12; - } - } - - return err_status; -} - -static irqreturn_t mvsd_irq(int irq, void *dev) -{ - struct mvsd_host *host = dev; - void __iomem *iobase = host->base; - u32 intr_status, intr_done_mask; - int irq_handled = 0; - - intr_status = mvsd_read(MVSD_NOR_INTR_STATUS); - dev_dbg(host->dev, "intr 0x%04x intr_en 0x%04x hw_state 0x%04x\n", - intr_status, mvsd_read(MVSD_NOR_INTR_EN), - mvsd_read(MVSD_HW_STATE)); - - spin_lock(&host->lock); - - /* PIO handling, if needed. Messy business... */ - if (host->pio_size && - (intr_status & host->intr_en & - (MVSD_NOR_RX_READY | MVSD_NOR_RX_FIFO_8W))) { - u16 *p = host->pio_ptr; - int s = host->pio_size; - while (s >= 32 && (intr_status & MVSD_NOR_RX_FIFO_8W)) { - readsw(iobase + MVSD_FIFO, p, 16); - p += 16; - s -= 32; - intr_status = mvsd_read(MVSD_NOR_INTR_STATUS); - } - /* - * Normally we'd use < 32 here, but the RX_FIFO_8W bit - * doesn't appear to assert when there is exactly 32 bytes - * (8 words) left to fetch in a transfer. - */ - if (s <= 32) { - while (s >= 4 && (intr_status & MVSD_NOR_RX_READY)) { - put_unaligned(mvsd_read(MVSD_FIFO), p++); - put_unaligned(mvsd_read(MVSD_FIFO), p++); - s -= 4; - intr_status = mvsd_read(MVSD_NOR_INTR_STATUS); - } - if (s && s < 4 && (intr_status & MVSD_NOR_RX_READY)) { - u16 val[2] = {0, 0}; - val[0] = mvsd_read(MVSD_FIFO); - val[1] = mvsd_read(MVSD_FIFO); - memcpy(p, ((void *)&val) + 4 - s, s); - s = 0; - intr_status = mvsd_read(MVSD_NOR_INTR_STATUS); - } - if (s == 0) { - host->intr_en &= - ~(MVSD_NOR_RX_READY | MVSD_NOR_RX_FIFO_8W); - mvsd_write(MVSD_NOR_INTR_EN, host->intr_en); - } else if (host->intr_en & MVSD_NOR_RX_FIFO_8W) { - host->intr_en &= ~MVSD_NOR_RX_FIFO_8W; - host->intr_en |= MVSD_NOR_RX_READY; - mvsd_write(MVSD_NOR_INTR_EN, host->intr_en); - } - } - dev_dbg(host->dev, "pio %d intr 0x%04x hw_state 0x%04x\n", - s, intr_status, mvsd_read(MVSD_HW_STATE)); - host->pio_ptr = p; - host->pio_size = s; - irq_handled = 1; - } else if (host->pio_size && - (intr_status & host->intr_en & - (MVSD_NOR_TX_AVAIL | MVSD_NOR_TX_FIFO_8W))) { - u16 *p = host->pio_ptr; - int s = host->pio_size; - /* - * The TX_FIFO_8W bit is unreliable. When set, bursting - * 16 halfwords all at once in the FIFO drops data. Actually - * TX_AVAIL does go off after only one word is pushed even if - * TX_FIFO_8W remains set. - */ - while (s >= 4 && (intr_status & MVSD_NOR_TX_AVAIL)) { - mvsd_write(MVSD_FIFO, get_unaligned(p++)); - mvsd_write(MVSD_FIFO, get_unaligned(p++)); - s -= 4; - intr_status = mvsd_read(MVSD_NOR_INTR_STATUS); - } - if (s < 4) { - if (s && (intr_status & MVSD_NOR_TX_AVAIL)) { - u16 val[2] = {0, 0}; - memcpy(((void *)&val) + 4 - s, p, s); - mvsd_write(MVSD_FIFO, val[0]); - mvsd_write(MVSD_FIFO, val[1]); - s = 0; - intr_status = mvsd_read(MVSD_NOR_INTR_STATUS); - } - if (s == 0) { - host->intr_en &= - ~(MVSD_NOR_TX_AVAIL | MVSD_NOR_TX_FIFO_8W); - mvsd_write(MVSD_NOR_INTR_EN, host->intr_en); - } - } - dev_dbg(host->dev, "pio %d intr 0x%04x hw_state 0x%04x\n", - s, intr_status, mvsd_read(MVSD_HW_STATE)); - host->pio_ptr = p; - host->pio_size = s; - irq_handled = 1; - } - - mvsd_write(MVSD_NOR_INTR_STATUS, intr_status); - - intr_done_mask = MVSD_NOR_CARD_INT | MVSD_NOR_RX_READY | - MVSD_NOR_RX_FIFO_8W | MVSD_NOR_TX_FIFO_8W; - if (intr_status & host->intr_en & ~intr_done_mask) { - struct mmc_request *mrq = host->mrq; - struct mmc_command *cmd = mrq->cmd; - u32 err_status = 0; - - del_timer(&host->timer); - host->mrq = NULL; - - host->intr_en &= MVSD_NOR_CARD_INT; - mvsd_write(MVSD_NOR_INTR_EN, host->intr_en); - mvsd_write(MVSD_ERR_INTR_EN, 0); - - spin_unlock(&host->lock); - - if (intr_status & MVSD_NOR_UNEXP_RSP) { - cmd->error = -EPROTO; - } else if (intr_status & MVSD_NOR_ERROR) { - err_status = mvsd_read(MVSD_ERR_INTR_STATUS); - dev_dbg(host->dev, "err 0x%04x\n", err_status); - } - - err_status = mvsd_finish_cmd(host, cmd, err_status); - if (mrq->data) - err_status = mvsd_finish_data(host, mrq->data, err_status); - if (err_status) { - pr_err("%s: unhandled error status %#04x\n", - mmc_hostname(host->mmc), err_status); - cmd->error = -ENOMSG; - } - - mmc_request_done(host->mmc, mrq); - irq_handled = 1; - } else - spin_unlock(&host->lock); - - if (intr_status & MVSD_NOR_CARD_INT) { - mmc_signal_sdio_irq(host->mmc); - irq_handled = 1; - } - - if (irq_handled) - return IRQ_HANDLED; - - pr_err("%s: unhandled interrupt status=0x%04x en=0x%04x " - "pio=%d\n", mmc_hostname(host->mmc), intr_status, - host->intr_en, host->pio_size); - return IRQ_NONE; -} - -static void mvsd_timeout_timer(unsigned long data) -{ - struct mvsd_host *host = (struct mvsd_host *)data; - void __iomem *iobase = host->base; - struct mmc_request *mrq; - unsigned long flags; - - spin_lock_irqsave(&host->lock, flags); - mrq = host->mrq; - if (mrq) { - pr_err("%s: Timeout waiting for hardware interrupt.\n", - mmc_hostname(host->mmc)); - pr_err("%s: hw_state=0x%04x, intr_status=0x%04x " - "intr_en=0x%04x\n", mmc_hostname(host->mmc), - mvsd_read(MVSD_HW_STATE), - mvsd_read(MVSD_NOR_INTR_STATUS), - mvsd_read(MVSD_NOR_INTR_EN)); - - host->mrq = NULL; - - mvsd_write(MVSD_SW_RESET, MVSD_SW_RESET_NOW); - - host->xfer_mode &= MVSD_XFER_MODE_INT_CHK_EN; - mvsd_write(MVSD_XFER_MODE, host->xfer_mode); - - host->intr_en &= MVSD_NOR_CARD_INT; - mvsd_write(MVSD_NOR_INTR_EN, host->intr_en); - mvsd_write(MVSD_ERR_INTR_EN, 0); - mvsd_write(MVSD_ERR_INTR_STATUS, 0xffff); - - mrq->cmd->error = -ETIMEDOUT; - mvsd_finish_cmd(host, mrq->cmd, 0); - if (mrq->data) { - mrq->data->error = -ETIMEDOUT; - mvsd_finish_data(host, mrq->data, 0); - } - } - spin_unlock_irqrestore(&host->lock, flags); - - if (mrq) - mmc_request_done(host->mmc, mrq); -} - -static irqreturn_t mvsd_card_detect_irq(int irq, void *dev) -{ - struct mvsd_host *host = dev; - mmc_detect_change(host->mmc, msecs_to_jiffies(100)); - return IRQ_HANDLED; -} - -static void mvsd_enable_sdio_irq(struct mmc_host *mmc, int enable) -{ - struct mvsd_host *host = mmc_priv(mmc); - void __iomem *iobase = host->base; - unsigned long flags; - - spin_lock_irqsave(&host->lock, flags); - if (enable) { - host->xfer_mode |= MVSD_XFER_MODE_INT_CHK_EN; - host->intr_en |= MVSD_NOR_CARD_INT; - } else { - host->xfer_mode &= ~MVSD_XFER_MODE_INT_CHK_EN; - host->intr_en &= ~MVSD_NOR_CARD_INT; - } - mvsd_write(MVSD_XFER_MODE, host->xfer_mode); - mvsd_write(MVSD_NOR_INTR_EN, host->intr_en); - spin_unlock_irqrestore(&host->lock, flags); -} - -static int mvsd_get_ro(struct mmc_host *mmc) -{ - struct mvsd_host *host = mmc_priv(mmc); - - if (host->gpio_write_protect) - return gpio_get_value(host->gpio_write_protect); - - /* - * Board doesn't support read only detection; let the mmc core - * decide what to do. - */ - return -ENOSYS; -} - -static void mvsd_power_up(struct mvsd_host *host) -{ - void __iomem *iobase = host->base; - dev_dbg(host->dev, "power up\n"); - mvsd_write(MVSD_NOR_INTR_EN, 0); - mvsd_write(MVSD_ERR_INTR_EN, 0); - mvsd_write(MVSD_SW_RESET, MVSD_SW_RESET_NOW); - mvsd_write(MVSD_XFER_MODE, 0); - mvsd_write(MVSD_NOR_STATUS_EN, 0xffff); - mvsd_write(MVSD_ERR_STATUS_EN, 0xffff); - mvsd_write(MVSD_NOR_INTR_STATUS, 0xffff); - mvsd_write(MVSD_ERR_INTR_STATUS, 0xffff); -} - -static void mvsd_power_down(struct mvsd_host *host) -{ - void __iomem *iobase = host->base; - dev_dbg(host->dev, "power down\n"); - mvsd_write(MVSD_NOR_INTR_EN, 0); - mvsd_write(MVSD_ERR_INTR_EN, 0); - mvsd_write(MVSD_SW_RESET, MVSD_SW_RESET_NOW); - mvsd_write(MVSD_XFER_MODE, MVSD_XFER_MODE_STOP_CLK); - mvsd_write(MVSD_NOR_STATUS_EN, 0); - mvsd_write(MVSD_ERR_STATUS_EN, 0); - mvsd_write(MVSD_NOR_INTR_STATUS, 0xffff); - mvsd_write(MVSD_ERR_INTR_STATUS, 0xffff); -} - -static void mvsd_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) -{ - struct mvsd_host *host = mmc_priv(mmc); - void __iomem *iobase = host->base; - u32 ctrl_reg = 0; - - if (ios->power_mode == MMC_POWER_UP) - mvsd_power_up(host); - - if (ios->clock == 0) { - mvsd_write(MVSD_XFER_MODE, MVSD_XFER_MODE_STOP_CLK); - mvsd_write(MVSD_CLK_DIV, MVSD_BASE_DIV_MAX); - host->clock = 0; - dev_dbg(host->dev, "clock off\n"); - } else if (ios->clock != host->clock) { - u32 m = DIV_ROUND_UP(host->base_clock, ios->clock) - 1; - if (m > MVSD_BASE_DIV_MAX) - m = MVSD_BASE_DIV_MAX; - mvsd_write(MVSD_CLK_DIV, m); - host->clock = ios->clock; - host->ns_per_clk = 1000000000 / (host->base_clock / (m+1)); - dev_dbg(host->dev, "clock=%d (%d), div=0x%04x\n", - ios->clock, host->base_clock / (m+1), m); - } - - /* default transfer mode */ - ctrl_reg |= MVSD_HOST_CTRL_BIG_ENDIAN; - ctrl_reg &= ~MVSD_HOST_CTRL_LSB_FIRST; - - /* default to maximum timeout */ - ctrl_reg |= MVSD_HOST_CTRL_TMOUT_MASK; - ctrl_reg |= MVSD_HOST_CTRL_TMOUT_EN; - - if (ios->bus_mode == MMC_BUSMODE_PUSHPULL) - ctrl_reg |= MVSD_HOST_CTRL_PUSH_PULL_EN; - - if (ios->bus_width == MMC_BUS_WIDTH_4) - ctrl_reg |= MVSD_HOST_CTRL_DATA_WIDTH_4_BITS; - - /* - * The HI_SPEED_EN bit is causing trouble with many (but not all) - * high speed SD, SDHC and SDIO cards. Not enabling that bit - * makes all cards work. So let's just ignore that bit for now - * and revisit this issue if problems for not enabling this bit - * are ever reported. - */ -#if 0 - if (ios->timing == MMC_TIMING_MMC_HS || - ios->timing == MMC_TIMING_SD_HS) - ctrl_reg |= MVSD_HOST_CTRL_HI_SPEED_EN; -#endif - - host->ctrl = ctrl_reg; - mvsd_write(MVSD_HOST_CTRL, ctrl_reg); - dev_dbg(host->dev, "ctrl 0x%04x: %s %s %s\n", ctrl_reg, - (ctrl_reg & MVSD_HOST_CTRL_PUSH_PULL_EN) ? - "push-pull" : "open-drain", - (ctrl_reg & MVSD_HOST_CTRL_DATA_WIDTH_4_BITS) ? - "4bit-width" : "1bit-width", - (ctrl_reg & MVSD_HOST_CTRL_HI_SPEED_EN) ? - "high-speed" : ""); - - if (ios->power_mode == MMC_POWER_OFF) - mvsd_power_down(host); -} - -static const struct mmc_host_ops mvsd_ops = { - .request = mvsd_request, - .get_ro = mvsd_get_ro, - .set_ios = mvsd_set_ios, - .enable_sdio_irq = mvsd_enable_sdio_irq, -}; - -static void __init -mv_conf_mbus_windows(struct mvsd_host *host, - const struct mbus_dram_target_info *dram) -{ - void __iomem *iobase = host->base; - int i; - - for (i = 0; i < 4; i++) { - writel(0, iobase + MVSD_WINDOW_CTRL(i)); - writel(0, iobase + MVSD_WINDOW_BASE(i)); - } - - for (i = 0; i < dram->num_cs; i++) { - const struct mbus_dram_window *cs = dram->cs + i; - writel(((cs->size - 1) & 0xffff0000) | - (cs->mbus_attr << 8) | - (dram->mbus_dram_target_id << 4) | 1, - iobase + MVSD_WINDOW_CTRL(i)); - writel(cs->base, iobase + MVSD_WINDOW_BASE(i)); - } -} - -static int __init mvsd_probe(struct platform_device *pdev) -{ - struct mmc_host *mmc = NULL; - struct mvsd_host *host = NULL; - const struct mvsdio_platform_data *mvsd_data; - const struct mbus_dram_target_info *dram; - struct resource *r; - int ret, irq; - - r = platform_get_resource(pdev, IORESOURCE_MEM, 0); - irq = platform_get_irq(pdev, 0); - mvsd_data = pdev->dev.platform_data; - if (!r || irq < 0 || !mvsd_data) - return -ENXIO; - - r = request_mem_region(r->start, SZ_1K, DRIVER_NAME); - if (!r) - return -EBUSY; - - mmc = mmc_alloc_host(sizeof(struct mvsd_host), &pdev->dev); - if (!mmc) { - ret = -ENOMEM; - goto out; - } - - host = mmc_priv(mmc); - host->mmc = mmc; - host->dev = &pdev->dev; - host->res = r; - host->base_clock = mvsd_data->clock / 2; - - mmc->ops = &mvsd_ops; - - mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; - mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ | - MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED; - - mmc->f_min = DIV_ROUND_UP(host->base_clock, MVSD_BASE_DIV_MAX); - mmc->f_max = maxfreq; - - mmc->max_blk_size = 2048; - mmc->max_blk_count = 65535; - - mmc->max_segs = 1; - mmc->max_seg_size = mmc->max_blk_size * mmc->max_blk_count; - mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count; - - spin_lock_init(&host->lock); - - host->base = ioremap(r->start, SZ_4K); - if (!host->base) { - ret = -ENOMEM; - goto out; - } - - /* (Re-)program MBUS remapping windows if we are asked to. */ - dram = mv_mbus_dram_info(); - if (dram) - mv_conf_mbus_windows(host, dram); - - mvsd_power_down(host); - - ret = request_irq(irq, mvsd_irq, 0, DRIVER_NAME, host); - if (ret) { - pr_err("%s: cannot assign irq %d\n", DRIVER_NAME, irq); - goto out; - } else - host->irq = irq; - - if (mvsd_data->gpio_card_detect) { - ret = gpio_request(mvsd_data->gpio_card_detect, - DRIVER_NAME " cd"); - if (ret == 0) { - gpio_direction_input(mvsd_data->gpio_card_detect); - irq = gpio_to_irq(mvsd_data->gpio_card_detect); - ret = request_irq(irq, mvsd_card_detect_irq, - IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING, - DRIVER_NAME " cd", host); - if (ret == 0) - host->gpio_card_detect = - mvsd_data->gpio_card_detect; - else - gpio_free(mvsd_data->gpio_card_detect); - } - } - if (!host->gpio_card_detect) - mmc->caps |= MMC_CAP_NEEDS_POLL; - - if (mvsd_data->gpio_write_protect) { - ret = gpio_request(mvsd_data->gpio_write_protect, - DRIVER_NAME " wp"); - if (ret == 0) { - gpio_direction_input(mvsd_data->gpio_write_protect); - host->gpio_write_protect = - mvsd_data->gpio_write_protect; - } - } - - setup_timer(&host->timer, mvsd_timeout_timer, (unsigned long)host); - platform_set_drvdata(pdev, mmc); - ret = mmc_add_host(mmc); - if (ret) - goto out; - - pr_notice("%s: %s driver initialized, ", - mmc_hostname(mmc), DRIVER_NAME); - if (host->gpio_card_detect) - printk("using GPIO %d for card detection\n", - host->gpio_card_detect); - else - printk("lacking card detect (fall back to polling)\n"); - return 0; - -out: - if (host) { - if (host->irq) - free_irq(host->irq, host); - if (host->gpio_card_detect) { - free_irq(gpio_to_irq(host->gpio_card_detect), host); - gpio_free(host->gpio_card_detect); - } - if (host->gpio_write_protect) - gpio_free(host->gpio_write_protect); - if (host->base) - iounmap(host->base); - } - if (r) - release_resource(r); - if (mmc) - mmc_free_host(mmc); - - return ret; -} - -static int __exit mvsd_remove(struct platform_device *pdev) -{ - struct mmc_host *mmc = platform_get_drvdata(pdev); - - if (mmc) { - struct mvsd_host *host = mmc_priv(mmc); - - if (host->gpio_card_detect) { - free_irq(gpio_to_irq(host->gpio_card_detect), host); - gpio_free(host->gpio_card_detect); - } - mmc_remove_host(mmc); - free_irq(host->irq, host); - if (host->gpio_write_protect) - gpio_free(host->gpio_write_protect); - del_timer_sync(&host->timer); - mvsd_power_down(host); - iounmap(host->base); - release_resource(host->res); - mmc_free_host(mmc); - } - platform_set_drvdata(pdev, NULL); - return 0; -} - -#ifdef CONFIG_PM -static int mvsd_suspend(struct platform_device *dev, pm_message_t state) -{ - struct mmc_host *mmc = platform_get_drvdata(dev); - int ret = 0; - - if (mmc) - ret = mmc_suspend_host(mmc); - - return ret; -} - -static int mvsd_resume(struct platform_device *dev) -{ - struct mmc_host *mmc = platform_get_drvdata(dev); - int ret = 0; - - if (mmc) - ret = mmc_resume_host(mmc); - - return ret; -} -#else -#define mvsd_suspend NULL -#define mvsd_resume NULL -#endif - -static struct platform_driver mvsd_driver = { - .remove = __exit_p(mvsd_remove), - .suspend = mvsd_suspend, - .resume = mvsd_resume, - .driver = { - .name = DRIVER_NAME, - }, -}; - -static int __init mvsd_init(void) -{ - return platform_driver_probe(&mvsd_driver, mvsd_probe); -} - -static void __exit mvsd_exit(void) -{ - platform_driver_unregister(&mvsd_driver); -} - -module_init(mvsd_init); -module_exit(mvsd_exit); - -/* maximum card clock frequency (default 50MHz) */ -module_param(maxfreq, int, 0); - -/* force PIO transfers all the time */ -module_param(nodma, int, 0); - -MODULE_AUTHOR("Maen Suleiman, Nicolas Pitre"); -MODULE_DESCRIPTION("Marvell MMC,SD,SDIO Host Controller driver"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:mvsdio"); diff --git a/ANDROID_3.4.5/drivers/mmc/host/mvsdio.h b/ANDROID_3.4.5/drivers/mmc/host/mvsdio.h deleted file mode 100644 index 7d9727b9..00000000 --- a/ANDROID_3.4.5/drivers/mmc/host/mvsdio.h +++ /dev/null @@ -1,190 +0,0 @@ -/* - * Copyright (C) 2008 Marvell Semiconductors, All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef __MVSDIO_H -#define __MVSDIO_H - -/* - * Clock rates - */ - -#define MVSD_CLOCKRATE_MAX 50000000 -#define MVSD_BASE_DIV_MAX 0x7ff - - -/* - * Register offsets - */ - -#define MVSD_SYS_ADDR_LOW 0x000 -#define MVSD_SYS_ADDR_HI 0x004 -#define MVSD_BLK_SIZE 0x008 -#define MVSD_BLK_COUNT 0x00c -#define MVSD_ARG_LOW 0x010 -#define MVSD_ARG_HI 0x014 -#define MVSD_XFER_MODE 0x018 -#define MVSD_CMD 0x01c -#define MVSD_RSP(i) (0x020 + ((i)<<2)) -#define MVSD_RSP0 0x020 -#define MVSD_RSP1 0x024 -#define MVSD_RSP2 0x028 -#define MVSD_RSP3 0x02c -#define MVSD_RSP4 0x030 -#define MVSD_RSP5 0x034 -#define MVSD_RSP6 0x038 -#define MVSD_RSP7 0x03c -#define MVSD_FIFO 0x040 -#define MVSD_RSP_CRC7 0x044 -#define MVSD_HW_STATE 0x048 -#define MVSD_HOST_CTRL 0x050 -#define MVSD_BLK_GAP_CTRL 0x054 -#define MVSD_CLK_CTRL 0x058 -#define MVSD_SW_RESET 0x05c -#define MVSD_NOR_INTR_STATUS 0x060 -#define MVSD_ERR_INTR_STATUS 0x064 -#define MVSD_NOR_STATUS_EN 0x068 -#define MVSD_ERR_STATUS_EN 0x06c -#define MVSD_NOR_INTR_EN 0x070 -#define MVSD_ERR_INTR_EN 0x074 -#define MVSD_AUTOCMD12_ERR_STATUS 0x078 -#define MVSD_CURR_BYTE_LEFT 0x07c -#define MVSD_CURR_BLK_LEFT 0x080 -#define MVSD_AUTOCMD12_ARG_LOW 0x084 -#define MVSD_AUTOCMD12_ARG_HI 0x088 -#define MVSD_AUTOCMD12_CMD 0x08c -#define MVSD_AUTO_RSP(i) (0x090 + ((i)<<2)) -#define MVSD_AUTO_RSP0 0x090 -#define MVSD_AUTO_RSP1 0x094 -#define MVSD_AUTO_RSP2 0x098 -#define MVSD_CLK_DIV 0x128 - -#define MVSD_WINDOW_CTRL(i) (0x108 + ((i) << 3)) -#define MVSD_WINDOW_BASE(i) (0x10c + ((i) << 3)) - - -/* - * MVSD_CMD - */ - -#define MVSD_CMD_RSP_NONE (0 << 0) -#define MVSD_CMD_RSP_136 (1 << 0) -#define MVSD_CMD_RSP_48 (2 << 0) -#define MVSD_CMD_RSP_48BUSY (3 << 0) - -#define MVSD_CMD_CHECK_DATACRC16 (1 << 2) -#define MVSD_CMD_CHECK_CMDCRC (1 << 3) -#define MVSD_CMD_INDX_CHECK (1 << 4) -#define MVSD_CMD_DATA_PRESENT (1 << 5) -#define MVSD_UNEXPECTED_RESP (1 << 7) -#define MVSD_CMD_INDEX(x) ((x) << 8) - - -/* - * MVSD_AUTOCMD12_CMD - */ - -#define MVSD_AUTOCMD12_BUSY (1 << 0) -#define MVSD_AUTOCMD12_INDX_CHECK (1 << 1) -#define MVSD_AUTOCMD12_INDEX(x) ((x) << 8) - -/* - * MVSD_XFER_MODE - */ - -#define MVSD_XFER_MODE_WR_DATA_START (1 << 0) -#define MVSD_XFER_MODE_HW_WR_DATA_EN (1 << 1) -#define MVSD_XFER_MODE_AUTO_CMD12 (1 << 2) -#define MVSD_XFER_MODE_INT_CHK_EN (1 << 3) -#define MVSD_XFER_MODE_TO_HOST (1 << 4) -#define MVSD_XFER_MODE_STOP_CLK (1 << 5) -#define MVSD_XFER_MODE_PIO (1 << 6) - - -/* - * MVSD_HOST_CTRL - */ - -#define MVSD_HOST_CTRL_PUSH_PULL_EN (1 << 0) - -#define MVSD_HOST_CTRL_CARD_TYPE_MEM_ONLY (0 << 1) -#define MVSD_HOST_CTRL_CARD_TYPE_IO_ONLY (1 << 1) -#define MVSD_HOST_CTRL_CARD_TYPE_IO_MEM_COMBO (2 << 1) -#define MVSD_HOST_CTRL_CARD_TYPE_IO_MMC (3 << 1) -#define MVSD_HOST_CTRL_CARD_TYPE_MASK (3 << 1) - -#define MVSD_HOST_CTRL_BIG_ENDIAN (1 << 3) -#define MVSD_HOST_CTRL_LSB_FIRST (1 << 4) -#define MVSD_HOST_CTRL_DATA_WIDTH_4_BITS (1 << 9) -#define MVSD_HOST_CTRL_HI_SPEED_EN (1 << 10) - -#define MVSD_HOST_CTRL_TMOUT_MAX 0xf -#define MVSD_HOST_CTRL_TMOUT_MASK (0xf << 11) -#define MVSD_HOST_CTRL_TMOUT(x) ((x) << 11) -#define MVSD_HOST_CTRL_TMOUT_EN (1 << 15) - - -/* - * MVSD_SW_RESET - */ - -#define MVSD_SW_RESET_NOW (1 << 8) - - -/* - * Normal interrupt status bits - */ - -#define MVSD_NOR_CMD_DONE (1 << 0) -#define MVSD_NOR_XFER_DONE (1 << 1) -#define MVSD_NOR_BLK_GAP_EVT (1 << 2) -#define MVSD_NOR_DMA_DONE (1 << 3) -#define MVSD_NOR_TX_AVAIL (1 << 4) -#define MVSD_NOR_RX_READY (1 << 5) -#define MVSD_NOR_CARD_INT (1 << 8) -#define MVSD_NOR_READ_WAIT_ON (1 << 9) -#define MVSD_NOR_RX_FIFO_8W (1 << 10) -#define MVSD_NOR_TX_FIFO_8W (1 << 11) -#define MVSD_NOR_SUSPEND_ON (1 << 12) -#define MVSD_NOR_AUTOCMD12_DONE (1 << 13) -#define MVSD_NOR_UNEXP_RSP (1 << 14) -#define MVSD_NOR_ERROR (1 << 15) - - -/* - * Error status bits - */ - -#define MVSD_ERR_CMD_TIMEOUT (1 << 0) -#define MVSD_ERR_CMD_CRC (1 << 1) -#define MVSD_ERR_CMD_ENDBIT (1 << 2) -#define MVSD_ERR_CMD_INDEX (1 << 3) -#define MVSD_ERR_DATA_TIMEOUT (1 << 4) -#define MVSD_ERR_DATA_CRC (1 << 5) -#define MVSD_ERR_DATA_ENDBIT (1 << 6) -#define MVSD_ERR_AUTOCMD12 (1 << 8) -#define MVSD_ERR_CMD_STARTBIT (1 << 9) -#define MVSD_ERR_XFER_SIZE (1 << 10) -#define MVSD_ERR_RESP_T_BIT (1 << 11) -#define MVSD_ERR_CRC_ENDBIT (1 << 12) -#define MVSD_ERR_CRC_STARTBIT (1 << 13) -#define MVSD_ERR_CRC_STATUS (1 << 14) - - -/* - * CMD12 error status bits - */ - -#define MVSD_AUTOCMD12_ERR_NOTEXE (1 << 0) -#define MVSD_AUTOCMD12_ERR_TIMEOUT (1 << 1) -#define MVSD_AUTOCMD12_ERR_CRC (1 << 2) -#define MVSD_AUTOCMD12_ERR_ENDBIT (1 << 3) -#define MVSD_AUTOCMD12_ERR_INDEX (1 << 4) -#define MVSD_AUTOCMD12_ERR_RESP_T_BIT (1 << 5) -#define MVSD_AUTOCMD12_ERR_RESP_STARTBIT (1 << 6) - -#endif diff --git a/ANDROID_3.4.5/drivers/mmc/host/mxcmmc.c b/ANDROID_3.4.5/drivers/mmc/host/mxcmmc.c deleted file mode 100644 index b2058b43..00000000 --- a/ANDROID_3.4.5/drivers/mmc/host/mxcmmc.c +++ /dev/null @@ -1,1062 +0,0 @@ -/* - * linux/drivers/mmc/host/mxcmmc.c - Freescale i.MX MMCI driver - * - * This is a driver for the SDHC controller found in Freescale MX2/MX3 - * SoCs. It is basically the same hardware as found on MX1 (imxmmc.c). - * Unlike the hardware found on MX1, this hardware just works and does - * not need all the quirks found in imxmmc.c, hence the separate driver. - * - * Copyright (C) 2008 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de> - * Copyright (C) 2006 Pavel Pisa, PiKRON <ppisa@pikron.com> - * - * derived from pxamci.c by Russell King - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - */ - -#include <linux/module.h> -#include <linux/init.h> -#include <linux/ioport.h> -#include <linux/platform_device.h> -#include <linux/interrupt.h> -#include <linux/irq.h> -#include <linux/blkdev.h> -#include <linux/dma-mapping.h> -#include <linux/mmc/host.h> -#include <linux/mmc/card.h> -#include <linux/delay.h> -#include <linux/clk.h> -#include <linux/io.h> -#include <linux/gpio.h> -#include <linux/regulator/consumer.h> -#include <linux/dmaengine.h> -#include <linux/types.h> - -#include <asm/dma.h> -#include <asm/irq.h> -#include <asm/sizes.h> -#include <mach/mmc.h> - -#include <mach/dma.h> -#include <mach/hardware.h> - -#define DRIVER_NAME "mxc-mmc" - -#define MMC_REG_STR_STP_CLK 0x00 -#define MMC_REG_STATUS 0x04 -#define MMC_REG_CLK_RATE 0x08 -#define MMC_REG_CMD_DAT_CONT 0x0C -#define MMC_REG_RES_TO 0x10 -#define MMC_REG_READ_TO 0x14 -#define MMC_REG_BLK_LEN 0x18 -#define MMC_REG_NOB 0x1C -#define MMC_REG_REV_NO 0x20 -#define MMC_REG_INT_CNTR 0x24 -#define MMC_REG_CMD 0x28 -#define MMC_REG_ARG 0x2C -#define MMC_REG_RES_FIFO 0x34 -#define MMC_REG_BUFFER_ACCESS 0x38 - -#define STR_STP_CLK_RESET (1 << 3) -#define STR_STP_CLK_START_CLK (1 << 1) -#define STR_STP_CLK_STOP_CLK (1 << 0) - -#define STATUS_CARD_INSERTION (1 << 31) -#define STATUS_CARD_REMOVAL (1 << 30) -#define STATUS_YBUF_EMPTY (1 << 29) -#define STATUS_XBUF_EMPTY (1 << 28) -#define STATUS_YBUF_FULL (1 << 27) -#define STATUS_XBUF_FULL (1 << 26) -#define STATUS_BUF_UND_RUN (1 << 25) -#define STATUS_BUF_OVFL (1 << 24) -#define STATUS_SDIO_INT_ACTIVE (1 << 14) -#define STATUS_END_CMD_RESP (1 << 13) -#define STATUS_WRITE_OP_DONE (1 << 12) -#define STATUS_DATA_TRANS_DONE (1 << 11) -#define STATUS_READ_OP_DONE (1 << 11) -#define STATUS_WR_CRC_ERROR_CODE_MASK (3 << 10) -#define STATUS_CARD_BUS_CLK_RUN (1 << 8) -#define STATUS_BUF_READ_RDY (1 << 7) -#define STATUS_BUF_WRITE_RDY (1 << 6) -#define STATUS_RESP_CRC_ERR (1 << 5) -#define STATUS_CRC_READ_ERR (1 << 3) -#define STATUS_CRC_WRITE_ERR (1 << 2) -#define STATUS_TIME_OUT_RESP (1 << 1) -#define STATUS_TIME_OUT_READ (1 << 0) -#define STATUS_ERR_MASK 0x2f - -#define CMD_DAT_CONT_CMD_RESP_LONG_OFF (1 << 12) -#define CMD_DAT_CONT_STOP_READWAIT (1 << 11) -#define CMD_DAT_CONT_START_READWAIT (1 << 10) -#define CMD_DAT_CONT_BUS_WIDTH_4 (2 << 8) -#define CMD_DAT_CONT_INIT (1 << 7) -#define CMD_DAT_CONT_WRITE (1 << 4) -#define CMD_DAT_CONT_DATA_ENABLE (1 << 3) -#define CMD_DAT_CONT_RESPONSE_48BIT_CRC (1 << 0) -#define CMD_DAT_CONT_RESPONSE_136BIT (2 << 0) -#define CMD_DAT_CONT_RESPONSE_48BIT (3 << 0) - -#define INT_SDIO_INT_WKP_EN (1 << 18) -#define INT_CARD_INSERTION_WKP_EN (1 << 17) -#define INT_CARD_REMOVAL_WKP_EN (1 << 16) -#define INT_CARD_INSERTION_EN (1 << 15) -#define INT_CARD_REMOVAL_EN (1 << 14) -#define INT_SDIO_IRQ_EN (1 << 13) -#define INT_DAT0_EN (1 << 12) -#define INT_BUF_READ_EN (1 << 4) -#define INT_BUF_WRITE_EN (1 << 3) -#define INT_END_CMD_RES_EN (1 << 2) -#define INT_WRITE_OP_DONE_EN (1 << 1) -#define INT_READ_OP_EN (1 << 0) - -struct mxcmci_host { - struct mmc_host *mmc; - struct resource *res; - void __iomem *base; - int irq; - int detect_irq; - struct dma_chan *dma; - struct dma_async_tx_descriptor *desc; - int do_dma; - int default_irq_mask; - int use_sdio; - unsigned int power_mode; - struct imxmmc_platform_data *pdata; - - struct mmc_request *req; - struct mmc_command *cmd; - struct mmc_data *data; - - unsigned int datasize; - unsigned int dma_dir; - - u16 rev_no; - unsigned int cmdat; - - struct clk *clk; - - int clock; - - struct work_struct datawork; - spinlock_t lock; - - struct regulator *vcc; - - int burstlen; - int dmareq; - struct dma_slave_config dma_slave_config; - struct imx_dma_data dma_data; -}; - -static void mxcmci_set_clk_rate(struct mxcmci_host *host, unsigned int clk_ios); - -static inline void mxcmci_init_ocr(struct mxcmci_host *host) -{ - host->vcc = regulator_get(mmc_dev(host->mmc), "vmmc"); - - if (IS_ERR(host->vcc)) { - host->vcc = NULL; - } else { - host->mmc->ocr_avail = mmc_regulator_get_ocrmask(host->vcc); - if (host->pdata && host->pdata->ocr_avail) - dev_warn(mmc_dev(host->mmc), - "pdata->ocr_avail will not be used\n"); - } - - if (host->vcc == NULL) { - /* fall-back to platform data */ - if (host->pdata && host->pdata->ocr_avail) - host->mmc->ocr_avail = host->pdata->ocr_avail; - else - host->mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; - } -} - -static inline void mxcmci_set_power(struct mxcmci_host *host, - unsigned char power_mode, - unsigned int vdd) -{ - if (host->vcc) { - if (power_mode == MMC_POWER_UP) - mmc_regulator_set_ocr(host->mmc, host->vcc, vdd); - else if (power_mode == MMC_POWER_OFF) - mmc_regulator_set_ocr(host->mmc, host->vcc, 0); - } - - if (host->pdata && host->pdata->setpower) - host->pdata->setpower(mmc_dev(host->mmc), vdd); -} - -static inline int mxcmci_use_dma(struct mxcmci_host *host) -{ - return host->do_dma; -} - -static void mxcmci_softreset(struct mxcmci_host *host) -{ - int i; - - dev_dbg(mmc_dev(host->mmc), "mxcmci_softreset\n"); - - /* reset sequence */ - writew(STR_STP_CLK_RESET, host->base + MMC_REG_STR_STP_CLK); - writew(STR_STP_CLK_RESET | STR_STP_CLK_START_CLK, - host->base + MMC_REG_STR_STP_CLK); - - for (i = 0; i < 8; i++) - writew(STR_STP_CLK_START_CLK, host->base + MMC_REG_STR_STP_CLK); - - writew(0xff, host->base + MMC_REG_RES_TO); -} -static int mxcmci_setup_dma(struct mmc_host *mmc); - -static int mxcmci_setup_data(struct mxcmci_host *host, struct mmc_data *data) -{ - unsigned int nob = data->blocks; - unsigned int blksz = data->blksz; - unsigned int datasize = nob * blksz; - struct scatterlist *sg; - enum dma_transfer_direction slave_dirn; - int i, nents; - - if (data->flags & MMC_DATA_STREAM) - nob = 0xffff; - - host->data = data; - data->bytes_xfered = 0; - - writew(nob, host->base + MMC_REG_NOB); - writew(blksz, host->base + MMC_REG_BLK_LEN); - host->datasize = datasize; - - if (!mxcmci_use_dma(host)) - return 0; - - for_each_sg(data->sg, sg, data->sg_len, i) { - if (sg->offset & 3 || sg->length & 3) { - host->do_dma = 0; - return 0; - } - } - - if (data->flags & MMC_DATA_READ) { - host->dma_dir = DMA_FROM_DEVICE; - slave_dirn = DMA_DEV_TO_MEM; - } else { - host->dma_dir = DMA_TO_DEVICE; - slave_dirn = DMA_MEM_TO_DEV; - } - - nents = dma_map_sg(host->dma->device->dev, data->sg, - data->sg_len, host->dma_dir); - if (nents != data->sg_len) - return -EINVAL; - - host->desc = dmaengine_prep_slave_sg(host->dma, - data->sg, data->sg_len, slave_dirn, - DMA_PREP_INTERRUPT | DMA_CTRL_ACK); - - if (!host->desc) { - dma_unmap_sg(host->dma->device->dev, data->sg, data->sg_len, - host->dma_dir); - host->do_dma = 0; - return 0; /* Fall back to PIO */ - } - wmb(); - - dmaengine_submit(host->desc); - dma_async_issue_pending(host->dma); - - return 0; -} - -static int mxcmci_start_cmd(struct mxcmci_host *host, struct mmc_command *cmd, - unsigned int cmdat) -{ - u32 int_cntr = host->default_irq_mask; - unsigned long flags; - - WARN_ON(host->cmd != NULL); - host->cmd = cmd; - - switch (mmc_resp_type(cmd)) { - case MMC_RSP_R1: /* short CRC, OPCODE */ - case MMC_RSP_R1B:/* short CRC, OPCODE, BUSY */ - cmdat |= CMD_DAT_CONT_RESPONSE_48BIT_CRC; - break; - case MMC_RSP_R2: /* long 136 bit + CRC */ - cmdat |= CMD_DAT_CONT_RESPONSE_136BIT; - break; - case MMC_RSP_R3: /* short */ - cmdat |= CMD_DAT_CONT_RESPONSE_48BIT; - break; - case MMC_RSP_NONE: - break; - default: - dev_err(mmc_dev(host->mmc), "unhandled response type 0x%x\n", - mmc_resp_type(cmd)); - cmd->error = -EINVAL; - return -EINVAL; - } - - int_cntr = INT_END_CMD_RES_EN; - - if (mxcmci_use_dma(host)) - int_cntr |= INT_READ_OP_EN | INT_WRITE_OP_DONE_EN; - - spin_lock_irqsave(&host->lock, flags); - if (host->use_sdio) - int_cntr |= INT_SDIO_IRQ_EN; - writel(int_cntr, host->base + MMC_REG_INT_CNTR); - spin_unlock_irqrestore(&host->lock, flags); - - writew(cmd->opcode, host->base + MMC_REG_CMD); - writel(cmd->arg, host->base + MMC_REG_ARG); - writew(cmdat, host->base + MMC_REG_CMD_DAT_CONT); - - return 0; -} - -static void mxcmci_finish_request(struct mxcmci_host *host, - struct mmc_request *req) -{ - u32 int_cntr = host->default_irq_mask; - unsigned long flags; - - spin_lock_irqsave(&host->lock, flags); - if (host->use_sdio) - int_cntr |= INT_SDIO_IRQ_EN; - writel(int_cntr, host->base + MMC_REG_INT_CNTR); - spin_unlock_irqrestore(&host->lock, flags); - - host->req = NULL; - host->cmd = NULL; - host->data = NULL; - - mmc_request_done(host->mmc, req); -} - -static int mxcmci_finish_data(struct mxcmci_host *host, unsigned int stat) -{ - struct mmc_data *data = host->data; - int data_error; - - if (mxcmci_use_dma(host)) { - dmaengine_terminate_all(host->dma); - dma_unmap_sg(host->dma->device->dev, data->sg, data->sg_len, - host->dma_dir); - } - - if (stat & STATUS_ERR_MASK) { - dev_dbg(mmc_dev(host->mmc), "request failed. status: 0x%08x\n", - stat); - if (stat & STATUS_CRC_READ_ERR) { - dev_err(mmc_dev(host->mmc), "%s: -EILSEQ\n", __func__); - data->error = -EILSEQ; - } else if (stat & STATUS_CRC_WRITE_ERR) { - u32 err_code = (stat >> 9) & 0x3; - if (err_code == 2) { /* No CRC response */ - dev_err(mmc_dev(host->mmc), - "%s: No CRC -ETIMEDOUT\n", __func__); - data->error = -ETIMEDOUT; - } else { - dev_err(mmc_dev(host->mmc), - "%s: -EILSEQ\n", __func__); - data->error = -EILSEQ; - } - } else if (stat & STATUS_TIME_OUT_READ) { - dev_err(mmc_dev(host->mmc), - "%s: read -ETIMEDOUT\n", __func__); - data->error = -ETIMEDOUT; - } else { - dev_err(mmc_dev(host->mmc), "%s: -EIO\n", __func__); - data->error = -EIO; - } - } else { - data->bytes_xfered = host->datasize; - } - - data_error = data->error; - - host->data = NULL; - - return data_error; -} - -static void mxcmci_read_response(struct mxcmci_host *host, unsigned int stat) -{ - struct mmc_command *cmd = host->cmd; - int i; - u32 a, b, c; - - if (!cmd) - return; - - if (stat & STATUS_TIME_OUT_RESP) { - dev_dbg(mmc_dev(host->mmc), "CMD TIMEOUT\n"); - cmd->error = -ETIMEDOUT; - } else if (stat & STATUS_RESP_CRC_ERR && cmd->flags & MMC_RSP_CRC) { - dev_dbg(mmc_dev(host->mmc), "cmd crc error\n"); - cmd->error = -EILSEQ; - } - - if (cmd->flags & MMC_RSP_PRESENT) { - if (cmd->flags & MMC_RSP_136) { - for (i = 0; i < 4; i++) { - a = readw(host->base + MMC_REG_RES_FIFO); - b = readw(host->base + MMC_REG_RES_FIFO); - cmd->resp[i] = a << 16 | b; - } - } else { - a = readw(host->base + MMC_REG_RES_FIFO); - b = readw(host->base + MMC_REG_RES_FIFO); - c = readw(host->base + MMC_REG_RES_FIFO); - cmd->resp[0] = a << 24 | b << 8 | c >> 8; - } - } -} - -static int mxcmci_poll_status(struct mxcmci_host *host, u32 mask) -{ - u32 stat; - unsigned long timeout = jiffies + HZ; - - do { - stat = readl(host->base + MMC_REG_STATUS); - if (stat & STATUS_ERR_MASK) - return stat; - if (time_after(jiffies, timeout)) { - mxcmci_softreset(host); - mxcmci_set_clk_rate(host, host->clock); - return STATUS_TIME_OUT_READ; - } - if (stat & mask) - return 0; - cpu_relax(); - } while (1); -} - -static int mxcmci_pull(struct mxcmci_host *host, void *_buf, int bytes) -{ - unsigned int stat; - u32 *buf = _buf; - - while (bytes > 3) { - stat = mxcmci_poll_status(host, - STATUS_BUF_READ_RDY | STATUS_READ_OP_DONE); - if (stat) - return stat; - *buf++ = readl(host->base + MMC_REG_BUFFER_ACCESS); - bytes -= 4; - } - - if (bytes) { - u8 *b = (u8 *)buf; - u32 tmp; - - stat = mxcmci_poll_status(host, - STATUS_BUF_READ_RDY | STATUS_READ_OP_DONE); - if (stat) - return stat; - tmp = readl(host->base + MMC_REG_BUFFER_ACCESS); - memcpy(b, &tmp, bytes); - } - - return 0; -} - -static int mxcmci_push(struct mxcmci_host *host, void *_buf, int bytes) -{ - unsigned int stat; - u32 *buf = _buf; - - while (bytes > 3) { - stat = mxcmci_poll_status(host, STATUS_BUF_WRITE_RDY); - if (stat) - return stat; - writel(*buf++, host->base + MMC_REG_BUFFER_ACCESS); - bytes -= 4; - } - - if (bytes) { - u8 *b = (u8 *)buf; - u32 tmp; - - stat = mxcmci_poll_status(host, STATUS_BUF_WRITE_RDY); - if (stat) - return stat; - - memcpy(&tmp, b, bytes); - writel(tmp, host->base + MMC_REG_BUFFER_ACCESS); - } - - stat = mxcmci_poll_status(host, STATUS_BUF_WRITE_RDY); - if (stat) - return stat; - - return 0; -} - -static int mxcmci_transfer_data(struct mxcmci_host *host) -{ - struct mmc_data *data = host->req->data; - struct scatterlist *sg; - int stat, i; - - host->data = data; - host->datasize = 0; - - if (data->flags & MMC_DATA_READ) { - for_each_sg(data->sg, sg, data->sg_len, i) { - stat = mxcmci_pull(host, sg_virt(sg), sg->length); - if (stat) - return stat; - host->datasize += sg->length; - } - } else { - for_each_sg(data->sg, sg, data->sg_len, i) { - stat = mxcmci_push(host, sg_virt(sg), sg->length); - if (stat) - return stat; - host->datasize += sg->length; - } - stat = mxcmci_poll_status(host, STATUS_WRITE_OP_DONE); - if (stat) - return stat; - } - return 0; -} - -static void mxcmci_datawork(struct work_struct *work) -{ - struct mxcmci_host *host = container_of(work, struct mxcmci_host, - datawork); - int datastat = mxcmci_transfer_data(host); - - writel(STATUS_READ_OP_DONE | STATUS_WRITE_OP_DONE, - host->base + MMC_REG_STATUS); - mxcmci_finish_data(host, datastat); - - if (host->req->stop) { - if (mxcmci_start_cmd(host, host->req->stop, 0)) { - mxcmci_finish_request(host, host->req); - return; - } - } else { - mxcmci_finish_request(host, host->req); - } -} - -static void mxcmci_data_done(struct mxcmci_host *host, unsigned int stat) -{ - struct mmc_data *data = host->data; - int data_error; - - if (!data) - return; - - data_error = mxcmci_finish_data(host, stat); - - mxcmci_read_response(host, stat); - host->cmd = NULL; - - if (host->req->stop) { - if (mxcmci_start_cmd(host, host->req->stop, 0)) { - mxcmci_finish_request(host, host->req); - return; - } - } else { - mxcmci_finish_request(host, host->req); - } -} - -static void mxcmci_cmd_done(struct mxcmci_host *host, unsigned int stat) -{ - mxcmci_read_response(host, stat); - host->cmd = NULL; - - if (!host->data && host->req) { - mxcmci_finish_request(host, host->req); - return; - } - - /* For the DMA case the DMA engine handles the data transfer - * automatically. For non DMA we have to do it ourselves. - * Don't do it in interrupt context though. - */ - if (!mxcmci_use_dma(host) && host->data) - schedule_work(&host->datawork); - -} - -static irqreturn_t mxcmci_irq(int irq, void *devid) -{ - struct mxcmci_host *host = devid; - unsigned long flags; - bool sdio_irq; - u32 stat; - - stat = readl(host->base + MMC_REG_STATUS); - writel(stat & ~(STATUS_SDIO_INT_ACTIVE | STATUS_DATA_TRANS_DONE | - STATUS_WRITE_OP_DONE), host->base + MMC_REG_STATUS); - - dev_dbg(mmc_dev(host->mmc), "%s: 0x%08x\n", __func__, stat); - - spin_lock_irqsave(&host->lock, flags); - sdio_irq = (stat & STATUS_SDIO_INT_ACTIVE) && host->use_sdio; - spin_unlock_irqrestore(&host->lock, flags); - - if (mxcmci_use_dma(host) && - (stat & (STATUS_READ_OP_DONE | STATUS_WRITE_OP_DONE))) - writel(STATUS_READ_OP_DONE | STATUS_WRITE_OP_DONE, - host->base + MMC_REG_STATUS); - - if (sdio_irq) { - writel(STATUS_SDIO_INT_ACTIVE, host->base + MMC_REG_STATUS); - mmc_signal_sdio_irq(host->mmc); - } - - if (stat & STATUS_END_CMD_RESP) - mxcmci_cmd_done(host, stat); - - if (mxcmci_use_dma(host) && - (stat & (STATUS_DATA_TRANS_DONE | STATUS_WRITE_OP_DONE))) - mxcmci_data_done(host, stat); - - if (host->default_irq_mask && - (stat & (STATUS_CARD_INSERTION | STATUS_CARD_REMOVAL))) - mmc_detect_change(host->mmc, msecs_to_jiffies(200)); - - return IRQ_HANDLED; -} - -static void mxcmci_request(struct mmc_host *mmc, struct mmc_request *req) -{ - struct mxcmci_host *host = mmc_priv(mmc); - unsigned int cmdat = host->cmdat; - int error; - - WARN_ON(host->req != NULL); - - host->req = req; - host->cmdat &= ~CMD_DAT_CONT_INIT; - - if (host->dma) - host->do_dma = 1; - - if (req->data) { - error = mxcmci_setup_data(host, req->data); - if (error) { - req->cmd->error = error; - goto out; - } - - - cmdat |= CMD_DAT_CONT_DATA_ENABLE; - - if (req->data->flags & MMC_DATA_WRITE) - cmdat |= CMD_DAT_CONT_WRITE; - } - - error = mxcmci_start_cmd(host, req->cmd, cmdat); - -out: - if (error) - mxcmci_finish_request(host, req); -} - -static void mxcmci_set_clk_rate(struct mxcmci_host *host, unsigned int clk_ios) -{ - unsigned int divider; - int prescaler = 0; - unsigned int clk_in = clk_get_rate(host->clk); - - while (prescaler <= 0x800) { - for (divider = 1; divider <= 0xF; divider++) { - int x; - - x = (clk_in / (divider + 1)); - - if (prescaler) - x /= (prescaler * 2); - - if (x <= clk_ios) - break; - } - if (divider < 0x10) - break; - - if (prescaler == 0) - prescaler = 1; - else - prescaler <<= 1; - } - - writew((prescaler << 4) | divider, host->base + MMC_REG_CLK_RATE); - - dev_dbg(mmc_dev(host->mmc), "scaler: %d divider: %d in: %d out: %d\n", - prescaler, divider, clk_in, clk_ios); -} - -static int mxcmci_setup_dma(struct mmc_host *mmc) -{ - struct mxcmci_host *host = mmc_priv(mmc); - struct dma_slave_config *config = &host->dma_slave_config; - - config->dst_addr = host->res->start + MMC_REG_BUFFER_ACCESS; - config->src_addr = host->res->start + MMC_REG_BUFFER_ACCESS; - config->dst_addr_width = 4; - config->src_addr_width = 4; - config->dst_maxburst = host->burstlen; - config->src_maxburst = host->burstlen; - config->device_fc = false; - - return dmaengine_slave_config(host->dma, config); -} - -static void mxcmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) -{ - struct mxcmci_host *host = mmc_priv(mmc); - int burstlen, ret; - - /* - * use burstlen of 64 (16 words) in 4 bit mode (--> reg value 0) - * use burstlen of 16 (4 words) in 1 bit mode (--> reg value 16) - */ - if (ios->bus_width == MMC_BUS_WIDTH_4) - burstlen = 16; - else - burstlen = 4; - - if (mxcmci_use_dma(host) && burstlen != host->burstlen) { - host->burstlen = burstlen; - ret = mxcmci_setup_dma(mmc); - if (ret) { - dev_err(mmc_dev(host->mmc), - "failed to config DMA channel. Falling back to PIO\n"); - dma_release_channel(host->dma); - host->do_dma = 0; - host->dma = NULL; - } - } - - if (ios->bus_width == MMC_BUS_WIDTH_4) - host->cmdat |= CMD_DAT_CONT_BUS_WIDTH_4; - else - host->cmdat &= ~CMD_DAT_CONT_BUS_WIDTH_4; - - if (host->power_mode != ios->power_mode) { - mxcmci_set_power(host, ios->power_mode, ios->vdd); - host->power_mode = ios->power_mode; - - if (ios->power_mode == MMC_POWER_ON) - host->cmdat |= CMD_DAT_CONT_INIT; - } - - if (ios->clock) { - mxcmci_set_clk_rate(host, ios->clock); - writew(STR_STP_CLK_START_CLK, host->base + MMC_REG_STR_STP_CLK); - } else { - writew(STR_STP_CLK_STOP_CLK, host->base + MMC_REG_STR_STP_CLK); - } - - host->clock = ios->clock; -} - -static irqreturn_t mxcmci_detect_irq(int irq, void *data) -{ - struct mmc_host *mmc = data; - - dev_dbg(mmc_dev(mmc), "%s\n", __func__); - - mmc_detect_change(mmc, msecs_to_jiffies(250)); - return IRQ_HANDLED; -} - -static int mxcmci_get_ro(struct mmc_host *mmc) -{ - struct mxcmci_host *host = mmc_priv(mmc); - - if (host->pdata && host->pdata->get_ro) - return !!host->pdata->get_ro(mmc_dev(mmc)); - /* - * Board doesn't support read only detection; let the mmc core - * decide what to do. - */ - return -ENOSYS; -} - -static void mxcmci_enable_sdio_irq(struct mmc_host *mmc, int enable) -{ - struct mxcmci_host *host = mmc_priv(mmc); - unsigned long flags; - u32 int_cntr; - - spin_lock_irqsave(&host->lock, flags); - host->use_sdio = enable; - int_cntr = readl(host->base + MMC_REG_INT_CNTR); - - if (enable) - int_cntr |= INT_SDIO_IRQ_EN; - else - int_cntr &= ~INT_SDIO_IRQ_EN; - - writel(int_cntr, host->base + MMC_REG_INT_CNTR); - spin_unlock_irqrestore(&host->lock, flags); -} - -static void mxcmci_init_card(struct mmc_host *host, struct mmc_card *card) -{ - /* - * MX3 SoCs have a silicon bug which corrupts CRC calculation of - * multi-block transfers when connected SDIO peripheral doesn't - * drive the BUSY line as required by the specs. - * One way to prevent this is to only allow 1-bit transfers. - */ - - if (cpu_is_mx3() && card->type == MMC_TYPE_SDIO) - host->caps &= ~MMC_CAP_4_BIT_DATA; - else - host->caps |= MMC_CAP_4_BIT_DATA; -} - -static bool filter(struct dma_chan *chan, void *param) -{ - struct mxcmci_host *host = param; - - if (!imx_dma_is_general_purpose(chan)) - return false; - - chan->private = &host->dma_data; - - return true; -} - -static const struct mmc_host_ops mxcmci_ops = { - .request = mxcmci_request, - .set_ios = mxcmci_set_ios, - .get_ro = mxcmci_get_ro, - .enable_sdio_irq = mxcmci_enable_sdio_irq, - .init_card = mxcmci_init_card, -}; - -static int mxcmci_probe(struct platform_device *pdev) -{ - struct mmc_host *mmc; - struct mxcmci_host *host = NULL; - struct resource *iores, *r; - int ret = 0, irq; - dma_cap_mask_t mask; - - pr_info("i.MX SDHC driver\n"); - - iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); - irq = platform_get_irq(pdev, 0); - if (!iores || irq < 0) - return -EINVAL; - - r = request_mem_region(iores->start, resource_size(iores), pdev->name); - if (!r) - return -EBUSY; - - mmc = mmc_alloc_host(sizeof(struct mxcmci_host), &pdev->dev); - if (!mmc) { - ret = -ENOMEM; - goto out_release_mem; - } - - mmc->ops = &mxcmci_ops; - mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ; - - /* MMC core transfer sizes tunable parameters */ - mmc->max_segs = 64; - mmc->max_blk_size = 2048; - mmc->max_blk_count = 65535; - mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count; - mmc->max_seg_size = mmc->max_req_size; - - host = mmc_priv(mmc); - host->base = ioremap(r->start, resource_size(r)); - if (!host->base) { - ret = -ENOMEM; - goto out_free; - } - - host->mmc = mmc; - host->pdata = pdev->dev.platform_data; - spin_lock_init(&host->lock); - - mxcmci_init_ocr(host); - - if (host->pdata && host->pdata->dat3_card_detect) - host->default_irq_mask = - INT_CARD_INSERTION_EN | INT_CARD_REMOVAL_EN; - else - host->default_irq_mask = 0; - - host->res = r; - host->irq = irq; - - host->clk = clk_get(&pdev->dev, NULL); - if (IS_ERR(host->clk)) { - ret = PTR_ERR(host->clk); - goto out_iounmap; - } - clk_enable(host->clk); - - mxcmci_softreset(host); - - host->rev_no = readw(host->base + MMC_REG_REV_NO); - if (host->rev_no != 0x400) { - ret = -ENODEV; - dev_err(mmc_dev(host->mmc), "wrong rev.no. 0x%08x. aborting.\n", - host->rev_no); - goto out_clk_put; - } - - mmc->f_min = clk_get_rate(host->clk) >> 16; - mmc->f_max = clk_get_rate(host->clk) >> 1; - - /* recommended in data sheet */ - writew(0x2db4, host->base + MMC_REG_READ_TO); - - writel(host->default_irq_mask, host->base + MMC_REG_INT_CNTR); - - r = platform_get_resource(pdev, IORESOURCE_DMA, 0); - if (r) { - host->dmareq = r->start; - host->dma_data.peripheral_type = IMX_DMATYPE_SDHC; - host->dma_data.priority = DMA_PRIO_LOW; - host->dma_data.dma_request = host->dmareq; - dma_cap_zero(mask); - dma_cap_set(DMA_SLAVE, mask); - host->dma = dma_request_channel(mask, filter, host); - if (host->dma) - mmc->max_seg_size = dma_get_max_seg_size( - host->dma->device->dev); - } - - if (!host->dma) - dev_info(mmc_dev(host->mmc), "dma not available. Using PIO\n"); - - INIT_WORK(&host->datawork, mxcmci_datawork); - - ret = request_irq(host->irq, mxcmci_irq, 0, DRIVER_NAME, host); - if (ret) - goto out_free_dma; - - platform_set_drvdata(pdev, mmc); - - if (host->pdata && host->pdata->init) { - ret = host->pdata->init(&pdev->dev, mxcmci_detect_irq, - host->mmc); - if (ret) - goto out_free_irq; - } - - mmc_add_host(mmc); - - return 0; - -out_free_irq: - free_irq(host->irq, host); -out_free_dma: - if (host->dma) - dma_release_channel(host->dma); -out_clk_put: - clk_disable(host->clk); - clk_put(host->clk); -out_iounmap: - iounmap(host->base); -out_free: - mmc_free_host(mmc); -out_release_mem: - release_mem_region(iores->start, resource_size(iores)); - return ret; -} - -static int mxcmci_remove(struct platform_device *pdev) -{ - struct mmc_host *mmc = platform_get_drvdata(pdev); - struct mxcmci_host *host = mmc_priv(mmc); - - platform_set_drvdata(pdev, NULL); - - mmc_remove_host(mmc); - - if (host->vcc) - regulator_put(host->vcc); - - if (host->pdata && host->pdata->exit) - host->pdata->exit(&pdev->dev, mmc); - - free_irq(host->irq, host); - iounmap(host->base); - - if (host->dma) - dma_release_channel(host->dma); - - clk_disable(host->clk); - clk_put(host->clk); - - release_mem_region(host->res->start, resource_size(host->res)); - - mmc_free_host(mmc); - - return 0; -} - -#ifdef CONFIG_PM -static int mxcmci_suspend(struct device *dev) -{ - struct mmc_host *mmc = dev_get_drvdata(dev); - struct mxcmci_host *host = mmc_priv(mmc); - int ret = 0; - - if (mmc) - ret = mmc_suspend_host(mmc); - clk_disable(host->clk); - - return ret; -} - -static int mxcmci_resume(struct device *dev) -{ - struct mmc_host *mmc = dev_get_drvdata(dev); - struct mxcmci_host *host = mmc_priv(mmc); - int ret = 0; - - clk_enable(host->clk); - if (mmc) - ret = mmc_resume_host(mmc); - - return ret; -} - -static const struct dev_pm_ops mxcmci_pm_ops = { - .suspend = mxcmci_suspend, - .resume = mxcmci_resume, -}; -#endif - -static struct platform_driver mxcmci_driver = { - .probe = mxcmci_probe, - .remove = mxcmci_remove, - .driver = { - .name = DRIVER_NAME, - .owner = THIS_MODULE, -#ifdef CONFIG_PM - .pm = &mxcmci_pm_ops, -#endif - } -}; - -module_platform_driver(mxcmci_driver); - -MODULE_DESCRIPTION("i.MX Multimedia Card Interface Driver"); -MODULE_AUTHOR("Sascha Hauer, Pengutronix"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:imx-mmc"); diff --git a/ANDROID_3.4.5/drivers/mmc/host/mxs-mmc.c b/ANDROID_3.4.5/drivers/mmc/host/mxs-mmc.c deleted file mode 100644 index e3f5af96..00000000 --- a/ANDROID_3.4.5/drivers/mmc/host/mxs-mmc.c +++ /dev/null @@ -1,873 +0,0 @@ -/* - * Portions copyright (C) 2003 Russell King, PXA MMCI Driver - * Portions copyright (C) 2004-2005 Pierre Ossman, W83L51xD SD/MMC driver - * - * Copyright 2008 Embedded Alley Solutions, Inc. - * Copyright 2009-2011 Freescale Semiconductor, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/ioport.h> -#include <linux/platform_device.h> -#include <linux/delay.h> -#include <linux/interrupt.h> -#include <linux/dma-mapping.h> -#include <linux/dmaengine.h> -#include <linux/highmem.h> -#include <linux/clk.h> -#include <linux/err.h> -#include <linux/completion.h> -#include <linux/mmc/host.h> -#include <linux/mmc/mmc.h> -#include <linux/mmc/sdio.h> -#include <linux/gpio.h> -#include <linux/regulator/consumer.h> -#include <linux/module.h> -#include <linux/fsl/mxs-dma.h> - -#include <mach/mxs.h> -#include <mach/common.h> -#include <mach/mmc.h> - -#define DRIVER_NAME "mxs-mmc" - -/* card detect polling timeout */ -#define MXS_MMC_DETECT_TIMEOUT (HZ/2) - -#define SSP_VERSION_LATEST 4 -#define ssp_is_old() (host->version < SSP_VERSION_LATEST) - -/* SSP registers */ -#define HW_SSP_CTRL0 0x000 -#define BM_SSP_CTRL0_RUN (1 << 29) -#define BM_SSP_CTRL0_SDIO_IRQ_CHECK (1 << 28) -#define BM_SSP_CTRL0_IGNORE_CRC (1 << 26) -#define BM_SSP_CTRL0_READ (1 << 25) -#define BM_SSP_CTRL0_DATA_XFER (1 << 24) -#define BP_SSP_CTRL0_BUS_WIDTH (22) -#define BM_SSP_CTRL0_BUS_WIDTH (0x3 << 22) -#define BM_SSP_CTRL0_WAIT_FOR_IRQ (1 << 21) -#define BM_SSP_CTRL0_LONG_RESP (1 << 19) -#define BM_SSP_CTRL0_GET_RESP (1 << 17) -#define BM_SSP_CTRL0_ENABLE (1 << 16) -#define BP_SSP_CTRL0_XFER_COUNT (0) -#define BM_SSP_CTRL0_XFER_COUNT (0xffff) -#define HW_SSP_CMD0 0x010 -#define BM_SSP_CMD0_DBL_DATA_RATE_EN (1 << 25) -#define BM_SSP_CMD0_SLOW_CLKING_EN (1 << 22) -#define BM_SSP_CMD0_CONT_CLKING_EN (1 << 21) -#define BM_SSP_CMD0_APPEND_8CYC (1 << 20) -#define BP_SSP_CMD0_BLOCK_SIZE (16) -#define BM_SSP_CMD0_BLOCK_SIZE (0xf << 16) -#define BP_SSP_CMD0_BLOCK_COUNT (8) -#define BM_SSP_CMD0_BLOCK_COUNT (0xff << 8) -#define BP_SSP_CMD0_CMD (0) -#define BM_SSP_CMD0_CMD (0xff) -#define HW_SSP_CMD1 0x020 -#define HW_SSP_XFER_SIZE 0x030 -#define HW_SSP_BLOCK_SIZE 0x040 -#define BP_SSP_BLOCK_SIZE_BLOCK_COUNT (4) -#define BM_SSP_BLOCK_SIZE_BLOCK_COUNT (0xffffff << 4) -#define BP_SSP_BLOCK_SIZE_BLOCK_SIZE (0) -#define BM_SSP_BLOCK_SIZE_BLOCK_SIZE (0xf) -#define HW_SSP_TIMING (ssp_is_old() ? 0x050 : 0x070) -#define BP_SSP_TIMING_TIMEOUT (16) -#define BM_SSP_TIMING_TIMEOUT (0xffff << 16) -#define BP_SSP_TIMING_CLOCK_DIVIDE (8) -#define BM_SSP_TIMING_CLOCK_DIVIDE (0xff << 8) -#define BP_SSP_TIMING_CLOCK_RATE (0) -#define BM_SSP_TIMING_CLOCK_RATE (0xff) -#define HW_SSP_CTRL1 (ssp_is_old() ? 0x060 : 0x080) -#define BM_SSP_CTRL1_SDIO_IRQ (1 << 31) -#define BM_SSP_CTRL1_SDIO_IRQ_EN (1 << 30) -#define BM_SSP_CTRL1_RESP_ERR_IRQ (1 << 29) -#define BM_SSP_CTRL1_RESP_ERR_IRQ_EN (1 << 28) -#define BM_SSP_CTRL1_RESP_TIMEOUT_IRQ (1 << 27) -#define BM_SSP_CTRL1_RESP_TIMEOUT_IRQ_EN (1 << 26) -#define BM_SSP_CTRL1_DATA_TIMEOUT_IRQ (1 << 25) -#define BM_SSP_CTRL1_DATA_TIMEOUT_IRQ_EN (1 << 24) -#define BM_SSP_CTRL1_DATA_CRC_IRQ (1 << 23) -#define BM_SSP_CTRL1_DATA_CRC_IRQ_EN (1 << 22) -#define BM_SSP_CTRL1_FIFO_UNDERRUN_IRQ (1 << 21) -#define BM_SSP_CTRL1_FIFO_UNDERRUN_IRQ_EN (1 << 20) -#define BM_SSP_CTRL1_RECV_TIMEOUT_IRQ (1 << 17) -#define BM_SSP_CTRL1_RECV_TIMEOUT_IRQ_EN (1 << 16) -#define BM_SSP_CTRL1_FIFO_OVERRUN_IRQ (1 << 15) -#define BM_SSP_CTRL1_FIFO_OVERRUN_IRQ_EN (1 << 14) -#define BM_SSP_CTRL1_DMA_ENABLE (1 << 13) -#define BM_SSP_CTRL1_POLARITY (1 << 9) -#define BP_SSP_CTRL1_WORD_LENGTH (4) -#define BM_SSP_CTRL1_WORD_LENGTH (0xf << 4) -#define BP_SSP_CTRL1_SSP_MODE (0) -#define BM_SSP_CTRL1_SSP_MODE (0xf) -#define HW_SSP_SDRESP0 (ssp_is_old() ? 0x080 : 0x0a0) -#define HW_SSP_SDRESP1 (ssp_is_old() ? 0x090 : 0x0b0) -#define HW_SSP_SDRESP2 (ssp_is_old() ? 0x0a0 : 0x0c0) -#define HW_SSP_SDRESP3 (ssp_is_old() ? 0x0b0 : 0x0d0) -#define HW_SSP_STATUS (ssp_is_old() ? 0x0c0 : 0x100) -#define BM_SSP_STATUS_CARD_DETECT (1 << 28) -#define BM_SSP_STATUS_SDIO_IRQ (1 << 17) -#define HW_SSP_VERSION (cpu_is_mx23() ? 0x110 : 0x130) -#define BP_SSP_VERSION_MAJOR (24) - -#define BF_SSP(value, field) (((value) << BP_SSP_##field) & BM_SSP_##field) - -#define MXS_MMC_IRQ_BITS (BM_SSP_CTRL1_SDIO_IRQ | \ - BM_SSP_CTRL1_RESP_ERR_IRQ | \ - BM_SSP_CTRL1_RESP_TIMEOUT_IRQ | \ - BM_SSP_CTRL1_DATA_TIMEOUT_IRQ | \ - BM_SSP_CTRL1_DATA_CRC_IRQ | \ - BM_SSP_CTRL1_FIFO_UNDERRUN_IRQ | \ - BM_SSP_CTRL1_RECV_TIMEOUT_IRQ | \ - BM_SSP_CTRL1_FIFO_OVERRUN_IRQ) - -#define SSP_PIO_NUM 3 - -struct mxs_mmc_host { - struct mmc_host *mmc; - struct mmc_request *mrq; - struct mmc_command *cmd; - struct mmc_data *data; - - void __iomem *base; - int irq; - struct resource *res; - struct resource *dma_res; - struct clk *clk; - unsigned int clk_rate; - - struct dma_chan *dmach; - struct mxs_dma_data dma_data; - unsigned int dma_dir; - enum dma_transfer_direction slave_dirn; - u32 ssp_pio_words[SSP_PIO_NUM]; - - unsigned int version; - unsigned char bus_width; - spinlock_t lock; - int sdio_irq_en; -}; - -static int mxs_mmc_get_ro(struct mmc_host *mmc) -{ - struct mxs_mmc_host *host = mmc_priv(mmc); - struct mxs_mmc_platform_data *pdata = - mmc_dev(host->mmc)->platform_data; - - if (!pdata) - return -EFAULT; - - if (!gpio_is_valid(pdata->wp_gpio)) - return -EINVAL; - - return gpio_get_value(pdata->wp_gpio); -} - -static int mxs_mmc_get_cd(struct mmc_host *mmc) -{ - struct mxs_mmc_host *host = mmc_priv(mmc); - - return !(readl(host->base + HW_SSP_STATUS) & - BM_SSP_STATUS_CARD_DETECT); -} - -static void mxs_mmc_reset(struct mxs_mmc_host *host) -{ - u32 ctrl0, ctrl1; - - mxs_reset_block(host->base); - - ctrl0 = BM_SSP_CTRL0_IGNORE_CRC; - ctrl1 = BF_SSP(0x3, CTRL1_SSP_MODE) | - BF_SSP(0x7, CTRL1_WORD_LENGTH) | - BM_SSP_CTRL1_DMA_ENABLE | - BM_SSP_CTRL1_POLARITY | - BM_SSP_CTRL1_RECV_TIMEOUT_IRQ_EN | - BM_SSP_CTRL1_DATA_CRC_IRQ_EN | - BM_SSP_CTRL1_DATA_TIMEOUT_IRQ_EN | - BM_SSP_CTRL1_RESP_TIMEOUT_IRQ_EN | - BM_SSP_CTRL1_RESP_ERR_IRQ_EN; - - writel(BF_SSP(0xffff, TIMING_TIMEOUT) | - BF_SSP(2, TIMING_CLOCK_DIVIDE) | - BF_SSP(0, TIMING_CLOCK_RATE), - host->base + HW_SSP_TIMING); - - if (host->sdio_irq_en) { - ctrl0 |= BM_SSP_CTRL0_SDIO_IRQ_CHECK; - ctrl1 |= BM_SSP_CTRL1_SDIO_IRQ_EN; - } - - writel(ctrl0, host->base + HW_SSP_CTRL0); - writel(ctrl1, host->base + HW_SSP_CTRL1); -} - -static void mxs_mmc_start_cmd(struct mxs_mmc_host *host, - struct mmc_command *cmd); - -static void mxs_mmc_request_done(struct mxs_mmc_host *host) -{ - struct mmc_command *cmd = host->cmd; - struct mmc_data *data = host->data; - struct mmc_request *mrq = host->mrq; - - if (mmc_resp_type(cmd) & MMC_RSP_PRESENT) { - if (mmc_resp_type(cmd) & MMC_RSP_136) { - cmd->resp[3] = readl(host->base + HW_SSP_SDRESP0); - cmd->resp[2] = readl(host->base + HW_SSP_SDRESP1); - cmd->resp[1] = readl(host->base + HW_SSP_SDRESP2); - cmd->resp[0] = readl(host->base + HW_SSP_SDRESP3); - } else { - cmd->resp[0] = readl(host->base + HW_SSP_SDRESP0); - } - } - - if (data) { - dma_unmap_sg(mmc_dev(host->mmc), data->sg, - data->sg_len, host->dma_dir); - /* - * If there was an error on any block, we mark all - * data blocks as being in error. - */ - if (!data->error) - data->bytes_xfered = data->blocks * data->blksz; - else - data->bytes_xfered = 0; - - host->data = NULL; - if (mrq->stop) { - mxs_mmc_start_cmd(host, mrq->stop); - return; - } - } - - host->mrq = NULL; - mmc_request_done(host->mmc, mrq); -} - -static void mxs_mmc_dma_irq_callback(void *param) -{ - struct mxs_mmc_host *host = param; - - mxs_mmc_request_done(host); -} - -static irqreturn_t mxs_mmc_irq_handler(int irq, void *dev_id) -{ - struct mxs_mmc_host *host = dev_id; - struct mmc_command *cmd = host->cmd; - struct mmc_data *data = host->data; - u32 stat; - - spin_lock(&host->lock); - - stat = readl(host->base + HW_SSP_CTRL1); - writel(stat & MXS_MMC_IRQ_BITS, - host->base + HW_SSP_CTRL1 + MXS_CLR_ADDR); - - if ((stat & BM_SSP_CTRL1_SDIO_IRQ) && (stat & BM_SSP_CTRL1_SDIO_IRQ_EN)) - mmc_signal_sdio_irq(host->mmc); - - spin_unlock(&host->lock); - - if (stat & BM_SSP_CTRL1_RESP_TIMEOUT_IRQ) - cmd->error = -ETIMEDOUT; - else if (stat & BM_SSP_CTRL1_RESP_ERR_IRQ) - cmd->error = -EIO; - - if (data) { - if (stat & (BM_SSP_CTRL1_DATA_TIMEOUT_IRQ | - BM_SSP_CTRL1_RECV_TIMEOUT_IRQ)) - data->error = -ETIMEDOUT; - else if (stat & BM_SSP_CTRL1_DATA_CRC_IRQ) - data->error = -EILSEQ; - else if (stat & (BM_SSP_CTRL1_FIFO_UNDERRUN_IRQ | - BM_SSP_CTRL1_FIFO_OVERRUN_IRQ)) - data->error = -EIO; - } - - return IRQ_HANDLED; -} - -static struct dma_async_tx_descriptor *mxs_mmc_prep_dma( - struct mxs_mmc_host *host, unsigned long flags) -{ - struct dma_async_tx_descriptor *desc; - struct mmc_data *data = host->data; - struct scatterlist * sgl; - unsigned int sg_len; - - if (data) { - /* data */ - dma_map_sg(mmc_dev(host->mmc), data->sg, - data->sg_len, host->dma_dir); - sgl = data->sg; - sg_len = data->sg_len; - } else { - /* pio */ - sgl = (struct scatterlist *) host->ssp_pio_words; - sg_len = SSP_PIO_NUM; - } - - desc = dmaengine_prep_slave_sg(host->dmach, - sgl, sg_len, host->slave_dirn, flags); - if (desc) { - desc->callback = mxs_mmc_dma_irq_callback; - desc->callback_param = host; - } else { - if (data) - dma_unmap_sg(mmc_dev(host->mmc), data->sg, - data->sg_len, host->dma_dir); - } - - return desc; -} - -static void mxs_mmc_bc(struct mxs_mmc_host *host) -{ - struct mmc_command *cmd = host->cmd; - struct dma_async_tx_descriptor *desc; - u32 ctrl0, cmd0, cmd1; - - ctrl0 = BM_SSP_CTRL0_ENABLE | BM_SSP_CTRL0_IGNORE_CRC; - cmd0 = BF_SSP(cmd->opcode, CMD0_CMD) | BM_SSP_CMD0_APPEND_8CYC; - cmd1 = cmd->arg; - - if (host->sdio_irq_en) { - ctrl0 |= BM_SSP_CTRL0_SDIO_IRQ_CHECK; - cmd0 |= BM_SSP_CMD0_CONT_CLKING_EN | BM_SSP_CMD0_SLOW_CLKING_EN; - } - - host->ssp_pio_words[0] = ctrl0; - host->ssp_pio_words[1] = cmd0; - host->ssp_pio_words[2] = cmd1; - host->dma_dir = DMA_NONE; - host->slave_dirn = DMA_TRANS_NONE; - desc = mxs_mmc_prep_dma(host, DMA_CTRL_ACK); - if (!desc) - goto out; - - dmaengine_submit(desc); - dma_async_issue_pending(host->dmach); - return; - -out: - dev_warn(mmc_dev(host->mmc), - "%s: failed to prep dma\n", __func__); -} - -static void mxs_mmc_ac(struct mxs_mmc_host *host) -{ - struct mmc_command *cmd = host->cmd; - struct dma_async_tx_descriptor *desc; - u32 ignore_crc, get_resp, long_resp; - u32 ctrl0, cmd0, cmd1; - - ignore_crc = (mmc_resp_type(cmd) & MMC_RSP_CRC) ? - 0 : BM_SSP_CTRL0_IGNORE_CRC; - get_resp = (mmc_resp_type(cmd) & MMC_RSP_PRESENT) ? - BM_SSP_CTRL0_GET_RESP : 0; - long_resp = (mmc_resp_type(cmd) & MMC_RSP_136) ? - BM_SSP_CTRL0_LONG_RESP : 0; - - ctrl0 = BM_SSP_CTRL0_ENABLE | ignore_crc | get_resp | long_resp; - cmd0 = BF_SSP(cmd->opcode, CMD0_CMD); - cmd1 = cmd->arg; - - if (host->sdio_irq_en) { - ctrl0 |= BM_SSP_CTRL0_SDIO_IRQ_CHECK; - cmd0 |= BM_SSP_CMD0_CONT_CLKING_EN | BM_SSP_CMD0_SLOW_CLKING_EN; - } - - host->ssp_pio_words[0] = ctrl0; - host->ssp_pio_words[1] = cmd0; - host->ssp_pio_words[2] = cmd1; - host->dma_dir = DMA_NONE; - host->slave_dirn = DMA_TRANS_NONE; - desc = mxs_mmc_prep_dma(host, DMA_CTRL_ACK); - if (!desc) - goto out; - - dmaengine_submit(desc); - dma_async_issue_pending(host->dmach); - return; - -out: - dev_warn(mmc_dev(host->mmc), - "%s: failed to prep dma\n", __func__); -} - -static unsigned short mxs_ns_to_ssp_ticks(unsigned clock_rate, unsigned ns) -{ - const unsigned int ssp_timeout_mul = 4096; - /* - * Calculate ticks in ms since ns are large numbers - * and might overflow - */ - const unsigned int clock_per_ms = clock_rate / 1000; - const unsigned int ms = ns / 1000; - const unsigned int ticks = ms * clock_per_ms; - const unsigned int ssp_ticks = ticks / ssp_timeout_mul; - - WARN_ON(ssp_ticks == 0); - return ssp_ticks; -} - -static void mxs_mmc_adtc(struct mxs_mmc_host *host) -{ - struct mmc_command *cmd = host->cmd; - struct mmc_data *data = cmd->data; - struct dma_async_tx_descriptor *desc; - struct scatterlist *sgl = data->sg, *sg; - unsigned int sg_len = data->sg_len; - int i; - - unsigned short dma_data_dir, timeout; - enum dma_transfer_direction slave_dirn; - unsigned int data_size = 0, log2_blksz; - unsigned int blocks = data->blocks; - - u32 ignore_crc, get_resp, long_resp, read; - u32 ctrl0, cmd0, cmd1, val; - - ignore_crc = (mmc_resp_type(cmd) & MMC_RSP_CRC) ? - 0 : BM_SSP_CTRL0_IGNORE_CRC; - get_resp = (mmc_resp_type(cmd) & MMC_RSP_PRESENT) ? - BM_SSP_CTRL0_GET_RESP : 0; - long_resp = (mmc_resp_type(cmd) & MMC_RSP_136) ? - BM_SSP_CTRL0_LONG_RESP : 0; - - if (data->flags & MMC_DATA_WRITE) { - dma_data_dir = DMA_TO_DEVICE; - slave_dirn = DMA_MEM_TO_DEV; - read = 0; - } else { - dma_data_dir = DMA_FROM_DEVICE; - slave_dirn = DMA_DEV_TO_MEM; - read = BM_SSP_CTRL0_READ; - } - - ctrl0 = BF_SSP(host->bus_width, CTRL0_BUS_WIDTH) | - ignore_crc | get_resp | long_resp | - BM_SSP_CTRL0_DATA_XFER | read | - BM_SSP_CTRL0_WAIT_FOR_IRQ | - BM_SSP_CTRL0_ENABLE; - - cmd0 = BF_SSP(cmd->opcode, CMD0_CMD); - - /* get logarithm to base 2 of block size for setting register */ - log2_blksz = ilog2(data->blksz); - - /* - * take special care of the case that data size from data->sg - * is not equal to blocks x blksz - */ - for_each_sg(sgl, sg, sg_len, i) - data_size += sg->length; - - if (data_size != data->blocks * data->blksz) - blocks = 1; - - /* xfer count, block size and count need to be set differently */ - if (ssp_is_old()) { - ctrl0 |= BF_SSP(data_size, CTRL0_XFER_COUNT); - cmd0 |= BF_SSP(log2_blksz, CMD0_BLOCK_SIZE) | - BF_SSP(blocks - 1, CMD0_BLOCK_COUNT); - } else { - writel(data_size, host->base + HW_SSP_XFER_SIZE); - writel(BF_SSP(log2_blksz, BLOCK_SIZE_BLOCK_SIZE) | - BF_SSP(blocks - 1, BLOCK_SIZE_BLOCK_COUNT), - host->base + HW_SSP_BLOCK_SIZE); - } - - if ((cmd->opcode == MMC_STOP_TRANSMISSION) || - (cmd->opcode == SD_IO_RW_EXTENDED)) - cmd0 |= BM_SSP_CMD0_APPEND_8CYC; - - cmd1 = cmd->arg; - - if (host->sdio_irq_en) { - ctrl0 |= BM_SSP_CTRL0_SDIO_IRQ_CHECK; - cmd0 |= BM_SSP_CMD0_CONT_CLKING_EN | BM_SSP_CMD0_SLOW_CLKING_EN; - } - - /* set the timeout count */ - timeout = mxs_ns_to_ssp_ticks(host->clk_rate, data->timeout_ns); - val = readl(host->base + HW_SSP_TIMING); - val &= ~(BM_SSP_TIMING_TIMEOUT); - val |= BF_SSP(timeout, TIMING_TIMEOUT); - writel(val, host->base + HW_SSP_TIMING); - - /* pio */ - host->ssp_pio_words[0] = ctrl0; - host->ssp_pio_words[1] = cmd0; - host->ssp_pio_words[2] = cmd1; - host->dma_dir = DMA_NONE; - host->slave_dirn = DMA_TRANS_NONE; - desc = mxs_mmc_prep_dma(host, 0); - if (!desc) - goto out; - - /* append data sg */ - WARN_ON(host->data != NULL); - host->data = data; - host->dma_dir = dma_data_dir; - host->slave_dirn = slave_dirn; - desc = mxs_mmc_prep_dma(host, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); - if (!desc) - goto out; - - dmaengine_submit(desc); - dma_async_issue_pending(host->dmach); - return; -out: - dev_warn(mmc_dev(host->mmc), - "%s: failed to prep dma\n", __func__); -} - -static void mxs_mmc_start_cmd(struct mxs_mmc_host *host, - struct mmc_command *cmd) -{ - host->cmd = cmd; - - switch (mmc_cmd_type(cmd)) { - case MMC_CMD_BC: - mxs_mmc_bc(host); - break; - case MMC_CMD_BCR: - mxs_mmc_ac(host); - break; - case MMC_CMD_AC: - mxs_mmc_ac(host); - break; - case MMC_CMD_ADTC: - mxs_mmc_adtc(host); - break; - default: - dev_warn(mmc_dev(host->mmc), - "%s: unknown MMC command\n", __func__); - break; - } -} - -static void mxs_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq) -{ - struct mxs_mmc_host *host = mmc_priv(mmc); - - WARN_ON(host->mrq != NULL); - host->mrq = mrq; - mxs_mmc_start_cmd(host, mrq->cmd); -} - -static void mxs_mmc_set_clk_rate(struct mxs_mmc_host *host, unsigned int rate) -{ - unsigned int ssp_clk, ssp_sck; - u32 clock_divide, clock_rate; - u32 val; - - ssp_clk = clk_get_rate(host->clk); - - for (clock_divide = 2; clock_divide <= 254; clock_divide += 2) { - clock_rate = DIV_ROUND_UP(ssp_clk, rate * clock_divide); - clock_rate = (clock_rate > 0) ? clock_rate - 1 : 0; - if (clock_rate <= 255) - break; - } - - if (clock_divide > 254) { - dev_err(mmc_dev(host->mmc), - "%s: cannot set clock to %d\n", __func__, rate); - return; - } - - ssp_sck = ssp_clk / clock_divide / (1 + clock_rate); - - val = readl(host->base + HW_SSP_TIMING); - val &= ~(BM_SSP_TIMING_CLOCK_DIVIDE | BM_SSP_TIMING_CLOCK_RATE); - val |= BF_SSP(clock_divide, TIMING_CLOCK_DIVIDE); - val |= BF_SSP(clock_rate, TIMING_CLOCK_RATE); - writel(val, host->base + HW_SSP_TIMING); - - host->clk_rate = ssp_sck; - - dev_dbg(mmc_dev(host->mmc), - "%s: clock_divide %d, clock_rate %d, ssp_clk %d, rate_actual %d, rate_requested %d\n", - __func__, clock_divide, clock_rate, ssp_clk, ssp_sck, rate); -} - -static void mxs_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) -{ - struct mxs_mmc_host *host = mmc_priv(mmc); - - if (ios->bus_width == MMC_BUS_WIDTH_8) - host->bus_width = 2; - else if (ios->bus_width == MMC_BUS_WIDTH_4) - host->bus_width = 1; - else - host->bus_width = 0; - - if (ios->clock) - mxs_mmc_set_clk_rate(host, ios->clock); -} - -static void mxs_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable) -{ - struct mxs_mmc_host *host = mmc_priv(mmc); - unsigned long flags; - - spin_lock_irqsave(&host->lock, flags); - - host->sdio_irq_en = enable; - - if (enable) { - writel(BM_SSP_CTRL0_SDIO_IRQ_CHECK, - host->base + HW_SSP_CTRL0 + MXS_SET_ADDR); - writel(BM_SSP_CTRL1_SDIO_IRQ_EN, - host->base + HW_SSP_CTRL1 + MXS_SET_ADDR); - - if (readl(host->base + HW_SSP_STATUS) & BM_SSP_STATUS_SDIO_IRQ) - mmc_signal_sdio_irq(host->mmc); - - } else { - writel(BM_SSP_CTRL0_SDIO_IRQ_CHECK, - host->base + HW_SSP_CTRL0 + MXS_CLR_ADDR); - writel(BM_SSP_CTRL1_SDIO_IRQ_EN, - host->base + HW_SSP_CTRL1 + MXS_CLR_ADDR); - } - - spin_unlock_irqrestore(&host->lock, flags); -} - -static const struct mmc_host_ops mxs_mmc_ops = { - .request = mxs_mmc_request, - .get_ro = mxs_mmc_get_ro, - .get_cd = mxs_mmc_get_cd, - .set_ios = mxs_mmc_set_ios, - .enable_sdio_irq = mxs_mmc_enable_sdio_irq, -}; - -static bool mxs_mmc_dma_filter(struct dma_chan *chan, void *param) -{ - struct mxs_mmc_host *host = param; - - if (!mxs_dma_is_apbh(chan)) - return false; - - if (chan->chan_id != host->dma_res->start) - return false; - - chan->private = &host->dma_data; - - return true; -} - -static int mxs_mmc_probe(struct platform_device *pdev) -{ - struct mxs_mmc_host *host; - struct mmc_host *mmc; - struct resource *iores, *dmares, *r; - struct mxs_mmc_platform_data *pdata; - int ret = 0, irq_err, irq_dma; - dma_cap_mask_t mask; - - iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); - dmares = platform_get_resource(pdev, IORESOURCE_DMA, 0); - irq_err = platform_get_irq(pdev, 0); - irq_dma = platform_get_irq(pdev, 1); - if (!iores || !dmares || irq_err < 0 || irq_dma < 0) - return -EINVAL; - - r = request_mem_region(iores->start, resource_size(iores), pdev->name); - if (!r) - return -EBUSY; - - mmc = mmc_alloc_host(sizeof(struct mxs_mmc_host), &pdev->dev); - if (!mmc) { - ret = -ENOMEM; - goto out_release_mem; - } - - host = mmc_priv(mmc); - host->base = ioremap(r->start, resource_size(r)); - if (!host->base) { - ret = -ENOMEM; - goto out_mmc_free; - } - - /* only major verion does matter */ - host->version = readl(host->base + HW_SSP_VERSION) >> - BP_SSP_VERSION_MAJOR; - - host->mmc = mmc; - host->res = r; - host->dma_res = dmares; - host->irq = irq_err; - host->sdio_irq_en = 0; - - host->clk = clk_get(&pdev->dev, NULL); - if (IS_ERR(host->clk)) { - ret = PTR_ERR(host->clk); - goto out_iounmap; - } - clk_prepare_enable(host->clk); - - mxs_mmc_reset(host); - - dma_cap_zero(mask); - dma_cap_set(DMA_SLAVE, mask); - host->dma_data.chan_irq = irq_dma; - host->dmach = dma_request_channel(mask, mxs_mmc_dma_filter, host); - if (!host->dmach) { - dev_err(mmc_dev(host->mmc), - "%s: failed to request dma\n", __func__); - goto out_clk_put; - } - - /* set mmc core parameters */ - mmc->ops = &mxs_mmc_ops; - mmc->caps = MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED | - MMC_CAP_SDIO_IRQ | MMC_CAP_NEEDS_POLL; - - pdata = mmc_dev(host->mmc)->platform_data; - if (pdata) { - if (pdata->flags & SLOTF_8_BIT_CAPABLE) - mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA; - if (pdata->flags & SLOTF_4_BIT_CAPABLE) - mmc->caps |= MMC_CAP_4_BIT_DATA; - } - - mmc->f_min = 400000; - mmc->f_max = 288000000; - mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; - - mmc->max_segs = 52; - mmc->max_blk_size = 1 << 0xf; - mmc->max_blk_count = (ssp_is_old()) ? 0xff : 0xffffff; - mmc->max_req_size = (ssp_is_old()) ? 0xffff : 0xffffffff; - mmc->max_seg_size = dma_get_max_seg_size(host->dmach->device->dev); - - platform_set_drvdata(pdev, mmc); - - ret = request_irq(host->irq, mxs_mmc_irq_handler, 0, DRIVER_NAME, host); - if (ret) - goto out_free_dma; - - spin_lock_init(&host->lock); - - ret = mmc_add_host(mmc); - if (ret) - goto out_free_irq; - - dev_info(mmc_dev(host->mmc), "initialized\n"); - - return 0; - -out_free_irq: - free_irq(host->irq, host); -out_free_dma: - if (host->dmach) - dma_release_channel(host->dmach); -out_clk_put: - clk_disable_unprepare(host->clk); - clk_put(host->clk); -out_iounmap: - iounmap(host->base); -out_mmc_free: - mmc_free_host(mmc); -out_release_mem: - release_mem_region(iores->start, resource_size(iores)); - return ret; -} - -static int mxs_mmc_remove(struct platform_device *pdev) -{ - struct mmc_host *mmc = platform_get_drvdata(pdev); - struct mxs_mmc_host *host = mmc_priv(mmc); - struct resource *res = host->res; - - mmc_remove_host(mmc); - - free_irq(host->irq, host); - - platform_set_drvdata(pdev, NULL); - - if (host->dmach) - dma_release_channel(host->dmach); - - clk_disable_unprepare(host->clk); - clk_put(host->clk); - - iounmap(host->base); - - mmc_free_host(mmc); - - release_mem_region(res->start, resource_size(res)); - - return 0; -} - -#ifdef CONFIG_PM -static int mxs_mmc_suspend(struct device *dev) -{ - struct mmc_host *mmc = dev_get_drvdata(dev); - struct mxs_mmc_host *host = mmc_priv(mmc); - int ret = 0; - - ret = mmc_suspend_host(mmc); - - clk_disable_unprepare(host->clk); - - return ret; -} - -static int mxs_mmc_resume(struct device *dev) -{ - struct mmc_host *mmc = dev_get_drvdata(dev); - struct mxs_mmc_host *host = mmc_priv(mmc); - int ret = 0; - - clk_prepare_enable(host->clk); - - ret = mmc_resume_host(mmc); - - return ret; -} - -static const struct dev_pm_ops mxs_mmc_pm_ops = { - .suspend = mxs_mmc_suspend, - .resume = mxs_mmc_resume, -}; -#endif - -static struct platform_driver mxs_mmc_driver = { - .probe = mxs_mmc_probe, - .remove = mxs_mmc_remove, - .driver = { - .name = DRIVER_NAME, - .owner = THIS_MODULE, -#ifdef CONFIG_PM - .pm = &mxs_mmc_pm_ops, -#endif - }, -}; - -module_platform_driver(mxs_mmc_driver); - -MODULE_DESCRIPTION("FREESCALE MXS MMC peripheral"); -MODULE_AUTHOR("Freescale Semiconductor"); -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/mmc/host/of_mmc_spi.c b/ANDROID_3.4.5/drivers/mmc/host/of_mmc_spi.c deleted file mode 100644 index 1534b582..00000000 --- a/ANDROID_3.4.5/drivers/mmc/host/of_mmc_spi.c +++ /dev/null @@ -1,181 +0,0 @@ -/* - * OpenFirmware bindings for the MMC-over-SPI driver - * - * Copyright (c) MontaVista Software, Inc. 2008. - * - * Author: Anton Vorontsov <avorontsov@ru.mvista.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - */ - -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/device.h> -#include <linux/slab.h> -#include <linux/irq.h> -#include <linux/gpio.h> -#include <linux/of.h> -#include <linux/of_gpio.h> -#include <linux/of_irq.h> -#include <linux/spi/spi.h> -#include <linux/spi/mmc_spi.h> -#include <linux/mmc/core.h> -#include <linux/mmc/host.h> - -/* For archs that don't support NO_IRQ (such as mips), provide a dummy value */ -#ifndef NO_IRQ -#define NO_IRQ 0 -#endif - -MODULE_LICENSE("GPL"); - -enum { - CD_GPIO = 0, - WP_GPIO, - NUM_GPIOS, -}; - -struct of_mmc_spi { - int gpios[NUM_GPIOS]; - bool alow_gpios[NUM_GPIOS]; - int detect_irq; - struct mmc_spi_platform_data pdata; -}; - -static struct of_mmc_spi *to_of_mmc_spi(struct device *dev) -{ - return container_of(dev->platform_data, struct of_mmc_spi, pdata); -} - -static int of_mmc_spi_read_gpio(struct device *dev, int gpio_num) -{ - struct of_mmc_spi *oms = to_of_mmc_spi(dev); - bool active_low = oms->alow_gpios[gpio_num]; - bool value = gpio_get_value(oms->gpios[gpio_num]); - - return active_low ^ value; -} - -static int of_mmc_spi_get_cd(struct device *dev) -{ - return of_mmc_spi_read_gpio(dev, CD_GPIO); -} - -static int of_mmc_spi_get_ro(struct device *dev) -{ - return of_mmc_spi_read_gpio(dev, WP_GPIO); -} - -static int of_mmc_spi_init(struct device *dev, - irqreturn_t (*irqhandler)(int, void *), void *mmc) -{ - struct of_mmc_spi *oms = to_of_mmc_spi(dev); - - return request_threaded_irq(oms->detect_irq, NULL, irqhandler, 0, - dev_name(dev), mmc); -} - -static void of_mmc_spi_exit(struct device *dev, void *mmc) -{ - struct of_mmc_spi *oms = to_of_mmc_spi(dev); - - free_irq(oms->detect_irq, mmc); -} - -struct mmc_spi_platform_data *mmc_spi_get_pdata(struct spi_device *spi) -{ - struct device *dev = &spi->dev; - struct device_node *np = dev->of_node; - struct of_mmc_spi *oms; - const u32 *voltage_ranges; - int num_ranges; - int i; - int ret = -EINVAL; - - if (dev->platform_data || !np) - return dev->platform_data; - - oms = kzalloc(sizeof(*oms), GFP_KERNEL); - if (!oms) - return NULL; - - voltage_ranges = of_get_property(np, "voltage-ranges", &num_ranges); - num_ranges = num_ranges / sizeof(*voltage_ranges) / 2; - if (!voltage_ranges || !num_ranges) { - dev_err(dev, "OF: voltage-ranges unspecified\n"); - goto err_ocr; - } - - for (i = 0; i < num_ranges; i++) { - const int j = i * 2; - u32 mask; - - mask = mmc_vddrange_to_ocrmask(be32_to_cpu(voltage_ranges[j]), - be32_to_cpu(voltage_ranges[j + 1])); - if (!mask) { - ret = -EINVAL; - dev_err(dev, "OF: voltage-range #%d is invalid\n", i); - goto err_ocr; - } - oms->pdata.ocr_mask |= mask; - } - - for (i = 0; i < ARRAY_SIZE(oms->gpios); i++) { - enum of_gpio_flags gpio_flags; - - oms->gpios[i] = of_get_gpio_flags(np, i, &gpio_flags); - if (!gpio_is_valid(oms->gpios[i])) - continue; - - ret = gpio_request(oms->gpios[i], dev_name(dev)); - if (ret < 0) { - oms->gpios[i] = -EINVAL; - continue; - } - - if (gpio_flags & OF_GPIO_ACTIVE_LOW) - oms->alow_gpios[i] = true; - } - - if (gpio_is_valid(oms->gpios[CD_GPIO])) - oms->pdata.get_cd = of_mmc_spi_get_cd; - if (gpio_is_valid(oms->gpios[WP_GPIO])) - oms->pdata.get_ro = of_mmc_spi_get_ro; - - oms->detect_irq = irq_of_parse_and_map(np, 0); - if (oms->detect_irq != NO_IRQ) { - oms->pdata.init = of_mmc_spi_init; - oms->pdata.exit = of_mmc_spi_exit; - } else { - oms->pdata.caps |= MMC_CAP_NEEDS_POLL; - } - - dev->platform_data = &oms->pdata; - return dev->platform_data; -err_ocr: - kfree(oms); - return NULL; -} -EXPORT_SYMBOL(mmc_spi_get_pdata); - -void mmc_spi_put_pdata(struct spi_device *spi) -{ - struct device *dev = &spi->dev; - struct device_node *np = dev->of_node; - struct of_mmc_spi *oms = to_of_mmc_spi(dev); - int i; - - if (!dev->platform_data || !np) - return; - - for (i = 0; i < ARRAY_SIZE(oms->gpios); i++) { - if (gpio_is_valid(oms->gpios[i])) - gpio_free(oms->gpios[i]); - } - kfree(oms); - dev->platform_data = NULL; -} -EXPORT_SYMBOL(mmc_spi_put_pdata); diff --git a/ANDROID_3.4.5/drivers/mmc/host/omap.c b/ANDROID_3.4.5/drivers/mmc/host/omap.c deleted file mode 100644 index 887c0e59..00000000 --- a/ANDROID_3.4.5/drivers/mmc/host/omap.c +++ /dev/null @@ -1,1637 +0,0 @@ -/* - * linux/drivers/mmc/host/omap.c - * - * Copyright (C) 2004 Nokia Corporation - * Written by Tuukka Tikkanen and Juha Yrjölä<juha.yrjola@nokia.com> - * Misc hacks here and there by Tony Lindgren <tony@atomide.com> - * Other hacks (DMA, SD, etc) by David Brownell - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include <linux/module.h> -#include <linux/moduleparam.h> -#include <linux/init.h> -#include <linux/ioport.h> -#include <linux/platform_device.h> -#include <linux/interrupt.h> -#include <linux/dma-mapping.h> -#include <linux/delay.h> -#include <linux/spinlock.h> -#include <linux/timer.h> -#include <linux/mmc/host.h> -#include <linux/mmc/card.h> -#include <linux/clk.h> -#include <linux/scatterlist.h> -#include <linux/i2c/tps65010.h> -#include <linux/slab.h> - -#include <asm/io.h> -#include <asm/irq.h> - -#include <plat/board.h> -#include <plat/mmc.h> -#include <asm/gpio.h> -#include <plat/dma.h> -#include <plat/mux.h> -#include <plat/fpga.h> - -#define OMAP_MMC_REG_CMD 0x00 -#define OMAP_MMC_REG_ARGL 0x01 -#define OMAP_MMC_REG_ARGH 0x02 -#define OMAP_MMC_REG_CON 0x03 -#define OMAP_MMC_REG_STAT 0x04 -#define OMAP_MMC_REG_IE 0x05 -#define OMAP_MMC_REG_CTO 0x06 -#define OMAP_MMC_REG_DTO 0x07 -#define OMAP_MMC_REG_DATA 0x08 -#define OMAP_MMC_REG_BLEN 0x09 -#define OMAP_MMC_REG_NBLK 0x0a -#define OMAP_MMC_REG_BUF 0x0b -#define OMAP_MMC_REG_SDIO 0x0d -#define OMAP_MMC_REG_REV 0x0f -#define OMAP_MMC_REG_RSP0 0x10 -#define OMAP_MMC_REG_RSP1 0x11 -#define OMAP_MMC_REG_RSP2 0x12 -#define OMAP_MMC_REG_RSP3 0x13 -#define OMAP_MMC_REG_RSP4 0x14 -#define OMAP_MMC_REG_RSP5 0x15 -#define OMAP_MMC_REG_RSP6 0x16 -#define OMAP_MMC_REG_RSP7 0x17 -#define OMAP_MMC_REG_IOSR 0x18 -#define OMAP_MMC_REG_SYSC 0x19 -#define OMAP_MMC_REG_SYSS 0x1a - -#define OMAP_MMC_STAT_CARD_ERR (1 << 14) -#define OMAP_MMC_STAT_CARD_IRQ (1 << 13) -#define OMAP_MMC_STAT_OCR_BUSY (1 << 12) -#define OMAP_MMC_STAT_A_EMPTY (1 << 11) -#define OMAP_MMC_STAT_A_FULL (1 << 10) -#define OMAP_MMC_STAT_CMD_CRC (1 << 8) -#define OMAP_MMC_STAT_CMD_TOUT (1 << 7) -#define OMAP_MMC_STAT_DATA_CRC (1 << 6) -#define OMAP_MMC_STAT_DATA_TOUT (1 << 5) -#define OMAP_MMC_STAT_END_BUSY (1 << 4) -#define OMAP_MMC_STAT_END_OF_DATA (1 << 3) -#define OMAP_MMC_STAT_CARD_BUSY (1 << 2) -#define OMAP_MMC_STAT_END_OF_CMD (1 << 0) - -#define OMAP_MMC_REG(host, reg) (OMAP_MMC_REG_##reg << (host)->reg_shift) -#define OMAP_MMC_READ(host, reg) __raw_readw((host)->virt_base + OMAP_MMC_REG(host, reg)) -#define OMAP_MMC_WRITE(host, reg, val) __raw_writew((val), (host)->virt_base + OMAP_MMC_REG(host, reg)) - -/* - * Command types - */ -#define OMAP_MMC_CMDTYPE_BC 0 -#define OMAP_MMC_CMDTYPE_BCR 1 -#define OMAP_MMC_CMDTYPE_AC 2 -#define OMAP_MMC_CMDTYPE_ADTC 3 - - -#define DRIVER_NAME "mmci-omap" - -/* Specifies how often in millisecs to poll for card status changes - * when the cover switch is open */ -#define OMAP_MMC_COVER_POLL_DELAY 500 - -struct mmc_omap_host; - -struct mmc_omap_slot { - int id; - unsigned int vdd; - u16 saved_con; - u16 bus_mode; - unsigned int fclk_freq; - unsigned powered:1; - - struct tasklet_struct cover_tasklet; - struct timer_list cover_timer; - unsigned cover_open; - - struct mmc_request *mrq; - struct mmc_omap_host *host; - struct mmc_host *mmc; - struct omap_mmc_slot_data *pdata; -}; - -struct mmc_omap_host { - int initialized; - int suspended; - struct mmc_request * mrq; - struct mmc_command * cmd; - struct mmc_data * data; - struct mmc_host * mmc; - struct device * dev; - unsigned char id; /* 16xx chips have 2 MMC blocks */ - struct clk * iclk; - struct clk * fclk; - struct resource *mem_res; - void __iomem *virt_base; - unsigned int phys_base; - int irq; - unsigned char bus_mode; - unsigned char hw_bus_mode; - unsigned int reg_shift; - - struct work_struct cmd_abort_work; - unsigned abort:1; - struct timer_list cmd_abort_timer; - - struct work_struct slot_release_work; - struct mmc_omap_slot *next_slot; - struct work_struct send_stop_work; - struct mmc_data *stop_data; - - unsigned int sg_len; - int sg_idx; - u16 * buffer; - u32 buffer_bytes_left; - u32 total_bytes_left; - - unsigned use_dma:1; - unsigned brs_received:1, dma_done:1; - unsigned dma_is_read:1; - unsigned dma_in_use:1; - int dma_ch; - spinlock_t dma_lock; - struct timer_list dma_timer; - unsigned dma_len; - - struct mmc_omap_slot *slots[OMAP_MMC_MAX_SLOTS]; - struct mmc_omap_slot *current_slot; - spinlock_t slot_lock; - wait_queue_head_t slot_wq; - int nr_slots; - - struct timer_list clk_timer; - spinlock_t clk_lock; /* for changing enabled state */ - unsigned int fclk_enabled:1; - - struct omap_mmc_platform_data *pdata; -}; - -static struct workqueue_struct *mmc_omap_wq; - -static void mmc_omap_fclk_offdelay(struct mmc_omap_slot *slot) -{ - unsigned long tick_ns; - - if (slot != NULL && slot->host->fclk_enabled && slot->fclk_freq > 0) { - tick_ns = (1000000000 + slot->fclk_freq - 1) / slot->fclk_freq; - ndelay(8 * tick_ns); - } -} - -static void mmc_omap_fclk_enable(struct mmc_omap_host *host, unsigned int enable) -{ - unsigned long flags; - - spin_lock_irqsave(&host->clk_lock, flags); - if (host->fclk_enabled != enable) { - host->fclk_enabled = enable; - if (enable) - clk_enable(host->fclk); - else - clk_disable(host->fclk); - } - spin_unlock_irqrestore(&host->clk_lock, flags); -} - -static void mmc_omap_select_slot(struct mmc_omap_slot *slot, int claimed) -{ - struct mmc_omap_host *host = slot->host; - unsigned long flags; - - if (claimed) - goto no_claim; - spin_lock_irqsave(&host->slot_lock, flags); - while (host->mmc != NULL) { - spin_unlock_irqrestore(&host->slot_lock, flags); - wait_event(host->slot_wq, host->mmc == NULL); - spin_lock_irqsave(&host->slot_lock, flags); - } - host->mmc = slot->mmc; - spin_unlock_irqrestore(&host->slot_lock, flags); -no_claim: - del_timer(&host->clk_timer); - if (host->current_slot != slot || !claimed) - mmc_omap_fclk_offdelay(host->current_slot); - - if (host->current_slot != slot) { - OMAP_MMC_WRITE(host, CON, slot->saved_con & 0xFC00); - if (host->pdata->switch_slot != NULL) - host->pdata->switch_slot(mmc_dev(slot->mmc), slot->id); - host->current_slot = slot; - } - - if (claimed) { - mmc_omap_fclk_enable(host, 1); - - /* Doing the dummy read here seems to work around some bug - * at least in OMAP24xx silicon where the command would not - * start after writing the CMD register. Sigh. */ - OMAP_MMC_READ(host, CON); - - OMAP_MMC_WRITE(host, CON, slot->saved_con); - } else - mmc_omap_fclk_enable(host, 0); -} - -static void mmc_omap_start_request(struct mmc_omap_host *host, - struct mmc_request *req); - -static void mmc_omap_slot_release_work(struct work_struct *work) -{ - struct mmc_omap_host *host = container_of(work, struct mmc_omap_host, - slot_release_work); - struct mmc_omap_slot *next_slot = host->next_slot; - struct mmc_request *rq; - - host->next_slot = NULL; - mmc_omap_select_slot(next_slot, 1); - - rq = next_slot->mrq; - next_slot->mrq = NULL; - mmc_omap_start_request(host, rq); -} - -static void mmc_omap_release_slot(struct mmc_omap_slot *slot, int clk_enabled) -{ - struct mmc_omap_host *host = slot->host; - unsigned long flags; - int i; - - BUG_ON(slot == NULL || host->mmc == NULL); - - if (clk_enabled) - /* Keeps clock running for at least 8 cycles on valid freq */ - mod_timer(&host->clk_timer, jiffies + HZ/10); - else { - del_timer(&host->clk_timer); - mmc_omap_fclk_offdelay(slot); - mmc_omap_fclk_enable(host, 0); - } - - spin_lock_irqsave(&host->slot_lock, flags); - /* Check for any pending requests */ - for (i = 0; i < host->nr_slots; i++) { - struct mmc_omap_slot *new_slot; - - if (host->slots[i] == NULL || host->slots[i]->mrq == NULL) - continue; - - BUG_ON(host->next_slot != NULL); - new_slot = host->slots[i]; - /* The current slot should not have a request in queue */ - BUG_ON(new_slot == host->current_slot); - - host->next_slot = new_slot; - host->mmc = new_slot->mmc; - spin_unlock_irqrestore(&host->slot_lock, flags); - queue_work(mmc_omap_wq, &host->slot_release_work); - return; - } - - host->mmc = NULL; - wake_up(&host->slot_wq); - spin_unlock_irqrestore(&host->slot_lock, flags); -} - -static inline -int mmc_omap_cover_is_open(struct mmc_omap_slot *slot) -{ - if (slot->pdata->get_cover_state) - return slot->pdata->get_cover_state(mmc_dev(slot->mmc), - slot->id); - return 0; -} - -static ssize_t -mmc_omap_show_cover_switch(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct mmc_host *mmc = container_of(dev, struct mmc_host, class_dev); - struct mmc_omap_slot *slot = mmc_priv(mmc); - - return sprintf(buf, "%s\n", mmc_omap_cover_is_open(slot) ? "open" : - "closed"); -} - -static DEVICE_ATTR(cover_switch, S_IRUGO, mmc_omap_show_cover_switch, NULL); - -static ssize_t -mmc_omap_show_slot_name(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct mmc_host *mmc = container_of(dev, struct mmc_host, class_dev); - struct mmc_omap_slot *slot = mmc_priv(mmc); - - return sprintf(buf, "%s\n", slot->pdata->name); -} - -static DEVICE_ATTR(slot_name, S_IRUGO, mmc_omap_show_slot_name, NULL); - -static void -mmc_omap_start_command(struct mmc_omap_host *host, struct mmc_command *cmd) -{ - u32 cmdreg; - u32 resptype; - u32 cmdtype; - - host->cmd = cmd; - - resptype = 0; - cmdtype = 0; - - /* Our hardware needs to know exact type */ - switch (mmc_resp_type(cmd)) { - case MMC_RSP_NONE: - break; - case MMC_RSP_R1: - case MMC_RSP_R1B: - /* resp 1, 1b, 6, 7 */ - resptype = 1; - break; - case MMC_RSP_R2: - resptype = 2; - break; - case MMC_RSP_R3: - resptype = 3; - break; - default: - dev_err(mmc_dev(host->mmc), "Invalid response type: %04x\n", mmc_resp_type(cmd)); - break; - } - - if (mmc_cmd_type(cmd) == MMC_CMD_ADTC) { - cmdtype = OMAP_MMC_CMDTYPE_ADTC; - } else if (mmc_cmd_type(cmd) == MMC_CMD_BC) { - cmdtype = OMAP_MMC_CMDTYPE_BC; - } else if (mmc_cmd_type(cmd) == MMC_CMD_BCR) { - cmdtype = OMAP_MMC_CMDTYPE_BCR; - } else { - cmdtype = OMAP_MMC_CMDTYPE_AC; - } - - cmdreg = cmd->opcode | (resptype << 8) | (cmdtype << 12); - - if (host->current_slot->bus_mode == MMC_BUSMODE_OPENDRAIN) - cmdreg |= 1 << 6; - - if (cmd->flags & MMC_RSP_BUSY) - cmdreg |= 1 << 11; - - if (host->data && !(host->data->flags & MMC_DATA_WRITE)) - cmdreg |= 1 << 15; - - mod_timer(&host->cmd_abort_timer, jiffies + HZ/2); - - OMAP_MMC_WRITE(host, CTO, 200); - OMAP_MMC_WRITE(host, ARGL, cmd->arg & 0xffff); - OMAP_MMC_WRITE(host, ARGH, cmd->arg >> 16); - OMAP_MMC_WRITE(host, IE, - OMAP_MMC_STAT_A_EMPTY | OMAP_MMC_STAT_A_FULL | - OMAP_MMC_STAT_CMD_CRC | OMAP_MMC_STAT_CMD_TOUT | - OMAP_MMC_STAT_DATA_CRC | OMAP_MMC_STAT_DATA_TOUT | - OMAP_MMC_STAT_END_OF_CMD | OMAP_MMC_STAT_CARD_ERR | - OMAP_MMC_STAT_END_OF_DATA); - OMAP_MMC_WRITE(host, CMD, cmdreg); -} - -static void -mmc_omap_release_dma(struct mmc_omap_host *host, struct mmc_data *data, - int abort) -{ - enum dma_data_direction dma_data_dir; - - BUG_ON(host->dma_ch < 0); - if (data->error) - omap_stop_dma(host->dma_ch); - /* Release DMA channel lazily */ - mod_timer(&host->dma_timer, jiffies + HZ); - if (data->flags & MMC_DATA_WRITE) - dma_data_dir = DMA_TO_DEVICE; - else - dma_data_dir = DMA_FROM_DEVICE; - dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->sg_len, - dma_data_dir); -} - -static void mmc_omap_send_stop_work(struct work_struct *work) -{ - struct mmc_omap_host *host = container_of(work, struct mmc_omap_host, - send_stop_work); - struct mmc_omap_slot *slot = host->current_slot; - struct mmc_data *data = host->stop_data; - unsigned long tick_ns; - - tick_ns = (1000000000 + slot->fclk_freq - 1)/slot->fclk_freq; - ndelay(8*tick_ns); - - mmc_omap_start_command(host, data->stop); -} - -static void -mmc_omap_xfer_done(struct mmc_omap_host *host, struct mmc_data *data) -{ - if (host->dma_in_use) - mmc_omap_release_dma(host, data, data->error); - - host->data = NULL; - host->sg_len = 0; - - /* NOTE: MMC layer will sometimes poll-wait CMD13 next, issuing - * dozens of requests until the card finishes writing data. - * It'd be cheaper to just wait till an EOFB interrupt arrives... - */ - - if (!data->stop) { - struct mmc_host *mmc; - - host->mrq = NULL; - mmc = host->mmc; - mmc_omap_release_slot(host->current_slot, 1); - mmc_request_done(mmc, data->mrq); - return; - } - - host->stop_data = data; - queue_work(mmc_omap_wq, &host->send_stop_work); -} - -static void -mmc_omap_send_abort(struct mmc_omap_host *host, int maxloops) -{ - struct mmc_omap_slot *slot = host->current_slot; - unsigned int restarts, passes, timeout; - u16 stat = 0; - - /* Sending abort takes 80 clocks. Have some extra and round up */ - timeout = (120*1000000 + slot->fclk_freq - 1)/slot->fclk_freq; - restarts = 0; - while (restarts < maxloops) { - OMAP_MMC_WRITE(host, STAT, 0xFFFF); - OMAP_MMC_WRITE(host, CMD, (3 << 12) | (1 << 7)); - - passes = 0; - while (passes < timeout) { - stat = OMAP_MMC_READ(host, STAT); - if (stat & OMAP_MMC_STAT_END_OF_CMD) - goto out; - udelay(1); - passes++; - } - - restarts++; - } -out: - OMAP_MMC_WRITE(host, STAT, stat); -} - -static void -mmc_omap_abort_xfer(struct mmc_omap_host *host, struct mmc_data *data) -{ - if (host->dma_in_use) - mmc_omap_release_dma(host, data, 1); - - host->data = NULL; - host->sg_len = 0; - - mmc_omap_send_abort(host, 10000); -} - -static void -mmc_omap_end_of_data(struct mmc_omap_host *host, struct mmc_data *data) -{ - unsigned long flags; - int done; - - if (!host->dma_in_use) { - mmc_omap_xfer_done(host, data); - return; - } - done = 0; - spin_lock_irqsave(&host->dma_lock, flags); - if (host->dma_done) - done = 1; - else - host->brs_received = 1; - spin_unlock_irqrestore(&host->dma_lock, flags); - if (done) - mmc_omap_xfer_done(host, data); -} - -static void -mmc_omap_dma_timer(unsigned long data) -{ - struct mmc_omap_host *host = (struct mmc_omap_host *) data; - - BUG_ON(host->dma_ch < 0); - omap_free_dma(host->dma_ch); - host->dma_ch = -1; -} - -static void -mmc_omap_dma_done(struct mmc_omap_host *host, struct mmc_data *data) -{ - unsigned long flags; - int done; - - done = 0; - spin_lock_irqsave(&host->dma_lock, flags); - if (host->brs_received) - done = 1; - else - host->dma_done = 1; - spin_unlock_irqrestore(&host->dma_lock, flags); - if (done) - mmc_omap_xfer_done(host, data); -} - -static void -mmc_omap_cmd_done(struct mmc_omap_host *host, struct mmc_command *cmd) -{ - host->cmd = NULL; - - del_timer(&host->cmd_abort_timer); - - if (cmd->flags & MMC_RSP_PRESENT) { - if (cmd->flags & MMC_RSP_136) { - /* response type 2 */ - cmd->resp[3] = - OMAP_MMC_READ(host, RSP0) | - (OMAP_MMC_READ(host, RSP1) << 16); - cmd->resp[2] = - OMAP_MMC_READ(host, RSP2) | - (OMAP_MMC_READ(host, RSP3) << 16); - cmd->resp[1] = - OMAP_MMC_READ(host, RSP4) | - (OMAP_MMC_READ(host, RSP5) << 16); - cmd->resp[0] = - OMAP_MMC_READ(host, RSP6) | - (OMAP_MMC_READ(host, RSP7) << 16); - } else { - /* response types 1, 1b, 3, 4, 5, 6 */ - cmd->resp[0] = - OMAP_MMC_READ(host, RSP6) | - (OMAP_MMC_READ(host, RSP7) << 16); - } - } - - if (host->data == NULL || cmd->error) { - struct mmc_host *mmc; - - if (host->data != NULL) - mmc_omap_abort_xfer(host, host->data); - host->mrq = NULL; - mmc = host->mmc; - mmc_omap_release_slot(host->current_slot, 1); - mmc_request_done(mmc, cmd->mrq); - } -} - -/* - * Abort stuck command. Can occur when card is removed while it is being - * read. - */ -static void mmc_omap_abort_command(struct work_struct *work) -{ - struct mmc_omap_host *host = container_of(work, struct mmc_omap_host, - cmd_abort_work); - BUG_ON(!host->cmd); - - dev_dbg(mmc_dev(host->mmc), "Aborting stuck command CMD%d\n", - host->cmd->opcode); - - if (host->cmd->error == 0) - host->cmd->error = -ETIMEDOUT; - - if (host->data == NULL) { - struct mmc_command *cmd; - struct mmc_host *mmc; - - cmd = host->cmd; - host->cmd = NULL; - mmc_omap_send_abort(host, 10000); - - host->mrq = NULL; - mmc = host->mmc; - mmc_omap_release_slot(host->current_slot, 1); - mmc_request_done(mmc, cmd->mrq); - } else - mmc_omap_cmd_done(host, host->cmd); - - host->abort = 0; - enable_irq(host->irq); -} - -static void -mmc_omap_cmd_timer(unsigned long data) -{ - struct mmc_omap_host *host = (struct mmc_omap_host *) data; - unsigned long flags; - - spin_lock_irqsave(&host->slot_lock, flags); - if (host->cmd != NULL && !host->abort) { - OMAP_MMC_WRITE(host, IE, 0); - disable_irq(host->irq); - host->abort = 1; - queue_work(mmc_omap_wq, &host->cmd_abort_work); - } - spin_unlock_irqrestore(&host->slot_lock, flags); -} - -/* PIO only */ -static void -mmc_omap_sg_to_buf(struct mmc_omap_host *host) -{ - struct scatterlist *sg; - - sg = host->data->sg + host->sg_idx; - host->buffer_bytes_left = sg->length; - host->buffer = sg_virt(sg); - if (host->buffer_bytes_left > host->total_bytes_left) - host->buffer_bytes_left = host->total_bytes_left; -} - -static void -mmc_omap_clk_timer(unsigned long data) -{ - struct mmc_omap_host *host = (struct mmc_omap_host *) data; - - mmc_omap_fclk_enable(host, 0); -} - -/* PIO only */ -static void -mmc_omap_xfer_data(struct mmc_omap_host *host, int write) -{ - int n; - - if (host->buffer_bytes_left == 0) { - host->sg_idx++; - BUG_ON(host->sg_idx == host->sg_len); - mmc_omap_sg_to_buf(host); - } - n = 64; - if (n > host->buffer_bytes_left) - n = host->buffer_bytes_left; - host->buffer_bytes_left -= n; - host->total_bytes_left -= n; - host->data->bytes_xfered += n; - - if (write) { - __raw_writesw(host->virt_base + OMAP_MMC_REG(host, DATA), host->buffer, n); - } else { - __raw_readsw(host->virt_base + OMAP_MMC_REG(host, DATA), host->buffer, n); - } -} - -static inline void mmc_omap_report_irq(u16 status) -{ - static const char *mmc_omap_status_bits[] = { - "EOC", "CD", "CB", "BRS", "EOFB", "DTO", "DCRC", "CTO", - "CCRC", "CRW", "AF", "AE", "OCRB", "CIRQ", "CERR" - }; - int i, c = 0; - - for (i = 0; i < ARRAY_SIZE(mmc_omap_status_bits); i++) - if (status & (1 << i)) { - if (c) - printk(" "); - printk("%s", mmc_omap_status_bits[i]); - c++; - } -} - -static irqreturn_t mmc_omap_irq(int irq, void *dev_id) -{ - struct mmc_omap_host * host = (struct mmc_omap_host *)dev_id; - u16 status; - int end_command; - int end_transfer; - int transfer_error, cmd_error; - - if (host->cmd == NULL && host->data == NULL) { - status = OMAP_MMC_READ(host, STAT); - dev_info(mmc_dev(host->slots[0]->mmc), - "Spurious IRQ 0x%04x\n", status); - if (status != 0) { - OMAP_MMC_WRITE(host, STAT, status); - OMAP_MMC_WRITE(host, IE, 0); - } - return IRQ_HANDLED; - } - - end_command = 0; - end_transfer = 0; - transfer_error = 0; - cmd_error = 0; - - while ((status = OMAP_MMC_READ(host, STAT)) != 0) { - int cmd; - - OMAP_MMC_WRITE(host, STAT, status); - if (host->cmd != NULL) - cmd = host->cmd->opcode; - else - cmd = -1; -#ifdef CONFIG_MMC_DEBUG - dev_dbg(mmc_dev(host->mmc), "MMC IRQ %04x (CMD %d): ", - status, cmd); - mmc_omap_report_irq(status); - printk("\n"); -#endif - if (host->total_bytes_left) { - if ((status & OMAP_MMC_STAT_A_FULL) || - (status & OMAP_MMC_STAT_END_OF_DATA)) - mmc_omap_xfer_data(host, 0); - if (status & OMAP_MMC_STAT_A_EMPTY) - mmc_omap_xfer_data(host, 1); - } - - if (status & OMAP_MMC_STAT_END_OF_DATA) - end_transfer = 1; - - if (status & OMAP_MMC_STAT_DATA_TOUT) { - dev_dbg(mmc_dev(host->mmc), "data timeout (CMD%d)\n", - cmd); - if (host->data) { - host->data->error = -ETIMEDOUT; - transfer_error = 1; - } - } - - if (status & OMAP_MMC_STAT_DATA_CRC) { - if (host->data) { - host->data->error = -EILSEQ; - dev_dbg(mmc_dev(host->mmc), - "data CRC error, bytes left %d\n", - host->total_bytes_left); - transfer_error = 1; - } else { - dev_dbg(mmc_dev(host->mmc), "data CRC error\n"); - } - } - - if (status & OMAP_MMC_STAT_CMD_TOUT) { - /* Timeouts are routine with some commands */ - if (host->cmd) { - struct mmc_omap_slot *slot = - host->current_slot; - if (slot == NULL || - !mmc_omap_cover_is_open(slot)) - dev_err(mmc_dev(host->mmc), - "command timeout (CMD%d)\n", - cmd); - host->cmd->error = -ETIMEDOUT; - end_command = 1; - cmd_error = 1; - } - } - - if (status & OMAP_MMC_STAT_CMD_CRC) { - if (host->cmd) { - dev_err(mmc_dev(host->mmc), - "command CRC error (CMD%d, arg 0x%08x)\n", - cmd, host->cmd->arg); - host->cmd->error = -EILSEQ; - end_command = 1; - cmd_error = 1; - } else - dev_err(mmc_dev(host->mmc), - "command CRC error without cmd?\n"); - } - - if (status & OMAP_MMC_STAT_CARD_ERR) { - dev_dbg(mmc_dev(host->mmc), - "ignoring card status error (CMD%d)\n", - cmd); - end_command = 1; - } - - /* - * NOTE: On 1610 the END_OF_CMD may come too early when - * starting a write - */ - if ((status & OMAP_MMC_STAT_END_OF_CMD) && - (!(status & OMAP_MMC_STAT_A_EMPTY))) { - end_command = 1; - } - } - - if (cmd_error && host->data) { - del_timer(&host->cmd_abort_timer); - host->abort = 1; - OMAP_MMC_WRITE(host, IE, 0); - disable_irq_nosync(host->irq); - queue_work(mmc_omap_wq, &host->cmd_abort_work); - return IRQ_HANDLED; - } - - if (end_command && host->cmd) - mmc_omap_cmd_done(host, host->cmd); - if (host->data != NULL) { - if (transfer_error) - mmc_omap_xfer_done(host, host->data); - else if (end_transfer) - mmc_omap_end_of_data(host, host->data); - } - - return IRQ_HANDLED; -} - -void omap_mmc_notify_cover_event(struct device *dev, int num, int is_closed) -{ - int cover_open; - struct mmc_omap_host *host = dev_get_drvdata(dev); - struct mmc_omap_slot *slot = host->slots[num]; - - BUG_ON(num >= host->nr_slots); - - /* Other subsystems can call in here before we're initialised. */ - if (host->nr_slots == 0 || !host->slots[num]) - return; - - cover_open = mmc_omap_cover_is_open(slot); - if (cover_open != slot->cover_open) { - slot->cover_open = cover_open; - sysfs_notify(&slot->mmc->class_dev.kobj, NULL, "cover_switch"); - } - - tasklet_hi_schedule(&slot->cover_tasklet); -} - -static void mmc_omap_cover_timer(unsigned long arg) -{ - struct mmc_omap_slot *slot = (struct mmc_omap_slot *) arg; - tasklet_schedule(&slot->cover_tasklet); -} - -static void mmc_omap_cover_handler(unsigned long param) -{ - struct mmc_omap_slot *slot = (struct mmc_omap_slot *)param; - int cover_open = mmc_omap_cover_is_open(slot); - - mmc_detect_change(slot->mmc, 0); - if (!cover_open) - return; - - /* - * If no card is inserted, we postpone polling until - * the cover has been closed. - */ - if (slot->mmc->card == NULL || !mmc_card_present(slot->mmc->card)) - return; - - mod_timer(&slot->cover_timer, - jiffies + msecs_to_jiffies(OMAP_MMC_COVER_POLL_DELAY)); -} - -/* Prepare to transfer the next segment of a scatterlist */ -static void -mmc_omap_prepare_dma(struct mmc_omap_host *host, struct mmc_data *data) -{ - int dma_ch = host->dma_ch; - unsigned long data_addr; - u16 buf, frame; - u32 count; - struct scatterlist *sg = &data->sg[host->sg_idx]; - int src_port = 0; - int dst_port = 0; - int sync_dev = 0; - - data_addr = host->phys_base + OMAP_MMC_REG(host, DATA); - frame = data->blksz; - count = sg_dma_len(sg); - - if ((data->blocks == 1) && (count > data->blksz)) - count = frame; - - host->dma_len = count; - - /* FIFO is 16x2 bytes on 15xx, and 32x2 bytes on 16xx and 24xx. - * Use 16 or 32 word frames when the blocksize is at least that large. - * Blocksize is usually 512 bytes; but not for some SD reads. - */ - if (cpu_is_omap15xx() && frame > 32) - frame = 32; - else if (frame > 64) - frame = 64; - count /= frame; - frame >>= 1; - - if (!(data->flags & MMC_DATA_WRITE)) { - buf = 0x800f | ((frame - 1) << 8); - - if (cpu_class_is_omap1()) { - src_port = OMAP_DMA_PORT_TIPB; - dst_port = OMAP_DMA_PORT_EMIFF; - } - if (cpu_is_omap24xx()) - sync_dev = OMAP24XX_DMA_MMC1_RX; - - omap_set_dma_src_params(dma_ch, src_port, - OMAP_DMA_AMODE_CONSTANT, - data_addr, 0, 0); - omap_set_dma_dest_params(dma_ch, dst_port, - OMAP_DMA_AMODE_POST_INC, - sg_dma_address(sg), 0, 0); - omap_set_dma_dest_data_pack(dma_ch, 1); - omap_set_dma_dest_burst_mode(dma_ch, OMAP_DMA_DATA_BURST_4); - } else { - buf = 0x0f80 | ((frame - 1) << 0); - - if (cpu_class_is_omap1()) { - src_port = OMAP_DMA_PORT_EMIFF; - dst_port = OMAP_DMA_PORT_TIPB; - } - if (cpu_is_omap24xx()) - sync_dev = OMAP24XX_DMA_MMC1_TX; - - omap_set_dma_dest_params(dma_ch, dst_port, - OMAP_DMA_AMODE_CONSTANT, - data_addr, 0, 0); - omap_set_dma_src_params(dma_ch, src_port, - OMAP_DMA_AMODE_POST_INC, - sg_dma_address(sg), 0, 0); - omap_set_dma_src_data_pack(dma_ch, 1); - omap_set_dma_src_burst_mode(dma_ch, OMAP_DMA_DATA_BURST_4); - } - - /* Max limit for DMA frame count is 0xffff */ - BUG_ON(count > 0xffff); - - OMAP_MMC_WRITE(host, BUF, buf); - omap_set_dma_transfer_params(dma_ch, OMAP_DMA_DATA_TYPE_S16, - frame, count, OMAP_DMA_SYNC_FRAME, - sync_dev, 0); -} - -/* A scatterlist segment completed */ -static void mmc_omap_dma_cb(int lch, u16 ch_status, void *data) -{ - struct mmc_omap_host *host = (struct mmc_omap_host *) data; - struct mmc_data *mmcdat = host->data; - - if (unlikely(host->dma_ch < 0)) { - dev_err(mmc_dev(host->mmc), - "DMA callback while DMA not enabled\n"); - return; - } - /* FIXME: We really should do something to _handle_ the errors */ - if (ch_status & OMAP1_DMA_TOUT_IRQ) { - dev_err(mmc_dev(host->mmc),"DMA timeout\n"); - return; - } - if (ch_status & OMAP_DMA_DROP_IRQ) { - dev_err(mmc_dev(host->mmc), "DMA sync error\n"); - return; - } - if (!(ch_status & OMAP_DMA_BLOCK_IRQ)) { - return; - } - mmcdat->bytes_xfered += host->dma_len; - host->sg_idx++; - if (host->sg_idx < host->sg_len) { - mmc_omap_prepare_dma(host, host->data); - omap_start_dma(host->dma_ch); - } else - mmc_omap_dma_done(host, host->data); -} - -static int mmc_omap_get_dma_channel(struct mmc_omap_host *host, struct mmc_data *data) -{ - const char *dma_dev_name; - int sync_dev, dma_ch, is_read, r; - - is_read = !(data->flags & MMC_DATA_WRITE); - del_timer_sync(&host->dma_timer); - if (host->dma_ch >= 0) { - if (is_read == host->dma_is_read) - return 0; - omap_free_dma(host->dma_ch); - host->dma_ch = -1; - } - - if (is_read) { - if (host->id == 0) { - sync_dev = OMAP_DMA_MMC_RX; - dma_dev_name = "MMC1 read"; - } else { - sync_dev = OMAP_DMA_MMC2_RX; - dma_dev_name = "MMC2 read"; - } - } else { - if (host->id == 0) { - sync_dev = OMAP_DMA_MMC_TX; - dma_dev_name = "MMC1 write"; - } else { - sync_dev = OMAP_DMA_MMC2_TX; - dma_dev_name = "MMC2 write"; - } - } - r = omap_request_dma(sync_dev, dma_dev_name, mmc_omap_dma_cb, - host, &dma_ch); - if (r != 0) { - dev_dbg(mmc_dev(host->mmc), "omap_request_dma() failed with %d\n", r); - return r; - } - host->dma_ch = dma_ch; - host->dma_is_read = is_read; - - return 0; -} - -static inline void set_cmd_timeout(struct mmc_omap_host *host, struct mmc_request *req) -{ - u16 reg; - - reg = OMAP_MMC_READ(host, SDIO); - reg &= ~(1 << 5); - OMAP_MMC_WRITE(host, SDIO, reg); - /* Set maximum timeout */ - OMAP_MMC_WRITE(host, CTO, 0xff); -} - -static inline void set_data_timeout(struct mmc_omap_host *host, struct mmc_request *req) -{ - unsigned int timeout, cycle_ns; - u16 reg; - - cycle_ns = 1000000000 / host->current_slot->fclk_freq; - timeout = req->data->timeout_ns / cycle_ns; - timeout += req->data->timeout_clks; - - /* Check if we need to use timeout multiplier register */ - reg = OMAP_MMC_READ(host, SDIO); - if (timeout > 0xffff) { - reg |= (1 << 5); - timeout /= 1024; - } else - reg &= ~(1 << 5); - OMAP_MMC_WRITE(host, SDIO, reg); - OMAP_MMC_WRITE(host, DTO, timeout); -} - -static void -mmc_omap_prepare_data(struct mmc_omap_host *host, struct mmc_request *req) -{ - struct mmc_data *data = req->data; - int i, use_dma, block_size; - unsigned sg_len; - - host->data = data; - if (data == NULL) { - OMAP_MMC_WRITE(host, BLEN, 0); - OMAP_MMC_WRITE(host, NBLK, 0); - OMAP_MMC_WRITE(host, BUF, 0); - host->dma_in_use = 0; - set_cmd_timeout(host, req); - return; - } - - block_size = data->blksz; - - OMAP_MMC_WRITE(host, NBLK, data->blocks - 1); - OMAP_MMC_WRITE(host, BLEN, block_size - 1); - set_data_timeout(host, req); - - /* cope with calling layer confusion; it issues "single - * block" writes using multi-block scatterlists. - */ - sg_len = (data->blocks == 1) ? 1 : data->sg_len; - - /* Only do DMA for entire blocks */ - use_dma = host->use_dma; - if (use_dma) { - for (i = 0; i < sg_len; i++) { - if ((data->sg[i].length % block_size) != 0) { - use_dma = 0; - break; - } - } - } - - host->sg_idx = 0; - if (use_dma) { - if (mmc_omap_get_dma_channel(host, data) == 0) { - enum dma_data_direction dma_data_dir; - - if (data->flags & MMC_DATA_WRITE) - dma_data_dir = DMA_TO_DEVICE; - else - dma_data_dir = DMA_FROM_DEVICE; - - host->sg_len = dma_map_sg(mmc_dev(host->mmc), data->sg, - sg_len, dma_data_dir); - host->total_bytes_left = 0; - mmc_omap_prepare_dma(host, req->data); - host->brs_received = 0; - host->dma_done = 0; - host->dma_in_use = 1; - } else - use_dma = 0; - } - - /* Revert to PIO? */ - if (!use_dma) { - OMAP_MMC_WRITE(host, BUF, 0x1f1f); - host->total_bytes_left = data->blocks * block_size; - host->sg_len = sg_len; - mmc_omap_sg_to_buf(host); - host->dma_in_use = 0; - } -} - -static void mmc_omap_start_request(struct mmc_omap_host *host, - struct mmc_request *req) -{ - BUG_ON(host->mrq != NULL); - - host->mrq = req; - - /* only touch fifo AFTER the controller readies it */ - mmc_omap_prepare_data(host, req); - mmc_omap_start_command(host, req->cmd); - if (host->dma_in_use) - omap_start_dma(host->dma_ch); -} - -static void mmc_omap_request(struct mmc_host *mmc, struct mmc_request *req) -{ - struct mmc_omap_slot *slot = mmc_priv(mmc); - struct mmc_omap_host *host = slot->host; - unsigned long flags; - - spin_lock_irqsave(&host->slot_lock, flags); - if (host->mmc != NULL) { - BUG_ON(slot->mrq != NULL); - slot->mrq = req; - spin_unlock_irqrestore(&host->slot_lock, flags); - return; - } else - host->mmc = mmc; - spin_unlock_irqrestore(&host->slot_lock, flags); - mmc_omap_select_slot(slot, 1); - mmc_omap_start_request(host, req); -} - -static void mmc_omap_set_power(struct mmc_omap_slot *slot, int power_on, - int vdd) -{ - struct mmc_omap_host *host; - - host = slot->host; - - if (slot->pdata->set_power != NULL) - slot->pdata->set_power(mmc_dev(slot->mmc), slot->id, power_on, - vdd); - - if (cpu_is_omap24xx()) { - u16 w; - - if (power_on) { - w = OMAP_MMC_READ(host, CON); - OMAP_MMC_WRITE(host, CON, w | (1 << 11)); - } else { - w = OMAP_MMC_READ(host, CON); - OMAP_MMC_WRITE(host, CON, w & ~(1 << 11)); - } - } -} - -static int mmc_omap_calc_divisor(struct mmc_host *mmc, struct mmc_ios *ios) -{ - struct mmc_omap_slot *slot = mmc_priv(mmc); - struct mmc_omap_host *host = slot->host; - int func_clk_rate = clk_get_rate(host->fclk); - int dsor; - - if (ios->clock == 0) - return 0; - - dsor = func_clk_rate / ios->clock; - if (dsor < 1) - dsor = 1; - - if (func_clk_rate / dsor > ios->clock) - dsor++; - - if (dsor > 250) - dsor = 250; - - slot->fclk_freq = func_clk_rate / dsor; - - if (ios->bus_width == MMC_BUS_WIDTH_4) - dsor |= 1 << 15; - - return dsor; -} - -static void mmc_omap_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) -{ - struct mmc_omap_slot *slot = mmc_priv(mmc); - struct mmc_omap_host *host = slot->host; - int i, dsor; - int clk_enabled; - - mmc_omap_select_slot(slot, 0); - - dsor = mmc_omap_calc_divisor(mmc, ios); - - if (ios->vdd != slot->vdd) - slot->vdd = ios->vdd; - - clk_enabled = 0; - switch (ios->power_mode) { - case MMC_POWER_OFF: - mmc_omap_set_power(slot, 0, ios->vdd); - break; - case MMC_POWER_UP: - /* Cannot touch dsor yet, just power up MMC */ - mmc_omap_set_power(slot, 1, ios->vdd); - goto exit; - case MMC_POWER_ON: - mmc_omap_fclk_enable(host, 1); - clk_enabled = 1; - dsor |= 1 << 11; - break; - } - - if (slot->bus_mode != ios->bus_mode) { - if (slot->pdata->set_bus_mode != NULL) - slot->pdata->set_bus_mode(mmc_dev(mmc), slot->id, - ios->bus_mode); - slot->bus_mode = ios->bus_mode; - } - - /* On insanely high arm_per frequencies something sometimes - * goes somehow out of sync, and the POW bit is not being set, - * which results in the while loop below getting stuck. - * Writing to the CON register twice seems to do the trick. */ - for (i = 0; i < 2; i++) - OMAP_MMC_WRITE(host, CON, dsor); - slot->saved_con = dsor; - if (ios->power_mode == MMC_POWER_ON) { - /* worst case at 400kHz, 80 cycles makes 200 microsecs */ - int usecs = 250; - - /* Send clock cycles, poll completion */ - OMAP_MMC_WRITE(host, IE, 0); - OMAP_MMC_WRITE(host, STAT, 0xffff); - OMAP_MMC_WRITE(host, CMD, 1 << 7); - while (usecs > 0 && (OMAP_MMC_READ(host, STAT) & 1) == 0) { - udelay(1); - usecs--; - } - OMAP_MMC_WRITE(host, STAT, 1); - } - -exit: - mmc_omap_release_slot(slot, clk_enabled); -} - -static const struct mmc_host_ops mmc_omap_ops = { - .request = mmc_omap_request, - .set_ios = mmc_omap_set_ios, -}; - -static int __init mmc_omap_new_slot(struct mmc_omap_host *host, int id) -{ - struct mmc_omap_slot *slot = NULL; - struct mmc_host *mmc; - int r; - - mmc = mmc_alloc_host(sizeof(struct mmc_omap_slot), host->dev); - if (mmc == NULL) - return -ENOMEM; - - slot = mmc_priv(mmc); - slot->host = host; - slot->mmc = mmc; - slot->id = id; - slot->pdata = &host->pdata->slots[id]; - - host->slots[id] = slot; - - mmc->caps = 0; - if (host->pdata->slots[id].wires >= 4) - mmc->caps |= MMC_CAP_4_BIT_DATA; - - mmc->ops = &mmc_omap_ops; - mmc->f_min = 400000; - - if (cpu_class_is_omap2()) - mmc->f_max = 48000000; - else - mmc->f_max = 24000000; - if (host->pdata->max_freq) - mmc->f_max = min(host->pdata->max_freq, mmc->f_max); - mmc->ocr_avail = slot->pdata->ocr_mask; - - /* Use scatterlist DMA to reduce per-transfer costs. - * NOTE max_seg_size assumption that small blocks aren't - * normally used (except e.g. for reading SD registers). - */ - mmc->max_segs = 32; - mmc->max_blk_size = 2048; /* BLEN is 11 bits (+1) */ - mmc->max_blk_count = 2048; /* NBLK is 11 bits (+1) */ - mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count; - mmc->max_seg_size = mmc->max_req_size; - - r = mmc_add_host(mmc); - if (r < 0) - goto err_remove_host; - - if (slot->pdata->name != NULL) { - r = device_create_file(&mmc->class_dev, - &dev_attr_slot_name); - if (r < 0) - goto err_remove_host; - } - - if (slot->pdata->get_cover_state != NULL) { - r = device_create_file(&mmc->class_dev, - &dev_attr_cover_switch); - if (r < 0) - goto err_remove_slot_name; - - setup_timer(&slot->cover_timer, mmc_omap_cover_timer, - (unsigned long)slot); - tasklet_init(&slot->cover_tasklet, mmc_omap_cover_handler, - (unsigned long)slot); - tasklet_schedule(&slot->cover_tasklet); - } - - return 0; - -err_remove_slot_name: - if (slot->pdata->name != NULL) - device_remove_file(&mmc->class_dev, &dev_attr_slot_name); -err_remove_host: - mmc_remove_host(mmc); - mmc_free_host(mmc); - return r; -} - -static void mmc_omap_remove_slot(struct mmc_omap_slot *slot) -{ - struct mmc_host *mmc = slot->mmc; - - if (slot->pdata->name != NULL) - device_remove_file(&mmc->class_dev, &dev_attr_slot_name); - if (slot->pdata->get_cover_state != NULL) - device_remove_file(&mmc->class_dev, &dev_attr_cover_switch); - - tasklet_kill(&slot->cover_tasklet); - del_timer_sync(&slot->cover_timer); - flush_workqueue(mmc_omap_wq); - - mmc_remove_host(mmc); - mmc_free_host(mmc); -} - -static int __init mmc_omap_probe(struct platform_device *pdev) -{ - struct omap_mmc_platform_data *pdata = pdev->dev.platform_data; - struct mmc_omap_host *host = NULL; - struct resource *res; - int i, ret = 0; - int irq; - - if (pdata == NULL) { - dev_err(&pdev->dev, "platform data missing\n"); - return -ENXIO; - } - if (pdata->nr_slots == 0) { - dev_err(&pdev->dev, "no slots\n"); - return -ENXIO; - } - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - irq = platform_get_irq(pdev, 0); - if (res == NULL || irq < 0) - return -ENXIO; - - res = request_mem_region(res->start, resource_size(res), - pdev->name); - if (res == NULL) - return -EBUSY; - - host = kzalloc(sizeof(struct mmc_omap_host), GFP_KERNEL); - if (host == NULL) { - ret = -ENOMEM; - goto err_free_mem_region; - } - - INIT_WORK(&host->slot_release_work, mmc_omap_slot_release_work); - INIT_WORK(&host->send_stop_work, mmc_omap_send_stop_work); - - INIT_WORK(&host->cmd_abort_work, mmc_omap_abort_command); - setup_timer(&host->cmd_abort_timer, mmc_omap_cmd_timer, - (unsigned long) host); - - spin_lock_init(&host->clk_lock); - setup_timer(&host->clk_timer, mmc_omap_clk_timer, (unsigned long) host); - - spin_lock_init(&host->dma_lock); - setup_timer(&host->dma_timer, mmc_omap_dma_timer, (unsigned long) host); - spin_lock_init(&host->slot_lock); - init_waitqueue_head(&host->slot_wq); - - host->pdata = pdata; - host->dev = &pdev->dev; - platform_set_drvdata(pdev, host); - - host->id = pdev->id; - host->mem_res = res; - host->irq = irq; - - host->use_dma = 1; - host->dev->dma_mask = &pdata->dma_mask; - host->dma_ch = -1; - - host->irq = irq; - host->phys_base = host->mem_res->start; - host->virt_base = ioremap(res->start, resource_size(res)); - if (!host->virt_base) - goto err_ioremap; - - host->iclk = clk_get(&pdev->dev, "ick"); - if (IS_ERR(host->iclk)) { - ret = PTR_ERR(host->iclk); - goto err_free_mmc_host; - } - clk_enable(host->iclk); - - host->fclk = clk_get(&pdev->dev, "fck"); - if (IS_ERR(host->fclk)) { - ret = PTR_ERR(host->fclk); - goto err_free_iclk; - } - - ret = request_irq(host->irq, mmc_omap_irq, 0, DRIVER_NAME, host); - if (ret) - goto err_free_fclk; - - if (pdata->init != NULL) { - ret = pdata->init(&pdev->dev); - if (ret < 0) - goto err_free_irq; - } - - host->nr_slots = pdata->nr_slots; - for (i = 0; i < pdata->nr_slots; i++) { - ret = mmc_omap_new_slot(host, i); - if (ret < 0) { - while (--i >= 0) - mmc_omap_remove_slot(host->slots[i]); - - goto err_plat_cleanup; - } - } - - host->reg_shift = (cpu_is_omap7xx() ? 1 : 2); - - return 0; - -err_plat_cleanup: - if (pdata->cleanup) - pdata->cleanup(&pdev->dev); -err_free_irq: - free_irq(host->irq, host); -err_free_fclk: - clk_put(host->fclk); -err_free_iclk: - clk_disable(host->iclk); - clk_put(host->iclk); -err_free_mmc_host: - iounmap(host->virt_base); -err_ioremap: - kfree(host); -err_free_mem_region: - release_mem_region(res->start, resource_size(res)); - return ret; -} - -static int mmc_omap_remove(struct platform_device *pdev) -{ - struct mmc_omap_host *host = platform_get_drvdata(pdev); - int i; - - platform_set_drvdata(pdev, NULL); - - BUG_ON(host == NULL); - - for (i = 0; i < host->nr_slots; i++) - mmc_omap_remove_slot(host->slots[i]); - - if (host->pdata->cleanup) - host->pdata->cleanup(&pdev->dev); - - mmc_omap_fclk_enable(host, 0); - free_irq(host->irq, host); - clk_put(host->fclk); - clk_disable(host->iclk); - clk_put(host->iclk); - - iounmap(host->virt_base); - release_mem_region(pdev->resource[0].start, - pdev->resource[0].end - pdev->resource[0].start + 1); - - kfree(host); - - return 0; -} - -#ifdef CONFIG_PM -static int mmc_omap_suspend(struct platform_device *pdev, pm_message_t mesg) -{ - int i, ret = 0; - struct mmc_omap_host *host = platform_get_drvdata(pdev); - - if (host == NULL || host->suspended) - return 0; - - for (i = 0; i < host->nr_slots; i++) { - struct mmc_omap_slot *slot; - - slot = host->slots[i]; - ret = mmc_suspend_host(slot->mmc); - if (ret < 0) { - while (--i >= 0) { - slot = host->slots[i]; - mmc_resume_host(slot->mmc); - } - return ret; - } - } - host->suspended = 1; - return 0; -} - -static int mmc_omap_resume(struct platform_device *pdev) -{ - int i, ret = 0; - struct mmc_omap_host *host = platform_get_drvdata(pdev); - - if (host == NULL || !host->suspended) - return 0; - - for (i = 0; i < host->nr_slots; i++) { - struct mmc_omap_slot *slot; - slot = host->slots[i]; - ret = mmc_resume_host(slot->mmc); - if (ret < 0) - return ret; - - host->suspended = 0; - } - return 0; -} -#else -#define mmc_omap_suspend NULL -#define mmc_omap_resume NULL -#endif - -static struct platform_driver mmc_omap_driver = { - .remove = mmc_omap_remove, - .suspend = mmc_omap_suspend, - .resume = mmc_omap_resume, - .driver = { - .name = DRIVER_NAME, - .owner = THIS_MODULE, - }, -}; - -static int __init mmc_omap_init(void) -{ - int ret; - - mmc_omap_wq = alloc_workqueue("mmc_omap", 0, 0); - if (!mmc_omap_wq) - return -ENOMEM; - - ret = platform_driver_probe(&mmc_omap_driver, mmc_omap_probe); - if (ret) - destroy_workqueue(mmc_omap_wq); - return ret; -} - -static void __exit mmc_omap_exit(void) -{ - platform_driver_unregister(&mmc_omap_driver); - destroy_workqueue(mmc_omap_wq); -} - -module_init(mmc_omap_init); -module_exit(mmc_omap_exit); - -MODULE_DESCRIPTION("OMAP Multimedia Card driver"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:" DRIVER_NAME); -MODULE_AUTHOR("Juha Yrjölä"); diff --git a/ANDROID_3.4.5/drivers/mmc/host/omap_hsmmc.c b/ANDROID_3.4.5/drivers/mmc/host/omap_hsmmc.c deleted file mode 100644 index 71a0c4ea..00000000 --- a/ANDROID_3.4.5/drivers/mmc/host/omap_hsmmc.c +++ /dev/null @@ -1,2209 +0,0 @@ -/* - * drivers/mmc/host/omap_hsmmc.c - * - * Driver for OMAP2430/3430 MMC controller. - * - * Copyright (C) 2007 Texas Instruments. - * - * Authors: - * Syed Mohammed Khasim <x0khasim@ti.com> - * Madhusudhan <madhu.cr@ti.com> - * Mohit Jalori <mjalori@ti.com> - * - * This file is licensed under the terms of the GNU General Public License - * version 2. This program is licensed "as is" without any warranty of any - * kind, whether express or implied. - */ - -#include <linux/module.h> -#include <linux/init.h> -#include <linux/kernel.h> -#include <linux/debugfs.h> -#include <linux/seq_file.h> -#include <linux/interrupt.h> -#include <linux/delay.h> -#include <linux/dma-mapping.h> -#include <linux/platform_device.h> -#include <linux/timer.h> -#include <linux/clk.h> -#include <linux/of.h> -#include <linux/of_gpio.h> -#include <linux/of_device.h> -#include <linux/mmc/host.h> -#include <linux/mmc/core.h> -#include <linux/mmc/mmc.h> -#include <linux/io.h> -#include <linux/semaphore.h> -#include <linux/gpio.h> -#include <linux/regulator/consumer.h> -#include <linux/pm_runtime.h> -#include <plat/dma.h> -#include <mach/hardware.h> -#include <plat/board.h> -#include <plat/mmc.h> -#include <plat/cpu.h> - -/* OMAP HSMMC Host Controller Registers */ -#define OMAP_HSMMC_SYSCONFIG 0x0010 -#define OMAP_HSMMC_SYSSTATUS 0x0014 -#define OMAP_HSMMC_CON 0x002C -#define OMAP_HSMMC_BLK 0x0104 -#define OMAP_HSMMC_ARG 0x0108 -#define OMAP_HSMMC_CMD 0x010C -#define OMAP_HSMMC_RSP10 0x0110 -#define OMAP_HSMMC_RSP32 0x0114 -#define OMAP_HSMMC_RSP54 0x0118 -#define OMAP_HSMMC_RSP76 0x011C -#define OMAP_HSMMC_DATA 0x0120 -#define OMAP_HSMMC_HCTL 0x0128 -#define OMAP_HSMMC_SYSCTL 0x012C -#define OMAP_HSMMC_STAT 0x0130 -#define OMAP_HSMMC_IE 0x0134 -#define OMAP_HSMMC_ISE 0x0138 -#define OMAP_HSMMC_CAPA 0x0140 - -#define VS18 (1 << 26) -#define VS30 (1 << 25) -#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 -#define SDBP (1 << 8) -#define DTO 0xe -#define ICE 0x1 -#define ICS 0x2 -#define CEN (1 << 2) -#define CLKD_MASK 0x0000FFC0 -#define CLKD_SHIFT 6 -#define DTO_MASK 0x000F0000 -#define DTO_SHIFT 16 -#define INT_EN_MASK 0x307F0033 -#define BWR_ENABLE (1 << 4) -#define BRR_ENABLE (1 << 5) -#define DTO_ENABLE (1 << 20) -#define INIT_STREAM (1 << 1) -#define DP_SELECT (1 << 21) -#define DDIR (1 << 4) -#define DMA_EN 0x1 -#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 -#define ERR (1 << 15) -#define CMD_TIMEOUT (1 << 16) -#define DATA_TIMEOUT (1 << 20) -#define CMD_CRC (1 << 17) -#define DATA_CRC (1 << 21) -#define CARD_ERR (1 << 28) -#define STAT_CLEAR 0xFFFFFFFF -#define INIT_STREAM_CMD 0x00000000 -#define DUAL_VOLT_OCR_BIT 7 -#define SRC (1 << 25) -#define SRD (1 << 26) -#define SOFTRESET (1 << 1) -#define RESETDONE (1 << 0) - -#define MMC_AUTOSUSPEND_DELAY 100 -#define MMC_TIMEOUT_MS 20 -#define OMAP_MMC_MIN_CLOCK 400000 -#define OMAP_MMC_MAX_CLOCK 52000000 -#define DRIVER_NAME "omap_hsmmc" - -/* - * One controller can have multiple slots, like on some omap boards using - * omap.c controller driver. Luckily this is not currently done on any known - * omap_hsmmc.c device. - */ -#define mmc_slot(host) (host->pdata->slots[host->slot_id]) - -/* - * MMC Host controller read/write API's - */ -#define OMAP_HSMMC_READ(base, reg) \ - __raw_readl((base) + OMAP_HSMMC_##reg) - -#define OMAP_HSMMC_WRITE(base, reg, val) \ - __raw_writel((val), (base) + OMAP_HSMMC_##reg) - -struct omap_hsmmc_next { - unsigned int dma_len; - s32 cookie; -}; - -struct omap_hsmmc_host { - struct device *dev; - struct mmc_host *mmc; - struct mmc_request *mrq; - struct mmc_command *cmd; - struct mmc_data *data; - struct clk *fclk; - struct clk *dbclk; - /* - * vcc == configured supply - * vcc_aux == optional - * - MMC1, supply for DAT4..DAT7 - * - MMC2/MMC2, external level shifter voltage supply, for - * chip (SDIO, eMMC, etc) or transceiver (MMC2 only) - */ - struct regulator *vcc; - struct regulator *vcc_aux; - void __iomem *base; - resource_size_t mapbase; - spinlock_t irq_lock; /* Prevent races with irq handler */ - unsigned int dma_len; - unsigned int dma_sg_idx; - unsigned char bus_mode; - unsigned char power_mode; - u32 *buffer; - u32 bytesleft; - int suspended; - int irq; - int use_dma, dma_ch; - int dma_line_tx, dma_line_rx; - int slot_id; - int got_dbclk; - int response_busy; - int context_loss; - int vdd; - int protect_card; - int reqs_blocked; - int use_reg; - int req_in_progress; - struct omap_hsmmc_next next_data; - - struct omap_mmc_platform_data *pdata; -}; - -static int omap_hsmmc_card_detect(struct device *dev, int slot) -{ - struct omap_mmc_platform_data *mmc = dev->platform_data; - - /* NOTE: assumes card detect signal is active-low */ - return !gpio_get_value_cansleep(mmc->slots[0].switch_pin); -} - -static int omap_hsmmc_get_wp(struct device *dev, int slot) -{ - struct omap_mmc_platform_data *mmc = dev->platform_data; - - /* NOTE: assumes write protect signal is active-high */ - return gpio_get_value_cansleep(mmc->slots[0].gpio_wp); -} - -static int omap_hsmmc_get_cover_state(struct device *dev, int slot) -{ - struct omap_mmc_platform_data *mmc = dev->platform_data; - - /* NOTE: assumes card detect signal is active-low */ - return !gpio_get_value_cansleep(mmc->slots[0].switch_pin); -} - -#ifdef CONFIG_PM - -static int omap_hsmmc_suspend_cdirq(struct device *dev, int slot) -{ - struct omap_mmc_platform_data *mmc = dev->platform_data; - - disable_irq(mmc->slots[0].card_detect_irq); - return 0; -} - -static int omap_hsmmc_resume_cdirq(struct device *dev, int slot) -{ - struct omap_mmc_platform_data *mmc = dev->platform_data; - - enable_irq(mmc->slots[0].card_detect_irq); - return 0; -} - -#else - -#define omap_hsmmc_suspend_cdirq NULL -#define omap_hsmmc_resume_cdirq NULL - -#endif - -#ifdef CONFIG_REGULATOR - -static int omap_hsmmc_set_power(struct device *dev, int slot, int power_on, - int vdd) -{ - struct omap_hsmmc_host *host = - platform_get_drvdata(to_platform_device(dev)); - int ret = 0; - - /* - * If we don't see a Vcc regulator, assume it's a fixed - * voltage always-on regulator. - */ - if (!host->vcc) - return 0; - /* - * With DT, never turn OFF the regulator. This is because - * the pbias cell programming support is still missing when - * booting with Device tree - */ - if (dev->of_node && !vdd) - return 0; - - if (mmc_slot(host).before_set_reg) - mmc_slot(host).before_set_reg(dev, slot, power_on, vdd); - - /* - * Assume Vcc regulator is used only to power the card ... OMAP - * VDDS is used to power the pins, optionally with a transceiver to - * support cards using voltages other than VDDS (1.8V nominal). When a - * transceiver is used, DAT3..7 are muxed as transceiver control pins. - * - * In some cases this regulator won't support enable/disable; - * e.g. it's a fixed rail for a WLAN chip. - * - * In other cases vcc_aux switches interface power. Example, for - * eMMC cards it represents VccQ. Sometimes transceivers or SDIO - * chips/cards need an interface voltage rail too. - */ - if (power_on) { - ret = mmc_regulator_set_ocr(host->mmc, host->vcc, vdd); - /* Enable interface voltage rail, if needed */ - if (ret == 0 && host->vcc_aux) { - ret = regulator_enable(host->vcc_aux); - if (ret < 0) - ret = mmc_regulator_set_ocr(host->mmc, - host->vcc, 0); - } - } else { - /* Shut down the rail */ - if (host->vcc_aux) - ret = regulator_disable(host->vcc_aux); - if (!ret) { - /* Then proceed to shut down the local regulator */ - ret = mmc_regulator_set_ocr(host->mmc, - host->vcc, 0); - } - } - - if (mmc_slot(host).after_set_reg) - mmc_slot(host).after_set_reg(dev, slot, power_on, vdd); - - return ret; -} - -static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host) -{ - struct regulator *reg; - int ocr_value = 0; - - mmc_slot(host).set_power = omap_hsmmc_set_power; - - reg = regulator_get(host->dev, "vmmc"); - if (IS_ERR(reg)) { - dev_dbg(host->dev, "vmmc regulator missing\n"); - } else { - host->vcc = reg; - ocr_value = mmc_regulator_get_ocrmask(reg); - if (!mmc_slot(host).ocr_mask) { - mmc_slot(host).ocr_mask = ocr_value; - } else { - if (!(mmc_slot(host).ocr_mask & ocr_value)) { - dev_err(host->dev, "ocrmask %x is not supported\n", - mmc_slot(host).ocr_mask); - mmc_slot(host).ocr_mask = 0; - return -EINVAL; - } - } - - /* Allow an aux regulator */ - reg = regulator_get(host->dev, "vmmc_aux"); - host->vcc_aux = IS_ERR(reg) ? NULL : reg; - - /* For eMMC do not power off when not in sleep state */ - if (mmc_slot(host).no_regulator_off_init) - return 0; - /* - * UGLY HACK: workaround regulator framework bugs. - * When the bootloader leaves a supply active, it's - * initialized with zero usecount ... and we can't - * disable it without first enabling it. Until the - * framework is fixed, we need a workaround like this - * (which is safe for MMC, but not in general). - */ - if (regulator_is_enabled(host->vcc) > 0 || - (host->vcc_aux && regulator_is_enabled(host->vcc_aux))) { - int vdd = ffs(mmc_slot(host).ocr_mask) - 1; - - mmc_slot(host).set_power(host->dev, host->slot_id, - 1, vdd); - mmc_slot(host).set_power(host->dev, host->slot_id, - 0, 0); - } - } - - return 0; -} - -static void omap_hsmmc_reg_put(struct omap_hsmmc_host *host) -{ - regulator_put(host->vcc); - regulator_put(host->vcc_aux); - mmc_slot(host).set_power = NULL; -} - -static inline int omap_hsmmc_have_reg(void) -{ - return 1; -} - -#else - -static inline int omap_hsmmc_reg_get(struct omap_hsmmc_host *host) -{ - return -EINVAL; -} - -static inline void omap_hsmmc_reg_put(struct omap_hsmmc_host *host) -{ -} - -static inline int omap_hsmmc_have_reg(void) -{ - return 0; -} - -#endif - -static int omap_hsmmc_gpio_init(struct omap_mmc_platform_data *pdata) -{ - int ret; - - if (gpio_is_valid(pdata->slots[0].switch_pin)) { - if (pdata->slots[0].cover) - pdata->slots[0].get_cover_state = - omap_hsmmc_get_cover_state; - else - pdata->slots[0].card_detect = omap_hsmmc_card_detect; - pdata->slots[0].card_detect_irq = - gpio_to_irq(pdata->slots[0].switch_pin); - ret = gpio_request(pdata->slots[0].switch_pin, "mmc_cd"); - if (ret) - return ret; - ret = gpio_direction_input(pdata->slots[0].switch_pin); - if (ret) - goto err_free_sp; - } else - pdata->slots[0].switch_pin = -EINVAL; - - if (gpio_is_valid(pdata->slots[0].gpio_wp)) { - pdata->slots[0].get_ro = omap_hsmmc_get_wp; - ret = gpio_request(pdata->slots[0].gpio_wp, "mmc_wp"); - if (ret) - goto err_free_cd; - ret = gpio_direction_input(pdata->slots[0].gpio_wp); - if (ret) - goto err_free_wp; - } else - pdata->slots[0].gpio_wp = -EINVAL; - - return 0; - -err_free_wp: - gpio_free(pdata->slots[0].gpio_wp); -err_free_cd: - if (gpio_is_valid(pdata->slots[0].switch_pin)) -err_free_sp: - gpio_free(pdata->slots[0].switch_pin); - return ret; -} - -static void omap_hsmmc_gpio_free(struct omap_mmc_platform_data *pdata) -{ - if (gpio_is_valid(pdata->slots[0].gpio_wp)) - gpio_free(pdata->slots[0].gpio_wp); - if (gpio_is_valid(pdata->slots[0].switch_pin)) - gpio_free(pdata->slots[0].switch_pin); -} - -/* - * Start clock to the card - */ -static void omap_hsmmc_start_clock(struct omap_hsmmc_host *host) -{ - OMAP_HSMMC_WRITE(host->base, SYSCTL, - OMAP_HSMMC_READ(host->base, SYSCTL) | CEN); -} - -/* - * Stop clock to the card - */ -static void omap_hsmmc_stop_clock(struct omap_hsmmc_host *host) -{ - OMAP_HSMMC_WRITE(host->base, SYSCTL, - OMAP_HSMMC_READ(host->base, SYSCTL) & ~CEN); - if ((OMAP_HSMMC_READ(host->base, SYSCTL) & CEN) != 0x0) - dev_dbg(mmc_dev(host->mmc), "MMC Clock is not stoped\n"); -} - -static void omap_hsmmc_enable_irq(struct omap_hsmmc_host *host, - struct mmc_command *cmd) -{ - unsigned int irq_mask; - - if (host->use_dma) - irq_mask = INT_EN_MASK & ~(BRR_ENABLE | BWR_ENABLE); - else - irq_mask = INT_EN_MASK; - - /* Disable timeout for erases */ - if (cmd->opcode == MMC_ERASE) - irq_mask &= ~DTO_ENABLE; - - OMAP_HSMMC_WRITE(host->base, STAT, STAT_CLEAR); - OMAP_HSMMC_WRITE(host->base, ISE, irq_mask); - OMAP_HSMMC_WRITE(host->base, IE, irq_mask); -} - -static void omap_hsmmc_disable_irq(struct omap_hsmmc_host *host) -{ - OMAP_HSMMC_WRITE(host->base, ISE, 0); - OMAP_HSMMC_WRITE(host->base, IE, 0); - OMAP_HSMMC_WRITE(host->base, STAT, STAT_CLEAR); -} - -/* Calculate divisor for the given clock frequency */ -static u16 calc_divisor(struct omap_hsmmc_host *host, struct mmc_ios *ios) -{ - u16 dsor = 0; - - if (ios->clock) { - dsor = DIV_ROUND_UP(clk_get_rate(host->fclk), ios->clock); - if (dsor > 250) - dsor = 250; - } - - return dsor; -} - -static void omap_hsmmc_set_clock(struct omap_hsmmc_host *host) -{ - struct mmc_ios *ios = &host->mmc->ios; - unsigned long regval; - unsigned long timeout; - - dev_dbg(mmc_dev(host->mmc), "Set clock to %uHz\n", ios->clock); - - omap_hsmmc_stop_clock(host); - - regval = OMAP_HSMMC_READ(host->base, SYSCTL); - regval = regval & ~(CLKD_MASK | DTO_MASK); - regval = regval | (calc_divisor(host, ios) << 6) | (DTO << 16); - OMAP_HSMMC_WRITE(host->base, SYSCTL, regval); - OMAP_HSMMC_WRITE(host->base, SYSCTL, - OMAP_HSMMC_READ(host->base, SYSCTL) | ICE); - - /* Wait till the ICS bit is set */ - timeout = jiffies + msecs_to_jiffies(MMC_TIMEOUT_MS); - while ((OMAP_HSMMC_READ(host->base, SYSCTL) & ICS) != ICS - && time_before(jiffies, timeout)) - cpu_relax(); - - omap_hsmmc_start_clock(host); -} - -static void omap_hsmmc_set_bus_width(struct omap_hsmmc_host *host) -{ - struct mmc_ios *ios = &host->mmc->ios; - u32 con; - - con = OMAP_HSMMC_READ(host->base, CON); - switch (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; - } -} - -static void omap_hsmmc_set_bus_mode(struct omap_hsmmc_host *host) -{ - struct mmc_ios *ios = &host->mmc->ios; - u32 con; - - con = OMAP_HSMMC_READ(host->base, CON); - if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN) - OMAP_HSMMC_WRITE(host->base, CON, con | OD); - else - OMAP_HSMMC_WRITE(host->base, CON, con & ~OD); -} - -#ifdef CONFIG_PM - -/* - * Restore the MMC host context, if it was lost as result of a - * power state change. - */ -static int omap_hsmmc_context_restore(struct omap_hsmmc_host *host) -{ - struct mmc_ios *ios = &host->mmc->ios; - struct omap_mmc_platform_data *pdata = host->pdata; - int context_loss = 0; - u32 hctl, capa; - unsigned long timeout; - - if (pdata->get_context_loss_count) { - context_loss = pdata->get_context_loss_count(host->dev); - if (context_loss < 0) - return 1; - } - - dev_dbg(mmc_dev(host->mmc), "context was %slost\n", - context_loss == host->context_loss ? "not " : ""); - if (host->context_loss == context_loss) - return 1; - - /* Wait for hardware reset */ - timeout = jiffies + msecs_to_jiffies(MMC_TIMEOUT_MS); - while ((OMAP_HSMMC_READ(host->base, SYSSTATUS) & RESETDONE) != RESETDONE - && time_before(jiffies, timeout)) - ; - - /* Do software reset */ - OMAP_HSMMC_WRITE(host->base, SYSCONFIG, SOFTRESET); - timeout = jiffies + msecs_to_jiffies(MMC_TIMEOUT_MS); - while ((OMAP_HSMMC_READ(host->base, SYSSTATUS) & RESETDONE) != RESETDONE - && time_before(jiffies, timeout)) - ; - - OMAP_HSMMC_WRITE(host->base, SYSCONFIG, - OMAP_HSMMC_READ(host->base, SYSCONFIG) | AUTOIDLE); - - if (host->pdata->controller_flags & OMAP_HSMMC_SUPPORTS_DUAL_VOLT) { - if (host->power_mode != MMC_POWER_OFF && - (1 << ios->vdd) <= MMC_VDD_23_24) - hctl = SDVS18; - else - 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); - - OMAP_HSMMC_WRITE(host->base, HCTL, - OMAP_HSMMC_READ(host->base, HCTL) | SDBP); - - timeout = jiffies + msecs_to_jiffies(MMC_TIMEOUT_MS); - while ((OMAP_HSMMC_READ(host->base, HCTL) & SDBP) != SDBP - && time_before(jiffies, timeout)) - ; - - omap_hsmmc_disable_irq(host); - - /* Do not initialize card-specific things if the power is off */ - if (host->power_mode == MMC_POWER_OFF) - goto out; - - omap_hsmmc_set_bus_width(host); - - omap_hsmmc_set_clock(host); - - omap_hsmmc_set_bus_mode(host); - -out: - host->context_loss = context_loss; - - dev_dbg(mmc_dev(host->mmc), "context is restored\n"); - return 0; -} - -/* - * Save the MMC host context (store the number of power state changes so far). - */ -static void omap_hsmmc_context_save(struct omap_hsmmc_host *host) -{ - struct omap_mmc_platform_data *pdata = host->pdata; - int context_loss; - - if (pdata->get_context_loss_count) { - context_loss = pdata->get_context_loss_count(host->dev); - if (context_loss < 0) - return; - host->context_loss = context_loss; - } -} - -#else - -static int omap_hsmmc_context_restore(struct omap_hsmmc_host *host) -{ - return 0; -} - -static void omap_hsmmc_context_save(struct omap_hsmmc_host *host) -{ -} - -#endif - -/* - * Send init stream sequence to card - * before sending IDLE command - */ -static void send_init_stream(struct omap_hsmmc_host *host) -{ - int reg = 0; - unsigned long timeout; - - if (host->protect_card) - return; - - disable_irq(host->irq); - - OMAP_HSMMC_WRITE(host->base, IE, INT_EN_MASK); - OMAP_HSMMC_WRITE(host->base, CON, - OMAP_HSMMC_READ(host->base, CON) | INIT_STREAM); - OMAP_HSMMC_WRITE(host->base, CMD, INIT_STREAM_CMD); - - timeout = jiffies + msecs_to_jiffies(MMC_TIMEOUT_MS); - while ((reg != CC) && time_before(jiffies, timeout)) - reg = OMAP_HSMMC_READ(host->base, STAT) & CC; - - OMAP_HSMMC_WRITE(host->base, CON, - OMAP_HSMMC_READ(host->base, CON) & ~INIT_STREAM); - - OMAP_HSMMC_WRITE(host->base, STAT, STAT_CLEAR); - OMAP_HSMMC_READ(host->base, STAT); - - enable_irq(host->irq); -} - -static inline -int omap_hsmmc_cover_is_closed(struct omap_hsmmc_host *host) -{ - int r = 1; - - if (mmc_slot(host).get_cover_state) - r = mmc_slot(host).get_cover_state(host->dev, host->slot_id); - return r; -} - -static ssize_t -omap_hsmmc_show_cover_switch(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct mmc_host *mmc = container_of(dev, struct mmc_host, class_dev); - struct omap_hsmmc_host *host = mmc_priv(mmc); - - return sprintf(buf, "%s\n", - omap_hsmmc_cover_is_closed(host) ? "closed" : "open"); -} - -static DEVICE_ATTR(cover_switch, S_IRUGO, omap_hsmmc_show_cover_switch, NULL); - -static ssize_t -omap_hsmmc_show_slot_name(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct mmc_host *mmc = container_of(dev, struct mmc_host, class_dev); - struct omap_hsmmc_host *host = mmc_priv(mmc); - - return sprintf(buf, "%s\n", mmc_slot(host).name); -} - -static DEVICE_ATTR(slot_name, S_IRUGO, omap_hsmmc_show_slot_name, NULL); - -/* - * Configure the response type and send the cmd. - */ -static void -omap_hsmmc_start_command(struct omap_hsmmc_host *host, struct mmc_command *cmd, - struct mmc_data *data) -{ - int cmdreg = 0, resptype = 0, cmdtype = 0; - - dev_dbg(mmc_dev(host->mmc), "%s: CMD%d, argument 0x%08x\n", - mmc_hostname(host->mmc), cmd->opcode, cmd->arg); - host->cmd = cmd; - - omap_hsmmc_enable_irq(host, cmd); - - host->response_busy = 0; - if (cmd->flags & MMC_RSP_PRESENT) { - if (cmd->flags & MMC_RSP_136) - resptype = 1; - else if (cmd->flags & MMC_RSP_BUSY) { - resptype = 3; - host->response_busy = 1; - } else - resptype = 2; - } - - /* - * Unlike OMAP1 controller, the cmdtype does not seem to be based on - * ac, bc, adtc, bcr. Only commands ending an open ended transfer need - * a val of 0x3, rest 0x0. - */ - if (cmd == host->mrq->stop) - cmdtype = 0x3; - - cmdreg = (cmd->opcode << 24) | (resptype << 16) | (cmdtype << 22); - - if (data) { - cmdreg |= DP_SELECT | MSBS | BCE; - if (data->flags & MMC_DATA_READ) - cmdreg |= DDIR; - else - cmdreg &= ~(DDIR); - } - - if (host->use_dma) - cmdreg |= DMA_EN; - - host->req_in_progress = 1; - - OMAP_HSMMC_WRITE(host->base, ARG, cmd->arg); - OMAP_HSMMC_WRITE(host->base, CMD, cmdreg); -} - -static int -omap_hsmmc_get_dma_dir(struct omap_hsmmc_host *host, struct mmc_data *data) -{ - if (data->flags & MMC_DATA_WRITE) - return DMA_TO_DEVICE; - else - return DMA_FROM_DEVICE; -} - -static void omap_hsmmc_request_done(struct omap_hsmmc_host *host, struct mmc_request *mrq) -{ - int dma_ch; - - spin_lock(&host->irq_lock); - host->req_in_progress = 0; - dma_ch = host->dma_ch; - spin_unlock(&host->irq_lock); - - omap_hsmmc_disable_irq(host); - /* Do not complete the request if DMA is still in progress */ - if (mrq->data && host->use_dma && dma_ch != -1) - return; - host->mrq = NULL; - mmc_request_done(host->mmc, mrq); -} - -/* - * Notify the transfer complete to MMC core - */ -static void -omap_hsmmc_xfer_done(struct omap_hsmmc_host *host, struct mmc_data *data) -{ - if (!data) { - struct mmc_request *mrq = host->mrq; - - /* TC before CC from CMD6 - don't know why, but it happens */ - if (host->cmd && host->cmd->opcode == 6 && - host->response_busy) { - host->response_busy = 0; - return; - } - - omap_hsmmc_request_done(host, mrq); - return; - } - - host->data = NULL; - - if (!data->error) - data->bytes_xfered += data->blocks * (data->blksz); - else - data->bytes_xfered = 0; - - if (!data->stop) { - omap_hsmmc_request_done(host, data->mrq); - return; - } - omap_hsmmc_start_command(host, data->stop, NULL); -} - -/* - * Notify the core about command completion - */ -static void -omap_hsmmc_cmd_done(struct omap_hsmmc_host *host, struct mmc_command *cmd) -{ - host->cmd = NULL; - - if (cmd->flags & MMC_RSP_PRESENT) { - if (cmd->flags & MMC_RSP_136) { - /* response type 2 */ - cmd->resp[3] = OMAP_HSMMC_READ(host->base, RSP10); - cmd->resp[2] = OMAP_HSMMC_READ(host->base, RSP32); - cmd->resp[1] = OMAP_HSMMC_READ(host->base, RSP54); - cmd->resp[0] = OMAP_HSMMC_READ(host->base, RSP76); - } else { - /* response types 1, 1b, 3, 4, 5, 6 */ - cmd->resp[0] = OMAP_HSMMC_READ(host->base, RSP10); - } - } - if ((host->data == NULL && !host->response_busy) || cmd->error) - omap_hsmmc_request_done(host, cmd->mrq); -} - -/* - * DMA clean up for command errors - */ -static void omap_hsmmc_dma_cleanup(struct omap_hsmmc_host *host, int errno) -{ - int dma_ch; - - host->data->error = errno; - - spin_lock(&host->irq_lock); - dma_ch = host->dma_ch; - host->dma_ch = -1; - spin_unlock(&host->irq_lock); - - if (host->use_dma && dma_ch != -1) { - dma_unmap_sg(mmc_dev(host->mmc), host->data->sg, - host->data->sg_len, - omap_hsmmc_get_dma_dir(host, host->data)); - omap_free_dma(dma_ch); - host->data->host_cookie = 0; - } - host->data = NULL; -} - -/* - * Readable error output - */ -#ifdef CONFIG_MMC_DEBUG -static void omap_hsmmc_dbg_report_irq(struct omap_hsmmc_host *host, u32 status) -{ - /* --- means reserved bit without definition at documentation */ - static const char *omap_hsmmc_status_bits[] = { - "CC" , "TC" , "BGE", "---", "BWR" , "BRR" , "---" , "---" , - "CIRQ", "OBI" , "---", "---", "---" , "---" , "---" , "ERRI", - "CTO" , "CCRC", "CEB", "CIE", "DTO" , "DCRC", "DEB" , "---" , - "ACE" , "---" , "---", "---", "CERR", "BADA", "---" , "---" - }; - char res[256]; - char *buf = res; - int len, i; - - len = sprintf(buf, "MMC IRQ 0x%x :", status); - buf += len; - - for (i = 0; i < ARRAY_SIZE(omap_hsmmc_status_bits); i++) - if (status & (1 << i)) { - len = sprintf(buf, " %s", omap_hsmmc_status_bits[i]); - buf += len; - } - - dev_dbg(mmc_dev(host->mmc), "%s\n", res); -} -#else -static inline void omap_hsmmc_dbg_report_irq(struct omap_hsmmc_host *host, - u32 status) -{ -} -#endif /* CONFIG_MMC_DEBUG */ - -/* - * MMC controller internal state machines reset - * - * Used to reset command or data internal state machines, using respectively - * SRC or SRD bit of SYSCTL register - * Can be called from interrupt context - */ -static inline void omap_hsmmc_reset_controller_fsm(struct omap_hsmmc_host *host, - unsigned long bit) -{ - unsigned long i = 0; - unsigned long limit = (loops_per_jiffy * - msecs_to_jiffies(MMC_TIMEOUT_MS)); - - OMAP_HSMMC_WRITE(host->base, SYSCTL, - OMAP_HSMMC_READ(host->base, SYSCTL) | bit); - - /* - * OMAP4 ES2 and greater has an updated reset logic. - * Monitor a 0->1 transition first - */ - if (mmc_slot(host).features & HSMMC_HAS_UPDATED_RESET) { - while ((!(OMAP_HSMMC_READ(host->base, SYSCTL) & bit)) - && (i++ < limit)) - cpu_relax(); - } - i = 0; - - while ((OMAP_HSMMC_READ(host->base, SYSCTL) & bit) && - (i++ < limit)) - cpu_relax(); - - if (OMAP_HSMMC_READ(host->base, SYSCTL) & bit) - dev_err(mmc_dev(host->mmc), - "Timeout waiting on controller reset in %s\n", - __func__); -} - -static void omap_hsmmc_do_irq(struct omap_hsmmc_host *host, int status) -{ - struct mmc_data *data; - int end_cmd = 0, end_trans = 0; - - if (!host->req_in_progress) { - do { - OMAP_HSMMC_WRITE(host->base, STAT, status); - /* Flush posted write */ - status = OMAP_HSMMC_READ(host->base, STAT); - } while (status & INT_EN_MASK); - return; - } - - data = host->data; - dev_dbg(mmc_dev(host->mmc), "IRQ Status is %x\n", status); - - if (status & ERR) { - omap_hsmmc_dbg_report_irq(host, status); - if ((status & CMD_TIMEOUT) || - (status & CMD_CRC)) { - if (host->cmd) { - if (status & CMD_TIMEOUT) { - omap_hsmmc_reset_controller_fsm(host, - SRC); - host->cmd->error = -ETIMEDOUT; - } else { - host->cmd->error = -EILSEQ; - } - end_cmd = 1; - } - if (host->data || host->response_busy) { - if (host->data) - omap_hsmmc_dma_cleanup(host, - -ETIMEDOUT); - host->response_busy = 0; - omap_hsmmc_reset_controller_fsm(host, SRD); - } - } - if ((status & DATA_TIMEOUT) || - (status & DATA_CRC)) { - if (host->data || host->response_busy) { - int err = (status & DATA_TIMEOUT) ? - -ETIMEDOUT : -EILSEQ; - - if (host->data) - omap_hsmmc_dma_cleanup(host, err); - else - host->mrq->cmd->error = err; - host->response_busy = 0; - omap_hsmmc_reset_controller_fsm(host, SRD); - end_trans = 1; - } - } - if (status & CARD_ERR) { - dev_dbg(mmc_dev(host->mmc), - "Ignoring card err CMD%d\n", host->cmd->opcode); - if (host->cmd) - end_cmd = 1; - if (host->data) - end_trans = 1; - } - } - - OMAP_HSMMC_WRITE(host->base, STAT, status); - - if (end_cmd || ((status & CC) && host->cmd)) - omap_hsmmc_cmd_done(host, host->cmd); - if ((end_trans || (status & TC)) && host->mrq) - omap_hsmmc_xfer_done(host, data); -} - -/* - * MMC controller IRQ handler - */ -static irqreturn_t omap_hsmmc_irq(int irq, void *dev_id) -{ - struct omap_hsmmc_host *host = dev_id; - int status; - - status = OMAP_HSMMC_READ(host->base, STAT); - do { - omap_hsmmc_do_irq(host, status); - /* Flush posted write */ - status = OMAP_HSMMC_READ(host->base, STAT); - } while (status & INT_EN_MASK); - - return IRQ_HANDLED; -} - -static void set_sd_bus_power(struct omap_hsmmc_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. - * - * MMC2 and MMC3 use fixed 1.8V levels, and maybe a transceiver. - * The MMC2 transceiver controls are used instead of DAT4..DAT7. - * Some chips, like eMMC ones, use internal transceivers. - */ -static int omap_hsmmc_switch_opcond(struct omap_hsmmc_host *host, int vdd) -{ - u32 reg_val = 0; - int ret; - - /* Disable the clocks */ - pm_runtime_put_sync(host->dev); - if (host->got_dbclk) - clk_disable(host->dbclk); - - /* Turn the power off */ - ret = mmc_slot(host).set_power(host->dev, host->slot_id, 0, 0); - - /* Turn the power ON with given VDD 1.8 or 3.0v */ - if (!ret) - ret = mmc_slot(host).set_power(host->dev, host->slot_id, 1, - vdd); - pm_runtime_get_sync(host->dev); - if (host->got_dbclk) - clk_enable(host->dbclk); - - if (ret != 0) - goto err; - - OMAP_HSMMC_WRITE(host->base, HCTL, - OMAP_HSMMC_READ(host->base, HCTL) & SDVSCLR); - reg_val = OMAP_HSMMC_READ(host->base, HCTL); - - /* - * If a MMC dual voltage card is detected, the set_ios fn calls - * this fn with VDD bit set for 1.8V. Upon card removal from the - * slot, omap_hsmmc_set_ios sets the VDD back to 3V on MMC_POWER_OFF. - * - * Cope with a bit of slop in the range ... per data sheets: - * - "1.8V" for vdds_mmc1/vdds_mmc1a can be up to 2.45V max, - * but recommended values are 1.71V to 1.89V - * - "3.0V" for vdds_mmc1/vdds_mmc1a can be up to 3.5V max, - * but recommended values are 2.7V to 3.3V - * - * Board setup code shouldn't permit anything very out-of-range. - * TWL4030-family VMMC1 and VSIM regulators are fine (avoiding the - * middle range) but VSIM can't power DAT4..DAT7 at more than 3V. - */ - if ((1 << vdd) <= MMC_VDD_23_24) - reg_val |= SDVS18; - else - reg_val |= SDVS30; - - OMAP_HSMMC_WRITE(host->base, HCTL, reg_val); - set_sd_bus_power(host); - - return 0; -err: - dev_dbg(mmc_dev(host->mmc), "Unable to switch operating voltage\n"); - return ret; -} - -/* Protect the card while the cover is open */ -static void omap_hsmmc_protect_card(struct omap_hsmmc_host *host) -{ - if (!mmc_slot(host).get_cover_state) - return; - - host->reqs_blocked = 0; - if (mmc_slot(host).get_cover_state(host->dev, host->slot_id)) { - if (host->protect_card) { - dev_info(host->dev, "%s: cover is closed, " - "card is now accessible\n", - mmc_hostname(host->mmc)); - host->protect_card = 0; - } - } else { - if (!host->protect_card) { - dev_info(host->dev, "%s: cover is open, " - "card is now inaccessible\n", - mmc_hostname(host->mmc)); - host->protect_card = 1; - } - } -} - -/* - * irq handler to notify the core about card insertion/removal - */ -static irqreturn_t omap_hsmmc_detect(int irq, void *dev_id) -{ - struct omap_hsmmc_host *host = dev_id; - struct omap_mmc_slot_data *slot = &mmc_slot(host); - int carddetect; - - if (host->suspended) - return IRQ_HANDLED; - - sysfs_notify(&host->mmc->class_dev.kobj, NULL, "cover_switch"); - - if (slot->card_detect) - carddetect = slot->card_detect(host->dev, host->slot_id); - else { - omap_hsmmc_protect_card(host); - carddetect = -ENOSYS; - } - - if (carddetect) - mmc_detect_change(host->mmc, (HZ * 200) / 1000); - else - mmc_detect_change(host->mmc, (HZ * 50) / 1000); - return IRQ_HANDLED; -} - -static int omap_hsmmc_get_dma_sync_dev(struct omap_hsmmc_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 omap_hsmmc_config_dma_params(struct omap_hsmmc_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, - omap_hsmmc_get_dma_sync_dev(host, data), - !(data->flags & MMC_DATA_WRITE)); - - omap_start_dma(dma_ch); -} - -/* - * DMA call back function - */ -static void omap_hsmmc_dma_cb(int lch, u16 ch_status, void *cb_data) -{ - struct omap_hsmmc_host *host = cb_data; - struct mmc_data *data; - int dma_ch, req_in_progress; - - if (!(ch_status & OMAP_DMA_BLOCK_IRQ)) { - dev_warn(mmc_dev(host->mmc), "unexpected dma status %x\n", - ch_status); - return; - } - - spin_lock(&host->irq_lock); - if (host->dma_ch < 0) { - spin_unlock(&host->irq_lock); - return; - } - - data = host->mrq->data; - host->dma_sg_idx++; - if (host->dma_sg_idx < host->dma_len) { - /* Fire up the next transfer. */ - omap_hsmmc_config_dma_params(host, data, - data->sg + host->dma_sg_idx); - spin_unlock(&host->irq_lock); - return; - } - - if (!data->host_cookie) - dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len, - omap_hsmmc_get_dma_dir(host, data)); - - req_in_progress = host->req_in_progress; - dma_ch = host->dma_ch; - host->dma_ch = -1; - spin_unlock(&host->irq_lock); - - omap_free_dma(dma_ch); - - /* If DMA has finished after TC, complete the request */ - if (!req_in_progress) { - struct mmc_request *mrq = host->mrq; - - host->mrq = NULL; - mmc_request_done(host->mmc, mrq); - } -} - -static int omap_hsmmc_pre_dma_transfer(struct omap_hsmmc_host *host, - struct mmc_data *data, - struct omap_hsmmc_next *next) -{ - int dma_len; - - if (!next && data->host_cookie && - data->host_cookie != host->next_data.cookie) { - dev_warn(host->dev, "[%s] invalid cookie: data->host_cookie %d" - " host->next_data.cookie %d\n", - __func__, data->host_cookie, host->next_data.cookie); - data->host_cookie = 0; - } - - /* Check if next job is already prepared */ - if (next || - (!next && data->host_cookie != host->next_data.cookie)) { - dma_len = dma_map_sg(mmc_dev(host->mmc), data->sg, - data->sg_len, - omap_hsmmc_get_dma_dir(host, data)); - - } else { - dma_len = host->next_data.dma_len; - host->next_data.dma_len = 0; - } - - - if (dma_len == 0) - return -EINVAL; - - if (next) { - next->dma_len = dma_len; - data->host_cookie = ++next->cookie < 0 ? 1 : next->cookie; - } else - host->dma_len = dma_len; - - return 0; -} - -/* - * Routine to configure and start DMA for the MMC card - */ -static int omap_hsmmc_start_dma_transfer(struct omap_hsmmc_host *host, - struct mmc_request *req) -{ - int dma_ch = 0, ret = 0, i; - struct mmc_data *data = req->data; - - /* Sanity check: all the SG entries must be aligned by block size. */ - for (i = 0; i < data->sg_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; - - BUG_ON(host->dma_ch != -1); - - ret = omap_request_dma(omap_hsmmc_get_dma_sync_dev(host, data), - "MMC/SD", omap_hsmmc_dma_cb, host, &dma_ch); - if (ret != 0) { - dev_err(mmc_dev(host->mmc), - "%s: omap_request_dma() failed with %d\n", - mmc_hostname(host->mmc), ret); - return ret; - } - ret = omap_hsmmc_pre_dma_transfer(host, data, NULL); - if (ret) - return ret; - - host->dma_ch = dma_ch; - host->dma_sg_idx = 0; - - omap_hsmmc_config_dma_params(host, data, data->sg); - - return 0; -} - -static void set_data_timeout(struct omap_hsmmc_host *host, - unsigned int timeout_ns, - unsigned int timeout_clks) -{ - unsigned int timeout, cycle_ns; - uint32_t reg, clkd, dto = 0; - - reg = OMAP_HSMMC_READ(host->base, SYSCTL); - clkd = (reg & CLKD_MASK) >> CLKD_SHIFT; - if (clkd == 0) - clkd = 1; - - cycle_ns = 1000000000 / (clk_get_rate(host->fclk) / clkd); - timeout = timeout_ns / cycle_ns; - timeout += timeout_clks; - if (timeout) { - while ((timeout & 0x80000000) == 0) { - dto += 1; - timeout <<= 1; - } - dto = 31 - dto; - timeout <<= 1; - if (timeout && dto) - dto += 1; - if (dto >= 13) - dto -= 13; - else - dto = 0; - if (dto > 14) - dto = 14; - } - - reg &= ~DTO_MASK; - reg |= dto << DTO_SHIFT; - OMAP_HSMMC_WRITE(host->base, SYSCTL, reg); -} - -/* - * Configure block length for MMC/SD cards and initiate the transfer. - */ -static int -omap_hsmmc_prepare_data(struct omap_hsmmc_host *host, struct mmc_request *req) -{ - int ret; - host->data = req->data; - - if (req->data == NULL) { - OMAP_HSMMC_WRITE(host->base, BLK, 0); - /* - * Set an arbitrary 100ms data timeout for commands with - * busy signal. - */ - if (req->cmd->flags & MMC_RSP_BUSY) - set_data_timeout(host, 100000000U, 0); - return 0; - } - - OMAP_HSMMC_WRITE(host->base, BLK, (req->data->blksz) - | (req->data->blocks << 16)); - set_data_timeout(host, req->data->timeout_ns, req->data->timeout_clks); - - if (host->use_dma) { - ret = omap_hsmmc_start_dma_transfer(host, req); - if (ret != 0) { - dev_dbg(mmc_dev(host->mmc), "MMC start dma failure\n"); - return ret; - } - } - return 0; -} - -static void omap_hsmmc_post_req(struct mmc_host *mmc, struct mmc_request *mrq, - int err) -{ - struct omap_hsmmc_host *host = mmc_priv(mmc); - struct mmc_data *data = mrq->data; - - if (host->use_dma) { - if (data->host_cookie) - dma_unmap_sg(mmc_dev(host->mmc), data->sg, - data->sg_len, - omap_hsmmc_get_dma_dir(host, data)); - data->host_cookie = 0; - } -} - -static void omap_hsmmc_pre_req(struct mmc_host *mmc, struct mmc_request *mrq, - bool is_first_req) -{ - struct omap_hsmmc_host *host = mmc_priv(mmc); - - if (mrq->data->host_cookie) { - mrq->data->host_cookie = 0; - return ; - } - - if (host->use_dma) - if (omap_hsmmc_pre_dma_transfer(host, mrq->data, - &host->next_data)) - mrq->data->host_cookie = 0; -} - -/* - * Request function. for read/write operation - */ -static void omap_hsmmc_request(struct mmc_host *mmc, struct mmc_request *req) -{ - struct omap_hsmmc_host *host = mmc_priv(mmc); - int err; - - BUG_ON(host->req_in_progress); - BUG_ON(host->dma_ch != -1); - if (host->protect_card) { - if (host->reqs_blocked < 3) { - /* - * Ensure the controller is left in a consistent - * state by resetting the command and data state - * machines. - */ - omap_hsmmc_reset_controller_fsm(host, SRD); - omap_hsmmc_reset_controller_fsm(host, SRC); - host->reqs_blocked += 1; - } - req->cmd->error = -EBADF; - if (req->data) - req->data->error = -EBADF; - req->cmd->retries = 0; - mmc_request_done(mmc, req); - return; - } else if (host->reqs_blocked) - host->reqs_blocked = 0; - WARN_ON(host->mrq != NULL); - host->mrq = req; - err = omap_hsmmc_prepare_data(host, req); - if (err) { - req->cmd->error = err; - if (req->data) - req->data->error = err; - host->mrq = NULL; - mmc_request_done(mmc, req); - return; - } - - omap_hsmmc_start_command(host, req->cmd, req->data); -} - -/* Routine to configure clock values. Exposed API to core */ -static void omap_hsmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) -{ - struct omap_hsmmc_host *host = mmc_priv(mmc); - int do_send_init_stream = 0; - - pm_runtime_get_sync(host->dev); - - if (ios->power_mode != host->power_mode) { - switch (ios->power_mode) { - case MMC_POWER_OFF: - mmc_slot(host).set_power(host->dev, host->slot_id, - 0, 0); - host->vdd = 0; - break; - case MMC_POWER_UP: - mmc_slot(host).set_power(host->dev, host->slot_id, - 1, ios->vdd); - host->vdd = ios->vdd; - break; - case MMC_POWER_ON: - do_send_init_stream = 1; - break; - } - host->power_mode = ios->power_mode; - } - - /* FIXME: set registers based only on changes to ios */ - - omap_hsmmc_set_bus_width(host); - - if (host->pdata->controller_flags & OMAP_HSMMC_SUPPORTS_DUAL_VOLT) { - /* Only MMC1 can interface at 3V without some flavor - * of external transceiver; but they all handle 1.8V. - */ - if ((OMAP_HSMMC_READ(host->base, HCTL) & SDVSDET) && - (ios->vdd == DUAL_VOLT_OCR_BIT) && - /* - * With pbias cell programming missing, this - * can't be allowed when booting with device - * tree. - */ - !host->dev->of_node) { - /* - * The mmc_select_voltage fn of the core does - * not seem to set the power_mode to - * MMC_POWER_UP upon recalculating the voltage. - * vdd 1.8v. - */ - if (omap_hsmmc_switch_opcond(host, ios->vdd) != 0) - dev_dbg(mmc_dev(host->mmc), - "Switch operation failed\n"); - } - } - - omap_hsmmc_set_clock(host); - - if (do_send_init_stream) - send_init_stream(host); - - omap_hsmmc_set_bus_mode(host); - - pm_runtime_put_autosuspend(host->dev); -} - -static int omap_hsmmc_get_cd(struct mmc_host *mmc) -{ - struct omap_hsmmc_host *host = mmc_priv(mmc); - - if (!mmc_slot(host).card_detect) - return -ENOSYS; - return mmc_slot(host).card_detect(host->dev, host->slot_id); -} - -static int omap_hsmmc_get_ro(struct mmc_host *mmc) -{ - struct omap_hsmmc_host *host = mmc_priv(mmc); - - if (!mmc_slot(host).get_ro) - return -ENOSYS; - return mmc_slot(host).get_ro(host->dev, 0); -} - -static void omap_hsmmc_init_card(struct mmc_host *mmc, struct mmc_card *card) -{ - struct omap_hsmmc_host *host = mmc_priv(mmc); - - if (mmc_slot(host).init_card) - mmc_slot(host).init_card(card); -} - -static void omap_hsmmc_conf_bus_power(struct omap_hsmmc_host *host) -{ - u32 hctl, capa, value; - - /* Only MMC1 supports 3.0V */ - if (host->pdata->controller_flags & OMAP_HSMMC_SUPPORTS_DUAL_VOLT) { - 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 int omap_hsmmc_enable_fclk(struct mmc_host *mmc) -{ - struct omap_hsmmc_host *host = mmc_priv(mmc); - - pm_runtime_get_sync(host->dev); - - return 0; -} - -static int omap_hsmmc_disable_fclk(struct mmc_host *mmc) -{ - struct omap_hsmmc_host *host = mmc_priv(mmc); - - pm_runtime_mark_last_busy(host->dev); - pm_runtime_put_autosuspend(host->dev); - - return 0; -} - -static const struct mmc_host_ops omap_hsmmc_ops = { - .enable = omap_hsmmc_enable_fclk, - .disable = omap_hsmmc_disable_fclk, - .post_req = omap_hsmmc_post_req, - .pre_req = omap_hsmmc_pre_req, - .request = omap_hsmmc_request, - .set_ios = omap_hsmmc_set_ios, - .get_cd = omap_hsmmc_get_cd, - .get_ro = omap_hsmmc_get_ro, - .init_card = omap_hsmmc_init_card, - /* NYET -- enable_sdio_irq */ -}; - -#ifdef CONFIG_DEBUG_FS - -static int omap_hsmmc_regs_show(struct seq_file *s, void *data) -{ - struct mmc_host *mmc = s->private; - struct omap_hsmmc_host *host = mmc_priv(mmc); - int context_loss = 0; - - if (host->pdata->get_context_loss_count) - context_loss = host->pdata->get_context_loss_count(host->dev); - - seq_printf(s, "mmc%d:\n ctx_loss:\t%d:%d\n\nregs:\n", - mmc->index, host->context_loss, context_loss); - - if (host->suspended) { - seq_printf(s, "host suspended, can't read registers\n"); - return 0; - } - - pm_runtime_get_sync(host->dev); - - seq_printf(s, "SYSCONFIG:\t0x%08x\n", - OMAP_HSMMC_READ(host->base, SYSCONFIG)); - seq_printf(s, "CON:\t\t0x%08x\n", - OMAP_HSMMC_READ(host->base, CON)); - seq_printf(s, "HCTL:\t\t0x%08x\n", - OMAP_HSMMC_READ(host->base, HCTL)); - seq_printf(s, "SYSCTL:\t\t0x%08x\n", - OMAP_HSMMC_READ(host->base, SYSCTL)); - seq_printf(s, "IE:\t\t0x%08x\n", - OMAP_HSMMC_READ(host->base, IE)); - seq_printf(s, "ISE:\t\t0x%08x\n", - OMAP_HSMMC_READ(host->base, ISE)); - seq_printf(s, "CAPA:\t\t0x%08x\n", - OMAP_HSMMC_READ(host->base, CAPA)); - - pm_runtime_mark_last_busy(host->dev); - pm_runtime_put_autosuspend(host->dev); - - return 0; -} - -static int omap_hsmmc_regs_open(struct inode *inode, struct file *file) -{ - return single_open(file, omap_hsmmc_regs_show, inode->i_private); -} - -static const struct file_operations mmc_regs_fops = { - .open = omap_hsmmc_regs_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static void omap_hsmmc_debugfs(struct mmc_host *mmc) -{ - if (mmc->debugfs_root) - debugfs_create_file("regs", S_IRUSR, mmc->debugfs_root, - mmc, &mmc_regs_fops); -} - -#else - -static void omap_hsmmc_debugfs(struct mmc_host *mmc) -{ -} - -#endif - -#ifdef CONFIG_OF -static u16 omap4_reg_offset = 0x100; - -static const struct of_device_id omap_mmc_of_match[] = { - { - .compatible = "ti,omap2-hsmmc", - }, - { - .compatible = "ti,omap3-hsmmc", - }, - { - .compatible = "ti,omap4-hsmmc", - .data = &omap4_reg_offset, - }, - {}, -}; -MODULE_DEVICE_TABLE(of, omap_mmc_of_match); - -static struct omap_mmc_platform_data *of_get_hsmmc_pdata(struct device *dev) -{ - struct omap_mmc_platform_data *pdata; - struct device_node *np = dev->of_node; - u32 bus_width; - - pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); - if (!pdata) - return NULL; /* out of memory */ - - if (of_find_property(np, "ti,dual-volt", NULL)) - pdata->controller_flags |= OMAP_HSMMC_SUPPORTS_DUAL_VOLT; - - /* This driver only supports 1 slot */ - pdata->nr_slots = 1; - pdata->slots[0].switch_pin = of_get_named_gpio(np, "cd-gpios", 0); - pdata->slots[0].gpio_wp = of_get_named_gpio(np, "wp-gpios", 0); - - if (of_find_property(np, "ti,non-removable", NULL)) { - pdata->slots[0].nonremovable = true; - pdata->slots[0].no_regulator_off_init = true; - } - of_property_read_u32(np, "ti,bus-width", &bus_width); - if (bus_width == 4) - pdata->slots[0].caps |= MMC_CAP_4_BIT_DATA; - else if (bus_width == 8) - pdata->slots[0].caps |= MMC_CAP_8_BIT_DATA; - - if (of_find_property(np, "ti,needs-special-reset", NULL)) - pdata->slots[0].features |= HSMMC_HAS_UPDATED_RESET; - - return pdata; -} -#else -static inline struct omap_mmc_platform_data - *of_get_hsmmc_pdata(struct device *dev) -{ - return NULL; -} -#endif - -static int __devinit omap_hsmmc_probe(struct platform_device *pdev) -{ - struct omap_mmc_platform_data *pdata = pdev->dev.platform_data; - struct mmc_host *mmc; - struct omap_hsmmc_host *host = NULL; - struct resource *res; - int ret, irq; - const struct of_device_id *match; - - match = of_match_device(of_match_ptr(omap_mmc_of_match), &pdev->dev); - if (match) { - pdata = of_get_hsmmc_pdata(&pdev->dev); - if (match->data) { - u16 *offsetp = match->data; - pdata->reg_offset = *offsetp; - } - } - - if (pdata == NULL) { - dev_err(&pdev->dev, "Platform Data is missing\n"); - return -ENXIO; - } - - if (pdata->nr_slots == 0) { - dev_err(&pdev->dev, "No Slots\n"); - return -ENXIO; - } - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - irq = platform_get_irq(pdev, 0); - if (res == NULL || irq < 0) - return -ENXIO; - - res = request_mem_region(res->start, resource_size(res), pdev->name); - if (res == NULL) - return -EBUSY; - - ret = omap_hsmmc_gpio_init(pdata); - if (ret) - goto err; - - mmc = mmc_alloc_host(sizeof(struct omap_hsmmc_host), &pdev->dev); - if (!mmc) { - ret = -ENOMEM; - goto err_alloc; - } - - host = mmc_priv(mmc); - host->mmc = mmc; - host->pdata = pdata; - host->dev = &pdev->dev; - host->use_dma = 1; - host->dev->dma_mask = &pdata->dma_mask; - host->dma_ch = -1; - host->irq = irq; - host->slot_id = 0; - host->mapbase = res->start + pdata->reg_offset; - host->base = ioremap(host->mapbase, SZ_4K); - host->power_mode = MMC_POWER_OFF; - host->next_data.cookie = 1; - - platform_set_drvdata(pdev, host); - - mmc->ops = &omap_hsmmc_ops; - - /* - * If regulator_disable can only put vcc_aux to sleep then there is - * no off state. - */ - if (mmc_slot(host).vcc_aux_disable_is_sleep) - mmc_slot(host).no_off = 1; - - mmc->f_min = OMAP_MMC_MIN_CLOCK; - - if (pdata->max_freq > 0) - mmc->f_max = pdata->max_freq; - else - mmc->f_max = OMAP_MMC_MAX_CLOCK; - - spin_lock_init(&host->irq_lock); - - host->fclk = clk_get(&pdev->dev, "fck"); - if (IS_ERR(host->fclk)) { - ret = PTR_ERR(host->fclk); - host->fclk = NULL; - goto err1; - } - - if (host->pdata->controller_flags & OMAP_HSMMC_BROKEN_MULTIBLOCK_READ) { - dev_info(&pdev->dev, "multiblock reads disabled due to 35xx erratum 2.1.1.128; MMC read performance may suffer\n"); - mmc->caps2 |= MMC_CAP2_NO_MULTI_READ; - } - - pm_runtime_enable(host->dev); - pm_runtime_get_sync(host->dev); - pm_runtime_set_autosuspend_delay(host->dev, MMC_AUTOSUSPEND_DELAY); - pm_runtime_use_autosuspend(host->dev); - - omap_hsmmc_context_save(host); - - if (cpu_is_omap2430()) { - host->dbclk = clk_get(&pdev->dev, "mmchsdb_fck"); - /* - * MMC can still work without debounce clock. - */ - if (IS_ERR(host->dbclk)) - dev_warn(mmc_dev(host->mmc), - "Failed to get debounce clock\n"); - else - host->got_dbclk = 1; - - if (host->got_dbclk) - if (clk_enable(host->dbclk) != 0) - dev_dbg(mmc_dev(host->mmc), "Enabling debounce" - " clk failed\n"); - } - - /* Since we do only SG emulation, we can have as many segs - * as we want. */ - mmc->max_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; - mmc->max_seg_size = mmc->max_req_size; - - mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED | - MMC_CAP_WAIT_WHILE_BUSY | MMC_CAP_ERASE; - - mmc->caps |= mmc_slot(host).caps; - if (mmc->caps & MMC_CAP_8_BIT_DATA) - mmc->caps |= MMC_CAP_4_BIT_DATA; - - if (mmc_slot(host).nonremovable) - mmc->caps |= MMC_CAP_NONREMOVABLE; - - mmc->pm_caps = mmc_slot(host).pm_caps; - - omap_hsmmc_conf_bus_power(host); - - res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx"); - if (!res) { - dev_err(mmc_dev(host->mmc), "cannot get DMA TX channel\n"); - goto err_irq; - } - host->dma_line_tx = res->start; - - res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "rx"); - if (!res) { - dev_err(mmc_dev(host->mmc), "cannot get DMA RX channel\n"); - goto err_irq; - } - host->dma_line_rx = res->start; - - /* Request IRQ for MMC operations */ - ret = request_irq(host->irq, omap_hsmmc_irq, 0, - mmc_hostname(mmc), host); - if (ret) { - dev_dbg(mmc_dev(host->mmc), "Unable to grab HSMMC IRQ\n"); - goto err_irq; - } - - if (pdata->init != NULL) { - if (pdata->init(&pdev->dev) != 0) { - dev_dbg(mmc_dev(host->mmc), - "Unable to configure MMC IRQs\n"); - goto err_irq_cd_init; - } - } - - if (omap_hsmmc_have_reg() && !mmc_slot(host).set_power) { - ret = omap_hsmmc_reg_get(host); - if (ret) - goto err_reg; - host->use_reg = 1; - } - - mmc->ocr_avail = mmc_slot(host).ocr_mask; - - /* Request IRQ for card detect */ - if ((mmc_slot(host).card_detect_irq)) { - ret = request_threaded_irq(mmc_slot(host).card_detect_irq, - NULL, - omap_hsmmc_detect, - IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, - mmc_hostname(mmc), host); - if (ret) { - dev_dbg(mmc_dev(host->mmc), - "Unable to grab MMC CD IRQ\n"); - goto err_irq_cd; - } - pdata->suspend = omap_hsmmc_suspend_cdirq; - pdata->resume = omap_hsmmc_resume_cdirq; - } - - omap_hsmmc_disable_irq(host); - - omap_hsmmc_protect_card(host); - - mmc_add_host(mmc); - - if (mmc_slot(host).name != NULL) { - ret = device_create_file(&mmc->class_dev, &dev_attr_slot_name); - if (ret < 0) - goto err_slot_name; - } - if (mmc_slot(host).card_detect_irq && mmc_slot(host).get_cover_state) { - ret = device_create_file(&mmc->class_dev, - &dev_attr_cover_switch); - if (ret < 0) - goto err_slot_name; - } - - omap_hsmmc_debugfs(mmc); - pm_runtime_mark_last_busy(host->dev); - pm_runtime_put_autosuspend(host->dev); - - return 0; - -err_slot_name: - mmc_remove_host(mmc); - free_irq(mmc_slot(host).card_detect_irq, host); -err_irq_cd: - if (host->use_reg) - omap_hsmmc_reg_put(host); -err_reg: - if (host->pdata->cleanup) - host->pdata->cleanup(&pdev->dev); -err_irq_cd_init: - free_irq(host->irq, host); -err_irq: - pm_runtime_put_sync(host->dev); - pm_runtime_disable(host->dev); - clk_put(host->fclk); - if (host->got_dbclk) { - clk_disable(host->dbclk); - clk_put(host->dbclk); - } -err1: - iounmap(host->base); - platform_set_drvdata(pdev, NULL); - mmc_free_host(mmc); -err_alloc: - omap_hsmmc_gpio_free(pdata); -err: - release_mem_region(res->start, resource_size(res)); - return ret; -} - -static int __devexit omap_hsmmc_remove(struct platform_device *pdev) -{ - struct omap_hsmmc_host *host = platform_get_drvdata(pdev); - struct resource *res; - - pm_runtime_get_sync(host->dev); - mmc_remove_host(host->mmc); - if (host->use_reg) - omap_hsmmc_reg_put(host); - if (host->pdata->cleanup) - host->pdata->cleanup(&pdev->dev); - free_irq(host->irq, host); - if (mmc_slot(host).card_detect_irq) - free_irq(mmc_slot(host).card_detect_irq, host); - - pm_runtime_put_sync(host->dev); - pm_runtime_disable(host->dev); - clk_put(host->fclk); - if (host->got_dbclk) { - clk_disable(host->dbclk); - clk_put(host->dbclk); - } - - mmc_free_host(host->mmc); - iounmap(host->base); - omap_hsmmc_gpio_free(pdev->dev.platform_data); - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (res) - release_mem_region(res->start, resource_size(res)); - platform_set_drvdata(pdev, NULL); - - return 0; -} - -#ifdef CONFIG_PM -static int omap_hsmmc_suspend(struct device *dev) -{ - int ret = 0; - struct omap_hsmmc_host *host = dev_get_drvdata(dev); - - if (!host) - return 0; - - if (host && host->suspended) - return 0; - - pm_runtime_get_sync(host->dev); - host->suspended = 1; - if (host->pdata->suspend) { - ret = host->pdata->suspend(dev, host->slot_id); - if (ret) { - dev_dbg(dev, "Unable to handle MMC board" - " level suspend\n"); - host->suspended = 0; - return ret; - } - } - ret = mmc_suspend_host(host->mmc); - - if (ret) { - host->suspended = 0; - if (host->pdata->resume) { - ret = host->pdata->resume(dev, host->slot_id); - if (ret) - dev_dbg(dev, "Unmask interrupt failed\n"); - } - goto err; - } - - if (!(host->mmc->pm_flags & MMC_PM_KEEP_POWER)) { - omap_hsmmc_disable_irq(host); - OMAP_HSMMC_WRITE(host->base, HCTL, - OMAP_HSMMC_READ(host->base, HCTL) & ~SDBP); - } - - if (host->got_dbclk) - clk_disable(host->dbclk); -err: - pm_runtime_put_sync(host->dev); - return ret; -} - -/* Routine to resume the MMC device */ -static int omap_hsmmc_resume(struct device *dev) -{ - int ret = 0; - struct omap_hsmmc_host *host = dev_get_drvdata(dev); - - if (!host) - return 0; - - if (host && !host->suspended) - return 0; - - pm_runtime_get_sync(host->dev); - - if (host->got_dbclk) - clk_enable(host->dbclk); - - if (!(host->mmc->pm_flags & MMC_PM_KEEP_POWER)) - omap_hsmmc_conf_bus_power(host); - - if (host->pdata->resume) { - ret = host->pdata->resume(dev, host->slot_id); - if (ret) - dev_dbg(dev, "Unmask interrupt failed\n"); - } - - omap_hsmmc_protect_card(host); - - /* Notify the core to resume the host */ - ret = mmc_resume_host(host->mmc); - if (ret == 0) - host->suspended = 0; - - pm_runtime_mark_last_busy(host->dev); - pm_runtime_put_autosuspend(host->dev); - - return ret; - -} - -#else -#define omap_hsmmc_suspend NULL -#define omap_hsmmc_resume NULL -#endif - -static int omap_hsmmc_runtime_suspend(struct device *dev) -{ - struct omap_hsmmc_host *host; - - host = platform_get_drvdata(to_platform_device(dev)); - omap_hsmmc_context_save(host); - dev_dbg(dev, "disabled\n"); - - return 0; -} - -static int omap_hsmmc_runtime_resume(struct device *dev) -{ - struct omap_hsmmc_host *host; - - host = platform_get_drvdata(to_platform_device(dev)); - omap_hsmmc_context_restore(host); - dev_dbg(dev, "enabled\n"); - - return 0; -} - -static struct dev_pm_ops omap_hsmmc_dev_pm_ops = { - .suspend = omap_hsmmc_suspend, - .resume = omap_hsmmc_resume, - .runtime_suspend = omap_hsmmc_runtime_suspend, - .runtime_resume = omap_hsmmc_runtime_resume, -}; - -static struct platform_driver omap_hsmmc_driver = { - .probe = omap_hsmmc_probe, - .remove = __devexit_p(omap_hsmmc_remove), - .driver = { - .name = DRIVER_NAME, - .owner = THIS_MODULE, - .pm = &omap_hsmmc_dev_pm_ops, - .of_match_table = of_match_ptr(omap_mmc_of_match), - }, -}; - -module_platform_driver(omap_hsmmc_driver); -MODULE_DESCRIPTION("OMAP High Speed Multimedia Card driver"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:" DRIVER_NAME); -MODULE_AUTHOR("Texas Instruments Inc"); diff --git a/ANDROID_3.4.5/drivers/mmc/host/pxamci.c b/ANDROID_3.4.5/drivers/mmc/host/pxamci.c deleted file mode 100644 index cb2dc0e7..00000000 --- a/ANDROID_3.4.5/drivers/mmc/host/pxamci.c +++ /dev/null @@ -1,879 +0,0 @@ -/* - * linux/drivers/mmc/host/pxa.c - PXA MMCI driver - * - * Copyright (C) 2003 Russell King, All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This hardware is really sick: - * - No way to clear interrupts. - * - Have to turn off the clock whenever we touch the device. - * - Doesn't tell you how many data blocks were transferred. - * Yuck! - * - * 1 and 3 byte data transfers not supported - * max block length up to 1023 - */ -#include <linux/module.h> -#include <linux/init.h> -#include <linux/ioport.h> -#include <linux/platform_device.h> -#include <linux/delay.h> -#include <linux/interrupt.h> -#include <linux/dma-mapping.h> -#include <linux/clk.h> -#include <linux/err.h> -#include <linux/mmc/host.h> -#include <linux/io.h> -#include <linux/regulator/consumer.h> -#include <linux/gpio.h> -#include <linux/gfp.h> - -#include <asm/sizes.h> - -#include <mach/hardware.h> -#include <mach/dma.h> -#include <mach/mmc.h> - -#include "pxamci.h" - -#define DRIVER_NAME "pxa2xx-mci" - -#define NR_SG 1 -#define CLKRT_OFF (~0) - -#define mmc_has_26MHz() (cpu_is_pxa300() || cpu_is_pxa310() \ - || cpu_is_pxa935()) - -struct pxamci_host { - struct mmc_host *mmc; - spinlock_t lock; - struct resource *res; - void __iomem *base; - struct clk *clk; - unsigned long clkrate; - int irq; - int dma; - unsigned int clkrt; - unsigned int cmdat; - unsigned int imask; - unsigned int power_mode; - struct pxamci_platform_data *pdata; - - struct mmc_request *mrq; - struct mmc_command *cmd; - struct mmc_data *data; - - dma_addr_t sg_dma; - struct pxa_dma_desc *sg_cpu; - unsigned int dma_len; - - unsigned int dma_dir; - unsigned int dma_drcmrrx; - unsigned int dma_drcmrtx; - - struct regulator *vcc; -}; - -static inline void pxamci_init_ocr(struct pxamci_host *host) -{ -#ifdef CONFIG_REGULATOR - host->vcc = regulator_get(mmc_dev(host->mmc), "vmmc"); - - if (IS_ERR(host->vcc)) - host->vcc = NULL; - else { - host->mmc->ocr_avail = mmc_regulator_get_ocrmask(host->vcc); - if (host->pdata && host->pdata->ocr_mask) - dev_warn(mmc_dev(host->mmc), - "ocr_mask/setpower will not be used\n"); - } -#endif - if (host->vcc == NULL) { - /* fall-back to platform data */ - host->mmc->ocr_avail = host->pdata ? - host->pdata->ocr_mask : - MMC_VDD_32_33 | MMC_VDD_33_34; - } -} - -static inline int pxamci_set_power(struct pxamci_host *host, - unsigned char power_mode, - unsigned int vdd) -{ - int on; - - if (host->vcc) { - int ret; - - if (power_mode == MMC_POWER_UP) { - ret = mmc_regulator_set_ocr(host->mmc, host->vcc, vdd); - if (ret) - return ret; - } else if (power_mode == MMC_POWER_OFF) { - ret = mmc_regulator_set_ocr(host->mmc, host->vcc, 0); - if (ret) - return ret; - } - } - if (!host->vcc && host->pdata && - gpio_is_valid(host->pdata->gpio_power)) { - on = ((1 << vdd) & host->pdata->ocr_mask); - gpio_set_value(host->pdata->gpio_power, - !!on ^ host->pdata->gpio_power_invert); - } - if (!host->vcc && host->pdata && host->pdata->setpower) - host->pdata->setpower(mmc_dev(host->mmc), vdd); - - return 0; -} - -static void pxamci_stop_clock(struct pxamci_host *host) -{ - if (readl(host->base + MMC_STAT) & STAT_CLK_EN) { - unsigned long timeout = 10000; - unsigned int v; - - writel(STOP_CLOCK, host->base + MMC_STRPCL); - - do { - v = readl(host->base + MMC_STAT); - if (!(v & STAT_CLK_EN)) - break; - udelay(1); - } while (timeout--); - - if (v & STAT_CLK_EN) - dev_err(mmc_dev(host->mmc), "unable to stop clock\n"); - } -} - -static void pxamci_enable_irq(struct pxamci_host *host, unsigned int mask) -{ - unsigned long flags; - - spin_lock_irqsave(&host->lock, flags); - host->imask &= ~mask; - writel(host->imask, host->base + MMC_I_MASK); - spin_unlock_irqrestore(&host->lock, flags); -} - -static void pxamci_disable_irq(struct pxamci_host *host, unsigned int mask) -{ - unsigned long flags; - - spin_lock_irqsave(&host->lock, flags); - host->imask |= mask; - writel(host->imask, host->base + MMC_I_MASK); - spin_unlock_irqrestore(&host->lock, flags); -} - -static void pxamci_setup_data(struct pxamci_host *host, struct mmc_data *data) -{ - unsigned int nob = data->blocks; - unsigned long long clks; - unsigned int timeout; - bool dalgn = 0; - u32 dcmd; - int i; - - host->data = data; - - if (data->flags & MMC_DATA_STREAM) - nob = 0xffff; - - writel(nob, host->base + MMC_NOB); - writel(data->blksz, host->base + MMC_BLKLEN); - - clks = (unsigned long long)data->timeout_ns * host->clkrate; - do_div(clks, 1000000000UL); - timeout = (unsigned int)clks + (data->timeout_clks << host->clkrt); - writel((timeout + 255) / 256, host->base + MMC_RDTO); - - if (data->flags & MMC_DATA_READ) { - host->dma_dir = DMA_FROM_DEVICE; - dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC; - DRCMR(host->dma_drcmrtx) = 0; - DRCMR(host->dma_drcmrrx) = host->dma | DRCMR_MAPVLD; - } else { - host->dma_dir = DMA_TO_DEVICE; - dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG; - DRCMR(host->dma_drcmrrx) = 0; - DRCMR(host->dma_drcmrtx) = host->dma | DRCMR_MAPVLD; - } - - dcmd |= DCMD_BURST32 | DCMD_WIDTH1; - - host->dma_len = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len, - host->dma_dir); - - for (i = 0; i < host->dma_len; i++) { - unsigned int length = sg_dma_len(&data->sg[i]); - host->sg_cpu[i].dcmd = dcmd | length; - if (length & 31 && !(data->flags & MMC_DATA_READ)) - host->sg_cpu[i].dcmd |= DCMD_ENDIRQEN; - /* Not aligned to 8-byte boundary? */ - if (sg_dma_address(&data->sg[i]) & 0x7) - dalgn = 1; - if (data->flags & MMC_DATA_READ) { - host->sg_cpu[i].dsadr = host->res->start + MMC_RXFIFO; - host->sg_cpu[i].dtadr = sg_dma_address(&data->sg[i]); - } else { - host->sg_cpu[i].dsadr = sg_dma_address(&data->sg[i]); - host->sg_cpu[i].dtadr = host->res->start + MMC_TXFIFO; - } - host->sg_cpu[i].ddadr = host->sg_dma + (i + 1) * - sizeof(struct pxa_dma_desc); - } - host->sg_cpu[host->dma_len - 1].ddadr = DDADR_STOP; - wmb(); - - /* - * The PXA27x DMA controller encounters overhead when working with - * unaligned (to 8-byte boundaries) data, so switch on byte alignment - * mode only if we have unaligned data. - */ - if (dalgn) - DALGN |= (1 << host->dma); - else - DALGN &= ~(1 << host->dma); - DDADR(host->dma) = host->sg_dma; - - /* - * workaround for erratum #91: - * only start DMA now if we are doing a read, - * otherwise we wait until CMD/RESP has finished - * before starting DMA. - */ - if (!cpu_is_pxa27x() || data->flags & MMC_DATA_READ) - DCSR(host->dma) = DCSR_RUN; -} - -static void pxamci_start_cmd(struct pxamci_host *host, struct mmc_command *cmd, unsigned int cmdat) -{ - WARN_ON(host->cmd != NULL); - host->cmd = cmd; - - if (cmd->flags & MMC_RSP_BUSY) - cmdat |= CMDAT_BUSY; - -#define RSP_TYPE(x) ((x) & ~(MMC_RSP_BUSY|MMC_RSP_OPCODE)) - switch (RSP_TYPE(mmc_resp_type(cmd))) { - case RSP_TYPE(MMC_RSP_R1): /* r1, r1b, r6, r7 */ - cmdat |= CMDAT_RESP_SHORT; - break; - case RSP_TYPE(MMC_RSP_R3): - cmdat |= CMDAT_RESP_R3; - break; - case RSP_TYPE(MMC_RSP_R2): - cmdat |= CMDAT_RESP_R2; - break; - default: - break; - } - - writel(cmd->opcode, host->base + MMC_CMD); - writel(cmd->arg >> 16, host->base + MMC_ARGH); - writel(cmd->arg & 0xffff, host->base + MMC_ARGL); - writel(cmdat, host->base + MMC_CMDAT); - writel(host->clkrt, host->base + MMC_CLKRT); - - writel(START_CLOCK, host->base + MMC_STRPCL); - - pxamci_enable_irq(host, END_CMD_RES); -} - -static void pxamci_finish_request(struct pxamci_host *host, struct mmc_request *mrq) -{ - host->mrq = NULL; - host->cmd = NULL; - host->data = NULL; - mmc_request_done(host->mmc, mrq); -} - -static int pxamci_cmd_done(struct pxamci_host *host, unsigned int stat) -{ - struct mmc_command *cmd = host->cmd; - int i; - u32 v; - - if (!cmd) - return 0; - - host->cmd = NULL; - - /* - * Did I mention this is Sick. We always need to - * discard the upper 8 bits of the first 16-bit word. - */ - v = readl(host->base + MMC_RES) & 0xffff; - for (i = 0; i < 4; i++) { - u32 w1 = readl(host->base + MMC_RES) & 0xffff; - u32 w2 = readl(host->base + MMC_RES) & 0xffff; - cmd->resp[i] = v << 24 | w1 << 8 | w2 >> 8; - v = w2; - } - - if (stat & STAT_TIME_OUT_RESPONSE) { - cmd->error = -ETIMEDOUT; - } else if (stat & STAT_RES_CRC_ERR && cmd->flags & MMC_RSP_CRC) { - /* - * workaround for erratum #42: - * Intel PXA27x Family Processor Specification Update Rev 001 - * A bogus CRC error can appear if the msb of a 136 bit - * response is a one. - */ - if (cpu_is_pxa27x() && - (cmd->flags & MMC_RSP_136 && cmd->resp[0] & 0x80000000)) - pr_debug("ignoring CRC from command %d - *risky*\n", cmd->opcode); - else - cmd->error = -EILSEQ; - } - - pxamci_disable_irq(host, END_CMD_RES); - if (host->data && !cmd->error) { - pxamci_enable_irq(host, DATA_TRAN_DONE); - /* - * workaround for erratum #91, if doing write - * enable DMA late - */ - if (cpu_is_pxa27x() && host->data->flags & MMC_DATA_WRITE) - DCSR(host->dma) = DCSR_RUN; - } else { - pxamci_finish_request(host, host->mrq); - } - - return 1; -} - -static int pxamci_data_done(struct pxamci_host *host, unsigned int stat) -{ - struct mmc_data *data = host->data; - - if (!data) - return 0; - - DCSR(host->dma) = 0; - dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len, - host->dma_dir); - - if (stat & STAT_READ_TIME_OUT) - data->error = -ETIMEDOUT; - else if (stat & (STAT_CRC_READ_ERROR|STAT_CRC_WRITE_ERROR)) - data->error = -EILSEQ; - - /* - * There appears to be a hardware design bug here. There seems to - * be no way to find out how much data was transferred to the card. - * This means that if there was an error on any block, we mark all - * data blocks as being in error. - */ - if (!data->error) - data->bytes_xfered = data->blocks * data->blksz; - else - data->bytes_xfered = 0; - - pxamci_disable_irq(host, DATA_TRAN_DONE); - - host->data = NULL; - if (host->mrq->stop) { - pxamci_stop_clock(host); - pxamci_start_cmd(host, host->mrq->stop, host->cmdat); - } else { - pxamci_finish_request(host, host->mrq); - } - - return 1; -} - -static irqreturn_t pxamci_irq(int irq, void *devid) -{ - struct pxamci_host *host = devid; - unsigned int ireg; - int handled = 0; - - ireg = readl(host->base + MMC_I_REG) & ~readl(host->base + MMC_I_MASK); - - if (ireg) { - unsigned stat = readl(host->base + MMC_STAT); - - pr_debug("PXAMCI: irq %08x stat %08x\n", ireg, stat); - - if (ireg & END_CMD_RES) - handled |= pxamci_cmd_done(host, stat); - if (ireg & DATA_TRAN_DONE) - handled |= pxamci_data_done(host, stat); - if (ireg & SDIO_INT) { - mmc_signal_sdio_irq(host->mmc); - handled = 1; - } - } - - return IRQ_RETVAL(handled); -} - -static void pxamci_request(struct mmc_host *mmc, struct mmc_request *mrq) -{ - struct pxamci_host *host = mmc_priv(mmc); - unsigned int cmdat; - - WARN_ON(host->mrq != NULL); - - host->mrq = mrq; - - pxamci_stop_clock(host); - - cmdat = host->cmdat; - host->cmdat &= ~CMDAT_INIT; - - if (mrq->data) { - pxamci_setup_data(host, mrq->data); - - cmdat &= ~CMDAT_BUSY; - cmdat |= CMDAT_DATAEN | CMDAT_DMAEN; - if (mrq->data->flags & MMC_DATA_WRITE) - cmdat |= CMDAT_WRITE; - - if (mrq->data->flags & MMC_DATA_STREAM) - cmdat |= CMDAT_STREAM; - } - - pxamci_start_cmd(host, mrq->cmd, cmdat); -} - -static int pxamci_get_ro(struct mmc_host *mmc) -{ - struct pxamci_host *host = mmc_priv(mmc); - - if (host->pdata && gpio_is_valid(host->pdata->gpio_card_ro)) { - if (host->pdata->gpio_card_ro_invert) - return !gpio_get_value(host->pdata->gpio_card_ro); - else - return gpio_get_value(host->pdata->gpio_card_ro); - } - if (host->pdata && host->pdata->get_ro) - return !!host->pdata->get_ro(mmc_dev(mmc)); - /* - * Board doesn't support read only detection; let the mmc core - * decide what to do. - */ - return -ENOSYS; -} - -static void pxamci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) -{ - struct pxamci_host *host = mmc_priv(mmc); - - if (ios->clock) { - unsigned long rate = host->clkrate; - unsigned int clk = rate / ios->clock; - - if (host->clkrt == CLKRT_OFF) - clk_enable(host->clk); - - if (ios->clock == 26000000) { - /* to support 26MHz */ - host->clkrt = 7; - } else { - /* to handle (19.5MHz, 26MHz) */ - if (!clk) - clk = 1; - - /* - * clk might result in a lower divisor than we - * desire. check for that condition and adjust - * as appropriate. - */ - if (rate / clk > ios->clock) - clk <<= 1; - host->clkrt = fls(clk) - 1; - } - - /* - * we write clkrt on the next command - */ - } else { - pxamci_stop_clock(host); - if (host->clkrt != CLKRT_OFF) { - host->clkrt = CLKRT_OFF; - clk_disable(host->clk); - } - } - - if (host->power_mode != ios->power_mode) { - int ret; - - host->power_mode = ios->power_mode; - - ret = pxamci_set_power(host, ios->power_mode, ios->vdd); - if (ret) { - dev_err(mmc_dev(mmc), "unable to set power\n"); - /* - * The .set_ios() function in the mmc_host_ops - * struct return void, and failing to set the - * power should be rare so we print an error and - * return here. - */ - return; - } - - if (ios->power_mode == MMC_POWER_ON) - host->cmdat |= CMDAT_INIT; - } - - if (ios->bus_width == MMC_BUS_WIDTH_4) - host->cmdat |= CMDAT_SD_4DAT; - else - host->cmdat &= ~CMDAT_SD_4DAT; - - dev_dbg(mmc_dev(mmc), "PXAMCI: clkrt = %x cmdat = %x\n", - host->clkrt, host->cmdat); -} - -static void pxamci_enable_sdio_irq(struct mmc_host *host, int enable) -{ - struct pxamci_host *pxa_host = mmc_priv(host); - - if (enable) - pxamci_enable_irq(pxa_host, SDIO_INT); - else - pxamci_disable_irq(pxa_host, SDIO_INT); -} - -static const struct mmc_host_ops pxamci_ops = { - .request = pxamci_request, - .get_ro = pxamci_get_ro, - .set_ios = pxamci_set_ios, - .enable_sdio_irq = pxamci_enable_sdio_irq, -}; - -static void pxamci_dma_irq(int dma, void *devid) -{ - struct pxamci_host *host = devid; - int dcsr = DCSR(dma); - DCSR(dma) = dcsr & ~DCSR_STOPIRQEN; - - if (dcsr & DCSR_ENDINTR) { - writel(BUF_PART_FULL, host->base + MMC_PRTBUF); - } else { - pr_err("%s: DMA error on channel %d (DCSR=%#x)\n", - mmc_hostname(host->mmc), dma, dcsr); - host->data->error = -EIO; - pxamci_data_done(host, 0); - } -} - -static irqreturn_t pxamci_detect_irq(int irq, void *devid) -{ - struct pxamci_host *host = mmc_priv(devid); - - mmc_detect_change(devid, msecs_to_jiffies(host->pdata->detect_delay_ms)); - return IRQ_HANDLED; -} - -static int pxamci_probe(struct platform_device *pdev) -{ - struct mmc_host *mmc; - struct pxamci_host *host = NULL; - struct resource *r, *dmarx, *dmatx; - int ret, irq, gpio_cd = -1, gpio_ro = -1, gpio_power = -1; - - r = platform_get_resource(pdev, IORESOURCE_MEM, 0); - irq = platform_get_irq(pdev, 0); - if (!r || irq < 0) - return -ENXIO; - - r = request_mem_region(r->start, SZ_4K, DRIVER_NAME); - if (!r) - return -EBUSY; - - mmc = mmc_alloc_host(sizeof(struct pxamci_host), &pdev->dev); - if (!mmc) { - ret = -ENOMEM; - goto out; - } - - mmc->ops = &pxamci_ops; - - /* - * We can do SG-DMA, but we don't because we never know how much - * data we successfully wrote to the card. - */ - mmc->max_segs = NR_SG; - - /* - * Our hardware DMA can handle a maximum of one page per SG entry. - */ - mmc->max_seg_size = PAGE_SIZE; - - /* - * Block length register is only 10 bits before PXA27x. - */ - mmc->max_blk_size = cpu_is_pxa25x() ? 1023 : 2048; - - /* - * Block count register is 16 bits. - */ - mmc->max_blk_count = 65535; - - host = mmc_priv(mmc); - host->mmc = mmc; - host->dma = -1; - host->pdata = pdev->dev.platform_data; - host->clkrt = CLKRT_OFF; - - host->clk = clk_get(&pdev->dev, NULL); - if (IS_ERR(host->clk)) { - ret = PTR_ERR(host->clk); - host->clk = NULL; - goto out; - } - - host->clkrate = clk_get_rate(host->clk); - - /* - * Calculate minimum clock rate, rounding up. - */ - mmc->f_min = (host->clkrate + 63) / 64; - mmc->f_max = (mmc_has_26MHz()) ? 26000000 : host->clkrate; - - pxamci_init_ocr(host); - - mmc->caps = 0; - host->cmdat = 0; - if (!cpu_is_pxa25x()) { - mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ; - host->cmdat |= CMDAT_SDIO_INT_EN; - if (mmc_has_26MHz()) - mmc->caps |= MMC_CAP_MMC_HIGHSPEED | - MMC_CAP_SD_HIGHSPEED; - } - - host->sg_cpu = dma_alloc_coherent(&pdev->dev, PAGE_SIZE, &host->sg_dma, GFP_KERNEL); - if (!host->sg_cpu) { - ret = -ENOMEM; - goto out; - } - - spin_lock_init(&host->lock); - host->res = r; - host->irq = irq; - host->imask = MMC_I_MASK_ALL; - - host->base = ioremap(r->start, SZ_4K); - if (!host->base) { - ret = -ENOMEM; - goto out; - } - - /* - * Ensure that the host controller is shut down, and setup - * with our defaults. - */ - pxamci_stop_clock(host); - writel(0, host->base + MMC_SPI); - writel(64, host->base + MMC_RESTO); - writel(host->imask, host->base + MMC_I_MASK); - - host->dma = pxa_request_dma(DRIVER_NAME, DMA_PRIO_LOW, - pxamci_dma_irq, host); - if (host->dma < 0) { - ret = -EBUSY; - goto out; - } - - ret = request_irq(host->irq, pxamci_irq, 0, DRIVER_NAME, host); - if (ret) - goto out; - - platform_set_drvdata(pdev, mmc); - - dmarx = platform_get_resource(pdev, IORESOURCE_DMA, 0); - if (!dmarx) { - ret = -ENXIO; - goto out; - } - host->dma_drcmrrx = dmarx->start; - - dmatx = platform_get_resource(pdev, IORESOURCE_DMA, 1); - if (!dmatx) { - ret = -ENXIO; - goto out; - } - host->dma_drcmrtx = dmatx->start; - - if (host->pdata) { - gpio_cd = host->pdata->gpio_card_detect; - gpio_ro = host->pdata->gpio_card_ro; - gpio_power = host->pdata->gpio_power; - } - if (gpio_is_valid(gpio_power)) { - ret = gpio_request(gpio_power, "mmc card power"); - if (ret) { - dev_err(&pdev->dev, "Failed requesting gpio_power %d\n", gpio_power); - goto out; - } - gpio_direction_output(gpio_power, - host->pdata->gpio_power_invert); - } - if (gpio_is_valid(gpio_ro)) { - ret = gpio_request(gpio_ro, "mmc card read only"); - if (ret) { - dev_err(&pdev->dev, "Failed requesting gpio_ro %d\n", gpio_ro); - goto err_gpio_ro; - } - gpio_direction_input(gpio_ro); - } - if (gpio_is_valid(gpio_cd)) { - ret = gpio_request(gpio_cd, "mmc card detect"); - if (ret) { - dev_err(&pdev->dev, "Failed requesting gpio_cd %d\n", gpio_cd); - goto err_gpio_cd; - } - gpio_direction_input(gpio_cd); - - ret = request_irq(gpio_to_irq(gpio_cd), pxamci_detect_irq, - IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, - "mmc card detect", mmc); - if (ret) { - dev_err(&pdev->dev, "failed to request card detect IRQ\n"); - goto err_request_irq; - } - } - - if (host->pdata && host->pdata->init) - host->pdata->init(&pdev->dev, pxamci_detect_irq, mmc); - - if (gpio_is_valid(gpio_power) && host->pdata->setpower) - dev_warn(&pdev->dev, "gpio_power and setpower() both defined\n"); - if (gpio_is_valid(gpio_ro) && host->pdata->get_ro) - dev_warn(&pdev->dev, "gpio_ro and get_ro() both defined\n"); - - mmc_add_host(mmc); - - return 0; - -err_request_irq: - gpio_free(gpio_cd); -err_gpio_cd: - gpio_free(gpio_ro); -err_gpio_ro: - gpio_free(gpio_power); - out: - if (host) { - if (host->dma >= 0) - pxa_free_dma(host->dma); - if (host->base) - iounmap(host->base); - if (host->sg_cpu) - dma_free_coherent(&pdev->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma); - if (host->clk) - clk_put(host->clk); - } - if (mmc) - mmc_free_host(mmc); - release_resource(r); - return ret; -} - -static int pxamci_remove(struct platform_device *pdev) -{ - struct mmc_host *mmc = platform_get_drvdata(pdev); - int gpio_cd = -1, gpio_ro = -1, gpio_power = -1; - - platform_set_drvdata(pdev, NULL); - - if (mmc) { - struct pxamci_host *host = mmc_priv(mmc); - - mmc_remove_host(mmc); - - if (host->pdata) { - gpio_cd = host->pdata->gpio_card_detect; - gpio_ro = host->pdata->gpio_card_ro; - gpio_power = host->pdata->gpio_power; - } - if (gpio_is_valid(gpio_cd)) { - free_irq(gpio_to_irq(gpio_cd), mmc); - gpio_free(gpio_cd); - } - if (gpio_is_valid(gpio_ro)) - gpio_free(gpio_ro); - if (gpio_is_valid(gpio_power)) - gpio_free(gpio_power); - if (host->vcc) - regulator_put(host->vcc); - - if (host->pdata && host->pdata->exit) - host->pdata->exit(&pdev->dev, mmc); - - pxamci_stop_clock(host); - writel(TXFIFO_WR_REQ|RXFIFO_RD_REQ|CLK_IS_OFF|STOP_CMD| - END_CMD_RES|PRG_DONE|DATA_TRAN_DONE, - host->base + MMC_I_MASK); - - DRCMR(host->dma_drcmrrx) = 0; - DRCMR(host->dma_drcmrtx) = 0; - - free_irq(host->irq, host); - pxa_free_dma(host->dma); - iounmap(host->base); - dma_free_coherent(&pdev->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma); - - clk_put(host->clk); - - release_resource(host->res); - - mmc_free_host(mmc); - } - return 0; -} - -#ifdef CONFIG_PM -static int pxamci_suspend(struct device *dev) -{ - struct mmc_host *mmc = dev_get_drvdata(dev); - int ret = 0; - - if (mmc) - ret = mmc_suspend_host(mmc); - - return ret; -} - -static int pxamci_resume(struct device *dev) -{ - struct mmc_host *mmc = dev_get_drvdata(dev); - int ret = 0; - - if (mmc) - ret = mmc_resume_host(mmc); - - return ret; -} - -static const struct dev_pm_ops pxamci_pm_ops = { - .suspend = pxamci_suspend, - .resume = pxamci_resume, -}; -#endif - -static struct platform_driver pxamci_driver = { - .probe = pxamci_probe, - .remove = pxamci_remove, - .driver = { - .name = DRIVER_NAME, - .owner = THIS_MODULE, -#ifdef CONFIG_PM - .pm = &pxamci_pm_ops, -#endif - }, -}; - -module_platform_driver(pxamci_driver); - -MODULE_DESCRIPTION("PXA Multimedia Card Interface Driver"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:pxa2xx-mci"); diff --git a/ANDROID_3.4.5/drivers/mmc/host/pxamci.h b/ANDROID_3.4.5/drivers/mmc/host/pxamci.h deleted file mode 100644 index f6c2e2fc..00000000 --- a/ANDROID_3.4.5/drivers/mmc/host/pxamci.h +++ /dev/null @@ -1,90 +0,0 @@ -#define MMC_STRPCL 0x0000 -#define STOP_CLOCK (1 << 0) -#define START_CLOCK (2 << 0) - -#define MMC_STAT 0x0004 -#define STAT_END_CMD_RES (1 << 13) -#define STAT_PRG_DONE (1 << 12) -#define STAT_DATA_TRAN_DONE (1 << 11) -#define STAT_CLK_EN (1 << 8) -#define STAT_RECV_FIFO_FULL (1 << 7) -#define STAT_XMIT_FIFO_EMPTY (1 << 6) -#define STAT_RES_CRC_ERR (1 << 5) -#define STAT_SPI_READ_ERROR_TOKEN (1 << 4) -#define STAT_CRC_READ_ERROR (1 << 3) -#define STAT_CRC_WRITE_ERROR (1 << 2) -#define STAT_TIME_OUT_RESPONSE (1 << 1) -#define STAT_READ_TIME_OUT (1 << 0) - -#define MMC_CLKRT 0x0008 /* 3 bit */ - -#define MMC_SPI 0x000c -#define SPI_CS_ADDRESS (1 << 3) -#define SPI_CS_EN (1 << 2) -#define CRC_ON (1 << 1) -#define SPI_EN (1 << 0) - -#define MMC_CMDAT 0x0010 -#define CMDAT_SDIO_INT_EN (1 << 11) -#define CMDAT_SD_4DAT (1 << 8) -#define CMDAT_DMAEN (1 << 7) -#define CMDAT_INIT (1 << 6) -#define CMDAT_BUSY (1 << 5) -#define CMDAT_STREAM (1 << 4) /* 1 = stream */ -#define CMDAT_WRITE (1 << 3) /* 1 = write */ -#define CMDAT_DATAEN (1 << 2) -#define CMDAT_RESP_NONE (0 << 0) -#define CMDAT_RESP_SHORT (1 << 0) -#define CMDAT_RESP_R2 (2 << 0) -#define CMDAT_RESP_R3 (3 << 0) - -#define MMC_RESTO 0x0014 /* 7 bit */ - -#define MMC_RDTO 0x0018 /* 16 bit */ - -#define MMC_BLKLEN 0x001c /* 10 bit */ - -#define MMC_NOB 0x0020 /* 16 bit */ - -#define MMC_PRTBUF 0x0024 -#define BUF_PART_FULL (1 << 0) - -#define MMC_I_MASK 0x0028 - -/*PXA27x MMC interrupts*/ -#define SDIO_SUSPEND_ACK (1 << 12) -#define SDIO_INT (1 << 11) -#define RD_STALLED (1 << 10) -#define RES_ERR (1 << 9) -#define DAT_ERR (1 << 8) -#define TINT (1 << 7) - -/*PXA2xx MMC interrupts*/ -#define TXFIFO_WR_REQ (1 << 6) -#define RXFIFO_RD_REQ (1 << 5) -#define CLK_IS_OFF (1 << 4) -#define STOP_CMD (1 << 3) -#define END_CMD_RES (1 << 2) -#define PRG_DONE (1 << 1) -#define DATA_TRAN_DONE (1 << 0) - -#if defined(CONFIG_PXA27x) || defined(CONFIG_PXA3xx) -#define MMC_I_MASK_ALL 0x00001fff -#else -#define MMC_I_MASK_ALL 0x0000007f -#endif - -#define MMC_I_REG 0x002c -/* same as MMC_I_MASK */ - -#define MMC_CMD 0x0030 - -#define MMC_ARGH 0x0034 /* 16 bit */ - -#define MMC_ARGL 0x0038 /* 16 bit */ - -#define MMC_RES 0x003c /* 16 bit */ - -#define MMC_RXFIFO 0x0040 /* 8 bit */ - -#define MMC_TXFIFO 0x0044 /* 8 bit */ diff --git a/ANDROID_3.4.5/drivers/mmc/host/s3cmci.c b/ANDROID_3.4.5/drivers/mmc/host/s3cmci.c deleted file mode 100644 index c3622a69..00000000 --- a/ANDROID_3.4.5/drivers/mmc/host/s3cmci.c +++ /dev/null @@ -1,1921 +0,0 @@ -/* - * linux/drivers/mmc/s3cmci.h - Samsung S3C MCI driver - * - * Copyright (C) 2004-2006 maintech GmbH, Thomas Kleffel <tk@maintech.de> - * - * Current driver maintained by Ben Dooks and Simtec Electronics - * Copyright (C) 2008 Simtec Electronics <ben-linux@fluff.org> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include <linux/module.h> -#include <linux/dma-mapping.h> -#include <linux/clk.h> -#include <linux/mmc/host.h> -#include <linux/platform_device.h> -#include <linux/cpufreq.h> -#include <linux/debugfs.h> -#include <linux/seq_file.h> -#include <linux/gpio.h> -#include <linux/irq.h> -#include <linux/io.h> - -#include <mach/dma.h> - -#include <mach/regs-sdi.h> -#include <mach/regs-gpio.h> - -#include <plat/mci.h> - -#include "s3cmci.h" - -#define DRIVER_NAME "s3c-mci" - -enum dbg_channels { - dbg_err = (1 << 0), - dbg_debug = (1 << 1), - dbg_info = (1 << 2), - dbg_irq = (1 << 3), - dbg_sg = (1 << 4), - dbg_dma = (1 << 5), - dbg_pio = (1 << 6), - dbg_fail = (1 << 7), - dbg_conf = (1 << 8), -}; - -static const int dbgmap_err = dbg_fail; -static const int dbgmap_info = dbg_info | dbg_conf; -static const int dbgmap_debug = dbg_err | dbg_debug; - -#define dbg(host, channels, args...) \ - do { \ - if (dbgmap_err & channels) \ - dev_err(&host->pdev->dev, args); \ - else if (dbgmap_info & channels) \ - dev_info(&host->pdev->dev, args); \ - else if (dbgmap_debug & channels) \ - dev_dbg(&host->pdev->dev, args); \ - } while (0) - -static struct s3c2410_dma_client s3cmci_dma_client = { - .name = "s3c-mci", -}; - -static void finalize_request(struct s3cmci_host *host); -static void s3cmci_send_request(struct mmc_host *mmc); -static void s3cmci_reset(struct s3cmci_host *host); - -#ifdef CONFIG_MMC_DEBUG - -static void dbg_dumpregs(struct s3cmci_host *host, char *prefix) -{ - u32 con, pre, cmdarg, cmdcon, cmdsta, r0, r1, r2, r3, timer, bsize; - u32 datcon, datcnt, datsta, fsta, imask; - - con = readl(host->base + S3C2410_SDICON); - pre = readl(host->base + S3C2410_SDIPRE); - cmdarg = readl(host->base + S3C2410_SDICMDARG); - cmdcon = readl(host->base + S3C2410_SDICMDCON); - cmdsta = readl(host->base + S3C2410_SDICMDSTAT); - r0 = readl(host->base + S3C2410_SDIRSP0); - r1 = readl(host->base + S3C2410_SDIRSP1); - r2 = readl(host->base + S3C2410_SDIRSP2); - r3 = readl(host->base + S3C2410_SDIRSP3); - timer = readl(host->base + S3C2410_SDITIMER); - bsize = readl(host->base + S3C2410_SDIBSIZE); - datcon = readl(host->base + S3C2410_SDIDCON); - datcnt = readl(host->base + S3C2410_SDIDCNT); - datsta = readl(host->base + S3C2410_SDIDSTA); - fsta = readl(host->base + S3C2410_SDIFSTA); - imask = readl(host->base + host->sdiimsk); - - dbg(host, dbg_debug, "%s CON:[%08x] PRE:[%08x] TMR:[%08x]\n", - prefix, con, pre, timer); - - dbg(host, dbg_debug, "%s CCON:[%08x] CARG:[%08x] CSTA:[%08x]\n", - prefix, cmdcon, cmdarg, cmdsta); - - dbg(host, dbg_debug, "%s DCON:[%08x] FSTA:[%08x]" - " DSTA:[%08x] DCNT:[%08x]\n", - prefix, datcon, fsta, datsta, datcnt); - - dbg(host, dbg_debug, "%s R0:[%08x] R1:[%08x]" - " R2:[%08x] R3:[%08x]\n", - prefix, r0, r1, r2, r3); -} - -static void prepare_dbgmsg(struct s3cmci_host *host, struct mmc_command *cmd, - int stop) -{ - snprintf(host->dbgmsg_cmd, 300, - "#%u%s op:%i arg:0x%08x flags:0x08%x retries:%u", - host->ccnt, (stop ? " (STOP)" : ""), - cmd->opcode, cmd->arg, cmd->flags, cmd->retries); - - if (cmd->data) { - snprintf(host->dbgmsg_dat, 300, - "#%u bsize:%u blocks:%u bytes:%u", - host->dcnt, cmd->data->blksz, - cmd->data->blocks, - cmd->data->blocks * cmd->data->blksz); - } else { - host->dbgmsg_dat[0] = '\0'; - } -} - -static void dbg_dumpcmd(struct s3cmci_host *host, struct mmc_command *cmd, - int fail) -{ - unsigned int dbglvl = fail ? dbg_fail : dbg_debug; - - if (!cmd) - return; - - if (cmd->error == 0) { - dbg(host, dbglvl, "CMD[OK] %s R0:0x%08x\n", - host->dbgmsg_cmd, cmd->resp[0]); - } else { - dbg(host, dbglvl, "CMD[ERR %i] %s Status:%s\n", - cmd->error, host->dbgmsg_cmd, host->status); - } - - if (!cmd->data) - return; - - if (cmd->data->error == 0) { - dbg(host, dbglvl, "DAT[OK] %s\n", host->dbgmsg_dat); - } else { - dbg(host, dbglvl, "DAT[ERR %i] %s DCNT:0x%08x\n", - cmd->data->error, host->dbgmsg_dat, - readl(host->base + S3C2410_SDIDCNT)); - } -} -#else -static void dbg_dumpcmd(struct s3cmci_host *host, - struct mmc_command *cmd, int fail) { } - -static void prepare_dbgmsg(struct s3cmci_host *host, struct mmc_command *cmd, - int stop) { } - -static void dbg_dumpregs(struct s3cmci_host *host, char *prefix) { } - -#endif /* CONFIG_MMC_DEBUG */ - -/** - * s3cmci_host_usedma - return whether the host is using dma or pio - * @host: The host state - * - * Return true if the host is using DMA to transfer data, else false - * to use PIO mode. Will return static data depending on the driver - * configuration. - */ -static inline bool s3cmci_host_usedma(struct s3cmci_host *host) -{ -#ifdef CONFIG_MMC_S3C_PIO - return false; -#elif defined(CONFIG_MMC_S3C_DMA) - return true; -#else - return host->dodma; -#endif -} - -/** - * s3cmci_host_canpio - return true if host has pio code available - * - * Return true if the driver has been compiled with the PIO support code - * available. - */ -static inline bool s3cmci_host_canpio(void) -{ -#ifdef CONFIG_MMC_S3C_PIO - return true; -#else - return false; -#endif -} - -static inline u32 enable_imask(struct s3cmci_host *host, u32 imask) -{ - u32 newmask; - - newmask = readl(host->base + host->sdiimsk); - newmask |= imask; - - writel(newmask, host->base + host->sdiimsk); - - return newmask; -} - -static inline u32 disable_imask(struct s3cmci_host *host, u32 imask) -{ - u32 newmask; - - newmask = readl(host->base + host->sdiimsk); - newmask &= ~imask; - - writel(newmask, host->base + host->sdiimsk); - - return newmask; -} - -static inline void clear_imask(struct s3cmci_host *host) -{ - u32 mask = readl(host->base + host->sdiimsk); - - /* preserve the SDIO IRQ mask state */ - mask &= S3C2410_SDIIMSK_SDIOIRQ; - writel(mask, host->base + host->sdiimsk); -} - -/** - * s3cmci_check_sdio_irq - test whether the SDIO IRQ is being signalled - * @host: The host to check. - * - * Test to see if the SDIO interrupt is being signalled in case the - * controller has failed to re-detect a card interrupt. Read GPE8 and - * see if it is low and if so, signal a SDIO interrupt. - * - * This is currently called if a request is finished (we assume that the - * bus is now idle) and when the SDIO IRQ is enabled in case the IRQ is - * already being indicated. -*/ -static void s3cmci_check_sdio_irq(struct s3cmci_host *host) -{ - if (host->sdio_irqen) { - if (gpio_get_value(S3C2410_GPE(8)) == 0) { - pr_debug("%s: signalling irq\n", __func__); - mmc_signal_sdio_irq(host->mmc); - } - } -} - -static inline int get_data_buffer(struct s3cmci_host *host, - u32 *bytes, u32 **pointer) -{ - struct scatterlist *sg; - - if (host->pio_active == XFER_NONE) - return -EINVAL; - - if ((!host->mrq) || (!host->mrq->data)) - return -EINVAL; - - if (host->pio_sgptr >= host->mrq->data->sg_len) { - dbg(host, dbg_debug, "no more buffers (%i/%i)\n", - host->pio_sgptr, host->mrq->data->sg_len); - return -EBUSY; - } - sg = &host->mrq->data->sg[host->pio_sgptr]; - - *bytes = sg->length; - *pointer = sg_virt(sg); - - host->pio_sgptr++; - - dbg(host, dbg_sg, "new buffer (%i/%i)\n", - host->pio_sgptr, host->mrq->data->sg_len); - - return 0; -} - -static inline u32 fifo_count(struct s3cmci_host *host) -{ - u32 fifostat = readl(host->base + S3C2410_SDIFSTA); - - fifostat &= S3C2410_SDIFSTA_COUNTMASK; - return fifostat; -} - -static inline u32 fifo_free(struct s3cmci_host *host) -{ - u32 fifostat = readl(host->base + S3C2410_SDIFSTA); - - fifostat &= S3C2410_SDIFSTA_COUNTMASK; - return 63 - fifostat; -} - -/** - * s3cmci_enable_irq - enable IRQ, after having disabled it. - * @host: The device state. - * @more: True if more IRQs are expected from transfer. - * - * Enable the main IRQ if needed after it has been disabled. - * - * The IRQ can be one of the following states: - * - disabled during IDLE - * - disabled whilst processing data - * - enabled during transfer - * - enabled whilst awaiting SDIO interrupt detection - */ -static void s3cmci_enable_irq(struct s3cmci_host *host, bool more) -{ - unsigned long flags; - bool enable = false; - - local_irq_save(flags); - - host->irq_enabled = more; - host->irq_disabled = false; - - enable = more | host->sdio_irqen; - - if (host->irq_state != enable) { - host->irq_state = enable; - - if (enable) - enable_irq(host->irq); - else - disable_irq(host->irq); - } - - local_irq_restore(flags); -} - -/** - * - */ -static void s3cmci_disable_irq(struct s3cmci_host *host, bool transfer) -{ - unsigned long flags; - - local_irq_save(flags); - - /* pr_debug("%s: transfer %d\n", __func__, transfer); */ - - host->irq_disabled = transfer; - - if (transfer && host->irq_state) { - host->irq_state = false; - disable_irq(host->irq); - } - - local_irq_restore(flags); -} - -static void do_pio_read(struct s3cmci_host *host) -{ - int res; - u32 fifo; - u32 *ptr; - u32 fifo_words; - void __iomem *from_ptr; - - /* write real prescaler to host, it might be set slow to fix */ - writel(host->prescaler, host->base + S3C2410_SDIPRE); - - from_ptr = host->base + host->sdidata; - - while ((fifo = fifo_count(host))) { - if (!host->pio_bytes) { - res = get_data_buffer(host, &host->pio_bytes, - &host->pio_ptr); - if (res) { - host->pio_active = XFER_NONE; - host->complete_what = COMPLETION_FINALIZE; - - dbg(host, dbg_pio, "pio_read(): " - "complete (no more data).\n"); - return; - } - - dbg(host, dbg_pio, - "pio_read(): new target: [%i]@[%p]\n", - host->pio_bytes, host->pio_ptr); - } - - dbg(host, dbg_pio, - "pio_read(): fifo:[%02i] buffer:[%03i] dcnt:[%08X]\n", - fifo, host->pio_bytes, - readl(host->base + S3C2410_SDIDCNT)); - - /* If we have reached the end of the block, we can - * read a word and get 1 to 3 bytes. If we in the - * middle of the block, we have to read full words, - * otherwise we will write garbage, so round down to - * an even multiple of 4. */ - if (fifo >= host->pio_bytes) - fifo = host->pio_bytes; - else - fifo -= fifo & 3; - - host->pio_bytes -= fifo; - host->pio_count += fifo; - - fifo_words = fifo >> 2; - ptr = host->pio_ptr; - while (fifo_words--) - *ptr++ = readl(from_ptr); - host->pio_ptr = ptr; - - if (fifo & 3) { - u32 n = fifo & 3; - u32 data = readl(from_ptr); - u8 *p = (u8 *)host->pio_ptr; - - while (n--) { - *p++ = data; - data >>= 8; - } - } - } - - if (!host->pio_bytes) { - res = get_data_buffer(host, &host->pio_bytes, &host->pio_ptr); - if (res) { - dbg(host, dbg_pio, - "pio_read(): complete (no more buffers).\n"); - host->pio_active = XFER_NONE; - host->complete_what = COMPLETION_FINALIZE; - - return; - } - } - - enable_imask(host, - S3C2410_SDIIMSK_RXFIFOHALF | S3C2410_SDIIMSK_RXFIFOLAST); -} - -static void do_pio_write(struct s3cmci_host *host) -{ - void __iomem *to_ptr; - int res; - u32 fifo; - u32 *ptr; - - to_ptr = host->base + host->sdidata; - - while ((fifo = fifo_free(host)) > 3) { - if (!host->pio_bytes) { - res = get_data_buffer(host, &host->pio_bytes, - &host->pio_ptr); - if (res) { - dbg(host, dbg_pio, - "pio_write(): complete (no more data).\n"); - host->pio_active = XFER_NONE; - - return; - } - - dbg(host, dbg_pio, - "pio_write(): new source: [%i]@[%p]\n", - host->pio_bytes, host->pio_ptr); - - } - - /* If we have reached the end of the block, we have to - * write exactly the remaining number of bytes. If we - * in the middle of the block, we have to write full - * words, so round down to an even multiple of 4. */ - if (fifo >= host->pio_bytes) - fifo = host->pio_bytes; - else - fifo -= fifo & 3; - - host->pio_bytes -= fifo; - host->pio_count += fifo; - - fifo = (fifo + 3) >> 2; - ptr = host->pio_ptr; - while (fifo--) - writel(*ptr++, to_ptr); - host->pio_ptr = ptr; - } - - enable_imask(host, S3C2410_SDIIMSK_TXFIFOHALF); -} - -static void pio_tasklet(unsigned long data) -{ - struct s3cmci_host *host = (struct s3cmci_host *) data; - - s3cmci_disable_irq(host, true); - - if (host->pio_active == XFER_WRITE) - do_pio_write(host); - - if (host->pio_active == XFER_READ) - do_pio_read(host); - - if (host->complete_what == COMPLETION_FINALIZE) { - clear_imask(host); - if (host->pio_active != XFER_NONE) { - dbg(host, dbg_err, "unfinished %s " - "- pio_count:[%u] pio_bytes:[%u]\n", - (host->pio_active == XFER_READ) ? "read" : "write", - host->pio_count, host->pio_bytes); - - if (host->mrq->data) - host->mrq->data->error = -EINVAL; - } - - s3cmci_enable_irq(host, false); - finalize_request(host); - } else - s3cmci_enable_irq(host, true); -} - -/* - * ISR for SDI Interface IRQ - * Communication between driver and ISR works as follows: - * host->mrq points to current request - * host->complete_what Indicates when the request is considered done - * COMPLETION_CMDSENT when the command was sent - * COMPLETION_RSPFIN when a response was received - * COMPLETION_XFERFINISH when the data transfer is finished - * COMPLETION_XFERFINISH_RSPFIN both of the above. - * host->complete_request is the completion-object the driver waits for - * - * 1) Driver sets up host->mrq and host->complete_what - * 2) Driver prepares the transfer - * 3) Driver enables interrupts - * 4) Driver starts transfer - * 5) Driver waits for host->complete_rquest - * 6) ISR checks for request status (errors and success) - * 6) ISR sets host->mrq->cmd->error and host->mrq->data->error - * 7) ISR completes host->complete_request - * 8) ISR disables interrupts - * 9) Driver wakes up and takes care of the request - * - * Note: "->error"-fields are expected to be set to 0 before the request - * was issued by mmc.c - therefore they are only set, when an error - * contition comes up - */ - -static irqreturn_t s3cmci_irq(int irq, void *dev_id) -{ - struct s3cmci_host *host = dev_id; - struct mmc_command *cmd; - u32 mci_csta, mci_dsta, mci_fsta, mci_dcnt, mci_imsk; - u32 mci_cclear = 0, mci_dclear; - unsigned long iflags; - - mci_dsta = readl(host->base + S3C2410_SDIDSTA); - mci_imsk = readl(host->base + host->sdiimsk); - - if (mci_dsta & S3C2410_SDIDSTA_SDIOIRQDETECT) { - if (mci_imsk & S3C2410_SDIIMSK_SDIOIRQ) { - mci_dclear = S3C2410_SDIDSTA_SDIOIRQDETECT; - writel(mci_dclear, host->base + S3C2410_SDIDSTA); - - mmc_signal_sdio_irq(host->mmc); - return IRQ_HANDLED; - } - } - - spin_lock_irqsave(&host->complete_lock, iflags); - - mci_csta = readl(host->base + S3C2410_SDICMDSTAT); - mci_dcnt = readl(host->base + S3C2410_SDIDCNT); - mci_fsta = readl(host->base + S3C2410_SDIFSTA); - mci_dclear = 0; - - if ((host->complete_what == COMPLETION_NONE) || - (host->complete_what == COMPLETION_FINALIZE)) { - host->status = "nothing to complete"; - clear_imask(host); - goto irq_out; - } - - if (!host->mrq) { - host->status = "no active mrq"; - clear_imask(host); - goto irq_out; - } - - cmd = host->cmd_is_stop ? host->mrq->stop : host->mrq->cmd; - - if (!cmd) { - host->status = "no active cmd"; - clear_imask(host); - goto irq_out; - } - - if (!s3cmci_host_usedma(host)) { - if ((host->pio_active == XFER_WRITE) && - (mci_fsta & S3C2410_SDIFSTA_TFDET)) { - - disable_imask(host, S3C2410_SDIIMSK_TXFIFOHALF); - tasklet_schedule(&host->pio_tasklet); - host->status = "pio tx"; - } - - if ((host->pio_active == XFER_READ) && - (mci_fsta & S3C2410_SDIFSTA_RFDET)) { - - disable_imask(host, - S3C2410_SDIIMSK_RXFIFOHALF | - S3C2410_SDIIMSK_RXFIFOLAST); - - tasklet_schedule(&host->pio_tasklet); - host->status = "pio rx"; - } - } - - if (mci_csta & S3C2410_SDICMDSTAT_CMDTIMEOUT) { - dbg(host, dbg_err, "CMDSTAT: error CMDTIMEOUT\n"); - cmd->error = -ETIMEDOUT; - host->status = "error: command timeout"; - goto fail_transfer; - } - - if (mci_csta & S3C2410_SDICMDSTAT_CMDSENT) { - if (host->complete_what == COMPLETION_CMDSENT) { - host->status = "ok: command sent"; - goto close_transfer; - } - - mci_cclear |= S3C2410_SDICMDSTAT_CMDSENT; - } - - if (mci_csta & S3C2410_SDICMDSTAT_CRCFAIL) { - if (cmd->flags & MMC_RSP_CRC) { - if (host->mrq->cmd->flags & MMC_RSP_136) { - dbg(host, dbg_irq, - "fixup: ignore CRC fail with long rsp\n"); - } else { - /* note, we used to fail the transfer - * here, but it seems that this is just - * the hardware getting it wrong. - * - * cmd->error = -EILSEQ; - * host->status = "error: bad command crc"; - * goto fail_transfer; - */ - } - } - - mci_cclear |= S3C2410_SDICMDSTAT_CRCFAIL; - } - - if (mci_csta & S3C2410_SDICMDSTAT_RSPFIN) { - if (host->complete_what == COMPLETION_RSPFIN) { - host->status = "ok: command response received"; - goto close_transfer; - } - - if (host->complete_what == COMPLETION_XFERFINISH_RSPFIN) - host->complete_what = COMPLETION_XFERFINISH; - - mci_cclear |= S3C2410_SDICMDSTAT_RSPFIN; - } - - /* errors handled after this point are only relevant - when a data transfer is in progress */ - - if (!cmd->data) - goto clear_status_bits; - - /* Check for FIFO failure */ - if (host->is2440) { - if (mci_fsta & S3C2440_SDIFSTA_FIFOFAIL) { - dbg(host, dbg_err, "FIFO failure\n"); - host->mrq->data->error = -EILSEQ; - host->status = "error: 2440 fifo failure"; - goto fail_transfer; - } - } else { - if (mci_dsta & S3C2410_SDIDSTA_FIFOFAIL) { - dbg(host, dbg_err, "FIFO failure\n"); - cmd->data->error = -EILSEQ; - host->status = "error: fifo failure"; - goto fail_transfer; - } - } - - if (mci_dsta & S3C2410_SDIDSTA_RXCRCFAIL) { - dbg(host, dbg_err, "bad data crc (outgoing)\n"); - cmd->data->error = -EILSEQ; - host->status = "error: bad data crc (outgoing)"; - goto fail_transfer; - } - - if (mci_dsta & S3C2410_SDIDSTA_CRCFAIL) { - dbg(host, dbg_err, "bad data crc (incoming)\n"); - cmd->data->error = -EILSEQ; - host->status = "error: bad data crc (incoming)"; - goto fail_transfer; - } - - if (mci_dsta & S3C2410_SDIDSTA_DATATIMEOUT) { - dbg(host, dbg_err, "data timeout\n"); - cmd->data->error = -ETIMEDOUT; - host->status = "error: data timeout"; - goto fail_transfer; - } - - if (mci_dsta & S3C2410_SDIDSTA_XFERFINISH) { - if (host->complete_what == COMPLETION_XFERFINISH) { - host->status = "ok: data transfer completed"; - goto close_transfer; - } - - if (host->complete_what == COMPLETION_XFERFINISH_RSPFIN) - host->complete_what = COMPLETION_RSPFIN; - - mci_dclear |= S3C2410_SDIDSTA_XFERFINISH; - } - -clear_status_bits: - writel(mci_cclear, host->base + S3C2410_SDICMDSTAT); - writel(mci_dclear, host->base + S3C2410_SDIDSTA); - - goto irq_out; - -fail_transfer: - host->pio_active = XFER_NONE; - -close_transfer: - host->complete_what = COMPLETION_FINALIZE; - - clear_imask(host); - tasklet_schedule(&host->pio_tasklet); - - goto irq_out; - -irq_out: - dbg(host, dbg_irq, - "csta:0x%08x dsta:0x%08x fsta:0x%08x dcnt:0x%08x status:%s.\n", - mci_csta, mci_dsta, mci_fsta, mci_dcnt, host->status); - - spin_unlock_irqrestore(&host->complete_lock, iflags); - return IRQ_HANDLED; - -} - -/* - * ISR for the CardDetect Pin -*/ - -static irqreturn_t s3cmci_irq_cd(int irq, void *dev_id) -{ - struct s3cmci_host *host = (struct s3cmci_host *)dev_id; - - dbg(host, dbg_irq, "card detect\n"); - - mmc_detect_change(host->mmc, msecs_to_jiffies(500)); - - return IRQ_HANDLED; -} - -static void s3cmci_dma_done_callback(struct s3c2410_dma_chan *dma_ch, - void *buf_id, int size, - enum s3c2410_dma_buffresult result) -{ - struct s3cmci_host *host = buf_id; - unsigned long iflags; - u32 mci_csta, mci_dsta, mci_fsta, mci_dcnt; - - mci_csta = readl(host->base + S3C2410_SDICMDSTAT); - mci_dsta = readl(host->base + S3C2410_SDIDSTA); - mci_fsta = readl(host->base + S3C2410_SDIFSTA); - mci_dcnt = readl(host->base + S3C2410_SDIDCNT); - - BUG_ON(!host->mrq); - BUG_ON(!host->mrq->data); - BUG_ON(!host->dmatogo); - - spin_lock_irqsave(&host->complete_lock, iflags); - - if (result != S3C2410_RES_OK) { - dbg(host, dbg_fail, "DMA FAILED: csta=0x%08x dsta=0x%08x " - "fsta=0x%08x dcnt:0x%08x result:0x%08x toGo:%u\n", - mci_csta, mci_dsta, mci_fsta, - mci_dcnt, result, host->dmatogo); - - goto fail_request; - } - - host->dmatogo--; - if (host->dmatogo) { - dbg(host, dbg_dma, "DMA DONE Size:%i DSTA:[%08x] " - "DCNT:[%08x] toGo:%u\n", - size, mci_dsta, mci_dcnt, host->dmatogo); - - goto out; - } - - dbg(host, dbg_dma, "DMA FINISHED Size:%i DSTA:%08x DCNT:%08x\n", - size, mci_dsta, mci_dcnt); - - host->dma_complete = 1; - host->complete_what = COMPLETION_FINALIZE; - -out: - tasklet_schedule(&host->pio_tasklet); - spin_unlock_irqrestore(&host->complete_lock, iflags); - return; - -fail_request: - host->mrq->data->error = -EINVAL; - host->complete_what = COMPLETION_FINALIZE; - clear_imask(host); - - goto out; -} - -static void finalize_request(struct s3cmci_host *host) -{ - struct mmc_request *mrq = host->mrq; - struct mmc_command *cmd; - int debug_as_failure = 0; - - if (host->complete_what != COMPLETION_FINALIZE) - return; - - if (!mrq) - return; - cmd = host->cmd_is_stop ? mrq->stop : mrq->cmd; - - if (cmd->data && (cmd->error == 0) && - (cmd->data->error == 0)) { - if (s3cmci_host_usedma(host) && (!host->dma_complete)) { - dbg(host, dbg_dma, "DMA Missing (%d)!\n", - host->dma_complete); - return; - } - } - - /* Read response from controller. */ - cmd->resp[0] = readl(host->base + S3C2410_SDIRSP0); - cmd->resp[1] = readl(host->base + S3C2410_SDIRSP1); - cmd->resp[2] = readl(host->base + S3C2410_SDIRSP2); - cmd->resp[3] = readl(host->base + S3C2410_SDIRSP3); - - writel(host->prescaler, host->base + S3C2410_SDIPRE); - - if (cmd->error) - debug_as_failure = 1; - - if (cmd->data && cmd->data->error) - debug_as_failure = 1; - - dbg_dumpcmd(host, cmd, debug_as_failure); - - /* Cleanup controller */ - writel(0, host->base + S3C2410_SDICMDARG); - writel(S3C2410_SDIDCON_STOP, host->base + S3C2410_SDIDCON); - writel(0, host->base + S3C2410_SDICMDCON); - clear_imask(host); - - if (cmd->data && cmd->error) - cmd->data->error = cmd->error; - - if (cmd->data && cmd->data->stop && (!host->cmd_is_stop)) { - host->cmd_is_stop = 1; - s3cmci_send_request(host->mmc); - return; - } - - /* If we have no data transfer we are finished here */ - if (!mrq->data) - goto request_done; - - /* Calculate the amout of bytes transfer if there was no error */ - if (mrq->data->error == 0) { - mrq->data->bytes_xfered = - (mrq->data->blocks * mrq->data->blksz); - } else { - mrq->data->bytes_xfered = 0; - } - - /* If we had an error while transferring data we flush the - * DMA channel and the fifo to clear out any garbage. */ - if (mrq->data->error != 0) { - if (s3cmci_host_usedma(host)) - s3c2410_dma_ctrl(host->dma, S3C2410_DMAOP_FLUSH); - - if (host->is2440) { - /* Clear failure register and reset fifo. */ - writel(S3C2440_SDIFSTA_FIFORESET | - S3C2440_SDIFSTA_FIFOFAIL, - host->base + S3C2410_SDIFSTA); - } else { - u32 mci_con; - - /* reset fifo */ - mci_con = readl(host->base + S3C2410_SDICON); - mci_con |= S3C2410_SDICON_FIFORESET; - - writel(mci_con, host->base + S3C2410_SDICON); - } - } - -request_done: - host->complete_what = COMPLETION_NONE; - host->mrq = NULL; - - s3cmci_check_sdio_irq(host); - mmc_request_done(host->mmc, mrq); -} - -static void s3cmci_dma_setup(struct s3cmci_host *host, - enum dma_data_direction source) -{ - static enum dma_data_direction last_source = -1; - static int setup_ok; - - if (last_source == source) - return; - - last_source = source; - - s3c2410_dma_devconfig(host->dma, source, - host->mem->start + host->sdidata); - - if (!setup_ok) { - s3c2410_dma_config(host->dma, 4); - s3c2410_dma_set_buffdone_fn(host->dma, - s3cmci_dma_done_callback); - s3c2410_dma_setflags(host->dma, S3C2410_DMAF_AUTOSTART); - setup_ok = 1; - } -} - -static void s3cmci_send_command(struct s3cmci_host *host, - struct mmc_command *cmd) -{ - u32 ccon, imsk; - - imsk = S3C2410_SDIIMSK_CRCSTATUS | S3C2410_SDIIMSK_CMDTIMEOUT | - S3C2410_SDIIMSK_RESPONSEND | S3C2410_SDIIMSK_CMDSENT | - S3C2410_SDIIMSK_RESPONSECRC; - - enable_imask(host, imsk); - - if (cmd->data) - host->complete_what = COMPLETION_XFERFINISH_RSPFIN; - else if (cmd->flags & MMC_RSP_PRESENT) - host->complete_what = COMPLETION_RSPFIN; - else - host->complete_what = COMPLETION_CMDSENT; - - writel(cmd->arg, host->base + S3C2410_SDICMDARG); - - ccon = cmd->opcode & S3C2410_SDICMDCON_INDEX; - ccon |= S3C2410_SDICMDCON_SENDERHOST | S3C2410_SDICMDCON_CMDSTART; - - if (cmd->flags & MMC_RSP_PRESENT) - ccon |= S3C2410_SDICMDCON_WAITRSP; - - if (cmd->flags & MMC_RSP_136) - ccon |= S3C2410_SDICMDCON_LONGRSP; - - writel(ccon, host->base + S3C2410_SDICMDCON); -} - -static int s3cmci_setup_data(struct s3cmci_host *host, struct mmc_data *data) -{ - u32 dcon, imsk, stoptries = 3; - - /* write DCON register */ - - if (!data) { - writel(0, host->base + S3C2410_SDIDCON); - return 0; - } - - if ((data->blksz & 3) != 0) { - /* We cannot deal with unaligned blocks with more than - * one block being transferred. */ - - if (data->blocks > 1) { - pr_warning("%s: can't do non-word sized block transfers (blksz %d)\n", __func__, data->blksz); - return -EINVAL; - } - } - - while (readl(host->base + S3C2410_SDIDSTA) & - (S3C2410_SDIDSTA_TXDATAON | S3C2410_SDIDSTA_RXDATAON)) { - - dbg(host, dbg_err, - "mci_setup_data() transfer stillin progress.\n"); - - writel(S3C2410_SDIDCON_STOP, host->base + S3C2410_SDIDCON); - s3cmci_reset(host); - - if ((stoptries--) == 0) { - dbg_dumpregs(host, "DRF"); - return -EINVAL; - } - } - - dcon = data->blocks & S3C2410_SDIDCON_BLKNUM_MASK; - - if (s3cmci_host_usedma(host)) - dcon |= S3C2410_SDIDCON_DMAEN; - - if (host->bus_width == MMC_BUS_WIDTH_4) - dcon |= S3C2410_SDIDCON_WIDEBUS; - - if (!(data->flags & MMC_DATA_STREAM)) - dcon |= S3C2410_SDIDCON_BLOCKMODE; - - if (data->flags & MMC_DATA_WRITE) { - dcon |= S3C2410_SDIDCON_TXAFTERRESP; - dcon |= S3C2410_SDIDCON_XFER_TXSTART; - } - - if (data->flags & MMC_DATA_READ) { - dcon |= S3C2410_SDIDCON_RXAFTERCMD; - dcon |= S3C2410_SDIDCON_XFER_RXSTART; - } - - if (host->is2440) { - dcon |= S3C2440_SDIDCON_DS_WORD; - dcon |= S3C2440_SDIDCON_DATSTART; - } - - writel(dcon, host->base + S3C2410_SDIDCON); - - /* write BSIZE register */ - - writel(data->blksz, host->base + S3C2410_SDIBSIZE); - - /* add to IMASK register */ - imsk = S3C2410_SDIIMSK_FIFOFAIL | S3C2410_SDIIMSK_DATACRC | - S3C2410_SDIIMSK_DATATIMEOUT | S3C2410_SDIIMSK_DATAFINISH; - - enable_imask(host, imsk); - - /* write TIMER register */ - - if (host->is2440) { - writel(0x007FFFFF, host->base + S3C2410_SDITIMER); - } else { - writel(0x0000FFFF, host->base + S3C2410_SDITIMER); - - /* FIX: set slow clock to prevent timeouts on read */ - if (data->flags & MMC_DATA_READ) - writel(0xFF, host->base + S3C2410_SDIPRE); - } - - return 0; -} - -#define BOTH_DIR (MMC_DATA_WRITE | MMC_DATA_READ) - -static int s3cmci_prepare_pio(struct s3cmci_host *host, struct mmc_data *data) -{ - int rw = (data->flags & MMC_DATA_WRITE) ? 1 : 0; - - BUG_ON((data->flags & BOTH_DIR) == BOTH_DIR); - - host->pio_sgptr = 0; - host->pio_bytes = 0; - host->pio_count = 0; - host->pio_active = rw ? XFER_WRITE : XFER_READ; - - if (rw) { - do_pio_write(host); - enable_imask(host, S3C2410_SDIIMSK_TXFIFOHALF); - } else { - enable_imask(host, S3C2410_SDIIMSK_RXFIFOHALF - | S3C2410_SDIIMSK_RXFIFOLAST); - } - - return 0; -} - -static int s3cmci_prepare_dma(struct s3cmci_host *host, struct mmc_data *data) -{ - int dma_len, i; - int rw = data->flags & MMC_DATA_WRITE; - - BUG_ON((data->flags & BOTH_DIR) == BOTH_DIR); - - s3cmci_dma_setup(host, rw ? DMA_TO_DEVICE : DMA_FROM_DEVICE); - s3c2410_dma_ctrl(host->dma, S3C2410_DMAOP_FLUSH); - - dma_len = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len, - rw ? DMA_TO_DEVICE : DMA_FROM_DEVICE); - - if (dma_len == 0) - return -ENOMEM; - - host->dma_complete = 0; - host->dmatogo = dma_len; - - for (i = 0; i < dma_len; i++) { - int res; - - dbg(host, dbg_dma, "enqueue %i: %08x@%u\n", i, - sg_dma_address(&data->sg[i]), - sg_dma_len(&data->sg[i])); - - res = s3c2410_dma_enqueue(host->dma, host, - sg_dma_address(&data->sg[i]), - sg_dma_len(&data->sg[i])); - - if (res) { - s3c2410_dma_ctrl(host->dma, S3C2410_DMAOP_FLUSH); - return -EBUSY; - } - } - - s3c2410_dma_ctrl(host->dma, S3C2410_DMAOP_START); - - return 0; -} - -static void s3cmci_send_request(struct mmc_host *mmc) -{ - struct s3cmci_host *host = mmc_priv(mmc); - struct mmc_request *mrq = host->mrq; - struct mmc_command *cmd = host->cmd_is_stop ? mrq->stop : mrq->cmd; - - host->ccnt++; - prepare_dbgmsg(host, cmd, host->cmd_is_stop); - - /* Clear command, data and fifo status registers - Fifo clear only necessary on 2440, but doesn't hurt on 2410 - */ - writel(0xFFFFFFFF, host->base + S3C2410_SDICMDSTAT); - writel(0xFFFFFFFF, host->base + S3C2410_SDIDSTA); - writel(0xFFFFFFFF, host->base + S3C2410_SDIFSTA); - - if (cmd->data) { - int res = s3cmci_setup_data(host, cmd->data); - - host->dcnt++; - - if (res) { - dbg(host, dbg_err, "setup data error %d\n", res); - cmd->error = res; - cmd->data->error = res; - - mmc_request_done(mmc, mrq); - return; - } - - if (s3cmci_host_usedma(host)) - res = s3cmci_prepare_dma(host, cmd->data); - else - res = s3cmci_prepare_pio(host, cmd->data); - - if (res) { - dbg(host, dbg_err, "data prepare error %d\n", res); - cmd->error = res; - cmd->data->error = res; - - mmc_request_done(mmc, mrq); - return; - } - } - - /* Send command */ - s3cmci_send_command(host, cmd); - - /* Enable Interrupt */ - s3cmci_enable_irq(host, true); -} - -static int s3cmci_card_present(struct mmc_host *mmc) -{ - struct s3cmci_host *host = mmc_priv(mmc); - struct s3c24xx_mci_pdata *pdata = host->pdata; - int ret; - - if (pdata->no_detect) - return -ENOSYS; - - ret = gpio_get_value(pdata->gpio_detect) ? 0 : 1; - return ret ^ pdata->detect_invert; -} - -static void s3cmci_request(struct mmc_host *mmc, struct mmc_request *mrq) -{ - struct s3cmci_host *host = mmc_priv(mmc); - - host->status = "mmc request"; - host->cmd_is_stop = 0; - host->mrq = mrq; - - if (s3cmci_card_present(mmc) == 0) { - dbg(host, dbg_err, "%s: no medium present\n", __func__); - host->mrq->cmd->error = -ENOMEDIUM; - mmc_request_done(mmc, mrq); - } else - s3cmci_send_request(mmc); -} - -static void s3cmci_set_clk(struct s3cmci_host *host, struct mmc_ios *ios) -{ - u32 mci_psc; - - /* Set clock */ - for (mci_psc = 0; mci_psc < 255; mci_psc++) { - host->real_rate = host->clk_rate / (host->clk_div*(mci_psc+1)); - - if (host->real_rate <= ios->clock) - break; - } - - if (mci_psc > 255) - mci_psc = 255; - - host->prescaler = mci_psc; - writel(host->prescaler, host->base + S3C2410_SDIPRE); - - /* If requested clock is 0, real_rate will be 0, too */ - if (ios->clock == 0) - host->real_rate = 0; -} - -static void s3cmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) -{ - struct s3cmci_host *host = mmc_priv(mmc); - u32 mci_con; - - /* Set the power state */ - - mci_con = readl(host->base + S3C2410_SDICON); - - switch (ios->power_mode) { - case MMC_POWER_ON: - case MMC_POWER_UP: - s3c2410_gpio_cfgpin(S3C2410_GPE(5), S3C2410_GPE5_SDCLK); - s3c2410_gpio_cfgpin(S3C2410_GPE(6), S3C2410_GPE6_SDCMD); - s3c2410_gpio_cfgpin(S3C2410_GPE(7), S3C2410_GPE7_SDDAT0); - s3c2410_gpio_cfgpin(S3C2410_GPE(8), S3C2410_GPE8_SDDAT1); - s3c2410_gpio_cfgpin(S3C2410_GPE(9), S3C2410_GPE9_SDDAT2); - s3c2410_gpio_cfgpin(S3C2410_GPE(10), S3C2410_GPE10_SDDAT3); - - if (host->pdata->set_power) - host->pdata->set_power(ios->power_mode, ios->vdd); - - if (!host->is2440) - mci_con |= S3C2410_SDICON_FIFORESET; - - break; - - case MMC_POWER_OFF: - default: - gpio_direction_output(S3C2410_GPE(5), 0); - - if (host->is2440) - mci_con |= S3C2440_SDICON_SDRESET; - - if (host->pdata->set_power) - host->pdata->set_power(ios->power_mode, ios->vdd); - - break; - } - - s3cmci_set_clk(host, ios); - - /* Set CLOCK_ENABLE */ - if (ios->clock) - mci_con |= S3C2410_SDICON_CLOCKTYPE; - else - mci_con &= ~S3C2410_SDICON_CLOCKTYPE; - - writel(mci_con, host->base + S3C2410_SDICON); - - if ((ios->power_mode == MMC_POWER_ON) || - (ios->power_mode == MMC_POWER_UP)) { - dbg(host, dbg_conf, "running at %lukHz (requested: %ukHz).\n", - host->real_rate/1000, ios->clock/1000); - } else { - dbg(host, dbg_conf, "powered down.\n"); - } - - host->bus_width = ios->bus_width; -} - -static void s3cmci_reset(struct s3cmci_host *host) -{ - u32 con = readl(host->base + S3C2410_SDICON); - - con |= S3C2440_SDICON_SDRESET; - writel(con, host->base + S3C2410_SDICON); -} - -static int s3cmci_get_ro(struct mmc_host *mmc) -{ - struct s3cmci_host *host = mmc_priv(mmc); - struct s3c24xx_mci_pdata *pdata = host->pdata; - int ret; - - if (pdata->no_wprotect) - return 0; - - ret = gpio_get_value(pdata->gpio_wprotect) ? 1 : 0; - ret ^= pdata->wprotect_invert; - - return ret; -} - -static void s3cmci_enable_sdio_irq(struct mmc_host *mmc, int enable) -{ - struct s3cmci_host *host = mmc_priv(mmc); - unsigned long flags; - u32 con; - - local_irq_save(flags); - - con = readl(host->base + S3C2410_SDICON); - host->sdio_irqen = enable; - - if (enable == host->sdio_irqen) - goto same_state; - - if (enable) { - con |= S3C2410_SDICON_SDIOIRQ; - enable_imask(host, S3C2410_SDIIMSK_SDIOIRQ); - - if (!host->irq_state && !host->irq_disabled) { - host->irq_state = true; - enable_irq(host->irq); - } - } else { - disable_imask(host, S3C2410_SDIIMSK_SDIOIRQ); - con &= ~S3C2410_SDICON_SDIOIRQ; - - if (!host->irq_enabled && host->irq_state) { - disable_irq_nosync(host->irq); - host->irq_state = false; - } - } - - writel(con, host->base + S3C2410_SDICON); - - same_state: - local_irq_restore(flags); - - s3cmci_check_sdio_irq(host); -} - -static struct mmc_host_ops s3cmci_ops = { - .request = s3cmci_request, - .set_ios = s3cmci_set_ios, - .get_ro = s3cmci_get_ro, - .get_cd = s3cmci_card_present, - .enable_sdio_irq = s3cmci_enable_sdio_irq, -}; - -static struct s3c24xx_mci_pdata s3cmci_def_pdata = { - /* This is currently here to avoid a number of if (host->pdata) - * checks. Any zero fields to ensure reasonable defaults are picked. */ - .no_wprotect = 1, - .no_detect = 1, -}; - -#ifdef CONFIG_CPU_FREQ - -static int s3cmci_cpufreq_transition(struct notifier_block *nb, - unsigned long val, void *data) -{ - struct s3cmci_host *host; - struct mmc_host *mmc; - unsigned long newclk; - unsigned long flags; - - host = container_of(nb, struct s3cmci_host, freq_transition); - newclk = clk_get_rate(host->clk); - mmc = host->mmc; - - if ((val == CPUFREQ_PRECHANGE && newclk > host->clk_rate) || - (val == CPUFREQ_POSTCHANGE && newclk < host->clk_rate)) { - spin_lock_irqsave(&mmc->lock, flags); - - host->clk_rate = newclk; - - if (mmc->ios.power_mode != MMC_POWER_OFF && - mmc->ios.clock != 0) - s3cmci_set_clk(host, &mmc->ios); - - spin_unlock_irqrestore(&mmc->lock, flags); - } - - return 0; -} - -static inline int s3cmci_cpufreq_register(struct s3cmci_host *host) -{ - host->freq_transition.notifier_call = s3cmci_cpufreq_transition; - - return cpufreq_register_notifier(&host->freq_transition, - CPUFREQ_TRANSITION_NOTIFIER); -} - -static inline void s3cmci_cpufreq_deregister(struct s3cmci_host *host) -{ - cpufreq_unregister_notifier(&host->freq_transition, - CPUFREQ_TRANSITION_NOTIFIER); -} - -#else -static inline int s3cmci_cpufreq_register(struct s3cmci_host *host) -{ - return 0; -} - -static inline void s3cmci_cpufreq_deregister(struct s3cmci_host *host) -{ -} -#endif - - -#ifdef CONFIG_DEBUG_FS - -static int s3cmci_state_show(struct seq_file *seq, void *v) -{ - struct s3cmci_host *host = seq->private; - - seq_printf(seq, "Register base = 0x%08x\n", (u32)host->base); - seq_printf(seq, "Clock rate = %ld\n", host->clk_rate); - seq_printf(seq, "Prescale = %d\n", host->prescaler); - seq_printf(seq, "is2440 = %d\n", host->is2440); - seq_printf(seq, "IRQ = %d\n", host->irq); - seq_printf(seq, "IRQ enabled = %d\n", host->irq_enabled); - seq_printf(seq, "IRQ disabled = %d\n", host->irq_disabled); - seq_printf(seq, "IRQ state = %d\n", host->irq_state); - seq_printf(seq, "CD IRQ = %d\n", host->irq_cd); - seq_printf(seq, "Do DMA = %d\n", s3cmci_host_usedma(host)); - seq_printf(seq, "SDIIMSK at %d\n", host->sdiimsk); - seq_printf(seq, "SDIDATA at %d\n", host->sdidata); - - return 0; -} - -static int s3cmci_state_open(struct inode *inode, struct file *file) -{ - return single_open(file, s3cmci_state_show, inode->i_private); -} - -static const struct file_operations s3cmci_fops_state = { - .owner = THIS_MODULE, - .open = s3cmci_state_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -#define DBG_REG(_r) { .addr = S3C2410_SDI##_r, .name = #_r } - -struct s3cmci_reg { - unsigned short addr; - unsigned char *name; -} debug_regs[] = { - DBG_REG(CON), - DBG_REG(PRE), - DBG_REG(CMDARG), - DBG_REG(CMDCON), - DBG_REG(CMDSTAT), - DBG_REG(RSP0), - DBG_REG(RSP1), - DBG_REG(RSP2), - DBG_REG(RSP3), - DBG_REG(TIMER), - DBG_REG(BSIZE), - DBG_REG(DCON), - DBG_REG(DCNT), - DBG_REG(DSTA), - DBG_REG(FSTA), - {} -}; - -static int s3cmci_regs_show(struct seq_file *seq, void *v) -{ - struct s3cmci_host *host = seq->private; - struct s3cmci_reg *rptr = debug_regs; - - for (; rptr->name; rptr++) - seq_printf(seq, "SDI%s\t=0x%08x\n", rptr->name, - readl(host->base + rptr->addr)); - - seq_printf(seq, "SDIIMSK\t=0x%08x\n", readl(host->base + host->sdiimsk)); - - return 0; -} - -static int s3cmci_regs_open(struct inode *inode, struct file *file) -{ - return single_open(file, s3cmci_regs_show, inode->i_private); -} - -static const struct file_operations s3cmci_fops_regs = { - .owner = THIS_MODULE, - .open = s3cmci_regs_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static void s3cmci_debugfs_attach(struct s3cmci_host *host) -{ - struct device *dev = &host->pdev->dev; - - host->debug_root = debugfs_create_dir(dev_name(dev), NULL); - if (IS_ERR(host->debug_root)) { - dev_err(dev, "failed to create debugfs root\n"); - return; - } - - host->debug_state = debugfs_create_file("state", 0444, - host->debug_root, host, - &s3cmci_fops_state); - - if (IS_ERR(host->debug_state)) - dev_err(dev, "failed to create debug state file\n"); - - host->debug_regs = debugfs_create_file("regs", 0444, - host->debug_root, host, - &s3cmci_fops_regs); - - if (IS_ERR(host->debug_regs)) - dev_err(dev, "failed to create debug regs file\n"); -} - -static void s3cmci_debugfs_remove(struct s3cmci_host *host) -{ - debugfs_remove(host->debug_regs); - debugfs_remove(host->debug_state); - debugfs_remove(host->debug_root); -} - -#else -static inline void s3cmci_debugfs_attach(struct s3cmci_host *host) { } -static inline void s3cmci_debugfs_remove(struct s3cmci_host *host) { } - -#endif /* CONFIG_DEBUG_FS */ - -static int __devinit s3cmci_probe(struct platform_device *pdev) -{ - struct s3cmci_host *host; - struct mmc_host *mmc; - int ret; - int is2440; - int i; - - is2440 = platform_get_device_id(pdev)->driver_data; - - mmc = mmc_alloc_host(sizeof(struct s3cmci_host), &pdev->dev); - if (!mmc) { - ret = -ENOMEM; - goto probe_out; - } - - for (i = S3C2410_GPE(5); i <= S3C2410_GPE(10); i++) { - ret = gpio_request(i, dev_name(&pdev->dev)); - if (ret) { - dev_err(&pdev->dev, "failed to get gpio %d\n", i); - - for (i--; i >= S3C2410_GPE(5); i--) - gpio_free(i); - - goto probe_free_host; - } - } - - host = mmc_priv(mmc); - host->mmc = mmc; - host->pdev = pdev; - host->is2440 = is2440; - - host->pdata = pdev->dev.platform_data; - if (!host->pdata) { - pdev->dev.platform_data = &s3cmci_def_pdata; - host->pdata = &s3cmci_def_pdata; - } - - spin_lock_init(&host->complete_lock); - tasklet_init(&host->pio_tasklet, pio_tasklet, (unsigned long) host); - - if (is2440) { - host->sdiimsk = S3C2440_SDIIMSK; - host->sdidata = S3C2440_SDIDATA; - host->clk_div = 1; - } else { - host->sdiimsk = S3C2410_SDIIMSK; - host->sdidata = S3C2410_SDIDATA; - host->clk_div = 2; - } - - host->complete_what = COMPLETION_NONE; - host->pio_active = XFER_NONE; - -#ifdef CONFIG_MMC_S3C_PIODMA - host->dodma = host->pdata->use_dma; -#endif - - host->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!host->mem) { - dev_err(&pdev->dev, - "failed to get io memory region resource.\n"); - - ret = -ENOENT; - goto probe_free_gpio; - } - - host->mem = request_mem_region(host->mem->start, - resource_size(host->mem), pdev->name); - - if (!host->mem) { - dev_err(&pdev->dev, "failed to request io memory region.\n"); - ret = -ENOENT; - goto probe_free_gpio; - } - - host->base = ioremap(host->mem->start, resource_size(host->mem)); - if (!host->base) { - dev_err(&pdev->dev, "failed to ioremap() io memory region.\n"); - ret = -EINVAL; - goto probe_free_mem_region; - } - - host->irq = platform_get_irq(pdev, 0); - if (host->irq == 0) { - dev_err(&pdev->dev, "failed to get interrupt resource.\n"); - ret = -EINVAL; - goto probe_iounmap; - } - - if (request_irq(host->irq, s3cmci_irq, 0, DRIVER_NAME, host)) { - dev_err(&pdev->dev, "failed to request mci interrupt.\n"); - ret = -ENOENT; - goto probe_iounmap; - } - - /* We get spurious interrupts even when we have set the IMSK - * register to ignore everything, so use disable_irq() to make - * ensure we don't lock the system with un-serviceable requests. */ - - disable_irq(host->irq); - host->irq_state = false; - - if (!host->pdata->no_detect) { - ret = gpio_request(host->pdata->gpio_detect, "s3cmci detect"); - if (ret) { - dev_err(&pdev->dev, "failed to get detect gpio\n"); - goto probe_free_irq; - } - - host->irq_cd = gpio_to_irq(host->pdata->gpio_detect); - - if (host->irq_cd >= 0) { - if (request_irq(host->irq_cd, s3cmci_irq_cd, - IRQF_TRIGGER_RISING | - IRQF_TRIGGER_FALLING, - DRIVER_NAME, host)) { - dev_err(&pdev->dev, - "can't get card detect irq.\n"); - ret = -ENOENT; - goto probe_free_gpio_cd; - } - } else { - dev_warn(&pdev->dev, - "host detect has no irq available\n"); - gpio_direction_input(host->pdata->gpio_detect); - } - } else - host->irq_cd = -1; - - if (!host->pdata->no_wprotect) { - ret = gpio_request(host->pdata->gpio_wprotect, "s3cmci wp"); - if (ret) { - dev_err(&pdev->dev, "failed to get writeprotect\n"); - goto probe_free_irq_cd; - } - - gpio_direction_input(host->pdata->gpio_wprotect); - } - - /* depending on the dma state, get a dma channel to use. */ - - if (s3cmci_host_usedma(host)) { - host->dma = s3c2410_dma_request(DMACH_SDI, &s3cmci_dma_client, - host); - if (host->dma < 0) { - dev_err(&pdev->dev, "cannot get DMA channel.\n"); - if (!s3cmci_host_canpio()) { - ret = -EBUSY; - goto probe_free_gpio_wp; - } else { - dev_warn(&pdev->dev, "falling back to PIO.\n"); - host->dodma = 0; - } - } - } - - host->clk = clk_get(&pdev->dev, "sdi"); - if (IS_ERR(host->clk)) { - dev_err(&pdev->dev, "failed to find clock source.\n"); - ret = PTR_ERR(host->clk); - host->clk = NULL; - goto probe_free_dma; - } - - ret = clk_enable(host->clk); - if (ret) { - dev_err(&pdev->dev, "failed to enable clock source.\n"); - goto clk_free; - } - - host->clk_rate = clk_get_rate(host->clk); - - mmc->ops = &s3cmci_ops; - mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; -#ifdef CONFIG_MMC_S3C_HW_SDIO_IRQ - mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ; -#else - mmc->caps = MMC_CAP_4_BIT_DATA; -#endif - mmc->f_min = host->clk_rate / (host->clk_div * 256); - mmc->f_max = host->clk_rate / host->clk_div; - - if (host->pdata->ocr_avail) - mmc->ocr_avail = host->pdata->ocr_avail; - - mmc->max_blk_count = 4095; - mmc->max_blk_size = 4095; - mmc->max_req_size = 4095 * 512; - mmc->max_seg_size = mmc->max_req_size; - - mmc->max_segs = 128; - - dbg(host, dbg_debug, - "probe: mode:%s mapped mci_base:%p irq:%u irq_cd:%u dma:%u.\n", - (host->is2440?"2440":""), - host->base, host->irq, host->irq_cd, host->dma); - - ret = s3cmci_cpufreq_register(host); - if (ret) { - dev_err(&pdev->dev, "failed to register cpufreq\n"); - goto free_dmabuf; - } - - ret = mmc_add_host(mmc); - if (ret) { - dev_err(&pdev->dev, "failed to add mmc host.\n"); - goto free_cpufreq; - } - - s3cmci_debugfs_attach(host); - - platform_set_drvdata(pdev, mmc); - dev_info(&pdev->dev, "%s - using %s, %s SDIO IRQ\n", mmc_hostname(mmc), - s3cmci_host_usedma(host) ? "dma" : "pio", - mmc->caps & MMC_CAP_SDIO_IRQ ? "hw" : "sw"); - - return 0; - - free_cpufreq: - s3cmci_cpufreq_deregister(host); - - free_dmabuf: - clk_disable(host->clk); - - clk_free: - clk_put(host->clk); - - probe_free_dma: - if (s3cmci_host_usedma(host)) - s3c2410_dma_free(host->dma, &s3cmci_dma_client); - - probe_free_gpio_wp: - if (!host->pdata->no_wprotect) - gpio_free(host->pdata->gpio_wprotect); - - probe_free_gpio_cd: - if (!host->pdata->no_detect) - gpio_free(host->pdata->gpio_detect); - - probe_free_irq_cd: - if (host->irq_cd >= 0) - free_irq(host->irq_cd, host); - - probe_free_irq: - free_irq(host->irq, host); - - probe_iounmap: - iounmap(host->base); - - probe_free_mem_region: - release_mem_region(host->mem->start, resource_size(host->mem)); - - probe_free_gpio: - for (i = S3C2410_GPE(5); i <= S3C2410_GPE(10); i++) - gpio_free(i); - - probe_free_host: - mmc_free_host(mmc); - - probe_out: - return ret; -} - -static void s3cmci_shutdown(struct platform_device *pdev) -{ - struct mmc_host *mmc = platform_get_drvdata(pdev); - struct s3cmci_host *host = mmc_priv(mmc); - - if (host->irq_cd >= 0) - free_irq(host->irq_cd, host); - - s3cmci_debugfs_remove(host); - s3cmci_cpufreq_deregister(host); - mmc_remove_host(mmc); - clk_disable(host->clk); -} - -static int __devexit s3cmci_remove(struct platform_device *pdev) -{ - struct mmc_host *mmc = platform_get_drvdata(pdev); - struct s3cmci_host *host = mmc_priv(mmc); - struct s3c24xx_mci_pdata *pd = host->pdata; - int i; - - s3cmci_shutdown(pdev); - - clk_put(host->clk); - - tasklet_disable(&host->pio_tasklet); - - if (s3cmci_host_usedma(host)) - s3c2410_dma_free(host->dma, &s3cmci_dma_client); - - free_irq(host->irq, host); - - if (!pd->no_wprotect) - gpio_free(pd->gpio_wprotect); - - if (!pd->no_detect) - gpio_free(pd->gpio_detect); - - for (i = S3C2410_GPE(5); i <= S3C2410_GPE(10); i++) - gpio_free(i); - - - iounmap(host->base); - release_mem_region(host->mem->start, resource_size(host->mem)); - - mmc_free_host(mmc); - return 0; -} - -static struct platform_device_id s3cmci_driver_ids[] = { - { - .name = "s3c2410-sdi", - .driver_data = 0, - }, { - .name = "s3c2412-sdi", - .driver_data = 1, - }, { - .name = "s3c2440-sdi", - .driver_data = 1, - }, - { } -}; - -MODULE_DEVICE_TABLE(platform, s3cmci_driver_ids); - - -#ifdef CONFIG_PM - -static int s3cmci_suspend(struct device *dev) -{ - struct mmc_host *mmc = platform_get_drvdata(to_platform_device(dev)); - - return mmc_suspend_host(mmc); -} - -static int s3cmci_resume(struct device *dev) -{ - struct mmc_host *mmc = platform_get_drvdata(to_platform_device(dev)); - - return mmc_resume_host(mmc); -} - -static const struct dev_pm_ops s3cmci_pm = { - .suspend = s3cmci_suspend, - .resume = s3cmci_resume, -}; - -#define s3cmci_pm_ops &s3cmci_pm -#else /* CONFIG_PM */ -#define s3cmci_pm_ops NULL -#endif /* CONFIG_PM */ - - -static struct platform_driver s3cmci_driver = { - .driver = { - .name = "s3c-sdi", - .owner = THIS_MODULE, - .pm = s3cmci_pm_ops, - }, - .id_table = s3cmci_driver_ids, - .probe = s3cmci_probe, - .remove = __devexit_p(s3cmci_remove), - .shutdown = s3cmci_shutdown, -}; - -module_platform_driver(s3cmci_driver); - -MODULE_DESCRIPTION("Samsung S3C MMC/SD Card Interface driver"); -MODULE_LICENSE("GPL v2"); -MODULE_AUTHOR("Thomas Kleffel <tk@maintech.de>, Ben Dooks <ben-linux@fluff.org>"); diff --git a/ANDROID_3.4.5/drivers/mmc/host/s3cmci.h b/ANDROID_3.4.5/drivers/mmc/host/s3cmci.h deleted file mode 100644 index c76b53db..00000000 --- a/ANDROID_3.4.5/drivers/mmc/host/s3cmci.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - * linux/drivers/mmc/s3cmci.h - Samsung S3C MCI driver - * - * Copyright (C) 2004-2006 Thomas Kleffel, All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -enum s3cmci_waitfor { - COMPLETION_NONE, - COMPLETION_FINALIZE, - COMPLETION_CMDSENT, - COMPLETION_RSPFIN, - COMPLETION_XFERFINISH, - COMPLETION_XFERFINISH_RSPFIN, -}; - -struct s3cmci_host { - struct platform_device *pdev; - struct s3c24xx_mci_pdata *pdata; - struct mmc_host *mmc; - struct resource *mem; - struct clk *clk; - void __iomem *base; - int irq; - int irq_cd; - int dma; - - unsigned long clk_rate; - unsigned long clk_div; - unsigned long real_rate; - u8 prescaler; - - int is2440; - unsigned sdiimsk; - unsigned sdidata; - int dodma; - int dmatogo; - - bool irq_disabled; - bool irq_enabled; - bool irq_state; - int sdio_irqen; - - struct mmc_request *mrq; - int cmd_is_stop; - - spinlock_t complete_lock; - enum s3cmci_waitfor complete_what; - - int dma_complete; - - u32 pio_sgptr; - u32 pio_bytes; - u32 pio_count; - u32 *pio_ptr; -#define XFER_NONE 0 -#define XFER_READ 1 -#define XFER_WRITE 2 - u32 pio_active; - - int bus_width; - - char dbgmsg_cmd[301]; - char dbgmsg_dat[301]; - char *status; - - unsigned int ccnt, dcnt; - struct tasklet_struct pio_tasklet; - -#ifdef CONFIG_DEBUG_FS - struct dentry *debug_root; - struct dentry *debug_state; - struct dentry *debug_regs; -#endif - -#ifdef CONFIG_CPU_FREQ - struct notifier_block freq_transition; -#endif -}; diff --git a/ANDROID_3.4.5/drivers/mmc/host/sdhci-cns3xxx.c b/ANDROID_3.4.5/drivers/mmc/host/sdhci-cns3xxx.c deleted file mode 100644 index 28a87080..00000000 --- a/ANDROID_3.4.5/drivers/mmc/host/sdhci-cns3xxx.c +++ /dev/null @@ -1,123 +0,0 @@ -/* - * SDHCI support for CNS3xxx SoC - * - * Copyright 2008 Cavium Networks - * Copyright 2010 MontaVista Software, LLC. - * - * Authors: Scott Shu - * Anton Vorontsov <avorontsov@mvista.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include <linux/delay.h> -#include <linux/device.h> -#include <linux/mmc/host.h> -#include <linux/module.h> -#include <mach/cns3xxx.h> -#include "sdhci-pltfm.h" - -static unsigned int sdhci_cns3xxx_get_max_clk(struct sdhci_host *host) -{ - return 150000000; -} - -static void sdhci_cns3xxx_set_clock(struct sdhci_host *host, unsigned int clock) -{ - struct device *dev = mmc_dev(host->mmc); - int div = 1; - u16 clk; - unsigned long timeout; - - if (clock == host->clock) - return; - - sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL); - - if (clock == 0) - goto out; - - while (host->max_clk / div > clock) { - /* - * On CNS3xxx divider grows linearly up to 4, and then - * exponentially up to 256. - */ - if (div < 4) - div += 1; - else if (div < 256) - div *= 2; - else - break; - } - - dev_dbg(dev, "desired SD clock: %d, actual: %d\n", - clock, host->max_clk / div); - - /* Divide by 3 is special. */ - if (div != 3) - div >>= 1; - - clk = div << SDHCI_DIVIDER_SHIFT; - clk |= SDHCI_CLOCK_INT_EN; - sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); - - timeout = 20; - while (!((clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL)) - & SDHCI_CLOCK_INT_STABLE)) { - if (timeout == 0) { - dev_warn(dev, "clock is unstable"); - break; - } - timeout--; - mdelay(1); - } - - clk |= SDHCI_CLOCK_CARD_EN; - sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); -out: - host->clock = clock; -} - -static struct sdhci_ops sdhci_cns3xxx_ops = { - .get_max_clock = sdhci_cns3xxx_get_max_clk, - .set_clock = sdhci_cns3xxx_set_clock, -}; - -static struct sdhci_pltfm_data sdhci_cns3xxx_pdata = { - .ops = &sdhci_cns3xxx_ops, - .quirks = SDHCI_QUIRK_BROKEN_DMA | - SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK | - SDHCI_QUIRK_INVERTED_WRITE_PROTECT | - SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN | - SDHCI_QUIRK_BROKEN_TIMEOUT_VAL | - SDHCI_QUIRK_NONSTANDARD_CLOCK, -}; - -static int __devinit sdhci_cns3xxx_probe(struct platform_device *pdev) -{ - return sdhci_pltfm_register(pdev, &sdhci_cns3xxx_pdata); -} - -static int __devexit sdhci_cns3xxx_remove(struct platform_device *pdev) -{ - return sdhci_pltfm_unregister(pdev); -} - -static struct platform_driver sdhci_cns3xxx_driver = { - .driver = { - .name = "sdhci-cns3xxx", - .owner = THIS_MODULE, - .pm = SDHCI_PLTFM_PMOPS, - }, - .probe = sdhci_cns3xxx_probe, - .remove = __devexit_p(sdhci_cns3xxx_remove), -}; - -module_platform_driver(sdhci_cns3xxx_driver); - -MODULE_DESCRIPTION("SDHCI driver for CNS3xxx"); -MODULE_AUTHOR("Scott Shu, " - "Anton Vorontsov <avorontsov@mvista.com>"); -MODULE_LICENSE("GPL v2"); diff --git a/ANDROID_3.4.5/drivers/mmc/host/sdhci-dove.c b/ANDROID_3.4.5/drivers/mmc/host/sdhci-dove.c deleted file mode 100644 index 177f697b..00000000 --- a/ANDROID_3.4.5/drivers/mmc/host/sdhci-dove.c +++ /dev/null @@ -1,97 +0,0 @@ -/* - * sdhci-dove.c Support for SDHCI on Marvell's Dove SoC - * - * Author: Saeed Bishara <saeed@marvell.com> - * Mike Rapoport <mike@compulab.co.il> - * Based on sdhci-cns3xxx.c - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include <linux/io.h> -#include <linux/module.h> -#include <linux/mmc/host.h> - -#include "sdhci-pltfm.h" - -static u16 sdhci_dove_readw(struct sdhci_host *host, int reg) -{ - u16 ret; - - switch (reg) { - case SDHCI_HOST_VERSION: - case SDHCI_SLOT_INT_STATUS: - /* those registers don't exist */ - return 0; - default: - ret = readw(host->ioaddr + reg); - } - return ret; -} - -static u32 sdhci_dove_readl(struct sdhci_host *host, int reg) -{ - u32 ret; - - switch (reg) { - case SDHCI_CAPABILITIES: - ret = readl(host->ioaddr + reg); - /* Mask the support for 3.0V */ - ret &= ~SDHCI_CAN_VDD_300; - break; - default: - ret = readl(host->ioaddr + reg); - } - return ret; -} - -static struct sdhci_ops sdhci_dove_ops = { - .read_w = sdhci_dove_readw, - .read_l = sdhci_dove_readl, -}; - -static struct sdhci_pltfm_data sdhci_dove_pdata = { - .ops = &sdhci_dove_ops, - .quirks = SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER | - SDHCI_QUIRK_NO_BUSY_IRQ | - SDHCI_QUIRK_BROKEN_TIMEOUT_VAL | - SDHCI_QUIRK_FORCE_DMA, -}; - -static int __devinit sdhci_dove_probe(struct platform_device *pdev) -{ - return sdhci_pltfm_register(pdev, &sdhci_dove_pdata); -} - -static int __devexit sdhci_dove_remove(struct platform_device *pdev) -{ - return sdhci_pltfm_unregister(pdev); -} - -static struct platform_driver sdhci_dove_driver = { - .driver = { - .name = "sdhci-dove", - .owner = THIS_MODULE, - .pm = SDHCI_PLTFM_PMOPS, - }, - .probe = sdhci_dove_probe, - .remove = __devexit_p(sdhci_dove_remove), -}; - -module_platform_driver(sdhci_dove_driver); - -MODULE_DESCRIPTION("SDHCI driver for Dove"); -MODULE_AUTHOR("Saeed Bishara <saeed@marvell.com>, " - "Mike Rapoport <mike@compulab.co.il>"); -MODULE_LICENSE("GPL v2"); diff --git a/ANDROID_3.4.5/drivers/mmc/host/sdhci-esdhc-imx.c b/ANDROID_3.4.5/drivers/mmc/host/sdhci-esdhc-imx.c deleted file mode 100644 index 8abdaf66..00000000 --- a/ANDROID_3.4.5/drivers/mmc/host/sdhci-esdhc-imx.c +++ /dev/null @@ -1,613 +0,0 @@ -/* - * Freescale eSDHC i.MX controller driver for the platform bus. - * - * derived from the OF-version. - * - * Copyright (c) 2010 Pengutronix e.K. - * Author: Wolfram Sang <w.sang@pengutronix.de> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License. - */ - -#include <linux/io.h> -#include <linux/delay.h> -#include <linux/err.h> -#include <linux/clk.h> -#include <linux/gpio.h> -#include <linux/module.h> -#include <linux/slab.h> -#include <linux/mmc/host.h> -#include <linux/mmc/mmc.h> -#include <linux/mmc/sdio.h> -#include <linux/of.h> -#include <linux/of_device.h> -#include <linux/of_gpio.h> -#include <mach/esdhc.h> -#include "sdhci-pltfm.h" -#include "sdhci-esdhc.h" - -#define SDHCI_CTRL_D3CD 0x08 -/* VENDOR SPEC register */ -#define SDHCI_VENDOR_SPEC 0xC0 -#define SDHCI_VENDOR_SPEC_SDIO_QUIRK 0x00000002 -#define SDHCI_WTMK_LVL 0x44 -#define SDHCI_MIX_CTRL 0x48 - -/* - * There is an INT DMA ERR mis-match between eSDHC and STD SDHC SPEC: - * Bit25 is used in STD SPEC, and is reserved in fsl eSDHC design, - * but bit28 is used as the INT DMA ERR in fsl eSDHC design. - * Define this macro DMA error INT for fsl eSDHC - */ -#define SDHCI_INT_VENDOR_SPEC_DMA_ERR 0x10000000 - -/* - * The CMDTYPE of the CMD register (offset 0xE) should be set to - * "11" when the STOP CMD12 is issued on imx53 to abort one - * open ended multi-blk IO. Otherwise the TC INT wouldn't - * be generated. - * In exact block transfer, the controller doesn't complete the - * operations automatically as required at the end of the - * transfer and remains on hold if the abort command is not sent. - * As a result, the TC flag is not asserted and SW received timeout - * exeception. Bit1 of Vendor Spec registor is used to fix it. - */ -#define ESDHC_FLAG_MULTIBLK_NO_INT (1 << 1) - -enum imx_esdhc_type { - IMX25_ESDHC, - IMX35_ESDHC, - IMX51_ESDHC, - IMX53_ESDHC, - IMX6Q_USDHC, -}; - -struct pltfm_imx_data { - int flags; - u32 scratchpad; - enum imx_esdhc_type devtype; - struct esdhc_platform_data boarddata; -}; - -static struct platform_device_id imx_esdhc_devtype[] = { - { - .name = "sdhci-esdhc-imx25", - .driver_data = IMX25_ESDHC, - }, { - .name = "sdhci-esdhc-imx35", - .driver_data = IMX35_ESDHC, - }, { - .name = "sdhci-esdhc-imx51", - .driver_data = IMX51_ESDHC, - }, { - .name = "sdhci-esdhc-imx53", - .driver_data = IMX53_ESDHC, - }, { - .name = "sdhci-usdhc-imx6q", - .driver_data = IMX6Q_USDHC, - }, { - /* sentinel */ - } -}; -MODULE_DEVICE_TABLE(platform, imx_esdhc_devtype); - -static const struct of_device_id imx_esdhc_dt_ids[] = { - { .compatible = "fsl,imx25-esdhc", .data = &imx_esdhc_devtype[IMX25_ESDHC], }, - { .compatible = "fsl,imx35-esdhc", .data = &imx_esdhc_devtype[IMX35_ESDHC], }, - { .compatible = "fsl,imx51-esdhc", .data = &imx_esdhc_devtype[IMX51_ESDHC], }, - { .compatible = "fsl,imx53-esdhc", .data = &imx_esdhc_devtype[IMX53_ESDHC], }, - { .compatible = "fsl,imx6q-usdhc", .data = &imx_esdhc_devtype[IMX6Q_USDHC], }, - { /* sentinel */ } -}; -MODULE_DEVICE_TABLE(of, imx_esdhc_dt_ids); - -static inline int is_imx25_esdhc(struct pltfm_imx_data *data) -{ - return data->devtype == IMX25_ESDHC; -} - -static inline int is_imx35_esdhc(struct pltfm_imx_data *data) -{ - return data->devtype == IMX35_ESDHC; -} - -static inline int is_imx51_esdhc(struct pltfm_imx_data *data) -{ - return data->devtype == IMX51_ESDHC; -} - -static inline int is_imx53_esdhc(struct pltfm_imx_data *data) -{ - return data->devtype == IMX53_ESDHC; -} - -static inline int is_imx6q_usdhc(struct pltfm_imx_data *data) -{ - return data->devtype == IMX6Q_USDHC; -} - -static inline void esdhc_clrset_le(struct sdhci_host *host, u32 mask, u32 val, int reg) -{ - void __iomem *base = host->ioaddr + (reg & ~0x3); - u32 shift = (reg & 0x3) * 8; - - writel(((readl(base) & ~(mask << shift)) | (val << shift)), base); -} - -static u32 esdhc_readl_le(struct sdhci_host *host, int reg) -{ - struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - struct pltfm_imx_data *imx_data = pltfm_host->priv; - struct esdhc_platform_data *boarddata = &imx_data->boarddata; - - /* fake CARD_PRESENT flag */ - u32 val = readl(host->ioaddr + reg); - - if (unlikely((reg == SDHCI_PRESENT_STATE) - && gpio_is_valid(boarddata->cd_gpio))) { - if (gpio_get_value(boarddata->cd_gpio)) - /* no card, if a valid gpio says so... */ - val &= ~SDHCI_CARD_PRESENT; - else - /* ... in all other cases assume card is present */ - val |= SDHCI_CARD_PRESENT; - } - - if (unlikely(reg == SDHCI_CAPABILITIES)) { - /* In FSL esdhc IC module, only bit20 is used to indicate the - * ADMA2 capability of esdhc, but this bit is messed up on - * some SOCs (e.g. on MX25, MX35 this bit is set, but they - * don't actually support ADMA2). So set the BROKEN_ADMA - * uirk on MX25/35 platforms. - */ - - if (val & SDHCI_CAN_DO_ADMA1) { - val &= ~SDHCI_CAN_DO_ADMA1; - val |= SDHCI_CAN_DO_ADMA2; - } - } - - if (unlikely(reg == SDHCI_INT_STATUS)) { - if (val & SDHCI_INT_VENDOR_SPEC_DMA_ERR) { - val &= ~SDHCI_INT_VENDOR_SPEC_DMA_ERR; - val |= SDHCI_INT_ADMA_ERROR; - } - } - - return val; -} - -static void esdhc_writel_le(struct sdhci_host *host, u32 val, int reg) -{ - struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - struct pltfm_imx_data *imx_data = pltfm_host->priv; - struct esdhc_platform_data *boarddata = &imx_data->boarddata; - u32 data; - - if (unlikely(reg == SDHCI_INT_ENABLE || reg == SDHCI_SIGNAL_ENABLE)) { - if (boarddata->cd_type == ESDHC_CD_GPIO) - /* - * These interrupts won't work with a custom - * card_detect gpio (only applied to mx25/35) - */ - val &= ~(SDHCI_INT_CARD_REMOVE | SDHCI_INT_CARD_INSERT); - - if (val & SDHCI_INT_CARD_INT) { - /* - * Clear and then set D3CD bit to avoid missing the - * card interrupt. This is a eSDHC controller problem - * so we need to apply the following workaround: clear - * and set D3CD bit will make eSDHC re-sample the card - * interrupt. In case a card interrupt was lost, - * re-sample it by the following steps. - */ - data = readl(host->ioaddr + SDHCI_HOST_CONTROL); - data &= ~SDHCI_CTRL_D3CD; - writel(data, host->ioaddr + SDHCI_HOST_CONTROL); - data |= SDHCI_CTRL_D3CD; - writel(data, host->ioaddr + SDHCI_HOST_CONTROL); - } - } - - if (unlikely((imx_data->flags & ESDHC_FLAG_MULTIBLK_NO_INT) - && (reg == SDHCI_INT_STATUS) - && (val & SDHCI_INT_DATA_END))) { - u32 v; - v = readl(host->ioaddr + SDHCI_VENDOR_SPEC); - v &= ~SDHCI_VENDOR_SPEC_SDIO_QUIRK; - writel(v, host->ioaddr + SDHCI_VENDOR_SPEC); - } - - if (unlikely(reg == SDHCI_INT_ENABLE || reg == SDHCI_SIGNAL_ENABLE)) { - if (val & SDHCI_INT_ADMA_ERROR) { - val &= ~SDHCI_INT_ADMA_ERROR; - val |= SDHCI_INT_VENDOR_SPEC_DMA_ERR; - } - } - - writel(val, host->ioaddr + reg); -} - -static u16 esdhc_readw_le(struct sdhci_host *host, int reg) -{ - if (unlikely(reg == SDHCI_HOST_VERSION)) { - u16 val = readw(host->ioaddr + (reg ^ 2)); - /* - * uSDHC supports SDHCI v3.0, but it's encoded as value - * 0x3 in host controller version register, which violates - * SDHCI_SPEC_300 definition. Work it around here. - */ - if ((val & SDHCI_SPEC_VER_MASK) == 3) - return --val; - } - - return readw(host->ioaddr + reg); -} - -static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg) -{ - struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - struct pltfm_imx_data *imx_data = pltfm_host->priv; - - switch (reg) { - case SDHCI_TRANSFER_MODE: - /* - * Postpone this write, we must do it together with a - * command write that is down below. - */ - if ((imx_data->flags & ESDHC_FLAG_MULTIBLK_NO_INT) - && (host->cmd->opcode == SD_IO_RW_EXTENDED) - && (host->cmd->data->blocks > 1) - && (host->cmd->data->flags & MMC_DATA_READ)) { - u32 v; - v = readl(host->ioaddr + SDHCI_VENDOR_SPEC); - v |= SDHCI_VENDOR_SPEC_SDIO_QUIRK; - writel(v, host->ioaddr + SDHCI_VENDOR_SPEC); - } - imx_data->scratchpad = val; - return; - case SDHCI_COMMAND: - if ((host->cmd->opcode == MMC_STOP_TRANSMISSION || - host->cmd->opcode == MMC_SET_BLOCK_COUNT) && - (imx_data->flags & ESDHC_FLAG_MULTIBLK_NO_INT)) - val |= SDHCI_CMD_ABORTCMD; - - if (is_imx6q_usdhc(imx_data)) { - u32 m = readl(host->ioaddr + SDHCI_MIX_CTRL); - m = imx_data->scratchpad | (m & 0xffff0000); - writel(m, host->ioaddr + SDHCI_MIX_CTRL); - writel(val << 16, - host->ioaddr + SDHCI_TRANSFER_MODE); - } else { - writel(val << 16 | imx_data->scratchpad, - host->ioaddr + SDHCI_TRANSFER_MODE); - } - return; - case SDHCI_BLOCK_SIZE: - val &= ~SDHCI_MAKE_BLKSZ(0x7, 0); - break; - } - esdhc_clrset_le(host, 0xffff, val, reg); -} - -static void esdhc_writeb_le(struct sdhci_host *host, u8 val, int reg) -{ - u32 new_val; - - switch (reg) { - case SDHCI_POWER_CONTROL: - /* - * FSL put some DMA bits here - * If your board has a regulator, code should be here - */ - return; - case SDHCI_HOST_CONTROL: - /* FSL messed up here, so we can just keep those three */ - new_val = val & (SDHCI_CTRL_LED | \ - SDHCI_CTRL_4BITBUS | \ - SDHCI_CTRL_D3CD); - /* ensure the endianess */ - new_val |= ESDHC_HOST_CONTROL_LE; - /* DMA mode bits are shifted */ - new_val |= (val & SDHCI_CTRL_DMA_MASK) << 5; - - esdhc_clrset_le(host, 0xffff, new_val, reg); - return; - } - esdhc_clrset_le(host, 0xff, val, reg); - - /* - * The esdhc has a design violation to SDHC spec which tells - * that software reset should not affect card detection circuit. - * But esdhc clears its SYSCTL register bits [0..2] during the - * software reset. This will stop those clocks that card detection - * circuit relies on. To work around it, we turn the clocks on back - * to keep card detection circuit functional. - */ - if ((reg == SDHCI_SOFTWARE_RESET) && (val & 1)) - esdhc_clrset_le(host, 0x7, 0x7, ESDHC_SYSTEM_CONTROL); -} - -static unsigned int esdhc_pltfm_get_max_clock(struct sdhci_host *host) -{ - struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - - return clk_get_rate(pltfm_host->clk); -} - -static unsigned int esdhc_pltfm_get_min_clock(struct sdhci_host *host) -{ - struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - - return clk_get_rate(pltfm_host->clk) / 256 / 16; -} - -static unsigned int esdhc_pltfm_get_ro(struct sdhci_host *host) -{ - struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - struct pltfm_imx_data *imx_data = pltfm_host->priv; - struct esdhc_platform_data *boarddata = &imx_data->boarddata; - - switch (boarddata->wp_type) { - case ESDHC_WP_GPIO: - if (gpio_is_valid(boarddata->wp_gpio)) - return gpio_get_value(boarddata->wp_gpio); - case ESDHC_WP_CONTROLLER: - return !(readl(host->ioaddr + SDHCI_PRESENT_STATE) & - SDHCI_WRITE_PROTECT); - case ESDHC_WP_NONE: - break; - } - - return -ENOSYS; -} - -static struct sdhci_ops sdhci_esdhc_ops = { - .read_l = esdhc_readl_le, - .read_w = esdhc_readw_le, - .write_l = esdhc_writel_le, - .write_w = esdhc_writew_le, - .write_b = esdhc_writeb_le, - .set_clock = esdhc_set_clock, - .get_max_clock = esdhc_pltfm_get_max_clock, - .get_min_clock = esdhc_pltfm_get_min_clock, - .get_ro = esdhc_pltfm_get_ro, -}; - -static struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = { - .quirks = ESDHC_DEFAULT_QUIRKS | SDHCI_QUIRK_NO_HISPD_BIT - | SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC - | SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC - | SDHCI_QUIRK_BROKEN_CARD_DETECTION, - .ops = &sdhci_esdhc_ops, -}; - -static irqreturn_t cd_irq(int irq, void *data) -{ - struct sdhci_host *sdhost = (struct sdhci_host *)data; - - tasklet_schedule(&sdhost->card_tasklet); - return IRQ_HANDLED; -}; - -#ifdef CONFIG_OF -static int __devinit -sdhci_esdhc_imx_probe_dt(struct platform_device *pdev, - struct esdhc_platform_data *boarddata) -{ - struct device_node *np = pdev->dev.of_node; - - if (!np) - return -ENODEV; - - if (of_get_property(np, "fsl,card-wired", NULL)) - boarddata->cd_type = ESDHC_CD_PERMANENT; - - if (of_get_property(np, "fsl,cd-controller", NULL)) - boarddata->cd_type = ESDHC_CD_CONTROLLER; - - if (of_get_property(np, "fsl,wp-controller", NULL)) - boarddata->wp_type = ESDHC_WP_CONTROLLER; - - boarddata->cd_gpio = of_get_named_gpio(np, "cd-gpios", 0); - if (gpio_is_valid(boarddata->cd_gpio)) - boarddata->cd_type = ESDHC_CD_GPIO; - - boarddata->wp_gpio = of_get_named_gpio(np, "wp-gpios", 0); - if (gpio_is_valid(boarddata->wp_gpio)) - boarddata->wp_type = ESDHC_WP_GPIO; - - return 0; -} -#else -static inline int -sdhci_esdhc_imx_probe_dt(struct platform_device *pdev, - struct esdhc_platform_data *boarddata) -{ - return -ENODEV; -} -#endif - -static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev) -{ - const struct of_device_id *of_id = - of_match_device(imx_esdhc_dt_ids, &pdev->dev); - struct sdhci_pltfm_host *pltfm_host; - struct sdhci_host *host; - struct esdhc_platform_data *boarddata; - struct clk *clk; - int err; - struct pltfm_imx_data *imx_data; - - host = sdhci_pltfm_init(pdev, &sdhci_esdhc_imx_pdata); - if (IS_ERR(host)) - return PTR_ERR(host); - - pltfm_host = sdhci_priv(host); - - imx_data = kzalloc(sizeof(struct pltfm_imx_data), GFP_KERNEL); - if (!imx_data) { - err = -ENOMEM; - goto err_imx_data; - } - - if (of_id) - pdev->id_entry = of_id->data; - imx_data->devtype = pdev->id_entry->driver_data; - pltfm_host->priv = imx_data; - - clk = clk_get(mmc_dev(host->mmc), NULL); - if (IS_ERR(clk)) { - dev_err(mmc_dev(host->mmc), "clk err\n"); - err = PTR_ERR(clk); - goto err_clk_get; - } - clk_prepare_enable(clk); - pltfm_host->clk = clk; - - host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL; - - if (is_imx25_esdhc(imx_data) || is_imx35_esdhc(imx_data)) - /* Fix errata ENGcm07207 present on i.MX25 and i.MX35 */ - host->quirks |= SDHCI_QUIRK_NO_MULTIBLOCK - | SDHCI_QUIRK_BROKEN_ADMA; - - if (is_imx53_esdhc(imx_data)) - imx_data->flags |= ESDHC_FLAG_MULTIBLK_NO_INT; - - /* - * The imx6q ROM code will change the default watermark level setting - * to something insane. Change it back here. - */ - if (is_imx6q_usdhc(imx_data)) - writel(0x08100810, host->ioaddr + SDHCI_WTMK_LVL); - - boarddata = &imx_data->boarddata; - if (sdhci_esdhc_imx_probe_dt(pdev, boarddata) < 0) { - if (!host->mmc->parent->platform_data) { - dev_err(mmc_dev(host->mmc), "no board data!\n"); - err = -EINVAL; - goto no_board_data; - } - imx_data->boarddata = *((struct esdhc_platform_data *) - host->mmc->parent->platform_data); - } - - /* write_protect */ - if (boarddata->wp_type == ESDHC_WP_GPIO) { - err = gpio_request_one(boarddata->wp_gpio, GPIOF_IN, "ESDHC_WP"); - if (err) { - dev_warn(mmc_dev(host->mmc), - "no write-protect pin available!\n"); - boarddata->wp_gpio = -EINVAL; - } - } else { - boarddata->wp_gpio = -EINVAL; - } - - /* card_detect */ - if (boarddata->cd_type != ESDHC_CD_GPIO) - boarddata->cd_gpio = -EINVAL; - - switch (boarddata->cd_type) { - case ESDHC_CD_GPIO: - err = gpio_request_one(boarddata->cd_gpio, GPIOF_IN, "ESDHC_CD"); - if (err) { - dev_err(mmc_dev(host->mmc), - "no card-detect pin available!\n"); - goto no_card_detect_pin; - } - - err = request_irq(gpio_to_irq(boarddata->cd_gpio), cd_irq, - IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, - mmc_hostname(host->mmc), host); - if (err) { - dev_err(mmc_dev(host->mmc), "request irq error\n"); - goto no_card_detect_irq; - } - /* fall through */ - - case ESDHC_CD_CONTROLLER: - /* we have a working card_detect back */ - host->quirks &= ~SDHCI_QUIRK_BROKEN_CARD_DETECTION; - break; - - case ESDHC_CD_PERMANENT: - host->mmc->caps = MMC_CAP_NONREMOVABLE; - break; - - case ESDHC_CD_NONE: - break; - } - - err = sdhci_add_host(host); - if (err) - goto err_add_host; - - return 0; - -err_add_host: - if (gpio_is_valid(boarddata->cd_gpio)) - free_irq(gpio_to_irq(boarddata->cd_gpio), host); -no_card_detect_irq: - if (gpio_is_valid(boarddata->cd_gpio)) - gpio_free(boarddata->cd_gpio); - if (gpio_is_valid(boarddata->wp_gpio)) - gpio_free(boarddata->wp_gpio); -no_card_detect_pin: -no_board_data: - clk_disable_unprepare(pltfm_host->clk); - clk_put(pltfm_host->clk); -err_clk_get: - kfree(imx_data); -err_imx_data: - sdhci_pltfm_free(pdev); - return err; -} - -static int __devexit sdhci_esdhc_imx_remove(struct platform_device *pdev) -{ - struct sdhci_host *host = platform_get_drvdata(pdev); - struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - struct pltfm_imx_data *imx_data = pltfm_host->priv; - struct esdhc_platform_data *boarddata = &imx_data->boarddata; - int dead = (readl(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff); - - sdhci_remove_host(host, dead); - - if (gpio_is_valid(boarddata->wp_gpio)) - gpio_free(boarddata->wp_gpio); - - if (gpio_is_valid(boarddata->cd_gpio)) { - free_irq(gpio_to_irq(boarddata->cd_gpio), host); - gpio_free(boarddata->cd_gpio); - } - - clk_disable_unprepare(pltfm_host->clk); - clk_put(pltfm_host->clk); - kfree(imx_data); - - sdhci_pltfm_free(pdev); - - return 0; -} - -static struct platform_driver sdhci_esdhc_imx_driver = { - .driver = { - .name = "sdhci-esdhc-imx", - .owner = THIS_MODULE, - .of_match_table = imx_esdhc_dt_ids, - .pm = SDHCI_PLTFM_PMOPS, - }, - .id_table = imx_esdhc_devtype, - .probe = sdhci_esdhc_imx_probe, - .remove = __devexit_p(sdhci_esdhc_imx_remove), -}; - -module_platform_driver(sdhci_esdhc_imx_driver); - -MODULE_DESCRIPTION("SDHCI driver for Freescale i.MX eSDHC"); -MODULE_AUTHOR("Wolfram Sang <w.sang@pengutronix.de>"); -MODULE_LICENSE("GPL v2"); diff --git a/ANDROID_3.4.5/drivers/mmc/host/sdhci-esdhc.h b/ANDROID_3.4.5/drivers/mmc/host/sdhci-esdhc.h deleted file mode 100644 index b97b2f5d..00000000 --- a/ANDROID_3.4.5/drivers/mmc/host/sdhci-esdhc.h +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Freescale eSDHC controller driver generics for OF and pltfm. - * - * Copyright (c) 2007 Freescale Semiconductor, Inc. - * Copyright (c) 2009 MontaVista Software, Inc. - * Copyright (c) 2010 Pengutronix e.K. - * Author: Wolfram Sang <w.sang@pengutronix.de> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License. - */ - -#ifndef _DRIVERS_MMC_SDHCI_ESDHC_H -#define _DRIVERS_MMC_SDHCI_ESDHC_H - -/* - * Ops and quirks for the Freescale eSDHC controller. - */ - -#define ESDHC_DEFAULT_QUIRKS (SDHCI_QUIRK_FORCE_BLK_SZ_2048 | \ - SDHCI_QUIRK_NO_BUSY_IRQ | \ - SDHCI_QUIRK_NONSTANDARD_CLOCK | \ - SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK | \ - SDHCI_QUIRK_PIO_NEEDS_DELAY | \ - SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET) - -#define ESDHC_SYSTEM_CONTROL 0x2c -#define ESDHC_CLOCK_MASK 0x0000fff0 -#define ESDHC_PREDIV_SHIFT 8 -#define ESDHC_DIVIDER_SHIFT 4 -#define ESDHC_CLOCK_PEREN 0x00000004 -#define ESDHC_CLOCK_HCKEN 0x00000002 -#define ESDHC_CLOCK_IPGEN 0x00000001 - -/* pltfm-specific */ -#define ESDHC_HOST_CONTROL_LE 0x20 - -/* OF-specific */ -#define ESDHC_DMA_SYSCTL 0x40c -#define ESDHC_DMA_SNOOP 0x00000040 - -#define ESDHC_HOST_CONTROL_RES 0x05 - -static inline void esdhc_set_clock(struct sdhci_host *host, unsigned int clock) -{ - int pre_div = 2; - int div = 1; - u32 temp; - - temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL); - temp &= ~(ESDHC_CLOCK_IPGEN | ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN - | ESDHC_CLOCK_MASK); - sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL); - - if (clock == 0) - goto out; - - while (host->max_clk / pre_div / 16 > clock && pre_div < 256) - pre_div *= 2; - - while (host->max_clk / pre_div / div > clock && div < 16) - div++; - - dev_dbg(mmc_dev(host->mmc), "desired SD clock: %d, actual: %d\n", - clock, host->max_clk / pre_div / div); - - pre_div >>= 1; - div--; - - temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL); - temp |= (ESDHC_CLOCK_IPGEN | ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN - | (div << ESDHC_DIVIDER_SHIFT) - | (pre_div << ESDHC_PREDIV_SHIFT)); - sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL); - mdelay(1); -out: - host->clock = clock; -} - -#endif /* _DRIVERS_MMC_SDHCI_ESDHC_H */ diff --git a/ANDROID_3.4.5/drivers/mmc/host/sdhci-of-esdhc.c b/ANDROID_3.4.5/drivers/mmc/host/sdhci-of-esdhc.c deleted file mode 100644 index f8eb1fb0..00000000 --- a/ANDROID_3.4.5/drivers/mmc/host/sdhci-of-esdhc.c +++ /dev/null @@ -1,204 +0,0 @@ -/* - * Freescale eSDHC controller driver. - * - * Copyright (c) 2007, 2010, 2012 Freescale Semiconductor, Inc. - * Copyright (c) 2009 MontaVista Software, Inc. - * - * Authors: Xiaobo Xie <X.Xie@freescale.com> - * Anton Vorontsov <avorontsov@ru.mvista.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at - * your option) any later version. - */ - -#include <linux/io.h> -#include <linux/of.h> -#include <linux/delay.h> -#include <linux/module.h> -#include <linux/mmc/host.h> -#include "sdhci-pltfm.h" -#include "sdhci-esdhc.h" - -static u16 esdhc_readw(struct sdhci_host *host, int reg) -{ - u16 ret; - int base = reg & ~0x3; - int shift = (reg & 0x2) * 8; - - if (unlikely(reg == SDHCI_HOST_VERSION)) - ret = in_be32(host->ioaddr + base) & 0xffff; - else - ret = (in_be32(host->ioaddr + base) >> shift) & 0xffff; - return ret; -} - -static u8 esdhc_readb(struct sdhci_host *host, int reg) -{ - int base = reg & ~0x3; - int shift = (reg & 0x3) * 8; - u8 ret = (in_be32(host->ioaddr + base) >> shift) & 0xff; - - /* - * "DMA select" locates at offset 0x28 in SD specification, but on - * P5020 or P3041, it locates at 0x29. - */ - if (reg == SDHCI_HOST_CONTROL) { - u32 dma_bits; - - dma_bits = in_be32(host->ioaddr + reg); - /* DMA select is 22,23 bits in Protocol Control Register */ - dma_bits = (dma_bits >> 5) & SDHCI_CTRL_DMA_MASK; - - /* fixup the result */ - ret &= ~SDHCI_CTRL_DMA_MASK; - ret |= dma_bits; - } - - return ret; -} - -static void esdhc_writew(struct sdhci_host *host, u16 val, int reg) -{ - if (reg == SDHCI_BLOCK_SIZE) { - /* - * Two last DMA bits are reserved, and first one is used for - * non-standard blksz of 4096 bytes that we don't support - * yet. So clear the DMA boundary bits. - */ - val &= ~SDHCI_MAKE_BLKSZ(0x7, 0); - } - sdhci_be32bs_writew(host, val, reg); -} - -static void esdhc_writeb(struct sdhci_host *host, u8 val, int reg) -{ - /* - * "DMA select" location is offset 0x28 in SD specification, but on - * P5020 or P3041, it's located at 0x29. - */ - if (reg == SDHCI_HOST_CONTROL) { - u32 dma_bits; - - /* DMA select is 22,23 bits in Protocol Control Register */ - dma_bits = (val & SDHCI_CTRL_DMA_MASK) << 5; - clrsetbits_be32(host->ioaddr + reg , SDHCI_CTRL_DMA_MASK << 5, - dma_bits); - val &= ~SDHCI_CTRL_DMA_MASK; - val |= in_be32(host->ioaddr + reg) & SDHCI_CTRL_DMA_MASK; - } - - /* Prevent SDHCI core from writing reserved bits (e.g. HISPD). */ - if (reg == SDHCI_HOST_CONTROL) - val &= ~ESDHC_HOST_CONTROL_RES; - sdhci_be32bs_writeb(host, val, reg); -} - -static int esdhc_of_enable_dma(struct sdhci_host *host) -{ - setbits32(host->ioaddr + ESDHC_DMA_SYSCTL, ESDHC_DMA_SNOOP); - return 0; -} - -static unsigned int esdhc_of_get_max_clock(struct sdhci_host *host) -{ - struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - - return pltfm_host->clock; -} - -static unsigned int esdhc_of_get_min_clock(struct sdhci_host *host) -{ - struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - - return pltfm_host->clock / 256 / 16; -} - -static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock) -{ - /* Workaround to reduce the clock frequency for p1010 esdhc */ - if (of_find_compatible_node(NULL, NULL, "fsl,p1010-esdhc")) { - if (clock > 20000000) - clock -= 5000000; - if (clock > 40000000) - clock -= 5000000; - } - - /* Set the clock */ - esdhc_set_clock(host, clock); -} - -#ifdef CONFIG_PM -static u32 esdhc_proctl; -static void esdhc_of_suspend(struct sdhci_host *host) -{ - esdhc_proctl = sdhci_be32bs_readl(host, SDHCI_HOST_CONTROL); -} - -static void esdhc_of_resume(struct sdhci_host *host) -{ - esdhc_of_enable_dma(host); - sdhci_be32bs_writel(host, esdhc_proctl, SDHCI_HOST_CONTROL); -} -#endif - -static struct sdhci_ops sdhci_esdhc_ops = { - .read_l = sdhci_be32bs_readl, - .read_w = esdhc_readw, - .read_b = esdhc_readb, - .write_l = sdhci_be32bs_writel, - .write_w = esdhc_writew, - .write_b = esdhc_writeb, - .set_clock = esdhc_of_set_clock, - .enable_dma = esdhc_of_enable_dma, - .get_max_clock = esdhc_of_get_max_clock, - .get_min_clock = esdhc_of_get_min_clock, -#ifdef CONFIG_PM - .platform_suspend = esdhc_of_suspend, - .platform_resume = esdhc_of_resume, -#endif -}; - -static struct sdhci_pltfm_data sdhci_esdhc_pdata = { - /* card detection could be handled via GPIO */ - .quirks = ESDHC_DEFAULT_QUIRKS | SDHCI_QUIRK_BROKEN_CARD_DETECTION - | SDHCI_QUIRK_NO_CARD_NO_RESET, - .ops = &sdhci_esdhc_ops, -}; - -static int __devinit sdhci_esdhc_probe(struct platform_device *pdev) -{ - return sdhci_pltfm_register(pdev, &sdhci_esdhc_pdata); -} - -static int __devexit sdhci_esdhc_remove(struct platform_device *pdev) -{ - return sdhci_pltfm_unregister(pdev); -} - -static const struct of_device_id sdhci_esdhc_of_match[] = { - { .compatible = "fsl,mpc8379-esdhc" }, - { .compatible = "fsl,mpc8536-esdhc" }, - { .compatible = "fsl,esdhc" }, - { } -}; -MODULE_DEVICE_TABLE(of, sdhci_esdhc_of_match); - -static struct platform_driver sdhci_esdhc_driver = { - .driver = { - .name = "sdhci-esdhc", - .owner = THIS_MODULE, - .of_match_table = sdhci_esdhc_of_match, - .pm = SDHCI_PLTFM_PMOPS, - }, - .probe = sdhci_esdhc_probe, - .remove = __devexit_p(sdhci_esdhc_remove), -}; - -module_platform_driver(sdhci_esdhc_driver); - -MODULE_DESCRIPTION("SDHCI OF driver for Freescale MPC eSDHC"); -MODULE_AUTHOR("Xiaobo Xie <X.Xie@freescale.com>, " - "Anton Vorontsov <avorontsov@ru.mvista.com>"); -MODULE_LICENSE("GPL v2"); diff --git a/ANDROID_3.4.5/drivers/mmc/host/sdhci-of-hlwd.c b/ANDROID_3.4.5/drivers/mmc/host/sdhci-of-hlwd.c deleted file mode 100644 index 0ce088ae..00000000 --- a/ANDROID_3.4.5/drivers/mmc/host/sdhci-of-hlwd.c +++ /dev/null @@ -1,100 +0,0 @@ -/* - * drivers/mmc/host/sdhci-of-hlwd.c - * - * Nintendo Wii Secure Digital Host Controller Interface. - * Copyright (C) 2009 The GameCube Linux Team - * Copyright (C) 2009 Albert Herranz - * - * Based on sdhci-of-esdhc.c - * - * Copyright (c) 2007 Freescale Semiconductor, Inc. - * Copyright (c) 2009 MontaVista Software, Inc. - * - * Authors: Xiaobo Xie <X.Xie@freescale.com> - * Anton Vorontsov <avorontsov@ru.mvista.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at - * your option) any later version. - */ - -#include <linux/delay.h> -#include <linux/module.h> -#include <linux/mmc/host.h> -#include "sdhci-pltfm.h" - -/* - * Ops and quirks for the Nintendo Wii SDHCI controllers. - */ - -/* - * We need a small delay after each write, or things go horribly wrong. - */ -#define SDHCI_HLWD_WRITE_DELAY 5 /* usecs */ - -static void sdhci_hlwd_writel(struct sdhci_host *host, u32 val, int reg) -{ - sdhci_be32bs_writel(host, val, reg); - udelay(SDHCI_HLWD_WRITE_DELAY); -} - -static void sdhci_hlwd_writew(struct sdhci_host *host, u16 val, int reg) -{ - sdhci_be32bs_writew(host, val, reg); - udelay(SDHCI_HLWD_WRITE_DELAY); -} - -static void sdhci_hlwd_writeb(struct sdhci_host *host, u8 val, int reg) -{ - sdhci_be32bs_writeb(host, val, reg); - udelay(SDHCI_HLWD_WRITE_DELAY); -} - -static struct sdhci_ops sdhci_hlwd_ops = { - .read_l = sdhci_be32bs_readl, - .read_w = sdhci_be32bs_readw, - .read_b = sdhci_be32bs_readb, - .write_l = sdhci_hlwd_writel, - .write_w = sdhci_hlwd_writew, - .write_b = sdhci_hlwd_writeb, -}; - -static struct sdhci_pltfm_data sdhci_hlwd_pdata = { - .quirks = SDHCI_QUIRK_32BIT_DMA_ADDR | - SDHCI_QUIRK_32BIT_DMA_SIZE, - .ops = &sdhci_hlwd_ops, -}; - -static int __devinit sdhci_hlwd_probe(struct platform_device *pdev) -{ - return sdhci_pltfm_register(pdev, &sdhci_hlwd_pdata); -} - -static int __devexit sdhci_hlwd_remove(struct platform_device *pdev) -{ - return sdhci_pltfm_unregister(pdev); -} - -static const struct of_device_id sdhci_hlwd_of_match[] = { - { .compatible = "nintendo,hollywood-sdhci" }, - { } -}; -MODULE_DEVICE_TABLE(of, sdhci_hlwd_of_match); - -static struct platform_driver sdhci_hlwd_driver = { - .driver = { - .name = "sdhci-hlwd", - .owner = THIS_MODULE, - .of_match_table = sdhci_hlwd_of_match, - .pm = SDHCI_PLTFM_PMOPS, - }, - .probe = sdhci_hlwd_probe, - .remove = __devexit_p(sdhci_hlwd_remove), -}; - -module_platform_driver(sdhci_hlwd_driver); - -MODULE_DESCRIPTION("Nintendo Wii SDHCI OF driver"); -MODULE_AUTHOR("The GameCube Linux Team, Albert Herranz"); -MODULE_LICENSE("GPL v2"); diff --git a/ANDROID_3.4.5/drivers/mmc/host/sdhci-pci-data.c b/ANDROID_3.4.5/drivers/mmc/host/sdhci-pci-data.c deleted file mode 100644 index a6112177..00000000 --- a/ANDROID_3.4.5/drivers/mmc/host/sdhci-pci-data.c +++ /dev/null @@ -1,5 +0,0 @@ -#include <linux/module.h> -#include <linux/mmc/sdhci-pci-data.h> - -struct sdhci_pci_data *(*sdhci_pci_get_data)(struct pci_dev *pdev, int slotno); -EXPORT_SYMBOL_GPL(sdhci_pci_get_data); diff --git a/ANDROID_3.4.5/drivers/mmc/host/sdhci-pci.c b/ANDROID_3.4.5/drivers/mmc/host/sdhci-pci.c deleted file mode 100644 index 69ef0bea..00000000 --- a/ANDROID_3.4.5/drivers/mmc/host/sdhci-pci.c +++ /dev/null @@ -1,1499 +0,0 @@ -/* linux/drivers/mmc/host/sdhci-pci.c - SDHCI on PCI bus interface - * - * Copyright (C) 2005-2008 Pierre Ossman, All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at - * your option) any later version. - * - * Thanks to the following companies for their support: - * - * - JMicron (hardware and technical support) - */ - -#include <linux/delay.h> -#include <linux/highmem.h> -#include <linux/module.h> -#include <linux/pci.h> -#include <linux/dma-mapping.h> -#include <linux/slab.h> -#include <linux/device.h> -#include <linux/mmc/host.h> -#include <linux/scatterlist.h> -#include <linux/io.h> -#include <linux/gpio.h> -#include <linux/pm_runtime.h> -#include <linux/mmc/sdhci-pci-data.h> - -#include "sdhci.h" - -/* - * PCI device IDs - */ -#define PCI_DEVICE_ID_INTEL_PCH_SDIO0 0x8809 -#define PCI_DEVICE_ID_INTEL_PCH_SDIO1 0x880a - -/* - * PCI registers - */ - -#define PCI_SDHCI_IFPIO 0x00 -#define PCI_SDHCI_IFDMA 0x01 -#define PCI_SDHCI_IFVENDOR 0x02 - -#define PCI_SLOT_INFO 0x40 /* 8 bits */ -#define PCI_SLOT_INFO_SLOTS(x) ((x >> 4) & 7) -#define PCI_SLOT_INFO_FIRST_BAR_MASK 0x07 - -#define MAX_SLOTS 8 - -struct sdhci_pci_chip; -struct sdhci_pci_slot; - -struct sdhci_pci_fixes { - unsigned int quirks; - unsigned int quirks2; - bool allow_runtime_pm; - - int (*probe) (struct sdhci_pci_chip *); - - int (*probe_slot) (struct sdhci_pci_slot *); - void (*remove_slot) (struct sdhci_pci_slot *, int); - - int (*suspend) (struct sdhci_pci_chip *); - int (*resume) (struct sdhci_pci_chip *); -}; - -struct sdhci_pci_slot { - struct sdhci_pci_chip *chip; - struct sdhci_host *host; - struct sdhci_pci_data *data; - - int pci_bar; - int rst_n_gpio; - int cd_gpio; - int cd_irq; -}; - -struct sdhci_pci_chip { - struct pci_dev *pdev; - - unsigned int quirks; - unsigned int quirks2; - bool allow_runtime_pm; - const struct sdhci_pci_fixes *fixes; - - int num_slots; /* Slots on controller */ - struct sdhci_pci_slot *slots[MAX_SLOTS]; /* Pointers to host slots */ -}; - - -/*****************************************************************************\ - * * - * Hardware specific quirk handling * - * * -\*****************************************************************************/ - -static int ricoh_probe(struct sdhci_pci_chip *chip) -{ - if (chip->pdev->subsystem_vendor == PCI_VENDOR_ID_SAMSUNG || - chip->pdev->subsystem_vendor == PCI_VENDOR_ID_SONY) - chip->quirks |= SDHCI_QUIRK_NO_CARD_NO_RESET; - return 0; -} - -static int ricoh_mmc_probe_slot(struct sdhci_pci_slot *slot) -{ - slot->host->caps = - ((0x21 << SDHCI_TIMEOUT_CLK_SHIFT) - & SDHCI_TIMEOUT_CLK_MASK) | - - ((0x21 << SDHCI_CLOCK_BASE_SHIFT) - & SDHCI_CLOCK_BASE_MASK) | - - SDHCI_TIMEOUT_CLK_UNIT | - SDHCI_CAN_VDD_330 | - SDHCI_CAN_DO_SDMA; - return 0; -} - -static int ricoh_mmc_resume(struct sdhci_pci_chip *chip) -{ - /* Apply a delay to allow controller to settle */ - /* Otherwise it becomes confused if card state changed - during suspend */ - msleep(500); - return 0; -} - -static const struct sdhci_pci_fixes sdhci_ricoh = { - .probe = ricoh_probe, - .quirks = SDHCI_QUIRK_32BIT_DMA_ADDR | - SDHCI_QUIRK_FORCE_DMA | - SDHCI_QUIRK_CLOCK_BEFORE_RESET, -}; - -static const struct sdhci_pci_fixes sdhci_ricoh_mmc = { - .probe_slot = ricoh_mmc_probe_slot, - .resume = ricoh_mmc_resume, - .quirks = SDHCI_QUIRK_32BIT_DMA_ADDR | - SDHCI_QUIRK_CLOCK_BEFORE_RESET | - SDHCI_QUIRK_NO_CARD_NO_RESET | - SDHCI_QUIRK_MISSING_CAPS -}; - -static const struct sdhci_pci_fixes sdhci_ene_712 = { - .quirks = SDHCI_QUIRK_SINGLE_POWER_WRITE | - SDHCI_QUIRK_BROKEN_DMA, -}; - -static const struct sdhci_pci_fixes sdhci_ene_714 = { - .quirks = SDHCI_QUIRK_SINGLE_POWER_WRITE | - SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS | - SDHCI_QUIRK_BROKEN_DMA, -}; - -static const struct sdhci_pci_fixes sdhci_cafe = { - .quirks = SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER | - SDHCI_QUIRK_NO_BUSY_IRQ | - SDHCI_QUIRK_BROKEN_TIMEOUT_VAL, -}; - -static int mrst_hc_probe_slot(struct sdhci_pci_slot *slot) -{ - slot->host->mmc->caps |= MMC_CAP_8_BIT_DATA; - return 0; -} - -/* - * ADMA operation is disabled for Moorestown platform due to - * hardware bugs. - */ -static int mrst_hc_probe(struct sdhci_pci_chip *chip) -{ - /* - * slots number is fixed here for MRST as SDIO3/5 are never used and - * have hardware bugs. - */ - chip->num_slots = 1; - return 0; -} - -static int pch_hc_probe_slot(struct sdhci_pci_slot *slot) -{ - slot->host->mmc->caps |= MMC_CAP_8_BIT_DATA; - return 0; -} - -#ifdef CONFIG_PM_RUNTIME - -static irqreturn_t sdhci_pci_sd_cd(int irq, void *dev_id) -{ - struct sdhci_pci_slot *slot = dev_id; - struct sdhci_host *host = slot->host; - - mmc_detect_change(host->mmc, msecs_to_jiffies(200)); - return IRQ_HANDLED; -} - -static void sdhci_pci_add_own_cd(struct sdhci_pci_slot *slot) -{ - int err, irq, gpio = slot->cd_gpio; - - slot->cd_gpio = -EINVAL; - slot->cd_irq = -EINVAL; - - if (!gpio_is_valid(gpio)) - return; - - err = gpio_request(gpio, "sd_cd"); - if (err < 0) - goto out; - - err = gpio_direction_input(gpio); - if (err < 0) - goto out_free; - - irq = gpio_to_irq(gpio); - if (irq < 0) - goto out_free; - - err = request_irq(irq, sdhci_pci_sd_cd, IRQF_TRIGGER_RISING | - IRQF_TRIGGER_FALLING, "sd_cd", slot); - if (err) - goto out_free; - - slot->cd_gpio = gpio; - slot->cd_irq = irq; - - return; - -out_free: - gpio_free(gpio); -out: - dev_warn(&slot->chip->pdev->dev, "failed to setup card detect wake up\n"); -} - -static void sdhci_pci_remove_own_cd(struct sdhci_pci_slot *slot) -{ - if (slot->cd_irq >= 0) - free_irq(slot->cd_irq, slot); - if (gpio_is_valid(slot->cd_gpio)) - gpio_free(slot->cd_gpio); -} - -#else - -static inline void sdhci_pci_add_own_cd(struct sdhci_pci_slot *slot) -{ -} - -static inline void sdhci_pci_remove_own_cd(struct sdhci_pci_slot *slot) -{ -} - -#endif - -static int mfd_emmc_probe_slot(struct sdhci_pci_slot *slot) -{ - slot->host->mmc->caps |= MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE; - slot->host->mmc->caps2 |= MMC_CAP2_BOOTPART_NOACC | - MMC_CAP2_HC_ERASE_SZ; - return 0; -} - -static int mfd_sdio_probe_slot(struct sdhci_pci_slot *slot) -{ - slot->host->mmc->caps |= MMC_CAP_POWER_OFF_CARD | MMC_CAP_NONREMOVABLE; - return 0; -} - -static const struct sdhci_pci_fixes sdhci_intel_mrst_hc0 = { - .quirks = SDHCI_QUIRK_BROKEN_ADMA | SDHCI_QUIRK_NO_HISPD_BIT, - .probe_slot = mrst_hc_probe_slot, -}; - -static const struct sdhci_pci_fixes sdhci_intel_mrst_hc1_hc2 = { - .quirks = SDHCI_QUIRK_BROKEN_ADMA | SDHCI_QUIRK_NO_HISPD_BIT, - .probe = mrst_hc_probe, -}; - -static const struct sdhci_pci_fixes sdhci_intel_mfd_sd = { - .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, - .allow_runtime_pm = true, -}; - -static const struct sdhci_pci_fixes sdhci_intel_mfd_sdio = { - .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, - .quirks2 = SDHCI_QUIRK2_HOST_OFF_CARD_ON, - .allow_runtime_pm = true, - .probe_slot = mfd_sdio_probe_slot, -}; - -static const struct sdhci_pci_fixes sdhci_intel_mfd_emmc = { - .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, - .allow_runtime_pm = true, - .probe_slot = mfd_emmc_probe_slot, -}; - -static const struct sdhci_pci_fixes sdhci_intel_pch_sdio = { - .quirks = SDHCI_QUIRK_BROKEN_ADMA, - .probe_slot = pch_hc_probe_slot, -}; - -/* O2Micro extra registers */ -#define O2_SD_LOCK_WP 0xD3 -#define O2_SD_MULTI_VCC3V 0xEE -#define O2_SD_CLKREQ 0xEC -#define O2_SD_CAPS 0xE0 -#define O2_SD_ADMA1 0xE2 -#define O2_SD_ADMA2 0xE7 -#define O2_SD_INF_MOD 0xF1 - -static int o2_probe(struct sdhci_pci_chip *chip) -{ - int ret; - u8 scratch; - - switch (chip->pdev->device) { - case PCI_DEVICE_ID_O2_8220: - case PCI_DEVICE_ID_O2_8221: - case PCI_DEVICE_ID_O2_8320: - case PCI_DEVICE_ID_O2_8321: - /* This extra setup is required due to broken ADMA. */ - ret = pci_read_config_byte(chip->pdev, O2_SD_LOCK_WP, &scratch); - if (ret) - return ret; - scratch &= 0x7f; - pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch); - - /* Set Multi 3 to VCC3V# */ - pci_write_config_byte(chip->pdev, O2_SD_MULTI_VCC3V, 0x08); - - /* Disable CLK_REQ# support after media DET */ - ret = pci_read_config_byte(chip->pdev, O2_SD_CLKREQ, &scratch); - if (ret) - return ret; - scratch |= 0x20; - pci_write_config_byte(chip->pdev, O2_SD_CLKREQ, scratch); - - /* Choose capabilities, enable SDMA. We have to write 0x01 - * to the capabilities register first to unlock it. - */ - ret = pci_read_config_byte(chip->pdev, O2_SD_CAPS, &scratch); - if (ret) - return ret; - scratch |= 0x01; - pci_write_config_byte(chip->pdev, O2_SD_CAPS, scratch); - pci_write_config_byte(chip->pdev, O2_SD_CAPS, 0x73); - - /* Disable ADMA1/2 */ - pci_write_config_byte(chip->pdev, O2_SD_ADMA1, 0x39); - pci_write_config_byte(chip->pdev, O2_SD_ADMA2, 0x08); - - /* Disable the infinite transfer mode */ - ret = pci_read_config_byte(chip->pdev, O2_SD_INF_MOD, &scratch); - if (ret) - return ret; - scratch |= 0x08; - pci_write_config_byte(chip->pdev, O2_SD_INF_MOD, scratch); - - /* Lock WP */ - ret = pci_read_config_byte(chip->pdev, O2_SD_LOCK_WP, &scratch); - if (ret) - return ret; - scratch |= 0x80; - pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch); - } - - return 0; -} - -static int jmicron_pmos(struct sdhci_pci_chip *chip, int on) -{ - u8 scratch; - int ret; - - ret = pci_read_config_byte(chip->pdev, 0xAE, &scratch); - if (ret) - return ret; - - /* - * Turn PMOS on [bit 0], set over current detection to 2.4 V - * [bit 1:2] and enable over current debouncing [bit 6]. - */ - if (on) - scratch |= 0x47; - else - scratch &= ~0x47; - - ret = pci_write_config_byte(chip->pdev, 0xAE, scratch); - if (ret) - return ret; - - return 0; -} - -static int jmicron_probe(struct sdhci_pci_chip *chip) -{ - int ret; - u16 mmcdev = 0; - - if (chip->pdev->revision == 0) { - chip->quirks |= SDHCI_QUIRK_32BIT_DMA_ADDR | - SDHCI_QUIRK_32BIT_DMA_SIZE | - SDHCI_QUIRK_32BIT_ADMA_SIZE | - SDHCI_QUIRK_RESET_AFTER_REQUEST | - SDHCI_QUIRK_BROKEN_SMALL_PIO; - } - - /* - * JMicron chips can have two interfaces to the same hardware - * in order to work around limitations in Microsoft's driver. - * We need to make sure we only bind to one of them. - * - * This code assumes two things: - * - * 1. The PCI code adds subfunctions in order. - * - * 2. The MMC interface has a lower subfunction number - * than the SD interface. - */ - if (chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB38X_SD) - mmcdev = PCI_DEVICE_ID_JMICRON_JMB38X_MMC; - else if (chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB388_SD) - mmcdev = PCI_DEVICE_ID_JMICRON_JMB388_ESD; - - if (mmcdev) { - struct pci_dev *sd_dev; - - sd_dev = NULL; - while ((sd_dev = pci_get_device(PCI_VENDOR_ID_JMICRON, - mmcdev, sd_dev)) != NULL) { - if ((PCI_SLOT(chip->pdev->devfn) == - PCI_SLOT(sd_dev->devfn)) && - (chip->pdev->bus == sd_dev->bus)) - break; - } - - if (sd_dev) { - pci_dev_put(sd_dev); - dev_info(&chip->pdev->dev, "Refusing to bind to " - "secondary interface.\n"); - return -ENODEV; - } - } - - /* - * JMicron chips need a bit of a nudge to enable the power - * output pins. - */ - ret = jmicron_pmos(chip, 1); - if (ret) { - dev_err(&chip->pdev->dev, "Failure enabling card power\n"); - return ret; - } - - /* quirk for unsable RO-detection on JM388 chips */ - if (chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB388_SD || - chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB388_ESD) - chip->quirks |= SDHCI_QUIRK_UNSTABLE_RO_DETECT; - - return 0; -} - -static void jmicron_enable_mmc(struct sdhci_host *host, int on) -{ - u8 scratch; - - scratch = readb(host->ioaddr + 0xC0); - - if (on) - scratch |= 0x01; - else - scratch &= ~0x01; - - writeb(scratch, host->ioaddr + 0xC0); -} - -static int jmicron_probe_slot(struct sdhci_pci_slot *slot) -{ - if (slot->chip->pdev->revision == 0) { - u16 version; - - version = readl(slot->host->ioaddr + SDHCI_HOST_VERSION); - version = (version & SDHCI_VENDOR_VER_MASK) >> - SDHCI_VENDOR_VER_SHIFT; - - /* - * Older versions of the chip have lots of nasty glitches - * in the ADMA engine. It's best just to avoid it - * completely. - */ - if (version < 0xAC) - slot->host->quirks |= SDHCI_QUIRK_BROKEN_ADMA; - } - - /* JM388 MMC doesn't support 1.8V while SD supports it */ - if (slot->chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB388_ESD) { - slot->host->ocr_avail_sd = MMC_VDD_32_33 | MMC_VDD_33_34 | - MMC_VDD_29_30 | MMC_VDD_30_31 | - MMC_VDD_165_195; /* allow 1.8V */ - slot->host->ocr_avail_mmc = MMC_VDD_32_33 | MMC_VDD_33_34 | - MMC_VDD_29_30 | MMC_VDD_30_31; /* no 1.8V for MMC */ - } - - /* - * The secondary interface requires a bit set to get the - * interrupts. - */ - if (slot->chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB38X_MMC || - slot->chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB388_ESD) - jmicron_enable_mmc(slot->host, 1); - - slot->host->mmc->caps |= MMC_CAP_BUS_WIDTH_TEST; - - return 0; -} - -static void jmicron_remove_slot(struct sdhci_pci_slot *slot, int dead) -{ - if (dead) - return; - - if (slot->chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB38X_MMC || - slot->chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB388_ESD) - jmicron_enable_mmc(slot->host, 0); -} - -static int jmicron_suspend(struct sdhci_pci_chip *chip) -{ - int i; - - if (chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB38X_MMC || - chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB388_ESD) { - for (i = 0; i < chip->num_slots; i++) - jmicron_enable_mmc(chip->slots[i]->host, 0); - } - - return 0; -} - -static int jmicron_resume(struct sdhci_pci_chip *chip) -{ - int ret, i; - - if (chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB38X_MMC || - chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB388_ESD) { - for (i = 0; i < chip->num_slots; i++) - jmicron_enable_mmc(chip->slots[i]->host, 1); - } - - ret = jmicron_pmos(chip, 1); - if (ret) { - dev_err(&chip->pdev->dev, "Failure enabling card power\n"); - return ret; - } - - return 0; -} - -static const struct sdhci_pci_fixes sdhci_o2 = { - .probe = o2_probe, -}; - -static const struct sdhci_pci_fixes sdhci_jmicron = { - .probe = jmicron_probe, - - .probe_slot = jmicron_probe_slot, - .remove_slot = jmicron_remove_slot, - - .suspend = jmicron_suspend, - .resume = jmicron_resume, -}; - -/* SysKonnect CardBus2SDIO extra registers */ -#define SYSKT_CTRL 0x200 -#define SYSKT_RDFIFO_STAT 0x204 -#define SYSKT_WRFIFO_STAT 0x208 -#define SYSKT_POWER_DATA 0x20c -#define SYSKT_POWER_330 0xef -#define SYSKT_POWER_300 0xf8 -#define SYSKT_POWER_184 0xcc -#define SYSKT_POWER_CMD 0x20d -#define SYSKT_POWER_START (1 << 7) -#define SYSKT_POWER_STATUS 0x20e -#define SYSKT_POWER_STATUS_OK (1 << 0) -#define SYSKT_BOARD_REV 0x210 -#define SYSKT_CHIP_REV 0x211 -#define SYSKT_CONF_DATA 0x212 -#define SYSKT_CONF_DATA_1V8 (1 << 2) -#define SYSKT_CONF_DATA_2V5 (1 << 1) -#define SYSKT_CONF_DATA_3V3 (1 << 0) - -static int syskt_probe(struct sdhci_pci_chip *chip) -{ - if ((chip->pdev->class & 0x0000FF) == PCI_SDHCI_IFVENDOR) { - chip->pdev->class &= ~0x0000FF; - chip->pdev->class |= PCI_SDHCI_IFDMA; - } - return 0; -} - -static int syskt_probe_slot(struct sdhci_pci_slot *slot) -{ - int tm, ps; - - u8 board_rev = readb(slot->host->ioaddr + SYSKT_BOARD_REV); - u8 chip_rev = readb(slot->host->ioaddr + SYSKT_CHIP_REV); - dev_info(&slot->chip->pdev->dev, "SysKonnect CardBus2SDIO, " - "board rev %d.%d, chip rev %d.%d\n", - board_rev >> 4, board_rev & 0xf, - chip_rev >> 4, chip_rev & 0xf); - if (chip_rev >= 0x20) - slot->host->quirks |= SDHCI_QUIRK_FORCE_DMA; - - writeb(SYSKT_POWER_330, slot->host->ioaddr + SYSKT_POWER_DATA); - writeb(SYSKT_POWER_START, slot->host->ioaddr + SYSKT_POWER_CMD); - udelay(50); - tm = 10; /* Wait max 1 ms */ - do { - ps = readw(slot->host->ioaddr + SYSKT_POWER_STATUS); - if (ps & SYSKT_POWER_STATUS_OK) - break; - udelay(100); - } while (--tm); - if (!tm) { - dev_err(&slot->chip->pdev->dev, - "power regulator never stabilized"); - writeb(0, slot->host->ioaddr + SYSKT_POWER_CMD); - return -ENODEV; - } - - return 0; -} - -static const struct sdhci_pci_fixes sdhci_syskt = { - .quirks = SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER, - .probe = syskt_probe, - .probe_slot = syskt_probe_slot, -}; - -static int via_probe(struct sdhci_pci_chip *chip) -{ - if (chip->pdev->revision == 0x10) - chip->quirks |= SDHCI_QUIRK_DELAY_AFTER_POWER; - - return 0; -} - -static const struct sdhci_pci_fixes sdhci_via = { - .probe = via_probe, -}; - -static const struct pci_device_id pci_ids[] __devinitdata = { - { - .vendor = PCI_VENDOR_ID_RICOH, - .device = PCI_DEVICE_ID_RICOH_R5C822, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (kernel_ulong_t)&sdhci_ricoh, - }, - - { - .vendor = PCI_VENDOR_ID_RICOH, - .device = 0x843, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (kernel_ulong_t)&sdhci_ricoh_mmc, - }, - - { - .vendor = PCI_VENDOR_ID_RICOH, - .device = 0xe822, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (kernel_ulong_t)&sdhci_ricoh_mmc, - }, - - { - .vendor = PCI_VENDOR_ID_RICOH, - .device = 0xe823, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (kernel_ulong_t)&sdhci_ricoh_mmc, - }, - - { - .vendor = PCI_VENDOR_ID_ENE, - .device = PCI_DEVICE_ID_ENE_CB712_SD, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (kernel_ulong_t)&sdhci_ene_712, - }, - - { - .vendor = PCI_VENDOR_ID_ENE, - .device = PCI_DEVICE_ID_ENE_CB712_SD_2, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (kernel_ulong_t)&sdhci_ene_712, - }, - - { - .vendor = PCI_VENDOR_ID_ENE, - .device = PCI_DEVICE_ID_ENE_CB714_SD, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (kernel_ulong_t)&sdhci_ene_714, - }, - - { - .vendor = PCI_VENDOR_ID_ENE, - .device = PCI_DEVICE_ID_ENE_CB714_SD_2, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (kernel_ulong_t)&sdhci_ene_714, - }, - - { - .vendor = PCI_VENDOR_ID_MARVELL, - .device = PCI_DEVICE_ID_MARVELL_88ALP01_SD, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (kernel_ulong_t)&sdhci_cafe, - }, - - { - .vendor = PCI_VENDOR_ID_JMICRON, - .device = PCI_DEVICE_ID_JMICRON_JMB38X_SD, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (kernel_ulong_t)&sdhci_jmicron, - }, - - { - .vendor = PCI_VENDOR_ID_JMICRON, - .device = PCI_DEVICE_ID_JMICRON_JMB38X_MMC, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (kernel_ulong_t)&sdhci_jmicron, - }, - - { - .vendor = PCI_VENDOR_ID_JMICRON, - .device = PCI_DEVICE_ID_JMICRON_JMB388_SD, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (kernel_ulong_t)&sdhci_jmicron, - }, - - { - .vendor = PCI_VENDOR_ID_JMICRON, - .device = PCI_DEVICE_ID_JMICRON_JMB388_ESD, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (kernel_ulong_t)&sdhci_jmicron, - }, - - { - .vendor = PCI_VENDOR_ID_SYSKONNECT, - .device = 0x8000, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (kernel_ulong_t)&sdhci_syskt, - }, - - { - .vendor = PCI_VENDOR_ID_VIA, - .device = 0x95d0, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (kernel_ulong_t)&sdhci_via, - }, - - { - .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_MRST_SD0, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (kernel_ulong_t)&sdhci_intel_mrst_hc0, - }, - - { - .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_MRST_SD1, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (kernel_ulong_t)&sdhci_intel_mrst_hc1_hc2, - }, - - { - .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_MRST_SD2, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (kernel_ulong_t)&sdhci_intel_mrst_hc1_hc2, - }, - - { - .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_MFD_SD, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (kernel_ulong_t)&sdhci_intel_mfd_sd, - }, - - { - .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_MFD_SDIO1, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (kernel_ulong_t)&sdhci_intel_mfd_sdio, - }, - - { - .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_MFD_SDIO2, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (kernel_ulong_t)&sdhci_intel_mfd_sdio, - }, - - { - .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_MFD_EMMC0, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (kernel_ulong_t)&sdhci_intel_mfd_emmc, - }, - - { - .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_MFD_EMMC1, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (kernel_ulong_t)&sdhci_intel_mfd_emmc, - }, - - { - .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_PCH_SDIO0, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (kernel_ulong_t)&sdhci_intel_pch_sdio, - }, - - { - .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_PCH_SDIO1, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (kernel_ulong_t)&sdhci_intel_pch_sdio, - }, - - { - .vendor = PCI_VENDOR_ID_O2, - .device = PCI_DEVICE_ID_O2_8120, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (kernel_ulong_t)&sdhci_o2, - }, - - { - .vendor = PCI_VENDOR_ID_O2, - .device = PCI_DEVICE_ID_O2_8220, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (kernel_ulong_t)&sdhci_o2, - }, - - { - .vendor = PCI_VENDOR_ID_O2, - .device = PCI_DEVICE_ID_O2_8221, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (kernel_ulong_t)&sdhci_o2, - }, - - { - .vendor = PCI_VENDOR_ID_O2, - .device = PCI_DEVICE_ID_O2_8320, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (kernel_ulong_t)&sdhci_o2, - }, - - { - .vendor = PCI_VENDOR_ID_O2, - .device = PCI_DEVICE_ID_O2_8321, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (kernel_ulong_t)&sdhci_o2, - }, - - { /* Generic SD host controller */ - PCI_DEVICE_CLASS((PCI_CLASS_SYSTEM_SDHCI << 8), 0xFFFF00) - }, - - { /* end: all zeroes */ }, -}; - -MODULE_DEVICE_TABLE(pci, pci_ids); - -/*****************************************************************************\ - * * - * SDHCI core callbacks * - * * -\*****************************************************************************/ - -static int sdhci_pci_enable_dma(struct sdhci_host *host) -{ - struct sdhci_pci_slot *slot; - struct pci_dev *pdev; - int ret; - - slot = sdhci_priv(host); - pdev = slot->chip->pdev; - - if (((pdev->class & 0xFFFF00) == (PCI_CLASS_SYSTEM_SDHCI << 8)) && - ((pdev->class & 0x0000FF) != PCI_SDHCI_IFDMA) && - (host->flags & SDHCI_USE_SDMA)) { - dev_warn(&pdev->dev, "Will use DMA mode even though HW " - "doesn't fully claim to support it.\n"); - } - - ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); - if (ret) - return ret; - - pci_set_master(pdev); - - return 0; -} - -static int sdhci_pci_8bit_width(struct sdhci_host *host, int width) -{ - u8 ctrl; - - ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL); - - switch (width) { - case MMC_BUS_WIDTH_8: - ctrl |= SDHCI_CTRL_8BITBUS; - ctrl &= ~SDHCI_CTRL_4BITBUS; - break; - case MMC_BUS_WIDTH_4: - ctrl |= SDHCI_CTRL_4BITBUS; - ctrl &= ~SDHCI_CTRL_8BITBUS; - break; - default: - ctrl &= ~(SDHCI_CTRL_8BITBUS | SDHCI_CTRL_4BITBUS); - break; - } - - sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); - - return 0; -} - -static void sdhci_pci_hw_reset(struct sdhci_host *host) -{ - struct sdhci_pci_slot *slot = sdhci_priv(host); - int rst_n_gpio = slot->rst_n_gpio; - - if (!gpio_is_valid(rst_n_gpio)) - return; - gpio_set_value_cansleep(rst_n_gpio, 0); - /* For eMMC, minimum is 1us but give it 10us for good measure */ - udelay(10); - gpio_set_value_cansleep(rst_n_gpio, 1); - /* For eMMC, minimum is 200us but give it 300us for good measure */ - usleep_range(300, 1000); -} - -static struct sdhci_ops sdhci_pci_ops = { - .enable_dma = sdhci_pci_enable_dma, - .platform_8bit_width = sdhci_pci_8bit_width, - .hw_reset = sdhci_pci_hw_reset, -}; - -/*****************************************************************************\ - * * - * Suspend/resume * - * * -\*****************************************************************************/ - -#ifdef CONFIG_PM - -static int sdhci_pci_suspend(struct device *dev) -{ - struct pci_dev *pdev = to_pci_dev(dev); - struct sdhci_pci_chip *chip; - struct sdhci_pci_slot *slot; - mmc_pm_flag_t slot_pm_flags; - mmc_pm_flag_t pm_flags = 0; - int i, ret; - - chip = pci_get_drvdata(pdev); - if (!chip) - return 0; - - for (i = 0; i < chip->num_slots; i++) { - slot = chip->slots[i]; - if (!slot) - continue; - - ret = sdhci_suspend_host(slot->host); - - if (ret) - goto err_pci_suspend; - - slot_pm_flags = slot->host->mmc->pm_flags; - if (slot_pm_flags & MMC_PM_WAKE_SDIO_IRQ) - sdhci_enable_irq_wakeups(slot->host); - - pm_flags |= slot_pm_flags; - } - - if (chip->fixes && chip->fixes->suspend) { - ret = chip->fixes->suspend(chip); - if (ret) - goto err_pci_suspend; - } - - pci_save_state(pdev); - if (pm_flags & MMC_PM_KEEP_POWER) { - if (pm_flags & MMC_PM_WAKE_SDIO_IRQ) { - pci_pme_active(pdev, true); - pci_enable_wake(pdev, PCI_D3hot, 1); - } - pci_set_power_state(pdev, PCI_D3hot); - } else { - pci_enable_wake(pdev, PCI_D3hot, 0); - pci_disable_device(pdev); - pci_set_power_state(pdev, PCI_D3hot); - } - - return 0; - -err_pci_suspend: - while (--i >= 0) - sdhci_resume_host(chip->slots[i]->host); - return ret; -} - -static int sdhci_pci_resume(struct device *dev) -{ - struct pci_dev *pdev = to_pci_dev(dev); - struct sdhci_pci_chip *chip; - struct sdhci_pci_slot *slot; - int i, ret; - - chip = pci_get_drvdata(pdev); - if (!chip) - return 0; - - pci_set_power_state(pdev, PCI_D0); - pci_restore_state(pdev); - ret = pci_enable_device(pdev); - if (ret) - return ret; - - if (chip->fixes && chip->fixes->resume) { - ret = chip->fixes->resume(chip); - if (ret) - return ret; - } - - for (i = 0; i < chip->num_slots; i++) { - slot = chip->slots[i]; - if (!slot) - continue; - - ret = sdhci_resume_host(slot->host); - if (ret) - return ret; - } - - return 0; -} - -#else /* CONFIG_PM */ - -#define sdhci_pci_suspend NULL -#define sdhci_pci_resume NULL - -#endif /* CONFIG_PM */ - -#ifdef CONFIG_PM_RUNTIME - -static int sdhci_pci_runtime_suspend(struct device *dev) -{ - struct pci_dev *pdev = container_of(dev, struct pci_dev, dev); - struct sdhci_pci_chip *chip; - struct sdhci_pci_slot *slot; - int i, ret; - - chip = pci_get_drvdata(pdev); - if (!chip) - return 0; - - for (i = 0; i < chip->num_slots; i++) { - slot = chip->slots[i]; - if (!slot) - continue; - - ret = sdhci_runtime_suspend_host(slot->host); - - if (ret) - goto err_pci_runtime_suspend; - } - - if (chip->fixes && chip->fixes->suspend) { - ret = chip->fixes->suspend(chip); - if (ret) - goto err_pci_runtime_suspend; - } - - return 0; - -err_pci_runtime_suspend: - while (--i >= 0) - sdhci_runtime_resume_host(chip->slots[i]->host); - return ret; -} - -static int sdhci_pci_runtime_resume(struct device *dev) -{ - struct pci_dev *pdev = container_of(dev, struct pci_dev, dev); - struct sdhci_pci_chip *chip; - struct sdhci_pci_slot *slot; - int i, ret; - - chip = pci_get_drvdata(pdev); - if (!chip) - return 0; - - if (chip->fixes && chip->fixes->resume) { - ret = chip->fixes->resume(chip); - if (ret) - return ret; - } - - for (i = 0; i < chip->num_slots; i++) { - slot = chip->slots[i]; - if (!slot) - continue; - - ret = sdhci_runtime_resume_host(slot->host); - if (ret) - return ret; - } - - return 0; -} - -static int sdhci_pci_runtime_idle(struct device *dev) -{ - return 0; -} - -#else - -#define sdhci_pci_runtime_suspend NULL -#define sdhci_pci_runtime_resume NULL -#define sdhci_pci_runtime_idle NULL - -#endif - -static const struct dev_pm_ops sdhci_pci_pm_ops = { - .suspend = sdhci_pci_suspend, - .resume = sdhci_pci_resume, - .runtime_suspend = sdhci_pci_runtime_suspend, - .runtime_resume = sdhci_pci_runtime_resume, - .runtime_idle = sdhci_pci_runtime_idle, -}; - -/*****************************************************************************\ - * * - * Device probing/removal * - * * -\*****************************************************************************/ - -static struct sdhci_pci_slot * __devinit sdhci_pci_probe_slot( - struct pci_dev *pdev, struct sdhci_pci_chip *chip, int first_bar, - int slotno) -{ - struct sdhci_pci_slot *slot; - struct sdhci_host *host; - int ret, bar = first_bar + slotno; - - if (!(pci_resource_flags(pdev, bar) & IORESOURCE_MEM)) { - dev_err(&pdev->dev, "BAR %d is not iomem. Aborting.\n", bar); - return ERR_PTR(-ENODEV); - } - - if (pci_resource_len(pdev, bar) != 0x100) { - dev_err(&pdev->dev, "Invalid iomem size. You may " - "experience problems.\n"); - } - - if ((pdev->class & 0x0000FF) == PCI_SDHCI_IFVENDOR) { - dev_err(&pdev->dev, "Vendor specific interface. Aborting.\n"); - return ERR_PTR(-ENODEV); - } - - if ((pdev->class & 0x0000FF) > PCI_SDHCI_IFVENDOR) { - dev_err(&pdev->dev, "Unknown interface. Aborting.\n"); - return ERR_PTR(-ENODEV); - } - - host = sdhci_alloc_host(&pdev->dev, sizeof(struct sdhci_pci_slot)); - if (IS_ERR(host)) { - dev_err(&pdev->dev, "cannot allocate host\n"); - return ERR_CAST(host); - } - - slot = sdhci_priv(host); - - slot->chip = chip; - slot->host = host; - slot->pci_bar = bar; - slot->rst_n_gpio = -EINVAL; - slot->cd_gpio = -EINVAL; - - /* Retrieve platform data if there is any */ - if (*sdhci_pci_get_data) - slot->data = sdhci_pci_get_data(pdev, slotno); - - if (slot->data) { - if (slot->data->setup) { - ret = slot->data->setup(slot->data); - if (ret) { - dev_err(&pdev->dev, "platform setup failed\n"); - goto free; - } - } - slot->rst_n_gpio = slot->data->rst_n_gpio; - slot->cd_gpio = slot->data->cd_gpio; - } - - host->hw_name = "PCI"; - host->ops = &sdhci_pci_ops; - host->quirks = chip->quirks; - host->quirks2 = chip->quirks2; - - host->irq = pdev->irq; - - ret = pci_request_region(pdev, bar, mmc_hostname(host->mmc)); - if (ret) { - dev_err(&pdev->dev, "cannot request region\n"); - goto cleanup; - } - - host->ioaddr = pci_ioremap_bar(pdev, bar); - if (!host->ioaddr) { - dev_err(&pdev->dev, "failed to remap registers\n"); - ret = -ENOMEM; - goto release; - } - - if (chip->fixes && chip->fixes->probe_slot) { - ret = chip->fixes->probe_slot(slot); - if (ret) - goto unmap; - } - - if (gpio_is_valid(slot->rst_n_gpio)) { - if (!gpio_request(slot->rst_n_gpio, "eMMC_reset")) { - gpio_direction_output(slot->rst_n_gpio, 1); - slot->host->mmc->caps |= MMC_CAP_HW_RESET; - } else { - dev_warn(&pdev->dev, "failed to request rst_n_gpio\n"); - slot->rst_n_gpio = -EINVAL; - } - } - - host->mmc->pm_caps = MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ; - - ret = sdhci_add_host(host); - if (ret) - goto remove; - - sdhci_pci_add_own_cd(slot); - - return slot; - -remove: - if (gpio_is_valid(slot->rst_n_gpio)) - gpio_free(slot->rst_n_gpio); - - if (chip->fixes && chip->fixes->remove_slot) - chip->fixes->remove_slot(slot, 0); - -unmap: - iounmap(host->ioaddr); - -release: - pci_release_region(pdev, bar); - -cleanup: - if (slot->data && slot->data->cleanup) - slot->data->cleanup(slot->data); - -free: - sdhci_free_host(host); - - return ERR_PTR(ret); -} - -static void sdhci_pci_remove_slot(struct sdhci_pci_slot *slot) -{ - int dead; - u32 scratch; - - sdhci_pci_remove_own_cd(slot); - - dead = 0; - scratch = readl(slot->host->ioaddr + SDHCI_INT_STATUS); - if (scratch == (u32)-1) - dead = 1; - - sdhci_remove_host(slot->host, dead); - - if (gpio_is_valid(slot->rst_n_gpio)) - gpio_free(slot->rst_n_gpio); - - if (slot->chip->fixes && slot->chip->fixes->remove_slot) - slot->chip->fixes->remove_slot(slot, dead); - - if (slot->data && slot->data->cleanup) - slot->data->cleanup(slot->data); - - pci_release_region(slot->chip->pdev, slot->pci_bar); - - sdhci_free_host(slot->host); -} - -static void __devinit sdhci_pci_runtime_pm_allow(struct device *dev) -{ - pm_runtime_put_noidle(dev); - pm_runtime_allow(dev); - pm_runtime_set_autosuspend_delay(dev, 50); - pm_runtime_use_autosuspend(dev); - pm_suspend_ignore_children(dev, 1); -} - -static void __devexit sdhci_pci_runtime_pm_forbid(struct device *dev) -{ - pm_runtime_forbid(dev); - pm_runtime_get_noresume(dev); -} - -static int __devinit sdhci_pci_probe(struct pci_dev *pdev, - const struct pci_device_id *ent) -{ - struct sdhci_pci_chip *chip; - struct sdhci_pci_slot *slot; - - u8 slots, first_bar; - int ret, i; - - BUG_ON(pdev == NULL); - BUG_ON(ent == NULL); - - dev_info(&pdev->dev, "SDHCI controller found [%04x:%04x] (rev %x)\n", - (int)pdev->vendor, (int)pdev->device, (int)pdev->revision); - - ret = pci_read_config_byte(pdev, PCI_SLOT_INFO, &slots); - if (ret) - return ret; - - slots = PCI_SLOT_INFO_SLOTS(slots) + 1; - dev_dbg(&pdev->dev, "found %d slot(s)\n", slots); - if (slots == 0) - return -ENODEV; - - BUG_ON(slots > MAX_SLOTS); - - ret = pci_read_config_byte(pdev, PCI_SLOT_INFO, &first_bar); - if (ret) - return ret; - - first_bar &= PCI_SLOT_INFO_FIRST_BAR_MASK; - - if (first_bar > 5) { - dev_err(&pdev->dev, "Invalid first BAR. Aborting.\n"); - return -ENODEV; - } - - ret = pci_enable_device(pdev); - if (ret) - return ret; - - chip = kzalloc(sizeof(struct sdhci_pci_chip), GFP_KERNEL); - if (!chip) { - ret = -ENOMEM; - goto err; - } - - chip->pdev = pdev; - chip->fixes = (const struct sdhci_pci_fixes *)ent->driver_data; - if (chip->fixes) { - chip->quirks = chip->fixes->quirks; - chip->quirks2 = chip->fixes->quirks2; - chip->allow_runtime_pm = chip->fixes->allow_runtime_pm; - } - chip->num_slots = slots; - - pci_set_drvdata(pdev, chip); - - if (chip->fixes && chip->fixes->probe) { - ret = chip->fixes->probe(chip); - if (ret) - goto free; - } - - slots = chip->num_slots; /* Quirk may have changed this */ - - for (i = 0; i < slots; i++) { - slot = sdhci_pci_probe_slot(pdev, chip, first_bar, i); - if (IS_ERR(slot)) { - for (i--; i >= 0; i--) - sdhci_pci_remove_slot(chip->slots[i]); - ret = PTR_ERR(slot); - goto free; - } - - chip->slots[i] = slot; - } - - if (chip->allow_runtime_pm) - sdhci_pci_runtime_pm_allow(&pdev->dev); - - return 0; - -free: - pci_set_drvdata(pdev, NULL); - kfree(chip); - -err: - pci_disable_device(pdev); - return ret; -} - -static void __devexit sdhci_pci_remove(struct pci_dev *pdev) -{ - int i; - struct sdhci_pci_chip *chip; - - chip = pci_get_drvdata(pdev); - - if (chip) { - if (chip->allow_runtime_pm) - sdhci_pci_runtime_pm_forbid(&pdev->dev); - - for (i = 0; i < chip->num_slots; i++) - sdhci_pci_remove_slot(chip->slots[i]); - - pci_set_drvdata(pdev, NULL); - kfree(chip); - } - - pci_disable_device(pdev); -} - -static struct pci_driver sdhci_driver = { - .name = "sdhci-pci", - .id_table = pci_ids, - .probe = sdhci_pci_probe, - .remove = __devexit_p(sdhci_pci_remove), - .driver = { - .pm = &sdhci_pci_pm_ops - }, -}; - -/*****************************************************************************\ - * * - * Driver init/exit * - * * -\*****************************************************************************/ - -static int __init sdhci_drv_init(void) -{ - return pci_register_driver(&sdhci_driver); -} - -static void __exit sdhci_drv_exit(void) -{ - pci_unregister_driver(&sdhci_driver); -} - -module_init(sdhci_drv_init); -module_exit(sdhci_drv_exit); - -MODULE_AUTHOR("Pierre Ossman <pierre@ossman.eu>"); -MODULE_DESCRIPTION("Secure Digital Host Controller Interface PCI driver"); -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/mmc/host/sdhci-pltfm.c b/ANDROID_3.4.5/drivers/mmc/host/sdhci-pltfm.c deleted file mode 100644 index c5c2a48b..00000000 --- a/ANDROID_3.4.5/drivers/mmc/host/sdhci-pltfm.c +++ /dev/null @@ -1,241 +0,0 @@ -/* - * sdhci-pltfm.c Support for SDHCI platform devices - * Copyright (c) 2009 Intel Corporation - * - * Copyright (c) 2007, 2011 Freescale Semiconductor, Inc. - * Copyright (c) 2009 MontaVista Software, Inc. - * - * Authors: Xiaobo Xie <X.Xie@freescale.com> - * Anton Vorontsov <avorontsov@ru.mvista.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -/* Supports: - * SDHCI platform devices - * - * Inspired by sdhci-pci.c, by Pierre Ossman - */ - -#include <linux/err.h> -#include <linux/module.h> -#include <linux/of.h> -#ifdef CONFIG_PPC -#include <asm/machdep.h> -#endif -#include "sdhci-pltfm.h" - -static struct sdhci_ops sdhci_pltfm_ops = { -}; - -#ifdef CONFIG_OF -static bool sdhci_of_wp_inverted(struct device_node *np) -{ - if (of_get_property(np, "sdhci,wp-inverted", NULL)) - return true; - - /* Old device trees don't have the wp-inverted property. */ -#ifdef CONFIG_PPC - return machine_is(mpc837x_rdb) || machine_is(mpc837x_mds); -#else - return false; -#endif /* CONFIG_PPC */ -} - -void sdhci_get_of_property(struct platform_device *pdev) -{ - struct device_node *np = pdev->dev.of_node; - struct sdhci_host *host = platform_get_drvdata(pdev); - struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - const __be32 *clk; - int size; - - if (of_device_is_available(np)) { - if (of_get_property(np, "sdhci,auto-cmd12", NULL)) - host->quirks |= SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12; - - if (of_get_property(np, "sdhci,1-bit-only", NULL)) - host->quirks |= SDHCI_QUIRK_FORCE_1_BIT_DATA; - - if (sdhci_of_wp_inverted(np)) - host->quirks |= SDHCI_QUIRK_INVERTED_WRITE_PROTECT; - - if (of_device_is_compatible(np, "fsl,p2020-rev1-esdhc")) - host->quirks |= SDHCI_QUIRK_BROKEN_DMA; - - if (of_device_is_compatible(np, "fsl,p2020-esdhc") || - of_device_is_compatible(np, "fsl,p1010-esdhc") || - of_device_is_compatible(np, "fsl,mpc8536-esdhc")) - host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL; - - clk = of_get_property(np, "clock-frequency", &size); - if (clk && size == sizeof(*clk) && *clk) - pltfm_host->clock = be32_to_cpup(clk); - } -} -#else -void sdhci_get_of_property(struct platform_device *pdev) {} -#endif /* CONFIG_OF */ -EXPORT_SYMBOL_GPL(sdhci_get_of_property); - -struct sdhci_host *sdhci_pltfm_init(struct platform_device *pdev, - struct sdhci_pltfm_data *pdata) -{ - struct sdhci_host *host; - struct sdhci_pltfm_host *pltfm_host; - struct device_node *np = pdev->dev.of_node; - struct resource *iomem; - int ret; - - iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!iomem) { - ret = -ENOMEM; - goto err; - } - - if (resource_size(iomem) < 0x100) - dev_err(&pdev->dev, "Invalid iomem size!\n"); - - /* Some PCI-based MFD need the parent here */ - if (pdev->dev.parent != &platform_bus && !np) - host = sdhci_alloc_host(pdev->dev.parent, sizeof(*pltfm_host)); - else - host = sdhci_alloc_host(&pdev->dev, sizeof(*pltfm_host)); - - if (IS_ERR(host)) { - ret = PTR_ERR(host); - goto err; - } - - pltfm_host = sdhci_priv(host); - - host->hw_name = dev_name(&pdev->dev); - if (pdata && pdata->ops) - host->ops = pdata->ops; - else - host->ops = &sdhci_pltfm_ops; - if (pdata) - host->quirks = pdata->quirks; - host->irq = platform_get_irq(pdev, 0); - - if (!request_mem_region(iomem->start, resource_size(iomem), - mmc_hostname(host->mmc))) { - dev_err(&pdev->dev, "cannot request region\n"); - ret = -EBUSY; - goto err_request; - } - - host->ioaddr = ioremap(iomem->start, resource_size(iomem)); - if (!host->ioaddr) { - dev_err(&pdev->dev, "failed to remap registers\n"); - ret = -ENOMEM; - goto err_remap; - } - - platform_set_drvdata(pdev, host); - - return host; - -err_remap: - release_mem_region(iomem->start, resource_size(iomem)); -err_request: - sdhci_free_host(host); -err: - dev_err(&pdev->dev, "%s failed %d\n", __func__, ret); - return ERR_PTR(ret); -} -EXPORT_SYMBOL_GPL(sdhci_pltfm_init); - -void sdhci_pltfm_free(struct platform_device *pdev) -{ - struct sdhci_host *host = platform_get_drvdata(pdev); - struct resource *iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - - iounmap(host->ioaddr); - release_mem_region(iomem->start, resource_size(iomem)); - sdhci_free_host(host); - platform_set_drvdata(pdev, NULL); -} -EXPORT_SYMBOL_GPL(sdhci_pltfm_free); - -int sdhci_pltfm_register(struct platform_device *pdev, - struct sdhci_pltfm_data *pdata) -{ - struct sdhci_host *host; - int ret = 0; - - host = sdhci_pltfm_init(pdev, pdata); - if (IS_ERR(host)) - return PTR_ERR(host); - - sdhci_get_of_property(pdev); - - ret = sdhci_add_host(host); - if (ret) - sdhci_pltfm_free(pdev); - - return ret; -} -EXPORT_SYMBOL_GPL(sdhci_pltfm_register); - -int sdhci_pltfm_unregister(struct platform_device *pdev) -{ - struct sdhci_host *host = platform_get_drvdata(pdev); - int dead = (readl(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff); - - sdhci_remove_host(host, dead); - sdhci_pltfm_free(pdev); - - return 0; -} -EXPORT_SYMBOL_GPL(sdhci_pltfm_unregister); - -#ifdef CONFIG_PM -static int sdhci_pltfm_suspend(struct device *dev) -{ - struct sdhci_host *host = dev_get_drvdata(dev); - - return sdhci_suspend_host(host); -} - -static int sdhci_pltfm_resume(struct device *dev) -{ - struct sdhci_host *host = dev_get_drvdata(dev); - - return sdhci_resume_host(host); -} - -const struct dev_pm_ops sdhci_pltfm_pmops = { - .suspend = sdhci_pltfm_suspend, - .resume = sdhci_pltfm_resume, -}; -EXPORT_SYMBOL_GPL(sdhci_pltfm_pmops); -#endif /* CONFIG_PM */ - -static int __init sdhci_pltfm_drv_init(void) -{ - pr_info("sdhci-pltfm: SDHCI platform and OF driver helper\n"); - - return 0; -} -module_init(sdhci_pltfm_drv_init); - -static void __exit sdhci_pltfm_drv_exit(void) -{ -} -module_exit(sdhci_pltfm_drv_exit); - -MODULE_DESCRIPTION("SDHCI platform and OF driver helper"); -MODULE_AUTHOR("Intel Corporation"); -MODULE_LICENSE("GPL v2"); diff --git a/ANDROID_3.4.5/drivers/mmc/host/sdhci-pltfm.h b/ANDROID_3.4.5/drivers/mmc/host/sdhci-pltfm.h deleted file mode 100644 index 37e0e184..00000000 --- a/ANDROID_3.4.5/drivers/mmc/host/sdhci-pltfm.h +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright 2010 MontaVista Software, LLC. - * - * Author: Anton Vorontsov <avorontsov@ru.mvista.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef _DRIVERS_MMC_SDHCI_PLTFM_H -#define _DRIVERS_MMC_SDHCI_PLTFM_H - -#include <linux/clk.h> -#include <linux/platform_device.h> -#include "sdhci.h" - -struct sdhci_pltfm_data { - struct sdhci_ops *ops; - unsigned int quirks; -}; - -struct sdhci_pltfm_host { - struct clk *clk; - void *priv; /* to handle quirks across io-accessor calls */ - - /* migrate from sdhci_of_host */ - unsigned int clock; - u16 xfer_mode_shadow; -}; - -#ifdef CONFIG_MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER -/* - * These accessors are designed for big endian hosts doing I/O to - * little endian controllers incorporating a 32-bit hardware byte swapper. - */ -static inline u32 sdhci_be32bs_readl(struct sdhci_host *host, int reg) -{ - return in_be32(host->ioaddr + reg); -} - -static inline u16 sdhci_be32bs_readw(struct sdhci_host *host, int reg) -{ - return in_be16(host->ioaddr + (reg ^ 0x2)); -} - -static inline u8 sdhci_be32bs_readb(struct sdhci_host *host, int reg) -{ - return in_8(host->ioaddr + (reg ^ 0x3)); -} - -static inline void sdhci_be32bs_writel(struct sdhci_host *host, - u32 val, int reg) -{ - out_be32(host->ioaddr + reg, val); -} - -static inline void sdhci_be32bs_writew(struct sdhci_host *host, - u16 val, int reg) -{ - struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - int base = reg & ~0x3; - int shift = (reg & 0x2) * 8; - - switch (reg) { - case SDHCI_TRANSFER_MODE: - /* - * Postpone this write, we must do it together with a - * command write that is down below. - */ - pltfm_host->xfer_mode_shadow = val; - return; - case SDHCI_COMMAND: - sdhci_be32bs_writel(host, - val << 16 | pltfm_host->xfer_mode_shadow, - SDHCI_TRANSFER_MODE); - return; - } - clrsetbits_be32(host->ioaddr + base, 0xffff << shift, val << shift); -} - -static inline void sdhci_be32bs_writeb(struct sdhci_host *host, u8 val, int reg) -{ - int base = reg & ~0x3; - int shift = (reg & 0x3) * 8; - - clrsetbits_be32(host->ioaddr + base , 0xff << shift, val << shift); -} -#endif /* CONFIG_MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER */ - -extern void sdhci_get_of_property(struct platform_device *pdev); - -extern struct sdhci_host *sdhci_pltfm_init(struct platform_device *pdev, - struct sdhci_pltfm_data *pdata); -extern void sdhci_pltfm_free(struct platform_device *pdev); - -extern int sdhci_pltfm_register(struct platform_device *pdev, - struct sdhci_pltfm_data *pdata); -extern int sdhci_pltfm_unregister(struct platform_device *pdev); - -#ifdef CONFIG_PM -extern const struct dev_pm_ops sdhci_pltfm_pmops; -#define SDHCI_PLTFM_PMOPS (&sdhci_pltfm_pmops) -#else -#define SDHCI_PLTFM_PMOPS NULL -#endif - -#endif /* _DRIVERS_MMC_SDHCI_PLTFM_H */ diff --git a/ANDROID_3.4.5/drivers/mmc/host/sdhci-pxav2.c b/ANDROID_3.4.5/drivers/mmc/host/sdhci-pxav2.c deleted file mode 100644 index dbb75bfb..00000000 --- a/ANDROID_3.4.5/drivers/mmc/host/sdhci-pxav2.c +++ /dev/null @@ -1,232 +0,0 @@ -/* - * Copyright (C) 2010 Marvell International Ltd. - * Zhangfei Gao <zhangfei.gao@marvell.com> - * Kevin Wang <dwang4@marvell.com> - * Jun Nie <njun@marvell.com> - * Qiming Wu <wuqm@marvell.com> - * Philip Rakity <prakity@marvell.com> - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#include <linux/err.h> -#include <linux/init.h> -#include <linux/platform_device.h> -#include <linux/clk.h> -#include <linux/module.h> -#include <linux/io.h> -#include <linux/gpio.h> -#include <linux/mmc/card.h> -#include <linux/mmc/host.h> -#include <linux/platform_data/pxa_sdhci.h> -#include <linux/slab.h> -#include "sdhci.h" -#include "sdhci-pltfm.h" - -#define SD_FIFO_PARAM 0xe0 -#define DIS_PAD_SD_CLK_GATE 0x0400 /* Turn on/off Dynamic SD Clock Gating */ -#define CLK_GATE_ON 0x0200 /* Disable/enable Clock Gate */ -#define CLK_GATE_CTL 0x0100 /* Clock Gate Control */ -#define CLK_GATE_SETTING_BITS (DIS_PAD_SD_CLK_GATE | \ - CLK_GATE_ON | CLK_GATE_CTL) - -#define SD_CLOCK_BURST_SIZE_SETUP 0xe6 -#define SDCLK_SEL_SHIFT 8 -#define SDCLK_SEL_MASK 0x3 -#define SDCLK_DELAY_SHIFT 10 -#define SDCLK_DELAY_MASK 0x3c - -#define SD_CE_ATA_2 0xea -#define MMC_CARD 0x1000 -#define MMC_WIDTH 0x0100 - -static void pxav2_set_private_registers(struct sdhci_host *host, u8 mask) -{ - struct platform_device *pdev = to_platform_device(mmc_dev(host->mmc)); - struct sdhci_pxa_platdata *pdata = pdev->dev.platform_data; - - if (mask == SDHCI_RESET_ALL) { - u16 tmp = 0; - - /* - * tune timing of read data/command when crc error happen - * no performance impact - */ - if (pdata && pdata->clk_delay_sel == 1) { - tmp = readw(host->ioaddr + SD_CLOCK_BURST_SIZE_SETUP); - - tmp &= ~(SDCLK_DELAY_MASK << SDCLK_DELAY_SHIFT); - tmp |= (pdata->clk_delay_cycles & SDCLK_DELAY_MASK) - << SDCLK_DELAY_SHIFT; - tmp &= ~(SDCLK_SEL_MASK << SDCLK_SEL_SHIFT); - tmp |= (1 & SDCLK_SEL_MASK) << SDCLK_SEL_SHIFT; - - writew(tmp, host->ioaddr + SD_CLOCK_BURST_SIZE_SETUP); - } - - if (pdata && (pdata->flags & PXA_FLAG_ENABLE_CLOCK_GATING)) { - tmp = readw(host->ioaddr + SD_FIFO_PARAM); - tmp &= ~CLK_GATE_SETTING_BITS; - writew(tmp, host->ioaddr + SD_FIFO_PARAM); - } else { - tmp = readw(host->ioaddr + SD_FIFO_PARAM); - tmp &= ~CLK_GATE_SETTING_BITS; - tmp |= CLK_GATE_SETTING_BITS; - writew(tmp, host->ioaddr + SD_FIFO_PARAM); - } - } -} - -static int pxav2_mmc_set_width(struct sdhci_host *host, int width) -{ - u8 ctrl; - u16 tmp; - - ctrl = readb(host->ioaddr + SDHCI_HOST_CONTROL); - tmp = readw(host->ioaddr + SD_CE_ATA_2); - if (width == MMC_BUS_WIDTH_8) { - ctrl &= ~SDHCI_CTRL_4BITBUS; - tmp |= MMC_CARD | MMC_WIDTH; - } else { - tmp &= ~(MMC_CARD | MMC_WIDTH); - if (width == MMC_BUS_WIDTH_4) - ctrl |= SDHCI_CTRL_4BITBUS; - else - ctrl &= ~SDHCI_CTRL_4BITBUS; - } - writew(tmp, host->ioaddr + SD_CE_ATA_2); - writeb(ctrl, host->ioaddr + SDHCI_HOST_CONTROL); - - return 0; -} - -static u32 pxav2_get_max_clock(struct sdhci_host *host) -{ - struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - - return clk_get_rate(pltfm_host->clk); -} - -static struct sdhci_ops pxav2_sdhci_ops = { - .get_max_clock = pxav2_get_max_clock, - .platform_reset_exit = pxav2_set_private_registers, - .platform_8bit_width = pxav2_mmc_set_width, -}; - -static int __devinit sdhci_pxav2_probe(struct platform_device *pdev) -{ - struct sdhci_pltfm_host *pltfm_host; - struct sdhci_pxa_platdata *pdata = pdev->dev.platform_data; - struct device *dev = &pdev->dev; - struct sdhci_host *host = NULL; - struct sdhci_pxa *pxa = NULL; - int ret; - struct clk *clk; - - pxa = kzalloc(sizeof(struct sdhci_pxa), GFP_KERNEL); - if (!pxa) - return -ENOMEM; - - host = sdhci_pltfm_init(pdev, NULL); - if (IS_ERR(host)) { - kfree(pxa); - return PTR_ERR(host); - } - pltfm_host = sdhci_priv(host); - pltfm_host->priv = pxa; - - clk = clk_get(dev, "PXA-SDHCLK"); - if (IS_ERR(clk)) { - dev_err(dev, "failed to get io clock\n"); - ret = PTR_ERR(clk); - goto err_clk_get; - } - pltfm_host->clk = clk; - clk_enable(clk); - - host->quirks = SDHCI_QUIRK_BROKEN_ADMA - | SDHCI_QUIRK_BROKEN_TIMEOUT_VAL - | SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN; - - if (pdata) { - if (pdata->flags & PXA_FLAG_CARD_PERMANENT) { - /* on-chip device */ - host->quirks |= SDHCI_QUIRK_BROKEN_CARD_DETECTION; - host->mmc->caps |= MMC_CAP_NONREMOVABLE; - } - - /* If slot design supports 8 bit data, indicate this to MMC. */ - if (pdata->flags & PXA_FLAG_SD_8_BIT_CAPABLE_SLOT) - host->mmc->caps |= MMC_CAP_8_BIT_DATA; - - if (pdata->quirks) - host->quirks |= pdata->quirks; - if (pdata->host_caps) - host->mmc->caps |= pdata->host_caps; - if (pdata->pm_caps) - host->mmc->pm_caps |= pdata->pm_caps; - } - - host->ops = &pxav2_sdhci_ops; - - ret = sdhci_add_host(host); - if (ret) { - dev_err(&pdev->dev, "failed to add host\n"); - goto err_add_host; - } - - platform_set_drvdata(pdev, host); - - return 0; - -err_add_host: - clk_disable(clk); - clk_put(clk); -err_clk_get: - sdhci_pltfm_free(pdev); - kfree(pxa); - return ret; -} - -static int __devexit sdhci_pxav2_remove(struct platform_device *pdev) -{ - struct sdhci_host *host = platform_get_drvdata(pdev); - struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - struct sdhci_pxa *pxa = pltfm_host->priv; - - sdhci_remove_host(host, 1); - - clk_disable(pltfm_host->clk); - clk_put(pltfm_host->clk); - sdhci_pltfm_free(pdev); - kfree(pxa); - - platform_set_drvdata(pdev, NULL); - - return 0; -} - -static struct platform_driver sdhci_pxav2_driver = { - .driver = { - .name = "sdhci-pxav2", - .owner = THIS_MODULE, - .pm = SDHCI_PLTFM_PMOPS, - }, - .probe = sdhci_pxav2_probe, - .remove = __devexit_p(sdhci_pxav2_remove), -}; - -module_platform_driver(sdhci_pxav2_driver); - -MODULE_DESCRIPTION("SDHCI driver for pxav2"); -MODULE_AUTHOR("Marvell International Ltd."); -MODULE_LICENSE("GPL v2"); - diff --git a/ANDROID_3.4.5/drivers/mmc/host/sdhci-pxav3.c b/ANDROID_3.4.5/drivers/mmc/host/sdhci-pxav3.c deleted file mode 100644 index f2969568..00000000 --- a/ANDROID_3.4.5/drivers/mmc/host/sdhci-pxav3.c +++ /dev/null @@ -1,278 +0,0 @@ -/* - * Copyright (C) 2010 Marvell International Ltd. - * Zhangfei Gao <zhangfei.gao@marvell.com> - * Kevin Wang <dwang4@marvell.com> - * Mingwei Wang <mwwang@marvell.com> - * Philip Rakity <prakity@marvell.com> - * Mark Brown <markb@marvell.com> - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ -#include <linux/err.h> -#include <linux/init.h> -#include <linux/platform_device.h> -#include <linux/clk.h> -#include <linux/io.h> -#include <linux/gpio.h> -#include <linux/mmc/card.h> -#include <linux/mmc/host.h> -#include <linux/platform_data/pxa_sdhci.h> -#include <linux/slab.h> -#include <linux/delay.h> -#include <linux/module.h> -#include "sdhci.h" -#include "sdhci-pltfm.h" - -#define SD_CLOCK_BURST_SIZE_SETUP 0x10A -#define SDCLK_SEL 0x100 -#define SDCLK_DELAY_SHIFT 9 -#define SDCLK_DELAY_MASK 0x1f - -#define SD_CFG_FIFO_PARAM 0x100 -#define SDCFG_GEN_PAD_CLK_ON (1<<6) -#define SDCFG_GEN_PAD_CLK_CNT_MASK 0xFF -#define SDCFG_GEN_PAD_CLK_CNT_SHIFT 24 - -#define SD_SPI_MODE 0x108 -#define SD_CE_ATA_1 0x10C - -#define SD_CE_ATA_2 0x10E -#define SDCE_MISC_INT (1<<2) -#define SDCE_MISC_INT_EN (1<<1) - -static void pxav3_set_private_registers(struct sdhci_host *host, u8 mask) -{ - struct platform_device *pdev = to_platform_device(mmc_dev(host->mmc)); - struct sdhci_pxa_platdata *pdata = pdev->dev.platform_data; - - if (mask == SDHCI_RESET_ALL) { - /* - * tune timing of read data/command when crc error happen - * no performance impact - */ - if (pdata && 0 != pdata->clk_delay_cycles) { - u16 tmp; - - tmp = readw(host->ioaddr + SD_CLOCK_BURST_SIZE_SETUP); - tmp |= (pdata->clk_delay_cycles & SDCLK_DELAY_MASK) - << SDCLK_DELAY_SHIFT; - tmp |= SDCLK_SEL; - writew(tmp, host->ioaddr + SD_CLOCK_BURST_SIZE_SETUP); - } - } -} - -#define MAX_WAIT_COUNT 5 -static void pxav3_gen_init_74_clocks(struct sdhci_host *host, u8 power_mode) -{ - struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - struct sdhci_pxa *pxa = pltfm_host->priv; - u16 tmp; - int count; - - if (pxa->power_mode == MMC_POWER_UP - && power_mode == MMC_POWER_ON) { - - dev_dbg(mmc_dev(host->mmc), - "%s: slot->power_mode = %d," - "ios->power_mode = %d\n", - __func__, - pxa->power_mode, - power_mode); - - /* set we want notice of when 74 clocks are sent */ - tmp = readw(host->ioaddr + SD_CE_ATA_2); - tmp |= SDCE_MISC_INT_EN; - writew(tmp, host->ioaddr + SD_CE_ATA_2); - - /* start sending the 74 clocks */ - tmp = readw(host->ioaddr + SD_CFG_FIFO_PARAM); - tmp |= SDCFG_GEN_PAD_CLK_ON; - writew(tmp, host->ioaddr + SD_CFG_FIFO_PARAM); - - /* slowest speed is about 100KHz or 10usec per clock */ - udelay(740); - count = 0; - - while (count++ < MAX_WAIT_COUNT) { - if ((readw(host->ioaddr + SD_CE_ATA_2) - & SDCE_MISC_INT) == 0) - break; - udelay(10); - } - - if (count == MAX_WAIT_COUNT) - dev_warn(mmc_dev(host->mmc), "74 clock interrupt not cleared\n"); - - /* clear the interrupt bit if posted */ - tmp = readw(host->ioaddr + SD_CE_ATA_2); - tmp |= SDCE_MISC_INT; - writew(tmp, host->ioaddr + SD_CE_ATA_2); - } - pxa->power_mode = power_mode; -} - -static int pxav3_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs) -{ - u16 ctrl_2; - - /* - * Set V18_EN -- UHS modes do not work without this. - * does not change signaling voltage - */ - ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2); - - /* Select Bus Speed Mode for host */ - ctrl_2 &= ~SDHCI_CTRL_UHS_MASK; - switch (uhs) { - case MMC_TIMING_UHS_SDR12: - ctrl_2 |= SDHCI_CTRL_UHS_SDR12; - break; - case MMC_TIMING_UHS_SDR25: - ctrl_2 |= SDHCI_CTRL_UHS_SDR25; - break; - case MMC_TIMING_UHS_SDR50: - ctrl_2 |= SDHCI_CTRL_UHS_SDR50 | SDHCI_CTRL_VDD_180; - break; - case MMC_TIMING_UHS_SDR104: - ctrl_2 |= SDHCI_CTRL_UHS_SDR104 | SDHCI_CTRL_VDD_180; - break; - case MMC_TIMING_UHS_DDR50: - ctrl_2 |= SDHCI_CTRL_UHS_DDR50 | SDHCI_CTRL_VDD_180; - break; - } - - sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2); - dev_dbg(mmc_dev(host->mmc), - "%s uhs = %d, ctrl_2 = %04X\n", - __func__, uhs, ctrl_2); - - return 0; -} - -static struct sdhci_ops pxav3_sdhci_ops = { - .platform_reset_exit = pxav3_set_private_registers, - .set_uhs_signaling = pxav3_set_uhs_signaling, - .platform_send_init_74_clocks = pxav3_gen_init_74_clocks, -}; - -static int __devinit sdhci_pxav3_probe(struct platform_device *pdev) -{ - struct sdhci_pltfm_host *pltfm_host; - struct sdhci_pxa_platdata *pdata = pdev->dev.platform_data; - struct device *dev = &pdev->dev; - struct sdhci_host *host = NULL; - struct sdhci_pxa *pxa = NULL; - int ret; - struct clk *clk; - - pxa = kzalloc(sizeof(struct sdhci_pxa), GFP_KERNEL); - if (!pxa) - return -ENOMEM; - - host = sdhci_pltfm_init(pdev, NULL); - if (IS_ERR(host)) { - kfree(pxa); - return PTR_ERR(host); - } - pltfm_host = sdhci_priv(host); - pltfm_host->priv = pxa; - - clk = clk_get(dev, "PXA-SDHCLK"); - if (IS_ERR(clk)) { - dev_err(dev, "failed to get io clock\n"); - ret = PTR_ERR(clk); - goto err_clk_get; - } - pltfm_host->clk = clk; - clk_enable(clk); - - host->quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL - | SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC - | SDHCI_QUIRK_32BIT_ADMA_SIZE; - - /* enable 1/8V DDR capable */ - host->mmc->caps |= MMC_CAP_1_8V_DDR; - - if (pdata) { - if (pdata->flags & PXA_FLAG_CARD_PERMANENT) { - /* on-chip device */ - host->quirks |= SDHCI_QUIRK_BROKEN_CARD_DETECTION; - host->mmc->caps |= MMC_CAP_NONREMOVABLE; - } - - /* If slot design supports 8 bit data, indicate this to MMC. */ - if (pdata->flags & PXA_FLAG_SD_8_BIT_CAPABLE_SLOT) - host->mmc->caps |= MMC_CAP_8_BIT_DATA; - - if (pdata->quirks) - host->quirks |= pdata->quirks; - if (pdata->host_caps) - host->mmc->caps |= pdata->host_caps; - if (pdata->pm_caps) - host->mmc->pm_caps |= pdata->pm_caps; - } - - host->ops = &pxav3_sdhci_ops; - - ret = sdhci_add_host(host); - if (ret) { - dev_err(&pdev->dev, "failed to add host\n"); - goto err_add_host; - } - - platform_set_drvdata(pdev, host); - - return 0; - -err_add_host: - clk_disable(clk); - clk_put(clk); -err_clk_get: - sdhci_pltfm_free(pdev); - kfree(pxa); - return ret; -} - -static int __devexit sdhci_pxav3_remove(struct platform_device *pdev) -{ - struct sdhci_host *host = platform_get_drvdata(pdev); - struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - struct sdhci_pxa *pxa = pltfm_host->priv; - - sdhci_remove_host(host, 1); - - clk_disable(pltfm_host->clk); - clk_put(pltfm_host->clk); - sdhci_pltfm_free(pdev); - kfree(pxa); - - platform_set_drvdata(pdev, NULL); - - return 0; -} - -static struct platform_driver sdhci_pxav3_driver = { - .driver = { - .name = "sdhci-pxav3", - .owner = THIS_MODULE, - .pm = SDHCI_PLTFM_PMOPS, - }, - .probe = sdhci_pxav3_probe, - .remove = __devexit_p(sdhci_pxav3_remove), -}; - -module_platform_driver(sdhci_pxav3_driver); - -MODULE_DESCRIPTION("SDHCI driver for pxav3"); -MODULE_AUTHOR("Marvell International Ltd."); -MODULE_LICENSE("GPL v2"); - diff --git a/ANDROID_3.4.5/drivers/mmc/host/sdhci-s3c.c b/ANDROID_3.4.5/drivers/mmc/host/sdhci-s3c.c deleted file mode 100644 index 55a164fc..00000000 --- a/ANDROID_3.4.5/drivers/mmc/host/sdhci-s3c.c +++ /dev/null @@ -1,756 +0,0 @@ -/* linux/drivers/mmc/host/sdhci-s3c.c - * - * Copyright 2008 Openmoko Inc. - * Copyright 2008 Simtec Electronics - * Ben Dooks <ben@simtec.co.uk> - * http://armlinux.simtec.co.uk/ - * - * SDHCI (HSMMC) support for Samsung SoC - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include <linux/delay.h> -#include <linux/dma-mapping.h> -#include <linux/platform_device.h> -#include <linux/slab.h> -#include <linux/clk.h> -#include <linux/io.h> -#include <linux/gpio.h> -#include <linux/module.h> -#include <linux/of.h> -#include <linux/of_gpio.h> -#include <linux/pm.h> -#include <linux/pm_runtime.h> - -#include <linux/mmc/host.h> - -#include <plat/sdhci.h> -#include <plat/regs-sdhci.h> - -#include "sdhci.h" - -#define MAX_BUS_CLK (4) - -/** - * struct sdhci_s3c - S3C SDHCI instance - * @host: The SDHCI host created - * @pdev: The platform device we where created from. - * @ioarea: The resource created when we claimed the IO area. - * @pdata: The platform data for this controller. - * @cur_clk: The index of the current bus clock. - * @clk_io: The clock for the internal bus interface. - * @clk_bus: The clocks that are available for the SD/MMC bus clock. - */ -struct sdhci_s3c { - struct sdhci_host *host; - struct platform_device *pdev; - struct resource *ioarea; - struct s3c_sdhci_platdata *pdata; - unsigned int cur_clk; - int ext_cd_irq; - int ext_cd_gpio; - - struct clk *clk_io; - struct clk *clk_bus[MAX_BUS_CLK]; -}; - -/** - * struct sdhci_s3c_driver_data - S3C SDHCI platform specific driver data - * @sdhci_quirks: sdhci host specific quirks. - * - * Specifies platform specific configuration of sdhci controller. - * Note: A structure for driver specific platform data is used for future - * expansion of its usage. - */ -struct sdhci_s3c_drv_data { - unsigned int sdhci_quirks; -}; - -static inline struct sdhci_s3c *to_s3c(struct sdhci_host *host) -{ - return sdhci_priv(host); -} - -/** - * get_curclk - convert ctrl2 register to clock source number - * @ctrl2: Control2 register value. - */ -static u32 get_curclk(u32 ctrl2) -{ - ctrl2 &= S3C_SDHCI_CTRL2_SELBASECLK_MASK; - ctrl2 >>= S3C_SDHCI_CTRL2_SELBASECLK_SHIFT; - - return ctrl2; -} - -static void sdhci_s3c_check_sclk(struct sdhci_host *host) -{ - struct sdhci_s3c *ourhost = to_s3c(host); - u32 tmp = readl(host->ioaddr + S3C_SDHCI_CONTROL2); - - if (get_curclk(tmp) != ourhost->cur_clk) { - dev_dbg(&ourhost->pdev->dev, "restored ctrl2 clock setting\n"); - - tmp &= ~S3C_SDHCI_CTRL2_SELBASECLK_MASK; - tmp |= ourhost->cur_clk << S3C_SDHCI_CTRL2_SELBASECLK_SHIFT; - writel(tmp, host->ioaddr + S3C_SDHCI_CONTROL2); - } -} - -/** - * sdhci_s3c_get_max_clk - callback to get maximum clock frequency. - * @host: The SDHCI host instance. - * - * Callback to return the maximum clock rate acheivable by the controller. -*/ -static unsigned int sdhci_s3c_get_max_clk(struct sdhci_host *host) -{ - struct sdhci_s3c *ourhost = to_s3c(host); - struct clk *busclk; - unsigned int rate, max; - int clk; - - /* note, a reset will reset the clock source */ - - sdhci_s3c_check_sclk(host); - - for (max = 0, clk = 0; clk < MAX_BUS_CLK; clk++) { - busclk = ourhost->clk_bus[clk]; - if (!busclk) - continue; - - rate = clk_get_rate(busclk); - if (rate > max) - max = rate; - } - - return max; -} - -/** - * sdhci_s3c_consider_clock - consider one the bus clocks for current setting - * @ourhost: Our SDHCI instance. - * @src: The source clock index. - * @wanted: The clock frequency wanted. - */ -static unsigned int sdhci_s3c_consider_clock(struct sdhci_s3c *ourhost, - unsigned int src, - unsigned int wanted) -{ - unsigned long rate; - struct clk *clksrc = ourhost->clk_bus[src]; - int div; - - if (!clksrc) - return UINT_MAX; - - /* - * If controller uses a non-standard clock division, find the best clock - * speed possible with selected clock source and skip the division. - */ - if (ourhost->host->quirks & SDHCI_QUIRK_NONSTANDARD_CLOCK) { - rate = clk_round_rate(clksrc, wanted); - return wanted - rate; - } - - rate = clk_get_rate(clksrc); - - for (div = 1; div < 256; div *= 2) { - if ((rate / div) <= wanted) - break; - } - - dev_dbg(&ourhost->pdev->dev, "clk %d: rate %ld, want %d, got %ld\n", - src, rate, wanted, rate / div); - - return (wanted - (rate / div)); -} - -/** - * sdhci_s3c_set_clock - callback on clock change - * @host: The SDHCI host being changed - * @clock: The clock rate being requested. - * - * When the card's clock is going to be changed, look at the new frequency - * and find the best clock source to go with it. -*/ -static void sdhci_s3c_set_clock(struct sdhci_host *host, unsigned int clock) -{ - struct sdhci_s3c *ourhost = to_s3c(host); - unsigned int best = UINT_MAX; - unsigned int delta; - int best_src = 0; - int src; - u32 ctrl; - - /* don't bother if the clock is going off. */ - if (clock == 0) - return; - - for (src = 0; src < MAX_BUS_CLK; src++) { - delta = sdhci_s3c_consider_clock(ourhost, src, clock); - if (delta < best) { - best = delta; - best_src = src; - } - } - - dev_dbg(&ourhost->pdev->dev, - "selected source %d, clock %d, delta %d\n", - best_src, clock, best); - - /* select the new clock source */ - - if (ourhost->cur_clk != best_src) { - struct clk *clk = ourhost->clk_bus[best_src]; - - /* turn clock off to card before changing clock source */ - writew(0, host->ioaddr + SDHCI_CLOCK_CONTROL); - - ourhost->cur_clk = best_src; - host->max_clk = clk_get_rate(clk); - - ctrl = readl(host->ioaddr + S3C_SDHCI_CONTROL2); - ctrl &= ~S3C_SDHCI_CTRL2_SELBASECLK_MASK; - ctrl |= best_src << S3C_SDHCI_CTRL2_SELBASECLK_SHIFT; - writel(ctrl, host->ioaddr + S3C_SDHCI_CONTROL2); - } - - /* reprogram default hardware configuration */ - writel(S3C64XX_SDHCI_CONTROL4_DRIVE_9mA, - host->ioaddr + S3C64XX_SDHCI_CONTROL4); - - ctrl = readl(host->ioaddr + S3C_SDHCI_CONTROL2); - ctrl |= (S3C64XX_SDHCI_CTRL2_ENSTAASYNCCLR | - S3C64XX_SDHCI_CTRL2_ENCMDCNFMSK | - S3C_SDHCI_CTRL2_ENFBCLKRX | - S3C_SDHCI_CTRL2_DFCNT_NONE | - S3C_SDHCI_CTRL2_ENCLKOUTHOLD); - writel(ctrl, host->ioaddr + S3C_SDHCI_CONTROL2); - - /* reconfigure the controller for new clock rate */ - ctrl = (S3C_SDHCI_CTRL3_FCSEL1 | S3C_SDHCI_CTRL3_FCSEL0); - if (clock < 25 * 1000000) - ctrl |= (S3C_SDHCI_CTRL3_FCSEL3 | S3C_SDHCI_CTRL3_FCSEL2); - writel(ctrl, host->ioaddr + S3C_SDHCI_CONTROL3); -} - -/** - * sdhci_s3c_get_min_clock - callback to get minimal supported clock value - * @host: The SDHCI host being queried - * - * To init mmc host properly a minimal clock value is needed. For high system - * bus clock's values the standard formula gives values out of allowed range. - * The clock still can be set to lower values, if clock source other then - * system bus is selected. -*/ -static unsigned int sdhci_s3c_get_min_clock(struct sdhci_host *host) -{ - struct sdhci_s3c *ourhost = to_s3c(host); - unsigned int delta, min = UINT_MAX; - int src; - - for (src = 0; src < MAX_BUS_CLK; src++) { - delta = sdhci_s3c_consider_clock(ourhost, src, 0); - if (delta == UINT_MAX) - continue; - /* delta is a negative value in this case */ - if (-delta < min) - min = -delta; - } - return min; -} - -/* sdhci_cmu_get_max_clk - callback to get maximum clock frequency.*/ -static unsigned int sdhci_cmu_get_max_clock(struct sdhci_host *host) -{ - struct sdhci_s3c *ourhost = to_s3c(host); - - return clk_round_rate(ourhost->clk_bus[ourhost->cur_clk], UINT_MAX); -} - -/* sdhci_cmu_get_min_clock - callback to get minimal supported clock value. */ -static unsigned int sdhci_cmu_get_min_clock(struct sdhci_host *host) -{ - struct sdhci_s3c *ourhost = to_s3c(host); - - /* - * initial clock can be in the frequency range of - * 100KHz-400KHz, so we set it as max value. - */ - return clk_round_rate(ourhost->clk_bus[ourhost->cur_clk], 400000); -} - -/* sdhci_cmu_set_clock - callback on clock change.*/ -static void sdhci_cmu_set_clock(struct sdhci_host *host, unsigned int clock) -{ - struct sdhci_s3c *ourhost = to_s3c(host); - unsigned long timeout; - u16 clk = 0; - - /* don't bother if the clock is going off */ - if (clock == 0) - return; - - sdhci_s3c_set_clock(host, clock); - - clk_set_rate(ourhost->clk_bus[ourhost->cur_clk], clock); - - host->clock = clock; - - clk = SDHCI_CLOCK_INT_EN; - sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); - - /* Wait max 20 ms */ - timeout = 20; - while (!((clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL)) - & SDHCI_CLOCK_INT_STABLE)) { - if (timeout == 0) { - printk(KERN_ERR "%s: Internal clock never " - "stabilised.\n", mmc_hostname(host->mmc)); - return; - } - timeout--; - mdelay(1); - } - - clk |= SDHCI_CLOCK_CARD_EN; - sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); -} - -/** - * sdhci_s3c_platform_8bit_width - support 8bit buswidth - * @host: The SDHCI host being queried - * @width: MMC_BUS_WIDTH_ macro for the bus width being requested - * - * We have 8-bit width support but is not a v3 controller. - * So we add platform_8bit_width() and support 8bit width. - */ -static int sdhci_s3c_platform_8bit_width(struct sdhci_host *host, int width) -{ - u8 ctrl; - - ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL); - - switch (width) { - case MMC_BUS_WIDTH_8: - ctrl |= SDHCI_CTRL_8BITBUS; - ctrl &= ~SDHCI_CTRL_4BITBUS; - break; - case MMC_BUS_WIDTH_4: - ctrl |= SDHCI_CTRL_4BITBUS; - ctrl &= ~SDHCI_CTRL_8BITBUS; - break; - default: - ctrl &= ~SDHCI_CTRL_4BITBUS; - ctrl &= ~SDHCI_CTRL_8BITBUS; - break; - } - - sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); - - return 0; -} - -static struct sdhci_ops sdhci_s3c_ops = { - .get_max_clock = sdhci_s3c_get_max_clk, - .set_clock = sdhci_s3c_set_clock, - .get_min_clock = sdhci_s3c_get_min_clock, - .platform_8bit_width = sdhci_s3c_platform_8bit_width, -}; - -static void sdhci_s3c_notify_change(struct platform_device *dev, int state) -{ - struct sdhci_host *host = platform_get_drvdata(dev); - unsigned long flags; - - if (host) { - spin_lock_irqsave(&host->lock, flags); - if (state) { - dev_dbg(&dev->dev, "card inserted.\n"); - host->flags &= ~SDHCI_DEVICE_DEAD; - host->quirks |= SDHCI_QUIRK_BROKEN_CARD_DETECTION; - } else { - dev_dbg(&dev->dev, "card removed.\n"); - host->flags |= SDHCI_DEVICE_DEAD; - host->quirks &= ~SDHCI_QUIRK_BROKEN_CARD_DETECTION; - } - tasklet_schedule(&host->card_tasklet); - spin_unlock_irqrestore(&host->lock, flags); - } -} - -static irqreturn_t sdhci_s3c_gpio_card_detect_thread(int irq, void *dev_id) -{ - struct sdhci_s3c *sc = dev_id; - int status = gpio_get_value(sc->ext_cd_gpio); - if (sc->pdata->ext_cd_gpio_invert) - status = !status; - sdhci_s3c_notify_change(sc->pdev, status); - return IRQ_HANDLED; -} - -static void sdhci_s3c_setup_card_detect_gpio(struct sdhci_s3c *sc) -{ - struct s3c_sdhci_platdata *pdata = sc->pdata; - struct device *dev = &sc->pdev->dev; - - if (gpio_request(pdata->ext_cd_gpio, "SDHCI EXT CD") == 0) { - sc->ext_cd_gpio = pdata->ext_cd_gpio; - sc->ext_cd_irq = gpio_to_irq(pdata->ext_cd_gpio); - if (sc->ext_cd_irq && - request_threaded_irq(sc->ext_cd_irq, NULL, - sdhci_s3c_gpio_card_detect_thread, - IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, - dev_name(dev), sc) == 0) { - int status = gpio_get_value(sc->ext_cd_gpio); - if (pdata->ext_cd_gpio_invert) - status = !status; - sdhci_s3c_notify_change(sc->pdev, status); - } else { - dev_warn(dev, "cannot request irq for card detect\n"); - sc->ext_cd_irq = 0; - } - } else { - dev_err(dev, "cannot request gpio for card detect\n"); - } -} - -static inline struct sdhci_s3c_drv_data *sdhci_s3c_get_driver_data( - struct platform_device *pdev) -{ - return (struct sdhci_s3c_drv_data *) - platform_get_device_id(pdev)->driver_data; -} - -static int __devinit sdhci_s3c_probe(struct platform_device *pdev) -{ - struct s3c_sdhci_platdata *pdata; - struct sdhci_s3c_drv_data *drv_data; - struct device *dev = &pdev->dev; - struct sdhci_host *host; - struct sdhci_s3c *sc; - struct resource *res; - int ret, irq, ptr, clks; - - if (!pdev->dev.platform_data) { - dev_err(dev, "no device data specified\n"); - return -ENOENT; - } - - irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(dev, "no irq specified\n"); - return irq; - } - - host = sdhci_alloc_host(dev, sizeof(struct sdhci_s3c)); - if (IS_ERR(host)) { - dev_err(dev, "sdhci_alloc_host() failed\n"); - return PTR_ERR(host); - } - - pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); - if (!pdata) { - ret = -ENOMEM; - goto err_io_clk; - } - memcpy(pdata, pdev->dev.platform_data, sizeof(*pdata)); - - drv_data = sdhci_s3c_get_driver_data(pdev); - sc = sdhci_priv(host); - - sc->host = host; - sc->pdev = pdev; - sc->pdata = pdata; - sc->ext_cd_gpio = -1; /* invalid gpio number */ - - platform_set_drvdata(pdev, host); - - sc->clk_io = clk_get(dev, "hsmmc"); - if (IS_ERR(sc->clk_io)) { - dev_err(dev, "failed to get io clock\n"); - ret = PTR_ERR(sc->clk_io); - goto err_io_clk; - } - - /* enable the local io clock and keep it running for the moment. */ - clk_enable(sc->clk_io); - - for (clks = 0, ptr = 0; ptr < MAX_BUS_CLK; ptr++) { - struct clk *clk; - char name[14]; - - snprintf(name, 14, "mmc_busclk.%d", ptr); - clk = clk_get(dev, name); - if (IS_ERR(clk)) { - continue; - } - - clks++; - sc->clk_bus[ptr] = clk; - - /* - * save current clock index to know which clock bus - * is used later in overriding functions. - */ - sc->cur_clk = ptr; - - clk_enable(clk); - - dev_info(dev, "clock source %d: %s (%ld Hz)\n", - ptr, name, clk_get_rate(clk)); - } - - if (clks == 0) { - dev_err(dev, "failed to find any bus clocks\n"); - ret = -ENOENT; - goto err_no_busclks; - } - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - host->ioaddr = devm_request_and_ioremap(&pdev->dev, res); - if (!host->ioaddr) { - dev_err(dev, "failed to map registers\n"); - ret = -ENXIO; - goto err_req_regs; - } - - /* Ensure we have minimal gpio selected CMD/CLK/Detect */ - if (pdata->cfg_gpio) - pdata->cfg_gpio(pdev, pdata->max_width); - - host->hw_name = "samsung-hsmmc"; - host->ops = &sdhci_s3c_ops; - host->quirks = 0; - host->irq = irq; - - /* Setup quirks for the controller */ - host->quirks |= SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC; - host->quirks |= SDHCI_QUIRK_NO_HISPD_BIT; - if (drv_data) - host->quirks |= drv_data->sdhci_quirks; - -#ifndef CONFIG_MMC_SDHCI_S3C_DMA - - /* we currently see overruns on errors, so disable the SDMA - * support as well. */ - host->quirks |= SDHCI_QUIRK_BROKEN_DMA; - -#endif /* CONFIG_MMC_SDHCI_S3C_DMA */ - - /* It seems we do not get an DATA transfer complete on non-busy - * transfers, not sure if this is a problem with this specific - * SDHCI block, or a missing configuration that needs to be set. */ - host->quirks |= SDHCI_QUIRK_NO_BUSY_IRQ; - - /* This host supports the Auto CMD12 */ - host->quirks |= SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12; - - /* Samsung SoCs need BROKEN_ADMA_ZEROLEN_DESC */ - host->quirks |= SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC; - - if (pdata->cd_type == S3C_SDHCI_CD_NONE || - pdata->cd_type == S3C_SDHCI_CD_PERMANENT) - host->quirks |= SDHCI_QUIRK_BROKEN_CARD_DETECTION; - - if (pdata->cd_type == S3C_SDHCI_CD_PERMANENT) - host->mmc->caps = MMC_CAP_NONREMOVABLE; - - switch (pdata->max_width) { - case 8: - host->mmc->caps |= MMC_CAP_8_BIT_DATA; - case 4: - host->mmc->caps |= MMC_CAP_4_BIT_DATA; - break; - } - - if (pdata->pm_caps) - host->mmc->pm_caps |= pdata->pm_caps; - - host->quirks |= (SDHCI_QUIRK_32BIT_DMA_ADDR | - SDHCI_QUIRK_32BIT_DMA_SIZE); - - /* HSMMC on Samsung SoCs uses SDCLK as timeout clock */ - host->quirks |= SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK; - - /* - * If controller does not have internal clock divider, - * we can use overriding functions instead of default. - */ - if (host->quirks & SDHCI_QUIRK_NONSTANDARD_CLOCK) { - sdhci_s3c_ops.set_clock = sdhci_cmu_set_clock; - sdhci_s3c_ops.get_min_clock = sdhci_cmu_get_min_clock; - sdhci_s3c_ops.get_max_clock = sdhci_cmu_get_max_clock; - } - - /* It supports additional host capabilities if needed */ - if (pdata->host_caps) - host->mmc->caps |= pdata->host_caps; - - if (pdata->host_caps2) - host->mmc->caps2 |= pdata->host_caps2; - - pm_runtime_enable(&pdev->dev); - pm_runtime_set_autosuspend_delay(&pdev->dev, 50); - pm_runtime_use_autosuspend(&pdev->dev); - pm_suspend_ignore_children(&pdev->dev, 1); - - ret = sdhci_add_host(host); - if (ret) { - dev_err(dev, "sdhci_add_host() failed\n"); - pm_runtime_forbid(&pdev->dev); - pm_runtime_get_noresume(&pdev->dev); - goto err_req_regs; - } - - /* The following two methods of card detection might call - sdhci_s3c_notify_change() immediately, so they can be called - only after sdhci_add_host(). Setup errors are ignored. */ - if (pdata->cd_type == S3C_SDHCI_CD_EXTERNAL && pdata->ext_cd_init) - pdata->ext_cd_init(&sdhci_s3c_notify_change); - if (pdata->cd_type == S3C_SDHCI_CD_GPIO && - gpio_is_valid(pdata->ext_cd_gpio)) - sdhci_s3c_setup_card_detect_gpio(sc); - - return 0; - - err_req_regs: - for (ptr = 0; ptr < MAX_BUS_CLK; ptr++) { - if (sc->clk_bus[ptr]) { - clk_disable(sc->clk_bus[ptr]); - clk_put(sc->clk_bus[ptr]); - } - } - - err_no_busclks: - clk_disable(sc->clk_io); - clk_put(sc->clk_io); - - err_io_clk: - sdhci_free_host(host); - - return ret; -} - -static int __devexit sdhci_s3c_remove(struct platform_device *pdev) -{ - struct s3c_sdhci_platdata *pdata = pdev->dev.platform_data; - struct sdhci_host *host = platform_get_drvdata(pdev); - struct sdhci_s3c *sc = sdhci_priv(host); - int ptr; - - if (pdata->cd_type == S3C_SDHCI_CD_EXTERNAL && pdata->ext_cd_cleanup) - pdata->ext_cd_cleanup(&sdhci_s3c_notify_change); - - if (sc->ext_cd_irq) - free_irq(sc->ext_cd_irq, sc); - - if (gpio_is_valid(sc->ext_cd_gpio)) - gpio_free(sc->ext_cd_gpio); - - sdhci_remove_host(host, 1); - - pm_runtime_disable(&pdev->dev); - - for (ptr = 0; ptr < 3; ptr++) { - if (sc->clk_bus[ptr]) { - clk_disable(sc->clk_bus[ptr]); - clk_put(sc->clk_bus[ptr]); - } - } - clk_disable(sc->clk_io); - clk_put(sc->clk_io); - - sdhci_free_host(host); - platform_set_drvdata(pdev, NULL); - - return 0; -} - -#ifdef CONFIG_PM_SLEEP -static int sdhci_s3c_suspend(struct device *dev) -{ - struct sdhci_host *host = dev_get_drvdata(dev); - - return sdhci_suspend_host(host); -} - -static int sdhci_s3c_resume(struct device *dev) -{ - struct sdhci_host *host = dev_get_drvdata(dev); - - return sdhci_resume_host(host); -} -#endif - -#ifdef CONFIG_PM_RUNTIME -static int sdhci_s3c_runtime_suspend(struct device *dev) -{ - struct sdhci_host *host = dev_get_drvdata(dev); - - return sdhci_runtime_suspend_host(host); -} - -static int sdhci_s3c_runtime_resume(struct device *dev) -{ - struct sdhci_host *host = dev_get_drvdata(dev); - - return sdhci_runtime_resume_host(host); -} -#endif - -#ifdef CONFIG_PM -static const struct dev_pm_ops sdhci_s3c_pmops = { - SET_SYSTEM_SLEEP_PM_OPS(sdhci_s3c_suspend, sdhci_s3c_resume) - SET_RUNTIME_PM_OPS(sdhci_s3c_runtime_suspend, sdhci_s3c_runtime_resume, - NULL) -}; - -#define SDHCI_S3C_PMOPS (&sdhci_s3c_pmops) - -#else -#define SDHCI_S3C_PMOPS NULL -#endif - -#if defined(CONFIG_CPU_EXYNOS4210) || defined(CONFIG_SOC_EXYNOS4212) -static struct sdhci_s3c_drv_data exynos4_sdhci_drv_data = { - .sdhci_quirks = SDHCI_QUIRK_NONSTANDARD_CLOCK, -}; -#define EXYNOS4_SDHCI_DRV_DATA ((kernel_ulong_t)&exynos4_sdhci_drv_data) -#else -#define EXYNOS4_SDHCI_DRV_DATA ((kernel_ulong_t)NULL) -#endif - -static struct platform_device_id sdhci_s3c_driver_ids[] = { - { - .name = "s3c-sdhci", - .driver_data = (kernel_ulong_t)NULL, - }, { - .name = "exynos4-sdhci", - .driver_data = EXYNOS4_SDHCI_DRV_DATA, - }, - { } -}; -MODULE_DEVICE_TABLE(platform, sdhci_s3c_driver_ids); - -static struct platform_driver sdhci_s3c_driver = { - .probe = sdhci_s3c_probe, - .remove = __devexit_p(sdhci_s3c_remove), - .id_table = sdhci_s3c_driver_ids, - .driver = { - .owner = THIS_MODULE, - .name = "s3c-sdhci", - .pm = SDHCI_S3C_PMOPS, - }, -}; - -module_platform_driver(sdhci_s3c_driver); - -MODULE_DESCRIPTION("Samsung SDHCI (HSMMC) glue"); -MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>"); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:s3c-sdhci"); diff --git a/ANDROID_3.4.5/drivers/mmc/host/sdhci-spear.c b/ANDROID_3.4.5/drivers/mmc/host/sdhci-spear.c deleted file mode 100644 index 6dfa82e0..00000000 --- a/ANDROID_3.4.5/drivers/mmc/host/sdhci-spear.c +++ /dev/null @@ -1,321 +0,0 @@ -/* - * drivers/mmc/host/sdhci-spear.c - * - * Support of SDHCI platform devices for spear soc family - * - * Copyright (C) 2010 ST Microelectronics - * Viresh Kumar<viresh.kumar@st.com> - * - * Inspired by sdhci-pltfm.c - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - */ - -#include <linux/clk.h> -#include <linux/delay.h> -#include <linux/gpio.h> -#include <linux/highmem.h> -#include <linux/module.h> -#include <linux/interrupt.h> -#include <linux/irq.h> -#include <linux/platform_device.h> -#include <linux/pm.h> -#include <linux/slab.h> -#include <linux/mmc/host.h> -#include <linux/mmc/sdhci-spear.h> -#include <linux/io.h> -#include "sdhci.h" - -struct spear_sdhci { - struct clk *clk; - struct sdhci_plat_data *data; -}; - -/* sdhci ops */ -static struct sdhci_ops sdhci_pltfm_ops = { - /* Nothing to do for now. */ -}; - -/* gpio card detection interrupt handler */ -static irqreturn_t sdhci_gpio_irq(int irq, void *dev_id) -{ - struct platform_device *pdev = dev_id; - struct sdhci_host *host = platform_get_drvdata(pdev); - struct spear_sdhci *sdhci = dev_get_platdata(&pdev->dev); - unsigned long gpio_irq_type; - int val; - - val = gpio_get_value(sdhci->data->card_int_gpio); - - /* val == 1 -> card removed, val == 0 -> card inserted */ - /* if card removed - set irq for low level, else vice versa */ - gpio_irq_type = val ? IRQF_TRIGGER_LOW : IRQF_TRIGGER_HIGH; - irq_set_irq_type(irq, gpio_irq_type); - - if (sdhci->data->card_power_gpio >= 0) { - if (!sdhci->data->power_always_enb) { - /* if card inserted, give power, otherwise remove it */ - val = sdhci->data->power_active_high ? !val : val ; - gpio_set_value(sdhci->data->card_power_gpio, val); - } - } - - /* inform sdhci driver about card insertion/removal */ - tasklet_schedule(&host->card_tasklet); - - return IRQ_HANDLED; -} - -static int __devinit sdhci_probe(struct platform_device *pdev) -{ - struct sdhci_host *host; - struct resource *iomem; - struct spear_sdhci *sdhci; - int ret; - - BUG_ON(pdev == NULL); - - iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!iomem) { - ret = -ENOMEM; - dev_dbg(&pdev->dev, "memory resource not defined\n"); - goto err; - } - - if (!request_mem_region(iomem->start, resource_size(iomem), - "spear-sdhci")) { - ret = -EBUSY; - dev_dbg(&pdev->dev, "cannot request region\n"); - goto err; - } - - sdhci = kzalloc(sizeof(*sdhci), GFP_KERNEL); - if (!sdhci) { - ret = -ENOMEM; - dev_dbg(&pdev->dev, "cannot allocate memory for sdhci\n"); - goto err_kzalloc; - } - - /* clk enable */ - sdhci->clk = clk_get(&pdev->dev, NULL); - if (IS_ERR(sdhci->clk)) { - ret = PTR_ERR(sdhci->clk); - dev_dbg(&pdev->dev, "Error getting clock\n"); - goto err_clk_get; - } - - ret = clk_enable(sdhci->clk); - if (ret) { - dev_dbg(&pdev->dev, "Error enabling clock\n"); - goto err_clk_enb; - } - - /* overwrite platform_data */ - sdhci->data = dev_get_platdata(&pdev->dev); - pdev->dev.platform_data = sdhci; - - if (pdev->dev.parent) - host = sdhci_alloc_host(pdev->dev.parent, 0); - else - host = sdhci_alloc_host(&pdev->dev, 0); - - if (IS_ERR(host)) { - ret = PTR_ERR(host); - dev_dbg(&pdev->dev, "error allocating host\n"); - goto err_alloc_host; - } - - host->hw_name = "sdhci"; - host->ops = &sdhci_pltfm_ops; - host->irq = platform_get_irq(pdev, 0); - host->quirks = SDHCI_QUIRK_BROKEN_ADMA; - - host->ioaddr = ioremap(iomem->start, resource_size(iomem)); - if (!host->ioaddr) { - ret = -ENOMEM; - dev_dbg(&pdev->dev, "failed to remap registers\n"); - goto err_ioremap; - } - - ret = sdhci_add_host(host); - if (ret) { - dev_dbg(&pdev->dev, "error adding host\n"); - goto err_add_host; - } - - platform_set_drvdata(pdev, host); - - /* - * It is optional to use GPIOs for sdhci Power control & sdhci card - * interrupt detection. If sdhci->data is NULL, then use original sdhci - * lines otherwise GPIO lines. - * If GPIO is selected for power control, then power should be disabled - * after card removal and should be enabled when card insertion - * interrupt occurs - */ - if (!sdhci->data) - return 0; - - if (sdhci->data->card_power_gpio >= 0) { - int val = 0; - - ret = gpio_request(sdhci->data->card_power_gpio, "sdhci"); - if (ret < 0) { - dev_dbg(&pdev->dev, "gpio request fail: %d\n", - sdhci->data->card_power_gpio); - goto err_pgpio_request; - } - - if (sdhci->data->power_always_enb) - val = sdhci->data->power_active_high; - else - val = !sdhci->data->power_active_high; - - ret = gpio_direction_output(sdhci->data->card_power_gpio, val); - if (ret) { - dev_dbg(&pdev->dev, "gpio set direction fail: %d\n", - sdhci->data->card_power_gpio); - goto err_pgpio_direction; - } - } - - if (sdhci->data->card_int_gpio >= 0) { - ret = gpio_request(sdhci->data->card_int_gpio, "sdhci"); - if (ret < 0) { - dev_dbg(&pdev->dev, "gpio request fail: %d\n", - sdhci->data->card_int_gpio); - goto err_igpio_request; - } - - ret = gpio_direction_input(sdhci->data->card_int_gpio); - if (ret) { - dev_dbg(&pdev->dev, "gpio set direction fail: %d\n", - sdhci->data->card_int_gpio); - goto err_igpio_direction; - } - ret = request_irq(gpio_to_irq(sdhci->data->card_int_gpio), - sdhci_gpio_irq, IRQF_TRIGGER_LOW, - mmc_hostname(host->mmc), pdev); - if (ret) { - dev_dbg(&pdev->dev, "gpio request irq fail: %d\n", - sdhci->data->card_int_gpio); - goto err_igpio_request_irq; - } - - } - - return 0; - -err_igpio_request_irq: -err_igpio_direction: - if (sdhci->data->card_int_gpio >= 0) - gpio_free(sdhci->data->card_int_gpio); -err_igpio_request: -err_pgpio_direction: - if (sdhci->data->card_power_gpio >= 0) - gpio_free(sdhci->data->card_power_gpio); -err_pgpio_request: - platform_set_drvdata(pdev, NULL); - sdhci_remove_host(host, 1); -err_add_host: - iounmap(host->ioaddr); -err_ioremap: - sdhci_free_host(host); -err_alloc_host: - clk_disable(sdhci->clk); -err_clk_enb: - clk_put(sdhci->clk); -err_clk_get: - kfree(sdhci); -err_kzalloc: - release_mem_region(iomem->start, resource_size(iomem)); -err: - dev_err(&pdev->dev, "spear-sdhci probe failed: %d\n", ret); - return ret; -} - -static int __devexit sdhci_remove(struct platform_device *pdev) -{ - struct sdhci_host *host = platform_get_drvdata(pdev); - struct resource *iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - struct spear_sdhci *sdhci = dev_get_platdata(&pdev->dev); - int dead; - u32 scratch; - - if (sdhci->data) { - if (sdhci->data->card_int_gpio >= 0) { - free_irq(gpio_to_irq(sdhci->data->card_int_gpio), pdev); - gpio_free(sdhci->data->card_int_gpio); - } - - if (sdhci->data->card_power_gpio >= 0) - gpio_free(sdhci->data->card_power_gpio); - } - - platform_set_drvdata(pdev, NULL); - dead = 0; - scratch = readl(host->ioaddr + SDHCI_INT_STATUS); - if (scratch == (u32)-1) - dead = 1; - - sdhci_remove_host(host, dead); - iounmap(host->ioaddr); - sdhci_free_host(host); - clk_disable(sdhci->clk); - clk_put(sdhci->clk); - kfree(sdhci); - if (iomem) - release_mem_region(iomem->start, resource_size(iomem)); - - return 0; -} - -#ifdef CONFIG_PM -static int sdhci_suspend(struct device *dev) -{ - struct sdhci_host *host = dev_get_drvdata(dev); - struct spear_sdhci *sdhci = dev_get_platdata(dev); - int ret; - - ret = sdhci_suspend_host(host); - if (!ret) - clk_disable(sdhci->clk); - - return ret; -} - -static int sdhci_resume(struct device *dev) -{ - struct sdhci_host *host = dev_get_drvdata(dev); - struct spear_sdhci *sdhci = dev_get_platdata(dev); - int ret; - - ret = clk_enable(sdhci->clk); - if (ret) { - dev_dbg(dev, "Resume: Error enabling clock\n"); - return ret; - } - - return sdhci_resume_host(host); -} -#endif - -static SIMPLE_DEV_PM_OPS(sdhci_pm_ops, sdhci_suspend, sdhci_resume); - -static struct platform_driver sdhci_driver = { - .driver = { - .name = "sdhci", - .owner = THIS_MODULE, - .pm = &sdhci_pm_ops, - }, - .probe = sdhci_probe, - .remove = __devexit_p(sdhci_remove), -}; - -module_platform_driver(sdhci_driver); - -MODULE_DESCRIPTION("SPEAr Secure Digital Host Controller Interface driver"); -MODULE_AUTHOR("Viresh Kumar <viresh.kumar@st.com>"); -MODULE_LICENSE("GPL v2"); diff --git a/ANDROID_3.4.5/drivers/mmc/host/sdhci-tegra.c b/ANDROID_3.4.5/drivers/mmc/host/sdhci-tegra.c deleted file mode 100644 index 53b26502..00000000 --- a/ANDROID_3.4.5/drivers/mmc/host/sdhci-tegra.c +++ /dev/null @@ -1,404 +0,0 @@ -/* - * Copyright (C) 2010 Google, Inc. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#include <linux/err.h> -#include <linux/module.h> -#include <linux/init.h> -#include <linux/platform_device.h> -#include <linux/clk.h> -#include <linux/io.h> -#include <linux/of.h> -#include <linux/of_device.h> -#include <linux/of_gpio.h> -#include <linux/gpio.h> -#include <linux/mmc/card.h> -#include <linux/mmc/host.h> - -#include <asm/gpio.h> - -#include <mach/gpio-tegra.h> -#include <mach/sdhci.h> - -#include "sdhci-pltfm.h" - -#define NVQUIRK_FORCE_SDHCI_SPEC_200 BIT(0) -#define NVQUIRK_ENABLE_BLOCK_GAP_DET BIT(1) - -struct sdhci_tegra_soc_data { - struct sdhci_pltfm_data *pdata; - u32 nvquirks; -}; - -struct sdhci_tegra { - const struct tegra_sdhci_platform_data *plat; - const struct sdhci_tegra_soc_data *soc_data; -}; - -static u32 tegra_sdhci_readl(struct sdhci_host *host, int reg) -{ - u32 val; - - if (unlikely(reg == SDHCI_PRESENT_STATE)) { - /* Use wp_gpio here instead? */ - val = readl(host->ioaddr + reg); - return val | SDHCI_WRITE_PROTECT; - } - - return readl(host->ioaddr + reg); -} - -static u16 tegra_sdhci_readw(struct sdhci_host *host, int reg) -{ - struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - struct sdhci_tegra *tegra_host = pltfm_host->priv; - const struct sdhci_tegra_soc_data *soc_data = tegra_host->soc_data; - - if (unlikely((soc_data->nvquirks & NVQUIRK_FORCE_SDHCI_SPEC_200) && - (reg == SDHCI_HOST_VERSION))) { - /* Erratum: Version register is invalid in HW. */ - return SDHCI_SPEC_200; - } - - return readw(host->ioaddr + reg); -} - -static void tegra_sdhci_writel(struct sdhci_host *host, u32 val, int reg) -{ - struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - struct sdhci_tegra *tegra_host = pltfm_host->priv; - const struct sdhci_tegra_soc_data *soc_data = tegra_host->soc_data; - - /* Seems like we're getting spurious timeout and crc errors, so - * disable signalling of them. In case of real errors software - * timers should take care of eventually detecting them. - */ - if (unlikely(reg == SDHCI_SIGNAL_ENABLE)) - val &= ~(SDHCI_INT_TIMEOUT|SDHCI_INT_CRC); - - writel(val, host->ioaddr + reg); - - if (unlikely((soc_data->nvquirks & NVQUIRK_ENABLE_BLOCK_GAP_DET) && - (reg == SDHCI_INT_ENABLE))) { - /* Erratum: Must enable block gap interrupt detection */ - u8 gap_ctrl = readb(host->ioaddr + SDHCI_BLOCK_GAP_CONTROL); - if (val & SDHCI_INT_CARD_INT) - gap_ctrl |= 0x8; - else - gap_ctrl &= ~0x8; - writeb(gap_ctrl, host->ioaddr + SDHCI_BLOCK_GAP_CONTROL); - } -} - -static unsigned int tegra_sdhci_get_ro(struct sdhci_host *host) -{ - struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - struct sdhci_tegra *tegra_host = pltfm_host->priv; - const struct tegra_sdhci_platform_data *plat = tegra_host->plat; - - if (!gpio_is_valid(plat->wp_gpio)) - return -1; - - return gpio_get_value(plat->wp_gpio); -} - -static irqreturn_t carddetect_irq(int irq, void *data) -{ - struct sdhci_host *sdhost = (struct sdhci_host *)data; - - tasklet_schedule(&sdhost->card_tasklet); - return IRQ_HANDLED; -}; - -static int tegra_sdhci_8bit(struct sdhci_host *host, int bus_width) -{ - struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - struct sdhci_tegra *tegra_host = pltfm_host->priv; - const struct tegra_sdhci_platform_data *plat = tegra_host->plat; - u32 ctrl; - - ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL); - if (plat->is_8bit && bus_width == MMC_BUS_WIDTH_8) { - ctrl &= ~SDHCI_CTRL_4BITBUS; - ctrl |= SDHCI_CTRL_8BITBUS; - } else { - ctrl &= ~SDHCI_CTRL_8BITBUS; - if (bus_width == MMC_BUS_WIDTH_4) - ctrl |= SDHCI_CTRL_4BITBUS; - else - ctrl &= ~SDHCI_CTRL_4BITBUS; - } - sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); - return 0; -} - -static struct sdhci_ops tegra_sdhci_ops = { - .get_ro = tegra_sdhci_get_ro, - .read_l = tegra_sdhci_readl, - .read_w = tegra_sdhci_readw, - .write_l = tegra_sdhci_writel, - .platform_8bit_width = tegra_sdhci_8bit, -}; - -#ifdef CONFIG_ARCH_TEGRA_2x_SOC -static struct sdhci_pltfm_data sdhci_tegra20_pdata = { - .quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL | - SDHCI_QUIRK_SINGLE_POWER_WRITE | - SDHCI_QUIRK_NO_HISPD_BIT | - SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC, - .ops = &tegra_sdhci_ops, -}; - -static struct sdhci_tegra_soc_data soc_data_tegra20 = { - .pdata = &sdhci_tegra20_pdata, - .nvquirks = NVQUIRK_FORCE_SDHCI_SPEC_200 | - NVQUIRK_ENABLE_BLOCK_GAP_DET, -}; -#endif - -#ifdef CONFIG_ARCH_TEGRA_3x_SOC -static struct sdhci_pltfm_data sdhci_tegra30_pdata = { - .quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL | - SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK | - SDHCI_QUIRK_SINGLE_POWER_WRITE | - SDHCI_QUIRK_NO_HISPD_BIT | - SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC, - .ops = &tegra_sdhci_ops, -}; - -static struct sdhci_tegra_soc_data soc_data_tegra30 = { - .pdata = &sdhci_tegra30_pdata, -}; -#endif - -static const struct of_device_id sdhci_tegra_dt_match[] __devinitdata = { -#ifdef CONFIG_ARCH_TEGRA_3x_SOC - { .compatible = "nvidia,tegra30-sdhci", .data = &soc_data_tegra30 }, -#endif -#ifdef CONFIG_ARCH_TEGRA_2x_SOC - { .compatible = "nvidia,tegra20-sdhci", .data = &soc_data_tegra20 }, -#endif - {} -}; -MODULE_DEVICE_TABLE(of, sdhci_dt_ids); - -static struct tegra_sdhci_platform_data * __devinit sdhci_tegra_dt_parse_pdata( - struct platform_device *pdev) -{ - struct tegra_sdhci_platform_data *plat; - struct device_node *np = pdev->dev.of_node; - - if (!np) - return NULL; - - plat = devm_kzalloc(&pdev->dev, sizeof(*plat), GFP_KERNEL); - if (!plat) { - dev_err(&pdev->dev, "Can't allocate platform data\n"); - return NULL; - } - - plat->cd_gpio = of_get_named_gpio(np, "cd-gpios", 0); - plat->wp_gpio = of_get_named_gpio(np, "wp-gpios", 0); - plat->power_gpio = of_get_named_gpio(np, "power-gpios", 0); - if (of_find_property(np, "support-8bit", NULL)) - plat->is_8bit = 1; - - return plat; -} - -static int __devinit sdhci_tegra_probe(struct platform_device *pdev) -{ - const struct of_device_id *match; - const struct sdhci_tegra_soc_data *soc_data; - struct sdhci_host *host; - struct sdhci_pltfm_host *pltfm_host; - struct tegra_sdhci_platform_data *plat; - struct sdhci_tegra *tegra_host; - struct clk *clk; - int rc; - - match = of_match_device(sdhci_tegra_dt_match, &pdev->dev); - if (match) - soc_data = match->data; - else - soc_data = &soc_data_tegra20; - - host = sdhci_pltfm_init(pdev, soc_data->pdata); - if (IS_ERR(host)) - return PTR_ERR(host); - - pltfm_host = sdhci_priv(host); - - plat = pdev->dev.platform_data; - - if (plat == NULL) - plat = sdhci_tegra_dt_parse_pdata(pdev); - - if (plat == NULL) { - dev_err(mmc_dev(host->mmc), "missing platform data\n"); - rc = -ENXIO; - goto err_no_plat; - } - - tegra_host = devm_kzalloc(&pdev->dev, sizeof(*tegra_host), GFP_KERNEL); - if (!tegra_host) { - dev_err(mmc_dev(host->mmc), "failed to allocate tegra_host\n"); - rc = -ENOMEM; - goto err_no_plat; - } - - tegra_host->plat = plat; - tegra_host->soc_data = soc_data; - - pltfm_host->priv = tegra_host; - - if (gpio_is_valid(plat->power_gpio)) { - rc = gpio_request(plat->power_gpio, "sdhci_power"); - if (rc) { - dev_err(mmc_dev(host->mmc), - "failed to allocate power gpio\n"); - goto err_power_req; - } - tegra_gpio_enable(plat->power_gpio); - gpio_direction_output(plat->power_gpio, 1); - } - - if (gpio_is_valid(plat->cd_gpio)) { - rc = gpio_request(plat->cd_gpio, "sdhci_cd"); - if (rc) { - dev_err(mmc_dev(host->mmc), - "failed to allocate cd gpio\n"); - goto err_cd_req; - } - tegra_gpio_enable(plat->cd_gpio); - gpio_direction_input(plat->cd_gpio); - - rc = request_irq(gpio_to_irq(plat->cd_gpio), carddetect_irq, - IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, - mmc_hostname(host->mmc), host); - - if (rc) { - dev_err(mmc_dev(host->mmc), "request irq error\n"); - goto err_cd_irq_req; - } - - } - - if (gpio_is_valid(plat->wp_gpio)) { - rc = gpio_request(plat->wp_gpio, "sdhci_wp"); - if (rc) { - dev_err(mmc_dev(host->mmc), - "failed to allocate wp gpio\n"); - goto err_wp_req; - } - tegra_gpio_enable(plat->wp_gpio); - gpio_direction_input(plat->wp_gpio); - } - - clk = clk_get(mmc_dev(host->mmc), NULL); - if (IS_ERR(clk)) { - dev_err(mmc_dev(host->mmc), "clk err\n"); - rc = PTR_ERR(clk); - goto err_clk_get; - } - clk_enable(clk); - pltfm_host->clk = clk; - - host->mmc->pm_caps = plat->pm_flags; - - if (plat->is_8bit) - host->mmc->caps |= MMC_CAP_8_BIT_DATA; - - rc = sdhci_add_host(host); - if (rc) - goto err_add_host; - - return 0; - -err_add_host: - clk_disable(pltfm_host->clk); - clk_put(pltfm_host->clk); -err_clk_get: - if (gpio_is_valid(plat->wp_gpio)) { - tegra_gpio_disable(plat->wp_gpio); - gpio_free(plat->wp_gpio); - } -err_wp_req: - if (gpio_is_valid(plat->cd_gpio)) - free_irq(gpio_to_irq(plat->cd_gpio), host); -err_cd_irq_req: - if (gpio_is_valid(plat->cd_gpio)) { - tegra_gpio_disable(plat->cd_gpio); - gpio_free(plat->cd_gpio); - } -err_cd_req: - if (gpio_is_valid(plat->power_gpio)) { - tegra_gpio_disable(plat->power_gpio); - gpio_free(plat->power_gpio); - } -err_power_req: -err_no_plat: - sdhci_pltfm_free(pdev); - return rc; -} - -static int __devexit sdhci_tegra_remove(struct platform_device *pdev) -{ - struct sdhci_host *host = platform_get_drvdata(pdev); - struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - struct sdhci_tegra *tegra_host = pltfm_host->priv; - const struct tegra_sdhci_platform_data *plat = tegra_host->plat; - int dead = (readl(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff); - - sdhci_remove_host(host, dead); - - if (gpio_is_valid(plat->wp_gpio)) { - tegra_gpio_disable(plat->wp_gpio); - gpio_free(plat->wp_gpio); - } - - if (gpio_is_valid(plat->cd_gpio)) { - free_irq(gpio_to_irq(plat->cd_gpio), host); - tegra_gpio_disable(plat->cd_gpio); - gpio_free(plat->cd_gpio); - } - - if (gpio_is_valid(plat->power_gpio)) { - tegra_gpio_disable(plat->power_gpio); - gpio_free(plat->power_gpio); - } - - clk_disable(pltfm_host->clk); - clk_put(pltfm_host->clk); - - sdhci_pltfm_free(pdev); - - return 0; -} - -static struct platform_driver sdhci_tegra_driver = { - .driver = { - .name = "sdhci-tegra", - .owner = THIS_MODULE, - .of_match_table = sdhci_tegra_dt_match, - .pm = SDHCI_PLTFM_PMOPS, - }, - .probe = sdhci_tegra_probe, - .remove = __devexit_p(sdhci_tegra_remove), -}; - -module_platform_driver(sdhci_tegra_driver); - -MODULE_DESCRIPTION("SDHCI driver for Tegra"); -MODULE_AUTHOR("Google, Inc."); -MODULE_LICENSE("GPL v2"); diff --git a/ANDROID_3.4.5/drivers/mmc/host/sdhci.c b/ANDROID_3.4.5/drivers/mmc/host/sdhci.c deleted file mode 100644 index 37601ec6..00000000 --- a/ANDROID_3.4.5/drivers/mmc/host/sdhci.c +++ /dev/null @@ -1,3136 +0,0 @@ -/* - * linux/drivers/mmc/host/sdhci.c - Secure Digital Host Controller Interface driver - * - * Copyright (C) 2005-2008 Pierre Ossman, All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at - * your option) any later version. - * - * Thanks to the following companies for their support: - * - * - JMicron (hardware and technical support) - */ - -#include <linux/delay.h> -#include <linux/highmem.h> -#include <linux/io.h> -#include <linux/module.h> -#include <linux/dma-mapping.h> -#include <linux/slab.h> -#include <linux/scatterlist.h> -#include <linux/regulator/consumer.h> -#include <linux/pm_runtime.h> - -#include <linux/leds.h> - -#include <linux/mmc/mmc.h> -#include <linux/mmc/host.h> - -#include "sdhci.h" - -#define DRIVER_NAME "sdhci" - -#define DBG(f, x...) \ - pr_debug(DRIVER_NAME " [%s()]: " f, __func__,## x) - -#if defined(CONFIG_LEDS_CLASS) || (defined(CONFIG_LEDS_CLASS_MODULE) && \ - defined(CONFIG_MMC_SDHCI_MODULE)) -#define SDHCI_USE_LEDS_CLASS -#endif - -#define MAX_TUNING_LOOP 40 - -static unsigned int debug_quirks = 0; -static unsigned int debug_quirks2; - -static void sdhci_finish_data(struct sdhci_host *); - -static void sdhci_send_command(struct sdhci_host *, struct mmc_command *); -static void sdhci_finish_command(struct sdhci_host *); -static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode); -static void sdhci_tuning_timer(unsigned long data); - -#ifdef CONFIG_PM_RUNTIME -static int sdhci_runtime_pm_get(struct sdhci_host *host); -static int sdhci_runtime_pm_put(struct sdhci_host *host); -#else -static inline int sdhci_runtime_pm_get(struct sdhci_host *host) -{ - return 0; -} -static inline int sdhci_runtime_pm_put(struct sdhci_host *host) -{ - return 0; -} -#endif - -static void sdhci_dumpregs(struct sdhci_host *host) -{ - pr_debug(DRIVER_NAME ": =========== REGISTER DUMP (%s)===========\n", - mmc_hostname(host->mmc)); - - pr_debug(DRIVER_NAME ": Sys addr: 0x%08x | Version: 0x%08x\n", - sdhci_readl(host, SDHCI_DMA_ADDRESS), - sdhci_readw(host, SDHCI_HOST_VERSION)); - pr_debug(DRIVER_NAME ": Blk size: 0x%08x | Blk cnt: 0x%08x\n", - sdhci_readw(host, SDHCI_BLOCK_SIZE), - sdhci_readw(host, SDHCI_BLOCK_COUNT)); - pr_debug(DRIVER_NAME ": Argument: 0x%08x | Trn mode: 0x%08x\n", - sdhci_readl(host, SDHCI_ARGUMENT), - sdhci_readw(host, SDHCI_TRANSFER_MODE)); - pr_debug(DRIVER_NAME ": Present: 0x%08x | Host ctl: 0x%08x\n", - sdhci_readl(host, SDHCI_PRESENT_STATE), - sdhci_readb(host, SDHCI_HOST_CONTROL)); - pr_debug(DRIVER_NAME ": Power: 0x%08x | Blk gap: 0x%08x\n", - sdhci_readb(host, SDHCI_POWER_CONTROL), - sdhci_readb(host, SDHCI_BLOCK_GAP_CONTROL)); - pr_debug(DRIVER_NAME ": Wake-up: 0x%08x | Clock: 0x%08x\n", - sdhci_readb(host, SDHCI_WAKE_UP_CONTROL), - sdhci_readw(host, SDHCI_CLOCK_CONTROL)); - pr_debug(DRIVER_NAME ": Timeout: 0x%08x | Int stat: 0x%08x\n", - sdhci_readb(host, SDHCI_TIMEOUT_CONTROL), - sdhci_readl(host, SDHCI_INT_STATUS)); - pr_debug(DRIVER_NAME ": Int enab: 0x%08x | Sig enab: 0x%08x\n", - sdhci_readl(host, SDHCI_INT_ENABLE), - sdhci_readl(host, SDHCI_SIGNAL_ENABLE)); - pr_debug(DRIVER_NAME ": AC12 err: 0x%08x | Slot int: 0x%08x\n", - sdhci_readw(host, SDHCI_ACMD12_ERR), - sdhci_readw(host, SDHCI_SLOT_INT_STATUS)); - pr_debug(DRIVER_NAME ": Caps: 0x%08x | Caps_1: 0x%08x\n", - sdhci_readl(host, SDHCI_CAPABILITIES), - sdhci_readl(host, SDHCI_CAPABILITIES_1)); - pr_debug(DRIVER_NAME ": Cmd: 0x%08x | Max curr: 0x%08x\n", - sdhci_readw(host, SDHCI_COMMAND), - sdhci_readl(host, SDHCI_MAX_CURRENT)); - pr_debug(DRIVER_NAME ": Host ctl2: 0x%08x\n", - sdhci_readw(host, SDHCI_HOST_CONTROL2)); - - if (host->flags & SDHCI_USE_ADMA) - pr_debug(DRIVER_NAME ": ADMA Err: 0x%08x | ADMA Ptr: 0x%08x\n", - readl(host->ioaddr + SDHCI_ADMA_ERROR), - readl(host->ioaddr + SDHCI_ADMA_ADDRESS)); - - pr_debug(DRIVER_NAME ": ===========================================\n"); -} - -/*****************************************************************************\ - * * - * Low level functions * - * * -\*****************************************************************************/ - -static void sdhci_clear_set_irqs(struct sdhci_host *host, u32 clear, u32 set) -{ - u32 ier; - - ier = sdhci_readl(host, SDHCI_INT_ENABLE); - ier &= ~clear; - ier |= set; - sdhci_writel(host, ier, SDHCI_INT_ENABLE); - sdhci_writel(host, ier, SDHCI_SIGNAL_ENABLE); -} - -static void sdhci_unmask_irqs(struct sdhci_host *host, u32 irqs) -{ - sdhci_clear_set_irqs(host, 0, irqs); -} - -static void sdhci_mask_irqs(struct sdhci_host *host, u32 irqs) -{ - sdhci_clear_set_irqs(host, irqs, 0); -} - -static void sdhci_set_card_detection(struct sdhci_host *host, bool enable) -{ - u32 present, irqs; - - if ((host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION) || - (host->mmc->caps & MMC_CAP_NONREMOVABLE)) - return; - - present = sdhci_readl(host, SDHCI_PRESENT_STATE) & - SDHCI_CARD_PRESENT; - irqs = present ? SDHCI_INT_CARD_REMOVE : SDHCI_INT_CARD_INSERT; - - if (enable) - sdhci_unmask_irqs(host, irqs); - else - sdhci_mask_irqs(host, irqs); -} - -static void sdhci_enable_card_detection(struct sdhci_host *host) -{ - sdhci_set_card_detection(host, true); -} - -static void sdhci_disable_card_detection(struct sdhci_host *host) -{ - sdhci_set_card_detection(host, false); -} - -static void sdhci_reset(struct sdhci_host *host, u8 mask) -{ - unsigned long timeout; - u32 uninitialized_var(ier); - - if (host->quirks & SDHCI_QUIRK_NO_CARD_NO_RESET) { - if (!(sdhci_readl(host, SDHCI_PRESENT_STATE) & - SDHCI_CARD_PRESENT)) - return; - } - - if (host->quirks & SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET) - ier = sdhci_readl(host, SDHCI_INT_ENABLE); - - if (host->ops->platform_reset_enter) - host->ops->platform_reset_enter(host, mask); - - sdhci_writeb(host, mask, SDHCI_SOFTWARE_RESET); - - if (mask & SDHCI_RESET_ALL) - host->clock = 0; - - /* Wait max 100 ms */ - timeout = 100; - - /* hw clears the bit when it's done */ - while (sdhci_readb(host, SDHCI_SOFTWARE_RESET) & mask) { - if (timeout == 0) { - pr_err("%s: Reset 0x%x never completed.\n", - mmc_hostname(host->mmc), (int)mask); - sdhci_dumpregs(host); - return; - } - timeout--; - mdelay(1); - } - - if (host->ops->platform_reset_exit) - host->ops->platform_reset_exit(host, mask); - - if (host->quirks & SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET) - sdhci_clear_set_irqs(host, SDHCI_INT_ALL_MASK, ier); - - if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) { - if ((host->ops->enable_dma) && (mask & SDHCI_RESET_ALL)) - host->ops->enable_dma(host); - } -} - -static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios); - -static void sdhci_init(struct sdhci_host *host, int soft) -{ - if (soft) - sdhci_reset(host, SDHCI_RESET_CMD|SDHCI_RESET_DATA); - else - sdhci_reset(host, SDHCI_RESET_ALL); - - sdhci_clear_set_irqs(host, SDHCI_INT_ALL_MASK, - SDHCI_INT_BUS_POWER | SDHCI_INT_DATA_END_BIT | - SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_TIMEOUT | SDHCI_INT_INDEX | - SDHCI_INT_END_BIT | SDHCI_INT_CRC | SDHCI_INT_TIMEOUT | - SDHCI_INT_DATA_END | SDHCI_INT_RESPONSE); - - if (soft) { - /* force clock reconfiguration */ - host->clock = 0; - sdhci_set_ios(host->mmc, &host->mmc->ios); - } -} - -static void sdhci_reinit(struct sdhci_host *host) -{ - sdhci_init(host, 0); - sdhci_enable_card_detection(host); -} - -static void sdhci_activate_led(struct sdhci_host *host) -{ - u8 ctrl; - - ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL); - ctrl |= SDHCI_CTRL_LED; - sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); -} - -static void sdhci_deactivate_led(struct sdhci_host *host) -{ - u8 ctrl; - - ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL); - ctrl &= ~SDHCI_CTRL_LED; - sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); -} - -#ifdef SDHCI_USE_LEDS_CLASS -static void sdhci_led_control(struct led_classdev *led, - enum led_brightness brightness) -{ - struct sdhci_host *host = container_of(led, struct sdhci_host, led); - unsigned long flags; - - spin_lock_irqsave(&host->lock, flags); - - if (host->runtime_suspended) - goto out; - - if (brightness == LED_OFF) - sdhci_deactivate_led(host); - else - sdhci_activate_led(host); -out: - spin_unlock_irqrestore(&host->lock, flags); -} -#endif - -/*****************************************************************************\ - * * - * Core functions * - * * -\*****************************************************************************/ - -static void sdhci_read_block_pio(struct sdhci_host *host) -{ - unsigned long flags; - size_t blksize, len, chunk; - u32 uninitialized_var(scratch); - u8 *buf; - - DBG("PIO reading\n"); - - blksize = host->data->blksz; - chunk = 0; - - local_irq_save(flags); - - while (blksize) { - if (!sg_miter_next(&host->sg_miter)) - BUG(); - - len = min(host->sg_miter.length, blksize); - - blksize -= len; - host->sg_miter.consumed = len; - - buf = host->sg_miter.addr; - - while (len) { - if (chunk == 0) { - scratch = sdhci_readl(host, SDHCI_BUFFER); - chunk = 4; - } - - *buf = scratch & 0xFF; - - buf++; - scratch >>= 8; - chunk--; - len--; - } - } - - sg_miter_stop(&host->sg_miter); - - local_irq_restore(flags); -} - -static void sdhci_write_block_pio(struct sdhci_host *host) -{ - unsigned long flags; - size_t blksize, len, chunk; - u32 scratch; - u8 *buf; - - DBG("PIO writing\n"); - - blksize = host->data->blksz; - chunk = 0; - scratch = 0; - - local_irq_save(flags); - - while (blksize) { - if (!sg_miter_next(&host->sg_miter)) - BUG(); - - len = min(host->sg_miter.length, blksize); - - blksize -= len; - host->sg_miter.consumed = len; - - buf = host->sg_miter.addr; - - while (len) { - scratch |= (u32)*buf << (chunk * 8); - - buf++; - chunk++; - len--; - - if ((chunk == 4) || ((len == 0) && (blksize == 0))) { - sdhci_writel(host, scratch, SDHCI_BUFFER); - chunk = 0; - scratch = 0; - } - } - } - - sg_miter_stop(&host->sg_miter); - - local_irq_restore(flags); -} - -static void sdhci_transfer_pio(struct sdhci_host *host) -{ - u32 mask; - - BUG_ON(!host->data); - - if (host->blocks == 0) - return; - - if (host->data->flags & MMC_DATA_READ) - mask = SDHCI_DATA_AVAILABLE; - else - mask = SDHCI_SPACE_AVAILABLE; - - /* - * Some controllers (JMicron JMB38x) mess up the buffer bits - * for transfers < 4 bytes. As long as it is just one block, - * we can ignore the bits. - */ - if ((host->quirks & SDHCI_QUIRK_BROKEN_SMALL_PIO) && - (host->data->blocks == 1)) - mask = ~0; - - while (sdhci_readl(host, SDHCI_PRESENT_STATE) & mask) { - if (host->quirks & SDHCI_QUIRK_PIO_NEEDS_DELAY) - udelay(100); - - if (host->data->flags & MMC_DATA_READ) - sdhci_read_block_pio(host); - else - sdhci_write_block_pio(host); - - host->blocks--; - if (host->blocks == 0) - break; - } - - DBG("PIO transfer complete.\n"); -} - -static char *sdhci_kmap_atomic(struct scatterlist *sg, unsigned long *flags) -{ - local_irq_save(*flags); - return kmap_atomic(sg_page(sg)) + sg->offset; -} - -static void sdhci_kunmap_atomic(void *buffer, unsigned long *flags) -{ - kunmap_atomic(buffer); - local_irq_restore(*flags); -} - -static void sdhci_set_adma_desc(u8 *desc, u32 addr, int len, unsigned cmd) -{ - __le32 *dataddr = (__le32 __force *)(desc + 4); - __le16 *cmdlen = (__le16 __force *)desc; - - /* SDHCI specification says ADMA descriptors should be 4 byte - * aligned, so using 16 or 32bit operations should be safe. */ - - cmdlen[0] = cpu_to_le16(cmd); - cmdlen[1] = cpu_to_le16(len); - - dataddr[0] = cpu_to_le32(addr); -} - -static int sdhci_adma_table_pre(struct sdhci_host *host, - struct mmc_data *data) -{ - int direction; - - u8 *desc; - u8 *align; - dma_addr_t addr; - dma_addr_t align_addr; - int len, offset; - - struct scatterlist *sg; - int i; - char *buffer; - unsigned long flags; - - /* - * The spec does not specify endianness of descriptor table. - * We currently guess that it is LE. - */ - - if (data->flags & MMC_DATA_READ) - direction = DMA_FROM_DEVICE; - else - direction = DMA_TO_DEVICE; - - /* - * The ADMA descriptor table is mapped further down as we - * need to fill it with data first. - */ - - host->align_addr = dma_map_single(mmc_dev(host->mmc), - host->align_buffer, 128 * 4, direction); - if (dma_mapping_error(mmc_dev(host->mmc), host->align_addr)) - goto fail; - BUG_ON(host->align_addr & 0x3); - - host->sg_count = dma_map_sg(mmc_dev(host->mmc), - data->sg, data->sg_len, direction); - if (host->sg_count == 0) - goto unmap_align; - - desc = host->adma_desc; - align = host->align_buffer; - - align_addr = host->align_addr; - - for_each_sg(data->sg, sg, host->sg_count, i) { - addr = sg_dma_address(sg); - len = sg_dma_len(sg); - - /* - * The SDHCI specification states that ADMA - * addresses must be 32-bit aligned. If they - * aren't, then we use a bounce buffer for - * the (up to three) bytes that screw up the - * alignment. - */ - offset = (4 - (addr & 0x3)) & 0x3; - if (offset) { - if (data->flags & MMC_DATA_WRITE) { - buffer = sdhci_kmap_atomic(sg, &flags); - WARN_ON(((long)buffer & PAGE_MASK) > (PAGE_SIZE - 3)); - memcpy(align, buffer, offset); - sdhci_kunmap_atomic(buffer, &flags); - } - - /* tran, valid */ - sdhci_set_adma_desc(desc, align_addr, offset, 0x21); - - BUG_ON(offset > 65536); - - align += 4; - align_addr += 4; - - desc += 8; - - addr += offset; - len -= offset; - } - - BUG_ON(len > 65536); - - /* tran, valid */ - sdhci_set_adma_desc(desc, addr, len, 0x21); - desc += 8; - - /* - * If this triggers then we have a calculation bug - * somewhere. :/ - */ - WARN_ON((desc - host->adma_desc) > (128 * 2 + 1) * 4); - } - - if (host->quirks & SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC) { - /* - * Mark the last descriptor as the terminating descriptor - */ - if (desc != host->adma_desc) { - desc -= 8; - desc[0] |= 0x2; /* end */ - } - } else { - /* - * Add a terminating entry. - */ - - /* nop, end, valid */ - sdhci_set_adma_desc(desc, 0, 0, 0x3); - } - - /* - * Resync align buffer as we might have changed it. - */ - if (data->flags & MMC_DATA_WRITE) { - dma_sync_single_for_device(mmc_dev(host->mmc), - host->align_addr, 128 * 4, direction); - } - - host->adma_addr = dma_map_single(mmc_dev(host->mmc), - host->adma_desc, (128 * 2 + 1) * 4, DMA_TO_DEVICE); - if (dma_mapping_error(mmc_dev(host->mmc), host->adma_addr)) - goto unmap_entries; - BUG_ON(host->adma_addr & 0x3); - - return 0; - -unmap_entries: - dma_unmap_sg(mmc_dev(host->mmc), data->sg, - data->sg_len, direction); -unmap_align: - dma_unmap_single(mmc_dev(host->mmc), host->align_addr, - 128 * 4, direction); -fail: - return -EINVAL; -} - -static void sdhci_adma_table_post(struct sdhci_host *host, - struct mmc_data *data) -{ - int direction; - - struct scatterlist *sg; - int i, size; - u8 *align; - char *buffer; - unsigned long flags; - - if (data->flags & MMC_DATA_READ) - direction = DMA_FROM_DEVICE; - else - direction = DMA_TO_DEVICE; - - dma_unmap_single(mmc_dev(host->mmc), host->adma_addr, - (128 * 2 + 1) * 4, DMA_TO_DEVICE); - - dma_unmap_single(mmc_dev(host->mmc), host->align_addr, - 128 * 4, direction); - - if (data->flags & MMC_DATA_READ) { - dma_sync_sg_for_cpu(mmc_dev(host->mmc), data->sg, - data->sg_len, direction); - - align = host->align_buffer; - - for_each_sg(data->sg, sg, host->sg_count, i) { - if (sg_dma_address(sg) & 0x3) { - size = 4 - (sg_dma_address(sg) & 0x3); - - buffer = sdhci_kmap_atomic(sg, &flags); - WARN_ON(((long)buffer & PAGE_MASK) > (PAGE_SIZE - 3)); - memcpy(buffer, align, size); - sdhci_kunmap_atomic(buffer, &flags); - - align += 4; - } - } - } - - dma_unmap_sg(mmc_dev(host->mmc), data->sg, - data->sg_len, direction); -} - -static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd) -{ - u8 count; - struct mmc_data *data = cmd->data; - unsigned target_timeout, current_timeout; - - /* - * If the host controller provides us with an incorrect timeout - * value, just skip the check and use 0xE. The hardware may take - * longer to time out, but that's much better than having a too-short - * timeout value. - */ - if (host->quirks & SDHCI_QUIRK_BROKEN_TIMEOUT_VAL) - return 0xE; - - /* Unspecified timeout, assume max */ - if (!data && !cmd->cmd_timeout_ms) - return 0xE; - - /* timeout in us */ - if (!data) - target_timeout = cmd->cmd_timeout_ms * 1000; - else { - target_timeout = data->timeout_ns / 1000; - if (host->clock) - target_timeout += data->timeout_clks / host->clock; - } - - /* - * Figure out needed cycles. - * We do this in steps in order to fit inside a 32 bit int. - * The first step is the minimum timeout, which will have a - * minimum resolution of 6 bits: - * (1) 2^13*1000 > 2^22, - * (2) host->timeout_clk < 2^16 - * => - * (1) / (2) > 2^6 - */ - count = 0; - current_timeout = (1 << 13) * 1000 / host->timeout_clk; - while (current_timeout < target_timeout) { - count++; - current_timeout <<= 1; - if (count >= 0xF) - break; - } - - if (count >= 0xF) - count = 0xE; - - return count; -} - -static void sdhci_set_transfer_irqs(struct sdhci_host *host) -{ - u32 pio_irqs = SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL; - u32 dma_irqs = SDHCI_INT_DMA_END | SDHCI_INT_ADMA_ERROR; - - if (host->flags & SDHCI_REQ_USE_DMA) - sdhci_clear_set_irqs(host, pio_irqs, dma_irqs); - else - sdhci_clear_set_irqs(host, dma_irqs, pio_irqs); -} - -static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd) -{ - u8 count; - u8 ctrl; - struct mmc_data *data = cmd->data; - int ret; - - WARN_ON(host->data); - - if (data || (cmd->flags & MMC_RSP_BUSY)) { - count = sdhci_calc_timeout(host, cmd); - sdhci_writeb(host, count, SDHCI_TIMEOUT_CONTROL); - } - - if (!data) - return; - - /* Sanity checks */ - BUG_ON(data->blksz * data->blocks > 524288); - BUG_ON(data->blksz > host->mmc->max_blk_size); - BUG_ON(data->blocks > 65535); - - host->data = data; - host->data_early = 0; - host->data->bytes_xfered = 0; - - if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) - host->flags |= SDHCI_REQ_USE_DMA; - - /* - * FIXME: This doesn't account for merging when mapping the - * scatterlist. - */ - if (host->flags & SDHCI_REQ_USE_DMA) { - int broken, i; - struct scatterlist *sg; - - broken = 0; - if (host->flags & SDHCI_USE_ADMA) { - if (host->quirks & SDHCI_QUIRK_32BIT_ADMA_SIZE) - broken = 1; - } else { - if (host->quirks & SDHCI_QUIRK_32BIT_DMA_SIZE) - broken = 1; - } - - if (unlikely(broken)) { - for_each_sg(data->sg, sg, data->sg_len, i) { - if (sg->length & 0x3) { - DBG("Reverting to PIO because of " - "transfer size (%d)\n", - sg->length); - host->flags &= ~SDHCI_REQ_USE_DMA; - break; - } - } - } - } - - /* - * The assumption here being that alignment is the same after - * translation to device address space. - */ - if (host->flags & SDHCI_REQ_USE_DMA) { - int broken, i; - struct scatterlist *sg; - - broken = 0; - if (host->flags & SDHCI_USE_ADMA) { - /* - * As we use 3 byte chunks to work around - * alignment problems, we need to check this - * quirk. - */ - if (host->quirks & SDHCI_QUIRK_32BIT_ADMA_SIZE) - broken = 1; - } else { - if (host->quirks & SDHCI_QUIRK_32BIT_DMA_ADDR) - broken = 1; - } - - if (unlikely(broken)) { - for_each_sg(data->sg, sg, data->sg_len, i) { - if (sg->offset & 0x3) { - DBG("Reverting to PIO because of " - "bad alignment\n"); - host->flags &= ~SDHCI_REQ_USE_DMA; - break; - } - } - } - } - - if (host->flags & SDHCI_REQ_USE_DMA) { - if (host->flags & SDHCI_USE_ADMA) { - ret = sdhci_adma_table_pre(host, data); - if (ret) { - /* - * This only happens when someone fed - * us an invalid request. - */ - WARN_ON(1); - host->flags &= ~SDHCI_REQ_USE_DMA; - } else { - sdhci_writel(host, host->adma_addr, - SDHCI_ADMA_ADDRESS); - } - } else { - int sg_cnt; - - sg_cnt = dma_map_sg(mmc_dev(host->mmc), - data->sg, data->sg_len, - (data->flags & MMC_DATA_READ) ? - DMA_FROM_DEVICE : - DMA_TO_DEVICE); - if (sg_cnt == 0) { - /* - * This only happens when someone fed - * us an invalid request. - */ - WARN_ON(1); - host->flags &= ~SDHCI_REQ_USE_DMA; - } else { - WARN_ON(sg_cnt != 1); - sdhci_writel(host, sg_dma_address(data->sg), - SDHCI_DMA_ADDRESS); - } - } - } - - /* - * Always adjust the DMA selection as some controllers - * (e.g. JMicron) can't do PIO properly when the selection - * is ADMA. - */ - if (host->version >= SDHCI_SPEC_200) { - ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL); - ctrl &= ~SDHCI_CTRL_DMA_MASK; - if ((host->flags & SDHCI_REQ_USE_DMA) && - (host->flags & SDHCI_USE_ADMA)) - ctrl |= SDHCI_CTRL_ADMA32; - else - ctrl |= SDHCI_CTRL_SDMA; - sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); - } - - if (!(host->flags & SDHCI_REQ_USE_DMA)) { - int flags; - - flags = SG_MITER_ATOMIC; - if (host->data->flags & MMC_DATA_READ) - flags |= SG_MITER_TO_SG; - else - flags |= SG_MITER_FROM_SG; - sg_miter_start(&host->sg_miter, data->sg, data->sg_len, flags); - host->blocks = data->blocks; - } - - sdhci_set_transfer_irqs(host); - - /* Set the DMA boundary value and block size */ - sdhci_writew(host, SDHCI_MAKE_BLKSZ(SDHCI_DEFAULT_BOUNDARY_ARG, - data->blksz), SDHCI_BLOCK_SIZE); - sdhci_writew(host, data->blocks, SDHCI_BLOCK_COUNT); -} - -static void sdhci_set_transfer_mode(struct sdhci_host *host, - struct mmc_command *cmd) -{ - u16 mode; - struct mmc_data *data = cmd->data; - - if (data == NULL) - return; - - WARN_ON(!host->data); - - mode = SDHCI_TRNS_BLK_CNT_EN; - if (mmc_op_multi(cmd->opcode) || data->blocks > 1) { - mode |= SDHCI_TRNS_MULTI; - /* - * If we are sending CMD23, CMD12 never gets sent - * on successful completion (so no Auto-CMD12). - */ - if (!host->mrq->sbc && (host->flags & SDHCI_AUTO_CMD12)) - mode |= SDHCI_TRNS_AUTO_CMD12; - else if (host->mrq->sbc && (host->flags & SDHCI_AUTO_CMD23)) { - mode |= SDHCI_TRNS_AUTO_CMD23; - sdhci_writel(host, host->mrq->sbc->arg, SDHCI_ARGUMENT2); - } - } - - if (data->flags & MMC_DATA_READ) - mode |= SDHCI_TRNS_READ; - if (host->flags & SDHCI_REQ_USE_DMA) - mode |= SDHCI_TRNS_DMA; - - sdhci_writew(host, mode, SDHCI_TRANSFER_MODE); -} - -static void sdhci_finish_data(struct sdhci_host *host) -{ - struct mmc_data *data; - - BUG_ON(!host->data); - - data = host->data; - host->data = NULL; - - if (host->flags & SDHCI_REQ_USE_DMA) { - if (host->flags & SDHCI_USE_ADMA) - sdhci_adma_table_post(host, data); - else { - dma_unmap_sg(mmc_dev(host->mmc), data->sg, - data->sg_len, (data->flags & MMC_DATA_READ) ? - DMA_FROM_DEVICE : DMA_TO_DEVICE); - } - } - - /* - * The specification states that the block count register must - * be updated, but it does not specify at what point in the - * data flow. That makes the register entirely useless to read - * back so we have to assume that nothing made it to the card - * in the event of an error. - */ - if (data->error) - data->bytes_xfered = 0; - else - data->bytes_xfered = data->blksz * data->blocks; - - /* - * Need to send CMD12 if - - * a) open-ended multiblock transfer (no CMD23) - * b) error in multiblock transfer - */ - if (data->stop && - (data->error || - !host->mrq->sbc)) { - - /* - * The controller needs a reset of internal state machines - * upon error conditions. - */ - if (data->error) { - sdhci_reset(host, SDHCI_RESET_CMD); - sdhci_reset(host, SDHCI_RESET_DATA); - } - - sdhci_send_command(host, data->stop); - } else - tasklet_schedule(&host->finish_tasklet); -} - -static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd) -{ - int flags; - u32 mask; - unsigned long timeout; - - WARN_ON(host->cmd); - - /* Wait max 10 ms */ - timeout = 10; - - mask = SDHCI_CMD_INHIBIT; - if ((cmd->data != NULL) || (cmd->flags & MMC_RSP_BUSY)) - mask |= SDHCI_DATA_INHIBIT; - - /* We shouldn't wait for data inihibit for stop commands, even - though they might use busy signaling */ - if (host->mrq->data && (cmd == host->mrq->data->stop)) - mask &= ~SDHCI_DATA_INHIBIT; - - while (sdhci_readl(host, SDHCI_PRESENT_STATE) & mask) { - if (timeout == 0) { - pr_err("%s: Controller never released " - "inhibit bit(s).\n", mmc_hostname(host->mmc)); - sdhci_dumpregs(host); - cmd->error = -EIO; - tasklet_schedule(&host->finish_tasklet); - return; - } - timeout--; - mdelay(1); - } - - mod_timer(&host->timer, jiffies + 10 * HZ); - - host->cmd = cmd; - - sdhci_prepare_data(host, cmd); - - sdhci_writel(host, cmd->arg, SDHCI_ARGUMENT); - - sdhci_set_transfer_mode(host, cmd); - - if ((cmd->flags & MMC_RSP_136) && (cmd->flags & MMC_RSP_BUSY)) { - pr_err("%s: Unsupported response type!\n", - mmc_hostname(host->mmc)); - cmd->error = -EINVAL; - tasklet_schedule(&host->finish_tasklet); - return; - } - - if (!(cmd->flags & MMC_RSP_PRESENT)) - flags = SDHCI_CMD_RESP_NONE; - else if (cmd->flags & MMC_RSP_136) - flags = SDHCI_CMD_RESP_LONG; - else if (cmd->flags & MMC_RSP_BUSY) - flags = SDHCI_CMD_RESP_SHORT_BUSY; - else - flags = SDHCI_CMD_RESP_SHORT; - - if (cmd->flags & MMC_RSP_CRC) - flags |= SDHCI_CMD_CRC; - if (cmd->flags & MMC_RSP_OPCODE) - flags |= SDHCI_CMD_INDEX; - - /* CMD19 is special in that the Data Present Select should be set */ - if (cmd->data || cmd->opcode == MMC_SEND_TUNING_BLOCK || - cmd->opcode == MMC_SEND_TUNING_BLOCK_HS200) - flags |= SDHCI_CMD_DATA; - - sdhci_writew(host, SDHCI_MAKE_CMD(cmd->opcode, flags), SDHCI_COMMAND); -} - -static void sdhci_finish_command(struct sdhci_host *host) -{ - int i; - - BUG_ON(host->cmd == NULL); - - if (host->cmd->flags & MMC_RSP_PRESENT) { - if (host->cmd->flags & MMC_RSP_136) { - /* CRC is stripped so we need to do some shifting. */ - for (i = 0;i < 4;i++) { - host->cmd->resp[i] = sdhci_readl(host, - SDHCI_RESPONSE + (3-i)*4) << 8; - if (i != 3) - host->cmd->resp[i] |= - sdhci_readb(host, - SDHCI_RESPONSE + (3-i)*4-1); - } - } else { - host->cmd->resp[0] = sdhci_readl(host, SDHCI_RESPONSE); - } - } - - host->cmd->error = 0; - - /* Finished CMD23, now send actual command. */ - if (host->cmd == host->mrq->sbc) { - host->cmd = NULL; - sdhci_send_command(host, host->mrq->cmd); - } else { - - /* Processed actual command. */ - if (host->data && host->data_early) - sdhci_finish_data(host); - - if (!host->cmd->data) - tasklet_schedule(&host->finish_tasklet); - - host->cmd = NULL; - } -} - -static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock) -{ - int div = 0; /* Initialized for compiler warning */ - int real_div = div, clk_mul = 1; - u16 clk = 0; - unsigned long timeout; - - if (clock && clock == host->clock) - return; - - host->mmc->actual_clock = 0; - - if (host->ops->set_clock) { - host->ops->set_clock(host, clock); - if (host->quirks & SDHCI_QUIRK_NONSTANDARD_CLOCK) - return; - } - - sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL); - - if (clock == 0) - goto out; - - if (host->version >= SDHCI_SPEC_300) { - /* - * Check if the Host Controller supports Programmable Clock - * Mode. - */ - if (host->clk_mul) { - u16 ctrl; - - /* - * We need to figure out whether the Host Driver needs - * to select Programmable Clock Mode, or the value can - * be set automatically by the Host Controller based on - * the Preset Value registers. - */ - ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2); - if (!(ctrl & SDHCI_CTRL_PRESET_VAL_ENABLE)) { - for (div = 1; div <= 1024; div++) { - if (((host->max_clk * host->clk_mul) / - div) <= clock) - break; - } - /* - * Set Programmable Clock Mode in the Clock - * Control register. - */ - clk = SDHCI_PROG_CLOCK_MODE; - real_div = div; - clk_mul = host->clk_mul; - div--; - } - } else { - /* Version 3.00 divisors must be a multiple of 2. */ - if (host->max_clk <= clock) - div = 1; - else { - for (div = 2; div < SDHCI_MAX_DIV_SPEC_300; - div += 2) { - if ((host->max_clk / div) <= clock) - break; - } - } - real_div = div; - div >>= 1; - } - } else { - /* Version 2.00 divisors must be a power of 2. */ - for (div = 1; div < SDHCI_MAX_DIV_SPEC_200; div *= 2) { - if ((host->max_clk / div) <= clock) - break; - } - real_div = div; - div >>= 1; - } - - if (real_div) - host->mmc->actual_clock = (host->max_clk * clk_mul) / real_div; - - clk |= (div & SDHCI_DIV_MASK) << SDHCI_DIVIDER_SHIFT; - clk |= ((div & SDHCI_DIV_HI_MASK) >> SDHCI_DIV_MASK_LEN) - << SDHCI_DIVIDER_HI_SHIFT; - clk |= SDHCI_CLOCK_INT_EN; - sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); - - /* Wait max 20 ms */ - timeout = 20; - while (!((clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL)) - & SDHCI_CLOCK_INT_STABLE)) { - if (timeout == 0) { - pr_err("%s: Internal clock never " - "stabilised.\n", mmc_hostname(host->mmc)); - sdhci_dumpregs(host); - return; - } - timeout--; - mdelay(1); - } - - clk |= SDHCI_CLOCK_CARD_EN; - sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); - -out: - host->clock = clock; -} - -static int sdhci_set_power(struct sdhci_host *host, unsigned short power) -{ - u8 pwr = 0; - - if (power != (unsigned short)-1) { - switch (1 << power) { - case MMC_VDD_165_195: - pwr = SDHCI_POWER_180; - break; - case MMC_VDD_29_30: - case MMC_VDD_30_31: - pwr = SDHCI_POWER_300; - break; - case MMC_VDD_32_33: - case MMC_VDD_33_34: - pwr = SDHCI_POWER_330; - break; - default: - BUG(); - } - } - - if (host->pwr == pwr) - return -1; - - host->pwr = pwr; - - if (pwr == 0) { - sdhci_writeb(host, 0, SDHCI_POWER_CONTROL); - return 0; - } - - /* - * Spec says that we should clear the power reg before setting - * a new value. Some controllers don't seem to like this though. - */ - if (!(host->quirks & SDHCI_QUIRK_SINGLE_POWER_WRITE)) - sdhci_writeb(host, 0, SDHCI_POWER_CONTROL); - - /* - * At least the Marvell CaFe chip gets confused if we set the voltage - * and set turn on power at the same time, so set the voltage first. - */ - if (host->quirks & SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER) - sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL); - - pwr |= SDHCI_POWER_ON; - - sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL); - - /* - * Some controllers need an extra 10ms delay of 10ms before they - * can apply clock after applying power - */ - if (host->quirks & SDHCI_QUIRK_DELAY_AFTER_POWER) - mdelay(10); - - return power; -} - -/*****************************************************************************\ - * * - * MMC callbacks * - * * -\*****************************************************************************/ - -static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq) -{ - struct sdhci_host *host; - bool present; - unsigned long flags; - - host = mmc_priv(mmc); - - sdhci_runtime_pm_get(host); - - spin_lock_irqsave(&host->lock, flags); - - WARN_ON(host->mrq != NULL); - -#ifndef SDHCI_USE_LEDS_CLASS - sdhci_activate_led(host); -#endif - - /* - * Ensure we don't send the STOP for non-SET_BLOCK_COUNTED - * requests if Auto-CMD12 is enabled. - */ - if (!mrq->sbc && (host->flags & SDHCI_AUTO_CMD12)) { - if (mrq->stop) { - mrq->data->stop = NULL; - mrq->stop = NULL; - } - } - - host->mrq = mrq; - - /* If polling, assume that the card is always present. */ - if (host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION) - present = true; - else - present = sdhci_readl(host, SDHCI_PRESENT_STATE) & - SDHCI_CARD_PRESENT; - - if (!present || host->flags & SDHCI_DEVICE_DEAD) { - host->mrq->cmd->error = -ENOMEDIUM; - tasklet_schedule(&host->finish_tasklet); - } else { - u32 present_state; - - present_state = sdhci_readl(host, SDHCI_PRESENT_STATE); - /* - * Check if the re-tuning timer has already expired and there - * is no on-going data transfer. If so, we need to execute - * tuning procedure before sending command. - */ - if ((host->flags & SDHCI_NEEDS_RETUNING) && - !(present_state & (SDHCI_DOING_WRITE | SDHCI_DOING_READ))) { - spin_unlock_irqrestore(&host->lock, flags); - sdhci_execute_tuning(mmc, mrq->cmd->opcode); - spin_lock_irqsave(&host->lock, flags); - - /* Restore original mmc_request structure */ - host->mrq = mrq; - } - - if (mrq->sbc && !(host->flags & SDHCI_AUTO_CMD23)) - sdhci_send_command(host, mrq->sbc); - else - sdhci_send_command(host, mrq->cmd); - } - - mmiowb(); - spin_unlock_irqrestore(&host->lock, flags); -} - -static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios) -{ - unsigned long flags; - int vdd_bit = -1; - u8 ctrl; - - spin_lock_irqsave(&host->lock, flags); - - if (host->flags & SDHCI_DEVICE_DEAD) { - spin_unlock_irqrestore(&host->lock, flags); - if (host->vmmc && ios->power_mode == MMC_POWER_OFF) - mmc_regulator_set_ocr(host->mmc, host->vmmc, 0); - return; - } - - /* - * Reset the chip on each power off. - * Should clear out any weird states. - */ - if (ios->power_mode == MMC_POWER_OFF) { - sdhci_writel(host, 0, SDHCI_SIGNAL_ENABLE); - sdhci_reinit(host); - } - - sdhci_set_clock(host, ios->clock); - - if (ios->power_mode == MMC_POWER_OFF) - vdd_bit = sdhci_set_power(host, -1); - else - vdd_bit = sdhci_set_power(host, ios->vdd); - - if (host->vmmc && vdd_bit != -1) { - spin_unlock_irqrestore(&host->lock, flags); - mmc_regulator_set_ocr(host->mmc, host->vmmc, vdd_bit); - spin_lock_irqsave(&host->lock, flags); - } - - if (host->ops->platform_send_init_74_clocks) - host->ops->platform_send_init_74_clocks(host, ios->power_mode); - - /* - * If your platform has 8-bit width support but is not a v3 controller, - * or if it requires special setup code, you should implement that in - * platform_8bit_width(). - */ - if (host->ops->platform_8bit_width) - host->ops->platform_8bit_width(host, ios->bus_width); - else { - ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL); - if (ios->bus_width == MMC_BUS_WIDTH_8) { - ctrl &= ~SDHCI_CTRL_4BITBUS; - if (host->version >= SDHCI_SPEC_300) - ctrl |= SDHCI_CTRL_8BITBUS; - } else { - if (host->version >= SDHCI_SPEC_300) - ctrl &= ~SDHCI_CTRL_8BITBUS; - if (ios->bus_width == MMC_BUS_WIDTH_4) - ctrl |= SDHCI_CTRL_4BITBUS; - else - ctrl &= ~SDHCI_CTRL_4BITBUS; - } - sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); - } - - ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL); - - if ((ios->timing == MMC_TIMING_SD_HS || - ios->timing == MMC_TIMING_MMC_HS) - && !(host->quirks & SDHCI_QUIRK_NO_HISPD_BIT)) - ctrl |= SDHCI_CTRL_HISPD; - else - ctrl &= ~SDHCI_CTRL_HISPD; - - if (host->version >= SDHCI_SPEC_300) { - u16 clk, ctrl_2; - unsigned int clock; - - /* In case of UHS-I modes, set High Speed Enable */ - if ((ios->timing == MMC_TIMING_MMC_HS200) || - (ios->timing == MMC_TIMING_UHS_SDR50) || - (ios->timing == MMC_TIMING_UHS_SDR104) || - (ios->timing == MMC_TIMING_UHS_DDR50) || - (ios->timing == MMC_TIMING_UHS_SDR25)) - ctrl |= SDHCI_CTRL_HISPD; - - ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2); - if (!(ctrl_2 & SDHCI_CTRL_PRESET_VAL_ENABLE)) { - sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); - /* - * We only need to set Driver Strength if the - * preset value enable is not set. - */ - ctrl_2 &= ~SDHCI_CTRL_DRV_TYPE_MASK; - if (ios->drv_type == MMC_SET_DRIVER_TYPE_A) - ctrl_2 |= SDHCI_CTRL_DRV_TYPE_A; - else if (ios->drv_type == MMC_SET_DRIVER_TYPE_C) - ctrl_2 |= SDHCI_CTRL_DRV_TYPE_C; - - sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2); - } else { - /* - * According to SDHC Spec v3.00, if the Preset Value - * Enable in the Host Control 2 register is set, we - * need to reset SD Clock Enable before changing High - * Speed Enable to avoid generating clock gliches. - */ - - /* Reset SD Clock Enable */ - clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL); - clk &= ~SDHCI_CLOCK_CARD_EN; - sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); - - sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); - - /* Re-enable SD Clock */ - clock = host->clock; - host->clock = 0; - sdhci_set_clock(host, clock); - } - - - /* Reset SD Clock Enable */ - clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL); - clk &= ~SDHCI_CLOCK_CARD_EN; - sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); - - if (host->ops->set_uhs_signaling) - host->ops->set_uhs_signaling(host, ios->timing); - else { - ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2); - /* Select Bus Speed Mode for host */ - ctrl_2 &= ~SDHCI_CTRL_UHS_MASK; - if (ios->timing == MMC_TIMING_MMC_HS200) - ctrl_2 |= SDHCI_CTRL_HS_SDR200; - else if (ios->timing == MMC_TIMING_UHS_SDR12) - ctrl_2 |= SDHCI_CTRL_UHS_SDR12; - else if (ios->timing == MMC_TIMING_UHS_SDR25) - ctrl_2 |= SDHCI_CTRL_UHS_SDR25; - else if (ios->timing == MMC_TIMING_UHS_SDR50) - ctrl_2 |= SDHCI_CTRL_UHS_SDR50; - else if (ios->timing == MMC_TIMING_UHS_SDR104) - ctrl_2 |= SDHCI_CTRL_UHS_SDR104; - else if (ios->timing == MMC_TIMING_UHS_DDR50) - ctrl_2 |= SDHCI_CTRL_UHS_DDR50; - sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2); - } - - /* Re-enable SD Clock */ - clock = host->clock; - host->clock = 0; - sdhci_set_clock(host, clock); - } else - sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); - - /* - * Some (ENE) controllers go apeshit on some ios operation, - * signalling timeout and CRC errors even on CMD0. Resetting - * it on each ios seems to solve the problem. - */ - if(host->quirks & SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS) - sdhci_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA); - - mmiowb(); - spin_unlock_irqrestore(&host->lock, flags); -} - -static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) -{ - struct sdhci_host *host = mmc_priv(mmc); - - sdhci_runtime_pm_get(host); - sdhci_do_set_ios(host, ios); - sdhci_runtime_pm_put(host); -} - -static int sdhci_check_ro(struct sdhci_host *host) -{ - unsigned long flags; - int is_readonly; - - spin_lock_irqsave(&host->lock, flags); - - if (host->flags & SDHCI_DEVICE_DEAD) - is_readonly = 0; - else if (host->ops->get_ro) - is_readonly = host->ops->get_ro(host); - else - is_readonly = !(sdhci_readl(host, SDHCI_PRESENT_STATE) - & SDHCI_WRITE_PROTECT); - - spin_unlock_irqrestore(&host->lock, flags); - - /* This quirk needs to be replaced by a callback-function later */ - return host->quirks & SDHCI_QUIRK_INVERTED_WRITE_PROTECT ? - !is_readonly : is_readonly; -} - -#define SAMPLE_COUNT 5 - -static int sdhci_do_get_ro(struct sdhci_host *host) -{ - int i, ro_count; - - if (!(host->quirks & SDHCI_QUIRK_UNSTABLE_RO_DETECT)) - return sdhci_check_ro(host); - - ro_count = 0; - for (i = 0; i < SAMPLE_COUNT; i++) { - if (sdhci_check_ro(host)) { - if (++ro_count > SAMPLE_COUNT / 2) - return 1; - } - msleep(30); - } - return 0; -} - -static void sdhci_hw_reset(struct mmc_host *mmc) -{ - struct sdhci_host *host = mmc_priv(mmc); - - if (host->ops && host->ops->hw_reset) - host->ops->hw_reset(host); -} - -static int sdhci_get_ro(struct mmc_host *mmc) -{ - struct sdhci_host *host = mmc_priv(mmc); - int ret; - - sdhci_runtime_pm_get(host); - ret = sdhci_do_get_ro(host); - sdhci_runtime_pm_put(host); - return ret; -} - -static void sdhci_enable_sdio_irq_nolock(struct sdhci_host *host, int enable) -{ - if (host->flags & SDHCI_DEVICE_DEAD) - goto out; - - if (enable) - host->flags |= SDHCI_SDIO_IRQ_ENABLED; - else - host->flags &= ~SDHCI_SDIO_IRQ_ENABLED; - - /* SDIO IRQ will be enabled as appropriate in runtime resume */ - if (host->runtime_suspended) - goto out; - - if (enable) - sdhci_unmask_irqs(host, SDHCI_INT_CARD_INT); - else - sdhci_mask_irqs(host, SDHCI_INT_CARD_INT); -out: - mmiowb(); -} - -static void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable) -{ - struct sdhci_host *host = mmc_priv(mmc); - unsigned long flags; - - spin_lock_irqsave(&host->lock, flags); - sdhci_enable_sdio_irq_nolock(host, enable); - spin_unlock_irqrestore(&host->lock, flags); -} - -static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host, - struct mmc_ios *ios) -{ - u8 pwr; - u16 clk, ctrl; - u32 present_state; - - /* - * Signal Voltage Switching is only applicable for Host Controllers - * v3.00 and above. - */ - if (host->version < SDHCI_SPEC_300) - return 0; - - /* - * We first check whether the request is to set signalling voltage - * to 3.3V. If so, we change the voltage to 3.3V and return quickly. - */ - ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2); - if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) { - /* Set 1.8V Signal Enable in the Host Control2 register to 0 */ - ctrl &= ~SDHCI_CTRL_VDD_180; - sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2); - - /* Wait for 5ms */ - usleep_range(5000, 5500); - - /* 3.3V regulator output should be stable within 5 ms */ - ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2); - if (!(ctrl & SDHCI_CTRL_VDD_180)) - return 0; - else { - pr_info(DRIVER_NAME ": Switching to 3.3V " - "signalling voltage failed\n"); - return -EIO; - } - } else if (!(ctrl & SDHCI_CTRL_VDD_180) && - (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_180)) { - /* Stop SDCLK */ - clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL); - clk &= ~SDHCI_CLOCK_CARD_EN; - sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); - - /* Check whether DAT[3:0] is 0000 */ - present_state = sdhci_readl(host, SDHCI_PRESENT_STATE); - if (!((present_state & SDHCI_DATA_LVL_MASK) >> - SDHCI_DATA_LVL_SHIFT)) { - /* - * Enable 1.8V Signal Enable in the Host Control2 - * register - */ - ctrl |= SDHCI_CTRL_VDD_180; - sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2); - - /* Wait for 5ms */ - usleep_range(5000, 5500); - - ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2); - if (ctrl & SDHCI_CTRL_VDD_180) { - /* Provide SDCLK again and wait for 1ms*/ - clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL); - clk |= SDHCI_CLOCK_CARD_EN; - sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); - usleep_range(1000, 1500); - - /* - * If DAT[3:0] level is 1111b, then the card - * was successfully switched to 1.8V signaling. - */ - present_state = sdhci_readl(host, - SDHCI_PRESENT_STATE); - if ((present_state & SDHCI_DATA_LVL_MASK) == - SDHCI_DATA_LVL_MASK) - return 0; - } - } - - /* - * If we are here, that means the switch to 1.8V signaling - * failed. We power cycle the card, and retry initialization - * sequence by setting S18R to 0. - */ - pwr = sdhci_readb(host, SDHCI_POWER_CONTROL); - pwr &= ~SDHCI_POWER_ON; - sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL); - - /* Wait for 1ms as per the spec */ - usleep_range(1000, 1500); - pwr |= SDHCI_POWER_ON; - sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL); - - pr_info(DRIVER_NAME ": Switching to 1.8V signalling " - "voltage failed, retrying with S18R set to 0\n"); - return -EAGAIN; - } else - /* No signal voltage switch required */ - return 0; -} - -static int sdhci_start_signal_voltage_switch(struct mmc_host *mmc, - struct mmc_ios *ios) -{ - struct sdhci_host *host = mmc_priv(mmc); - int err; - - if (host->version < SDHCI_SPEC_300) - return 0; - sdhci_runtime_pm_get(host); - err = sdhci_do_start_signal_voltage_switch(host, ios); - sdhci_runtime_pm_put(host); - return err; -} - -static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode) -{ - struct sdhci_host *host; - u16 ctrl; - u32 ier; - int tuning_loop_counter = MAX_TUNING_LOOP; - unsigned long timeout; - int err = 0; - bool requires_tuning_nonuhs = false; - - host = mmc_priv(mmc); - - sdhci_runtime_pm_get(host); - disable_irq(host->irq); - spin_lock(&host->lock); - - ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2); - - /* - * The Host Controller needs tuning only in case of SDR104 mode - * and for SDR50 mode when Use Tuning for SDR50 is set in the - * Capabilities register. - * If the Host Controller supports the HS200 mode then the - * tuning function has to be executed. - */ - if (((ctrl & SDHCI_CTRL_UHS_MASK) == SDHCI_CTRL_UHS_SDR50) && - (host->flags & SDHCI_SDR50_NEEDS_TUNING || - host->flags & SDHCI_HS200_NEEDS_TUNING)) - requires_tuning_nonuhs = true; - - if (((ctrl & SDHCI_CTRL_UHS_MASK) == SDHCI_CTRL_UHS_SDR104) || - requires_tuning_nonuhs) - ctrl |= SDHCI_CTRL_EXEC_TUNING; - else { - spin_unlock(&host->lock); - enable_irq(host->irq); - sdhci_runtime_pm_put(host); - return 0; - } - - sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2); - - /* - * As per the Host Controller spec v3.00, tuning command - * generates Buffer Read Ready interrupt, so enable that. - * - * Note: The spec clearly says that when tuning sequence - * is being performed, the controller does not generate - * interrupts other than Buffer Read Ready interrupt. But - * to make sure we don't hit a controller bug, we _only_ - * enable Buffer Read Ready interrupt here. - */ - ier = sdhci_readl(host, SDHCI_INT_ENABLE); - sdhci_clear_set_irqs(host, ier, SDHCI_INT_DATA_AVAIL); - - /* - * Issue CMD19 repeatedly till Execute Tuning is set to 0 or the number - * of loops reaches 40 times or a timeout of 150ms occurs. - */ - timeout = 150; - do { - struct mmc_command cmd = {0}; - struct mmc_request mrq = {NULL}; - - if (!tuning_loop_counter && !timeout) - break; - - cmd.opcode = opcode; - cmd.arg = 0; - cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; - cmd.retries = 0; - cmd.data = NULL; - cmd.error = 0; - - mrq.cmd = &cmd; - host->mrq = &mrq; - - /* - * In response to CMD19, the card sends 64 bytes of tuning - * block to the Host Controller. So we set the block size - * to 64 here. - */ - if (cmd.opcode == MMC_SEND_TUNING_BLOCK_HS200) { - if (mmc->ios.bus_width == MMC_BUS_WIDTH_8) - sdhci_writew(host, SDHCI_MAKE_BLKSZ(7, 128), - SDHCI_BLOCK_SIZE); - else if (mmc->ios.bus_width == MMC_BUS_WIDTH_4) - sdhci_writew(host, SDHCI_MAKE_BLKSZ(7, 64), - SDHCI_BLOCK_SIZE); - } else { - sdhci_writew(host, SDHCI_MAKE_BLKSZ(7, 64), - SDHCI_BLOCK_SIZE); - } - - /* - * The tuning block is sent by the card to the host controller. - * So we set the TRNS_READ bit in the Transfer Mode register. - * This also takes care of setting DMA Enable and Multi Block - * Select in the same register to 0. - */ - sdhci_writew(host, SDHCI_TRNS_READ, SDHCI_TRANSFER_MODE); - - sdhci_send_command(host, &cmd); - - host->cmd = NULL; - host->mrq = NULL; - - spin_unlock(&host->lock); - enable_irq(host->irq); - - /* Wait for Buffer Read Ready interrupt */ - wait_event_interruptible_timeout(host->buf_ready_int, - (host->tuning_done == 1), - msecs_to_jiffies(50)); - disable_irq(host->irq); - spin_lock(&host->lock); - - if (!host->tuning_done) { - pr_info(DRIVER_NAME ": Timeout waiting for " - "Buffer Read Ready interrupt during tuning " - "procedure, falling back to fixed sampling " - "clock\n"); - ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2); - ctrl &= ~SDHCI_CTRL_TUNED_CLK; - ctrl &= ~SDHCI_CTRL_EXEC_TUNING; - sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2); - - err = -EIO; - goto out; - } - - host->tuning_done = 0; - - ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2); - tuning_loop_counter--; - timeout--; - mdelay(1); - } while (ctrl & SDHCI_CTRL_EXEC_TUNING); - - /* - * The Host Driver has exhausted the maximum number of loops allowed, - * so use fixed sampling frequency. - */ - if (!tuning_loop_counter || !timeout) { - ctrl &= ~SDHCI_CTRL_TUNED_CLK; - sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2); - } else { - if (!(ctrl & SDHCI_CTRL_TUNED_CLK)) { - pr_info(DRIVER_NAME ": Tuning procedure" - " failed, falling back to fixed sampling" - " clock\n"); - err = -EIO; - } - } - -out: - /* - * If this is the very first time we are here, we start the retuning - * timer. Since only during the first time, SDHCI_NEEDS_RETUNING - * flag won't be set, we check this condition before actually starting - * the timer. - */ - if (!(host->flags & SDHCI_NEEDS_RETUNING) && host->tuning_count && - (host->tuning_mode == SDHCI_TUNING_MODE_1)) { - mod_timer(&host->tuning_timer, jiffies + - host->tuning_count * HZ); - /* Tuning mode 1 limits the maximum data length to 4MB */ - mmc->max_blk_count = (4 * 1024 * 1024) / mmc->max_blk_size; - } else { - host->flags &= ~SDHCI_NEEDS_RETUNING; - /* Reload the new initial value for timer */ - if (host->tuning_mode == SDHCI_TUNING_MODE_1) - mod_timer(&host->tuning_timer, jiffies + - host->tuning_count * HZ); - } - - /* - * In case tuning fails, host controllers which support re-tuning can - * try tuning again at a later time, when the re-tuning timer expires. - * So for these controllers, we return 0. Since there might be other - * controllers who do not have this capability, we return error for - * them. - */ - if (err && host->tuning_count && - host->tuning_mode == SDHCI_TUNING_MODE_1) - err = 0; - - sdhci_clear_set_irqs(host, SDHCI_INT_DATA_AVAIL, ier); - spin_unlock(&host->lock); - enable_irq(host->irq); - sdhci_runtime_pm_put(host); - - return err; -} - -static void sdhci_do_enable_preset_value(struct sdhci_host *host, bool enable) -{ - u16 ctrl; - unsigned long flags; - - /* Host Controller v3.00 defines preset value registers */ - if (host->version < SDHCI_SPEC_300) - return; - - spin_lock_irqsave(&host->lock, flags); - - ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2); - - /* - * We only enable or disable Preset Value if they are not already - * enabled or disabled respectively. Otherwise, we bail out. - */ - if (enable && !(ctrl & SDHCI_CTRL_PRESET_VAL_ENABLE)) { - ctrl |= SDHCI_CTRL_PRESET_VAL_ENABLE; - sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2); - host->flags |= SDHCI_PV_ENABLED; - } else if (!enable && (ctrl & SDHCI_CTRL_PRESET_VAL_ENABLE)) { - ctrl &= ~SDHCI_CTRL_PRESET_VAL_ENABLE; - sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2); - host->flags &= ~SDHCI_PV_ENABLED; - } - - spin_unlock_irqrestore(&host->lock, flags); -} - -static void sdhci_enable_preset_value(struct mmc_host *mmc, bool enable) -{ - struct sdhci_host *host = mmc_priv(mmc); - - sdhci_runtime_pm_get(host); - sdhci_do_enable_preset_value(host, enable); - sdhci_runtime_pm_put(host); -} - -static const struct mmc_host_ops sdhci_ops = { - .request = sdhci_request, - .set_ios = sdhci_set_ios, - .get_ro = sdhci_get_ro, - .hw_reset = sdhci_hw_reset, - .enable_sdio_irq = sdhci_enable_sdio_irq, - .start_signal_voltage_switch = sdhci_start_signal_voltage_switch, - .execute_tuning = sdhci_execute_tuning, - .enable_preset_value = sdhci_enable_preset_value, -}; - -/*****************************************************************************\ - * * - * Tasklets * - * * -\*****************************************************************************/ - -static void sdhci_tasklet_card(unsigned long param) -{ - struct sdhci_host *host; - unsigned long flags; - - host = (struct sdhci_host*)param; - - spin_lock_irqsave(&host->lock, flags); - - /* Check host->mrq first in case we are runtime suspended */ - if (host->mrq && - !(sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT)) { - pr_err("%s: Card removed during transfer!\n", - mmc_hostname(host->mmc)); - pr_err("%s: Resetting controller.\n", - mmc_hostname(host->mmc)); - - sdhci_reset(host, SDHCI_RESET_CMD); - sdhci_reset(host, SDHCI_RESET_DATA); - - host->mrq->cmd->error = -ENOMEDIUM; - tasklet_schedule(&host->finish_tasklet); - } - - spin_unlock_irqrestore(&host->lock, flags); - - mmc_detect_change(host->mmc, msecs_to_jiffies(200)); -} - -static void sdhci_tasklet_finish(unsigned long param) -{ - struct sdhci_host *host; - unsigned long flags; - struct mmc_request *mrq; - - host = (struct sdhci_host*)param; - - spin_lock_irqsave(&host->lock, flags); - - /* - * If this tasklet gets rescheduled while running, it will - * be run again afterwards but without any active request. - */ - if (!host->mrq) { - spin_unlock_irqrestore(&host->lock, flags); - return; - } - - del_timer(&host->timer); - - mrq = host->mrq; - - /* - * The controller needs a reset of internal state machines - * upon error conditions. - */ - if (!(host->flags & SDHCI_DEVICE_DEAD) && - ((mrq->cmd && mrq->cmd->error) || - (mrq->data && (mrq->data->error || - (mrq->data->stop && mrq->data->stop->error))) || - (host->quirks & SDHCI_QUIRK_RESET_AFTER_REQUEST))) { - - /* Some controllers need this kick or reset won't work here */ - if (host->quirks & SDHCI_QUIRK_CLOCK_BEFORE_RESET) { - unsigned int clock; - - /* This is to force an update */ - clock = host->clock; - host->clock = 0; - sdhci_set_clock(host, clock); - } - - /* Spec says we should do both at the same time, but Ricoh - controllers do not like that. */ - sdhci_reset(host, SDHCI_RESET_CMD); - sdhci_reset(host, SDHCI_RESET_DATA); - } - - host->mrq = NULL; - host->cmd = NULL; - host->data = NULL; - -#ifndef SDHCI_USE_LEDS_CLASS - sdhci_deactivate_led(host); -#endif - - mmiowb(); - spin_unlock_irqrestore(&host->lock, flags); - - mmc_request_done(host->mmc, mrq); - sdhci_runtime_pm_put(host); -} - -static void sdhci_timeout_timer(unsigned long data) -{ - struct sdhci_host *host; - unsigned long flags; - - host = (struct sdhci_host*)data; - - spin_lock_irqsave(&host->lock, flags); - - if (host->mrq) { - pr_err("%s: Timeout waiting for hardware " - "interrupt.\n", mmc_hostname(host->mmc)); - sdhci_dumpregs(host); - - if (host->data) { - host->data->error = -ETIMEDOUT; - sdhci_finish_data(host); - } else { - if (host->cmd) - host->cmd->error = -ETIMEDOUT; - else - host->mrq->cmd->error = -ETIMEDOUT; - - tasklet_schedule(&host->finish_tasklet); - } - } - - mmiowb(); - spin_unlock_irqrestore(&host->lock, flags); -} - -static void sdhci_tuning_timer(unsigned long data) -{ - struct sdhci_host *host; - unsigned long flags; - - host = (struct sdhci_host *)data; - - spin_lock_irqsave(&host->lock, flags); - - host->flags |= SDHCI_NEEDS_RETUNING; - - spin_unlock_irqrestore(&host->lock, flags); -} - -/*****************************************************************************\ - * * - * Interrupt handling * - * * -\*****************************************************************************/ - -static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask) -{ - BUG_ON(intmask == 0); - - if (!host->cmd) { - pr_err("%s: Got command interrupt 0x%08x even " - "though no command operation was in progress.\n", - mmc_hostname(host->mmc), (unsigned)intmask); - sdhci_dumpregs(host); - return; - } - - if (intmask & SDHCI_INT_TIMEOUT) - host->cmd->error = -ETIMEDOUT; - else if (intmask & (SDHCI_INT_CRC | SDHCI_INT_END_BIT | - SDHCI_INT_INDEX)) - host->cmd->error = -EILSEQ; - - if (host->cmd->error) { - tasklet_schedule(&host->finish_tasklet); - return; - } - - /* - * The host can send and interrupt when the busy state has - * ended, allowing us to wait without wasting CPU cycles. - * Unfortunately this is overloaded on the "data complete" - * interrupt, so we need to take some care when handling - * it. - * - * Note: The 1.0 specification is a bit ambiguous about this - * feature so there might be some problems with older - * controllers. - */ - if (host->cmd->flags & MMC_RSP_BUSY) { - if (host->cmd->data) - DBG("Cannot wait for busy signal when also " - "doing a data transfer"); - else if (!(host->quirks & SDHCI_QUIRK_NO_BUSY_IRQ)) - return; - - /* The controller does not support the end-of-busy IRQ, - * fall through and take the SDHCI_INT_RESPONSE */ - } - - if (intmask & SDHCI_INT_RESPONSE) - sdhci_finish_command(host); -} - -#ifdef CONFIG_MMC_DEBUG -static void sdhci_show_adma_error(struct sdhci_host *host) -{ - const char *name = mmc_hostname(host->mmc); - u8 *desc = host->adma_desc; - __le32 *dma; - __le16 *len; - u8 attr; - - sdhci_dumpregs(host); - - while (true) { - dma = (__le32 *)(desc + 4); - len = (__le16 *)(desc + 2); - attr = *desc; - - DBG("%s: %p: DMA 0x%08x, LEN 0x%04x, Attr=0x%02x\n", - name, desc, le32_to_cpu(*dma), le16_to_cpu(*len), attr); - - desc += 8; - - if (attr & 2) - break; - } -} -#else -static void sdhci_show_adma_error(struct sdhci_host *host) { } -#endif - -static void sdhci_data_irq(struct sdhci_host *host, u32 intmask) -{ - u32 command; - BUG_ON(intmask == 0); - - /* CMD19 generates _only_ Buffer Read Ready interrupt */ - if (intmask & SDHCI_INT_DATA_AVAIL) { - command = SDHCI_GET_CMD(sdhci_readw(host, SDHCI_COMMAND)); - if (command == MMC_SEND_TUNING_BLOCK || - command == MMC_SEND_TUNING_BLOCK_HS200) { - host->tuning_done = 1; - wake_up(&host->buf_ready_int); - return; - } - } - - if (!host->data) { - /* - * The "data complete" interrupt is also used to - * indicate that a busy state has ended. See comment - * above in sdhci_cmd_irq(). - */ - if (host->cmd && (host->cmd->flags & MMC_RSP_BUSY)) { - if (intmask & SDHCI_INT_DATA_END) { - sdhci_finish_command(host); - return; - } - } - - pr_err("%s: Got data interrupt 0x%08x even " - "though no data operation was in progress.\n", - mmc_hostname(host->mmc), (unsigned)intmask); - sdhci_dumpregs(host); - - return; - } - - if (intmask & SDHCI_INT_DATA_TIMEOUT) - host->data->error = -ETIMEDOUT; - else if (intmask & SDHCI_INT_DATA_END_BIT) - host->data->error = -EILSEQ; - else if ((intmask & SDHCI_INT_DATA_CRC) && - SDHCI_GET_CMD(sdhci_readw(host, SDHCI_COMMAND)) - != MMC_BUS_TEST_R) - host->data->error = -EILSEQ; - else if (intmask & SDHCI_INT_ADMA_ERROR) { - pr_err("%s: ADMA error\n", mmc_hostname(host->mmc)); - sdhci_show_adma_error(host); - host->data->error = -EIO; - } - - if (host->data->error) - sdhci_finish_data(host); - else { - if (intmask & (SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL)) - sdhci_transfer_pio(host); - - /* - * We currently don't do anything fancy with DMA - * boundaries, but as we can't disable the feature - * we need to at least restart the transfer. - * - * According to the spec sdhci_readl(host, SDHCI_DMA_ADDRESS) - * should return a valid address to continue from, but as - * some controllers are faulty, don't trust them. - */ - if (intmask & SDHCI_INT_DMA_END) { - u32 dmastart, dmanow; - dmastart = sg_dma_address(host->data->sg); - dmanow = dmastart + host->data->bytes_xfered; - /* - * Force update to the next DMA block boundary. - */ - dmanow = (dmanow & - ~(SDHCI_DEFAULT_BOUNDARY_SIZE - 1)) + - SDHCI_DEFAULT_BOUNDARY_SIZE; - host->data->bytes_xfered = dmanow - dmastart; - DBG("%s: DMA base 0x%08x, transferred 0x%06x bytes," - " next 0x%08x\n", - mmc_hostname(host->mmc), dmastart, - host->data->bytes_xfered, dmanow); - sdhci_writel(host, dmanow, SDHCI_DMA_ADDRESS); - } - - if (intmask & SDHCI_INT_DATA_END) { - if (host->cmd) { - /* - * Data managed to finish before the - * command completed. Make sure we do - * things in the proper order. - */ - host->data_early = 1; - } else { - sdhci_finish_data(host); - } - } - } -} - -static irqreturn_t sdhci_irq(int irq, void *dev_id) -{ - irqreturn_t result; - struct sdhci_host *host = dev_id; - u32 intmask, unexpected = 0; - int cardint = 0, max_loops = 16; - - spin_lock(&host->lock); - - if (host->runtime_suspended) { - spin_unlock(&host->lock); - pr_warning("%s: got irq while runtime suspended\n", - mmc_hostname(host->mmc)); - return IRQ_HANDLED; - } - - intmask = sdhci_readl(host, SDHCI_INT_STATUS); - - if (!intmask || intmask == 0xffffffff) { - result = IRQ_NONE; - goto out; - } - -again: - DBG("*** %s got interrupt: 0x%08x\n", - mmc_hostname(host->mmc), intmask); - - if (intmask & (SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE)) { - u32 present = sdhci_readl(host, SDHCI_PRESENT_STATE) & - SDHCI_CARD_PRESENT; - - /* - * There is a observation on i.mx esdhc. INSERT bit will be - * immediately set again when it gets cleared, if a card is - * inserted. We have to mask the irq to prevent interrupt - * storm which will freeze the system. And the REMOVE gets - * the same situation. - * - * More testing are needed here to ensure it works for other - * platforms though. - */ - sdhci_mask_irqs(host, present ? SDHCI_INT_CARD_INSERT : - SDHCI_INT_CARD_REMOVE); - sdhci_unmask_irqs(host, present ? SDHCI_INT_CARD_REMOVE : - SDHCI_INT_CARD_INSERT); - - sdhci_writel(host, intmask & (SDHCI_INT_CARD_INSERT | - SDHCI_INT_CARD_REMOVE), SDHCI_INT_STATUS); - intmask &= ~(SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE); - tasklet_schedule(&host->card_tasklet); - } - - if (intmask & SDHCI_INT_CMD_MASK) { - sdhci_writel(host, intmask & SDHCI_INT_CMD_MASK, - SDHCI_INT_STATUS); - sdhci_cmd_irq(host, intmask & SDHCI_INT_CMD_MASK); - } - - if (intmask & SDHCI_INT_DATA_MASK) { - sdhci_writel(host, intmask & SDHCI_INT_DATA_MASK, - SDHCI_INT_STATUS); - sdhci_data_irq(host, intmask & SDHCI_INT_DATA_MASK); - } - - intmask &= ~(SDHCI_INT_CMD_MASK | SDHCI_INT_DATA_MASK); - - intmask &= ~SDHCI_INT_ERROR; - - if (intmask & SDHCI_INT_BUS_POWER) { - pr_err("%s: Card is consuming too much power!\n", - mmc_hostname(host->mmc)); - sdhci_writel(host, SDHCI_INT_BUS_POWER, SDHCI_INT_STATUS); - } - - intmask &= ~SDHCI_INT_BUS_POWER; - - if (intmask & SDHCI_INT_CARD_INT) - cardint = 1; - - intmask &= ~SDHCI_INT_CARD_INT; - - if (intmask) { - unexpected |= intmask; - sdhci_writel(host, intmask, SDHCI_INT_STATUS); - } - - result = IRQ_HANDLED; - - intmask = sdhci_readl(host, SDHCI_INT_STATUS); - if (intmask && --max_loops) - goto again; -out: - spin_unlock(&host->lock); - - if (unexpected) { - pr_err("%s: Unexpected interrupt 0x%08x.\n", - mmc_hostname(host->mmc), unexpected); - sdhci_dumpregs(host); - } - /* - * We have to delay this as it calls back into the driver. - */ - if (cardint) - mmc_signal_sdio_irq(host->mmc); - - return result; -} - -/*****************************************************************************\ - * * - * Suspend/resume * - * * -\*****************************************************************************/ - -#ifdef CONFIG_PM - -int sdhci_suspend_host(struct sdhci_host *host) -{ - int ret; - bool has_tuning_timer; - - if (host->ops->platform_suspend) - host->ops->platform_suspend(host); - - sdhci_disable_card_detection(host); - - /* Disable tuning since we are suspending */ - has_tuning_timer = host->version >= SDHCI_SPEC_300 && - host->tuning_count && host->tuning_mode == SDHCI_TUNING_MODE_1; - if (has_tuning_timer) { - del_timer_sync(&host->tuning_timer); - host->flags &= ~SDHCI_NEEDS_RETUNING; - } - - ret = mmc_suspend_host(host->mmc); - if (ret) { - if (has_tuning_timer) { - host->flags |= SDHCI_NEEDS_RETUNING; - mod_timer(&host->tuning_timer, jiffies + - host->tuning_count * HZ); - } - - sdhci_enable_card_detection(host); - - return ret; - } - - free_irq(host->irq, host); - - return ret; -} - -EXPORT_SYMBOL_GPL(sdhci_suspend_host); - -int sdhci_resume_host(struct sdhci_host *host) -{ - int ret; - - if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) { - if (host->ops->enable_dma) - host->ops->enable_dma(host); - } - - ret = request_irq(host->irq, sdhci_irq, IRQF_SHARED, - mmc_hostname(host->mmc), host); - if (ret) - return ret; - - if ((host->mmc->pm_flags & MMC_PM_KEEP_POWER) && - (host->quirks2 & SDHCI_QUIRK2_HOST_OFF_CARD_ON)) { - /* Card keeps power but host controller does not */ - sdhci_init(host, 0); - host->pwr = 0; - host->clock = 0; - sdhci_do_set_ios(host, &host->mmc->ios); - } else { - sdhci_init(host, (host->mmc->pm_flags & MMC_PM_KEEP_POWER)); - mmiowb(); - } - - ret = mmc_resume_host(host->mmc); - sdhci_enable_card_detection(host); - - if (host->ops->platform_resume) - host->ops->platform_resume(host); - - /* Set the re-tuning expiration flag */ - if ((host->version >= SDHCI_SPEC_300) && host->tuning_count && - (host->tuning_mode == SDHCI_TUNING_MODE_1)) - host->flags |= SDHCI_NEEDS_RETUNING; - - return ret; -} - -EXPORT_SYMBOL_GPL(sdhci_resume_host); - -void sdhci_enable_irq_wakeups(struct sdhci_host *host) -{ - u8 val; - val = sdhci_readb(host, SDHCI_WAKE_UP_CONTROL); - val |= SDHCI_WAKE_ON_INT; - sdhci_writeb(host, val, SDHCI_WAKE_UP_CONTROL); -} - -EXPORT_SYMBOL_GPL(sdhci_enable_irq_wakeups); - -#endif /* CONFIG_PM */ - -#ifdef CONFIG_PM_RUNTIME - -static int sdhci_runtime_pm_get(struct sdhci_host *host) -{ - return pm_runtime_get_sync(host->mmc->parent); -} - -static int sdhci_runtime_pm_put(struct sdhci_host *host) -{ - pm_runtime_mark_last_busy(host->mmc->parent); - return pm_runtime_put_autosuspend(host->mmc->parent); -} - -int sdhci_runtime_suspend_host(struct sdhci_host *host) -{ - unsigned long flags; - int ret = 0; - - /* Disable tuning since we are suspending */ - if (host->version >= SDHCI_SPEC_300 && - host->tuning_mode == SDHCI_TUNING_MODE_1) { - del_timer_sync(&host->tuning_timer); - host->flags &= ~SDHCI_NEEDS_RETUNING; - } - - spin_lock_irqsave(&host->lock, flags); - sdhci_mask_irqs(host, SDHCI_INT_ALL_MASK); - spin_unlock_irqrestore(&host->lock, flags); - - synchronize_irq(host->irq); - - spin_lock_irqsave(&host->lock, flags); - host->runtime_suspended = true; - spin_unlock_irqrestore(&host->lock, flags); - - return ret; -} -EXPORT_SYMBOL_GPL(sdhci_runtime_suspend_host); - -int sdhci_runtime_resume_host(struct sdhci_host *host) -{ - unsigned long flags; - int ret = 0, host_flags = host->flags; - - if (host_flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) { - if (host->ops->enable_dma) - host->ops->enable_dma(host); - } - - sdhci_init(host, 0); - - /* Force clock and power re-program */ - host->pwr = 0; - host->clock = 0; - sdhci_do_set_ios(host, &host->mmc->ios); - - sdhci_do_start_signal_voltage_switch(host, &host->mmc->ios); - if (host_flags & SDHCI_PV_ENABLED) - sdhci_do_enable_preset_value(host, true); - - /* Set the re-tuning expiration flag */ - if ((host->version >= SDHCI_SPEC_300) && host->tuning_count && - (host->tuning_mode == SDHCI_TUNING_MODE_1)) - host->flags |= SDHCI_NEEDS_RETUNING; - - spin_lock_irqsave(&host->lock, flags); - - host->runtime_suspended = false; - - /* Enable SDIO IRQ */ - if ((host->flags & SDHCI_SDIO_IRQ_ENABLED)) - sdhci_enable_sdio_irq_nolock(host, true); - - /* Enable Card Detection */ - sdhci_enable_card_detection(host); - - spin_unlock_irqrestore(&host->lock, flags); - - return ret; -} -EXPORT_SYMBOL_GPL(sdhci_runtime_resume_host); - -#endif - -/*****************************************************************************\ - * * - * Device allocation/registration * - * * -\*****************************************************************************/ - -struct sdhci_host *sdhci_alloc_host(struct device *dev, - size_t priv_size) -{ - struct mmc_host *mmc; - struct sdhci_host *host; - - WARN_ON(dev == NULL); - - mmc = mmc_alloc_host(sizeof(struct sdhci_host) + priv_size, dev); - if (!mmc) - return ERR_PTR(-ENOMEM); - - host = mmc_priv(mmc); - host->mmc = mmc; - - return host; -} - -EXPORT_SYMBOL_GPL(sdhci_alloc_host); - -int sdhci_add_host(struct sdhci_host *host) -{ - struct mmc_host *mmc; - u32 caps[2]; - u32 max_current_caps; - unsigned int ocr_avail; - int ret; - - WARN_ON(host == NULL); - if (host == NULL) - return -EINVAL; - - mmc = host->mmc; - - if (debug_quirks) - host->quirks = debug_quirks; - if (debug_quirks2) - host->quirks2 = debug_quirks2; - - sdhci_reset(host, SDHCI_RESET_ALL); - - host->version = sdhci_readw(host, SDHCI_HOST_VERSION); - host->version = (host->version & SDHCI_SPEC_VER_MASK) - >> SDHCI_SPEC_VER_SHIFT; - if (host->version > SDHCI_SPEC_300) { - pr_err("%s: Unknown controller version (%d). " - "You may experience problems.\n", mmc_hostname(mmc), - host->version); - } - - caps[0] = (host->quirks & SDHCI_QUIRK_MISSING_CAPS) ? host->caps : - sdhci_readl(host, SDHCI_CAPABILITIES); - - caps[1] = (host->version >= SDHCI_SPEC_300) ? - sdhci_readl(host, SDHCI_CAPABILITIES_1) : 0; - - if (host->quirks & SDHCI_QUIRK_FORCE_DMA) - host->flags |= SDHCI_USE_SDMA; - else if (!(caps[0] & SDHCI_CAN_DO_SDMA)) - DBG("Controller doesn't have SDMA capability\n"); - else - host->flags |= SDHCI_USE_SDMA; - - if ((host->quirks & SDHCI_QUIRK_BROKEN_DMA) && - (host->flags & SDHCI_USE_SDMA)) { - DBG("Disabling DMA as it is marked broken\n"); - host->flags &= ~SDHCI_USE_SDMA; - } - - if ((host->version >= SDHCI_SPEC_200) && - (caps[0] & SDHCI_CAN_DO_ADMA2)) - host->flags |= SDHCI_USE_ADMA; - - if ((host->quirks & SDHCI_QUIRK_BROKEN_ADMA) && - (host->flags & SDHCI_USE_ADMA)) { - DBG("Disabling ADMA as it is marked broken\n"); - host->flags &= ~SDHCI_USE_ADMA; - } - - if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) { - if (host->ops->enable_dma) { - if (host->ops->enable_dma(host)) { - pr_warning("%s: No suitable DMA " - "available. Falling back to PIO.\n", - mmc_hostname(mmc)); - host->flags &= - ~(SDHCI_USE_SDMA | SDHCI_USE_ADMA); - } - } - } - - if (host->flags & SDHCI_USE_ADMA) { - /* - * We need to allocate descriptors for all sg entries - * (128) and potentially one alignment transfer for - * each of those entries. - */ - host->adma_desc = kmalloc((128 * 2 + 1) * 4, GFP_KERNEL); - host->align_buffer = kmalloc(128 * 4, GFP_KERNEL); - if (!host->adma_desc || !host->align_buffer) { - kfree(host->adma_desc); - kfree(host->align_buffer); - pr_warning("%s: Unable to allocate ADMA " - "buffers. Falling back to standard DMA.\n", - mmc_hostname(mmc)); - host->flags &= ~SDHCI_USE_ADMA; - } - } - - /* - * If we use DMA, then it's up to the caller to set the DMA - * mask, but PIO does not need the hw shim so we set a new - * mask here in that case. - */ - if (!(host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA))) { - host->dma_mask = DMA_BIT_MASK(64); - mmc_dev(host->mmc)->dma_mask = &host->dma_mask; - } - - if (host->version >= SDHCI_SPEC_300) - host->max_clk = (caps[0] & SDHCI_CLOCK_V3_BASE_MASK) - >> SDHCI_CLOCK_BASE_SHIFT; - else - host->max_clk = (caps[0] & SDHCI_CLOCK_BASE_MASK) - >> SDHCI_CLOCK_BASE_SHIFT; - - host->max_clk *= 1000000; - if (host->max_clk == 0 || host->quirks & - SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN) { - if (!host->ops->get_max_clock) { - pr_err("%s: Hardware doesn't specify base clock " - "frequency.\n", mmc_hostname(mmc)); - return -ENODEV; - } - host->max_clk = host->ops->get_max_clock(host); - } - - /* - * In case of Host Controller v3.00, find out whether clock - * multiplier is supported. - */ - host->clk_mul = (caps[1] & SDHCI_CLOCK_MUL_MASK) >> - SDHCI_CLOCK_MUL_SHIFT; - - /* - * In case the value in Clock Multiplier is 0, then programmable - * clock mode is not supported, otherwise the actual clock - * multiplier is one more than the value of Clock Multiplier - * in the Capabilities Register. - */ - if (host->clk_mul) - host->clk_mul += 1; - - /* - * Set host parameters. - */ - mmc->ops = &sdhci_ops; - mmc->f_max = host->max_clk; - if (host->ops->get_min_clock) - mmc->f_min = host->ops->get_min_clock(host); - else if (host->version >= SDHCI_SPEC_300) { - if (host->clk_mul) { - mmc->f_min = (host->max_clk * host->clk_mul) / 1024; - mmc->f_max = host->max_clk * host->clk_mul; - } else - mmc->f_min = host->max_clk / SDHCI_MAX_DIV_SPEC_300; - } else - mmc->f_min = host->max_clk / SDHCI_MAX_DIV_SPEC_200; - - host->timeout_clk = - (caps[0] & SDHCI_TIMEOUT_CLK_MASK) >> SDHCI_TIMEOUT_CLK_SHIFT; - if (host->timeout_clk == 0) { - if (host->ops->get_timeout_clock) { - host->timeout_clk = host->ops->get_timeout_clock(host); - } else if (!(host->quirks & - SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK)) { - pr_err("%s: Hardware doesn't specify timeout clock " - "frequency.\n", mmc_hostname(mmc)); - return -ENODEV; - } - } - if (caps[0] & SDHCI_TIMEOUT_CLK_UNIT) - host->timeout_clk *= 1000; - - if (host->quirks & SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK) - host->timeout_clk = mmc->f_max / 1000; - - mmc->max_discard_to = (1 << 27) / host->timeout_clk; - - mmc->caps |= MMC_CAP_SDIO_IRQ | MMC_CAP_ERASE | MMC_CAP_CMD23; - - if (host->quirks & SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12) - host->flags |= SDHCI_AUTO_CMD12; - - /* Auto-CMD23 stuff only works in ADMA or PIO. */ - if ((host->version >= SDHCI_SPEC_300) && - ((host->flags & SDHCI_USE_ADMA) || - !(host->flags & SDHCI_USE_SDMA))) { - host->flags |= SDHCI_AUTO_CMD23; - DBG("%s: Auto-CMD23 available\n", mmc_hostname(mmc)); - } else { - DBG("%s: Auto-CMD23 unavailable\n", mmc_hostname(mmc)); - } - - /* - * A controller may support 8-bit width, but the board itself - * might not have the pins brought out. Boards that support - * 8-bit width must set "mmc->caps |= MMC_CAP_8_BIT_DATA;" in - * their platform code before calling sdhci_add_host(), and we - * won't assume 8-bit width for hosts without that CAP. - */ - if (!(host->quirks & SDHCI_QUIRK_FORCE_1_BIT_DATA)) - mmc->caps |= MMC_CAP_4_BIT_DATA; - - if (caps[0] & SDHCI_CAN_DO_HISPD) - mmc->caps |= MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED; - - if ((host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION) && - mmc_card_is_removable(mmc)) - mmc->caps |= MMC_CAP_NEEDS_POLL; - - /* Any UHS-I mode in caps implies SDR12 and SDR25 support. */ - if (caps[1] & (SDHCI_SUPPORT_SDR104 | SDHCI_SUPPORT_SDR50 | - SDHCI_SUPPORT_DDR50)) - mmc->caps |= MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25; - - /* SDR104 supports also implies SDR50 support */ - if (caps[1] & SDHCI_SUPPORT_SDR104) - mmc->caps |= MMC_CAP_UHS_SDR104 | MMC_CAP_UHS_SDR50; - else if (caps[1] & SDHCI_SUPPORT_SDR50) - mmc->caps |= MMC_CAP_UHS_SDR50; - - if (caps[1] & SDHCI_SUPPORT_DDR50) - mmc->caps |= MMC_CAP_UHS_DDR50; - - /* Does the host need tuning for SDR50? */ - if (caps[1] & SDHCI_USE_SDR50_TUNING) - host->flags |= SDHCI_SDR50_NEEDS_TUNING; - - /* Does the host need tuning for HS200? */ - if (mmc->caps2 & MMC_CAP2_HS200) - host->flags |= SDHCI_HS200_NEEDS_TUNING; - - /* Driver Type(s) (A, C, D) supported by the host */ - if (caps[1] & SDHCI_DRIVER_TYPE_A) - mmc->caps |= MMC_CAP_DRIVER_TYPE_A; - if (caps[1] & SDHCI_DRIVER_TYPE_C) - mmc->caps |= MMC_CAP_DRIVER_TYPE_C; - if (caps[1] & SDHCI_DRIVER_TYPE_D) - mmc->caps |= MMC_CAP_DRIVER_TYPE_D; - - /* - * If Power Off Notify capability is enabled by the host, - * set notify to short power off notify timeout value. - */ - if (mmc->caps2 & MMC_CAP2_POWEROFF_NOTIFY) - mmc->power_notify_type = MMC_HOST_PW_NOTIFY_SHORT; - else - mmc->power_notify_type = MMC_HOST_PW_NOTIFY_NONE; - - /* Initial value for re-tuning timer count */ - host->tuning_count = (caps[1] & SDHCI_RETUNING_TIMER_COUNT_MASK) >> - SDHCI_RETUNING_TIMER_COUNT_SHIFT; - - /* - * In case Re-tuning Timer is not disabled, the actual value of - * re-tuning timer will be 2 ^ (n - 1). - */ - if (host->tuning_count) - host->tuning_count = 1 << (host->tuning_count - 1); - - /* Re-tuning mode supported by the Host Controller */ - host->tuning_mode = (caps[1] & SDHCI_RETUNING_MODE_MASK) >> - SDHCI_RETUNING_MODE_SHIFT; - - ocr_avail = 0; - /* - * According to SD Host Controller spec v3.00, if the Host System - * can afford more than 150mA, Host Driver should set XPC to 1. Also - * the value is meaningful only if Voltage Support in the Capabilities - * register is set. The actual current value is 4 times the register - * value. - */ - max_current_caps = sdhci_readl(host, SDHCI_MAX_CURRENT); - - if (caps[0] & SDHCI_CAN_VDD_330) { - int max_current_330; - - ocr_avail |= MMC_VDD_32_33 | MMC_VDD_33_34; - - max_current_330 = ((max_current_caps & - SDHCI_MAX_CURRENT_330_MASK) >> - SDHCI_MAX_CURRENT_330_SHIFT) * - SDHCI_MAX_CURRENT_MULTIPLIER; - - if (max_current_330 > 150) - mmc->caps |= MMC_CAP_SET_XPC_330; - } - if (caps[0] & SDHCI_CAN_VDD_300) { - int max_current_300; - - ocr_avail |= MMC_VDD_29_30 | MMC_VDD_30_31; - - max_current_300 = ((max_current_caps & - SDHCI_MAX_CURRENT_300_MASK) >> - SDHCI_MAX_CURRENT_300_SHIFT) * - SDHCI_MAX_CURRENT_MULTIPLIER; - - if (max_current_300 > 150) - mmc->caps |= MMC_CAP_SET_XPC_300; - } - if (caps[0] & SDHCI_CAN_VDD_180) { - int max_current_180; - - ocr_avail |= MMC_VDD_165_195; - - max_current_180 = ((max_current_caps & - SDHCI_MAX_CURRENT_180_MASK) >> - SDHCI_MAX_CURRENT_180_SHIFT) * - SDHCI_MAX_CURRENT_MULTIPLIER; - - if (max_current_180 > 150) - mmc->caps |= MMC_CAP_SET_XPC_180; - - /* Maximum current capabilities of the host at 1.8V */ - if (max_current_180 >= 800) - mmc->caps |= MMC_CAP_MAX_CURRENT_800; - else if (max_current_180 >= 600) - mmc->caps |= MMC_CAP_MAX_CURRENT_600; - else if (max_current_180 >= 400) - mmc->caps |= MMC_CAP_MAX_CURRENT_400; - else - mmc->caps |= MMC_CAP_MAX_CURRENT_200; - } - - mmc->ocr_avail = ocr_avail; - mmc->ocr_avail_sdio = ocr_avail; - if (host->ocr_avail_sdio) - mmc->ocr_avail_sdio &= host->ocr_avail_sdio; - mmc->ocr_avail_sd = ocr_avail; - if (host->ocr_avail_sd) - mmc->ocr_avail_sd &= host->ocr_avail_sd; - else /* normal SD controllers don't support 1.8V */ - mmc->ocr_avail_sd &= ~MMC_VDD_165_195; - mmc->ocr_avail_mmc = ocr_avail; - if (host->ocr_avail_mmc) - mmc->ocr_avail_mmc &= host->ocr_avail_mmc; - - if (mmc->ocr_avail == 0) { - pr_err("%s: Hardware doesn't report any " - "support voltages.\n", mmc_hostname(mmc)); - return -ENODEV; - } - - spin_lock_init(&host->lock); - - /* - * Maximum number of segments. Depends on if the hardware - * can do scatter/gather or not. - */ - if (host->flags & SDHCI_USE_ADMA) - mmc->max_segs = 128; - else if (host->flags & SDHCI_USE_SDMA) - mmc->max_segs = 1; - else /* PIO */ - mmc->max_segs = 128; - - /* - * Maximum number of sectors in one transfer. Limited by DMA boundary - * size (512KiB). - */ - mmc->max_req_size = 524288; - - /* - * Maximum segment size. Could be one segment with the maximum number - * of bytes. When doing hardware scatter/gather, each entry cannot - * be larger than 64 KiB though. - */ - if (host->flags & SDHCI_USE_ADMA) { - if (host->quirks & SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC) - mmc->max_seg_size = 65535; - else - mmc->max_seg_size = 65536; - } else { - mmc->max_seg_size = mmc->max_req_size; - } - - /* - * Maximum block size. This varies from controller to controller and - * is specified in the capabilities register. - */ - if (host->quirks & SDHCI_QUIRK_FORCE_BLK_SZ_2048) { - mmc->max_blk_size = 2; - } else { - mmc->max_blk_size = (caps[0] & SDHCI_MAX_BLOCK_MASK) >> - SDHCI_MAX_BLOCK_SHIFT; - if (mmc->max_blk_size >= 3) { - pr_warning("%s: Invalid maximum block size, " - "assuming 512 bytes\n", mmc_hostname(mmc)); - mmc->max_blk_size = 0; - } - } - - mmc->max_blk_size = 512 << mmc->max_blk_size; - - /* - * Maximum block count. - */ - mmc->max_blk_count = (host->quirks & SDHCI_QUIRK_NO_MULTIBLOCK) ? 1 : 65535; - - /* - * Init tasklets. - */ - tasklet_init(&host->card_tasklet, - sdhci_tasklet_card, (unsigned long)host); - tasklet_init(&host->finish_tasklet, - sdhci_tasklet_finish, (unsigned long)host); - - setup_timer(&host->timer, sdhci_timeout_timer, (unsigned long)host); - - if (host->version >= SDHCI_SPEC_300) { - init_waitqueue_head(&host->buf_ready_int); - - /* Initialize re-tuning timer */ - init_timer(&host->tuning_timer); - host->tuning_timer.data = (unsigned long)host; - host->tuning_timer.function = sdhci_tuning_timer; - } - - ret = request_irq(host->irq, sdhci_irq, IRQF_SHARED, - mmc_hostname(mmc), host); - if (ret) - goto untasklet; - - host->vmmc = regulator_get(mmc_dev(mmc), "vmmc"); - if (IS_ERR(host->vmmc)) { - pr_info("%s: no vmmc regulator found\n", mmc_hostname(mmc)); - host->vmmc = NULL; - } - - sdhci_init(host, 0); - -#ifdef CONFIG_MMC_DEBUG - sdhci_dumpregs(host); -#endif - -#ifdef SDHCI_USE_LEDS_CLASS - snprintf(host->led_name, sizeof(host->led_name), - "%s::", mmc_hostname(mmc)); - host->led.name = host->led_name; - host->led.brightness = LED_OFF; - host->led.default_trigger = mmc_hostname(mmc); - host->led.brightness_set = sdhci_led_control; - - ret = led_classdev_register(mmc_dev(mmc), &host->led); - if (ret) - goto reset; -#endif - - mmiowb(); - - mmc_add_host(mmc); - - pr_info("%s: SDHCI controller on %s [%s] using %s\n", - mmc_hostname(mmc), host->hw_name, dev_name(mmc_dev(mmc)), - (host->flags & SDHCI_USE_ADMA) ? "ADMA" : - (host->flags & SDHCI_USE_SDMA) ? "DMA" : "PIO"); - - sdhci_enable_card_detection(host); - - return 0; - -#ifdef SDHCI_USE_LEDS_CLASS -reset: - sdhci_reset(host, SDHCI_RESET_ALL); - free_irq(host->irq, host); -#endif -untasklet: - tasklet_kill(&host->card_tasklet); - tasklet_kill(&host->finish_tasklet); - - return ret; -} - -EXPORT_SYMBOL_GPL(sdhci_add_host); - -void sdhci_remove_host(struct sdhci_host *host, int dead) -{ - unsigned long flags; - - if (dead) { - spin_lock_irqsave(&host->lock, flags); - - host->flags |= SDHCI_DEVICE_DEAD; - - if (host->mrq) { - pr_err("%s: Controller removed during " - " transfer!\n", mmc_hostname(host->mmc)); - - host->mrq->cmd->error = -ENOMEDIUM; - tasklet_schedule(&host->finish_tasklet); - } - - spin_unlock_irqrestore(&host->lock, flags); - } - - sdhci_disable_card_detection(host); - - mmc_remove_host(host->mmc); - -#ifdef SDHCI_USE_LEDS_CLASS - led_classdev_unregister(&host->led); -#endif - - if (!dead) - sdhci_reset(host, SDHCI_RESET_ALL); - - free_irq(host->irq, host); - - del_timer_sync(&host->timer); - if (host->version >= SDHCI_SPEC_300) - del_timer_sync(&host->tuning_timer); - - tasklet_kill(&host->card_tasklet); - tasklet_kill(&host->finish_tasklet); - - if (host->vmmc) - regulator_put(host->vmmc); - - kfree(host->adma_desc); - kfree(host->align_buffer); - - host->adma_desc = NULL; - host->align_buffer = NULL; -} - -EXPORT_SYMBOL_GPL(sdhci_remove_host); - -void sdhci_free_host(struct sdhci_host *host) -{ - mmc_free_host(host->mmc); -} - -EXPORT_SYMBOL_GPL(sdhci_free_host); - -/*****************************************************************************\ - * * - * Driver init/exit * - * * -\*****************************************************************************/ - -static int __init sdhci_drv_init(void) -{ - pr_info(DRIVER_NAME - ": Secure Digital Host Controller Interface driver\n"); - pr_info(DRIVER_NAME ": Copyright(c) Pierre Ossman\n"); - - return 0; -} - -static void __exit sdhci_drv_exit(void) -{ -} - -module_init(sdhci_drv_init); -module_exit(sdhci_drv_exit); - -module_param(debug_quirks, uint, 0444); -module_param(debug_quirks2, uint, 0444); - -MODULE_AUTHOR("Pierre Ossman <pierre@ossman.eu>"); -MODULE_DESCRIPTION("Secure Digital Host Controller Interface core driver"); -MODULE_LICENSE("GPL"); - -MODULE_PARM_DESC(debug_quirks, "Force certain quirks."); -MODULE_PARM_DESC(debug_quirks2, "Force certain other quirks."); diff --git a/ANDROID_3.4.5/drivers/mmc/host/sdhci.h b/ANDROID_3.4.5/drivers/mmc/host/sdhci.h deleted file mode 100644 index f761f23d..00000000 --- a/ANDROID_3.4.5/drivers/mmc/host/sdhci.h +++ /dev/null @@ -1,390 +0,0 @@ -/* - * linux/drivers/mmc/host/sdhci.h - Secure Digital Host Controller Interface driver - * - * Header file for Host Controller registers and I/O accessors. - * - * Copyright (C) 2005-2008 Pierre Ossman, All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at - * your option) any later version. - */ -#ifndef __SDHCI_HW_H -#define __SDHCI_HW_H - -#include <linux/scatterlist.h> -#include <linux/compiler.h> -#include <linux/types.h> -#include <linux/io.h> - -#include <linux/mmc/sdhci.h> - -/* - * Controller registers - */ - -#define SDHCI_DMA_ADDRESS 0x00 -#define SDHCI_ARGUMENT2 SDHCI_DMA_ADDRESS - -#define SDHCI_BLOCK_SIZE 0x04 -#define SDHCI_MAKE_BLKSZ(dma, blksz) (((dma & 0x7) << 12) | (blksz & 0xFFF)) - -#define SDHCI_BLOCK_COUNT 0x06 - -#define SDHCI_ARGUMENT 0x08 - -#define SDHCI_TRANSFER_MODE 0x0C -#define SDHCI_TRNS_DMA 0x01 -#define SDHCI_TRNS_BLK_CNT_EN 0x02 -#define SDHCI_TRNS_AUTO_CMD12 0x04 -#define SDHCI_TRNS_AUTO_CMD23 0x08 -#define SDHCI_TRNS_READ 0x10 -#define SDHCI_TRNS_MULTI 0x20 - -#define SDHCI_COMMAND 0x0E -#define SDHCI_CMD_RESP_MASK 0x03 -#define SDHCI_CMD_CRC 0x08 -#define SDHCI_CMD_INDEX 0x10 -#define SDHCI_CMD_DATA 0x20 -#define SDHCI_CMD_ABORTCMD 0xC0 - -#define SDHCI_CMD_RESP_NONE 0x00 -#define SDHCI_CMD_RESP_LONG 0x01 -#define SDHCI_CMD_RESP_SHORT 0x02 -#define SDHCI_CMD_RESP_SHORT_BUSY 0x03 - -#define SDHCI_MAKE_CMD(c, f) (((c & 0xff) << 8) | (f & 0xff)) -#define SDHCI_GET_CMD(c) ((c>>8) & 0x3f) - -#define SDHCI_RESPONSE 0x10 - -#define SDHCI_BUFFER 0x20 - -#define SDHCI_PRESENT_STATE 0x24 -#define SDHCI_CMD_INHIBIT 0x00000001 -#define SDHCI_DATA_INHIBIT 0x00000002 -#define SDHCI_DOING_WRITE 0x00000100 -#define SDHCI_DOING_READ 0x00000200 -#define SDHCI_SPACE_AVAILABLE 0x00000400 -#define SDHCI_DATA_AVAILABLE 0x00000800 -#define SDHCI_CARD_PRESENT 0x00010000 -#define SDHCI_WRITE_PROTECT 0x00080000 -#define SDHCI_DATA_LVL_MASK 0x00F00000 -#define SDHCI_DATA_LVL_SHIFT 20 - -#define SDHCI_HOST_CONTROL 0x28 -#define SDHCI_CTRL_LED 0x01 -#define SDHCI_CTRL_4BITBUS 0x02 -#define SDHCI_CTRL_HISPD 0x04 -#define SDHCI_CTRL_DMA_MASK 0x18 -#define SDHCI_CTRL_SDMA 0x00 -#define SDHCI_CTRL_ADMA1 0x08 -#define SDHCI_CTRL_ADMA32 0x10 -#define SDHCI_CTRL_ADMA64 0x18 -#define SDHCI_CTRL_8BITBUS 0x20 - -#define SDHCI_POWER_CONTROL 0x29 -#define SDHCI_POWER_ON 0x01 -#define SDHCI_POWER_180 0x0A -#define SDHCI_POWER_300 0x0C -#define SDHCI_POWER_330 0x0E - -#define SDHCI_BLOCK_GAP_CONTROL 0x2A - -#define SDHCI_WAKE_UP_CONTROL 0x2B -#define SDHCI_WAKE_ON_INT 0x01 -#define SDHCI_WAKE_ON_INSERT 0x02 -#define SDHCI_WAKE_ON_REMOVE 0x04 - -#define SDHCI_CLOCK_CONTROL 0x2C -#define SDHCI_DIVIDER_SHIFT 8 -#define SDHCI_DIVIDER_HI_SHIFT 6 -#define SDHCI_DIV_MASK 0xFF -#define SDHCI_DIV_MASK_LEN 8 -#define SDHCI_DIV_HI_MASK 0x300 -#define SDHCI_PROG_CLOCK_MODE 0x0020 -#define SDHCI_CLOCK_CARD_EN 0x0004 -#define SDHCI_CLOCK_INT_STABLE 0x0002 -#define SDHCI_CLOCK_INT_EN 0x0001 - -#define SDHCI_TIMEOUT_CONTROL 0x2E - -#define SDHCI_SOFTWARE_RESET 0x2F -#define SDHCI_RESET_ALL 0x01 -#define SDHCI_RESET_CMD 0x02 -#define SDHCI_RESET_DATA 0x04 - -#define SDHCI_INT_STATUS 0x30 -#define SDHCI_INT_ENABLE 0x34 -#define SDHCI_SIGNAL_ENABLE 0x38 -#define SDHCI_INT_RESPONSE 0x00000001 -#define SDHCI_INT_DATA_END 0x00000002 -#define SDHCI_INT_DMA_END 0x00000008 -#define SDHCI_INT_SPACE_AVAIL 0x00000010 -#define SDHCI_INT_DATA_AVAIL 0x00000020 -#define SDHCI_INT_CARD_INSERT 0x00000040 -#define SDHCI_INT_CARD_REMOVE 0x00000080 -#define SDHCI_INT_CARD_INT 0x00000100 -#define SDHCI_INT_ERROR 0x00008000 -#define SDHCI_INT_TIMEOUT 0x00010000 -#define SDHCI_INT_CRC 0x00020000 -#define SDHCI_INT_END_BIT 0x00040000 -#define SDHCI_INT_INDEX 0x00080000 -#define SDHCI_INT_DATA_TIMEOUT 0x00100000 -#define SDHCI_INT_DATA_CRC 0x00200000 -#define SDHCI_INT_DATA_END_BIT 0x00400000 -#define SDHCI_INT_BUS_POWER 0x00800000 -#define SDHCI_INT_ACMD12ERR 0x01000000 -#define SDHCI_INT_ADMA_ERROR 0x02000000 - -#define SDHCI_INT_NORMAL_MASK 0x00007FFF -#define SDHCI_INT_ERROR_MASK 0xFFFF8000 - -#define SDHCI_INT_CMD_MASK (SDHCI_INT_RESPONSE | SDHCI_INT_TIMEOUT | \ - SDHCI_INT_CRC | SDHCI_INT_END_BIT | SDHCI_INT_INDEX) -#define SDHCI_INT_DATA_MASK (SDHCI_INT_DATA_END | SDHCI_INT_DMA_END | \ - SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL | \ - SDHCI_INT_DATA_TIMEOUT | SDHCI_INT_DATA_CRC | \ - SDHCI_INT_DATA_END_BIT | SDHCI_INT_ADMA_ERROR) -#define SDHCI_INT_ALL_MASK ((unsigned int)-1) - -#define SDHCI_ACMD12_ERR 0x3C - -#define SDHCI_HOST_CONTROL2 0x3E -#define SDHCI_CTRL_UHS_MASK 0x0007 -#define SDHCI_CTRL_UHS_SDR12 0x0000 -#define SDHCI_CTRL_UHS_SDR25 0x0001 -#define SDHCI_CTRL_UHS_SDR50 0x0002 -#define SDHCI_CTRL_UHS_SDR104 0x0003 -#define SDHCI_CTRL_UHS_DDR50 0x0004 -#define SDHCI_CTRL_HS_SDR200 0x0005 /* reserved value in SDIO spec */ -#define SDHCI_CTRL_VDD_180 0x0008 -#define SDHCI_CTRL_DRV_TYPE_MASK 0x0030 -#define SDHCI_CTRL_DRV_TYPE_B 0x0000 -#define SDHCI_CTRL_DRV_TYPE_A 0x0010 -#define SDHCI_CTRL_DRV_TYPE_C 0x0020 -#define SDHCI_CTRL_DRV_TYPE_D 0x0030 -#define SDHCI_CTRL_EXEC_TUNING 0x0040 -#define SDHCI_CTRL_TUNED_CLK 0x0080 -#define SDHCI_CTRL_PRESET_VAL_ENABLE 0x8000 - -#define SDHCI_CAPABILITIES 0x40 -#define SDHCI_TIMEOUT_CLK_MASK 0x0000003F -#define SDHCI_TIMEOUT_CLK_SHIFT 0 -#define SDHCI_TIMEOUT_CLK_UNIT 0x00000080 -#define SDHCI_CLOCK_BASE_MASK 0x00003F00 -#define SDHCI_CLOCK_V3_BASE_MASK 0x0000FF00 -#define SDHCI_CLOCK_BASE_SHIFT 8 -#define SDHCI_MAX_BLOCK_MASK 0x00030000 -#define SDHCI_MAX_BLOCK_SHIFT 16 -#define SDHCI_CAN_DO_8BIT 0x00040000 -#define SDHCI_CAN_DO_ADMA2 0x00080000 -#define SDHCI_CAN_DO_ADMA1 0x00100000 -#define SDHCI_CAN_DO_HISPD 0x00200000 -#define SDHCI_CAN_DO_SDMA 0x00400000 -#define SDHCI_CAN_VDD_330 0x01000000 -#define SDHCI_CAN_VDD_300 0x02000000 -#define SDHCI_CAN_VDD_180 0x04000000 -#define SDHCI_CAN_64BIT 0x10000000 - -#define SDHCI_SUPPORT_SDR50 0x00000001 -#define SDHCI_SUPPORT_SDR104 0x00000002 -#define SDHCI_SUPPORT_DDR50 0x00000004 -#define SDHCI_DRIVER_TYPE_A 0x00000010 -#define SDHCI_DRIVER_TYPE_C 0x00000020 -#define SDHCI_DRIVER_TYPE_D 0x00000040 -#define SDHCI_RETUNING_TIMER_COUNT_MASK 0x00000F00 -#define SDHCI_RETUNING_TIMER_COUNT_SHIFT 8 -#define SDHCI_USE_SDR50_TUNING 0x00002000 -#define SDHCI_RETUNING_MODE_MASK 0x0000C000 -#define SDHCI_RETUNING_MODE_SHIFT 14 -#define SDHCI_CLOCK_MUL_MASK 0x00FF0000 -#define SDHCI_CLOCK_MUL_SHIFT 16 - -#define SDHCI_CAPABILITIES_1 0x44 - -#define SDHCI_MAX_CURRENT 0x48 -#define SDHCI_MAX_CURRENT_330_MASK 0x0000FF -#define SDHCI_MAX_CURRENT_330_SHIFT 0 -#define SDHCI_MAX_CURRENT_300_MASK 0x00FF00 -#define SDHCI_MAX_CURRENT_300_SHIFT 8 -#define SDHCI_MAX_CURRENT_180_MASK 0xFF0000 -#define SDHCI_MAX_CURRENT_180_SHIFT 16 -#define SDHCI_MAX_CURRENT_MULTIPLIER 4 - -/* 4C-4F reserved for more max current */ - -#define SDHCI_SET_ACMD12_ERROR 0x50 -#define SDHCI_SET_INT_ERROR 0x52 - -#define SDHCI_ADMA_ERROR 0x54 - -/* 55-57 reserved */ - -#define SDHCI_ADMA_ADDRESS 0x58 - -/* 60-FB reserved */ - -#define SDHCI_SLOT_INT_STATUS 0xFC - -#define SDHCI_HOST_VERSION 0xFE -#define SDHCI_VENDOR_VER_MASK 0xFF00 -#define SDHCI_VENDOR_VER_SHIFT 8 -#define SDHCI_SPEC_VER_MASK 0x00FF -#define SDHCI_SPEC_VER_SHIFT 0 -#define SDHCI_SPEC_100 0 -#define SDHCI_SPEC_200 1 -#define SDHCI_SPEC_300 2 - -/* - * End of controller registers. - */ - -#define SDHCI_MAX_DIV_SPEC_200 256 -#define SDHCI_MAX_DIV_SPEC_300 2046 - -/* - * Host SDMA buffer boundary. Valid values from 4K to 512K in powers of 2. - */ -#define SDHCI_DEFAULT_BOUNDARY_SIZE (512 * 1024) -#define SDHCI_DEFAULT_BOUNDARY_ARG (ilog2(SDHCI_DEFAULT_BOUNDARY_SIZE) - 12) - -struct sdhci_ops { -#ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS - u32 (*read_l)(struct sdhci_host *host, int reg); - u16 (*read_w)(struct sdhci_host *host, int reg); - u8 (*read_b)(struct sdhci_host *host, int reg); - void (*write_l)(struct sdhci_host *host, u32 val, int reg); - void (*write_w)(struct sdhci_host *host, u16 val, int reg); - void (*write_b)(struct sdhci_host *host, u8 val, int reg); -#endif - - void (*set_clock)(struct sdhci_host *host, unsigned int clock); - - int (*enable_dma)(struct sdhci_host *host); - unsigned int (*get_max_clock)(struct sdhci_host *host); - unsigned int (*get_min_clock)(struct sdhci_host *host); - unsigned int (*get_timeout_clock)(struct sdhci_host *host); - int (*platform_8bit_width)(struct sdhci_host *host, - int width); - void (*platform_send_init_74_clocks)(struct sdhci_host *host, - u8 power_mode); - unsigned int (*get_ro)(struct sdhci_host *host); - void (*platform_reset_enter)(struct sdhci_host *host, u8 mask); - void (*platform_reset_exit)(struct sdhci_host *host, u8 mask); - int (*set_uhs_signaling)(struct sdhci_host *host, unsigned int uhs); - void (*hw_reset)(struct sdhci_host *host); - void (*platform_suspend)(struct sdhci_host *host); - void (*platform_resume)(struct sdhci_host *host); -}; - -#ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS - -static inline void sdhci_writel(struct sdhci_host *host, u32 val, int reg) -{ - if (unlikely(host->ops->write_l)) - host->ops->write_l(host, val, reg); - else - writel(val, host->ioaddr + reg); -} - -static inline void sdhci_writew(struct sdhci_host *host, u16 val, int reg) -{ - if (unlikely(host->ops->write_w)) - host->ops->write_w(host, val, reg); - else - writew(val, host->ioaddr + reg); -} - -static inline void sdhci_writeb(struct sdhci_host *host, u8 val, int reg) -{ - if (unlikely(host->ops->write_b)) - host->ops->write_b(host, val, reg); - else - writeb(val, host->ioaddr + reg); -} - -static inline u32 sdhci_readl(struct sdhci_host *host, int reg) -{ - if (unlikely(host->ops->read_l)) - return host->ops->read_l(host, reg); - else - return readl(host->ioaddr + reg); -} - -static inline u16 sdhci_readw(struct sdhci_host *host, int reg) -{ - if (unlikely(host->ops->read_w)) - return host->ops->read_w(host, reg); - else - return readw(host->ioaddr + reg); -} - -static inline u8 sdhci_readb(struct sdhci_host *host, int reg) -{ - if (unlikely(host->ops->read_b)) - return host->ops->read_b(host, reg); - else - return readb(host->ioaddr + reg); -} - -#else - -static inline void sdhci_writel(struct sdhci_host *host, u32 val, int reg) -{ - writel(val, host->ioaddr + reg); -} - -static inline void sdhci_writew(struct sdhci_host *host, u16 val, int reg) -{ - writew(val, host->ioaddr + reg); -} - -static inline void sdhci_writeb(struct sdhci_host *host, u8 val, int reg) -{ - writeb(val, host->ioaddr + reg); -} - -static inline u32 sdhci_readl(struct sdhci_host *host, int reg) -{ - return readl(host->ioaddr + reg); -} - -static inline u16 sdhci_readw(struct sdhci_host *host, int reg) -{ - return readw(host->ioaddr + reg); -} - -static inline u8 sdhci_readb(struct sdhci_host *host, int reg) -{ - return readb(host->ioaddr + reg); -} - -#endif /* CONFIG_MMC_SDHCI_IO_ACCESSORS */ - -extern struct sdhci_host *sdhci_alloc_host(struct device *dev, - size_t priv_size); -extern void sdhci_free_host(struct sdhci_host *host); - -static inline void *sdhci_priv(struct sdhci_host *host) -{ - return (void *)host->private; -} - -extern void sdhci_card_detect(struct sdhci_host *host); -extern int sdhci_add_host(struct sdhci_host *host); -extern void sdhci_remove_host(struct sdhci_host *host, int dead); - -#ifdef CONFIG_PM -extern int sdhci_suspend_host(struct sdhci_host *host); -extern int sdhci_resume_host(struct sdhci_host *host); -extern void sdhci_enable_irq_wakeups(struct sdhci_host *host); -#endif - -#ifdef CONFIG_PM_RUNTIME -extern int sdhci_runtime_suspend_host(struct sdhci_host *host); -extern int sdhci_runtime_resume_host(struct sdhci_host *host); -#endif - -#endif /* __SDHCI_HW_H */ diff --git a/ANDROID_3.4.5/drivers/mmc/host/sdricoh_cs.c b/ANDROID_3.4.5/drivers/mmc/host/sdricoh_cs.c deleted file mode 100644 index 7009f17a..00000000 --- a/ANDROID_3.4.5/drivers/mmc/host/sdricoh_cs.c +++ /dev/null @@ -1,573 +0,0 @@ -/* - * sdricoh_cs.c - driver for Ricoh Secure Digital Card Readers that can be - * found on some Ricoh RL5c476 II cardbus bridge - * - * Copyright (C) 2006 - 2008 Sascha Sommer <saschasommer@freenet.de> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -/* -#define DEBUG -#define VERBOSE_DEBUG -*/ -#include <linux/delay.h> -#include <linux/highmem.h> -#include <linux/module.h> -#include <linux/pci.h> -#include <linux/ioport.h> -#include <linux/scatterlist.h> - -#include <pcmcia/cistpl.h> -#include <pcmcia/ds.h> -#include <linux/io.h> - -#include <linux/mmc/host.h> - -#define DRIVER_NAME "sdricoh_cs" - -static unsigned int switchlocked; - -/* i/o region */ -#define SDRICOH_PCI_REGION 0 -#define SDRICOH_PCI_REGION_SIZE 0x1000 - -/* registers */ -#define R104_VERSION 0x104 -#define R200_CMD 0x200 -#define R204_CMD_ARG 0x204 -#define R208_DATAIO 0x208 -#define R20C_RESP 0x20c -#define R21C_STATUS 0x21c -#define R2E0_INIT 0x2e0 -#define R2E4_STATUS_RESP 0x2e4 -#define R2F0_RESET 0x2f0 -#define R224_MODE 0x224 -#define R226_BLOCKSIZE 0x226 -#define R228_POWER 0x228 -#define R230_DATA 0x230 - -/* flags for the R21C_STATUS register */ -#define STATUS_CMD_FINISHED 0x00000001 -#define STATUS_TRANSFER_FINISHED 0x00000004 -#define STATUS_CARD_INSERTED 0x00000020 -#define STATUS_CARD_LOCKED 0x00000080 -#define STATUS_CMD_TIMEOUT 0x00400000 -#define STATUS_READY_TO_READ 0x01000000 -#define STATUS_READY_TO_WRITE 0x02000000 -#define STATUS_BUSY 0x40000000 - -/* timeouts */ -#define INIT_TIMEOUT 100 -#define CMD_TIMEOUT 100000 -#define TRANSFER_TIMEOUT 100000 -#define BUSY_TIMEOUT 32767 - -/* list of supported pcmcia devices */ -static const struct pcmcia_device_id pcmcia_ids[] = { - /* vendor and device strings followed by their crc32 hashes */ - PCMCIA_DEVICE_PROD_ID12("RICOH", "Bay1Controller", 0xd9f522ed, - 0xc3901202), - PCMCIA_DEVICE_PROD_ID12("RICOH", "Bay Controller", 0xd9f522ed, - 0xace80909), - PCMCIA_DEVICE_NULL, -}; - -MODULE_DEVICE_TABLE(pcmcia, pcmcia_ids); - -/* mmc privdata */ -struct sdricoh_host { - struct device *dev; - struct mmc_host *mmc; /* MMC structure */ - unsigned char __iomem *iobase; - struct pci_dev *pci_dev; - int app_cmd; -}; - -/***************** register i/o helper functions *****************************/ - -static inline unsigned int sdricoh_readl(struct sdricoh_host *host, - unsigned int reg) -{ - unsigned int value = readl(host->iobase + reg); - dev_vdbg(host->dev, "rl %x 0x%x\n", reg, value); - return value; -} - -static inline void sdricoh_writel(struct sdricoh_host *host, unsigned int reg, - unsigned int value) -{ - writel(value, host->iobase + reg); - dev_vdbg(host->dev, "wl %x 0x%x\n", reg, value); - -} - -static inline unsigned int sdricoh_readw(struct sdricoh_host *host, - unsigned int reg) -{ - unsigned int value = readw(host->iobase + reg); - dev_vdbg(host->dev, "rb %x 0x%x\n", reg, value); - return value; -} - -static inline void sdricoh_writew(struct sdricoh_host *host, unsigned int reg, - unsigned short value) -{ - writew(value, host->iobase + reg); - dev_vdbg(host->dev, "ww %x 0x%x\n", reg, value); -} - -static inline unsigned int sdricoh_readb(struct sdricoh_host *host, - unsigned int reg) -{ - unsigned int value = readb(host->iobase + reg); - dev_vdbg(host->dev, "rb %x 0x%x\n", reg, value); - return value; -} - -static int sdricoh_query_status(struct sdricoh_host *host, unsigned int wanted, - unsigned int timeout){ - unsigned int loop; - unsigned int status = 0; - struct device *dev = host->dev; - for (loop = 0; loop < timeout; loop++) { - status = sdricoh_readl(host, R21C_STATUS); - sdricoh_writel(host, R2E4_STATUS_RESP, status); - if (status & wanted) - break; - } - - if (loop == timeout) { - dev_err(dev, "query_status: timeout waiting for %x\n", wanted); - return -ETIMEDOUT; - } - - /* do not do this check in the loop as some commands fail otherwise */ - if (status & 0x7F0000) { - dev_err(dev, "waiting for status bit %x failed\n", wanted); - return -EINVAL; - } - return 0; - -} - -static int sdricoh_mmc_cmd(struct sdricoh_host *host, unsigned char opcode, - unsigned int arg) -{ - unsigned int status; - int result = 0; - unsigned int loop = 0; - /* reset status reg? */ - sdricoh_writel(host, R21C_STATUS, 0x18); - /* fill parameters */ - sdricoh_writel(host, R204_CMD_ARG, arg); - sdricoh_writel(host, R200_CMD, (0x10000 << 8) | opcode); - /* wait for command completion */ - if (opcode) { - for (loop = 0; loop < CMD_TIMEOUT; loop++) { - status = sdricoh_readl(host, R21C_STATUS); - sdricoh_writel(host, R2E4_STATUS_RESP, status); - if (status & STATUS_CMD_FINISHED) - break; - } - /* don't check for timeout in the loop it is not always - reset correctly - */ - if (loop == CMD_TIMEOUT || status & STATUS_CMD_TIMEOUT) - result = -ETIMEDOUT; - - } - - return result; - -} - -static int sdricoh_reset(struct sdricoh_host *host) -{ - dev_dbg(host->dev, "reset\n"); - sdricoh_writel(host, R2F0_RESET, 0x10001); - sdricoh_writel(host, R2E0_INIT, 0x10000); - if (sdricoh_readl(host, R2E0_INIT) != 0x10000) - return -EIO; - sdricoh_writel(host, R2E0_INIT, 0x10007); - - sdricoh_writel(host, R224_MODE, 0x2000000); - sdricoh_writel(host, R228_POWER, 0xe0); - - - /* status register ? */ - sdricoh_writel(host, R21C_STATUS, 0x18); - - return 0; -} - -static int sdricoh_blockio(struct sdricoh_host *host, int read, - u8 *buf, int len) -{ - int size; - u32 data = 0; - /* wait until the data is available */ - if (read) { - if (sdricoh_query_status(host, STATUS_READY_TO_READ, - TRANSFER_TIMEOUT)) - return -ETIMEDOUT; - sdricoh_writel(host, R21C_STATUS, 0x18); - /* read data */ - while (len) { - data = sdricoh_readl(host, R230_DATA); - size = min(len, 4); - len -= size; - while (size) { - *buf = data & 0xFF; - buf++; - data >>= 8; - size--; - } - } - } else { - if (sdricoh_query_status(host, STATUS_READY_TO_WRITE, - TRANSFER_TIMEOUT)) - return -ETIMEDOUT; - sdricoh_writel(host, R21C_STATUS, 0x18); - /* write data */ - while (len) { - size = min(len, 4); - len -= size; - while (size) { - data >>= 8; - data |= (u32)*buf << 24; - buf++; - size--; - } - sdricoh_writel(host, R230_DATA, data); - } - } - - if (len) - return -EIO; - - return 0; -} - -static void sdricoh_request(struct mmc_host *mmc, struct mmc_request *mrq) -{ - struct sdricoh_host *host = mmc_priv(mmc); - struct mmc_command *cmd = mrq->cmd; - struct mmc_data *data = cmd->data; - struct device *dev = host->dev; - unsigned char opcode = cmd->opcode; - int i; - - dev_dbg(dev, "=============================\n"); - dev_dbg(dev, "sdricoh_request opcode=%i\n", opcode); - - sdricoh_writel(host, R21C_STATUS, 0x18); - - /* MMC_APP_CMDs need some special handling */ - if (host->app_cmd) { - opcode |= 64; - host->app_cmd = 0; - } else if (opcode == 55) - host->app_cmd = 1; - - /* read/write commands seem to require this */ - if (data) { - sdricoh_writew(host, R226_BLOCKSIZE, data->blksz); - sdricoh_writel(host, R208_DATAIO, 0); - } - - cmd->error = sdricoh_mmc_cmd(host, opcode, cmd->arg); - - /* read response buffer */ - if (cmd->flags & MMC_RSP_PRESENT) { - if (cmd->flags & MMC_RSP_136) { - /* CRC is stripped so we need to do some shifting. */ - for (i = 0; i < 4; i++) { - cmd->resp[i] = - sdricoh_readl(host, - R20C_RESP + (3 - i) * 4) << 8; - if (i != 3) - cmd->resp[i] |= - sdricoh_readb(host, R20C_RESP + - (3 - i) * 4 - 1); - } - } else - cmd->resp[0] = sdricoh_readl(host, R20C_RESP); - } - - /* transfer data */ - if (data && cmd->error == 0) { - dev_dbg(dev, "transfer: blksz %i blocks %i sg_len %i " - "sg length %i\n", data->blksz, data->blocks, - data->sg_len, data->sg->length); - - /* enter data reading mode */ - sdricoh_writel(host, R21C_STATUS, 0x837f031e); - for (i = 0; i < data->blocks; i++) { - size_t len = data->blksz; - u8 *buf; - struct page *page; - int result; - page = sg_page(data->sg); - - buf = kmap(page) + data->sg->offset + (len * i); - result = - sdricoh_blockio(host, - data->flags & MMC_DATA_READ, buf, len); - kunmap(page); - flush_dcache_page(page); - if (result) { - dev_err(dev, "sdricoh_request: cmd %i " - "block transfer failed\n", cmd->opcode); - cmd->error = result; - break; - } else - data->bytes_xfered += len; - } - - sdricoh_writel(host, R208_DATAIO, 1); - - if (sdricoh_query_status(host, STATUS_TRANSFER_FINISHED, - TRANSFER_TIMEOUT)) { - dev_err(dev, "sdricoh_request: transfer end error\n"); - cmd->error = -EINVAL; - } - } - /* FIXME check busy flag */ - - mmc_request_done(mmc, mrq); - dev_dbg(dev, "=============================\n"); -} - -static void sdricoh_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) -{ - struct sdricoh_host *host = mmc_priv(mmc); - dev_dbg(host->dev, "set_ios\n"); - - if (ios->power_mode == MMC_POWER_ON) { - sdricoh_writel(host, R228_POWER, 0xc0e0); - - if (ios->bus_width == MMC_BUS_WIDTH_4) { - sdricoh_writel(host, R224_MODE, 0x2000300); - sdricoh_writel(host, R228_POWER, 0x40e0); - } else { - sdricoh_writel(host, R224_MODE, 0x2000340); - } - - } else if (ios->power_mode == MMC_POWER_UP) { - sdricoh_writel(host, R224_MODE, 0x2000320); - sdricoh_writel(host, R228_POWER, 0xe0); - } -} - -static int sdricoh_get_ro(struct mmc_host *mmc) -{ - struct sdricoh_host *host = mmc_priv(mmc); - unsigned int status; - - status = sdricoh_readl(host, R21C_STATUS); - sdricoh_writel(host, R2E4_STATUS_RESP, status); - - /* some notebooks seem to have the locked flag switched */ - if (switchlocked) - return !(status & STATUS_CARD_LOCKED); - - return (status & STATUS_CARD_LOCKED); -} - -static struct mmc_host_ops sdricoh_ops = { - .request = sdricoh_request, - .set_ios = sdricoh_set_ios, - .get_ro = sdricoh_get_ro, -}; - -/* initialize the control and register it to the mmc framework */ -static int sdricoh_init_mmc(struct pci_dev *pci_dev, - struct pcmcia_device *pcmcia_dev) -{ - int result = 0; - void __iomem *iobase = NULL; - struct mmc_host *mmc = NULL; - struct sdricoh_host *host = NULL; - struct device *dev = &pcmcia_dev->dev; - /* map iomem */ - if (pci_resource_len(pci_dev, SDRICOH_PCI_REGION) != - SDRICOH_PCI_REGION_SIZE) { - dev_dbg(dev, "unexpected pci resource len\n"); - return -ENODEV; - } - iobase = - pci_iomap(pci_dev, SDRICOH_PCI_REGION, SDRICOH_PCI_REGION_SIZE); - if (!iobase) { - dev_err(dev, "unable to map iobase\n"); - return -ENODEV; - } - /* check version? */ - if (readl(iobase + R104_VERSION) != 0x4000) { - dev_dbg(dev, "no supported mmc controller found\n"); - result = -ENODEV; - goto err; - } - /* allocate privdata */ - mmc = pcmcia_dev->priv = - mmc_alloc_host(sizeof(struct sdricoh_host), &pcmcia_dev->dev); - if (!mmc) { - dev_err(dev, "mmc_alloc_host failed\n"); - result = -ENOMEM; - goto err; - } - host = mmc_priv(mmc); - - host->iobase = iobase; - host->dev = dev; - host->pci_dev = pci_dev; - - mmc->ops = &sdricoh_ops; - - /* FIXME: frequency and voltage handling is done by the controller - */ - mmc->f_min = 450000; - mmc->f_max = 24000000; - mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; - mmc->caps |= MMC_CAP_4_BIT_DATA; - - mmc->max_seg_size = 1024 * 512; - mmc->max_blk_size = 512; - - /* reset the controller */ - if (sdricoh_reset(host)) { - dev_dbg(dev, "could not reset\n"); - result = -EIO; - goto err; - - } - - result = mmc_add_host(mmc); - - if (!result) { - dev_dbg(dev, "mmc host registered\n"); - return 0; - } - -err: - if (iobase) - pci_iounmap(pci_dev, iobase); - if (mmc) - mmc_free_host(mmc); - - return result; -} - -/* search for supported mmc controllers */ -static int sdricoh_pcmcia_probe(struct pcmcia_device *pcmcia_dev) -{ - struct pci_dev *pci_dev = NULL; - - dev_info(&pcmcia_dev->dev, "Searching MMC controller for pcmcia device" - " %s %s ...\n", pcmcia_dev->prod_id[0], pcmcia_dev->prod_id[1]); - - /* search pci cardbus bridge that contains the mmc controller */ - /* the io region is already claimed by yenta_socket... */ - while ((pci_dev = - pci_get_device(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_RL5C476, - pci_dev))) { - /* try to init the device */ - if (!sdricoh_init_mmc(pci_dev, pcmcia_dev)) { - dev_info(&pcmcia_dev->dev, "MMC controller found\n"); - return 0; - } - - } - dev_err(&pcmcia_dev->dev, "No MMC controller was found.\n"); - return -ENODEV; -} - -static void sdricoh_pcmcia_detach(struct pcmcia_device *link) -{ - struct mmc_host *mmc = link->priv; - - dev_dbg(&link->dev, "detach\n"); - - /* remove mmc host */ - if (mmc) { - struct sdricoh_host *host = mmc_priv(mmc); - mmc_remove_host(mmc); - pci_iounmap(host->pci_dev, host->iobase); - pci_dev_put(host->pci_dev); - mmc_free_host(mmc); - } - pcmcia_disable_device(link); - -} - -#ifdef CONFIG_PM -static int sdricoh_pcmcia_suspend(struct pcmcia_device *link) -{ - struct mmc_host *mmc = link->priv; - dev_dbg(&link->dev, "suspend\n"); - mmc_suspend_host(mmc); - return 0; -} - -static int sdricoh_pcmcia_resume(struct pcmcia_device *link) -{ - struct mmc_host *mmc = link->priv; - dev_dbg(&link->dev, "resume\n"); - sdricoh_reset(mmc_priv(mmc)); - mmc_resume_host(mmc); - return 0; -} -#else -#define sdricoh_pcmcia_suspend NULL -#define sdricoh_pcmcia_resume NULL -#endif - -static struct pcmcia_driver sdricoh_driver = { - .name = DRIVER_NAME, - .probe = sdricoh_pcmcia_probe, - .remove = sdricoh_pcmcia_detach, - .id_table = pcmcia_ids, - .suspend = sdricoh_pcmcia_suspend, - .resume = sdricoh_pcmcia_resume, -}; - -/*****************************************************************************\ - * * - * Driver init/exit * - * * -\*****************************************************************************/ - -static int __init sdricoh_drv_init(void) -{ - return pcmcia_register_driver(&sdricoh_driver); -} - -static void __exit sdricoh_drv_exit(void) -{ - pcmcia_unregister_driver(&sdricoh_driver); -} - -module_init(sdricoh_drv_init); -module_exit(sdricoh_drv_exit); - -module_param(switchlocked, uint, 0444); - -MODULE_AUTHOR("Sascha Sommer <saschasommer@freenet.de>"); -MODULE_DESCRIPTION("Ricoh PCMCIA Secure Digital Interface driver"); -MODULE_LICENSE("GPL"); - -MODULE_PARM_DESC(switchlocked, "Switch the cards locked status." - "Use this when unlocked cards are shown readonly (default 0)"); diff --git a/ANDROID_3.4.5/drivers/mmc/host/sh_mmcif.c b/ANDROID_3.4.5/drivers/mmc/host/sh_mmcif.c deleted file mode 100644 index 724b35e8..00000000 --- a/ANDROID_3.4.5/drivers/mmc/host/sh_mmcif.c +++ /dev/null @@ -1,1454 +0,0 @@ -/* - * MMCIF eMMC driver. - * - * Copyright (C) 2010 Renesas Solutions Corp. - * Yusuke Goda <yusuke.goda.sx@renesas.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License. - * - * - * TODO - * 1. DMA - * 2. Power management - * 3. Handle MMC errors better - * - */ - -/* - * The MMCIF driver is now processing MMC requests asynchronously, according - * to the Linux MMC API requirement. - * - * The MMCIF driver processes MMC requests in up to 3 stages: command, optional - * data, and optional stop. To achieve asynchronous processing each of these - * stages is split into two halves: a top and a bottom half. The top half - * initialises the hardware, installs a timeout handler to handle completion - * timeouts, and returns. In case of the command stage this immediately returns - * control to the caller, leaving all further processing to run asynchronously. - * All further request processing is performed by the bottom halves. - * - * The bottom half further consists of a "hard" IRQ handler, an IRQ handler - * thread, a DMA completion callback, if DMA is used, a timeout work, and - * request- and stage-specific handler methods. - * - * Each bottom half run begins with either a hardware interrupt, a DMA callback - * invocation, or a timeout work run. In case of an error or a successful - * processing completion, the MMC core is informed and the request processing is - * finished. In case processing has to continue, i.e., if data has to be read - * from or written to the card, or if a stop command has to be sent, the next - * top half is called, which performs the necessary hardware handling and - * reschedules the timeout work. This returns the driver state machine into the - * bottom half waiting state. - */ - -#include <linux/bitops.h> -#include <linux/clk.h> -#include <linux/completion.h> -#include <linux/delay.h> -#include <linux/dma-mapping.h> -#include <linux/dmaengine.h> -#include <linux/mmc/card.h> -#include <linux/mmc/core.h> -#include <linux/mmc/host.h> -#include <linux/mmc/mmc.h> -#include <linux/mmc/sdio.h> -#include <linux/mmc/sh_mmcif.h> -#include <linux/pagemap.h> -#include <linux/platform_device.h> -#include <linux/pm_qos.h> -#include <linux/pm_runtime.h> -#include <linux/spinlock.h> -#include <linux/module.h> - -#define DRIVER_NAME "sh_mmcif" -#define DRIVER_VERSION "2010-04-28" - -/* CE_CMD_SET */ -#define CMD_MASK 0x3f000000 -#define CMD_SET_RTYP_NO ((0 << 23) | (0 << 22)) -#define CMD_SET_RTYP_6B ((0 << 23) | (1 << 22)) /* R1/R1b/R3/R4/R5 */ -#define CMD_SET_RTYP_17B ((1 << 23) | (0 << 22)) /* R2 */ -#define CMD_SET_RBSY (1 << 21) /* R1b */ -#define CMD_SET_CCSEN (1 << 20) -#define CMD_SET_WDAT (1 << 19) /* 1: on data, 0: no data */ -#define CMD_SET_DWEN (1 << 18) /* 1: write, 0: read */ -#define CMD_SET_CMLTE (1 << 17) /* 1: multi block trans, 0: single */ -#define CMD_SET_CMD12EN (1 << 16) /* 1: CMD12 auto issue */ -#define CMD_SET_RIDXC_INDEX ((0 << 15) | (0 << 14)) /* index check */ -#define CMD_SET_RIDXC_BITS ((0 << 15) | (1 << 14)) /* check bits check */ -#define CMD_SET_RIDXC_NO ((1 << 15) | (0 << 14)) /* no check */ -#define CMD_SET_CRC7C ((0 << 13) | (0 << 12)) /* CRC7 check*/ -#define CMD_SET_CRC7C_BITS ((0 << 13) | (1 << 12)) /* check bits check*/ -#define CMD_SET_CRC7C_INTERNAL ((1 << 13) | (0 << 12)) /* internal CRC7 check*/ -#define CMD_SET_CRC16C (1 << 10) /* 0: CRC16 check*/ -#define CMD_SET_CRCSTE (1 << 8) /* 1: not receive CRC status */ -#define CMD_SET_TBIT (1 << 7) /* 1: tran mission bit "Low" */ -#define CMD_SET_OPDM (1 << 6) /* 1: open/drain */ -#define CMD_SET_CCSH (1 << 5) -#define CMD_SET_DATW_1 ((0 << 1) | (0 << 0)) /* 1bit */ -#define CMD_SET_DATW_4 ((0 << 1) | (1 << 0)) /* 4bit */ -#define CMD_SET_DATW_8 ((1 << 1) | (0 << 0)) /* 8bit */ - -/* CE_CMD_CTRL */ -#define CMD_CTRL_BREAK (1 << 0) - -/* CE_BLOCK_SET */ -#define BLOCK_SIZE_MASK 0x0000ffff - -/* CE_INT */ -#define INT_CCSDE (1 << 29) -#define INT_CMD12DRE (1 << 26) -#define INT_CMD12RBE (1 << 25) -#define INT_CMD12CRE (1 << 24) -#define INT_DTRANE (1 << 23) -#define INT_BUFRE (1 << 22) -#define INT_BUFWEN (1 << 21) -#define INT_BUFREN (1 << 20) -#define INT_CCSRCV (1 << 19) -#define INT_RBSYE (1 << 17) -#define INT_CRSPE (1 << 16) -#define INT_CMDVIO (1 << 15) -#define INT_BUFVIO (1 << 14) -#define INT_WDATERR (1 << 11) -#define INT_RDATERR (1 << 10) -#define INT_RIDXERR (1 << 9) -#define INT_RSPERR (1 << 8) -#define INT_CCSTO (1 << 5) -#define INT_CRCSTO (1 << 4) -#define INT_WDATTO (1 << 3) -#define INT_RDATTO (1 << 2) -#define INT_RBSYTO (1 << 1) -#define INT_RSPTO (1 << 0) -#define INT_ERR_STS (INT_CMDVIO | INT_BUFVIO | INT_WDATERR | \ - INT_RDATERR | INT_RIDXERR | INT_RSPERR | \ - INT_CCSTO | INT_CRCSTO | INT_WDATTO | \ - INT_RDATTO | INT_RBSYTO | INT_RSPTO) - -/* CE_INT_MASK */ -#define MASK_ALL 0x00000000 -#define MASK_MCCSDE (1 << 29) -#define MASK_MCMD12DRE (1 << 26) -#define MASK_MCMD12RBE (1 << 25) -#define MASK_MCMD12CRE (1 << 24) -#define MASK_MDTRANE (1 << 23) -#define MASK_MBUFRE (1 << 22) -#define MASK_MBUFWEN (1 << 21) -#define MASK_MBUFREN (1 << 20) -#define MASK_MCCSRCV (1 << 19) -#define MASK_MRBSYE (1 << 17) -#define MASK_MCRSPE (1 << 16) -#define MASK_MCMDVIO (1 << 15) -#define MASK_MBUFVIO (1 << 14) -#define MASK_MWDATERR (1 << 11) -#define MASK_MRDATERR (1 << 10) -#define MASK_MRIDXERR (1 << 9) -#define MASK_MRSPERR (1 << 8) -#define MASK_MCCSTO (1 << 5) -#define MASK_MCRCSTO (1 << 4) -#define MASK_MWDATTO (1 << 3) -#define MASK_MRDATTO (1 << 2) -#define MASK_MRBSYTO (1 << 1) -#define MASK_MRSPTO (1 << 0) - -#define MASK_START_CMD (MASK_MCMDVIO | MASK_MBUFVIO | MASK_MWDATERR | \ - MASK_MRDATERR | MASK_MRIDXERR | MASK_MRSPERR | \ - MASK_MCCSTO | MASK_MCRCSTO | MASK_MWDATTO | \ - MASK_MRDATTO | MASK_MRBSYTO | MASK_MRSPTO) - -/* CE_HOST_STS1 */ -#define STS1_CMDSEQ (1 << 31) - -/* CE_HOST_STS2 */ -#define STS2_CRCSTE (1 << 31) -#define STS2_CRC16E (1 << 30) -#define STS2_AC12CRCE (1 << 29) -#define STS2_RSPCRC7E (1 << 28) -#define STS2_CRCSTEBE (1 << 27) -#define STS2_RDATEBE (1 << 26) -#define STS2_AC12REBE (1 << 25) -#define STS2_RSPEBE (1 << 24) -#define STS2_AC12IDXE (1 << 23) -#define STS2_RSPIDXE (1 << 22) -#define STS2_CCSTO (1 << 15) -#define STS2_RDATTO (1 << 14) -#define STS2_DATBSYTO (1 << 13) -#define STS2_CRCSTTO (1 << 12) -#define STS2_AC12BSYTO (1 << 11) -#define STS2_RSPBSYTO (1 << 10) -#define STS2_AC12RSPTO (1 << 9) -#define STS2_RSPTO (1 << 8) -#define STS2_CRC_ERR (STS2_CRCSTE | STS2_CRC16E | \ - STS2_AC12CRCE | STS2_RSPCRC7E | STS2_CRCSTEBE) -#define STS2_TIMEOUT_ERR (STS2_CCSTO | STS2_RDATTO | \ - STS2_DATBSYTO | STS2_CRCSTTO | \ - STS2_AC12BSYTO | STS2_RSPBSYTO | \ - STS2_AC12RSPTO | STS2_RSPTO) - -#define CLKDEV_EMMC_DATA 52000000 /* 52MHz */ -#define CLKDEV_MMC_DATA 20000000 /* 20MHz */ -#define CLKDEV_INIT 400000 /* 400 KHz */ - -enum mmcif_state { - STATE_IDLE, - STATE_REQUEST, - STATE_IOS, -}; - -enum mmcif_wait_for { - MMCIF_WAIT_FOR_REQUEST, - MMCIF_WAIT_FOR_CMD, - MMCIF_WAIT_FOR_MREAD, - MMCIF_WAIT_FOR_MWRITE, - MMCIF_WAIT_FOR_READ, - MMCIF_WAIT_FOR_WRITE, - MMCIF_WAIT_FOR_READ_END, - MMCIF_WAIT_FOR_WRITE_END, - MMCIF_WAIT_FOR_STOP, -}; - -struct sh_mmcif_host { - struct mmc_host *mmc; - struct mmc_request *mrq; - struct platform_device *pd; - struct sh_dmae_slave dma_slave_tx; - struct sh_dmae_slave dma_slave_rx; - struct clk *hclk; - unsigned int clk; - int bus_width; - bool sd_error; - bool dying; - long timeout; - void __iomem *addr; - u32 *pio_ptr; - spinlock_t lock; /* protect sh_mmcif_host::state */ - enum mmcif_state state; - enum mmcif_wait_for wait_for; - struct delayed_work timeout_work; - size_t blocksize; - int sg_idx; - int sg_blkidx; - bool power; - bool card_present; - - /* DMA support */ - struct dma_chan *chan_rx; - struct dma_chan *chan_tx; - struct completion dma_complete; - bool dma_active; -}; - -static inline void sh_mmcif_bitset(struct sh_mmcif_host *host, - unsigned int reg, u32 val) -{ - writel(val | readl(host->addr + reg), host->addr + reg); -} - -static inline void sh_mmcif_bitclr(struct sh_mmcif_host *host, - unsigned int reg, u32 val) -{ - writel(~val & readl(host->addr + reg), host->addr + reg); -} - -static void mmcif_dma_complete(void *arg) -{ - struct sh_mmcif_host *host = arg; - struct mmc_data *data = host->mrq->data; - - dev_dbg(&host->pd->dev, "Command completed\n"); - - if (WARN(!data, "%s: NULL data in DMA completion!\n", - dev_name(&host->pd->dev))) - return; - - if (data->flags & MMC_DATA_READ) - dma_unmap_sg(host->chan_rx->device->dev, - data->sg, data->sg_len, - DMA_FROM_DEVICE); - else - dma_unmap_sg(host->chan_tx->device->dev, - data->sg, data->sg_len, - DMA_TO_DEVICE); - - complete(&host->dma_complete); -} - -static void sh_mmcif_start_dma_rx(struct sh_mmcif_host *host) -{ - struct mmc_data *data = host->mrq->data; - struct scatterlist *sg = data->sg; - struct dma_async_tx_descriptor *desc = NULL; - struct dma_chan *chan = host->chan_rx; - dma_cookie_t cookie = -EINVAL; - int ret; - - ret = dma_map_sg(chan->device->dev, sg, data->sg_len, - DMA_FROM_DEVICE); - if (ret > 0) { - host->dma_active = true; - desc = dmaengine_prep_slave_sg(chan, sg, ret, - DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); - } - - if (desc) { - desc->callback = mmcif_dma_complete; - desc->callback_param = host; - cookie = dmaengine_submit(desc); - sh_mmcif_bitset(host, MMCIF_CE_BUF_ACC, BUF_ACC_DMAREN); - dma_async_issue_pending(chan); - } - dev_dbg(&host->pd->dev, "%s(): mapped %d -> %d, cookie %d\n", - __func__, data->sg_len, ret, cookie); - - if (!desc) { - /* DMA failed, fall back to PIO */ - if (ret >= 0) - ret = -EIO; - host->chan_rx = NULL; - host->dma_active = false; - dma_release_channel(chan); - /* Free the Tx channel too */ - chan = host->chan_tx; - if (chan) { - host->chan_tx = NULL; - dma_release_channel(chan); - } - dev_warn(&host->pd->dev, - "DMA failed: %d, falling back to PIO\n", ret); - sh_mmcif_bitclr(host, MMCIF_CE_BUF_ACC, BUF_ACC_DMAREN | BUF_ACC_DMAWEN); - } - - dev_dbg(&host->pd->dev, "%s(): desc %p, cookie %d, sg[%d]\n", __func__, - desc, cookie, data->sg_len); -} - -static void sh_mmcif_start_dma_tx(struct sh_mmcif_host *host) -{ - struct mmc_data *data = host->mrq->data; - struct scatterlist *sg = data->sg; - struct dma_async_tx_descriptor *desc = NULL; - struct dma_chan *chan = host->chan_tx; - dma_cookie_t cookie = -EINVAL; - int ret; - - ret = dma_map_sg(chan->device->dev, sg, data->sg_len, - DMA_TO_DEVICE); - if (ret > 0) { - host->dma_active = true; - desc = dmaengine_prep_slave_sg(chan, sg, ret, - DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); - } - - if (desc) { - desc->callback = mmcif_dma_complete; - desc->callback_param = host; - cookie = dmaengine_submit(desc); - sh_mmcif_bitset(host, MMCIF_CE_BUF_ACC, BUF_ACC_DMAWEN); - dma_async_issue_pending(chan); - } - dev_dbg(&host->pd->dev, "%s(): mapped %d -> %d, cookie %d\n", - __func__, data->sg_len, ret, cookie); - - if (!desc) { - /* DMA failed, fall back to PIO */ - if (ret >= 0) - ret = -EIO; - host->chan_tx = NULL; - host->dma_active = false; - dma_release_channel(chan); - /* Free the Rx channel too */ - chan = host->chan_rx; - if (chan) { - host->chan_rx = NULL; - dma_release_channel(chan); - } - dev_warn(&host->pd->dev, - "DMA failed: %d, falling back to PIO\n", ret); - sh_mmcif_bitclr(host, MMCIF_CE_BUF_ACC, BUF_ACC_DMAREN | BUF_ACC_DMAWEN); - } - - dev_dbg(&host->pd->dev, "%s(): desc %p, cookie %d\n", __func__, - desc, cookie); -} - -static bool sh_mmcif_filter(struct dma_chan *chan, void *arg) -{ - dev_dbg(chan->device->dev, "%s: slave data %p\n", __func__, arg); - chan->private = arg; - return true; -} - -static void sh_mmcif_request_dma(struct sh_mmcif_host *host, - struct sh_mmcif_plat_data *pdata) -{ - struct sh_dmae_slave *tx, *rx; - host->dma_active = false; - - /* We can only either use DMA for both Tx and Rx or not use it at all */ - if (pdata->dma) { - dev_warn(&host->pd->dev, - "Update your platform to use embedded DMA slave IDs\n"); - tx = &pdata->dma->chan_priv_tx; - rx = &pdata->dma->chan_priv_rx; - } else { - tx = &host->dma_slave_tx; - tx->slave_id = pdata->slave_id_tx; - rx = &host->dma_slave_rx; - rx->slave_id = pdata->slave_id_rx; - } - if (tx->slave_id > 0 && rx->slave_id > 0) { - dma_cap_mask_t mask; - - dma_cap_zero(mask); - dma_cap_set(DMA_SLAVE, mask); - - host->chan_tx = dma_request_channel(mask, sh_mmcif_filter, tx); - dev_dbg(&host->pd->dev, "%s: TX: got channel %p\n", __func__, - host->chan_tx); - - if (!host->chan_tx) - return; - - host->chan_rx = dma_request_channel(mask, sh_mmcif_filter, rx); - dev_dbg(&host->pd->dev, "%s: RX: got channel %p\n", __func__, - host->chan_rx); - - if (!host->chan_rx) { - dma_release_channel(host->chan_tx); - host->chan_tx = NULL; - return; - } - - init_completion(&host->dma_complete); - } -} - -static void sh_mmcif_release_dma(struct sh_mmcif_host *host) -{ - sh_mmcif_bitclr(host, MMCIF_CE_BUF_ACC, BUF_ACC_DMAREN | BUF_ACC_DMAWEN); - /* Descriptors are freed automatically */ - if (host->chan_tx) { - struct dma_chan *chan = host->chan_tx; - host->chan_tx = NULL; - dma_release_channel(chan); - } - if (host->chan_rx) { - struct dma_chan *chan = host->chan_rx; - host->chan_rx = NULL; - dma_release_channel(chan); - } - - host->dma_active = false; -} - -static void sh_mmcif_clock_control(struct sh_mmcif_host *host, unsigned int clk) -{ - struct sh_mmcif_plat_data *p = host->pd->dev.platform_data; - - sh_mmcif_bitclr(host, MMCIF_CE_CLK_CTRL, CLK_ENABLE); - sh_mmcif_bitclr(host, MMCIF_CE_CLK_CTRL, CLK_CLEAR); - - if (!clk) - return; - if (p->sup_pclk && clk == host->clk) - sh_mmcif_bitset(host, MMCIF_CE_CLK_CTRL, CLK_SUP_PCLK); - else - sh_mmcif_bitset(host, MMCIF_CE_CLK_CTRL, CLK_CLEAR & - ((fls(DIV_ROUND_UP(host->clk, - clk) - 1) - 1) << 16)); - - sh_mmcif_bitset(host, MMCIF_CE_CLK_CTRL, CLK_ENABLE); -} - -static void sh_mmcif_sync_reset(struct sh_mmcif_host *host) -{ - u32 tmp; - - tmp = 0x010f0000 & sh_mmcif_readl(host->addr, MMCIF_CE_CLK_CTRL); - - sh_mmcif_writel(host->addr, MMCIF_CE_VERSION, SOFT_RST_ON); - sh_mmcif_writel(host->addr, MMCIF_CE_VERSION, SOFT_RST_OFF); - sh_mmcif_bitset(host, MMCIF_CE_CLK_CTRL, tmp | - SRSPTO_256 | SRBSYTO_29 | SRWDTO_29 | SCCSTO_29); - /* byte swap on */ - sh_mmcif_bitset(host, MMCIF_CE_BUF_ACC, BUF_ACC_ATYP); -} - -static int sh_mmcif_error_manage(struct sh_mmcif_host *host) -{ - u32 state1, state2; - int ret, timeout; - - host->sd_error = false; - - state1 = sh_mmcif_readl(host->addr, MMCIF_CE_HOST_STS1); - state2 = sh_mmcif_readl(host->addr, MMCIF_CE_HOST_STS2); - dev_dbg(&host->pd->dev, "ERR HOST_STS1 = %08x\n", state1); - dev_dbg(&host->pd->dev, "ERR HOST_STS2 = %08x\n", state2); - - if (state1 & STS1_CMDSEQ) { - sh_mmcif_bitset(host, MMCIF_CE_CMD_CTRL, CMD_CTRL_BREAK); - sh_mmcif_bitset(host, MMCIF_CE_CMD_CTRL, ~CMD_CTRL_BREAK); - for (timeout = 10000000; timeout; timeout--) { - if (!(sh_mmcif_readl(host->addr, MMCIF_CE_HOST_STS1) - & STS1_CMDSEQ)) - break; - mdelay(1); - } - if (!timeout) { - dev_err(&host->pd->dev, - "Forced end of command sequence timeout err\n"); - return -EIO; - } - sh_mmcif_sync_reset(host); - dev_dbg(&host->pd->dev, "Forced end of command sequence\n"); - return -EIO; - } - - if (state2 & STS2_CRC_ERR) { - dev_dbg(&host->pd->dev, ": CRC error\n"); - ret = -EIO; - } else if (state2 & STS2_TIMEOUT_ERR) { - dev_dbg(&host->pd->dev, ": Timeout\n"); - ret = -ETIMEDOUT; - } else { - dev_dbg(&host->pd->dev, ": End/Index error\n"); - ret = -EIO; - } - return ret; -} - -static bool sh_mmcif_next_block(struct sh_mmcif_host *host, u32 *p) -{ - struct mmc_data *data = host->mrq->data; - - host->sg_blkidx += host->blocksize; - - /* data->sg->length must be a multiple of host->blocksize? */ - BUG_ON(host->sg_blkidx > data->sg->length); - - if (host->sg_blkidx == data->sg->length) { - host->sg_blkidx = 0; - if (++host->sg_idx < data->sg_len) - host->pio_ptr = sg_virt(++data->sg); - } else { - host->pio_ptr = p; - } - - if (host->sg_idx == data->sg_len) - return false; - - return true; -} - -static void sh_mmcif_single_read(struct sh_mmcif_host *host, - struct mmc_request *mrq) -{ - host->blocksize = (sh_mmcif_readl(host->addr, MMCIF_CE_BLOCK_SET) & - BLOCK_SIZE_MASK) + 3; - - host->wait_for = MMCIF_WAIT_FOR_READ; - schedule_delayed_work(&host->timeout_work, host->timeout); - - /* buf read enable */ - sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFREN); -} - -static bool sh_mmcif_read_block(struct sh_mmcif_host *host) -{ - struct mmc_data *data = host->mrq->data; - u32 *p = sg_virt(data->sg); - int i; - - if (host->sd_error) { - data->error = sh_mmcif_error_manage(host); - return false; - } - - for (i = 0; i < host->blocksize / 4; i++) - *p++ = sh_mmcif_readl(host->addr, MMCIF_CE_DATA); - - /* buffer read end */ - sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFRE); - host->wait_for = MMCIF_WAIT_FOR_READ_END; - - return true; -} - -static void sh_mmcif_multi_read(struct sh_mmcif_host *host, - struct mmc_request *mrq) -{ - struct mmc_data *data = mrq->data; - - if (!data->sg_len || !data->sg->length) - return; - - host->blocksize = sh_mmcif_readl(host->addr, MMCIF_CE_BLOCK_SET) & - BLOCK_SIZE_MASK; - - host->wait_for = MMCIF_WAIT_FOR_MREAD; - host->sg_idx = 0; - host->sg_blkidx = 0; - host->pio_ptr = sg_virt(data->sg); - schedule_delayed_work(&host->timeout_work, host->timeout); - sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFREN); -} - -static bool sh_mmcif_mread_block(struct sh_mmcif_host *host) -{ - struct mmc_data *data = host->mrq->data; - u32 *p = host->pio_ptr; - int i; - - if (host->sd_error) { - data->error = sh_mmcif_error_manage(host); - return false; - } - - BUG_ON(!data->sg->length); - - for (i = 0; i < host->blocksize / 4; i++) - *p++ = sh_mmcif_readl(host->addr, MMCIF_CE_DATA); - - if (!sh_mmcif_next_block(host, p)) - return false; - - schedule_delayed_work(&host->timeout_work, host->timeout); - sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFREN); - - return true; -} - -static void sh_mmcif_single_write(struct sh_mmcif_host *host, - struct mmc_request *mrq) -{ - host->blocksize = (sh_mmcif_readl(host->addr, MMCIF_CE_BLOCK_SET) & - BLOCK_SIZE_MASK) + 3; - - host->wait_for = MMCIF_WAIT_FOR_WRITE; - schedule_delayed_work(&host->timeout_work, host->timeout); - - /* buf write enable */ - sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFWEN); -} - -static bool sh_mmcif_write_block(struct sh_mmcif_host *host) -{ - struct mmc_data *data = host->mrq->data; - u32 *p = sg_virt(data->sg); - int i; - - if (host->sd_error) { - data->error = sh_mmcif_error_manage(host); - return false; - } - - for (i = 0; i < host->blocksize / 4; i++) - sh_mmcif_writel(host->addr, MMCIF_CE_DATA, *p++); - - /* buffer write end */ - sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MDTRANE); - host->wait_for = MMCIF_WAIT_FOR_WRITE_END; - - return true; -} - -static void sh_mmcif_multi_write(struct sh_mmcif_host *host, - struct mmc_request *mrq) -{ - struct mmc_data *data = mrq->data; - - if (!data->sg_len || !data->sg->length) - return; - - host->blocksize = sh_mmcif_readl(host->addr, MMCIF_CE_BLOCK_SET) & - BLOCK_SIZE_MASK; - - host->wait_for = MMCIF_WAIT_FOR_MWRITE; - host->sg_idx = 0; - host->sg_blkidx = 0; - host->pio_ptr = sg_virt(data->sg); - schedule_delayed_work(&host->timeout_work, host->timeout); - sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFWEN); -} - -static bool sh_mmcif_mwrite_block(struct sh_mmcif_host *host) -{ - struct mmc_data *data = host->mrq->data; - u32 *p = host->pio_ptr; - int i; - - if (host->sd_error) { - data->error = sh_mmcif_error_manage(host); - return false; - } - - BUG_ON(!data->sg->length); - - for (i = 0; i < host->blocksize / 4; i++) - sh_mmcif_writel(host->addr, MMCIF_CE_DATA, *p++); - - if (!sh_mmcif_next_block(host, p)) - return false; - - schedule_delayed_work(&host->timeout_work, host->timeout); - sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFWEN); - - return true; -} - -static void sh_mmcif_get_response(struct sh_mmcif_host *host, - struct mmc_command *cmd) -{ - if (cmd->flags & MMC_RSP_136) { - cmd->resp[0] = sh_mmcif_readl(host->addr, MMCIF_CE_RESP3); - cmd->resp[1] = sh_mmcif_readl(host->addr, MMCIF_CE_RESP2); - cmd->resp[2] = sh_mmcif_readl(host->addr, MMCIF_CE_RESP1); - cmd->resp[3] = sh_mmcif_readl(host->addr, MMCIF_CE_RESP0); - } else - cmd->resp[0] = sh_mmcif_readl(host->addr, MMCIF_CE_RESP0); -} - -static void sh_mmcif_get_cmd12response(struct sh_mmcif_host *host, - struct mmc_command *cmd) -{ - cmd->resp[0] = sh_mmcif_readl(host->addr, MMCIF_CE_RESP_CMD12); -} - -static u32 sh_mmcif_set_cmd(struct sh_mmcif_host *host, - struct mmc_request *mrq) -{ - struct mmc_data *data = mrq->data; - struct mmc_command *cmd = mrq->cmd; - u32 opc = cmd->opcode; - u32 tmp = 0; - - /* Response Type check */ - switch (mmc_resp_type(cmd)) { - case MMC_RSP_NONE: - tmp |= CMD_SET_RTYP_NO; - break; - case MMC_RSP_R1: - case MMC_RSP_R1B: - case MMC_RSP_R3: - tmp |= CMD_SET_RTYP_6B; - break; - case MMC_RSP_R2: - tmp |= CMD_SET_RTYP_17B; - break; - default: - dev_err(&host->pd->dev, "Unsupported response type.\n"); - break; - } - switch (opc) { - /* RBSY */ - case MMC_SWITCH: - case MMC_STOP_TRANSMISSION: - case MMC_SET_WRITE_PROT: - case MMC_CLR_WRITE_PROT: - case MMC_ERASE: - tmp |= CMD_SET_RBSY; - break; - } - /* WDAT / DATW */ - if (data) { - tmp |= CMD_SET_WDAT; - switch (host->bus_width) { - case MMC_BUS_WIDTH_1: - tmp |= CMD_SET_DATW_1; - break; - case MMC_BUS_WIDTH_4: - tmp |= CMD_SET_DATW_4; - break; - case MMC_BUS_WIDTH_8: - tmp |= CMD_SET_DATW_8; - break; - default: - dev_err(&host->pd->dev, "Unsupported bus width.\n"); - break; - } - } - /* DWEN */ - if (opc == MMC_WRITE_BLOCK || opc == MMC_WRITE_MULTIPLE_BLOCK) - tmp |= CMD_SET_DWEN; - /* CMLTE/CMD12EN */ - if (opc == MMC_READ_MULTIPLE_BLOCK || opc == MMC_WRITE_MULTIPLE_BLOCK) { - tmp |= CMD_SET_CMLTE | CMD_SET_CMD12EN; - sh_mmcif_bitset(host, MMCIF_CE_BLOCK_SET, - data->blocks << 16); - } - /* RIDXC[1:0] check bits */ - if (opc == MMC_SEND_OP_COND || opc == MMC_ALL_SEND_CID || - opc == MMC_SEND_CSD || opc == MMC_SEND_CID) - tmp |= CMD_SET_RIDXC_BITS; - /* RCRC7C[1:0] check bits */ - if (opc == MMC_SEND_OP_COND) - tmp |= CMD_SET_CRC7C_BITS; - /* RCRC7C[1:0] internal CRC7 */ - if (opc == MMC_ALL_SEND_CID || - opc == MMC_SEND_CSD || opc == MMC_SEND_CID) - tmp |= CMD_SET_CRC7C_INTERNAL; - - return (opc << 24) | tmp; -} - -static int sh_mmcif_data_trans(struct sh_mmcif_host *host, - struct mmc_request *mrq, u32 opc) -{ - switch (opc) { - case MMC_READ_MULTIPLE_BLOCK: - sh_mmcif_multi_read(host, mrq); - return 0; - case MMC_WRITE_MULTIPLE_BLOCK: - sh_mmcif_multi_write(host, mrq); - return 0; - case MMC_WRITE_BLOCK: - sh_mmcif_single_write(host, mrq); - return 0; - case MMC_READ_SINGLE_BLOCK: - case MMC_SEND_EXT_CSD: - sh_mmcif_single_read(host, mrq); - return 0; - default: - dev_err(&host->pd->dev, "UNSUPPORTED CMD = d'%08d\n", opc); - return -EINVAL; - } -} - -static void sh_mmcif_start_cmd(struct sh_mmcif_host *host, - struct mmc_request *mrq) -{ - struct mmc_command *cmd = mrq->cmd; - u32 opc = cmd->opcode; - u32 mask; - - switch (opc) { - /* response busy check */ - case MMC_SWITCH: - case MMC_STOP_TRANSMISSION: - case MMC_SET_WRITE_PROT: - case MMC_CLR_WRITE_PROT: - case MMC_ERASE: - mask = MASK_START_CMD | MASK_MRBSYE; - break; - default: - mask = MASK_START_CMD | MASK_MCRSPE; - break; - } - - if (mrq->data) { - sh_mmcif_writel(host->addr, MMCIF_CE_BLOCK_SET, 0); - sh_mmcif_writel(host->addr, MMCIF_CE_BLOCK_SET, - mrq->data->blksz); - } - opc = sh_mmcif_set_cmd(host, mrq); - - sh_mmcif_writel(host->addr, MMCIF_CE_INT, 0xD80430C0); - sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, mask); - /* set arg */ - sh_mmcif_writel(host->addr, MMCIF_CE_ARG, cmd->arg); - /* set cmd */ - sh_mmcif_writel(host->addr, MMCIF_CE_CMD_SET, opc); - - host->wait_for = MMCIF_WAIT_FOR_CMD; - schedule_delayed_work(&host->timeout_work, host->timeout); -} - -static void sh_mmcif_stop_cmd(struct sh_mmcif_host *host, - struct mmc_request *mrq) -{ - switch (mrq->cmd->opcode) { - case MMC_READ_MULTIPLE_BLOCK: - sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MCMD12DRE); - break; - case MMC_WRITE_MULTIPLE_BLOCK: - sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MCMD12RBE); - break; - default: - dev_err(&host->pd->dev, "unsupported stop cmd\n"); - mrq->stop->error = sh_mmcif_error_manage(host); - return; - } - - host->wait_for = MMCIF_WAIT_FOR_STOP; - schedule_delayed_work(&host->timeout_work, host->timeout); -} - -static void sh_mmcif_request(struct mmc_host *mmc, struct mmc_request *mrq) -{ - struct sh_mmcif_host *host = mmc_priv(mmc); - unsigned long flags; - - spin_lock_irqsave(&host->lock, flags); - if (host->state != STATE_IDLE) { - spin_unlock_irqrestore(&host->lock, flags); - mrq->cmd->error = -EAGAIN; - mmc_request_done(mmc, mrq); - return; - } - - host->state = STATE_REQUEST; - spin_unlock_irqrestore(&host->lock, flags); - - switch (mrq->cmd->opcode) { - /* MMCIF does not support SD/SDIO command */ - case SD_IO_SEND_OP_COND: - case MMC_APP_CMD: - host->state = STATE_IDLE; - mrq->cmd->error = -ETIMEDOUT; - mmc_request_done(mmc, mrq); - return; - case MMC_SEND_EXT_CSD: /* = SD_SEND_IF_COND (8) */ - if (!mrq->data) { - /* send_if_cond cmd (not support) */ - host->state = STATE_IDLE; - mrq->cmd->error = -ETIMEDOUT; - mmc_request_done(mmc, mrq); - return; - } - break; - default: - break; - } - - host->mrq = mrq; - - sh_mmcif_start_cmd(host, mrq); -} - -static void sh_mmcif_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) -{ - struct sh_mmcif_host *host = mmc_priv(mmc); - struct sh_mmcif_plat_data *p = host->pd->dev.platform_data; - unsigned long flags; - - spin_lock_irqsave(&host->lock, flags); - if (host->state != STATE_IDLE) { - spin_unlock_irqrestore(&host->lock, flags); - return; - } - - host->state = STATE_IOS; - spin_unlock_irqrestore(&host->lock, flags); - - if (ios->power_mode == MMC_POWER_UP) { - if (!host->card_present) { - /* See if we also get DMA */ - sh_mmcif_request_dma(host, host->pd->dev.platform_data); - host->card_present = true; - } - } else if (ios->power_mode == MMC_POWER_OFF || !ios->clock) { - /* clock stop */ - sh_mmcif_clock_control(host, 0); - if (ios->power_mode == MMC_POWER_OFF) { - if (host->card_present) { - sh_mmcif_release_dma(host); - host->card_present = false; - } - } - if (host->power) { - pm_runtime_put(&host->pd->dev); - host->power = false; - if (p->down_pwr && ios->power_mode == MMC_POWER_OFF) - p->down_pwr(host->pd); - } - host->state = STATE_IDLE; - return; - } - - if (ios->clock) { - if (!host->power) { - if (p->set_pwr) - p->set_pwr(host->pd, ios->power_mode); - pm_runtime_get_sync(&host->pd->dev); - host->power = true; - sh_mmcif_sync_reset(host); - } - sh_mmcif_clock_control(host, ios->clock); - } - - host->bus_width = ios->bus_width; - host->state = STATE_IDLE; -} - -static int sh_mmcif_get_cd(struct mmc_host *mmc) -{ - struct sh_mmcif_host *host = mmc_priv(mmc); - struct sh_mmcif_plat_data *p = host->pd->dev.platform_data; - - if (!p->get_cd) - return -ENOSYS; - else - return p->get_cd(host->pd); -} - -static struct mmc_host_ops sh_mmcif_ops = { - .request = sh_mmcif_request, - .set_ios = sh_mmcif_set_ios, - .get_cd = sh_mmcif_get_cd, -}; - -static bool sh_mmcif_end_cmd(struct sh_mmcif_host *host) -{ - struct mmc_command *cmd = host->mrq->cmd; - struct mmc_data *data = host->mrq->data; - long time; - - if (host->sd_error) { - switch (cmd->opcode) { - case MMC_ALL_SEND_CID: - case MMC_SELECT_CARD: - case MMC_APP_CMD: - cmd->error = -ETIMEDOUT; - host->sd_error = false; - break; - default: - cmd->error = sh_mmcif_error_manage(host); - dev_dbg(&host->pd->dev, "Cmd(d'%d) error %d\n", - cmd->opcode, cmd->error); - break; - } - return false; - } - if (!(cmd->flags & MMC_RSP_PRESENT)) { - cmd->error = 0; - return false; - } - - sh_mmcif_get_response(host, cmd); - - if (!data) - return false; - - if (data->flags & MMC_DATA_READ) { - if (host->chan_rx) - sh_mmcif_start_dma_rx(host); - } else { - if (host->chan_tx) - sh_mmcif_start_dma_tx(host); - } - - if (!host->dma_active) { - data->error = sh_mmcif_data_trans(host, host->mrq, cmd->opcode); - if (!data->error) - return true; - return false; - } - - /* Running in the IRQ thread, can sleep */ - time = wait_for_completion_interruptible_timeout(&host->dma_complete, - host->timeout); - if (host->sd_error) { - dev_err(host->mmc->parent, - "Error IRQ while waiting for DMA completion!\n"); - /* Woken up by an error IRQ: abort DMA */ - if (data->flags & MMC_DATA_READ) - dmaengine_terminate_all(host->chan_rx); - else - dmaengine_terminate_all(host->chan_tx); - data->error = sh_mmcif_error_manage(host); - } else if (!time) { - data->error = -ETIMEDOUT; - } else if (time < 0) { - data->error = time; - } - sh_mmcif_bitclr(host, MMCIF_CE_BUF_ACC, - BUF_ACC_DMAREN | BUF_ACC_DMAWEN); - host->dma_active = false; - - if (data->error) - data->bytes_xfered = 0; - - return false; -} - -static irqreturn_t sh_mmcif_irqt(int irq, void *dev_id) -{ - struct sh_mmcif_host *host = dev_id; - struct mmc_request *mrq = host->mrq; - struct mmc_data *data = mrq->data; - - cancel_delayed_work_sync(&host->timeout_work); - - /* - * All handlers return true, if processing continues, and false, if the - * request has to be completed - successfully or not - */ - switch (host->wait_for) { - case MMCIF_WAIT_FOR_REQUEST: - /* We're too late, the timeout has already kicked in */ - return IRQ_HANDLED; - case MMCIF_WAIT_FOR_CMD: - if (sh_mmcif_end_cmd(host)) - /* Wait for data */ - return IRQ_HANDLED; - break; - case MMCIF_WAIT_FOR_MREAD: - if (sh_mmcif_mread_block(host)) - /* Wait for more data */ - return IRQ_HANDLED; - break; - case MMCIF_WAIT_FOR_READ: - if (sh_mmcif_read_block(host)) - /* Wait for data end */ - return IRQ_HANDLED; - break; - case MMCIF_WAIT_FOR_MWRITE: - if (sh_mmcif_mwrite_block(host)) - /* Wait data to write */ - return IRQ_HANDLED; - break; - case MMCIF_WAIT_FOR_WRITE: - if (sh_mmcif_write_block(host)) - /* Wait for data end */ - return IRQ_HANDLED; - break; - case MMCIF_WAIT_FOR_STOP: - if (host->sd_error) { - mrq->stop->error = sh_mmcif_error_manage(host); - break; - } - sh_mmcif_get_cmd12response(host, mrq->stop); - mrq->stop->error = 0; - break; - case MMCIF_WAIT_FOR_READ_END: - case MMCIF_WAIT_FOR_WRITE_END: - if (host->sd_error) - data->error = sh_mmcif_error_manage(host); - break; - default: - BUG(); - } - - if (host->wait_for != MMCIF_WAIT_FOR_STOP) { - if (!mrq->cmd->error && data && !data->error) - data->bytes_xfered = - data->blocks * data->blksz; - - if (mrq->stop && !mrq->cmd->error && (!data || !data->error)) { - sh_mmcif_stop_cmd(host, mrq); - if (!mrq->stop->error) - return IRQ_HANDLED; - } - } - - host->wait_for = MMCIF_WAIT_FOR_REQUEST; - host->state = STATE_IDLE; - host->mrq = NULL; - mmc_request_done(host->mmc, mrq); - - return IRQ_HANDLED; -} - -static irqreturn_t sh_mmcif_intr(int irq, void *dev_id) -{ - struct sh_mmcif_host *host = dev_id; - u32 state; - int err = 0; - - state = sh_mmcif_readl(host->addr, MMCIF_CE_INT); - - if (state & INT_ERR_STS) { - /* error interrupts - process first */ - sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~state); - sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, state); - err = 1; - } else if (state & INT_RBSYE) { - sh_mmcif_writel(host->addr, MMCIF_CE_INT, - ~(INT_RBSYE | INT_CRSPE)); - sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, MASK_MRBSYE); - } else if (state & INT_CRSPE) { - sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~INT_CRSPE); - sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, MASK_MCRSPE); - } else if (state & INT_BUFREN) { - sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~INT_BUFREN); - sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, MASK_MBUFREN); - } else if (state & INT_BUFWEN) { - sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~INT_BUFWEN); - sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, MASK_MBUFWEN); - } else if (state & INT_CMD12DRE) { - sh_mmcif_writel(host->addr, MMCIF_CE_INT, - ~(INT_CMD12DRE | INT_CMD12RBE | - INT_CMD12CRE | INT_BUFRE)); - sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, MASK_MCMD12DRE); - } else if (state & INT_BUFRE) { - sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~INT_BUFRE); - sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, MASK_MBUFRE); - } else if (state & INT_DTRANE) { - sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~INT_DTRANE); - sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, MASK_MDTRANE); - } else if (state & INT_CMD12RBE) { - sh_mmcif_writel(host->addr, MMCIF_CE_INT, - ~(INT_CMD12RBE | INT_CMD12CRE)); - sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, MASK_MCMD12RBE); - } else { - dev_dbg(&host->pd->dev, "Unsupported interrupt: 0x%x\n", state); - sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~state); - sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, state); - err = 1; - } - if (err) { - host->sd_error = true; - dev_dbg(&host->pd->dev, "int err state = %08x\n", state); - } - if (state & ~(INT_CMD12RBE | INT_CMD12CRE)) { - if (!host->dma_active) - return IRQ_WAKE_THREAD; - else if (host->sd_error) - mmcif_dma_complete(host); - } else { - dev_dbg(&host->pd->dev, "Unexpected IRQ 0x%x\n", state); - } - - return IRQ_HANDLED; -} - -static void mmcif_timeout_work(struct work_struct *work) -{ - struct delayed_work *d = container_of(work, struct delayed_work, work); - struct sh_mmcif_host *host = container_of(d, struct sh_mmcif_host, timeout_work); - struct mmc_request *mrq = host->mrq; - - if (host->dying) - /* Don't run after mmc_remove_host() */ - return; - - /* - * Handle races with cancel_delayed_work(), unless - * cancel_delayed_work_sync() is used - */ - switch (host->wait_for) { - case MMCIF_WAIT_FOR_CMD: - mrq->cmd->error = sh_mmcif_error_manage(host); - break; - case MMCIF_WAIT_FOR_STOP: - mrq->stop->error = sh_mmcif_error_manage(host); - break; - case MMCIF_WAIT_FOR_MREAD: - case MMCIF_WAIT_FOR_MWRITE: - case MMCIF_WAIT_FOR_READ: - case MMCIF_WAIT_FOR_WRITE: - case MMCIF_WAIT_FOR_READ_END: - case MMCIF_WAIT_FOR_WRITE_END: - mrq->data->error = sh_mmcif_error_manage(host); - break; - default: - BUG(); - } - - host->state = STATE_IDLE; - host->wait_for = MMCIF_WAIT_FOR_REQUEST; - host->mrq = NULL; - mmc_request_done(host->mmc, mrq); -} - -static int __devinit sh_mmcif_probe(struct platform_device *pdev) -{ - int ret = 0, irq[2]; - struct mmc_host *mmc; - struct sh_mmcif_host *host; - struct sh_mmcif_plat_data *pd; - struct resource *res; - void __iomem *reg; - char clk_name[8]; - - irq[0] = platform_get_irq(pdev, 0); - irq[1] = platform_get_irq(pdev, 1); - if (irq[0] < 0 || irq[1] < 0) { - dev_err(&pdev->dev, "Get irq error\n"); - return -ENXIO; - } - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, "platform_get_resource error.\n"); - return -ENXIO; - } - reg = ioremap(res->start, resource_size(res)); - if (!reg) { - dev_err(&pdev->dev, "ioremap error.\n"); - return -ENOMEM; - } - pd = pdev->dev.platform_data; - if (!pd) { - dev_err(&pdev->dev, "sh_mmcif plat data error.\n"); - ret = -ENXIO; - goto clean_up; - } - mmc = mmc_alloc_host(sizeof(struct sh_mmcif_host), &pdev->dev); - if (!mmc) { - ret = -ENOMEM; - goto clean_up; - } - host = mmc_priv(mmc); - host->mmc = mmc; - host->addr = reg; - host->timeout = 1000; - - snprintf(clk_name, sizeof(clk_name), "mmc%d", pdev->id); - host->hclk = clk_get(&pdev->dev, clk_name); - if (IS_ERR(host->hclk)) { - dev_err(&pdev->dev, "cannot get clock \"%s\"\n", clk_name); - ret = PTR_ERR(host->hclk); - goto clean_up1; - } - clk_enable(host->hclk); - host->clk = clk_get_rate(host->hclk); - host->pd = pdev; - - spin_lock_init(&host->lock); - - mmc->ops = &sh_mmcif_ops; - mmc->f_max = host->clk / 2; - mmc->f_min = host->clk / 512; - if (pd->ocr) - mmc->ocr_avail = pd->ocr; - mmc->caps = MMC_CAP_MMC_HIGHSPEED; - if (pd->caps) - mmc->caps |= pd->caps; - mmc->max_segs = 32; - mmc->max_blk_size = 512; - mmc->max_req_size = PAGE_CACHE_SIZE * mmc->max_segs; - mmc->max_blk_count = mmc->max_req_size / mmc->max_blk_size; - mmc->max_seg_size = mmc->max_req_size; - - sh_mmcif_sync_reset(host); - platform_set_drvdata(pdev, host); - - pm_runtime_enable(&pdev->dev); - host->power = false; - - ret = pm_runtime_resume(&pdev->dev); - if (ret < 0) - goto clean_up2; - - INIT_DELAYED_WORK(&host->timeout_work, mmcif_timeout_work); - - sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, MASK_ALL); - - ret = request_threaded_irq(irq[0], sh_mmcif_intr, sh_mmcif_irqt, 0, "sh_mmc:error", host); - if (ret) { - dev_err(&pdev->dev, "request_irq error (sh_mmc:error)\n"); - goto clean_up3; - } - ret = request_threaded_irq(irq[1], sh_mmcif_intr, sh_mmcif_irqt, 0, "sh_mmc:int", host); - if (ret) { - dev_err(&pdev->dev, "request_irq error (sh_mmc:int)\n"); - goto clean_up4; - } - - ret = mmc_add_host(mmc); - if (ret < 0) - goto clean_up5; - - dev_pm_qos_expose_latency_limit(&pdev->dev, 100); - - dev_info(&pdev->dev, "driver version %s\n", DRIVER_VERSION); - dev_dbg(&pdev->dev, "chip ver H'%04x\n", - sh_mmcif_readl(host->addr, MMCIF_CE_VERSION) & 0x0000ffff); - return ret; - -clean_up5: - free_irq(irq[1], host); -clean_up4: - free_irq(irq[0], host); -clean_up3: - pm_runtime_suspend(&pdev->dev); -clean_up2: - pm_runtime_disable(&pdev->dev); - clk_disable(host->hclk); -clean_up1: - mmc_free_host(mmc); -clean_up: - if (reg) - iounmap(reg); - return ret; -} - -static int __devexit sh_mmcif_remove(struct platform_device *pdev) -{ - struct sh_mmcif_host *host = platform_get_drvdata(pdev); - int irq[2]; - - host->dying = true; - pm_runtime_get_sync(&pdev->dev); - - dev_pm_qos_hide_latency_limit(&pdev->dev); - - mmc_remove_host(host->mmc); - sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, MASK_ALL); - - /* - * FIXME: cancel_delayed_work(_sync)() and free_irq() race with the - * mmc_remove_host() call above. But swapping order doesn't help either - * (a query on the linux-mmc mailing list didn't bring any replies). - */ - cancel_delayed_work_sync(&host->timeout_work); - - if (host->addr) - iounmap(host->addr); - - irq[0] = platform_get_irq(pdev, 0); - irq[1] = platform_get_irq(pdev, 1); - - free_irq(irq[0], host); - free_irq(irq[1], host); - - platform_set_drvdata(pdev, NULL); - - clk_disable(host->hclk); - mmc_free_host(host->mmc); - pm_runtime_put_sync(&pdev->dev); - pm_runtime_disable(&pdev->dev); - - return 0; -} - -#ifdef CONFIG_PM -static int sh_mmcif_suspend(struct device *dev) -{ - struct platform_device *pdev = to_platform_device(dev); - struct sh_mmcif_host *host = platform_get_drvdata(pdev); - int ret = mmc_suspend_host(host->mmc); - - if (!ret) { - sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, MASK_ALL); - clk_disable(host->hclk); - } - - return ret; -} - -static int sh_mmcif_resume(struct device *dev) -{ - struct platform_device *pdev = to_platform_device(dev); - struct sh_mmcif_host *host = platform_get_drvdata(pdev); - - clk_enable(host->hclk); - - return mmc_resume_host(host->mmc); -} -#else -#define sh_mmcif_suspend NULL -#define sh_mmcif_resume NULL -#endif /* CONFIG_PM */ - -static const struct dev_pm_ops sh_mmcif_dev_pm_ops = { - .suspend = sh_mmcif_suspend, - .resume = sh_mmcif_resume, -}; - -static struct platform_driver sh_mmcif_driver = { - .probe = sh_mmcif_probe, - .remove = sh_mmcif_remove, - .driver = { - .name = DRIVER_NAME, - .pm = &sh_mmcif_dev_pm_ops, - }, -}; - -module_platform_driver(sh_mmcif_driver); - -MODULE_DESCRIPTION("SuperH on-chip MMC/eMMC interface driver"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:" DRIVER_NAME); -MODULE_AUTHOR("Yusuke Goda <yusuke.goda.sx@renesas.com>"); diff --git a/ANDROID_3.4.5/drivers/mmc/host/sh_mobile_sdhi.c b/ANDROID_3.4.5/drivers/mmc/host/sh_mobile_sdhi.c deleted file mode 100644 index 934b68e9..00000000 --- a/ANDROID_3.4.5/drivers/mmc/host/sh_mobile_sdhi.c +++ /dev/null @@ -1,309 +0,0 @@ -/* - * SuperH Mobile SDHI - * - * Copyright (C) 2009 Magnus Damm - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Based on "Compaq ASIC3 support": - * - * Copyright 2001 Compaq Computer Corporation. - * Copyright 2004-2005 Phil Blundell - * Copyright 2007-2008 OpenedHand Ltd. - * - * Authors: Phil Blundell <pb@handhelds.org>, - * Samuel Ortiz <sameo@openedhand.com> - * - */ - -#include <linux/kernel.h> -#include <linux/clk.h> -#include <linux/slab.h> -#include <linux/module.h> -#include <linux/platform_device.h> -#include <linux/mmc/host.h> -#include <linux/mmc/sh_mobile_sdhi.h> -#include <linux/mfd/tmio.h> -#include <linux/sh_dma.h> -#include <linux/delay.h> - -#include "tmio_mmc.h" - -struct sh_mobile_sdhi { - struct clk *clk; - struct tmio_mmc_data mmc_data; - struct sh_dmae_slave param_tx; - struct sh_dmae_slave param_rx; - struct tmio_mmc_dma dma_priv; -}; - -static void sh_mobile_sdhi_set_pwr(struct platform_device *pdev, int state) -{ - struct sh_mobile_sdhi_info *p = pdev->dev.platform_data; - - if (p && p->set_pwr) - p->set_pwr(pdev, state); -} - -static int sh_mobile_sdhi_get_cd(struct platform_device *pdev) -{ - struct sh_mobile_sdhi_info *p = pdev->dev.platform_data; - - if (p && p->get_cd) - return p->get_cd(pdev); - else - return -ENOSYS; -} - -static int sh_mobile_sdhi_wait_idle(struct tmio_mmc_host *host) -{ - int timeout = 1000; - - while (--timeout && !(sd_ctrl_read16(host, CTL_STATUS2) & (1 << 13))) - udelay(1); - - if (!timeout) { - dev_warn(host->pdata->dev, "timeout waiting for SD bus idle\n"); - return -EBUSY; - } - - return 0; -} - -static int sh_mobile_sdhi_write16_hook(struct tmio_mmc_host *host, int addr) -{ - switch (addr) - { - case CTL_SD_CMD: - case CTL_STOP_INTERNAL_ACTION: - case CTL_XFER_BLK_COUNT: - case CTL_SD_CARD_CLK_CTL: - case CTL_SD_XFER_LEN: - case CTL_SD_MEM_CARD_OPT: - case CTL_TRANSACTION_CTL: - case CTL_DMA_ENABLE: - return sh_mobile_sdhi_wait_idle(host); - } - - return 0; -} - -static void sh_mobile_sdhi_cd_wakeup(const struct platform_device *pdev) -{ - mmc_detect_change(dev_get_drvdata(&pdev->dev), msecs_to_jiffies(100)); -} - -static const struct sh_mobile_sdhi_ops sdhi_ops = { - .cd_wakeup = sh_mobile_sdhi_cd_wakeup, -}; - -static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev) -{ - struct sh_mobile_sdhi *priv; - struct tmio_mmc_data *mmc_data; - struct sh_mobile_sdhi_info *p = pdev->dev.platform_data; - struct tmio_mmc_host *host; - char clk_name[8]; - int irq, ret, i = 0; - bool multiplexed_isr = true; - - priv = kzalloc(sizeof(struct sh_mobile_sdhi), GFP_KERNEL); - if (priv == NULL) { - dev_err(&pdev->dev, "kzalloc failed\n"); - return -ENOMEM; - } - - mmc_data = &priv->mmc_data; - p->pdata = mmc_data; - - if (p->init) { - ret = p->init(pdev, &sdhi_ops); - if (ret) - goto einit; - } - - snprintf(clk_name, sizeof(clk_name), "sdhi%d", pdev->id); - priv->clk = clk_get(&pdev->dev, clk_name); - if (IS_ERR(priv->clk)) { - dev_err(&pdev->dev, "cannot get clock \"%s\"\n", clk_name); - ret = PTR_ERR(priv->clk); - goto eclkget; - } - - mmc_data->hclk = clk_get_rate(priv->clk); - mmc_data->set_pwr = sh_mobile_sdhi_set_pwr; - mmc_data->get_cd = sh_mobile_sdhi_get_cd; - mmc_data->capabilities = MMC_CAP_MMC_HIGHSPEED; - if (p) { - mmc_data->flags = p->tmio_flags; - if (mmc_data->flags & TMIO_MMC_HAS_IDLE_WAIT) - mmc_data->write16_hook = sh_mobile_sdhi_write16_hook; - mmc_data->ocr_mask = p->tmio_ocr_mask; - mmc_data->capabilities |= p->tmio_caps; - mmc_data->cd_gpio = p->cd_gpio; - - if (p->dma_slave_tx > 0 && p->dma_slave_rx > 0) { - priv->param_tx.slave_id = p->dma_slave_tx; - priv->param_rx.slave_id = p->dma_slave_rx; - priv->dma_priv.chan_priv_tx = &priv->param_tx; - priv->dma_priv.chan_priv_rx = &priv->param_rx; - priv->dma_priv.alignment_shift = 1; /* 2-byte alignment */ - mmc_data->dma = &priv->dma_priv; - } - } - - /* - * All SDHI blocks support 2-byte and larger block sizes in 4-bit - * bus width mode. - */ - mmc_data->flags |= TMIO_MMC_BLKSZ_2BYTES; - - /* - * All SDHI blocks support SDIO IRQ signalling. - */ - mmc_data->flags |= TMIO_MMC_SDIO_IRQ; - - ret = tmio_mmc_host_probe(&host, pdev, mmc_data); - if (ret < 0) - goto eprobe; - - /* - * Allow one or more specific (named) ISRs or - * one or more multiplexed (un-named) ISRs. - */ - - irq = platform_get_irq_byname(pdev, SH_MOBILE_SDHI_IRQ_CARD_DETECT); - if (irq >= 0) { - multiplexed_isr = false; - ret = request_irq(irq, tmio_mmc_card_detect_irq, 0, - dev_name(&pdev->dev), host); - if (ret) - goto eirq_card_detect; - } - - irq = platform_get_irq_byname(pdev, SH_MOBILE_SDHI_IRQ_SDIO); - if (irq >= 0) { - multiplexed_isr = false; - ret = request_irq(irq, tmio_mmc_sdio_irq, 0, - dev_name(&pdev->dev), host); - if (ret) - goto eirq_sdio; - } - - irq = platform_get_irq_byname(pdev, SH_MOBILE_SDHI_IRQ_SDCARD); - if (irq >= 0) { - multiplexed_isr = false; - ret = request_irq(irq, tmio_mmc_sdcard_irq, 0, - dev_name(&pdev->dev), host); - if (ret) - goto eirq_sdcard; - } else if (!multiplexed_isr) { - dev_err(&pdev->dev, - "Principal SD-card IRQ is missing among named interrupts\n"); - ret = irq; - goto eirq_sdcard; - } - - if (multiplexed_isr) { - while (1) { - irq = platform_get_irq(pdev, i); - if (irq < 0) - break; - i++; - ret = request_irq(irq, tmio_mmc_irq, 0, - dev_name(&pdev->dev), host); - if (ret) - goto eirq_multiplexed; - } - - /* There must be at least one IRQ source */ - if (!i) - goto eirq_multiplexed; - } - - dev_info(&pdev->dev, "%s base at 0x%08lx clock rate %u MHz\n", - mmc_hostname(host->mmc), (unsigned long) - (platform_get_resource(pdev, IORESOURCE_MEM, 0)->start), - mmc_data->hclk / 1000000); - - return ret; - -eirq_multiplexed: - while (i--) { - irq = platform_get_irq(pdev, i); - free_irq(irq, host); - } -eirq_sdcard: - irq = platform_get_irq_byname(pdev, SH_MOBILE_SDHI_IRQ_SDIO); - if (irq >= 0) - free_irq(irq, host); -eirq_sdio: - irq = platform_get_irq_byname(pdev, SH_MOBILE_SDHI_IRQ_CARD_DETECT); - if (irq >= 0) - free_irq(irq, host); -eirq_card_detect: - tmio_mmc_host_remove(host); -eprobe: - clk_put(priv->clk); -eclkget: - if (p->cleanup) - p->cleanup(pdev); -einit: - kfree(priv); - return ret; -} - -static int sh_mobile_sdhi_remove(struct platform_device *pdev) -{ - struct mmc_host *mmc = platform_get_drvdata(pdev); - struct tmio_mmc_host *host = mmc_priv(mmc); - struct sh_mobile_sdhi *priv = container_of(host->pdata, struct sh_mobile_sdhi, mmc_data); - struct sh_mobile_sdhi_info *p = pdev->dev.platform_data; - int i = 0, irq; - - p->pdata = NULL; - - tmio_mmc_host_remove(host); - - while (1) { - irq = platform_get_irq(pdev, i++); - if (irq < 0) - break; - free_irq(irq, host); - } - - clk_put(priv->clk); - - if (p->cleanup) - p->cleanup(pdev); - - kfree(priv); - - return 0; -} - -static const struct dev_pm_ops tmio_mmc_dev_pm_ops = { - .suspend = tmio_mmc_host_suspend, - .resume = tmio_mmc_host_resume, - .runtime_suspend = tmio_mmc_host_runtime_suspend, - .runtime_resume = tmio_mmc_host_runtime_resume, -}; - -static struct platform_driver sh_mobile_sdhi_driver = { - .driver = { - .name = "sh_mobile_sdhi", - .owner = THIS_MODULE, - .pm = &tmio_mmc_dev_pm_ops, - }, - .probe = sh_mobile_sdhi_probe, - .remove = __devexit_p(sh_mobile_sdhi_remove), -}; - -module_platform_driver(sh_mobile_sdhi_driver); - -MODULE_DESCRIPTION("SuperH Mobile SDHI driver"); -MODULE_AUTHOR("Magnus Damm"); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:sh_mobile_sdhi"); diff --git a/ANDROID_3.4.5/drivers/mmc/host/tifm_sd.c b/ANDROID_3.4.5/drivers/mmc/host/tifm_sd.c deleted file mode 100644 index 43d96282..00000000 --- a/ANDROID_3.4.5/drivers/mmc/host/tifm_sd.c +++ /dev/null @@ -1,1093 +0,0 @@ -/* - * tifm_sd.c - TI FlashMedia driver - * - * Copyright (C) 2006 Alex Dubov <oakad@yahoo.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Special thanks to Brad Campbell for extensive testing of this driver. - * - */ - - -#include <linux/tifm.h> -#include <linux/mmc/host.h> -#include <linux/highmem.h> -#include <linux/scatterlist.h> -#include <linux/module.h> -#include <asm/io.h> - -#define DRIVER_NAME "tifm_sd" -#define DRIVER_VERSION "0.8" - -static bool no_dma = 0; -static bool fixed_timeout = 0; -module_param(no_dma, bool, 0644); -module_param(fixed_timeout, bool, 0644); - -/* Constants here are mostly from OMAP5912 datasheet */ -#define TIFM_MMCSD_RESET 0x0002 -#define TIFM_MMCSD_CLKMASK 0x03ff -#define TIFM_MMCSD_POWER 0x0800 -#define TIFM_MMCSD_4BBUS 0x8000 -#define TIFM_MMCSD_RXDE 0x8000 /* rx dma enable */ -#define TIFM_MMCSD_TXDE 0x0080 /* tx dma enable */ -#define TIFM_MMCSD_BUFINT 0x0c00 /* set bits: AE, AF */ -#define TIFM_MMCSD_DPE 0x0020 /* data timeout counted in kilocycles */ -#define TIFM_MMCSD_INAB 0x0080 /* abort / initialize command */ -#define TIFM_MMCSD_READ 0x8000 - -#define TIFM_MMCSD_ERRMASK 0x01e0 /* set bits: CCRC, CTO, DCRC, DTO */ -#define TIFM_MMCSD_EOC 0x0001 /* end of command phase */ -#define TIFM_MMCSD_CD 0x0002 /* card detect */ -#define TIFM_MMCSD_CB 0x0004 /* card enter busy state */ -#define TIFM_MMCSD_BRS 0x0008 /* block received/sent */ -#define TIFM_MMCSD_EOFB 0x0010 /* card exit busy state */ -#define TIFM_MMCSD_DTO 0x0020 /* data time-out */ -#define TIFM_MMCSD_DCRC 0x0040 /* data crc error */ -#define TIFM_MMCSD_CTO 0x0080 /* command time-out */ -#define TIFM_MMCSD_CCRC 0x0100 /* command crc error */ -#define TIFM_MMCSD_AF 0x0400 /* fifo almost full */ -#define TIFM_MMCSD_AE 0x0800 /* fifo almost empty */ -#define TIFM_MMCSD_OCRB 0x1000 /* OCR busy */ -#define TIFM_MMCSD_CIRQ 0x2000 /* card irq (cmd40/sdio) */ -#define TIFM_MMCSD_CERR 0x4000 /* card status error */ - -#define TIFM_MMCSD_ODTO 0x0040 /* open drain / extended timeout */ -#define TIFM_MMCSD_CARD_RO 0x0200 /* card is read-only */ - -#define TIFM_MMCSD_FIFO_SIZE 0x0020 - -#define TIFM_MMCSD_RSP_R0 0x0000 -#define TIFM_MMCSD_RSP_R1 0x0100 -#define TIFM_MMCSD_RSP_R2 0x0200 -#define TIFM_MMCSD_RSP_R3 0x0300 -#define TIFM_MMCSD_RSP_R4 0x0400 -#define TIFM_MMCSD_RSP_R5 0x0500 -#define TIFM_MMCSD_RSP_R6 0x0600 - -#define TIFM_MMCSD_RSP_BUSY 0x0800 - -#define TIFM_MMCSD_CMD_BC 0x0000 -#define TIFM_MMCSD_CMD_BCR 0x1000 -#define TIFM_MMCSD_CMD_AC 0x2000 -#define TIFM_MMCSD_CMD_ADTC 0x3000 - -#define TIFM_MMCSD_MAX_BLOCK_SIZE 0x0800UL - -enum { - CMD_READY = 0x0001, - FIFO_READY = 0x0002, - BRS_READY = 0x0004, - SCMD_ACTIVE = 0x0008, - SCMD_READY = 0x0010, - CARD_BUSY = 0x0020, - DATA_CARRY = 0x0040 -}; - -struct tifm_sd { - struct tifm_dev *dev; - - unsigned short eject:1, - open_drain:1, - no_dma:1; - unsigned short cmd_flags; - - unsigned int clk_freq; - unsigned int clk_div; - unsigned long timeout_jiffies; - - struct tasklet_struct finish_tasklet; - struct timer_list timer; - struct mmc_request *req; - - int sg_len; - int sg_pos; - unsigned int block_pos; - struct scatterlist bounce_buf; - unsigned char bounce_buf_data[TIFM_MMCSD_MAX_BLOCK_SIZE]; -}; - -/* for some reason, host won't respond correctly to readw/writew */ -static void tifm_sd_read_fifo(struct tifm_sd *host, struct page *pg, - unsigned int off, unsigned int cnt) -{ - struct tifm_dev *sock = host->dev; - unsigned char *buf; - unsigned int pos = 0, val; - - buf = kmap_atomic(pg) + off; - if (host->cmd_flags & DATA_CARRY) { - buf[pos++] = host->bounce_buf_data[0]; - host->cmd_flags &= ~DATA_CARRY; - } - - while (pos < cnt) { - val = readl(sock->addr + SOCK_MMCSD_DATA); - buf[pos++] = val & 0xff; - if (pos == cnt) { - host->bounce_buf_data[0] = (val >> 8) & 0xff; - host->cmd_flags |= DATA_CARRY; - break; - } - buf[pos++] = (val >> 8) & 0xff; - } - kunmap_atomic(buf - off); -} - -static void tifm_sd_write_fifo(struct tifm_sd *host, struct page *pg, - unsigned int off, unsigned int cnt) -{ - struct tifm_dev *sock = host->dev; - unsigned char *buf; - unsigned int pos = 0, val; - - buf = kmap_atomic(pg) + off; - if (host->cmd_flags & DATA_CARRY) { - val = host->bounce_buf_data[0] | ((buf[pos++] << 8) & 0xff00); - writel(val, sock->addr + SOCK_MMCSD_DATA); - host->cmd_flags &= ~DATA_CARRY; - } - - while (pos < cnt) { - val = buf[pos++]; - if (pos == cnt) { - host->bounce_buf_data[0] = val & 0xff; - host->cmd_flags |= DATA_CARRY; - break; - } - val |= (buf[pos++] << 8) & 0xff00; - writel(val, sock->addr + SOCK_MMCSD_DATA); - } - kunmap_atomic(buf - off); -} - -static void tifm_sd_transfer_data(struct tifm_sd *host) -{ - struct mmc_data *r_data = host->req->cmd->data; - struct scatterlist *sg = r_data->sg; - unsigned int off, cnt, t_size = TIFM_MMCSD_FIFO_SIZE * 2; - unsigned int p_off, p_cnt; - struct page *pg; - - if (host->sg_pos == host->sg_len) - return; - while (t_size) { - cnt = sg[host->sg_pos].length - host->block_pos; - if (!cnt) { - host->block_pos = 0; - host->sg_pos++; - if (host->sg_pos == host->sg_len) { - if ((r_data->flags & MMC_DATA_WRITE) - && (host->cmd_flags & DATA_CARRY)) - writel(host->bounce_buf_data[0], - host->dev->addr - + SOCK_MMCSD_DATA); - - return; - } - cnt = sg[host->sg_pos].length; - } - off = sg[host->sg_pos].offset + host->block_pos; - - pg = nth_page(sg_page(&sg[host->sg_pos]), off >> PAGE_SHIFT); - p_off = offset_in_page(off); - p_cnt = PAGE_SIZE - p_off; - p_cnt = min(p_cnt, cnt); - p_cnt = min(p_cnt, t_size); - - if (r_data->flags & MMC_DATA_READ) - tifm_sd_read_fifo(host, pg, p_off, p_cnt); - else if (r_data->flags & MMC_DATA_WRITE) - tifm_sd_write_fifo(host, pg, p_off, p_cnt); - - t_size -= p_cnt; - host->block_pos += p_cnt; - } -} - -static void tifm_sd_copy_page(struct page *dst, unsigned int dst_off, - struct page *src, unsigned int src_off, - unsigned int count) -{ - unsigned char *src_buf = kmap_atomic(src) + src_off; - unsigned char *dst_buf = kmap_atomic(dst) + dst_off; - - memcpy(dst_buf, src_buf, count); - - kunmap_atomic(dst_buf - dst_off); - kunmap_atomic(src_buf - src_off); -} - -static void tifm_sd_bounce_block(struct tifm_sd *host, struct mmc_data *r_data) -{ - struct scatterlist *sg = r_data->sg; - unsigned int t_size = r_data->blksz; - unsigned int off, cnt; - unsigned int p_off, p_cnt; - struct page *pg; - - dev_dbg(&host->dev->dev, "bouncing block\n"); - while (t_size) { - cnt = sg[host->sg_pos].length - host->block_pos; - if (!cnt) { - host->block_pos = 0; - host->sg_pos++; - if (host->sg_pos == host->sg_len) - return; - cnt = sg[host->sg_pos].length; - } - off = sg[host->sg_pos].offset + host->block_pos; - - pg = nth_page(sg_page(&sg[host->sg_pos]), off >> PAGE_SHIFT); - p_off = offset_in_page(off); - p_cnt = PAGE_SIZE - p_off; - p_cnt = min(p_cnt, cnt); - p_cnt = min(p_cnt, t_size); - - if (r_data->flags & MMC_DATA_WRITE) - tifm_sd_copy_page(sg_page(&host->bounce_buf), - r_data->blksz - t_size, - pg, p_off, p_cnt); - else if (r_data->flags & MMC_DATA_READ) - tifm_sd_copy_page(pg, p_off, sg_page(&host->bounce_buf), - r_data->blksz - t_size, p_cnt); - - t_size -= p_cnt; - host->block_pos += p_cnt; - } -} - -static int tifm_sd_set_dma_data(struct tifm_sd *host, struct mmc_data *r_data) -{ - struct tifm_dev *sock = host->dev; - unsigned int t_size = TIFM_DMA_TSIZE * r_data->blksz; - unsigned int dma_len, dma_blk_cnt, dma_off; - struct scatterlist *sg = NULL; - unsigned long flags; - - if (host->sg_pos == host->sg_len) - return 1; - - if (host->cmd_flags & DATA_CARRY) { - host->cmd_flags &= ~DATA_CARRY; - local_irq_save(flags); - tifm_sd_bounce_block(host, r_data); - local_irq_restore(flags); - if (host->sg_pos == host->sg_len) - return 1; - } - - dma_len = sg_dma_len(&r_data->sg[host->sg_pos]) - host->block_pos; - if (!dma_len) { - host->block_pos = 0; - host->sg_pos++; - if (host->sg_pos == host->sg_len) - return 1; - dma_len = sg_dma_len(&r_data->sg[host->sg_pos]); - } - - if (dma_len < t_size) { - dma_blk_cnt = dma_len / r_data->blksz; - dma_off = host->block_pos; - host->block_pos += dma_blk_cnt * r_data->blksz; - } else { - dma_blk_cnt = TIFM_DMA_TSIZE; - dma_off = host->block_pos; - host->block_pos += t_size; - } - - if (dma_blk_cnt) - sg = &r_data->sg[host->sg_pos]; - else if (dma_len) { - if (r_data->flags & MMC_DATA_WRITE) { - local_irq_save(flags); - tifm_sd_bounce_block(host, r_data); - local_irq_restore(flags); - } else - host->cmd_flags |= DATA_CARRY; - - sg = &host->bounce_buf; - dma_off = 0; - dma_blk_cnt = 1; - } else - return 1; - - dev_dbg(&sock->dev, "setting dma for %d blocks\n", dma_blk_cnt); - writel(sg_dma_address(sg) + dma_off, sock->addr + SOCK_DMA_ADDRESS); - if (r_data->flags & MMC_DATA_WRITE) - writel((dma_blk_cnt << 8) | TIFM_DMA_TX | TIFM_DMA_EN, - sock->addr + SOCK_DMA_CONTROL); - else - writel((dma_blk_cnt << 8) | TIFM_DMA_EN, - sock->addr + SOCK_DMA_CONTROL); - - return 0; -} - -static unsigned int tifm_sd_op_flags(struct mmc_command *cmd) -{ - unsigned int rc = 0; - - switch (mmc_resp_type(cmd)) { - case MMC_RSP_NONE: - rc |= TIFM_MMCSD_RSP_R0; - break; - case MMC_RSP_R1B: - rc |= TIFM_MMCSD_RSP_BUSY; // deliberate fall-through - case MMC_RSP_R1: - rc |= TIFM_MMCSD_RSP_R1; - break; - case MMC_RSP_R2: - rc |= TIFM_MMCSD_RSP_R2; - break; - case MMC_RSP_R3: - rc |= TIFM_MMCSD_RSP_R3; - break; - default: - BUG(); - } - - switch (mmc_cmd_type(cmd)) { - case MMC_CMD_BC: - rc |= TIFM_MMCSD_CMD_BC; - break; - case MMC_CMD_BCR: - rc |= TIFM_MMCSD_CMD_BCR; - break; - case MMC_CMD_AC: - rc |= TIFM_MMCSD_CMD_AC; - break; - case MMC_CMD_ADTC: - rc |= TIFM_MMCSD_CMD_ADTC; - break; - default: - BUG(); - } - return rc; -} - -static void tifm_sd_exec(struct tifm_sd *host, struct mmc_command *cmd) -{ - struct tifm_dev *sock = host->dev; - unsigned int cmd_mask = tifm_sd_op_flags(cmd); - - if (host->open_drain) - cmd_mask |= TIFM_MMCSD_ODTO; - - if (cmd->data && (cmd->data->flags & MMC_DATA_READ)) - cmd_mask |= TIFM_MMCSD_READ; - - dev_dbg(&sock->dev, "executing opcode 0x%x, arg: 0x%x, mask: 0x%x\n", - cmd->opcode, cmd->arg, cmd_mask); - - writel((cmd->arg >> 16) & 0xffff, sock->addr + SOCK_MMCSD_ARG_HIGH); - writel(cmd->arg & 0xffff, sock->addr + SOCK_MMCSD_ARG_LOW); - writel(cmd->opcode | cmd_mask, sock->addr + SOCK_MMCSD_COMMAND); -} - -static void tifm_sd_fetch_resp(struct mmc_command *cmd, struct tifm_dev *sock) -{ - cmd->resp[0] = (readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x1c) << 16) - | readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x18); - cmd->resp[1] = (readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x14) << 16) - | readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x10); - cmd->resp[2] = (readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x0c) << 16) - | readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x08); - cmd->resp[3] = (readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x04) << 16) - | readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x00); -} - -static void tifm_sd_check_status(struct tifm_sd *host) -{ - struct tifm_dev *sock = host->dev; - struct mmc_command *cmd = host->req->cmd; - - if (cmd->error) - goto finish_request; - - if (!(host->cmd_flags & CMD_READY)) - return; - - if (cmd->data) { - if (cmd->data->error) { - if ((host->cmd_flags & SCMD_ACTIVE) - && !(host->cmd_flags & SCMD_READY)) - return; - - goto finish_request; - } - - if (!(host->cmd_flags & BRS_READY)) - return; - - if (!(host->no_dma || (host->cmd_flags & FIFO_READY))) - return; - - if (cmd->data->flags & MMC_DATA_WRITE) { - if (host->req->stop) { - if (!(host->cmd_flags & SCMD_ACTIVE)) { - host->cmd_flags |= SCMD_ACTIVE; - writel(TIFM_MMCSD_EOFB - | readl(sock->addr - + SOCK_MMCSD_INT_ENABLE), - sock->addr - + SOCK_MMCSD_INT_ENABLE); - tifm_sd_exec(host, host->req->stop); - return; - } else { - if (!(host->cmd_flags & SCMD_READY) - || (host->cmd_flags & CARD_BUSY)) - return; - writel((~TIFM_MMCSD_EOFB) - & readl(sock->addr - + SOCK_MMCSD_INT_ENABLE), - sock->addr - + SOCK_MMCSD_INT_ENABLE); - } - } else { - if (host->cmd_flags & CARD_BUSY) - return; - writel((~TIFM_MMCSD_EOFB) - & readl(sock->addr - + SOCK_MMCSD_INT_ENABLE), - sock->addr + SOCK_MMCSD_INT_ENABLE); - } - } else { - if (host->req->stop) { - if (!(host->cmd_flags & SCMD_ACTIVE)) { - host->cmd_flags |= SCMD_ACTIVE; - tifm_sd_exec(host, host->req->stop); - return; - } else { - if (!(host->cmd_flags & SCMD_READY)) - return; - } - } - } - } -finish_request: - tasklet_schedule(&host->finish_tasklet); -} - -/* Called from interrupt handler */ -static void tifm_sd_data_event(struct tifm_dev *sock) -{ - struct tifm_sd *host; - unsigned int fifo_status = 0; - struct mmc_data *r_data = NULL; - - spin_lock(&sock->lock); - host = mmc_priv((struct mmc_host*)tifm_get_drvdata(sock)); - fifo_status = readl(sock->addr + SOCK_DMA_FIFO_STATUS); - dev_dbg(&sock->dev, "data event: fifo_status %x, flags %x\n", - fifo_status, host->cmd_flags); - - if (host->req) { - r_data = host->req->cmd->data; - - if (r_data && (fifo_status & TIFM_FIFO_READY)) { - if (tifm_sd_set_dma_data(host, r_data)) { - host->cmd_flags |= FIFO_READY; - tifm_sd_check_status(host); - } - } - } - - writel(fifo_status, sock->addr + SOCK_DMA_FIFO_STATUS); - spin_unlock(&sock->lock); -} - -/* Called from interrupt handler */ -static void tifm_sd_card_event(struct tifm_dev *sock) -{ - struct tifm_sd *host; - unsigned int host_status = 0; - int cmd_error = 0; - struct mmc_command *cmd = NULL; - unsigned long flags; - - spin_lock(&sock->lock); - host = mmc_priv((struct mmc_host*)tifm_get_drvdata(sock)); - host_status = readl(sock->addr + SOCK_MMCSD_STATUS); - dev_dbg(&sock->dev, "host event: host_status %x, flags %x\n", - host_status, host->cmd_flags); - - if (host->req) { - cmd = host->req->cmd; - - if (host_status & TIFM_MMCSD_ERRMASK) { - writel(host_status & TIFM_MMCSD_ERRMASK, - sock->addr + SOCK_MMCSD_STATUS); - if (host_status & TIFM_MMCSD_CTO) - cmd_error = -ETIMEDOUT; - else if (host_status & TIFM_MMCSD_CCRC) - cmd_error = -EILSEQ; - - if (cmd->data) { - if (host_status & TIFM_MMCSD_DTO) - cmd->data->error = -ETIMEDOUT; - else if (host_status & TIFM_MMCSD_DCRC) - cmd->data->error = -EILSEQ; - } - - writel(TIFM_FIFO_INT_SETALL, - sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR); - writel(TIFM_DMA_RESET, sock->addr + SOCK_DMA_CONTROL); - - if (host->req->stop) { - if (host->cmd_flags & SCMD_ACTIVE) { - host->req->stop->error = cmd_error; - host->cmd_flags |= SCMD_READY; - } else { - cmd->error = cmd_error; - host->cmd_flags |= SCMD_ACTIVE; - tifm_sd_exec(host, host->req->stop); - goto done; - } - } else - cmd->error = cmd_error; - } else { - if (host_status & (TIFM_MMCSD_EOC | TIFM_MMCSD_CERR)) { - if (!(host->cmd_flags & CMD_READY)) { - host->cmd_flags |= CMD_READY; - tifm_sd_fetch_resp(cmd, sock); - } else if (host->cmd_flags & SCMD_ACTIVE) { - host->cmd_flags |= SCMD_READY; - tifm_sd_fetch_resp(host->req->stop, - sock); - } - } - if (host_status & TIFM_MMCSD_BRS) - host->cmd_flags |= BRS_READY; - } - - if (host->no_dma && cmd->data) { - if (host_status & TIFM_MMCSD_AE) - writel(host_status & TIFM_MMCSD_AE, - sock->addr + SOCK_MMCSD_STATUS); - - if (host_status & (TIFM_MMCSD_AE | TIFM_MMCSD_AF - | TIFM_MMCSD_BRS)) { - local_irq_save(flags); - tifm_sd_transfer_data(host); - local_irq_restore(flags); - host_status &= ~TIFM_MMCSD_AE; - } - } - - if (host_status & TIFM_MMCSD_EOFB) - host->cmd_flags &= ~CARD_BUSY; - else if (host_status & TIFM_MMCSD_CB) - host->cmd_flags |= CARD_BUSY; - - tifm_sd_check_status(host); - } -done: - writel(host_status, sock->addr + SOCK_MMCSD_STATUS); - spin_unlock(&sock->lock); -} - -static void tifm_sd_set_data_timeout(struct tifm_sd *host, - struct mmc_data *data) -{ - struct tifm_dev *sock = host->dev; - unsigned int data_timeout = data->timeout_clks; - - if (fixed_timeout) - return; - - data_timeout += data->timeout_ns / - ((1000000000UL / host->clk_freq) * host->clk_div); - - if (data_timeout < 0xffff) { - writel(data_timeout, sock->addr + SOCK_MMCSD_DATA_TO); - writel((~TIFM_MMCSD_DPE) - & readl(sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG), - sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG); - } else { - data_timeout = (data_timeout >> 10) + 1; - if (data_timeout > 0xffff) - data_timeout = 0; /* set to unlimited */ - writel(data_timeout, sock->addr + SOCK_MMCSD_DATA_TO); - writel(TIFM_MMCSD_DPE - | readl(sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG), - sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG); - } -} - -static void tifm_sd_request(struct mmc_host *mmc, struct mmc_request *mrq) -{ - struct tifm_sd *host = mmc_priv(mmc); - struct tifm_dev *sock = host->dev; - unsigned long flags; - struct mmc_data *r_data = mrq->cmd->data; - - spin_lock_irqsave(&sock->lock, flags); - if (host->eject) { - mrq->cmd->error = -ENOMEDIUM; - goto err_out; - } - - if (host->req) { - pr_err("%s : unfinished request detected\n", - dev_name(&sock->dev)); - mrq->cmd->error = -ETIMEDOUT; - goto err_out; - } - - host->cmd_flags = 0; - host->block_pos = 0; - host->sg_pos = 0; - - if (mrq->data && !is_power_of_2(mrq->data->blksz)) - host->no_dma = 1; - else - host->no_dma = no_dma ? 1 : 0; - - if (r_data) { - tifm_sd_set_data_timeout(host, r_data); - - if ((r_data->flags & MMC_DATA_WRITE) && !mrq->stop) - writel(TIFM_MMCSD_EOFB - | readl(sock->addr + SOCK_MMCSD_INT_ENABLE), - sock->addr + SOCK_MMCSD_INT_ENABLE); - - if (host->no_dma) { - writel(TIFM_MMCSD_BUFINT - | readl(sock->addr + SOCK_MMCSD_INT_ENABLE), - sock->addr + SOCK_MMCSD_INT_ENABLE); - writel(((TIFM_MMCSD_FIFO_SIZE - 1) << 8) - | (TIFM_MMCSD_FIFO_SIZE - 1), - sock->addr + SOCK_MMCSD_BUFFER_CONFIG); - - host->sg_len = r_data->sg_len; - } else { - sg_init_one(&host->bounce_buf, host->bounce_buf_data, - r_data->blksz); - - if(1 != tifm_map_sg(sock, &host->bounce_buf, 1, - r_data->flags & MMC_DATA_WRITE - ? PCI_DMA_TODEVICE - : PCI_DMA_FROMDEVICE)) { - pr_err("%s : scatterlist map failed\n", - dev_name(&sock->dev)); - mrq->cmd->error = -ENOMEM; - goto err_out; - } - host->sg_len = tifm_map_sg(sock, r_data->sg, - r_data->sg_len, - r_data->flags - & MMC_DATA_WRITE - ? PCI_DMA_TODEVICE - : PCI_DMA_FROMDEVICE); - if (host->sg_len < 1) { - pr_err("%s : scatterlist map failed\n", - dev_name(&sock->dev)); - tifm_unmap_sg(sock, &host->bounce_buf, 1, - r_data->flags & MMC_DATA_WRITE - ? PCI_DMA_TODEVICE - : PCI_DMA_FROMDEVICE); - mrq->cmd->error = -ENOMEM; - goto err_out; - } - - writel(TIFM_FIFO_INT_SETALL, - sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR); - writel(ilog2(r_data->blksz) - 2, - sock->addr + SOCK_FIFO_PAGE_SIZE); - writel(TIFM_FIFO_ENABLE, - sock->addr + SOCK_FIFO_CONTROL); - writel(TIFM_FIFO_INTMASK, - sock->addr + SOCK_DMA_FIFO_INT_ENABLE_SET); - - if (r_data->flags & MMC_DATA_WRITE) - writel(TIFM_MMCSD_TXDE, - sock->addr + SOCK_MMCSD_BUFFER_CONFIG); - else - writel(TIFM_MMCSD_RXDE, - sock->addr + SOCK_MMCSD_BUFFER_CONFIG); - - tifm_sd_set_dma_data(host, r_data); - } - - writel(r_data->blocks - 1, - sock->addr + SOCK_MMCSD_NUM_BLOCKS); - writel(r_data->blksz - 1, - sock->addr + SOCK_MMCSD_BLOCK_LEN); - } - - host->req = mrq; - mod_timer(&host->timer, jiffies + host->timeout_jiffies); - writel(TIFM_CTRL_LED | readl(sock->addr + SOCK_CONTROL), - sock->addr + SOCK_CONTROL); - tifm_sd_exec(host, mrq->cmd); - spin_unlock_irqrestore(&sock->lock, flags); - return; - -err_out: - spin_unlock_irqrestore(&sock->lock, flags); - mmc_request_done(mmc, mrq); -} - -static void tifm_sd_end_cmd(unsigned long data) -{ - struct tifm_sd *host = (struct tifm_sd*)data; - struct tifm_dev *sock = host->dev; - struct mmc_host *mmc = tifm_get_drvdata(sock); - struct mmc_request *mrq; - struct mmc_data *r_data = NULL; - unsigned long flags; - - spin_lock_irqsave(&sock->lock, flags); - - del_timer(&host->timer); - mrq = host->req; - host->req = NULL; - - if (!mrq) { - pr_err(" %s : no request to complete?\n", - dev_name(&sock->dev)); - spin_unlock_irqrestore(&sock->lock, flags); - return; - } - - r_data = mrq->cmd->data; - if (r_data) { - if (host->no_dma) { - writel((~TIFM_MMCSD_BUFINT) - & readl(sock->addr + SOCK_MMCSD_INT_ENABLE), - sock->addr + SOCK_MMCSD_INT_ENABLE); - } else { - tifm_unmap_sg(sock, &host->bounce_buf, 1, - (r_data->flags & MMC_DATA_WRITE) - ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE); - tifm_unmap_sg(sock, r_data->sg, r_data->sg_len, - (r_data->flags & MMC_DATA_WRITE) - ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE); - } - - r_data->bytes_xfered = r_data->blocks - - readl(sock->addr + SOCK_MMCSD_NUM_BLOCKS) - 1; - r_data->bytes_xfered *= r_data->blksz; - r_data->bytes_xfered += r_data->blksz - - readl(sock->addr + SOCK_MMCSD_BLOCK_LEN) + 1; - } - - writel((~TIFM_CTRL_LED) & readl(sock->addr + SOCK_CONTROL), - sock->addr + SOCK_CONTROL); - - spin_unlock_irqrestore(&sock->lock, flags); - mmc_request_done(mmc, mrq); -} - -static void tifm_sd_abort(unsigned long data) -{ - struct tifm_sd *host = (struct tifm_sd*)data; - - pr_err("%s : card failed to respond for a long period of time " - "(%x, %x)\n", - dev_name(&host->dev->dev), host->req->cmd->opcode, host->cmd_flags); - - tifm_eject(host->dev); -} - -static void tifm_sd_ios(struct mmc_host *mmc, struct mmc_ios *ios) -{ - struct tifm_sd *host = mmc_priv(mmc); - struct tifm_dev *sock = host->dev; - unsigned int clk_div1, clk_div2; - unsigned long flags; - - spin_lock_irqsave(&sock->lock, flags); - - dev_dbg(&sock->dev, "ios: clock = %u, vdd = %x, bus_mode = %x, " - "chip_select = %x, power_mode = %x, bus_width = %x\n", - ios->clock, ios->vdd, ios->bus_mode, ios->chip_select, - ios->power_mode, ios->bus_width); - - if (ios->bus_width == MMC_BUS_WIDTH_4) { - writel(TIFM_MMCSD_4BBUS | readl(sock->addr + SOCK_MMCSD_CONFIG), - sock->addr + SOCK_MMCSD_CONFIG); - } else { - writel((~TIFM_MMCSD_4BBUS) - & readl(sock->addr + SOCK_MMCSD_CONFIG), - sock->addr + SOCK_MMCSD_CONFIG); - } - - if (ios->clock) { - clk_div1 = 20000000 / ios->clock; - if (!clk_div1) - clk_div1 = 1; - - clk_div2 = 24000000 / ios->clock; - if (!clk_div2) - clk_div2 = 1; - - if ((20000000 / clk_div1) > ios->clock) - clk_div1++; - if ((24000000 / clk_div2) > ios->clock) - clk_div2++; - if ((20000000 / clk_div1) > (24000000 / clk_div2)) { - host->clk_freq = 20000000; - host->clk_div = clk_div1; - writel((~TIFM_CTRL_FAST_CLK) - & readl(sock->addr + SOCK_CONTROL), - sock->addr + SOCK_CONTROL); - } else { - host->clk_freq = 24000000; - host->clk_div = clk_div2; - writel(TIFM_CTRL_FAST_CLK - | readl(sock->addr + SOCK_CONTROL), - sock->addr + SOCK_CONTROL); - } - } else { - host->clk_div = 0; - } - host->clk_div &= TIFM_MMCSD_CLKMASK; - writel(host->clk_div - | ((~TIFM_MMCSD_CLKMASK) - & readl(sock->addr + SOCK_MMCSD_CONFIG)), - sock->addr + SOCK_MMCSD_CONFIG); - - host->open_drain = (ios->bus_mode == MMC_BUSMODE_OPENDRAIN); - - /* chip_select : maybe later */ - //vdd - //power is set before probe / after remove - - spin_unlock_irqrestore(&sock->lock, flags); -} - -static int tifm_sd_ro(struct mmc_host *mmc) -{ - int rc = 0; - struct tifm_sd *host = mmc_priv(mmc); - struct tifm_dev *sock = host->dev; - unsigned long flags; - - spin_lock_irqsave(&sock->lock, flags); - if (TIFM_MMCSD_CARD_RO & readl(sock->addr + SOCK_PRESENT_STATE)) - rc = 1; - spin_unlock_irqrestore(&sock->lock, flags); - return rc; -} - -static const struct mmc_host_ops tifm_sd_ops = { - .request = tifm_sd_request, - .set_ios = tifm_sd_ios, - .get_ro = tifm_sd_ro -}; - -static int tifm_sd_initialize_host(struct tifm_sd *host) -{ - int rc; - unsigned int host_status = 0; - struct tifm_dev *sock = host->dev; - - writel(0, sock->addr + SOCK_MMCSD_INT_ENABLE); - mmiowb(); - host->clk_div = 61; - host->clk_freq = 20000000; - writel(TIFM_MMCSD_RESET, sock->addr + SOCK_MMCSD_SYSTEM_CONTROL); - writel(host->clk_div | TIFM_MMCSD_POWER, - sock->addr + SOCK_MMCSD_CONFIG); - - /* wait up to 0.51 sec for reset */ - for (rc = 32; rc <= 256; rc <<= 1) { - if (1 & readl(sock->addr + SOCK_MMCSD_SYSTEM_STATUS)) { - rc = 0; - break; - } - msleep(rc); - } - - if (rc) { - pr_err("%s : controller failed to reset\n", - dev_name(&sock->dev)); - return -ENODEV; - } - - writel(0, sock->addr + SOCK_MMCSD_NUM_BLOCKS); - writel(host->clk_div | TIFM_MMCSD_POWER, - sock->addr + SOCK_MMCSD_CONFIG); - writel(TIFM_MMCSD_RXDE, sock->addr + SOCK_MMCSD_BUFFER_CONFIG); - - // command timeout fixed to 64 clocks for now - writel(64, sock->addr + SOCK_MMCSD_COMMAND_TO); - writel(TIFM_MMCSD_INAB, sock->addr + SOCK_MMCSD_COMMAND); - - for (rc = 16; rc <= 64; rc <<= 1) { - host_status = readl(sock->addr + SOCK_MMCSD_STATUS); - writel(host_status, sock->addr + SOCK_MMCSD_STATUS); - if (!(host_status & TIFM_MMCSD_ERRMASK) - && (host_status & TIFM_MMCSD_EOC)) { - rc = 0; - break; - } - msleep(rc); - } - - if (rc) { - pr_err("%s : card not ready - probe failed on initialization\n", - dev_name(&sock->dev)); - return -ENODEV; - } - - writel(TIFM_MMCSD_CERR | TIFM_MMCSD_BRS | TIFM_MMCSD_EOC - | TIFM_MMCSD_ERRMASK, - sock->addr + SOCK_MMCSD_INT_ENABLE); - mmiowb(); - - return 0; -} - -static int tifm_sd_probe(struct tifm_dev *sock) -{ - struct mmc_host *mmc; - struct tifm_sd *host; - int rc = -EIO; - - if (!(TIFM_SOCK_STATE_OCCUPIED - & readl(sock->addr + SOCK_PRESENT_STATE))) { - pr_warning("%s : card gone, unexpectedly\n", - dev_name(&sock->dev)); - return rc; - } - - mmc = mmc_alloc_host(sizeof(struct tifm_sd), &sock->dev); - if (!mmc) - return -ENOMEM; - - host = mmc_priv(mmc); - tifm_set_drvdata(sock, mmc); - host->dev = sock; - host->timeout_jiffies = msecs_to_jiffies(1000); - - tasklet_init(&host->finish_tasklet, tifm_sd_end_cmd, - (unsigned long)host); - setup_timer(&host->timer, tifm_sd_abort, (unsigned long)host); - - mmc->ops = &tifm_sd_ops; - mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; - mmc->caps = MMC_CAP_4_BIT_DATA; - mmc->f_min = 20000000 / 60; - mmc->f_max = 24000000; - - mmc->max_blk_count = 2048; - mmc->max_segs = mmc->max_blk_count; - mmc->max_blk_size = min(TIFM_MMCSD_MAX_BLOCK_SIZE, PAGE_SIZE); - mmc->max_seg_size = mmc->max_blk_count * mmc->max_blk_size; - mmc->max_req_size = mmc->max_seg_size; - - sock->card_event = tifm_sd_card_event; - sock->data_event = tifm_sd_data_event; - rc = tifm_sd_initialize_host(host); - - if (!rc) - rc = mmc_add_host(mmc); - if (!rc) - return 0; - - mmc_free_host(mmc); - return rc; -} - -static void tifm_sd_remove(struct tifm_dev *sock) -{ - struct mmc_host *mmc = tifm_get_drvdata(sock); - struct tifm_sd *host = mmc_priv(mmc); - unsigned long flags; - - spin_lock_irqsave(&sock->lock, flags); - host->eject = 1; - writel(0, sock->addr + SOCK_MMCSD_INT_ENABLE); - mmiowb(); - spin_unlock_irqrestore(&sock->lock, flags); - - tasklet_kill(&host->finish_tasklet); - - spin_lock_irqsave(&sock->lock, flags); - if (host->req) { - writel(TIFM_FIFO_INT_SETALL, - sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR); - writel(0, sock->addr + SOCK_DMA_FIFO_INT_ENABLE_SET); - host->req->cmd->error = -ENOMEDIUM; - if (host->req->stop) - host->req->stop->error = -ENOMEDIUM; - tasklet_schedule(&host->finish_tasklet); - } - spin_unlock_irqrestore(&sock->lock, flags); - mmc_remove_host(mmc); - dev_dbg(&sock->dev, "after remove\n"); - - mmc_free_host(mmc); -} - -#ifdef CONFIG_PM - -static int tifm_sd_suspend(struct tifm_dev *sock, pm_message_t state) -{ - return mmc_suspend_host(tifm_get_drvdata(sock)); -} - -static int tifm_sd_resume(struct tifm_dev *sock) -{ - struct mmc_host *mmc = tifm_get_drvdata(sock); - struct tifm_sd *host = mmc_priv(mmc); - int rc; - - rc = tifm_sd_initialize_host(host); - dev_dbg(&sock->dev, "resume initialize %d\n", rc); - - if (rc) - host->eject = 1; - else - rc = mmc_resume_host(mmc); - - return rc; -} - -#else - -#define tifm_sd_suspend NULL -#define tifm_sd_resume NULL - -#endif /* CONFIG_PM */ - -static struct tifm_device_id tifm_sd_id_tbl[] = { - { TIFM_TYPE_SD }, { } -}; - -static struct tifm_driver tifm_sd_driver = { - .driver = { - .name = DRIVER_NAME, - .owner = THIS_MODULE - }, - .id_table = tifm_sd_id_tbl, - .probe = tifm_sd_probe, - .remove = tifm_sd_remove, - .suspend = tifm_sd_suspend, - .resume = tifm_sd_resume -}; - -static int __init tifm_sd_init(void) -{ - return tifm_register_driver(&tifm_sd_driver); -} - -static void __exit tifm_sd_exit(void) -{ - tifm_unregister_driver(&tifm_sd_driver); -} - -MODULE_AUTHOR("Alex Dubov"); -MODULE_DESCRIPTION("TI FlashMedia SD driver"); -MODULE_LICENSE("GPL"); -MODULE_DEVICE_TABLE(tifm, tifm_sd_id_tbl); -MODULE_VERSION(DRIVER_VERSION); - -module_init(tifm_sd_init); -module_exit(tifm_sd_exit); diff --git a/ANDROID_3.4.5/drivers/mmc/host/tmio_mmc.c b/ANDROID_3.4.5/drivers/mmc/host/tmio_mmc.c deleted file mode 100644 index 113ce6c9..00000000 --- a/ANDROID_3.4.5/drivers/mmc/host/tmio_mmc.c +++ /dev/null @@ -1,146 +0,0 @@ -/* - * linux/drivers/mmc/host/tmio_mmc.c - * - * Copyright (C) 2007 Ian Molton - * Copyright (C) 2004 Ian Molton - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Driver for the MMC / SD / SDIO cell found in: - * - * TC6393XB TC6391XB TC6387XB T7L66XB ASIC3 - */ - -#include <linux/device.h> -#include <linux/mfd/core.h> -#include <linux/mfd/tmio.h> -#include <linux/mmc/host.h> -#include <linux/module.h> -#include <linux/pagemap.h> -#include <linux/scatterlist.h> - -#include "tmio_mmc.h" - -#ifdef CONFIG_PM -static int tmio_mmc_suspend(struct platform_device *dev, pm_message_t state) -{ - const struct mfd_cell *cell = mfd_get_cell(dev); - int ret; - - ret = tmio_mmc_host_suspend(&dev->dev); - - /* Tell MFD core it can disable us now.*/ - if (!ret && cell->disable) - cell->disable(dev); - - return ret; -} - -static int tmio_mmc_resume(struct platform_device *dev) -{ - const struct mfd_cell *cell = mfd_get_cell(dev); - int ret = 0; - - /* Tell the MFD core we are ready to be enabled */ - if (cell->resume) - ret = cell->resume(dev); - - if (!ret) - ret = tmio_mmc_host_resume(&dev->dev); - - return ret; -} -#else -#define tmio_mmc_suspend NULL -#define tmio_mmc_resume NULL -#endif - -static int __devinit tmio_mmc_probe(struct platform_device *pdev) -{ - const struct mfd_cell *cell = mfd_get_cell(pdev); - struct tmio_mmc_data *pdata; - struct tmio_mmc_host *host; - int ret = -EINVAL, irq; - - if (pdev->num_resources != 2) - goto out; - - pdata = pdev->dev.platform_data; - if (!pdata || !pdata->hclk) - goto out; - - irq = platform_get_irq(pdev, 0); - if (irq < 0) { - ret = irq; - goto out; - } - - /* Tell the MFD core we are ready to be enabled */ - if (cell->enable) { - ret = cell->enable(pdev); - if (ret) - goto out; - } - - ret = tmio_mmc_host_probe(&host, pdev, pdata); - if (ret) - goto cell_disable; - - ret = request_irq(irq, tmio_mmc_irq, IRQF_TRIGGER_FALLING, - dev_name(&pdev->dev), host); - if (ret) - goto host_remove; - - pr_info("%s at 0x%08lx irq %d\n", mmc_hostname(host->mmc), - (unsigned long)host->ctl, irq); - - return 0; - -host_remove: - tmio_mmc_host_remove(host); -cell_disable: - if (cell->disable) - cell->disable(pdev); -out: - return ret; -} - -static int __devexit tmio_mmc_remove(struct platform_device *pdev) -{ - const struct mfd_cell *cell = mfd_get_cell(pdev); - struct mmc_host *mmc = platform_get_drvdata(pdev); - - platform_set_drvdata(pdev, NULL); - - if (mmc) { - struct tmio_mmc_host *host = mmc_priv(mmc); - free_irq(platform_get_irq(pdev, 0), host); - tmio_mmc_host_remove(host); - if (cell->disable) - cell->disable(pdev); - } - - return 0; -} - -/* ------------------- device registration ----------------------- */ - -static struct platform_driver tmio_mmc_driver = { - .driver = { - .name = "tmio-mmc", - .owner = THIS_MODULE, - }, - .probe = tmio_mmc_probe, - .remove = __devexit_p(tmio_mmc_remove), - .suspend = tmio_mmc_suspend, - .resume = tmio_mmc_resume, -}; - -module_platform_driver(tmio_mmc_driver); - -MODULE_DESCRIPTION("Toshiba TMIO SD/MMC driver"); -MODULE_AUTHOR("Ian Molton <spyro@f2s.com>"); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:tmio-mmc"); diff --git a/ANDROID_3.4.5/drivers/mmc/host/tmio_mmc.h b/ANDROID_3.4.5/drivers/mmc/host/tmio_mmc.h deleted file mode 100644 index d857f5c6..00000000 --- a/ANDROID_3.4.5/drivers/mmc/host/tmio_mmc.h +++ /dev/null @@ -1,200 +0,0 @@ -/* - * linux/drivers/mmc/host/tmio_mmc.h - * - * Copyright (C) 2007 Ian Molton - * Copyright (C) 2004 Ian Molton - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Driver for the MMC / SD / SDIO cell found in: - * - * TC6393XB TC6391XB TC6387XB T7L66XB ASIC3 - */ - -#ifndef TMIO_MMC_H -#define TMIO_MMC_H - -#include <linux/highmem.h> -#include <linux/mmc/tmio.h> -#include <linux/mutex.h> -#include <linux/pagemap.h> -#include <linux/scatterlist.h> -#include <linux/spinlock.h> - -/* Definitions for values the CTRL_SDIO_STATUS register can take. */ -#define TMIO_SDIO_STAT_IOIRQ 0x0001 -#define TMIO_SDIO_STAT_EXPUB52 0x4000 -#define TMIO_SDIO_STAT_EXWT 0x8000 -#define TMIO_SDIO_MASK_ALL 0xc007 - -/* Define some IRQ masks */ -/* This is the mask used at reset by the chip */ -#define TMIO_MASK_ALL 0x837f031d -#define TMIO_MASK_READOP (TMIO_STAT_RXRDY | TMIO_STAT_DATAEND) -#define TMIO_MASK_WRITEOP (TMIO_STAT_TXRQ | TMIO_STAT_DATAEND) -#define TMIO_MASK_CMD (TMIO_STAT_CMDRESPEND | TMIO_STAT_CMDTIMEOUT | \ - TMIO_STAT_CARD_REMOVE | TMIO_STAT_CARD_INSERT) -#define TMIO_MASK_IRQ (TMIO_MASK_READOP | TMIO_MASK_WRITEOP | TMIO_MASK_CMD) - -struct tmio_mmc_data; - -struct tmio_mmc_host { - void __iomem *ctl; - unsigned long bus_shift; - struct mmc_command *cmd; - struct mmc_request *mrq; - struct mmc_data *data; - struct mmc_host *mmc; - - /* Controller power state */ - bool power; - - /* Callbacks for clock / power control */ - void (*set_pwr)(struct platform_device *host, int state); - void (*set_clk_div)(struct platform_device *host, int state); - - /* pio related stuff */ - struct scatterlist *sg_ptr; - struct scatterlist *sg_orig; - unsigned int sg_len; - unsigned int sg_off; - - struct platform_device *pdev; - struct tmio_mmc_data *pdata; - - /* DMA support */ - bool force_pio; - struct dma_chan *chan_rx; - struct dma_chan *chan_tx; - struct tasklet_struct dma_complete; - struct tasklet_struct dma_issue; - struct scatterlist bounce_sg; - u8 *bounce_buf; - - /* Track lost interrupts */ - struct delayed_work delayed_reset_work; - struct work_struct done; - - /* Cache IRQ mask */ - u32 sdcard_irq_mask; - u32 sdio_irq_mask; - - spinlock_t lock; /* protect host private data */ - unsigned long last_req_ts; - struct mutex ios_lock; /* protect set_ios() context */ - bool native_hotplug; -}; - -int tmio_mmc_host_probe(struct tmio_mmc_host **host, - struct platform_device *pdev, - struct tmio_mmc_data *pdata); -void tmio_mmc_host_remove(struct tmio_mmc_host *host); -void tmio_mmc_do_data_irq(struct tmio_mmc_host *host); - -void tmio_mmc_enable_mmc_irqs(struct tmio_mmc_host *host, u32 i); -void tmio_mmc_disable_mmc_irqs(struct tmio_mmc_host *host, u32 i); -irqreturn_t tmio_mmc_irq(int irq, void *devid); -irqreturn_t tmio_mmc_sdcard_irq(int irq, void *devid); -irqreturn_t tmio_mmc_card_detect_irq(int irq, void *devid); -irqreturn_t tmio_mmc_sdio_irq(int irq, void *devid); - -static inline char *tmio_mmc_kmap_atomic(struct scatterlist *sg, - unsigned long *flags) -{ - local_irq_save(*flags); - return kmap_atomic(sg_page(sg)) + sg->offset; -} - -static inline void tmio_mmc_kunmap_atomic(struct scatterlist *sg, - unsigned long *flags, void *virt) -{ - kunmap_atomic(virt - sg->offset); - local_irq_restore(*flags); -} - -#if defined(CONFIG_MMC_SDHI) || defined(CONFIG_MMC_SDHI_MODULE) -void tmio_mmc_start_dma(struct tmio_mmc_host *host, struct mmc_data *data); -void tmio_mmc_enable_dma(struct tmio_mmc_host *host, bool enable); -void tmio_mmc_request_dma(struct tmio_mmc_host *host, struct tmio_mmc_data *pdata); -void tmio_mmc_release_dma(struct tmio_mmc_host *host); -void tmio_mmc_abort_dma(struct tmio_mmc_host *host); -#else -static inline void tmio_mmc_start_dma(struct tmio_mmc_host *host, - struct mmc_data *data) -{ -} - -static inline void tmio_mmc_enable_dma(struct tmio_mmc_host *host, bool enable) -{ -} - -static inline void tmio_mmc_request_dma(struct tmio_mmc_host *host, - struct tmio_mmc_data *pdata) -{ - host->chan_tx = NULL; - host->chan_rx = NULL; -} - -static inline void tmio_mmc_release_dma(struct tmio_mmc_host *host) -{ -} - -static inline void tmio_mmc_abort_dma(struct tmio_mmc_host *host) -{ -} -#endif - -#ifdef CONFIG_PM -int tmio_mmc_host_suspend(struct device *dev); -int tmio_mmc_host_resume(struct device *dev); -#else -#define tmio_mmc_host_suspend NULL -#define tmio_mmc_host_resume NULL -#endif - -int tmio_mmc_host_runtime_suspend(struct device *dev); -int tmio_mmc_host_runtime_resume(struct device *dev); - -static inline u16 sd_ctrl_read16(struct tmio_mmc_host *host, int addr) -{ - return readw(host->ctl + (addr << host->bus_shift)); -} - -static inline void sd_ctrl_read16_rep(struct tmio_mmc_host *host, int addr, - u16 *buf, int count) -{ - readsw(host->ctl + (addr << host->bus_shift), buf, count); -} - -static inline u32 sd_ctrl_read32(struct tmio_mmc_host *host, int addr) -{ - return readw(host->ctl + (addr << host->bus_shift)) | - readw(host->ctl + ((addr + 2) << host->bus_shift)) << 16; -} - -static inline void sd_ctrl_write16(struct tmio_mmc_host *host, int addr, u16 val) -{ - /* If there is a hook and it returns non-zero then there - * is an error and the write should be skipped - */ - if (host->pdata->write16_hook && host->pdata->write16_hook(host, addr)) - return; - writew(val, host->ctl + (addr << host->bus_shift)); -} - -static inline void sd_ctrl_write16_rep(struct tmio_mmc_host *host, int addr, - u16 *buf, int count) -{ - writesw(host->ctl + (addr << host->bus_shift), buf, count); -} - -static inline void sd_ctrl_write32(struct tmio_mmc_host *host, int addr, u32 val) -{ - writew(val, host->ctl + (addr << host->bus_shift)); - writew(val >> 16, host->ctl + ((addr + 2) << host->bus_shift)); -} - - -#endif diff --git a/ANDROID_3.4.5/drivers/mmc/host/tmio_mmc_dma.c b/ANDROID_3.4.5/drivers/mmc/host/tmio_mmc_dma.c deleted file mode 100644 index fff92860..00000000 --- a/ANDROID_3.4.5/drivers/mmc/host/tmio_mmc_dma.c +++ /dev/null @@ -1,336 +0,0 @@ -/* - * linux/drivers/mmc/tmio_mmc_dma.c - * - * Copyright (C) 2010-2011 Guennadi Liakhovetski - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * DMA function for TMIO MMC implementations - */ - -#include <linux/device.h> -#include <linux/dma-mapping.h> -#include <linux/dmaengine.h> -#include <linux/mfd/tmio.h> -#include <linux/mmc/host.h> -#include <linux/mmc/tmio.h> -#include <linux/pagemap.h> -#include <linux/scatterlist.h> - -#include "tmio_mmc.h" - -#define TMIO_MMC_MIN_DMA_LEN 8 - -void tmio_mmc_enable_dma(struct tmio_mmc_host *host, bool enable) -{ - if (!host->chan_tx || !host->chan_rx) - return; - -#if defined(CONFIG_SUPERH) || defined(CONFIG_ARCH_SHMOBILE) - /* Switch DMA mode on or off - SuperH specific? */ - sd_ctrl_write16(host, CTL_DMA_ENABLE, enable ? 2 : 0); -#endif -} - -void tmio_mmc_abort_dma(struct tmio_mmc_host *host) -{ - tmio_mmc_enable_dma(host, false); - - if (host->chan_rx) - dmaengine_terminate_all(host->chan_rx); - if (host->chan_tx) - dmaengine_terminate_all(host->chan_tx); - - tmio_mmc_enable_dma(host, true); -} - -static void tmio_mmc_start_dma_rx(struct tmio_mmc_host *host) -{ - struct scatterlist *sg = host->sg_ptr, *sg_tmp; - struct dma_async_tx_descriptor *desc = NULL; - struct dma_chan *chan = host->chan_rx; - struct tmio_mmc_data *pdata = host->pdata; - dma_cookie_t cookie; - int ret, i; - bool aligned = true, multiple = true; - unsigned int align = (1 << pdata->dma->alignment_shift) - 1; - - for_each_sg(sg, sg_tmp, host->sg_len, i) { - if (sg_tmp->offset & align) - aligned = false; - if (sg_tmp->length & align) { - multiple = false; - break; - } - } - - if ((!aligned && (host->sg_len > 1 || sg->length > PAGE_CACHE_SIZE || - (align & PAGE_MASK))) || !multiple) { - ret = -EINVAL; - goto pio; - } - - if (sg->length < TMIO_MMC_MIN_DMA_LEN) { - host->force_pio = true; - return; - } - - tmio_mmc_disable_mmc_irqs(host, TMIO_STAT_RXRDY); - - /* The only sg element can be unaligned, use our bounce buffer then */ - if (!aligned) { - sg_init_one(&host->bounce_sg, host->bounce_buf, sg->length); - host->sg_ptr = &host->bounce_sg; - sg = host->sg_ptr; - } - - ret = dma_map_sg(chan->device->dev, sg, host->sg_len, DMA_FROM_DEVICE); - if (ret > 0) - desc = dmaengine_prep_slave_sg(chan, sg, ret, - DMA_DEV_TO_MEM, DMA_CTRL_ACK); - - if (desc) { - cookie = dmaengine_submit(desc); - if (cookie < 0) { - desc = NULL; - ret = cookie; - } - } - dev_dbg(&host->pdev->dev, "%s(): mapped %d -> %d, cookie %d, rq %p\n", - __func__, host->sg_len, ret, cookie, host->mrq); - -pio: - if (!desc) { - /* DMA failed, fall back to PIO */ - if (ret >= 0) - ret = -EIO; - host->chan_rx = NULL; - dma_release_channel(chan); - /* Free the Tx channel too */ - chan = host->chan_tx; - if (chan) { - host->chan_tx = NULL; - dma_release_channel(chan); - } - dev_warn(&host->pdev->dev, - "DMA failed: %d, falling back to PIO\n", ret); - tmio_mmc_enable_dma(host, false); - } - - dev_dbg(&host->pdev->dev, "%s(): desc %p, cookie %d, sg[%d]\n", __func__, - desc, cookie, host->sg_len); -} - -static void tmio_mmc_start_dma_tx(struct tmio_mmc_host *host) -{ - struct scatterlist *sg = host->sg_ptr, *sg_tmp; - struct dma_async_tx_descriptor *desc = NULL; - struct dma_chan *chan = host->chan_tx; - struct tmio_mmc_data *pdata = host->pdata; - dma_cookie_t cookie; - int ret, i; - bool aligned = true, multiple = true; - unsigned int align = (1 << pdata->dma->alignment_shift) - 1; - - for_each_sg(sg, sg_tmp, host->sg_len, i) { - if (sg_tmp->offset & align) - aligned = false; - if (sg_tmp->length & align) { - multiple = false; - break; - } - } - - if ((!aligned && (host->sg_len > 1 || sg->length > PAGE_CACHE_SIZE || - (align & PAGE_MASK))) || !multiple) { - ret = -EINVAL; - goto pio; - } - - if (sg->length < TMIO_MMC_MIN_DMA_LEN) { - host->force_pio = true; - return; - } - - tmio_mmc_disable_mmc_irqs(host, TMIO_STAT_TXRQ); - - /* The only sg element can be unaligned, use our bounce buffer then */ - if (!aligned) { - unsigned long flags; - void *sg_vaddr = tmio_mmc_kmap_atomic(sg, &flags); - sg_init_one(&host->bounce_sg, host->bounce_buf, sg->length); - memcpy(host->bounce_buf, sg_vaddr, host->bounce_sg.length); - tmio_mmc_kunmap_atomic(sg, &flags, sg_vaddr); - host->sg_ptr = &host->bounce_sg; - sg = host->sg_ptr; - } - - ret = dma_map_sg(chan->device->dev, sg, host->sg_len, DMA_TO_DEVICE); - if (ret > 0) - desc = dmaengine_prep_slave_sg(chan, sg, ret, - DMA_MEM_TO_DEV, DMA_CTRL_ACK); - - if (desc) { - cookie = dmaengine_submit(desc); - if (cookie < 0) { - desc = NULL; - ret = cookie; - } - } - dev_dbg(&host->pdev->dev, "%s(): mapped %d -> %d, cookie %d, rq %p\n", - __func__, host->sg_len, ret, cookie, host->mrq); - -pio: - if (!desc) { - /* DMA failed, fall back to PIO */ - if (ret >= 0) - ret = -EIO; - host->chan_tx = NULL; - dma_release_channel(chan); - /* Free the Rx channel too */ - chan = host->chan_rx; - if (chan) { - host->chan_rx = NULL; - dma_release_channel(chan); - } - dev_warn(&host->pdev->dev, - "DMA failed: %d, falling back to PIO\n", ret); - tmio_mmc_enable_dma(host, false); - } - - dev_dbg(&host->pdev->dev, "%s(): desc %p, cookie %d\n", __func__, - desc, cookie); -} - -void tmio_mmc_start_dma(struct tmio_mmc_host *host, - struct mmc_data *data) -{ - if (data->flags & MMC_DATA_READ) { - if (host->chan_rx) - tmio_mmc_start_dma_rx(host); - } else { - if (host->chan_tx) - tmio_mmc_start_dma_tx(host); - } -} - -static void tmio_mmc_issue_tasklet_fn(unsigned long priv) -{ - struct tmio_mmc_host *host = (struct tmio_mmc_host *)priv; - struct dma_chan *chan = NULL; - - spin_lock_irq(&host->lock); - - if (host && host->data) { - if (host->data->flags & MMC_DATA_READ) - chan = host->chan_rx; - else - chan = host->chan_tx; - } - - spin_unlock_irq(&host->lock); - - tmio_mmc_enable_mmc_irqs(host, TMIO_STAT_DATAEND); - - if (chan) - dma_async_issue_pending(chan); -} - -static void tmio_mmc_tasklet_fn(unsigned long arg) -{ - struct tmio_mmc_host *host = (struct tmio_mmc_host *)arg; - - spin_lock_irq(&host->lock); - - if (!host->data) - goto out; - - if (host->data->flags & MMC_DATA_READ) - dma_unmap_sg(host->chan_rx->device->dev, - host->sg_ptr, host->sg_len, - DMA_FROM_DEVICE); - else - dma_unmap_sg(host->chan_tx->device->dev, - host->sg_ptr, host->sg_len, - DMA_TO_DEVICE); - - tmio_mmc_do_data_irq(host); -out: - spin_unlock_irq(&host->lock); -} - -/* It might be necessary to make filter MFD specific */ -static bool tmio_mmc_filter(struct dma_chan *chan, void *arg) -{ - dev_dbg(chan->device->dev, "%s: slave data %p\n", __func__, arg); - chan->private = arg; - return true; -} - -void tmio_mmc_request_dma(struct tmio_mmc_host *host, struct tmio_mmc_data *pdata) -{ - /* We can only either use DMA for both Tx and Rx or not use it at all */ - if (!pdata->dma) - return; - - if (!host->chan_tx && !host->chan_rx) { - dma_cap_mask_t mask; - - dma_cap_zero(mask); - dma_cap_set(DMA_SLAVE, mask); - - host->chan_tx = dma_request_channel(mask, tmio_mmc_filter, - pdata->dma->chan_priv_tx); - dev_dbg(&host->pdev->dev, "%s: TX: got channel %p\n", __func__, - host->chan_tx); - - if (!host->chan_tx) - return; - - host->chan_rx = dma_request_channel(mask, tmio_mmc_filter, - pdata->dma->chan_priv_rx); - dev_dbg(&host->pdev->dev, "%s: RX: got channel %p\n", __func__, - host->chan_rx); - - if (!host->chan_rx) - goto ereqrx; - - host->bounce_buf = (u8 *)__get_free_page(GFP_KERNEL | GFP_DMA); - if (!host->bounce_buf) - goto ebouncebuf; - - tasklet_init(&host->dma_complete, tmio_mmc_tasklet_fn, (unsigned long)host); - tasklet_init(&host->dma_issue, tmio_mmc_issue_tasklet_fn, (unsigned long)host); - } - - tmio_mmc_enable_dma(host, true); - - return; - -ebouncebuf: - dma_release_channel(host->chan_rx); - host->chan_rx = NULL; -ereqrx: - dma_release_channel(host->chan_tx); - host->chan_tx = NULL; -} - -void tmio_mmc_release_dma(struct tmio_mmc_host *host) -{ - if (host->chan_tx) { - struct dma_chan *chan = host->chan_tx; - host->chan_tx = NULL; - dma_release_channel(chan); - } - if (host->chan_rx) { - struct dma_chan *chan = host->chan_rx; - host->chan_rx = NULL; - dma_release_channel(chan); - } - if (host->bounce_buf) { - free_pages((unsigned long)host->bounce_buf, 0); - host->bounce_buf = NULL; - } -} diff --git a/ANDROID_3.4.5/drivers/mmc/host/tmio_mmc_pio.c b/ANDROID_3.4.5/drivers/mmc/host/tmio_mmc_pio.c deleted file mode 100644 index 9a7996ad..00000000 --- a/ANDROID_3.4.5/drivers/mmc/host/tmio_mmc_pio.c +++ /dev/null @@ -1,1078 +0,0 @@ -/* - * linux/drivers/mmc/host/tmio_mmc_pio.c - * - * Copyright (C) 2011 Guennadi Liakhovetski - * Copyright (C) 2007 Ian Molton - * Copyright (C) 2004 Ian Molton - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Driver for the MMC / SD / SDIO IP found in: - * - * TC6393XB, TC6391XB, TC6387XB, T7L66XB, ASIC3, SH-Mobile SoCs - * - * This driver draws mainly on scattered spec sheets, Reverse engineering - * of the toshiba e800 SD driver and some parts of the 2.4 ASIC3 driver (4 bit - * support). (Further 4 bit support from a later datasheet). - * - * TODO: - * Investigate using a workqueue for PIO transfers - * Eliminate FIXMEs - * SDIO support - * Better Power management - * Handle MMC errors better - * double buffer support - * - */ - -#include <linux/delay.h> -#include <linux/device.h> -#include <linux/highmem.h> -#include <linux/interrupt.h> -#include <linux/io.h> -#include <linux/irq.h> -#include <linux/mfd/tmio.h> -#include <linux/mmc/cd-gpio.h> -#include <linux/mmc/host.h> -#include <linux/mmc/tmio.h> -#include <linux/module.h> -#include <linux/pagemap.h> -#include <linux/platform_device.h> -#include <linux/pm_qos.h> -#include <linux/pm_runtime.h> -#include <linux/scatterlist.h> -#include <linux/spinlock.h> -#include <linux/workqueue.h> - -#include "tmio_mmc.h" - -void tmio_mmc_enable_mmc_irqs(struct tmio_mmc_host *host, u32 i) -{ - host->sdcard_irq_mask &= ~(i & TMIO_MASK_IRQ); - sd_ctrl_write32(host, CTL_IRQ_MASK, host->sdcard_irq_mask); -} - -void tmio_mmc_disable_mmc_irqs(struct tmio_mmc_host *host, u32 i) -{ - host->sdcard_irq_mask |= (i & TMIO_MASK_IRQ); - sd_ctrl_write32(host, CTL_IRQ_MASK, host->sdcard_irq_mask); -} - -static void tmio_mmc_ack_mmc_irqs(struct tmio_mmc_host *host, u32 i) -{ - sd_ctrl_write32(host, CTL_STATUS, ~i); -} - -static void tmio_mmc_init_sg(struct tmio_mmc_host *host, struct mmc_data *data) -{ - host->sg_len = data->sg_len; - host->sg_ptr = data->sg; - host->sg_orig = data->sg; - host->sg_off = 0; -} - -static int tmio_mmc_next_sg(struct tmio_mmc_host *host) -{ - host->sg_ptr = sg_next(host->sg_ptr); - host->sg_off = 0; - return --host->sg_len; -} - -#ifdef CONFIG_MMC_DEBUG - -#define STATUS_TO_TEXT(a, status, i) \ - do { \ - if (status & TMIO_STAT_##a) { \ - if (i++) \ - printk(" | "); \ - printk(#a); \ - } \ - } while (0) - -static void pr_debug_status(u32 status) -{ - int i = 0; - pr_debug("status: %08x = ", status); - STATUS_TO_TEXT(CARD_REMOVE, status, i); - STATUS_TO_TEXT(CARD_INSERT, status, i); - STATUS_TO_TEXT(SIGSTATE, status, i); - STATUS_TO_TEXT(WRPROTECT, status, i); - STATUS_TO_TEXT(CARD_REMOVE_A, status, i); - STATUS_TO_TEXT(CARD_INSERT_A, status, i); - STATUS_TO_TEXT(SIGSTATE_A, status, i); - STATUS_TO_TEXT(CMD_IDX_ERR, status, i); - STATUS_TO_TEXT(STOPBIT_ERR, status, i); - STATUS_TO_TEXT(ILL_FUNC, status, i); - STATUS_TO_TEXT(CMD_BUSY, status, i); - STATUS_TO_TEXT(CMDRESPEND, status, i); - STATUS_TO_TEXT(DATAEND, status, i); - STATUS_TO_TEXT(CRCFAIL, status, i); - STATUS_TO_TEXT(DATATIMEOUT, status, i); - STATUS_TO_TEXT(CMDTIMEOUT, status, i); - STATUS_TO_TEXT(RXOVERFLOW, status, i); - STATUS_TO_TEXT(TXUNDERRUN, status, i); - STATUS_TO_TEXT(RXRDY, status, i); - STATUS_TO_TEXT(TXRQ, status, i); - STATUS_TO_TEXT(ILL_ACCESS, status, i); - printk("\n"); -} - -#else -#define pr_debug_status(s) do { } while (0) -#endif - -static void tmio_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable) -{ - struct tmio_mmc_host *host = mmc_priv(mmc); - - if (enable) { - host->sdio_irq_mask = TMIO_SDIO_MASK_ALL & - ~TMIO_SDIO_STAT_IOIRQ; - sd_ctrl_write16(host, CTL_TRANSACTION_CTL, 0x0001); - sd_ctrl_write16(host, CTL_SDIO_IRQ_MASK, host->sdio_irq_mask); - } else { - host->sdio_irq_mask = TMIO_SDIO_MASK_ALL; - sd_ctrl_write16(host, CTL_SDIO_IRQ_MASK, host->sdio_irq_mask); - sd_ctrl_write16(host, CTL_TRANSACTION_CTL, 0x0000); - } -} - -static void tmio_mmc_set_clock(struct tmio_mmc_host *host, int new_clock) -{ - u32 clk = 0, clock; - - if (new_clock) { - for (clock = host->mmc->f_min, clk = 0x80000080; - new_clock >= (clock<<1); clk >>= 1) - clock <<= 1; - clk |= 0x100; - } - - if (host->set_clk_div) - host->set_clk_div(host->pdev, (clk>>22) & 1); - - sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, clk & 0x1ff); -} - -static void tmio_mmc_clk_stop(struct tmio_mmc_host *host) -{ - struct resource *res = platform_get_resource(host->pdev, IORESOURCE_MEM, 0); - - /* implicit BUG_ON(!res) */ - if (resource_size(res) > 0x100) { - sd_ctrl_write16(host, CTL_CLK_AND_WAIT_CTL, 0x0000); - msleep(10); - } - - sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, ~0x0100 & - sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL)); - msleep(10); -} - -static void tmio_mmc_clk_start(struct tmio_mmc_host *host) -{ - struct resource *res = platform_get_resource(host->pdev, IORESOURCE_MEM, 0); - - sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, 0x0100 | - sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL)); - msleep(10); - - /* implicit BUG_ON(!res) */ - if (resource_size(res) > 0x100) { - sd_ctrl_write16(host, CTL_CLK_AND_WAIT_CTL, 0x0100); - msleep(10); - } -} - -static void tmio_mmc_reset(struct tmio_mmc_host *host) -{ - struct resource *res = platform_get_resource(host->pdev, IORESOURCE_MEM, 0); - - /* FIXME - should we set stop clock reg here */ - sd_ctrl_write16(host, CTL_RESET_SD, 0x0000); - /* implicit BUG_ON(!res) */ - if (resource_size(res) > 0x100) - sd_ctrl_write16(host, CTL_RESET_SDIO, 0x0000); - msleep(10); - sd_ctrl_write16(host, CTL_RESET_SD, 0x0001); - if (resource_size(res) > 0x100) - sd_ctrl_write16(host, CTL_RESET_SDIO, 0x0001); - msleep(10); -} - -static void tmio_mmc_reset_work(struct work_struct *work) -{ - struct tmio_mmc_host *host = container_of(work, struct tmio_mmc_host, - delayed_reset_work.work); - struct mmc_request *mrq; - unsigned long flags; - - spin_lock_irqsave(&host->lock, flags); - mrq = host->mrq; - - /* - * is request already finished? Since we use a non-blocking - * cancel_delayed_work(), it can happen, that a .set_ios() call preempts - * us, so, have to check for IS_ERR(host->mrq) - */ - if (IS_ERR_OR_NULL(mrq) - || time_is_after_jiffies(host->last_req_ts + - msecs_to_jiffies(2000))) { - spin_unlock_irqrestore(&host->lock, flags); - return; - } - - dev_warn(&host->pdev->dev, - "timeout waiting for hardware interrupt (CMD%u)\n", - mrq->cmd->opcode); - - if (host->data) - host->data->error = -ETIMEDOUT; - else if (host->cmd) - host->cmd->error = -ETIMEDOUT; - else - mrq->cmd->error = -ETIMEDOUT; - - host->cmd = NULL; - host->data = NULL; - host->force_pio = false; - - spin_unlock_irqrestore(&host->lock, flags); - - tmio_mmc_reset(host); - - /* Ready for new calls */ - host->mrq = NULL; - - tmio_mmc_abort_dma(host); - mmc_request_done(host->mmc, mrq); -} - -/* called with host->lock held, interrupts disabled */ -static void tmio_mmc_finish_request(struct tmio_mmc_host *host) -{ - struct mmc_request *mrq; - unsigned long flags; - - spin_lock_irqsave(&host->lock, flags); - - mrq = host->mrq; - if (IS_ERR_OR_NULL(mrq)) { - spin_unlock_irqrestore(&host->lock, flags); - return; - } - - host->cmd = NULL; - host->data = NULL; - host->force_pio = false; - - cancel_delayed_work(&host->delayed_reset_work); - - host->mrq = NULL; - spin_unlock_irqrestore(&host->lock, flags); - - if (mrq->cmd->error || (mrq->data && mrq->data->error)) - tmio_mmc_abort_dma(host); - - mmc_request_done(host->mmc, mrq); -} - -static void tmio_mmc_done_work(struct work_struct *work) -{ - struct tmio_mmc_host *host = container_of(work, struct tmio_mmc_host, - done); - tmio_mmc_finish_request(host); -} - -/* These are the bitmasks the tmio chip requires to implement the MMC response - * types. Note that R1 and R6 are the same in this scheme. */ -#define APP_CMD 0x0040 -#define RESP_NONE 0x0300 -#define RESP_R1 0x0400 -#define RESP_R1B 0x0500 -#define RESP_R2 0x0600 -#define RESP_R3 0x0700 -#define DATA_PRESENT 0x0800 -#define TRANSFER_READ 0x1000 -#define TRANSFER_MULTI 0x2000 -#define SECURITY_CMD 0x4000 - -static int tmio_mmc_start_command(struct tmio_mmc_host *host, struct mmc_command *cmd) -{ - struct mmc_data *data = host->data; - int c = cmd->opcode; - u32 irq_mask = TMIO_MASK_CMD; - - /* Command 12 is handled by hardware */ - if (cmd->opcode == 12 && !cmd->arg) { - sd_ctrl_write16(host, CTL_STOP_INTERNAL_ACTION, 0x001); - return 0; - } - - switch (mmc_resp_type(cmd)) { - case MMC_RSP_NONE: c |= RESP_NONE; break; - case MMC_RSP_R1: c |= RESP_R1; break; - case MMC_RSP_R1B: c |= RESP_R1B; break; - case MMC_RSP_R2: c |= RESP_R2; break; - case MMC_RSP_R3: c |= RESP_R3; break; - default: - pr_debug("Unknown response type %d\n", mmc_resp_type(cmd)); - return -EINVAL; - } - - host->cmd = cmd; - -/* FIXME - this seems to be ok commented out but the spec suggest this bit - * should be set when issuing app commands. - * if(cmd->flags & MMC_FLAG_ACMD) - * c |= APP_CMD; - */ - if (data) { - c |= DATA_PRESENT; - if (data->blocks > 1) { - sd_ctrl_write16(host, CTL_STOP_INTERNAL_ACTION, 0x100); - c |= TRANSFER_MULTI; - } - if (data->flags & MMC_DATA_READ) - c |= TRANSFER_READ; - } - - if (!host->native_hotplug) - irq_mask &= ~(TMIO_STAT_CARD_REMOVE | TMIO_STAT_CARD_INSERT); - tmio_mmc_enable_mmc_irqs(host, irq_mask); - - /* Fire off the command */ - sd_ctrl_write32(host, CTL_ARG_REG, cmd->arg); - sd_ctrl_write16(host, CTL_SD_CMD, c); - - return 0; -} - -/* - * This chip always returns (at least?) as much data as you ask for. - * I'm unsure what happens if you ask for less than a block. This should be - * looked into to ensure that a funny length read doesn't hose the controller. - */ -static void tmio_mmc_pio_irq(struct tmio_mmc_host *host) -{ - struct mmc_data *data = host->data; - void *sg_virt; - unsigned short *buf; - unsigned int count; - unsigned long flags; - - if ((host->chan_tx || host->chan_rx) && !host->force_pio) { - pr_err("PIO IRQ in DMA mode!\n"); - return; - } else if (!data) { - pr_debug("Spurious PIO IRQ\n"); - return; - } - - sg_virt = tmio_mmc_kmap_atomic(host->sg_ptr, &flags); - buf = (unsigned short *)(sg_virt + host->sg_off); - - count = host->sg_ptr->length - host->sg_off; - if (count > data->blksz) - count = data->blksz; - - pr_debug("count: %08x offset: %08x flags %08x\n", - count, host->sg_off, data->flags); - - /* Transfer the data */ - if (data->flags & MMC_DATA_READ) - sd_ctrl_read16_rep(host, CTL_SD_DATA_PORT, buf, count >> 1); - else - sd_ctrl_write16_rep(host, CTL_SD_DATA_PORT, buf, count >> 1); - - host->sg_off += count; - - tmio_mmc_kunmap_atomic(host->sg_ptr, &flags, sg_virt); - - if (host->sg_off == host->sg_ptr->length) - tmio_mmc_next_sg(host); - - return; -} - -static void tmio_mmc_check_bounce_buffer(struct tmio_mmc_host *host) -{ - if (host->sg_ptr == &host->bounce_sg) { - unsigned long flags; - void *sg_vaddr = tmio_mmc_kmap_atomic(host->sg_orig, &flags); - memcpy(sg_vaddr, host->bounce_buf, host->bounce_sg.length); - tmio_mmc_kunmap_atomic(host->sg_orig, &flags, sg_vaddr); - } -} - -/* needs to be called with host->lock held */ -void tmio_mmc_do_data_irq(struct tmio_mmc_host *host) -{ - struct mmc_data *data = host->data; - struct mmc_command *stop; - - host->data = NULL; - - if (!data) { - dev_warn(&host->pdev->dev, "Spurious data end IRQ\n"); - return; - } - stop = data->stop; - - /* FIXME - return correct transfer count on errors */ - if (!data->error) - data->bytes_xfered = data->blocks * data->blksz; - else - data->bytes_xfered = 0; - - pr_debug("Completed data request\n"); - - /* - * FIXME: other drivers allow an optional stop command of any given type - * which we dont do, as the chip can auto generate them. - * Perhaps we can be smarter about when to use auto CMD12 and - * only issue the auto request when we know this is the desired - * stop command, allowing fallback to the stop command the - * upper layers expect. For now, we do what works. - */ - - if (data->flags & MMC_DATA_READ) { - if (host->chan_rx && !host->force_pio) - tmio_mmc_check_bounce_buffer(host); - dev_dbg(&host->pdev->dev, "Complete Rx request %p\n", - host->mrq); - } else { - dev_dbg(&host->pdev->dev, "Complete Tx request %p\n", - host->mrq); - } - - if (stop) { - if (stop->opcode == 12 && !stop->arg) - sd_ctrl_write16(host, CTL_STOP_INTERNAL_ACTION, 0x000); - else - BUG(); - } - - schedule_work(&host->done); -} - -static void tmio_mmc_data_irq(struct tmio_mmc_host *host) -{ - struct mmc_data *data; - spin_lock(&host->lock); - data = host->data; - - if (!data) - goto out; - - if (host->chan_tx && (data->flags & MMC_DATA_WRITE) && !host->force_pio) { - /* - * Has all data been written out yet? Testing on SuperH showed, - * that in most cases the first interrupt comes already with the - * BUSY status bit clear, but on some operations, like mount or - * in the beginning of a write / sync / umount, there is one - * DATAEND interrupt with the BUSY bit set, in this cases - * waiting for one more interrupt fixes the problem. - */ - if (!(sd_ctrl_read32(host, CTL_STATUS) & TMIO_STAT_CMD_BUSY)) { - tmio_mmc_disable_mmc_irqs(host, TMIO_STAT_DATAEND); - tasklet_schedule(&host->dma_complete); - } - } else if (host->chan_rx && (data->flags & MMC_DATA_READ) && !host->force_pio) { - tmio_mmc_disable_mmc_irqs(host, TMIO_STAT_DATAEND); - tasklet_schedule(&host->dma_complete); - } else { - tmio_mmc_do_data_irq(host); - tmio_mmc_disable_mmc_irqs(host, TMIO_MASK_READOP | TMIO_MASK_WRITEOP); - } -out: - spin_unlock(&host->lock); -} - -static void tmio_mmc_cmd_irq(struct tmio_mmc_host *host, - unsigned int stat) -{ - struct mmc_command *cmd = host->cmd; - int i, addr; - - spin_lock(&host->lock); - - if (!host->cmd) { - pr_debug("Spurious CMD irq\n"); - goto out; - } - - host->cmd = NULL; - - /* This controller is sicker than the PXA one. Not only do we need to - * drop the top 8 bits of the first response word, we also need to - * modify the order of the response for short response command types. - */ - - for (i = 3, addr = CTL_RESPONSE ; i >= 0 ; i--, addr += 4) - cmd->resp[i] = sd_ctrl_read32(host, addr); - - if (cmd->flags & MMC_RSP_136) { - cmd->resp[0] = (cmd->resp[0] << 8) | (cmd->resp[1] >> 24); - cmd->resp[1] = (cmd->resp[1] << 8) | (cmd->resp[2] >> 24); - cmd->resp[2] = (cmd->resp[2] << 8) | (cmd->resp[3] >> 24); - cmd->resp[3] <<= 8; - } else if (cmd->flags & MMC_RSP_R3) { - cmd->resp[0] = cmd->resp[3]; - } - - if (stat & TMIO_STAT_CMDTIMEOUT) - cmd->error = -ETIMEDOUT; - else if (stat & TMIO_STAT_CRCFAIL && cmd->flags & MMC_RSP_CRC) - cmd->error = -EILSEQ; - - /* If there is data to handle we enable data IRQs here, and - * we will ultimatley finish the request in the data_end handler. - * If theres no data or we encountered an error, finish now. - */ - if (host->data && !cmd->error) { - if (host->data->flags & MMC_DATA_READ) { - if (host->force_pio || !host->chan_rx) - tmio_mmc_enable_mmc_irqs(host, TMIO_MASK_READOP); - else - tasklet_schedule(&host->dma_issue); - } else { - if (host->force_pio || !host->chan_tx) - tmio_mmc_enable_mmc_irqs(host, TMIO_MASK_WRITEOP); - else - tasklet_schedule(&host->dma_issue); - } - } else { - schedule_work(&host->done); - } - -out: - spin_unlock(&host->lock); -} - -static void tmio_mmc_card_irq_status(struct tmio_mmc_host *host, - int *ireg, int *status) -{ - *status = sd_ctrl_read32(host, CTL_STATUS); - *ireg = *status & TMIO_MASK_IRQ & ~host->sdcard_irq_mask; - - pr_debug_status(*status); - pr_debug_status(*ireg); -} - -static bool __tmio_mmc_card_detect_irq(struct tmio_mmc_host *host, - int ireg, int status) -{ - struct mmc_host *mmc = host->mmc; - - /* Card insert / remove attempts */ - if (ireg & (TMIO_STAT_CARD_INSERT | TMIO_STAT_CARD_REMOVE)) { - tmio_mmc_ack_mmc_irqs(host, TMIO_STAT_CARD_INSERT | - TMIO_STAT_CARD_REMOVE); - if ((((ireg & TMIO_STAT_CARD_REMOVE) && mmc->card) || - ((ireg & TMIO_STAT_CARD_INSERT) && !mmc->card)) && - !work_pending(&mmc->detect.work)) - mmc_detect_change(host->mmc, msecs_to_jiffies(100)); - return true; - } - - return false; -} - -irqreturn_t tmio_mmc_card_detect_irq(int irq, void *devid) -{ - unsigned int ireg, status; - struct tmio_mmc_host *host = devid; - - tmio_mmc_card_irq_status(host, &ireg, &status); - __tmio_mmc_card_detect_irq(host, ireg, status); - - return IRQ_HANDLED; -} -EXPORT_SYMBOL(tmio_mmc_card_detect_irq); - -static bool __tmio_mmc_sdcard_irq(struct tmio_mmc_host *host, - int ireg, int status) -{ - /* Command completion */ - if (ireg & (TMIO_STAT_CMDRESPEND | TMIO_STAT_CMDTIMEOUT)) { - tmio_mmc_ack_mmc_irqs(host, - TMIO_STAT_CMDRESPEND | - TMIO_STAT_CMDTIMEOUT); - tmio_mmc_cmd_irq(host, status); - return true; - } - - /* Data transfer */ - if (ireg & (TMIO_STAT_RXRDY | TMIO_STAT_TXRQ)) { - tmio_mmc_ack_mmc_irqs(host, TMIO_STAT_RXRDY | TMIO_STAT_TXRQ); - tmio_mmc_pio_irq(host); - return true; - } - - /* Data transfer completion */ - if (ireg & TMIO_STAT_DATAEND) { - tmio_mmc_ack_mmc_irqs(host, TMIO_STAT_DATAEND); - tmio_mmc_data_irq(host); - return true; - } - - return false; -} - -irqreturn_t tmio_mmc_sdcard_irq(int irq, void *devid) -{ - unsigned int ireg, status; - struct tmio_mmc_host *host = devid; - - tmio_mmc_card_irq_status(host, &ireg, &status); - __tmio_mmc_sdcard_irq(host, ireg, status); - - return IRQ_HANDLED; -} -EXPORT_SYMBOL(tmio_mmc_sdcard_irq); - -irqreturn_t tmio_mmc_sdio_irq(int irq, void *devid) -{ - struct tmio_mmc_host *host = devid; - struct mmc_host *mmc = host->mmc; - struct tmio_mmc_data *pdata = host->pdata; - unsigned int ireg, status; - - if (!(pdata->flags & TMIO_MMC_SDIO_IRQ)) - return IRQ_HANDLED; - - status = sd_ctrl_read16(host, CTL_SDIO_STATUS); - ireg = status & TMIO_SDIO_MASK_ALL & ~host->sdcard_irq_mask; - - sd_ctrl_write16(host, CTL_SDIO_STATUS, status & ~TMIO_SDIO_MASK_ALL); - - if (mmc->caps & MMC_CAP_SDIO_IRQ && ireg & TMIO_SDIO_STAT_IOIRQ) - mmc_signal_sdio_irq(mmc); - - return IRQ_HANDLED; -} -EXPORT_SYMBOL(tmio_mmc_sdio_irq); - -irqreturn_t tmio_mmc_irq(int irq, void *devid) -{ - struct tmio_mmc_host *host = devid; - unsigned int ireg, status; - - pr_debug("MMC IRQ begin\n"); - - tmio_mmc_card_irq_status(host, &ireg, &status); - if (__tmio_mmc_card_detect_irq(host, ireg, status)) - return IRQ_HANDLED; - if (__tmio_mmc_sdcard_irq(host, ireg, status)) - return IRQ_HANDLED; - - tmio_mmc_sdio_irq(irq, devid); - - return IRQ_HANDLED; -} -EXPORT_SYMBOL(tmio_mmc_irq); - -static int tmio_mmc_start_data(struct tmio_mmc_host *host, - struct mmc_data *data) -{ - struct tmio_mmc_data *pdata = host->pdata; - - pr_debug("setup data transfer: blocksize %08x nr_blocks %d\n", - data->blksz, data->blocks); - - /* Some hardware cannot perform 2 byte requests in 4 bit mode */ - if (host->mmc->ios.bus_width == MMC_BUS_WIDTH_4) { - int blksz_2bytes = pdata->flags & TMIO_MMC_BLKSZ_2BYTES; - - if (data->blksz < 2 || (data->blksz < 4 && !blksz_2bytes)) { - pr_err("%s: %d byte block unsupported in 4 bit mode\n", - mmc_hostname(host->mmc), data->blksz); - return -EINVAL; - } - } - - tmio_mmc_init_sg(host, data); - host->data = data; - - /* Set transfer length / blocksize */ - sd_ctrl_write16(host, CTL_SD_XFER_LEN, data->blksz); - sd_ctrl_write16(host, CTL_XFER_BLK_COUNT, data->blocks); - - tmio_mmc_start_dma(host, data); - - return 0; -} - -/* Process requests from the MMC layer */ -static void tmio_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq) -{ - struct tmio_mmc_host *host = mmc_priv(mmc); - unsigned long flags; - int ret; - - spin_lock_irqsave(&host->lock, flags); - - if (host->mrq) { - pr_debug("request not null\n"); - if (IS_ERR(host->mrq)) { - spin_unlock_irqrestore(&host->lock, flags); - mrq->cmd->error = -EAGAIN; - mmc_request_done(mmc, mrq); - return; - } - } - - host->last_req_ts = jiffies; - wmb(); - host->mrq = mrq; - - spin_unlock_irqrestore(&host->lock, flags); - - if (mrq->data) { - ret = tmio_mmc_start_data(host, mrq->data); - if (ret) - goto fail; - } - - ret = tmio_mmc_start_command(host, mrq->cmd); - if (!ret) { - schedule_delayed_work(&host->delayed_reset_work, - msecs_to_jiffies(2000)); - return; - } - -fail: - host->force_pio = false; - host->mrq = NULL; - mrq->cmd->error = ret; - mmc_request_done(mmc, mrq); -} - -/* Set MMC clock / power. - * Note: This controller uses a simple divider scheme therefore it cannot - * run a MMC card at full speed (20MHz). The max clock is 24MHz on SD, but as - * MMC wont run that fast, it has to be clocked at 12MHz which is the next - * slowest setting. - */ -static void tmio_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) -{ - struct tmio_mmc_host *host = mmc_priv(mmc); - struct device *dev = &host->pdev->dev; - unsigned long flags; - - mutex_lock(&host->ios_lock); - - spin_lock_irqsave(&host->lock, flags); - if (host->mrq) { - if (IS_ERR(host->mrq)) { - dev_dbg(dev, - "%s.%d: concurrent .set_ios(), clk %u, mode %u\n", - current->comm, task_pid_nr(current), - ios->clock, ios->power_mode); - host->mrq = ERR_PTR(-EINTR); - } else { - dev_dbg(dev, - "%s.%d: CMD%u active since %lu, now %lu!\n", - current->comm, task_pid_nr(current), - host->mrq->cmd->opcode, host->last_req_ts, jiffies); - } - spin_unlock_irqrestore(&host->lock, flags); - - mutex_unlock(&host->ios_lock); - return; - } - - host->mrq = ERR_PTR(-EBUSY); - - spin_unlock_irqrestore(&host->lock, flags); - - /* - * host->power toggles between false and true in both cases - either - * or not the controller can be runtime-suspended during inactivity. - * But if the controller has to be kept on, the runtime-pm usage_count - * is kept positive, so no suspending actually takes place. - */ - if (ios->power_mode == MMC_POWER_ON && ios->clock) { - if (!host->power) { - pm_runtime_get_sync(dev); - host->power = true; - } - tmio_mmc_set_clock(host, ios->clock); - /* power up SD bus */ - if (host->set_pwr) - host->set_pwr(host->pdev, 1); - /* start bus clock */ - tmio_mmc_clk_start(host); - } else if (ios->power_mode != MMC_POWER_UP) { - if (host->set_pwr && ios->power_mode == MMC_POWER_OFF) - host->set_pwr(host->pdev, 0); - if (host->power) { - host->power = false; - pm_runtime_put(dev); - } - tmio_mmc_clk_stop(host); - } - - switch (ios->bus_width) { - case MMC_BUS_WIDTH_1: - sd_ctrl_write16(host, CTL_SD_MEM_CARD_OPT, 0x80e0); - break; - case MMC_BUS_WIDTH_4: - sd_ctrl_write16(host, CTL_SD_MEM_CARD_OPT, 0x00e0); - break; - } - - /* Let things settle. delay taken from winCE driver */ - udelay(140); - if (PTR_ERR(host->mrq) == -EINTR) - dev_dbg(&host->pdev->dev, - "%s.%d: IOS interrupted: clk %u, mode %u", - current->comm, task_pid_nr(current), - ios->clock, ios->power_mode); - host->mrq = NULL; - - mutex_unlock(&host->ios_lock); -} - -static int tmio_mmc_get_ro(struct mmc_host *mmc) -{ - struct tmio_mmc_host *host = mmc_priv(mmc); - struct tmio_mmc_data *pdata = host->pdata; - - return !((pdata->flags & TMIO_MMC_WRPROTECT_DISABLE) || - (sd_ctrl_read32(host, CTL_STATUS) & TMIO_STAT_WRPROTECT)); -} - -static int tmio_mmc_get_cd(struct mmc_host *mmc) -{ - struct tmio_mmc_host *host = mmc_priv(mmc); - struct tmio_mmc_data *pdata = host->pdata; - - if (!pdata->get_cd) - return -ENOSYS; - else - return pdata->get_cd(host->pdev); -} - -static const struct mmc_host_ops tmio_mmc_ops = { - .request = tmio_mmc_request, - .set_ios = tmio_mmc_set_ios, - .get_ro = tmio_mmc_get_ro, - .get_cd = tmio_mmc_get_cd, - .enable_sdio_irq = tmio_mmc_enable_sdio_irq, -}; - -int __devinit tmio_mmc_host_probe(struct tmio_mmc_host **host, - struct platform_device *pdev, - struct tmio_mmc_data *pdata) -{ - struct tmio_mmc_host *_host; - struct mmc_host *mmc; - struct resource *res_ctl; - int ret; - u32 irq_mask = TMIO_MASK_CMD; - - res_ctl = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res_ctl) - return -EINVAL; - - mmc = mmc_alloc_host(sizeof(struct tmio_mmc_host), &pdev->dev); - if (!mmc) - return -ENOMEM; - - pdata->dev = &pdev->dev; - _host = mmc_priv(mmc); - _host->pdata = pdata; - _host->mmc = mmc; - _host->pdev = pdev; - platform_set_drvdata(pdev, mmc); - - _host->set_pwr = pdata->set_pwr; - _host->set_clk_div = pdata->set_clk_div; - - /* SD control register space size is 0x200, 0x400 for bus_shift=1 */ - _host->bus_shift = resource_size(res_ctl) >> 10; - - _host->ctl = ioremap(res_ctl->start, resource_size(res_ctl)); - if (!_host->ctl) { - ret = -ENOMEM; - goto host_free; - } - - mmc->ops = &tmio_mmc_ops; - mmc->caps = MMC_CAP_4_BIT_DATA | pdata->capabilities; - mmc->f_max = pdata->hclk; - mmc->f_min = mmc->f_max / 512; - mmc->max_segs = 32; - mmc->max_blk_size = 512; - mmc->max_blk_count = (PAGE_CACHE_SIZE / mmc->max_blk_size) * - mmc->max_segs; - mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count; - mmc->max_seg_size = mmc->max_req_size; - if (pdata->ocr_mask) - mmc->ocr_avail = pdata->ocr_mask; - else - mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; - - _host->native_hotplug = !(pdata->flags & TMIO_MMC_USE_GPIO_CD || - mmc->caps & MMC_CAP_NEEDS_POLL || - mmc->caps & MMC_CAP_NONREMOVABLE); - - _host->power = false; - pm_runtime_enable(&pdev->dev); - ret = pm_runtime_resume(&pdev->dev); - if (ret < 0) - goto pm_disable; - - /* - * There are 4 different scenarios for the card detection: - * 1) an external gpio irq handles the cd (best for power savings) - * 2) internal sdhi irq handles the cd - * 3) a worker thread polls the sdhi - indicated by MMC_CAP_NEEDS_POLL - * 4) the medium is non-removable - indicated by MMC_CAP_NONREMOVABLE - * - * While we increment the runtime PM counter for all scenarios when - * the mmc core activates us by calling an appropriate set_ios(), we - * must additionally ensure that in case 2) the tmio mmc hardware stays - * additionally ensure that in case 2) the tmio mmc hardware stays - * powered on during runtime for the card detection to work. - */ - if (_host->native_hotplug) - pm_runtime_get_noresume(&pdev->dev); - - tmio_mmc_clk_stop(_host); - tmio_mmc_reset(_host); - - _host->sdcard_irq_mask = sd_ctrl_read32(_host, CTL_IRQ_MASK); - tmio_mmc_disable_mmc_irqs(_host, TMIO_MASK_ALL); - if (pdata->flags & TMIO_MMC_SDIO_IRQ) - tmio_mmc_enable_sdio_irq(mmc, 0); - - spin_lock_init(&_host->lock); - mutex_init(&_host->ios_lock); - - /* Init delayed work for request timeouts */ - INIT_DELAYED_WORK(&_host->delayed_reset_work, tmio_mmc_reset_work); - INIT_WORK(&_host->done, tmio_mmc_done_work); - - /* See if we also get DMA */ - tmio_mmc_request_dma(_host, pdata); - - mmc_add_host(mmc); - - dev_pm_qos_expose_latency_limit(&pdev->dev, 100); - - /* Unmask the IRQs we want to know about */ - if (!_host->chan_rx) - irq_mask |= TMIO_MASK_READOP; - if (!_host->chan_tx) - irq_mask |= TMIO_MASK_WRITEOP; - if (!_host->native_hotplug) - irq_mask &= ~(TMIO_STAT_CARD_REMOVE | TMIO_STAT_CARD_INSERT); - - tmio_mmc_enable_mmc_irqs(_host, irq_mask); - - if (pdata->flags & TMIO_MMC_USE_GPIO_CD) { - ret = mmc_cd_gpio_request(mmc, pdata->cd_gpio); - if (ret < 0) { - tmio_mmc_host_remove(_host); - return ret; - } - } - - *host = _host; - - return 0; - -pm_disable: - pm_runtime_disable(&pdev->dev); - iounmap(_host->ctl); -host_free: - mmc_free_host(mmc); - - return ret; -} -EXPORT_SYMBOL(tmio_mmc_host_probe); - -void tmio_mmc_host_remove(struct tmio_mmc_host *host) -{ - struct platform_device *pdev = host->pdev; - struct tmio_mmc_data *pdata = host->pdata; - struct mmc_host *mmc = host->mmc; - - if (pdata->flags & TMIO_MMC_USE_GPIO_CD) - /* - * This means we can miss a card-eject, but this is anyway - * possible, because of delayed processing of hotplug events. - */ - mmc_cd_gpio_free(mmc); - - if (!host->native_hotplug) - pm_runtime_get_sync(&pdev->dev); - - dev_pm_qos_hide_latency_limit(&pdev->dev); - - mmc_remove_host(mmc); - cancel_work_sync(&host->done); - cancel_delayed_work_sync(&host->delayed_reset_work); - tmio_mmc_release_dma(host); - - pm_runtime_put_sync(&pdev->dev); - pm_runtime_disable(&pdev->dev); - - iounmap(host->ctl); - mmc_free_host(mmc); -} -EXPORT_SYMBOL(tmio_mmc_host_remove); - -#ifdef CONFIG_PM -int tmio_mmc_host_suspend(struct device *dev) -{ - struct mmc_host *mmc = dev_get_drvdata(dev); - struct tmio_mmc_host *host = mmc_priv(mmc); - int ret = mmc_suspend_host(mmc); - - if (!ret) - tmio_mmc_disable_mmc_irqs(host, TMIO_MASK_ALL); - - return ret; -} -EXPORT_SYMBOL(tmio_mmc_host_suspend); - -int tmio_mmc_host_resume(struct device *dev) -{ - struct mmc_host *mmc = dev_get_drvdata(dev); - struct tmio_mmc_host *host = mmc_priv(mmc); - - tmio_mmc_reset(host); - tmio_mmc_enable_dma(host, true); - - /* The MMC core will perform the complete set up */ - return mmc_resume_host(mmc); -} -EXPORT_SYMBOL(tmio_mmc_host_resume); - -#endif /* CONFIG_PM */ - -int tmio_mmc_host_runtime_suspend(struct device *dev) -{ - return 0; -} -EXPORT_SYMBOL(tmio_mmc_host_runtime_suspend); - -int tmio_mmc_host_runtime_resume(struct device *dev) -{ - struct mmc_host *mmc = dev_get_drvdata(dev); - struct tmio_mmc_host *host = mmc_priv(mmc); - - tmio_mmc_reset(host); - tmio_mmc_enable_dma(host, true); - - return 0; -} -EXPORT_SYMBOL(tmio_mmc_host_runtime_resume); - -MODULE_LICENSE("GPL v2"); diff --git a/ANDROID_3.4.5/drivers/mmc/host/ushc.c b/ANDROID_3.4.5/drivers/mmc/host/ushc.c deleted file mode 100644 index c0105a2e..00000000 --- a/ANDROID_3.4.5/drivers/mmc/host/ushc.c +++ /dev/null @@ -1,569 +0,0 @@ -/* - * USB SD Host Controller (USHC) controller driver. - * - * Copyright (C) 2010 Cambridge Silicon Radio Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at - * your option) any later version. - * - * Notes: - * - Only version 2 devices are supported. - * - Version 2 devices only support SDIO cards/devices (R2 response is - * unsupported). - * - * References: - * [USHC] USB SD Host Controller specification (CS-118793-SP) - */ -#include <linux/module.h> -#include <linux/usb.h> -#include <linux/kernel.h> -#include <linux/slab.h> -#include <linux/dma-mapping.h> -#include <linux/mmc/host.h> - -enum ushc_request { - USHC_GET_CAPS = 0x00, - USHC_HOST_CTRL = 0x01, - USHC_PWR_CTRL = 0x02, - USHC_CLK_FREQ = 0x03, - USHC_EXEC_CMD = 0x04, - USHC_READ_RESP = 0x05, - USHC_RESET = 0x06, -}; - -enum ushc_request_type { - USHC_GET_CAPS_TYPE = USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - USHC_HOST_CTRL_TYPE = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - USHC_PWR_CTRL_TYPE = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - USHC_CLK_FREQ_TYPE = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - USHC_EXEC_CMD_TYPE = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - USHC_READ_RESP_TYPE = USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - USHC_RESET_TYPE = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, -}; - -#define USHC_GET_CAPS_VERSION_MASK 0xff -#define USHC_GET_CAPS_3V3 (1 << 8) -#define USHC_GET_CAPS_3V0 (1 << 9) -#define USHC_GET_CAPS_1V8 (1 << 10) -#define USHC_GET_CAPS_HIGH_SPD (1 << 16) - -#define USHC_HOST_CTRL_4BIT (1 << 1) -#define USHC_HOST_CTRL_HIGH_SPD (1 << 0) - -#define USHC_PWR_CTRL_OFF 0x00 -#define USHC_PWR_CTRL_3V3 0x01 -#define USHC_PWR_CTRL_3V0 0x02 -#define USHC_PWR_CTRL_1V8 0x03 - -#define USHC_READ_RESP_BUSY (1 << 4) -#define USHC_READ_RESP_ERR_TIMEOUT (1 << 3) -#define USHC_READ_RESP_ERR_CRC (1 << 2) -#define USHC_READ_RESP_ERR_DAT (1 << 1) -#define USHC_READ_RESP_ERR_CMD (1 << 0) -#define USHC_READ_RESP_ERR_MASK 0x0f - -struct ushc_cbw { - __u8 signature; - __u8 cmd_idx; - __le16 block_size; - __le32 arg; -} __attribute__((packed)); - -#define USHC_CBW_SIGNATURE 'C' - -struct ushc_csw { - __u8 signature; - __u8 status; - __le32 response; -} __attribute__((packed)); - -#define USHC_CSW_SIGNATURE 'S' - -struct ushc_int_data { - u8 status; - u8 reserved[3]; -}; - -#define USHC_INT_STATUS_SDIO_INT (1 << 1) -#define USHC_INT_STATUS_CARD_PRESENT (1 << 0) - - -struct ushc_data { - struct usb_device *usb_dev; - struct mmc_host *mmc; - - struct urb *int_urb; - struct ushc_int_data *int_data; - - struct urb *cbw_urb; - struct ushc_cbw *cbw; - - struct urb *data_urb; - - struct urb *csw_urb; - struct ushc_csw *csw; - - spinlock_t lock; - struct mmc_request *current_req; - u32 caps; - u16 host_ctrl; - unsigned long flags; - u8 last_status; - int clock_freq; -}; - -#define DISCONNECTED 0 -#define INT_EN 1 -#define IGNORE_NEXT_INT 2 - -static void data_callback(struct urb *urb); - -static int ushc_hw_reset(struct ushc_data *ushc) -{ - return usb_control_msg(ushc->usb_dev, usb_sndctrlpipe(ushc->usb_dev, 0), - USHC_RESET, USHC_RESET_TYPE, - 0, 0, NULL, 0, 100); -} - -static int ushc_hw_get_caps(struct ushc_data *ushc) -{ - int ret; - int version; - - ret = usb_control_msg(ushc->usb_dev, usb_rcvctrlpipe(ushc->usb_dev, 0), - USHC_GET_CAPS, USHC_GET_CAPS_TYPE, - 0, 0, &ushc->caps, sizeof(ushc->caps), 100); - if (ret < 0) - return ret; - - ushc->caps = le32_to_cpu(ushc->caps); - - version = ushc->caps & USHC_GET_CAPS_VERSION_MASK; - if (version != 0x02) { - dev_err(&ushc->usb_dev->dev, "controller version %d is not supported\n", version); - return -EINVAL; - } - - return 0; -} - -static int ushc_hw_set_host_ctrl(struct ushc_data *ushc, u16 mask, u16 val) -{ - u16 host_ctrl; - int ret; - - host_ctrl = (ushc->host_ctrl & ~mask) | val; - ret = usb_control_msg(ushc->usb_dev, usb_sndctrlpipe(ushc->usb_dev, 0), - USHC_HOST_CTRL, USHC_HOST_CTRL_TYPE, - host_ctrl, 0, NULL, 0, 100); - if (ret < 0) - return ret; - ushc->host_ctrl = host_ctrl; - return 0; -} - -static void int_callback(struct urb *urb) -{ - struct ushc_data *ushc = urb->context; - u8 status, last_status; - - if (urb->status < 0) - return; - - status = ushc->int_data->status; - last_status = ushc->last_status; - ushc->last_status = status; - - /* - * Ignore the card interrupt status on interrupt transfers that - * were submitted while card interrupts where disabled. - * - * This avoid occasional spurious interrupts when enabling - * interrupts immediately after clearing the source on the card. - */ - - if (!test_and_clear_bit(IGNORE_NEXT_INT, &ushc->flags) - && test_bit(INT_EN, &ushc->flags) - && status & USHC_INT_STATUS_SDIO_INT) { - mmc_signal_sdio_irq(ushc->mmc); - } - - if ((status ^ last_status) & USHC_INT_STATUS_CARD_PRESENT) - mmc_detect_change(ushc->mmc, msecs_to_jiffies(100)); - - if (!test_bit(INT_EN, &ushc->flags)) - set_bit(IGNORE_NEXT_INT, &ushc->flags); - usb_submit_urb(ushc->int_urb, GFP_ATOMIC); -} - -static void cbw_callback(struct urb *urb) -{ - struct ushc_data *ushc = urb->context; - - if (urb->status != 0) { - usb_unlink_urb(ushc->data_urb); - usb_unlink_urb(ushc->csw_urb); - } -} - -static void data_callback(struct urb *urb) -{ - struct ushc_data *ushc = urb->context; - - if (urb->status != 0) - usb_unlink_urb(ushc->csw_urb); -} - -static void csw_callback(struct urb *urb) -{ - struct ushc_data *ushc = urb->context; - struct mmc_request *req = ushc->current_req; - int status; - - status = ushc->csw->status; - - if (urb->status != 0) { - req->cmd->error = urb->status; - } else if (status & USHC_READ_RESP_ERR_CMD) { - if (status & USHC_READ_RESP_ERR_CRC) - req->cmd->error = -EIO; - else - req->cmd->error = -ETIMEDOUT; - } - if (req->data) { - if (status & USHC_READ_RESP_ERR_DAT) { - if (status & USHC_READ_RESP_ERR_CRC) - req->data->error = -EIO; - else - req->data->error = -ETIMEDOUT; - req->data->bytes_xfered = 0; - } else { - req->data->bytes_xfered = req->data->blksz * req->data->blocks; - } - } - - req->cmd->resp[0] = le32_to_cpu(ushc->csw->response); - - mmc_request_done(ushc->mmc, req); -} - -static void ushc_request(struct mmc_host *mmc, struct mmc_request *req) -{ - struct ushc_data *ushc = mmc_priv(mmc); - int ret; - unsigned long flags; - - spin_lock_irqsave(&ushc->lock, flags); - - if (test_bit(DISCONNECTED, &ushc->flags)) { - ret = -ENODEV; - goto out; - } - - /* Version 2 firmware doesn't support the R2 response format. */ - if (req->cmd->flags & MMC_RSP_136) { - ret = -EINVAL; - goto out; - } - - /* The Astoria's data FIFOs don't work with clock speeds < 5MHz so - limit commands with data to 6MHz or more. */ - if (req->data && ushc->clock_freq < 6000000) { - ret = -EINVAL; - goto out; - } - - ushc->current_req = req; - - /* Start cmd with CBW. */ - ushc->cbw->cmd_idx = cpu_to_le16(req->cmd->opcode); - if (req->data) - ushc->cbw->block_size = cpu_to_le16(req->data->blksz); - else - ushc->cbw->block_size = 0; - ushc->cbw->arg = cpu_to_le32(req->cmd->arg); - - ret = usb_submit_urb(ushc->cbw_urb, GFP_ATOMIC); - if (ret < 0) - goto out; - - /* Submit data (if any). */ - if (req->data) { - struct mmc_data *data = req->data; - int pipe; - - if (data->flags & MMC_DATA_READ) - pipe = usb_rcvbulkpipe(ushc->usb_dev, 6); - else - pipe = usb_sndbulkpipe(ushc->usb_dev, 2); - - usb_fill_bulk_urb(ushc->data_urb, ushc->usb_dev, pipe, - sg_virt(data->sg), data->sg->length, - data_callback, ushc); - ret = usb_submit_urb(ushc->data_urb, GFP_ATOMIC); - if (ret < 0) - goto out; - } - - /* Submit CSW. */ - ret = usb_submit_urb(ushc->csw_urb, GFP_ATOMIC); - if (ret < 0) - goto out; - -out: - spin_unlock_irqrestore(&ushc->lock, flags); - if (ret < 0) { - usb_unlink_urb(ushc->cbw_urb); - usb_unlink_urb(ushc->data_urb); - req->cmd->error = ret; - mmc_request_done(mmc, req); - } -} - -static int ushc_set_power(struct ushc_data *ushc, unsigned char power_mode) -{ - u16 voltage; - - switch (power_mode) { - case MMC_POWER_OFF: - voltage = USHC_PWR_CTRL_OFF; - break; - case MMC_POWER_UP: - case MMC_POWER_ON: - voltage = USHC_PWR_CTRL_3V3; - break; - default: - return -EINVAL; - } - - return usb_control_msg(ushc->usb_dev, usb_sndctrlpipe(ushc->usb_dev, 0), - USHC_PWR_CTRL, USHC_PWR_CTRL_TYPE, - voltage, 0, NULL, 0, 100); -} - -static int ushc_set_bus_width(struct ushc_data *ushc, int bus_width) -{ - return ushc_hw_set_host_ctrl(ushc, USHC_HOST_CTRL_4BIT, - bus_width == 4 ? USHC_HOST_CTRL_4BIT : 0); -} - -static int ushc_set_bus_freq(struct ushc_data *ushc, int clk, bool enable_hs) -{ - int ret; - - /* Hardware can't detect interrupts while the clock is off. */ - if (clk == 0) - clk = 400000; - - ret = ushc_hw_set_host_ctrl(ushc, USHC_HOST_CTRL_HIGH_SPD, - enable_hs ? USHC_HOST_CTRL_HIGH_SPD : 0); - if (ret < 0) - return ret; - - ret = usb_control_msg(ushc->usb_dev, usb_sndctrlpipe(ushc->usb_dev, 0), - USHC_CLK_FREQ, USHC_CLK_FREQ_TYPE, - clk & 0xffff, (clk >> 16) & 0xffff, NULL, 0, 100); - if (ret < 0) - return ret; - - ushc->clock_freq = clk; - return 0; -} - -static void ushc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) -{ - struct ushc_data *ushc = mmc_priv(mmc); - - ushc_set_power(ushc, ios->power_mode); - ushc_set_bus_width(ushc, 1 << ios->bus_width); - ushc_set_bus_freq(ushc, ios->clock, ios->timing == MMC_TIMING_SD_HS); -} - -static int ushc_get_cd(struct mmc_host *mmc) -{ - struct ushc_data *ushc = mmc_priv(mmc); - - return !!(ushc->last_status & USHC_INT_STATUS_CARD_PRESENT); -} - -static void ushc_enable_sdio_irq(struct mmc_host *mmc, int enable) -{ - struct ushc_data *ushc = mmc_priv(mmc); - - if (enable) - set_bit(INT_EN, &ushc->flags); - else - clear_bit(INT_EN, &ushc->flags); -} - -static void ushc_clean_up(struct ushc_data *ushc) -{ - usb_free_urb(ushc->int_urb); - usb_free_urb(ushc->csw_urb); - usb_free_urb(ushc->data_urb); - usb_free_urb(ushc->cbw_urb); - - kfree(ushc->int_data); - kfree(ushc->cbw); - kfree(ushc->csw); - - mmc_free_host(ushc->mmc); -} - -static const struct mmc_host_ops ushc_ops = { - .request = ushc_request, - .set_ios = ushc_set_ios, - .get_cd = ushc_get_cd, - .enable_sdio_irq = ushc_enable_sdio_irq, -}; - -static int ushc_probe(struct usb_interface *intf, const struct usb_device_id *id) -{ - struct usb_device *usb_dev = interface_to_usbdev(intf); - struct mmc_host *mmc; - struct ushc_data *ushc; - int ret; - - mmc = mmc_alloc_host(sizeof(struct ushc_data), &intf->dev); - if (mmc == NULL) - return -ENOMEM; - ushc = mmc_priv(mmc); - usb_set_intfdata(intf, ushc); - - ushc->usb_dev = usb_dev; - ushc->mmc = mmc; - - spin_lock_init(&ushc->lock); - - ret = ushc_hw_reset(ushc); - if (ret < 0) - goto err; - - /* Read capabilities. */ - ret = ushc_hw_get_caps(ushc); - if (ret < 0) - goto err; - - mmc->ops = &ushc_ops; - - mmc->f_min = 400000; - mmc->f_max = 50000000; - mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; - mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ; - mmc->caps |= (ushc->caps & USHC_GET_CAPS_HIGH_SPD) ? MMC_CAP_SD_HIGHSPEED : 0; - - mmc->max_seg_size = 512*511; - mmc->max_segs = 1; - mmc->max_req_size = 512*511; - mmc->max_blk_size = 512; - mmc->max_blk_count = 511; - - ushc->int_urb = usb_alloc_urb(0, GFP_KERNEL); - if (ushc->int_urb == NULL) { - ret = -ENOMEM; - goto err; - } - ushc->int_data = kzalloc(sizeof(struct ushc_int_data), GFP_KERNEL); - if (ushc->int_data == NULL) { - ret = -ENOMEM; - goto err; - } - usb_fill_int_urb(ushc->int_urb, ushc->usb_dev, - usb_rcvintpipe(usb_dev, - intf->cur_altsetting->endpoint[0].desc.bEndpointAddress), - ushc->int_data, sizeof(struct ushc_int_data), - int_callback, ushc, - intf->cur_altsetting->endpoint[0].desc.bInterval); - - ushc->cbw_urb = usb_alloc_urb(0, GFP_KERNEL); - if (ushc->cbw_urb == NULL) { - ret = -ENOMEM; - goto err; - } - ushc->cbw = kzalloc(sizeof(struct ushc_cbw), GFP_KERNEL); - if (ushc->cbw == NULL) { - ret = -ENOMEM; - goto err; - } - ushc->cbw->signature = USHC_CBW_SIGNATURE; - - usb_fill_bulk_urb(ushc->cbw_urb, ushc->usb_dev, usb_sndbulkpipe(usb_dev, 2), - ushc->cbw, sizeof(struct ushc_cbw), - cbw_callback, ushc); - - ushc->data_urb = usb_alloc_urb(0, GFP_KERNEL); - if (ushc->data_urb == NULL) { - ret = -ENOMEM; - goto err; - } - - ushc->csw_urb = usb_alloc_urb(0, GFP_KERNEL); - if (ushc->csw_urb == NULL) { - ret = -ENOMEM; - goto err; - } - ushc->csw = kzalloc(sizeof(struct ushc_cbw), GFP_KERNEL); - if (ushc->csw == NULL) { - ret = -ENOMEM; - goto err; - } - usb_fill_bulk_urb(ushc->csw_urb, ushc->usb_dev, usb_rcvbulkpipe(usb_dev, 6), - ushc->csw, sizeof(struct ushc_csw), - csw_callback, ushc); - - ret = mmc_add_host(ushc->mmc); - if (ret) - goto err; - - ret = usb_submit_urb(ushc->int_urb, GFP_KERNEL); - if (ret < 0) { - mmc_remove_host(ushc->mmc); - goto err; - } - - return 0; - -err: - ushc_clean_up(ushc); - return ret; -} - -static void ushc_disconnect(struct usb_interface *intf) -{ - struct ushc_data *ushc = usb_get_intfdata(intf); - - spin_lock_irq(&ushc->lock); - set_bit(DISCONNECTED, &ushc->flags); - spin_unlock_irq(&ushc->lock); - - usb_kill_urb(ushc->int_urb); - usb_kill_urb(ushc->cbw_urb); - usb_kill_urb(ushc->data_urb); - usb_kill_urb(ushc->csw_urb); - - mmc_remove_host(ushc->mmc); - - ushc_clean_up(ushc); -} - -static struct usb_device_id ushc_id_table[] = { - /* CSR USB SD Host Controller */ - { USB_DEVICE(0x0a12, 0x5d10) }, - { }, -}; -MODULE_DEVICE_TABLE(usb, ushc_id_table); - -static struct usb_driver ushc_driver = { - .name = "ushc", - .id_table = ushc_id_table, - .probe = ushc_probe, - .disconnect = ushc_disconnect, -}; - -module_usb_driver(ushc_driver); - -MODULE_DESCRIPTION("USB SD Host Controller driver"); -MODULE_AUTHOR("David Vrabel <david.vrabel@csr.com>"); -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/mmc/host/via-sdmmc.c b/ANDROID_3.4.5/drivers/mmc/host/via-sdmmc.c deleted file mode 100644 index 4b83c43f..00000000 --- a/ANDROID_3.4.5/drivers/mmc/host/via-sdmmc.c +++ /dev/null @@ -1,1358 +0,0 @@ -/* - * drivers/mmc/host/via-sdmmc.c - VIA SD/MMC Card Reader driver - * Copyright (c) 2008, VIA Technologies Inc. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at - * your option) any later version. - */ - -#include <linux/pci.h> -#include <linux/module.h> -#include <linux/dma-mapping.h> -#include <linux/highmem.h> -#include <linux/delay.h> - -#include <linux/mmc/host.h> - -#define DRV_NAME "via_sdmmc" - -#define PCI_DEVICE_ID_VIA_9530 0x9530 - -#define VIA_CRDR_SDC_OFF 0x200 -#define VIA_CRDR_DDMA_OFF 0x400 -#define VIA_CRDR_PCICTRL_OFF 0x600 - -#define VIA_CRDR_MIN_CLOCK 375000 -#define VIA_CRDR_MAX_CLOCK 48000000 - -/* - * PCI registers - */ - -#define VIA_CRDR_PCI_WORK_MODE 0x40 -#define VIA_CRDR_PCI_DBG_MODE 0x41 - -/* - * SDC MMIO Registers - */ - -#define VIA_CRDR_SDCTRL 0x0 -#define VIA_CRDR_SDCTRL_START 0x01 -#define VIA_CRDR_SDCTRL_WRITE 0x04 -#define VIA_CRDR_SDCTRL_SINGLE_WR 0x10 -#define VIA_CRDR_SDCTRL_SINGLE_RD 0x20 -#define VIA_CRDR_SDCTRL_MULTI_WR 0x30 -#define VIA_CRDR_SDCTRL_MULTI_RD 0x40 -#define VIA_CRDR_SDCTRL_STOP 0x70 - -#define VIA_CRDR_SDCTRL_RSP_NONE 0x0 -#define VIA_CRDR_SDCTRL_RSP_R1 0x10000 -#define VIA_CRDR_SDCTRL_RSP_R2 0x20000 -#define VIA_CRDR_SDCTRL_RSP_R3 0x30000 -#define VIA_CRDR_SDCTRL_RSP_R1B 0x90000 - -#define VIA_CRDR_SDCARG 0x4 - -#define VIA_CRDR_SDBUSMODE 0x8 -#define VIA_CRDR_SDMODE_4BIT 0x02 -#define VIA_CRDR_SDMODE_CLK_ON 0x40 - -#define VIA_CRDR_SDBLKLEN 0xc -/* - * Bit 0 -Bit 10 : Block length. So, the maximum block length should be 2048. - * Bit 11 - Bit 13 : Reserved. - * GPIDET : Select GPI pin to detect card, GPI means CR_CD# in top design. - * INTEN : Enable SD host interrupt. - * Bit 16 - Bit 31 : Block count. So, the maximun block count should be 65536. - */ -#define VIA_CRDR_SDBLKLEN_GPIDET 0x2000 -#define VIA_CRDR_SDBLKLEN_INTEN 0x8000 -#define VIA_CRDR_MAX_BLOCK_COUNT 65536 -#define VIA_CRDR_MAX_BLOCK_LENGTH 2048 - -#define VIA_CRDR_SDRESP0 0x10 -#define VIA_CRDR_SDRESP1 0x14 -#define VIA_CRDR_SDRESP2 0x18 -#define VIA_CRDR_SDRESP3 0x1c - -#define VIA_CRDR_SDCURBLKCNT 0x20 - -#define VIA_CRDR_SDINTMASK 0x24 -/* - * MBDIE : Multiple Blocks transfer Done Interrupt Enable - * BDDIE : Block Data transfer Done Interrupt Enable - * CIRIE : Card Insertion or Removal Interrupt Enable - * CRDIE : Command-Response transfer Done Interrupt Enable - * CRTOIE : Command-Response response TimeOut Interrupt Enable - * ASCRDIE : Auto Stop Command-Response transfer Done Interrupt Enable - * DTIE : Data access Timeout Interrupt Enable - * SCIE : reSponse CRC error Interrupt Enable - * RCIE : Read data CRC error Interrupt Enable - * WCIE : Write data CRC error Interrupt Enable - */ -#define VIA_CRDR_SDINTMASK_MBDIE 0x10 -#define VIA_CRDR_SDINTMASK_BDDIE 0x20 -#define VIA_CRDR_SDINTMASK_CIRIE 0x80 -#define VIA_CRDR_SDINTMASK_CRDIE 0x200 -#define VIA_CRDR_SDINTMASK_CRTOIE 0x400 -#define VIA_CRDR_SDINTMASK_ASCRDIE 0x800 -#define VIA_CRDR_SDINTMASK_DTIE 0x1000 -#define VIA_CRDR_SDINTMASK_SCIE 0x2000 -#define VIA_CRDR_SDINTMASK_RCIE 0x4000 -#define VIA_CRDR_SDINTMASK_WCIE 0x8000 - -#define VIA_CRDR_SDACTIVE_INTMASK \ - (VIA_CRDR_SDINTMASK_MBDIE | VIA_CRDR_SDINTMASK_CIRIE \ - | VIA_CRDR_SDINTMASK_CRDIE | VIA_CRDR_SDINTMASK_CRTOIE \ - | VIA_CRDR_SDINTMASK_DTIE | VIA_CRDR_SDINTMASK_SCIE \ - | VIA_CRDR_SDINTMASK_RCIE | VIA_CRDR_SDINTMASK_WCIE) - -#define VIA_CRDR_SDSTATUS 0x28 -/* - * CECC : Reserved - * WP : SD card Write Protect status - * SLOTD : Reserved - * SLOTG : SD SLOT status(Gpi pin status) - * MBD : Multiple Blocks transfer Done interrupt status - * BDD : Block Data transfer Done interrupt status - * CD : Reserved - * CIR : Card Insertion or Removal interrupt detected on GPI pin - * IO : Reserved - * CRD : Command-Response transfer Done interrupt status - * CRTO : Command-Response response TimeOut interrupt status - * ASCRDIE : Auto Stop Command-Response transfer Done interrupt status - * DT : Data access Timeout interrupt status - * SC : reSponse CRC error interrupt status - * RC : Read data CRC error interrupt status - * WC : Write data CRC error interrupt status - */ -#define VIA_CRDR_SDSTS_CECC 0x01 -#define VIA_CRDR_SDSTS_WP 0x02 -#define VIA_CRDR_SDSTS_SLOTD 0x04 -#define VIA_CRDR_SDSTS_SLOTG 0x08 -#define VIA_CRDR_SDSTS_MBD 0x10 -#define VIA_CRDR_SDSTS_BDD 0x20 -#define VIA_CRDR_SDSTS_CD 0x40 -#define VIA_CRDR_SDSTS_CIR 0x80 -#define VIA_CRDR_SDSTS_IO 0x100 -#define VIA_CRDR_SDSTS_CRD 0x200 -#define VIA_CRDR_SDSTS_CRTO 0x400 -#define VIA_CRDR_SDSTS_ASCRDIE 0x800 -#define VIA_CRDR_SDSTS_DT 0x1000 -#define VIA_CRDR_SDSTS_SC 0x2000 -#define VIA_CRDR_SDSTS_RC 0x4000 -#define VIA_CRDR_SDSTS_WC 0x8000 - -#define VIA_CRDR_SDSTS_IGN_MASK\ - (VIA_CRDR_SDSTS_BDD | VIA_CRDR_SDSTS_ASCRDIE | VIA_CRDR_SDSTS_IO) -#define VIA_CRDR_SDSTS_INT_MASK \ - (VIA_CRDR_SDSTS_MBD | VIA_CRDR_SDSTS_BDD | VIA_CRDR_SDSTS_CD \ - | VIA_CRDR_SDSTS_CIR | VIA_CRDR_SDSTS_IO | VIA_CRDR_SDSTS_CRD \ - | VIA_CRDR_SDSTS_CRTO | VIA_CRDR_SDSTS_ASCRDIE | VIA_CRDR_SDSTS_DT \ - | VIA_CRDR_SDSTS_SC | VIA_CRDR_SDSTS_RC | VIA_CRDR_SDSTS_WC) -#define VIA_CRDR_SDSTS_W1C_MASK \ - (VIA_CRDR_SDSTS_CECC | VIA_CRDR_SDSTS_MBD | VIA_CRDR_SDSTS_BDD \ - | VIA_CRDR_SDSTS_CD | VIA_CRDR_SDSTS_CIR | VIA_CRDR_SDSTS_CRD \ - | VIA_CRDR_SDSTS_CRTO | VIA_CRDR_SDSTS_ASCRDIE | VIA_CRDR_SDSTS_DT \ - | VIA_CRDR_SDSTS_SC | VIA_CRDR_SDSTS_RC | VIA_CRDR_SDSTS_WC) -#define VIA_CRDR_SDSTS_CMD_MASK \ - (VIA_CRDR_SDSTS_CRD | VIA_CRDR_SDSTS_CRTO | VIA_CRDR_SDSTS_SC) -#define VIA_CRDR_SDSTS_DATA_MASK\ - (VIA_CRDR_SDSTS_MBD | VIA_CRDR_SDSTS_DT \ - | VIA_CRDR_SDSTS_RC | VIA_CRDR_SDSTS_WC) - -#define VIA_CRDR_SDSTATUS2 0x2a -/* - * CFE : Enable SD host automatic Clock FReezing - */ -#define VIA_CRDR_SDSTS_CFE 0x80 - -#define VIA_CRDR_SDRSPTMO 0x2C - -#define VIA_CRDR_SDCLKSEL 0x30 - -#define VIA_CRDR_SDEXTCTRL 0x34 -#define VIS_CRDR_SDEXTCTRL_AUTOSTOP_SD 0x01 -#define VIS_CRDR_SDEXTCTRL_SHIFT_9 0x02 -#define VIS_CRDR_SDEXTCTRL_MMC_8BIT 0x04 -#define VIS_CRDR_SDEXTCTRL_RELD_BLK 0x08 -#define VIS_CRDR_SDEXTCTRL_BAD_CMDA 0x10 -#define VIS_CRDR_SDEXTCTRL_BAD_DATA 0x20 -#define VIS_CRDR_SDEXTCTRL_AUTOSTOP_SPI 0x40 -#define VIA_CRDR_SDEXTCTRL_HISPD 0x80 -/* 0x38-0xFF reserved */ - -/* - * Data DMA Control Registers - */ - -#define VIA_CRDR_DMABASEADD 0x0 -#define VIA_CRDR_DMACOUNTER 0x4 - -#define VIA_CRDR_DMACTRL 0x8 -/* - * DIR :Transaction Direction - * 0 : From card to memory - * 1 : From memory to card - */ -#define VIA_CRDR_DMACTRL_DIR 0x100 -#define VIA_CRDR_DMACTRL_ENIRQ 0x10000 -#define VIA_CRDR_DMACTRL_SFTRST 0x1000000 - -#define VIA_CRDR_DMASTS 0xc - -#define VIA_CRDR_DMASTART 0x10 -/*0x14-0xFF reserved*/ - -/* - * PCI Control Registers - */ - -/*0x0 - 0x1 reserved*/ -#define VIA_CRDR_PCICLKGATT 0x2 -/* - * SFTRST : - * 0 : Soft reset all the controller and it will be de-asserted automatically - * 1 : Soft reset is de-asserted - */ -#define VIA_CRDR_PCICLKGATT_SFTRST 0x01 -/* - * 3V3 : Pad power select - * 0 : 1.8V - * 1 : 3.3V - * NOTE : No mater what the actual value should be, this bit always - * read as 0. This is a hardware bug. - */ -#define VIA_CRDR_PCICLKGATT_3V3 0x10 -/* - * PAD_PWRON : Pad Power on/off select - * 0 : Power off - * 1 : Power on - * NOTE : No mater what the actual value should be, this bit always - * read as 0. This is a hardware bug. - */ -#define VIA_CRDR_PCICLKGATT_PAD_PWRON 0x20 - -#define VIA_CRDR_PCISDCCLK 0x5 - -#define VIA_CRDR_PCIDMACLK 0x7 -#define VIA_CRDR_PCIDMACLK_SDC 0x2 - -#define VIA_CRDR_PCIINTCTRL 0x8 -#define VIA_CRDR_PCIINTCTRL_SDCIRQEN 0x04 - -#define VIA_CRDR_PCIINTSTATUS 0x9 -#define VIA_CRDR_PCIINTSTATUS_SDC 0x04 - -#define VIA_CRDR_PCITMOCTRL 0xa -#define VIA_CRDR_PCITMOCTRL_NO 0x0 -#define VIA_CRDR_PCITMOCTRL_32US 0x1 -#define VIA_CRDR_PCITMOCTRL_256US 0x2 -#define VIA_CRDR_PCITMOCTRL_1024US 0x3 -#define VIA_CRDR_PCITMOCTRL_256MS 0x4 -#define VIA_CRDR_PCITMOCTRL_512MS 0x5 -#define VIA_CRDR_PCITMOCTRL_1024MS 0x6 - -/*0xB-0xFF reserved*/ - -enum PCI_HOST_CLK_CONTROL { - PCI_CLK_375K = 0x03, - PCI_CLK_8M = 0x04, - PCI_CLK_12M = 0x00, - PCI_CLK_16M = 0x05, - PCI_CLK_24M = 0x01, - PCI_CLK_33M = 0x06, - PCI_CLK_48M = 0x02 -}; - -struct sdhcreg { - u32 sdcontrol_reg; - u32 sdcmdarg_reg; - u32 sdbusmode_reg; - u32 sdblklen_reg; - u32 sdresp_reg[4]; - u32 sdcurblkcnt_reg; - u32 sdintmask_reg; - u32 sdstatus_reg; - u32 sdrsptmo_reg; - u32 sdclksel_reg; - u32 sdextctrl_reg; -}; - -struct pcictrlreg { - u8 reserve[2]; - u8 pciclkgat_reg; - u8 pcinfcclk_reg; - u8 pcimscclk_reg; - u8 pcisdclk_reg; - u8 pcicaclk_reg; - u8 pcidmaclk_reg; - u8 pciintctrl_reg; - u8 pciintstatus_reg; - u8 pcitmoctrl_reg; - u8 Resv; -}; - -struct via_crdr_mmc_host { - struct mmc_host *mmc; - struct mmc_request *mrq; - struct mmc_command *cmd; - struct mmc_data *data; - - void __iomem *mmiobase; - void __iomem *sdhc_mmiobase; - void __iomem *ddma_mmiobase; - void __iomem *pcictrl_mmiobase; - - struct pcictrlreg pm_pcictrl_reg; - struct sdhcreg pm_sdhc_reg; - - struct work_struct carddet_work; - struct tasklet_struct finish_tasklet; - - struct timer_list timer; - spinlock_t lock; - u8 power; - int reject; - unsigned int quirks; -}; - -/* some devices need a very long delay for power to stabilize */ -#define VIA_CRDR_QUIRK_300MS_PWRDELAY 0x0001 - -static struct pci_device_id via_ids[] = { - {PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_9530, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0,}, - {0,} -}; - -MODULE_DEVICE_TABLE(pci, via_ids); - -static void via_print_sdchc(struct via_crdr_mmc_host *host) -{ - void __iomem *addrbase = host->sdhc_mmiobase; - - pr_debug("SDC MMIO Registers:\n"); - pr_debug("SDCONTROL=%08x, SDCMDARG=%08x, SDBUSMODE=%08x\n", - readl(addrbase + VIA_CRDR_SDCTRL), - readl(addrbase + VIA_CRDR_SDCARG), - readl(addrbase + VIA_CRDR_SDBUSMODE)); - pr_debug("SDBLKLEN=%08x, SDCURBLKCNT=%08x, SDINTMASK=%08x\n", - readl(addrbase + VIA_CRDR_SDBLKLEN), - readl(addrbase + VIA_CRDR_SDCURBLKCNT), - readl(addrbase + VIA_CRDR_SDINTMASK)); - pr_debug("SDSTATUS=%08x, SDCLKSEL=%08x, SDEXTCTRL=%08x\n", - readl(addrbase + VIA_CRDR_SDSTATUS), - readl(addrbase + VIA_CRDR_SDCLKSEL), - readl(addrbase + VIA_CRDR_SDEXTCTRL)); -} - -static void via_print_pcictrl(struct via_crdr_mmc_host *host) -{ - void __iomem *addrbase = host->pcictrl_mmiobase; - - pr_debug("PCI Control Registers:\n"); - pr_debug("PCICLKGATT=%02x, PCISDCCLK=%02x, PCIDMACLK=%02x\n", - readb(addrbase + VIA_CRDR_PCICLKGATT), - readb(addrbase + VIA_CRDR_PCISDCCLK), - readb(addrbase + VIA_CRDR_PCIDMACLK)); - pr_debug("PCIINTCTRL=%02x, PCIINTSTATUS=%02x\n", - readb(addrbase + VIA_CRDR_PCIINTCTRL), - readb(addrbase + VIA_CRDR_PCIINTSTATUS)); -} - -static void via_save_pcictrlreg(struct via_crdr_mmc_host *host) -{ - struct pcictrlreg *pm_pcictrl_reg; - void __iomem *addrbase; - - pm_pcictrl_reg = &(host->pm_pcictrl_reg); - addrbase = host->pcictrl_mmiobase; - - pm_pcictrl_reg->pciclkgat_reg = readb(addrbase + VIA_CRDR_PCICLKGATT); - pm_pcictrl_reg->pciclkgat_reg |= - VIA_CRDR_PCICLKGATT_3V3 | VIA_CRDR_PCICLKGATT_PAD_PWRON; - pm_pcictrl_reg->pcisdclk_reg = readb(addrbase + VIA_CRDR_PCISDCCLK); - pm_pcictrl_reg->pcidmaclk_reg = readb(addrbase + VIA_CRDR_PCIDMACLK); - pm_pcictrl_reg->pciintctrl_reg = readb(addrbase + VIA_CRDR_PCIINTCTRL); - pm_pcictrl_reg->pciintstatus_reg = - readb(addrbase + VIA_CRDR_PCIINTSTATUS); - pm_pcictrl_reg->pcitmoctrl_reg = readb(addrbase + VIA_CRDR_PCITMOCTRL); -} - -static void via_restore_pcictrlreg(struct via_crdr_mmc_host *host) -{ - struct pcictrlreg *pm_pcictrl_reg; - void __iomem *addrbase; - - pm_pcictrl_reg = &(host->pm_pcictrl_reg); - addrbase = host->pcictrl_mmiobase; - - writeb(pm_pcictrl_reg->pciclkgat_reg, addrbase + VIA_CRDR_PCICLKGATT); - writeb(pm_pcictrl_reg->pcisdclk_reg, addrbase + VIA_CRDR_PCISDCCLK); - writeb(pm_pcictrl_reg->pcidmaclk_reg, addrbase + VIA_CRDR_PCIDMACLK); - writeb(pm_pcictrl_reg->pciintctrl_reg, addrbase + VIA_CRDR_PCIINTCTRL); - writeb(pm_pcictrl_reg->pciintstatus_reg, - addrbase + VIA_CRDR_PCIINTSTATUS); - writeb(pm_pcictrl_reg->pcitmoctrl_reg, addrbase + VIA_CRDR_PCITMOCTRL); -} - -static void via_save_sdcreg(struct via_crdr_mmc_host *host) -{ - struct sdhcreg *pm_sdhc_reg; - void __iomem *addrbase; - - pm_sdhc_reg = &(host->pm_sdhc_reg); - addrbase = host->sdhc_mmiobase; - - pm_sdhc_reg->sdcontrol_reg = readl(addrbase + VIA_CRDR_SDCTRL); - pm_sdhc_reg->sdcmdarg_reg = readl(addrbase + VIA_CRDR_SDCARG); - pm_sdhc_reg->sdbusmode_reg = readl(addrbase + VIA_CRDR_SDBUSMODE); - pm_sdhc_reg->sdblklen_reg = readl(addrbase + VIA_CRDR_SDBLKLEN); - pm_sdhc_reg->sdcurblkcnt_reg = readl(addrbase + VIA_CRDR_SDCURBLKCNT); - pm_sdhc_reg->sdintmask_reg = readl(addrbase + VIA_CRDR_SDINTMASK); - pm_sdhc_reg->sdstatus_reg = readl(addrbase + VIA_CRDR_SDSTATUS); - pm_sdhc_reg->sdrsptmo_reg = readl(addrbase + VIA_CRDR_SDRSPTMO); - pm_sdhc_reg->sdclksel_reg = readl(addrbase + VIA_CRDR_SDCLKSEL); - pm_sdhc_reg->sdextctrl_reg = readl(addrbase + VIA_CRDR_SDEXTCTRL); -} - -static void via_restore_sdcreg(struct via_crdr_mmc_host *host) -{ - struct sdhcreg *pm_sdhc_reg; - void __iomem *addrbase; - - pm_sdhc_reg = &(host->pm_sdhc_reg); - addrbase = host->sdhc_mmiobase; - - writel(pm_sdhc_reg->sdcontrol_reg, addrbase + VIA_CRDR_SDCTRL); - writel(pm_sdhc_reg->sdcmdarg_reg, addrbase + VIA_CRDR_SDCARG); - writel(pm_sdhc_reg->sdbusmode_reg, addrbase + VIA_CRDR_SDBUSMODE); - writel(pm_sdhc_reg->sdblklen_reg, addrbase + VIA_CRDR_SDBLKLEN); - writel(pm_sdhc_reg->sdcurblkcnt_reg, addrbase + VIA_CRDR_SDCURBLKCNT); - writel(pm_sdhc_reg->sdintmask_reg, addrbase + VIA_CRDR_SDINTMASK); - writel(pm_sdhc_reg->sdstatus_reg, addrbase + VIA_CRDR_SDSTATUS); - writel(pm_sdhc_reg->sdrsptmo_reg, addrbase + VIA_CRDR_SDRSPTMO); - writel(pm_sdhc_reg->sdclksel_reg, addrbase + VIA_CRDR_SDCLKSEL); - writel(pm_sdhc_reg->sdextctrl_reg, addrbase + VIA_CRDR_SDEXTCTRL); -} - -static void via_pwron_sleep(struct via_crdr_mmc_host *sdhost) -{ - if (sdhost->quirks & VIA_CRDR_QUIRK_300MS_PWRDELAY) - msleep(300); - else - msleep(3); -} - -static void via_set_ddma(struct via_crdr_mmc_host *host, - dma_addr_t dmaaddr, u32 count, int dir, int enirq) -{ - void __iomem *addrbase; - u32 ctrl_data = 0; - - if (enirq) - ctrl_data |= VIA_CRDR_DMACTRL_ENIRQ; - - if (dir) - ctrl_data |= VIA_CRDR_DMACTRL_DIR; - - addrbase = host->ddma_mmiobase; - - writel(dmaaddr, addrbase + VIA_CRDR_DMABASEADD); - writel(count, addrbase + VIA_CRDR_DMACOUNTER); - writel(ctrl_data, addrbase + VIA_CRDR_DMACTRL); - writel(0x01, addrbase + VIA_CRDR_DMASTART); - - /* It seems that our DMA can not work normally with 375kHz clock */ - /* FIXME: don't brute-force 8MHz but use PIO at 375kHz !! */ - addrbase = host->pcictrl_mmiobase; - if (readb(addrbase + VIA_CRDR_PCISDCCLK) == PCI_CLK_375K) { - dev_info(host->mmc->parent, "forcing card speed to 8MHz\n"); - writeb(PCI_CLK_8M, addrbase + VIA_CRDR_PCISDCCLK); - } -} - -static void via_sdc_preparedata(struct via_crdr_mmc_host *host, - struct mmc_data *data) -{ - void __iomem *addrbase; - u32 blk_reg; - int count; - - WARN_ON(host->data); - - /* Sanity checks */ - BUG_ON(data->blksz > host->mmc->max_blk_size); - BUG_ON(data->blocks > host->mmc->max_blk_count); - - host->data = data; - - count = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len, - ((data->flags & MMC_DATA_READ) ? - PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE)); - BUG_ON(count != 1); - - via_set_ddma(host, sg_dma_address(data->sg), sg_dma_len(data->sg), - (data->flags & MMC_DATA_WRITE) ? 1 : 0, 1); - - addrbase = host->sdhc_mmiobase; - - blk_reg = data->blksz - 1; - blk_reg |= VIA_CRDR_SDBLKLEN_GPIDET | VIA_CRDR_SDBLKLEN_INTEN; - blk_reg |= (data->blocks) << 16; - - writel(blk_reg, addrbase + VIA_CRDR_SDBLKLEN); -} - -static void via_sdc_get_response(struct via_crdr_mmc_host *host, - struct mmc_command *cmd) -{ - void __iomem *addrbase = host->sdhc_mmiobase; - u32 dwdata0 = readl(addrbase + VIA_CRDR_SDRESP0); - u32 dwdata1 = readl(addrbase + VIA_CRDR_SDRESP1); - u32 dwdata2 = readl(addrbase + VIA_CRDR_SDRESP2); - u32 dwdata3 = readl(addrbase + VIA_CRDR_SDRESP3); - - if (cmd->flags & MMC_RSP_136) { - cmd->resp[0] = ((u8) (dwdata1)) | - (((u8) (dwdata0 >> 24)) << 8) | - (((u8) (dwdata0 >> 16)) << 16) | - (((u8) (dwdata0 >> 8)) << 24); - - cmd->resp[1] = ((u8) (dwdata2)) | - (((u8) (dwdata1 >> 24)) << 8) | - (((u8) (dwdata1 >> 16)) << 16) | - (((u8) (dwdata1 >> 8)) << 24); - - cmd->resp[2] = ((u8) (dwdata3)) | - (((u8) (dwdata2 >> 24)) << 8) | - (((u8) (dwdata2 >> 16)) << 16) | - (((u8) (dwdata2 >> 8)) << 24); - - cmd->resp[3] = 0xff | - ((((u8) (dwdata3 >> 24))) << 8) | - (((u8) (dwdata3 >> 16)) << 16) | - (((u8) (dwdata3 >> 8)) << 24); - } else { - dwdata0 >>= 8; - cmd->resp[0] = ((dwdata0 & 0xff) << 24) | - (((dwdata0 >> 8) & 0xff) << 16) | - (((dwdata0 >> 16) & 0xff) << 8) | (dwdata1 & 0xff); - - dwdata1 >>= 8; - cmd->resp[1] = ((dwdata1 & 0xff) << 24) | - (((dwdata1 >> 8) & 0xff) << 16) | - (((dwdata1 >> 16) & 0xff) << 8); - } -} - -static void via_sdc_send_command(struct via_crdr_mmc_host *host, - struct mmc_command *cmd) -{ - void __iomem *addrbase; - struct mmc_data *data; - u32 cmdctrl = 0; - - WARN_ON(host->cmd); - - data = cmd->data; - mod_timer(&host->timer, jiffies + HZ); - host->cmd = cmd; - - /*Command index*/ - cmdctrl = cmd->opcode << 8; - - /*Response type*/ - switch (mmc_resp_type(cmd)) { - case MMC_RSP_NONE: - cmdctrl |= VIA_CRDR_SDCTRL_RSP_NONE; - break; - case MMC_RSP_R1: - cmdctrl |= VIA_CRDR_SDCTRL_RSP_R1; - break; - case MMC_RSP_R1B: - cmdctrl |= VIA_CRDR_SDCTRL_RSP_R1B; - break; - case MMC_RSP_R2: - cmdctrl |= VIA_CRDR_SDCTRL_RSP_R2; - break; - case MMC_RSP_R3: - cmdctrl |= VIA_CRDR_SDCTRL_RSP_R3; - break; - default: - pr_err("%s: cmd->flag is not valid\n", mmc_hostname(host->mmc)); - break; - } - - if (!(cmd->data)) - goto nodata; - - via_sdc_preparedata(host, data); - - /*Command control*/ - if (data->blocks > 1) { - if (data->flags & MMC_DATA_WRITE) { - cmdctrl |= VIA_CRDR_SDCTRL_WRITE; - cmdctrl |= VIA_CRDR_SDCTRL_MULTI_WR; - } else { - cmdctrl |= VIA_CRDR_SDCTRL_MULTI_RD; - } - } else { - if (data->flags & MMC_DATA_WRITE) { - cmdctrl |= VIA_CRDR_SDCTRL_WRITE; - cmdctrl |= VIA_CRDR_SDCTRL_SINGLE_WR; - } else { - cmdctrl |= VIA_CRDR_SDCTRL_SINGLE_RD; - } - } - -nodata: - if (cmd == host->mrq->stop) - cmdctrl |= VIA_CRDR_SDCTRL_STOP; - - cmdctrl |= VIA_CRDR_SDCTRL_START; - - addrbase = host->sdhc_mmiobase; - writel(cmd->arg, addrbase + VIA_CRDR_SDCARG); - writel(cmdctrl, addrbase + VIA_CRDR_SDCTRL); -} - -static void via_sdc_finish_data(struct via_crdr_mmc_host *host) -{ - struct mmc_data *data; - - BUG_ON(!host->data); - - data = host->data; - host->data = NULL; - - if (data->error) - data->bytes_xfered = 0; - else - data->bytes_xfered = data->blocks * data->blksz; - - dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len, - ((data->flags & MMC_DATA_READ) ? - PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE)); - - if (data->stop) - via_sdc_send_command(host, data->stop); - else - tasklet_schedule(&host->finish_tasklet); -} - -static void via_sdc_finish_command(struct via_crdr_mmc_host *host) -{ - via_sdc_get_response(host, host->cmd); - - host->cmd->error = 0; - - if (!host->cmd->data) - tasklet_schedule(&host->finish_tasklet); - - host->cmd = NULL; -} - -static void via_sdc_request(struct mmc_host *mmc, struct mmc_request *mrq) -{ - void __iomem *addrbase; - struct via_crdr_mmc_host *host; - unsigned long flags; - u16 status; - - host = mmc_priv(mmc); - - spin_lock_irqsave(&host->lock, flags); - - addrbase = host->pcictrl_mmiobase; - writeb(VIA_CRDR_PCIDMACLK_SDC, addrbase + VIA_CRDR_PCIDMACLK); - - status = readw(host->sdhc_mmiobase + VIA_CRDR_SDSTATUS); - status &= VIA_CRDR_SDSTS_W1C_MASK; - writew(status, host->sdhc_mmiobase + VIA_CRDR_SDSTATUS); - - WARN_ON(host->mrq != NULL); - host->mrq = mrq; - - status = readw(host->sdhc_mmiobase + VIA_CRDR_SDSTATUS); - if (!(status & VIA_CRDR_SDSTS_SLOTG) || host->reject) { - host->mrq->cmd->error = -ENOMEDIUM; - tasklet_schedule(&host->finish_tasklet); - } else { - via_sdc_send_command(host, mrq->cmd); - } - - mmiowb(); - spin_unlock_irqrestore(&host->lock, flags); -} - -static void via_sdc_set_power(struct via_crdr_mmc_host *host, - unsigned short power, unsigned int on) -{ - unsigned long flags; - u8 gatt; - - spin_lock_irqsave(&host->lock, flags); - - host->power = (1 << power); - - gatt = readb(host->pcictrl_mmiobase + VIA_CRDR_PCICLKGATT); - if (host->power == MMC_VDD_165_195) - gatt &= ~VIA_CRDR_PCICLKGATT_3V3; - else - gatt |= VIA_CRDR_PCICLKGATT_3V3; - if (on) - gatt |= VIA_CRDR_PCICLKGATT_PAD_PWRON; - else - gatt &= ~VIA_CRDR_PCICLKGATT_PAD_PWRON; - writeb(gatt, host->pcictrl_mmiobase + VIA_CRDR_PCICLKGATT); - - mmiowb(); - spin_unlock_irqrestore(&host->lock, flags); - - via_pwron_sleep(host); -} - -static void via_sdc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) -{ - struct via_crdr_mmc_host *host; - unsigned long flags; - void __iomem *addrbase; - u32 org_data, sdextctrl; - u8 clock; - - host = mmc_priv(mmc); - - spin_lock_irqsave(&host->lock, flags); - - addrbase = host->sdhc_mmiobase; - org_data = readl(addrbase + VIA_CRDR_SDBUSMODE); - sdextctrl = readl(addrbase + VIA_CRDR_SDEXTCTRL); - - if (ios->bus_width == MMC_BUS_WIDTH_1) - org_data &= ~VIA_CRDR_SDMODE_4BIT; - else - org_data |= VIA_CRDR_SDMODE_4BIT; - - if (ios->power_mode == MMC_POWER_OFF) - org_data &= ~VIA_CRDR_SDMODE_CLK_ON; - else - org_data |= VIA_CRDR_SDMODE_CLK_ON; - - if (ios->timing == MMC_TIMING_SD_HS) - sdextctrl |= VIA_CRDR_SDEXTCTRL_HISPD; - else - sdextctrl &= ~VIA_CRDR_SDEXTCTRL_HISPD; - - writel(org_data, addrbase + VIA_CRDR_SDBUSMODE); - writel(sdextctrl, addrbase + VIA_CRDR_SDEXTCTRL); - - if (ios->clock >= 48000000) - clock = PCI_CLK_48M; - else if (ios->clock >= 33000000) - clock = PCI_CLK_33M; - else if (ios->clock >= 24000000) - clock = PCI_CLK_24M; - else if (ios->clock >= 16000000) - clock = PCI_CLK_16M; - else if (ios->clock >= 12000000) - clock = PCI_CLK_12M; - else if (ios->clock >= 8000000) - clock = PCI_CLK_8M; - else - clock = PCI_CLK_375K; - - addrbase = host->pcictrl_mmiobase; - if (readb(addrbase + VIA_CRDR_PCISDCCLK) != clock) - writeb(clock, addrbase + VIA_CRDR_PCISDCCLK); - - mmiowb(); - spin_unlock_irqrestore(&host->lock, flags); - - if (ios->power_mode != MMC_POWER_OFF) - via_sdc_set_power(host, ios->vdd, 1); - else - via_sdc_set_power(host, ios->vdd, 0); -} - -static int via_sdc_get_ro(struct mmc_host *mmc) -{ - struct via_crdr_mmc_host *host; - unsigned long flags; - u16 status; - - host = mmc_priv(mmc); - - spin_lock_irqsave(&host->lock, flags); - - status = readw(host->sdhc_mmiobase + VIA_CRDR_SDSTATUS); - - spin_unlock_irqrestore(&host->lock, flags); - - return !(status & VIA_CRDR_SDSTS_WP); -} - -static const struct mmc_host_ops via_sdc_ops = { - .request = via_sdc_request, - .set_ios = via_sdc_set_ios, - .get_ro = via_sdc_get_ro, -}; - -static void via_reset_pcictrl(struct via_crdr_mmc_host *host) -{ - unsigned long flags; - u8 gatt; - - spin_lock_irqsave(&host->lock, flags); - - via_save_pcictrlreg(host); - via_save_sdcreg(host); - - spin_unlock_irqrestore(&host->lock, flags); - - gatt = VIA_CRDR_PCICLKGATT_PAD_PWRON; - if (host->power == MMC_VDD_165_195) - gatt &= VIA_CRDR_PCICLKGATT_3V3; - else - gatt |= VIA_CRDR_PCICLKGATT_3V3; - writeb(gatt, host->pcictrl_mmiobase + VIA_CRDR_PCICLKGATT); - via_pwron_sleep(host); - gatt |= VIA_CRDR_PCICLKGATT_SFTRST; - writeb(gatt, host->pcictrl_mmiobase + VIA_CRDR_PCICLKGATT); - msleep(3); - - spin_lock_irqsave(&host->lock, flags); - - via_restore_pcictrlreg(host); - via_restore_sdcreg(host); - - mmiowb(); - spin_unlock_irqrestore(&host->lock, flags); -} - -static void via_sdc_cmd_isr(struct via_crdr_mmc_host *host, u16 intmask) -{ - BUG_ON(intmask == 0); - - if (!host->cmd) { - pr_err("%s: Got command interrupt 0x%x even " - "though no command operation was in progress.\n", - mmc_hostname(host->mmc), intmask); - return; - } - - if (intmask & VIA_CRDR_SDSTS_CRTO) - host->cmd->error = -ETIMEDOUT; - else if (intmask & VIA_CRDR_SDSTS_SC) - host->cmd->error = -EILSEQ; - - if (host->cmd->error) - tasklet_schedule(&host->finish_tasklet); - else if (intmask & VIA_CRDR_SDSTS_CRD) - via_sdc_finish_command(host); -} - -static void via_sdc_data_isr(struct via_crdr_mmc_host *host, u16 intmask) -{ - BUG_ON(intmask == 0); - - if (intmask & VIA_CRDR_SDSTS_DT) - host->data->error = -ETIMEDOUT; - else if (intmask & (VIA_CRDR_SDSTS_RC | VIA_CRDR_SDSTS_WC)) - host->data->error = -EILSEQ; - - via_sdc_finish_data(host); -} - -static irqreturn_t via_sdc_isr(int irq, void *dev_id) -{ - struct via_crdr_mmc_host *sdhost = dev_id; - void __iomem *addrbase; - u8 pci_status; - u16 sd_status; - irqreturn_t result; - - if (!sdhost) - return IRQ_NONE; - - spin_lock(&sdhost->lock); - - addrbase = sdhost->pcictrl_mmiobase; - pci_status = readb(addrbase + VIA_CRDR_PCIINTSTATUS); - if (!(pci_status & VIA_CRDR_PCIINTSTATUS_SDC)) { - result = IRQ_NONE; - goto out; - } - - addrbase = sdhost->sdhc_mmiobase; - sd_status = readw(addrbase + VIA_CRDR_SDSTATUS); - sd_status &= VIA_CRDR_SDSTS_INT_MASK; - sd_status &= ~VIA_CRDR_SDSTS_IGN_MASK; - if (!sd_status) { - result = IRQ_NONE; - goto out; - } - - if (sd_status & VIA_CRDR_SDSTS_CIR) { - writew(sd_status & VIA_CRDR_SDSTS_CIR, - addrbase + VIA_CRDR_SDSTATUS); - - schedule_work(&sdhost->carddet_work); - } - - sd_status &= ~VIA_CRDR_SDSTS_CIR; - if (sd_status & VIA_CRDR_SDSTS_CMD_MASK) { - writew(sd_status & VIA_CRDR_SDSTS_CMD_MASK, - addrbase + VIA_CRDR_SDSTATUS); - via_sdc_cmd_isr(sdhost, sd_status & VIA_CRDR_SDSTS_CMD_MASK); - } - if (sd_status & VIA_CRDR_SDSTS_DATA_MASK) { - writew(sd_status & VIA_CRDR_SDSTS_DATA_MASK, - addrbase + VIA_CRDR_SDSTATUS); - via_sdc_data_isr(sdhost, sd_status & VIA_CRDR_SDSTS_DATA_MASK); - } - - sd_status &= ~(VIA_CRDR_SDSTS_CMD_MASK | VIA_CRDR_SDSTS_DATA_MASK); - if (sd_status) { - pr_err("%s: Unexpected interrupt 0x%x\n", - mmc_hostname(sdhost->mmc), sd_status); - writew(sd_status, addrbase + VIA_CRDR_SDSTATUS); - } - - result = IRQ_HANDLED; - - mmiowb(); -out: - spin_unlock(&sdhost->lock); - - return result; -} - -static void via_sdc_timeout(unsigned long ulongdata) -{ - struct via_crdr_mmc_host *sdhost; - unsigned long flags; - - sdhost = (struct via_crdr_mmc_host *)ulongdata; - - spin_lock_irqsave(&sdhost->lock, flags); - - if (sdhost->mrq) { - pr_err("%s: Timeout waiting for hardware interrupt." - "cmd:0x%x\n", mmc_hostname(sdhost->mmc), - sdhost->mrq->cmd->opcode); - - if (sdhost->data) { - writel(VIA_CRDR_DMACTRL_SFTRST, - sdhost->ddma_mmiobase + VIA_CRDR_DMACTRL); - sdhost->data->error = -ETIMEDOUT; - via_sdc_finish_data(sdhost); - } else { - if (sdhost->cmd) - sdhost->cmd->error = -ETIMEDOUT; - else - sdhost->mrq->cmd->error = -ETIMEDOUT; - tasklet_schedule(&sdhost->finish_tasklet); - } - } - - mmiowb(); - spin_unlock_irqrestore(&sdhost->lock, flags); -} - -static void via_sdc_tasklet_finish(unsigned long param) -{ - struct via_crdr_mmc_host *host; - unsigned long flags; - struct mmc_request *mrq; - - host = (struct via_crdr_mmc_host *)param; - - spin_lock_irqsave(&host->lock, flags); - - del_timer(&host->timer); - mrq = host->mrq; - host->mrq = NULL; - host->cmd = NULL; - host->data = NULL; - - spin_unlock_irqrestore(&host->lock, flags); - - mmc_request_done(host->mmc, mrq); -} - -static void via_sdc_card_detect(struct work_struct *work) -{ - struct via_crdr_mmc_host *host; - void __iomem *addrbase; - unsigned long flags; - u16 status; - - host = container_of(work, struct via_crdr_mmc_host, carddet_work); - - addrbase = host->ddma_mmiobase; - writel(VIA_CRDR_DMACTRL_SFTRST, addrbase + VIA_CRDR_DMACTRL); - - spin_lock_irqsave(&host->lock, flags); - - addrbase = host->pcictrl_mmiobase; - writeb(VIA_CRDR_PCIDMACLK_SDC, addrbase + VIA_CRDR_PCIDMACLK); - - addrbase = host->sdhc_mmiobase; - status = readw(addrbase + VIA_CRDR_SDSTATUS); - if (!(status & VIA_CRDR_SDSTS_SLOTG)) { - if (host->mrq) { - pr_err("%s: Card removed during transfer!\n", - mmc_hostname(host->mmc)); - host->mrq->cmd->error = -ENOMEDIUM; - tasklet_schedule(&host->finish_tasklet); - } - - mmiowb(); - spin_unlock_irqrestore(&host->lock, flags); - - via_reset_pcictrl(host); - - spin_lock_irqsave(&host->lock, flags); - } - - mmiowb(); - spin_unlock_irqrestore(&host->lock, flags); - - via_print_pcictrl(host); - via_print_sdchc(host); - - mmc_detect_change(host->mmc, msecs_to_jiffies(500)); -} - -static void via_init_mmc_host(struct via_crdr_mmc_host *host) -{ - struct mmc_host *mmc = host->mmc; - void __iomem *addrbase; - u32 lenreg; - u32 status; - - init_timer(&host->timer); - host->timer.data = (unsigned long)host; - host->timer.function = via_sdc_timeout; - - spin_lock_init(&host->lock); - - mmc->f_min = VIA_CRDR_MIN_CLOCK; - mmc->f_max = VIA_CRDR_MAX_CLOCK; - mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195; - mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SD_HIGHSPEED; - mmc->ops = &via_sdc_ops; - - /*Hardware cannot do scatter lists*/ - mmc->max_segs = 1; - - mmc->max_blk_size = VIA_CRDR_MAX_BLOCK_LENGTH; - mmc->max_blk_count = VIA_CRDR_MAX_BLOCK_COUNT; - - mmc->max_seg_size = mmc->max_blk_size * mmc->max_blk_count; - mmc->max_req_size = mmc->max_seg_size; - - INIT_WORK(&host->carddet_work, via_sdc_card_detect); - - tasklet_init(&host->finish_tasklet, via_sdc_tasklet_finish, - (unsigned long)host); - - addrbase = host->sdhc_mmiobase; - writel(0x0, addrbase + VIA_CRDR_SDINTMASK); - msleep(1); - - lenreg = VIA_CRDR_SDBLKLEN_GPIDET | VIA_CRDR_SDBLKLEN_INTEN; - writel(lenreg, addrbase + VIA_CRDR_SDBLKLEN); - - status = readw(addrbase + VIA_CRDR_SDSTATUS); - status &= VIA_CRDR_SDSTS_W1C_MASK; - writew(status, addrbase + VIA_CRDR_SDSTATUS); - - status = readw(addrbase + VIA_CRDR_SDSTATUS2); - status |= VIA_CRDR_SDSTS_CFE; - writew(status, addrbase + VIA_CRDR_SDSTATUS2); - - writeb(0x0, addrbase + VIA_CRDR_SDEXTCTRL); - - writel(VIA_CRDR_SDACTIVE_INTMASK, addrbase + VIA_CRDR_SDINTMASK); - msleep(1); -} - -static int __devinit via_sd_probe(struct pci_dev *pcidev, - const struct pci_device_id *id) -{ - struct mmc_host *mmc; - struct via_crdr_mmc_host *sdhost; - u32 base, len; - u8 gatt; - int ret; - - pr_info(DRV_NAME - ": VIA SDMMC controller found at %s [%04x:%04x] (rev %x)\n", - pci_name(pcidev), (int)pcidev->vendor, (int)pcidev->device, - (int)pcidev->revision); - - ret = pci_enable_device(pcidev); - if (ret) - return ret; - - ret = pci_request_regions(pcidev, DRV_NAME); - if (ret) - goto disable; - - pci_write_config_byte(pcidev, VIA_CRDR_PCI_WORK_MODE, 0); - pci_write_config_byte(pcidev, VIA_CRDR_PCI_DBG_MODE, 0); - - mmc = mmc_alloc_host(sizeof(struct via_crdr_mmc_host), &pcidev->dev); - if (!mmc) { - ret = -ENOMEM; - goto release; - } - - sdhost = mmc_priv(mmc); - sdhost->mmc = mmc; - dev_set_drvdata(&pcidev->dev, sdhost); - - len = pci_resource_len(pcidev, 0); - base = pci_resource_start(pcidev, 0); - sdhost->mmiobase = ioremap_nocache(base, len); - if (!sdhost->mmiobase) { - ret = -ENOMEM; - goto free_mmc_host; - } - - sdhost->sdhc_mmiobase = - sdhost->mmiobase + VIA_CRDR_SDC_OFF; - sdhost->ddma_mmiobase = - sdhost->mmiobase + VIA_CRDR_DDMA_OFF; - sdhost->pcictrl_mmiobase = - sdhost->mmiobase + VIA_CRDR_PCICTRL_OFF; - - sdhost->power = MMC_VDD_165_195; - - gatt = VIA_CRDR_PCICLKGATT_3V3 | VIA_CRDR_PCICLKGATT_PAD_PWRON; - writeb(gatt, sdhost->pcictrl_mmiobase + VIA_CRDR_PCICLKGATT); - via_pwron_sleep(sdhost); - gatt |= VIA_CRDR_PCICLKGATT_SFTRST; - writeb(gatt, sdhost->pcictrl_mmiobase + VIA_CRDR_PCICLKGATT); - msleep(3); - - via_init_mmc_host(sdhost); - - ret = - request_irq(pcidev->irq, via_sdc_isr, IRQF_SHARED, DRV_NAME, - sdhost); - if (ret) - goto unmap; - - writeb(VIA_CRDR_PCIINTCTRL_SDCIRQEN, - sdhost->pcictrl_mmiobase + VIA_CRDR_PCIINTCTRL); - writeb(VIA_CRDR_PCITMOCTRL_1024MS, - sdhost->pcictrl_mmiobase + VIA_CRDR_PCITMOCTRL); - - /* device-specific quirks */ - if (pcidev->subsystem_vendor == PCI_VENDOR_ID_LENOVO && - pcidev->subsystem_device == 0x3891) - sdhost->quirks = VIA_CRDR_QUIRK_300MS_PWRDELAY; - - mmc_add_host(mmc); - - return 0; - -unmap: - iounmap(sdhost->mmiobase); -free_mmc_host: - dev_set_drvdata(&pcidev->dev, NULL); - mmc_free_host(mmc); -release: - pci_release_regions(pcidev); -disable: - pci_disable_device(pcidev); - - return ret; -} - -static void __devexit via_sd_remove(struct pci_dev *pcidev) -{ - struct via_crdr_mmc_host *sdhost = pci_get_drvdata(pcidev); - unsigned long flags; - u8 gatt; - - spin_lock_irqsave(&sdhost->lock, flags); - - /* Ensure we don't accept more commands from mmc layer */ - sdhost->reject = 1; - - /* Disable generating further interrupts */ - writeb(0x0, sdhost->pcictrl_mmiobase + VIA_CRDR_PCIINTCTRL); - mmiowb(); - - if (sdhost->mrq) { - pr_err("%s: Controller removed during " - "transfer\n", mmc_hostname(sdhost->mmc)); - - /* make sure all DMA is stopped */ - writel(VIA_CRDR_DMACTRL_SFTRST, - sdhost->ddma_mmiobase + VIA_CRDR_DMACTRL); - mmiowb(); - sdhost->mrq->cmd->error = -ENOMEDIUM; - if (sdhost->mrq->stop) - sdhost->mrq->stop->error = -ENOMEDIUM; - tasklet_schedule(&sdhost->finish_tasklet); - } - spin_unlock_irqrestore(&sdhost->lock, flags); - - mmc_remove_host(sdhost->mmc); - - free_irq(pcidev->irq, sdhost); - - del_timer_sync(&sdhost->timer); - - tasklet_kill(&sdhost->finish_tasklet); - - /* switch off power */ - gatt = readb(sdhost->pcictrl_mmiobase + VIA_CRDR_PCICLKGATT); - gatt &= ~VIA_CRDR_PCICLKGATT_PAD_PWRON; - writeb(gatt, sdhost->pcictrl_mmiobase + VIA_CRDR_PCICLKGATT); - - iounmap(sdhost->mmiobase); - dev_set_drvdata(&pcidev->dev, NULL); - mmc_free_host(sdhost->mmc); - pci_release_regions(pcidev); - pci_disable_device(pcidev); - - pr_info(DRV_NAME - ": VIA SDMMC controller at %s [%04x:%04x] has been removed\n", - pci_name(pcidev), (int)pcidev->vendor, (int)pcidev->device); -} - -#ifdef CONFIG_PM - -static void via_init_sdc_pm(struct via_crdr_mmc_host *host) -{ - struct sdhcreg *pm_sdhcreg; - void __iomem *addrbase; - u32 lenreg; - u16 status; - - pm_sdhcreg = &(host->pm_sdhc_reg); - addrbase = host->sdhc_mmiobase; - - writel(0x0, addrbase + VIA_CRDR_SDINTMASK); - - lenreg = VIA_CRDR_SDBLKLEN_GPIDET | VIA_CRDR_SDBLKLEN_INTEN; - writel(lenreg, addrbase + VIA_CRDR_SDBLKLEN); - - status = readw(addrbase + VIA_CRDR_SDSTATUS); - status &= VIA_CRDR_SDSTS_W1C_MASK; - writew(status, addrbase + VIA_CRDR_SDSTATUS); - - status = readw(addrbase + VIA_CRDR_SDSTATUS2); - status |= VIA_CRDR_SDSTS_CFE; - writew(status, addrbase + VIA_CRDR_SDSTATUS2); - - writel(pm_sdhcreg->sdcontrol_reg, addrbase + VIA_CRDR_SDCTRL); - writel(pm_sdhcreg->sdcmdarg_reg, addrbase + VIA_CRDR_SDCARG); - writel(pm_sdhcreg->sdintmask_reg, addrbase + VIA_CRDR_SDINTMASK); - writel(pm_sdhcreg->sdrsptmo_reg, addrbase + VIA_CRDR_SDRSPTMO); - writel(pm_sdhcreg->sdclksel_reg, addrbase + VIA_CRDR_SDCLKSEL); - writel(pm_sdhcreg->sdextctrl_reg, addrbase + VIA_CRDR_SDEXTCTRL); - - via_print_pcictrl(host); - via_print_sdchc(host); -} - -static int via_sd_suspend(struct pci_dev *pcidev, pm_message_t state) -{ - struct via_crdr_mmc_host *host; - int ret = 0; - - host = pci_get_drvdata(pcidev); - - via_save_pcictrlreg(host); - via_save_sdcreg(host); - - ret = mmc_suspend_host(host->mmc); - - pci_save_state(pcidev); - pci_enable_wake(pcidev, pci_choose_state(pcidev, state), 0); - pci_disable_device(pcidev); - pci_set_power_state(pcidev, pci_choose_state(pcidev, state)); - - return ret; -} - -static int via_sd_resume(struct pci_dev *pcidev) -{ - struct via_crdr_mmc_host *sdhost; - int ret = 0; - u8 gatt; - - sdhost = pci_get_drvdata(pcidev); - - gatt = VIA_CRDR_PCICLKGATT_PAD_PWRON; - if (sdhost->power == MMC_VDD_165_195) - gatt &= ~VIA_CRDR_PCICLKGATT_3V3; - else - gatt |= VIA_CRDR_PCICLKGATT_3V3; - writeb(gatt, sdhost->pcictrl_mmiobase + VIA_CRDR_PCICLKGATT); - via_pwron_sleep(sdhost); - gatt |= VIA_CRDR_PCICLKGATT_SFTRST; - writeb(gatt, sdhost->pcictrl_mmiobase + VIA_CRDR_PCICLKGATT); - msleep(3); - - msleep(100); - - pci_set_power_state(pcidev, PCI_D0); - pci_restore_state(pcidev); - ret = pci_enable_device(pcidev); - if (ret) - return ret; - - via_restore_pcictrlreg(sdhost); - via_init_sdc_pm(sdhost); - - ret = mmc_resume_host(sdhost->mmc); - - return ret; -} - -#else /* CONFIG_PM */ - -#define via_sd_suspend NULL -#define via_sd_resume NULL - -#endif /* CONFIG_PM */ - -static struct pci_driver via_sd_driver = { - .name = DRV_NAME, - .id_table = via_ids, - .probe = via_sd_probe, - .remove = __devexit_p(via_sd_remove), - .suspend = via_sd_suspend, - .resume = via_sd_resume, -}; - -static int __init via_sd_drv_init(void) -{ - pr_info(DRV_NAME ": VIA SD/MMC Card Reader driver " - "(C) 2008 VIA Technologies, Inc.\n"); - - return pci_register_driver(&via_sd_driver); -} - -static void __exit via_sd_drv_exit(void) -{ - pci_unregister_driver(&via_sd_driver); -} - -module_init(via_sd_drv_init); -module_exit(via_sd_drv_exit); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("VIA Technologies Inc."); -MODULE_DESCRIPTION("VIA SD/MMC Card Interface driver"); diff --git a/ANDROID_3.4.5/drivers/mmc/host/vub300.c b/ANDROID_3.4.5/drivers/mmc/host/vub300.c deleted file mode 100644 index 3135a1a5..00000000 --- a/ANDROID_3.4.5/drivers/mmc/host/vub300.c +++ /dev/null @@ -1,2503 +0,0 @@ -/* - * Remote VUB300 SDIO/SDmem Host Controller Driver - * - * Copyright (C) 2010 Elan Digital Systems Limited - * - * based on USB Skeleton driver - 2.2 - * - * Copyright (C) 2001-2004 Greg Kroah-Hartman (greg@kroah.com) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2 - * - * VUB300: is a USB 2.0 client device with a single SDIO/SDmem/MMC slot - * Any SDIO/SDmem/MMC device plugged into the VUB300 will appear, - * by virtue of this driver, to have been plugged into a local - * SDIO host controller, similar to, say, a PCI Ricoh controller - * This is because this kernel device driver is both a USB 2.0 - * client device driver AND an MMC host controller driver. Thus - * if there is an existing driver for the inserted SDIO/SDmem/MMC - * device then that driver will be used by the kernel to manage - * the device in exactly the same fashion as if it had been - * directly plugged into, say, a local pci bus Ricoh controller - * - * RANT: this driver was written using a display 128x48 - converting it - * to a line width of 80 makes it very difficult to support. In - * particular functions have been broken down into sub functions - * and the original meaningful names have been shortened into - * cryptic ones. - * The problem is that executing a fragment of code subject to - * two conditions means an indentation of 24, thus leaving only - * 56 characters for a C statement. And that is quite ridiculous! - * - * Data types: data passed to/from the VUB300 is fixed to a number of - * bits and driver data fields reflect that limit by using - * u8, u16, u32 - */ -#include <linux/kernel.h> -#include <linux/errno.h> -#include <linux/init.h> -#include <linux/slab.h> -#include <linux/module.h> -#include <linux/kref.h> -#include <linux/uaccess.h> -#include <linux/usb.h> -#include <linux/mutex.h> -#include <linux/mmc/host.h> -#include <linux/mmc/card.h> -#include <linux/mmc/sdio_func.h> -#include <linux/mmc/sdio_ids.h> -#include <linux/workqueue.h> -#include <linux/ctype.h> -#include <linux/firmware.h> -#include <linux/scatterlist.h> - -struct host_controller_info { - u8 info_size; - u16 firmware_version; - u8 number_of_ports; -} __packed; - -#define FIRMWARE_BLOCK_BOUNDARY 1024 -struct sd_command_header { - u8 header_size; - u8 header_type; - u8 port_number; - u8 command_type; /* Bit7 - Rd/Wr */ - u8 command_index; - u8 transfer_size[4]; /* ReadSize + ReadSize */ - u8 response_type; - u8 arguments[4]; - u8 block_count[2]; - u8 block_size[2]; - u8 block_boundary[2]; - u8 reserved[44]; /* to pad out to 64 bytes */ -} __packed; - -struct sd_irqpoll_header { - u8 header_size; - u8 header_type; - u8 port_number; - u8 command_type; /* Bit7 - Rd/Wr */ - u8 padding[16]; /* don't ask why !! */ - u8 poll_timeout_msb; - u8 poll_timeout_lsb; - u8 reserved[42]; /* to pad out to 64 bytes */ -} __packed; - -struct sd_common_header { - u8 header_size; - u8 header_type; - u8 port_number; -} __packed; - -struct sd_response_header { - u8 header_size; - u8 header_type; - u8 port_number; - u8 command_type; - u8 command_index; - u8 command_response[0]; -} __packed; - -struct sd_status_header { - u8 header_size; - u8 header_type; - u8 port_number; - u16 port_flags; - u32 sdio_clock; - u16 host_header_size; - u16 func_header_size; - u16 ctrl_header_size; -} __packed; - -struct sd_error_header { - u8 header_size; - u8 header_type; - u8 port_number; - u8 error_code; -} __packed; - -struct sd_interrupt_header { - u8 header_size; - u8 header_type; - u8 port_number; -} __packed; - -struct offload_registers_access { - u8 command_byte[4]; - u8 Respond_Byte[4]; -} __packed; - -#define INTERRUPT_REGISTER_ACCESSES 15 -struct sd_offloaded_interrupt { - u8 header_size; - u8 header_type; - u8 port_number; - struct offload_registers_access reg[INTERRUPT_REGISTER_ACCESSES]; -} __packed; - -struct sd_register_header { - u8 header_size; - u8 header_type; - u8 port_number; - u8 command_type; - u8 command_index; - u8 command_response[6]; -} __packed; - -#define PIGGYBACK_REGISTER_ACCESSES 14 -struct sd_offloaded_piggyback { - struct sd_register_header sdio; - struct offload_registers_access reg[PIGGYBACK_REGISTER_ACCESSES]; -} __packed; - -union sd_response { - struct sd_common_header common; - struct sd_status_header status; - struct sd_error_header error; - struct sd_interrupt_header interrupt; - struct sd_response_header response; - struct sd_offloaded_interrupt irq; - struct sd_offloaded_piggyback pig; -} __packed; - -union sd_command { - struct sd_command_header head; - struct sd_irqpoll_header poll; -} __packed; - -enum SD_RESPONSE_TYPE { - SDRT_UNSPECIFIED = 0, - SDRT_NONE, - SDRT_1, - SDRT_1B, - SDRT_2, - SDRT_3, - SDRT_4, - SDRT_5, - SDRT_5B, - SDRT_6, - SDRT_7, -}; - -#define RESPONSE_INTERRUPT 0x01 -#define RESPONSE_ERROR 0x02 -#define RESPONSE_STATUS 0x03 -#define RESPONSE_IRQ_DISABLED 0x05 -#define RESPONSE_IRQ_ENABLED 0x06 -#define RESPONSE_PIGGYBACKED 0x07 -#define RESPONSE_NO_INTERRUPT 0x08 -#define RESPONSE_PIG_DISABLED 0x09 -#define RESPONSE_PIG_ENABLED 0x0A -#define SD_ERROR_1BIT_TIMEOUT 0x01 -#define SD_ERROR_4BIT_TIMEOUT 0x02 -#define SD_ERROR_1BIT_CRC_WRONG 0x03 -#define SD_ERROR_4BIT_CRC_WRONG 0x04 -#define SD_ERROR_1BIT_CRC_ERROR 0x05 -#define SD_ERROR_4BIT_CRC_ERROR 0x06 -#define SD_ERROR_NO_CMD_ENDBIT 0x07 -#define SD_ERROR_NO_1BIT_DATEND 0x08 -#define SD_ERROR_NO_4BIT_DATEND 0x09 -#define SD_ERROR_1BIT_UNEXPECTED_TIMEOUT 0x0A -#define SD_ERROR_4BIT_UNEXPECTED_TIMEOUT 0x0B -#define SD_ERROR_ILLEGAL_COMMAND 0x0C -#define SD_ERROR_NO_DEVICE 0x0D -#define SD_ERROR_TRANSFER_LENGTH 0x0E -#define SD_ERROR_1BIT_DATA_TIMEOUT 0x0F -#define SD_ERROR_4BIT_DATA_TIMEOUT 0x10 -#define SD_ERROR_ILLEGAL_STATE 0x11 -#define SD_ERROR_UNKNOWN_ERROR 0x12 -#define SD_ERROR_RESERVED_ERROR 0x13 -#define SD_ERROR_INVALID_FUNCTION 0x14 -#define SD_ERROR_OUT_OF_RANGE 0x15 -#define SD_ERROR_STAT_CMD 0x16 -#define SD_ERROR_STAT_DATA 0x17 -#define SD_ERROR_STAT_CMD_TIMEOUT 0x18 -#define SD_ERROR_SDCRDY_STUCK 0x19 -#define SD_ERROR_UNHANDLED 0x1A -#define SD_ERROR_OVERRUN 0x1B -#define SD_ERROR_PIO_TIMEOUT 0x1C - -#define FUN(c) (0x000007 & (c->arg>>28)) -#define REG(c) (0x01FFFF & (c->arg>>9)) - -static bool limit_speed_to_24_MHz; -module_param(limit_speed_to_24_MHz, bool, 0644); -MODULE_PARM_DESC(limit_speed_to_24_MHz, "Limit Max SDIO Clock Speed to 24 MHz"); - -static bool pad_input_to_usb_pkt; -module_param(pad_input_to_usb_pkt, bool, 0644); -MODULE_PARM_DESC(pad_input_to_usb_pkt, - "Pad USB data input transfers to whole USB Packet"); - -static bool disable_offload_processing; -module_param(disable_offload_processing, bool, 0644); -MODULE_PARM_DESC(disable_offload_processing, "Disable Offload Processing"); - -static bool force_1_bit_data_xfers; -module_param(force_1_bit_data_xfers, bool, 0644); -MODULE_PARM_DESC(force_1_bit_data_xfers, - "Force SDIO Data Transfers to 1-bit Mode"); - -static bool force_polling_for_irqs; -module_param(force_polling_for_irqs, bool, 0644); -MODULE_PARM_DESC(force_polling_for_irqs, "Force Polling for SDIO interrupts"); - -static int firmware_irqpoll_timeout = 1024; -module_param(firmware_irqpoll_timeout, int, 0644); -MODULE_PARM_DESC(firmware_irqpoll_timeout, "VUB300 firmware irqpoll timeout"); - -static int force_max_req_size = 128; -module_param(force_max_req_size, int, 0644); -MODULE_PARM_DESC(force_max_req_size, "set max request size in kBytes"); - -#ifdef SMSC_DEVELOPMENT_BOARD -static int firmware_rom_wait_states = 0x04; -#else -static int firmware_rom_wait_states = 0x1C; -#endif - -module_param(firmware_rom_wait_states, int, 0644); -MODULE_PARM_DESC(firmware_rom_wait_states, - "ROM wait states byte=RRRIIEEE (Reserved Internal External)"); - -#define ELAN_VENDOR_ID 0x2201 -#define VUB300_VENDOR_ID 0x0424 -#define VUB300_PRODUCT_ID 0x012C -static struct usb_device_id vub300_table[] = { - {USB_DEVICE(ELAN_VENDOR_ID, VUB300_PRODUCT_ID)}, - {USB_DEVICE(VUB300_VENDOR_ID, VUB300_PRODUCT_ID)}, - {} /* Terminating entry */ -}; -MODULE_DEVICE_TABLE(usb, vub300_table); - -static struct workqueue_struct *cmndworkqueue; -static struct workqueue_struct *pollworkqueue; -static struct workqueue_struct *deadworkqueue; - -static inline int interface_to_InterfaceNumber(struct usb_interface *interface) -{ - if (!interface) - return -1; - if (!interface->cur_altsetting) - return -1; - return interface->cur_altsetting->desc.bInterfaceNumber; -} - -struct sdio_register { - unsigned func_num:3; - unsigned sdio_reg:17; - unsigned activate:1; - unsigned prepared:1; - unsigned regvalue:8; - unsigned response:8; - unsigned sparebit:26; -}; - -struct vub300_mmc_host { - struct usb_device *udev; - struct usb_interface *interface; - struct kref kref; - struct mutex cmd_mutex; - struct mutex irq_mutex; - char vub_name[3 + (9 * 8) + 4 + 1]; /* max of 7 sdio fn's */ - u8 cmnd_out_ep; /* EndPoint for commands */ - u8 cmnd_res_ep; /* EndPoint for responses */ - u8 data_out_ep; /* EndPoint for out data */ - u8 data_inp_ep; /* EndPoint for inp data */ - bool card_powered; - bool card_present; - bool read_only; - bool large_usb_packets; - bool app_spec; /* ApplicationSpecific */ - bool irq_enabled; /* by the MMC CORE */ - bool irq_disabled; /* in the firmware */ - unsigned bus_width:4; - u8 total_offload_count; - u8 dynamic_register_count; - u8 resp_len; - u32 datasize; - int errors; - int usb_transport_fail; - int usb_timed_out; - int irqs_queued; - struct sdio_register sdio_register[16]; - struct offload_interrupt_function_register { -#define MAXREGBITS 4 -#define MAXREGS (1<<MAXREGBITS) -#define MAXREGMASK (MAXREGS-1) - u8 offload_count; - u32 offload_point; - struct offload_registers_access reg[MAXREGS]; - } fn[8]; - u16 fbs[8]; /* Function Block Size */ - struct mmc_command *cmd; - struct mmc_request *req; - struct mmc_data *data; - struct mmc_host *mmc; - struct urb *urb; - struct urb *command_out_urb; - struct urb *command_res_urb; - struct completion command_complete; - struct completion irqpoll_complete; - union sd_command cmnd; - union sd_response resp; - struct timer_list sg_transfer_timer; - struct usb_sg_request sg_request; - struct timer_list inactivity_timer; - struct work_struct deadwork; - struct work_struct cmndwork; - struct delayed_work pollwork; - struct host_controller_info hc_info; - struct sd_status_header system_port_status; - u8 padded_buffer[64]; -}; - -#define kref_to_vub300_mmc_host(d) container_of(d, struct vub300_mmc_host, kref) -#define SET_TRANSFER_PSEUDOCODE 21 -#define SET_INTERRUPT_PSEUDOCODE 20 -#define SET_FAILURE_MODE 18 -#define SET_ROM_WAIT_STATES 16 -#define SET_IRQ_ENABLE 13 -#define SET_CLOCK_SPEED 11 -#define SET_FUNCTION_BLOCK_SIZE 9 -#define SET_SD_DATA_MODE 6 -#define SET_SD_POWER 4 -#define ENTER_DFU_MODE 3 -#define GET_HC_INF0 1 -#define GET_SYSTEM_PORT_STATUS 0 - -static void vub300_delete(struct kref *kref) -{ /* kref callback - softirq */ - struct vub300_mmc_host *vub300 = kref_to_vub300_mmc_host(kref); - struct mmc_host *mmc = vub300->mmc; - usb_free_urb(vub300->command_out_urb); - vub300->command_out_urb = NULL; - usb_free_urb(vub300->command_res_urb); - vub300->command_res_urb = NULL; - usb_put_dev(vub300->udev); - mmc_free_host(mmc); - /* - * and hence also frees vub300 - * which is contained at the end of struct mmc - */ -} - -static void vub300_queue_cmnd_work(struct vub300_mmc_host *vub300) -{ - kref_get(&vub300->kref); - if (queue_work(cmndworkqueue, &vub300->cmndwork)) { - /* - * then the cmndworkqueue was not previously - * running and the above get ref is obvious - * required and will be put when the thread - * terminates by a specific call - */ - } else { - /* - * the cmndworkqueue was already running from - * a previous invocation and thus to keep the - * kref counts correct we must undo the get - */ - kref_put(&vub300->kref, vub300_delete); - } -} - -static void vub300_queue_poll_work(struct vub300_mmc_host *vub300, int delay) -{ - kref_get(&vub300->kref); - if (queue_delayed_work(pollworkqueue, &vub300->pollwork, delay)) { - /* - * then the pollworkqueue was not previously - * running and the above get ref is obvious - * required and will be put when the thread - * terminates by a specific call - */ - } else { - /* - * the pollworkqueue was already running from - * a previous invocation and thus to keep the - * kref counts correct we must undo the get - */ - kref_put(&vub300->kref, vub300_delete); - } -} - -static void vub300_queue_dead_work(struct vub300_mmc_host *vub300) -{ - kref_get(&vub300->kref); - if (queue_work(deadworkqueue, &vub300->deadwork)) { - /* - * then the deadworkqueue was not previously - * running and the above get ref is obvious - * required and will be put when the thread - * terminates by a specific call - */ - } else { - /* - * the deadworkqueue was already running from - * a previous invocation and thus to keep the - * kref counts correct we must undo the get - */ - kref_put(&vub300->kref, vub300_delete); - } -} - -static void irqpoll_res_completed(struct urb *urb) -{ /* urb completion handler - hardirq */ - struct vub300_mmc_host *vub300 = (struct vub300_mmc_host *)urb->context; - if (urb->status) - vub300->usb_transport_fail = urb->status; - complete(&vub300->irqpoll_complete); -} - -static void irqpoll_out_completed(struct urb *urb) -{ /* urb completion handler - hardirq */ - struct vub300_mmc_host *vub300 = (struct vub300_mmc_host *)urb->context; - if (urb->status) { - vub300->usb_transport_fail = urb->status; - complete(&vub300->irqpoll_complete); - return; - } else { - int ret; - unsigned int pipe = - usb_rcvbulkpipe(vub300->udev, vub300->cmnd_res_ep); - usb_fill_bulk_urb(vub300->command_res_urb, vub300->udev, pipe, - &vub300->resp, sizeof(vub300->resp), - irqpoll_res_completed, vub300); - vub300->command_res_urb->actual_length = 0; - ret = usb_submit_urb(vub300->command_res_urb, GFP_ATOMIC); - if (ret) { - vub300->usb_transport_fail = ret; - complete(&vub300->irqpoll_complete); - } - return; - } -} - -static void send_irqpoll(struct vub300_mmc_host *vub300) -{ - /* cmd_mutex is held by vub300_pollwork_thread */ - int retval; - int timeout = 0xFFFF & (0x0001FFFF - firmware_irqpoll_timeout); - vub300->cmnd.poll.header_size = 22; - vub300->cmnd.poll.header_type = 1; - vub300->cmnd.poll.port_number = 0; - vub300->cmnd.poll.command_type = 2; - vub300->cmnd.poll.poll_timeout_lsb = 0xFF & (unsigned)timeout; - vub300->cmnd.poll.poll_timeout_msb = 0xFF & (unsigned)(timeout >> 8); - usb_fill_bulk_urb(vub300->command_out_urb, vub300->udev, - usb_sndbulkpipe(vub300->udev, vub300->cmnd_out_ep) - , &vub300->cmnd, sizeof(vub300->cmnd) - , irqpoll_out_completed, vub300); - retval = usb_submit_urb(vub300->command_out_urb, GFP_KERNEL); - if (0 > retval) { - vub300->usb_transport_fail = retval; - vub300_queue_poll_work(vub300, 1); - complete(&vub300->irqpoll_complete); - return; - } else { - return; - } -} - -static void new_system_port_status(struct vub300_mmc_host *vub300) -{ - int old_card_present = vub300->card_present; - int new_card_present = - (0x0001 & vub300->system_port_status.port_flags) ? 1 : 0; - vub300->read_only = - (0x0010 & vub300->system_port_status.port_flags) ? 1 : 0; - if (new_card_present && !old_card_present) { - dev_info(&vub300->udev->dev, "card just inserted\n"); - vub300->card_present = 1; - vub300->bus_width = 0; - if (disable_offload_processing) - strncpy(vub300->vub_name, "EMPTY Processing Disabled", - sizeof(vub300->vub_name)); - else - vub300->vub_name[0] = 0; - mmc_detect_change(vub300->mmc, 1); - } else if (!new_card_present && old_card_present) { - dev_info(&vub300->udev->dev, "card just ejected\n"); - vub300->card_present = 0; - mmc_detect_change(vub300->mmc, 0); - } else { - /* no change */ - } -} - -static void __add_offloaded_reg_to_fifo(struct vub300_mmc_host *vub300, - struct offload_registers_access - *register_access, u8 func) -{ - u8 r = vub300->fn[func].offload_point + vub300->fn[func].offload_count; - memcpy(&vub300->fn[func].reg[MAXREGMASK & r], register_access, - sizeof(struct offload_registers_access)); - vub300->fn[func].offload_count += 1; - vub300->total_offload_count += 1; -} - -static void add_offloaded_reg(struct vub300_mmc_host *vub300, - struct offload_registers_access *register_access) -{ - u32 Register = ((0x03 & register_access->command_byte[0]) << 15) - | ((0xFF & register_access->command_byte[1]) << 7) - | ((0xFE & register_access->command_byte[2]) >> 1); - u8 func = ((0x70 & register_access->command_byte[0]) >> 4); - u8 regs = vub300->dynamic_register_count; - u8 i = 0; - while (0 < regs-- && 1 == vub300->sdio_register[i].activate) { - if (vub300->sdio_register[i].func_num == func && - vub300->sdio_register[i].sdio_reg == Register) { - if (vub300->sdio_register[i].prepared == 0) - vub300->sdio_register[i].prepared = 1; - vub300->sdio_register[i].response = - register_access->Respond_Byte[2]; - vub300->sdio_register[i].regvalue = - register_access->Respond_Byte[3]; - return; - } else { - i += 1; - continue; - } - }; - __add_offloaded_reg_to_fifo(vub300, register_access, func); -} - -static void check_vub300_port_status(struct vub300_mmc_host *vub300) -{ - /* - * cmd_mutex is held by vub300_pollwork_thread, - * vub300_deadwork_thread or vub300_cmndwork_thread - */ - int retval; - retval = - usb_control_msg(vub300->udev, usb_rcvctrlpipe(vub300->udev, 0), - GET_SYSTEM_PORT_STATUS, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 0x0000, 0x0000, &vub300->system_port_status, - sizeof(vub300->system_port_status), HZ); - if (sizeof(vub300->system_port_status) == retval) - new_system_port_status(vub300); -} - -static void __vub300_irqpoll_response(struct vub300_mmc_host *vub300) -{ - /* cmd_mutex is held by vub300_pollwork_thread */ - if (vub300->command_res_urb->actual_length == 0) - return; - - switch (vub300->resp.common.header_type) { - case RESPONSE_INTERRUPT: - mutex_lock(&vub300->irq_mutex); - if (vub300->irq_enabled) - mmc_signal_sdio_irq(vub300->mmc); - else - vub300->irqs_queued += 1; - vub300->irq_disabled = 1; - mutex_unlock(&vub300->irq_mutex); - break; - case RESPONSE_ERROR: - if (vub300->resp.error.error_code == SD_ERROR_NO_DEVICE) - check_vub300_port_status(vub300); - break; - case RESPONSE_STATUS: - vub300->system_port_status = vub300->resp.status; - new_system_port_status(vub300); - if (!vub300->card_present) - vub300_queue_poll_work(vub300, HZ / 5); - break; - case RESPONSE_IRQ_DISABLED: - { - int offloaded_data_length = vub300->resp.common.header_size - 3; - int register_count = offloaded_data_length >> 3; - int ri = 0; - while (register_count--) { - add_offloaded_reg(vub300, &vub300->resp.irq.reg[ri]); - ri += 1; - } - mutex_lock(&vub300->irq_mutex); - if (vub300->irq_enabled) - mmc_signal_sdio_irq(vub300->mmc); - else - vub300->irqs_queued += 1; - vub300->irq_disabled = 1; - mutex_unlock(&vub300->irq_mutex); - break; - } - case RESPONSE_IRQ_ENABLED: - { - int offloaded_data_length = vub300->resp.common.header_size - 3; - int register_count = offloaded_data_length >> 3; - int ri = 0; - while (register_count--) { - add_offloaded_reg(vub300, &vub300->resp.irq.reg[ri]); - ri += 1; - } - mutex_lock(&vub300->irq_mutex); - if (vub300->irq_enabled) - mmc_signal_sdio_irq(vub300->mmc); - else if (vub300->irqs_queued) - vub300->irqs_queued += 1; - else - vub300->irqs_queued += 1; - vub300->irq_disabled = 0; - mutex_unlock(&vub300->irq_mutex); - break; - } - case RESPONSE_NO_INTERRUPT: - vub300_queue_poll_work(vub300, 1); - break; - default: - break; - } -} - -static void __do_poll(struct vub300_mmc_host *vub300) -{ - /* cmd_mutex is held by vub300_pollwork_thread */ - long commretval; - mod_timer(&vub300->inactivity_timer, jiffies + HZ); - init_completion(&vub300->irqpoll_complete); - send_irqpoll(vub300); - commretval = wait_for_completion_timeout(&vub300->irqpoll_complete, - msecs_to_jiffies(500)); - if (vub300->usb_transport_fail) { - /* no need to do anything */ - } else if (commretval == 0) { - vub300->usb_timed_out = 1; - usb_kill_urb(vub300->command_out_urb); - usb_kill_urb(vub300->command_res_urb); - } else if (commretval < 0) { - vub300_queue_poll_work(vub300, 1); - } else { /* commretval > 0 */ - __vub300_irqpoll_response(vub300); - } -} - -/* this thread runs only when the driver - * is trying to poll the device for an IRQ - */ -static void vub300_pollwork_thread(struct work_struct *work) -{ /* NOT irq */ - struct vub300_mmc_host *vub300 = container_of(work, - struct vub300_mmc_host, pollwork.work); - if (!vub300->interface) { - kref_put(&vub300->kref, vub300_delete); - return; - } - mutex_lock(&vub300->cmd_mutex); - if (vub300->cmd) { - vub300_queue_poll_work(vub300, 1); - } else if (!vub300->card_present) { - /* no need to do anything */ - } else { /* vub300->card_present */ - mutex_lock(&vub300->irq_mutex); - if (!vub300->irq_enabled) { - mutex_unlock(&vub300->irq_mutex); - } else if (vub300->irqs_queued) { - vub300->irqs_queued -= 1; - mmc_signal_sdio_irq(vub300->mmc); - mod_timer(&vub300->inactivity_timer, jiffies + HZ); - mutex_unlock(&vub300->irq_mutex); - } else { /* NOT vub300->irqs_queued */ - mutex_unlock(&vub300->irq_mutex); - __do_poll(vub300); - } - } - mutex_unlock(&vub300->cmd_mutex); - kref_put(&vub300->kref, vub300_delete); -} - -static void vub300_deadwork_thread(struct work_struct *work) -{ /* NOT irq */ - struct vub300_mmc_host *vub300 = - container_of(work, struct vub300_mmc_host, deadwork); - if (!vub300->interface) { - kref_put(&vub300->kref, vub300_delete); - return; - } - mutex_lock(&vub300->cmd_mutex); - if (vub300->cmd) { - /* - * a command got in as the inactivity - * timer expired - so we just let the - * processing of the command show if - * the device is dead - */ - } else if (vub300->card_present) { - check_vub300_port_status(vub300); - } else if (vub300->mmc && vub300->mmc->card && - mmc_card_present(vub300->mmc->card)) { - /* - * the MMC core must not have responded - * to the previous indication - lets - * hope that it eventually does so we - * will just ignore this for now - */ - } else { - check_vub300_port_status(vub300); - } - mod_timer(&vub300->inactivity_timer, jiffies + HZ); - mutex_unlock(&vub300->cmd_mutex); - kref_put(&vub300->kref, vub300_delete); -} - -static void vub300_inactivity_timer_expired(unsigned long data) -{ /* softirq */ - struct vub300_mmc_host *vub300 = (struct vub300_mmc_host *)data; - if (!vub300->interface) { - kref_put(&vub300->kref, vub300_delete); - } else if (vub300->cmd) { - mod_timer(&vub300->inactivity_timer, jiffies + HZ); - } else { - vub300_queue_dead_work(vub300); - mod_timer(&vub300->inactivity_timer, jiffies + HZ); - } -} - -static int vub300_response_error(u8 error_code) -{ - switch (error_code) { - case SD_ERROR_PIO_TIMEOUT: - case SD_ERROR_1BIT_TIMEOUT: - case SD_ERROR_4BIT_TIMEOUT: - return -ETIMEDOUT; - case SD_ERROR_STAT_DATA: - case SD_ERROR_OVERRUN: - case SD_ERROR_STAT_CMD: - case SD_ERROR_STAT_CMD_TIMEOUT: - case SD_ERROR_SDCRDY_STUCK: - case SD_ERROR_UNHANDLED: - case SD_ERROR_1BIT_CRC_WRONG: - case SD_ERROR_4BIT_CRC_WRONG: - case SD_ERROR_1BIT_CRC_ERROR: - case SD_ERROR_4BIT_CRC_ERROR: - case SD_ERROR_NO_CMD_ENDBIT: - case SD_ERROR_NO_1BIT_DATEND: - case SD_ERROR_NO_4BIT_DATEND: - case SD_ERROR_1BIT_DATA_TIMEOUT: - case SD_ERROR_4BIT_DATA_TIMEOUT: - case SD_ERROR_1BIT_UNEXPECTED_TIMEOUT: - case SD_ERROR_4BIT_UNEXPECTED_TIMEOUT: - return -EILSEQ; - case 33: - return -EILSEQ; - case SD_ERROR_ILLEGAL_COMMAND: - return -EINVAL; - case SD_ERROR_NO_DEVICE: - return -ENOMEDIUM; - default: - return -ENODEV; - } -} - -static void command_res_completed(struct urb *urb) -{ /* urb completion handler - hardirq */ - struct vub300_mmc_host *vub300 = (struct vub300_mmc_host *)urb->context; - if (urb->status) { - /* we have to let the initiator handle the error */ - } else if (vub300->command_res_urb->actual_length == 0) { - /* - * we have seen this happen once or twice and - * we suspect a buggy USB host controller - */ - } else if (!vub300->data) { - /* this means that the command (typically CMD52) suceeded */ - } else if (vub300->resp.common.header_type != 0x02) { - /* - * this is an error response from the VUB300 chip - * and we let the initiator handle it - */ - } else if (vub300->urb) { - vub300->cmd->error = - vub300_response_error(vub300->resp.error.error_code); - usb_unlink_urb(vub300->urb); - } else { - vub300->cmd->error = - vub300_response_error(vub300->resp.error.error_code); - usb_sg_cancel(&vub300->sg_request); - } - complete(&vub300->command_complete); /* got_response_in */ -} - -static void command_out_completed(struct urb *urb) -{ /* urb completion handler - hardirq */ - struct vub300_mmc_host *vub300 = (struct vub300_mmc_host *)urb->context; - if (urb->status) { - complete(&vub300->command_complete); - } else { - int ret; - unsigned int pipe = - usb_rcvbulkpipe(vub300->udev, vub300->cmnd_res_ep); - usb_fill_bulk_urb(vub300->command_res_urb, vub300->udev, pipe, - &vub300->resp, sizeof(vub300->resp), - command_res_completed, vub300); - vub300->command_res_urb->actual_length = 0; - ret = usb_submit_urb(vub300->command_res_urb, GFP_ATOMIC); - if (ret == 0) { - /* - * the urb completion handler will call - * our completion handler - */ - } else { - /* - * and thus we only call it directly - * when it will not be called - */ - complete(&vub300->command_complete); - } - } -} - -/* - * the STUFF bits are masked out for the comparisons - */ -static void snoop_block_size_and_bus_width(struct vub300_mmc_host *vub300, - u32 cmd_arg) -{ - if ((0xFBFFFE00 & cmd_arg) == 0x80022200) - vub300->fbs[1] = (cmd_arg << 8) | (0x00FF & vub300->fbs[1]); - else if ((0xFBFFFE00 & cmd_arg) == 0x80022000) - vub300->fbs[1] = (0xFF & cmd_arg) | (0xFF00 & vub300->fbs[1]); - else if ((0xFBFFFE00 & cmd_arg) == 0x80042200) - vub300->fbs[2] = (cmd_arg << 8) | (0x00FF & vub300->fbs[2]); - else if ((0xFBFFFE00 & cmd_arg) == 0x80042000) - vub300->fbs[2] = (0xFF & cmd_arg) | (0xFF00 & vub300->fbs[2]); - else if ((0xFBFFFE00 & cmd_arg) == 0x80062200) - vub300->fbs[3] = (cmd_arg << 8) | (0x00FF & vub300->fbs[3]); - else if ((0xFBFFFE00 & cmd_arg) == 0x80062000) - vub300->fbs[3] = (0xFF & cmd_arg) | (0xFF00 & vub300->fbs[3]); - else if ((0xFBFFFE00 & cmd_arg) == 0x80082200) - vub300->fbs[4] = (cmd_arg << 8) | (0x00FF & vub300->fbs[4]); - else if ((0xFBFFFE00 & cmd_arg) == 0x80082000) - vub300->fbs[4] = (0xFF & cmd_arg) | (0xFF00 & vub300->fbs[4]); - else if ((0xFBFFFE00 & cmd_arg) == 0x800A2200) - vub300->fbs[5] = (cmd_arg << 8) | (0x00FF & vub300->fbs[5]); - else if ((0xFBFFFE00 & cmd_arg) == 0x800A2000) - vub300->fbs[5] = (0xFF & cmd_arg) | (0xFF00 & vub300->fbs[5]); - else if ((0xFBFFFE00 & cmd_arg) == 0x800C2200) - vub300->fbs[6] = (cmd_arg << 8) | (0x00FF & vub300->fbs[6]); - else if ((0xFBFFFE00 & cmd_arg) == 0x800C2000) - vub300->fbs[6] = (0xFF & cmd_arg) | (0xFF00 & vub300->fbs[6]); - else if ((0xFBFFFE00 & cmd_arg) == 0x800E2200) - vub300->fbs[7] = (cmd_arg << 8) | (0x00FF & vub300->fbs[7]); - else if ((0xFBFFFE00 & cmd_arg) == 0x800E2000) - vub300->fbs[7] = (0xFF & cmd_arg) | (0xFF00 & vub300->fbs[7]); - else if ((0xFBFFFE03 & cmd_arg) == 0x80000E00) - vub300->bus_width = 1; - else if ((0xFBFFFE03 & cmd_arg) == 0x80000E02) - vub300->bus_width = 4; -} - -static void send_command(struct vub300_mmc_host *vub300) -{ - /* cmd_mutex is held by vub300_cmndwork_thread */ - struct mmc_command *cmd = vub300->cmd; - struct mmc_data *data = vub300->data; - int retval; - int i; - u8 response_type; - if (vub300->app_spec) { - switch (cmd->opcode) { - case 6: - response_type = SDRT_1; - vub300->resp_len = 6; - if (0x00000000 == (0x00000003 & cmd->arg)) - vub300->bus_width = 1; - else if (0x00000002 == (0x00000003 & cmd->arg)) - vub300->bus_width = 4; - else - dev_err(&vub300->udev->dev, - "unexpected ACMD6 bus_width=%d\n", - 0x00000003 & cmd->arg); - break; - case 13: - response_type = SDRT_1; - vub300->resp_len = 6; - break; - case 22: - response_type = SDRT_1; - vub300->resp_len = 6; - break; - case 23: - response_type = SDRT_1; - vub300->resp_len = 6; - break; - case 41: - response_type = SDRT_3; - vub300->resp_len = 6; - break; - case 42: - response_type = SDRT_1; - vub300->resp_len = 6; - break; - case 51: - response_type = SDRT_1; - vub300->resp_len = 6; - break; - case 55: - response_type = SDRT_1; - vub300->resp_len = 6; - break; - default: - vub300->resp_len = 0; - cmd->error = -EINVAL; - complete(&vub300->command_complete); - return; - } - vub300->app_spec = 0; - } else { - switch (cmd->opcode) { - case 0: - response_type = SDRT_NONE; - vub300->resp_len = 0; - break; - case 1: - response_type = SDRT_3; - vub300->resp_len = 6; - break; - case 2: - response_type = SDRT_2; - vub300->resp_len = 17; - break; - case 3: - response_type = SDRT_6; - vub300->resp_len = 6; - break; - case 4: - response_type = SDRT_NONE; - vub300->resp_len = 0; - break; - case 5: - response_type = SDRT_4; - vub300->resp_len = 6; - break; - case 6: - response_type = SDRT_1; - vub300->resp_len = 6; - break; - case 7: - response_type = SDRT_1B; - vub300->resp_len = 6; - break; - case 8: - response_type = SDRT_7; - vub300->resp_len = 6; - break; - case 9: - response_type = SDRT_2; - vub300->resp_len = 17; - break; - case 10: - response_type = SDRT_2; - vub300->resp_len = 17; - break; - case 12: - response_type = SDRT_1B; - vub300->resp_len = 6; - break; - case 13: - response_type = SDRT_1; - vub300->resp_len = 6; - break; - case 15: - response_type = SDRT_NONE; - vub300->resp_len = 0; - break; - case 16: - for (i = 0; i < ARRAY_SIZE(vub300->fbs); i++) - vub300->fbs[i] = 0xFFFF & cmd->arg; - response_type = SDRT_1; - vub300->resp_len = 6; - break; - case 17: - case 18: - case 24: - case 25: - case 27: - response_type = SDRT_1; - vub300->resp_len = 6; - break; - case 28: - case 29: - response_type = SDRT_1B; - vub300->resp_len = 6; - break; - case 30: - case 32: - case 33: - response_type = SDRT_1; - vub300->resp_len = 6; - break; - case 38: - response_type = SDRT_1B; - vub300->resp_len = 6; - break; - case 42: - response_type = SDRT_1; - vub300->resp_len = 6; - break; - case 52: - response_type = SDRT_5; - vub300->resp_len = 6; - snoop_block_size_and_bus_width(vub300, cmd->arg); - break; - case 53: - response_type = SDRT_5; - vub300->resp_len = 6; - break; - case 55: - response_type = SDRT_1; - vub300->resp_len = 6; - vub300->app_spec = 1; - break; - case 56: - response_type = SDRT_1; - vub300->resp_len = 6; - break; - default: - vub300->resp_len = 0; - cmd->error = -EINVAL; - complete(&vub300->command_complete); - return; - } - } - /* - * it is a shame that we can not use "sizeof(struct sd_command_header)" - * this is because the packet _must_ be padded to 64 bytes - */ - vub300->cmnd.head.header_size = 20; - vub300->cmnd.head.header_type = 0x00; - vub300->cmnd.head.port_number = 0; /* "0" means port 1 */ - vub300->cmnd.head.command_type = 0x00; /* standard read command */ - vub300->cmnd.head.response_type = response_type; - vub300->cmnd.head.command_index = cmd->opcode; - vub300->cmnd.head.arguments[0] = cmd->arg >> 24; - vub300->cmnd.head.arguments[1] = cmd->arg >> 16; - vub300->cmnd.head.arguments[2] = cmd->arg >> 8; - vub300->cmnd.head.arguments[3] = cmd->arg >> 0; - if (cmd->opcode == 52) { - int fn = 0x7 & (cmd->arg >> 28); - vub300->cmnd.head.block_count[0] = 0; - vub300->cmnd.head.block_count[1] = 0; - vub300->cmnd.head.block_size[0] = (vub300->fbs[fn] >> 8) & 0xFF; - vub300->cmnd.head.block_size[1] = (vub300->fbs[fn] >> 0) & 0xFF; - vub300->cmnd.head.command_type = 0x00; - vub300->cmnd.head.transfer_size[0] = 0; - vub300->cmnd.head.transfer_size[1] = 0; - vub300->cmnd.head.transfer_size[2] = 0; - vub300->cmnd.head.transfer_size[3] = 0; - } else if (!data) { - vub300->cmnd.head.block_count[0] = 0; - vub300->cmnd.head.block_count[1] = 0; - vub300->cmnd.head.block_size[0] = (vub300->fbs[0] >> 8) & 0xFF; - vub300->cmnd.head.block_size[1] = (vub300->fbs[0] >> 0) & 0xFF; - vub300->cmnd.head.command_type = 0x00; - vub300->cmnd.head.transfer_size[0] = 0; - vub300->cmnd.head.transfer_size[1] = 0; - vub300->cmnd.head.transfer_size[2] = 0; - vub300->cmnd.head.transfer_size[3] = 0; - } else if (cmd->opcode == 53) { - int fn = 0x7 & (cmd->arg >> 28); - if (0x08 & vub300->cmnd.head.arguments[0]) { /* BLOCK MODE */ - vub300->cmnd.head.block_count[0] = - (data->blocks >> 8) & 0xFF; - vub300->cmnd.head.block_count[1] = - (data->blocks >> 0) & 0xFF; - vub300->cmnd.head.block_size[0] = - (data->blksz >> 8) & 0xFF; - vub300->cmnd.head.block_size[1] = - (data->blksz >> 0) & 0xFF; - } else { /* BYTE MODE */ - vub300->cmnd.head.block_count[0] = 0; - vub300->cmnd.head.block_count[1] = 0; - vub300->cmnd.head.block_size[0] = - (vub300->datasize >> 8) & 0xFF; - vub300->cmnd.head.block_size[1] = - (vub300->datasize >> 0) & 0xFF; - } - vub300->cmnd.head.command_type = - (MMC_DATA_READ & data->flags) ? 0x00 : 0x80; - vub300->cmnd.head.transfer_size[0] = - (vub300->datasize >> 24) & 0xFF; - vub300->cmnd.head.transfer_size[1] = - (vub300->datasize >> 16) & 0xFF; - vub300->cmnd.head.transfer_size[2] = - (vub300->datasize >> 8) & 0xFF; - vub300->cmnd.head.transfer_size[3] = - (vub300->datasize >> 0) & 0xFF; - if (vub300->datasize < vub300->fbs[fn]) { - vub300->cmnd.head.block_count[0] = 0; - vub300->cmnd.head.block_count[1] = 0; - } - } else { - vub300->cmnd.head.block_count[0] = (data->blocks >> 8) & 0xFF; - vub300->cmnd.head.block_count[1] = (data->blocks >> 0) & 0xFF; - vub300->cmnd.head.block_size[0] = (data->blksz >> 8) & 0xFF; - vub300->cmnd.head.block_size[1] = (data->blksz >> 0) & 0xFF; - vub300->cmnd.head.command_type = - (MMC_DATA_READ & data->flags) ? 0x00 : 0x80; - vub300->cmnd.head.transfer_size[0] = - (vub300->datasize >> 24) & 0xFF; - vub300->cmnd.head.transfer_size[1] = - (vub300->datasize >> 16) & 0xFF; - vub300->cmnd.head.transfer_size[2] = - (vub300->datasize >> 8) & 0xFF; - vub300->cmnd.head.transfer_size[3] = - (vub300->datasize >> 0) & 0xFF; - if (vub300->datasize < vub300->fbs[0]) { - vub300->cmnd.head.block_count[0] = 0; - vub300->cmnd.head.block_count[1] = 0; - } - } - if (vub300->cmnd.head.block_size[0] || vub300->cmnd.head.block_size[1]) { - u16 block_size = vub300->cmnd.head.block_size[1] | - (vub300->cmnd.head.block_size[0] << 8); - u16 block_boundary = FIRMWARE_BLOCK_BOUNDARY - - (FIRMWARE_BLOCK_BOUNDARY % block_size); - vub300->cmnd.head.block_boundary[0] = - (block_boundary >> 8) & 0xFF; - vub300->cmnd.head.block_boundary[1] = - (block_boundary >> 0) & 0xFF; - } else { - vub300->cmnd.head.block_boundary[0] = 0; - vub300->cmnd.head.block_boundary[1] = 0; - } - usb_fill_bulk_urb(vub300->command_out_urb, vub300->udev, - usb_sndbulkpipe(vub300->udev, vub300->cmnd_out_ep), - &vub300->cmnd, sizeof(vub300->cmnd), - command_out_completed, vub300); - retval = usb_submit_urb(vub300->command_out_urb, GFP_KERNEL); - if (retval < 0) { - cmd->error = retval; - complete(&vub300->command_complete); - return; - } else { - return; - } -} - -/* - * timer callback runs in atomic mode - * so it cannot call usb_kill_urb() - */ -static void vub300_sg_timed_out(unsigned long data) -{ - struct vub300_mmc_host *vub300 = (struct vub300_mmc_host *)data; - vub300->usb_timed_out = 1; - usb_sg_cancel(&vub300->sg_request); - usb_unlink_urb(vub300->command_out_urb); - usb_unlink_urb(vub300->command_res_urb); -} - -static u16 roundup_to_multiple_of_64(u16 number) -{ - return 0xFFC0 & (0x3F + number); -} - -/* - * this is a separate function to solve the 80 column width restriction - */ -static void __download_offload_pseudocode(struct vub300_mmc_host *vub300, - const struct firmware *fw) -{ - u8 register_count = 0; - u16 ts = 0; - u16 interrupt_size = 0; - const u8 *data = fw->data; - int size = fw->size; - u8 c; - dev_info(&vub300->udev->dev, "using %s for SDIO offload processing\n", - vub300->vub_name); - do { - c = *data++; - } while (size-- && c); /* skip comment */ - dev_info(&vub300->udev->dev, "using offload firmware %s %s\n", fw->data, - vub300->vub_name); - if (size < 4) { - dev_err(&vub300->udev->dev, - "corrupt offload pseudocode in firmware %s\n", - vub300->vub_name); - strncpy(vub300->vub_name, "corrupt offload pseudocode", - sizeof(vub300->vub_name)); - return; - } - interrupt_size += *data++; - size -= 1; - interrupt_size <<= 8; - interrupt_size += *data++; - size -= 1; - if (interrupt_size < size) { - u16 xfer_length = roundup_to_multiple_of_64(interrupt_size); - u8 *xfer_buffer = kmalloc(xfer_length, GFP_KERNEL); - if (xfer_buffer) { - int retval; - memcpy(xfer_buffer, data, interrupt_size); - memset(xfer_buffer + interrupt_size, 0, - xfer_length - interrupt_size); - size -= interrupt_size; - data += interrupt_size; - retval = - usb_control_msg(vub300->udev, - usb_sndctrlpipe(vub300->udev, 0), - SET_INTERRUPT_PSEUDOCODE, - USB_DIR_OUT | USB_TYPE_VENDOR | - USB_RECIP_DEVICE, 0x0000, 0x0000, - xfer_buffer, xfer_length, HZ); - kfree(xfer_buffer); - if (retval < 0) { - strncpy(vub300->vub_name, - "SDIO pseudocode download failed", - sizeof(vub300->vub_name)); - return; - } - } else { - dev_err(&vub300->udev->dev, - "not enough memory for xfer buffer to send" - " INTERRUPT_PSEUDOCODE for %s %s\n", fw->data, - vub300->vub_name); - strncpy(vub300->vub_name, - "SDIO interrupt pseudocode download failed", - sizeof(vub300->vub_name)); - return; - } - } else { - dev_err(&vub300->udev->dev, - "corrupt interrupt pseudocode in firmware %s %s\n", - fw->data, vub300->vub_name); - strncpy(vub300->vub_name, "corrupt interrupt pseudocode", - sizeof(vub300->vub_name)); - return; - } - ts += *data++; - size -= 1; - ts <<= 8; - ts += *data++; - size -= 1; - if (ts < size) { - u16 xfer_length = roundup_to_multiple_of_64(ts); - u8 *xfer_buffer = kmalloc(xfer_length, GFP_KERNEL); - if (xfer_buffer) { - int retval; - memcpy(xfer_buffer, data, ts); - memset(xfer_buffer + ts, 0, - xfer_length - ts); - size -= ts; - data += ts; - retval = - usb_control_msg(vub300->udev, - usb_sndctrlpipe(vub300->udev, 0), - SET_TRANSFER_PSEUDOCODE, - USB_DIR_OUT | USB_TYPE_VENDOR | - USB_RECIP_DEVICE, 0x0000, 0x0000, - xfer_buffer, xfer_length, HZ); - kfree(xfer_buffer); - if (retval < 0) { - strncpy(vub300->vub_name, - "SDIO pseudocode download failed", - sizeof(vub300->vub_name)); - return; - } - } else { - dev_err(&vub300->udev->dev, - "not enough memory for xfer buffer to send" - " TRANSFER_PSEUDOCODE for %s %s\n", fw->data, - vub300->vub_name); - strncpy(vub300->vub_name, - "SDIO transfer pseudocode download failed", - sizeof(vub300->vub_name)); - return; - } - } else { - dev_err(&vub300->udev->dev, - "corrupt transfer pseudocode in firmware %s %s\n", - fw->data, vub300->vub_name); - strncpy(vub300->vub_name, "corrupt transfer pseudocode", - sizeof(vub300->vub_name)); - return; - } - register_count += *data++; - size -= 1; - if (register_count * 4 == size) { - int I = vub300->dynamic_register_count = register_count; - int i = 0; - while (I--) { - unsigned int func_num = 0; - vub300->sdio_register[i].func_num = *data++; - size -= 1; - func_num += *data++; - size -= 1; - func_num <<= 8; - func_num += *data++; - size -= 1; - func_num <<= 8; - func_num += *data++; - size -= 1; - vub300->sdio_register[i].sdio_reg = func_num; - vub300->sdio_register[i].activate = 1; - vub300->sdio_register[i].prepared = 0; - i += 1; - } - dev_info(&vub300->udev->dev, - "initialized %d dynamic pseudocode registers\n", - vub300->dynamic_register_count); - return; - } else { - dev_err(&vub300->udev->dev, - "corrupt dynamic registers in firmware %s\n", - vub300->vub_name); - strncpy(vub300->vub_name, "corrupt dynamic registers", - sizeof(vub300->vub_name)); - return; - } -} - -/* - * if the binary containing the EMPTY PseudoCode can not be found - * vub300->vub_name is set anyway in order to prevent an automatic retry - */ -static void download_offload_pseudocode(struct vub300_mmc_host *vub300) -{ - struct mmc_card *card = vub300->mmc->card; - int sdio_funcs = card->sdio_funcs; - const struct firmware *fw = NULL; - int l = snprintf(vub300->vub_name, sizeof(vub300->vub_name), - "vub_%04X%04X", card->cis.vendor, card->cis.device); - int n = 0; - int retval; - for (n = 0; n < sdio_funcs; n++) { - struct sdio_func *sf = card->sdio_func[n]; - l += snprintf(vub300->vub_name + l, - sizeof(vub300->vub_name) - l, "_%04X%04X", - sf->vendor, sf->device); - }; - snprintf(vub300->vub_name + l, sizeof(vub300->vub_name) - l, ".bin"); - dev_info(&vub300->udev->dev, "requesting offload firmware %s\n", - vub300->vub_name); - retval = request_firmware(&fw, vub300->vub_name, &card->dev); - if (retval < 0) { - strncpy(vub300->vub_name, "vub_default.bin", - sizeof(vub300->vub_name)); - retval = request_firmware(&fw, vub300->vub_name, &card->dev); - if (retval < 0) { - strncpy(vub300->vub_name, - "no SDIO offload firmware found", - sizeof(vub300->vub_name)); - } else { - __download_offload_pseudocode(vub300, fw); - release_firmware(fw); - } - } else { - __download_offload_pseudocode(vub300, fw); - release_firmware(fw); - } -} - -static void vub300_usb_bulk_msg_completion(struct urb *urb) -{ /* urb completion handler - hardirq */ - complete((struct completion *)urb->context); -} - -static int vub300_usb_bulk_msg(struct vub300_mmc_host *vub300, - unsigned int pipe, void *data, int len, - int *actual_length, int timeout_msecs) -{ - /* cmd_mutex is held by vub300_cmndwork_thread */ - struct usb_device *usb_dev = vub300->udev; - struct completion done; - int retval; - vub300->urb = usb_alloc_urb(0, GFP_KERNEL); - if (!vub300->urb) - return -ENOMEM; - usb_fill_bulk_urb(vub300->urb, usb_dev, pipe, data, len, - vub300_usb_bulk_msg_completion, NULL); - init_completion(&done); - vub300->urb->context = &done; - vub300->urb->actual_length = 0; - retval = usb_submit_urb(vub300->urb, GFP_KERNEL); - if (unlikely(retval)) - goto out; - if (!wait_for_completion_timeout - (&done, msecs_to_jiffies(timeout_msecs))) { - retval = -ETIMEDOUT; - usb_kill_urb(vub300->urb); - } else { - retval = vub300->urb->status; - } -out: - *actual_length = vub300->urb->actual_length; - usb_free_urb(vub300->urb); - vub300->urb = NULL; - return retval; -} - -static int __command_read_data(struct vub300_mmc_host *vub300, - struct mmc_command *cmd, struct mmc_data *data) -{ - /* cmd_mutex is held by vub300_cmndwork_thread */ - int linear_length = vub300->datasize; - int padded_length = vub300->large_usb_packets ? - ((511 + linear_length) >> 9) << 9 : - ((63 + linear_length) >> 6) << 6; - if ((padded_length == linear_length) || !pad_input_to_usb_pkt) { - int result; - unsigned pipe; - pipe = usb_rcvbulkpipe(vub300->udev, vub300->data_inp_ep); - result = usb_sg_init(&vub300->sg_request, vub300->udev, - pipe, 0, data->sg, - data->sg_len, 0, GFP_KERNEL); - if (result < 0) { - usb_unlink_urb(vub300->command_out_urb); - usb_unlink_urb(vub300->command_res_urb); - cmd->error = result; - data->bytes_xfered = 0; - return 0; - } else { - vub300->sg_transfer_timer.expires = - jiffies + msecs_to_jiffies(2000 + - (linear_length / 16384)); - add_timer(&vub300->sg_transfer_timer); - usb_sg_wait(&vub300->sg_request); - del_timer(&vub300->sg_transfer_timer); - if (vub300->sg_request.status < 0) { - cmd->error = vub300->sg_request.status; - data->bytes_xfered = 0; - return 0; - } else { - data->bytes_xfered = vub300->datasize; - return linear_length; - } - } - } else { - u8 *buf = kmalloc(padded_length, GFP_KERNEL); - if (buf) { - int result; - unsigned pipe = usb_rcvbulkpipe(vub300->udev, - vub300->data_inp_ep); - int actual_length = 0; - result = vub300_usb_bulk_msg(vub300, pipe, buf, - padded_length, &actual_length, - 2000 + (padded_length / 16384)); - if (result < 0) { - cmd->error = result; - data->bytes_xfered = 0; - kfree(buf); - return 0; - } else if (actual_length < linear_length) { - cmd->error = -EREMOTEIO; - data->bytes_xfered = 0; - kfree(buf); - return 0; - } else { - sg_copy_from_buffer(data->sg, data->sg_len, buf, - linear_length); - kfree(buf); - data->bytes_xfered = vub300->datasize; - return linear_length; - } - } else { - cmd->error = -ENOMEM; - data->bytes_xfered = 0; - return 0; - } - } -} - -static int __command_write_data(struct vub300_mmc_host *vub300, - struct mmc_command *cmd, struct mmc_data *data) -{ - /* cmd_mutex is held by vub300_cmndwork_thread */ - unsigned pipe = usb_sndbulkpipe(vub300->udev, vub300->data_out_ep); - int linear_length = vub300->datasize; - int modulo_64_length = linear_length & 0x003F; - int modulo_512_length = linear_length & 0x01FF; - if (linear_length < 64) { - int result; - int actual_length; - sg_copy_to_buffer(data->sg, data->sg_len, - vub300->padded_buffer, - sizeof(vub300->padded_buffer)); - memset(vub300->padded_buffer + linear_length, 0, - sizeof(vub300->padded_buffer) - linear_length); - result = vub300_usb_bulk_msg(vub300, pipe, vub300->padded_buffer, - sizeof(vub300->padded_buffer), - &actual_length, 2000 + - (sizeof(vub300->padded_buffer) / - 16384)); - if (result < 0) { - cmd->error = result; - data->bytes_xfered = 0; - } else { - data->bytes_xfered = vub300->datasize; - } - } else if ((!vub300->large_usb_packets && (0 < modulo_64_length)) || - (vub300->large_usb_packets && (64 > modulo_512_length)) - ) { /* don't you just love these work-rounds */ - int padded_length = ((63 + linear_length) >> 6) << 6; - u8 *buf = kmalloc(padded_length, GFP_KERNEL); - if (buf) { - int result; - int actual_length; - sg_copy_to_buffer(data->sg, data->sg_len, buf, - padded_length); - memset(buf + linear_length, 0, - padded_length - linear_length); - result = - vub300_usb_bulk_msg(vub300, pipe, buf, - padded_length, &actual_length, - 2000 + padded_length / 16384); - kfree(buf); - if (result < 0) { - cmd->error = result; - data->bytes_xfered = 0; - } else { - data->bytes_xfered = vub300->datasize; - } - } else { - cmd->error = -ENOMEM; - data->bytes_xfered = 0; - } - } else { /* no data padding required */ - int result; - unsigned char buf[64 * 4]; - sg_copy_to_buffer(data->sg, data->sg_len, buf, sizeof(buf)); - result = usb_sg_init(&vub300->sg_request, vub300->udev, - pipe, 0, data->sg, - data->sg_len, 0, GFP_KERNEL); - if (result < 0) { - usb_unlink_urb(vub300->command_out_urb); - usb_unlink_urb(vub300->command_res_urb); - cmd->error = result; - data->bytes_xfered = 0; - } else { - vub300->sg_transfer_timer.expires = - jiffies + msecs_to_jiffies(2000 + - linear_length / 16384); - add_timer(&vub300->sg_transfer_timer); - usb_sg_wait(&vub300->sg_request); - if (cmd->error) { - data->bytes_xfered = 0; - } else { - del_timer(&vub300->sg_transfer_timer); - if (vub300->sg_request.status < 0) { - cmd->error = vub300->sg_request.status; - data->bytes_xfered = 0; - } else { - data->bytes_xfered = vub300->datasize; - } - } - } - } - return linear_length; -} - -static void __vub300_command_response(struct vub300_mmc_host *vub300, - struct mmc_command *cmd, - struct mmc_data *data, int data_length) -{ - /* cmd_mutex is held by vub300_cmndwork_thread */ - long respretval; - int msec_timeout = 1000 + data_length / 4; - respretval = - wait_for_completion_timeout(&vub300->command_complete, - msecs_to_jiffies(msec_timeout)); - if (respretval == 0) { /* TIMED OUT */ - /* we don't know which of "out" and "res" if any failed */ - int result; - vub300->usb_timed_out = 1; - usb_kill_urb(vub300->command_out_urb); - usb_kill_urb(vub300->command_res_urb); - cmd->error = -ETIMEDOUT; - result = usb_lock_device_for_reset(vub300->udev, - vub300->interface); - if (result == 0) { - result = usb_reset_device(vub300->udev); - usb_unlock_device(vub300->udev); - } - } else if (respretval < 0) { - /* we don't know which of "out" and "res" if any failed */ - usb_kill_urb(vub300->command_out_urb); - usb_kill_urb(vub300->command_res_urb); - cmd->error = respretval; - } else if (cmd->error) { - /* - * the error occurred sending the command - * or receiving the response - */ - } else if (vub300->command_out_urb->status) { - vub300->usb_transport_fail = vub300->command_out_urb->status; - cmd->error = -EPROTO == vub300->command_out_urb->status ? - -ESHUTDOWN : vub300->command_out_urb->status; - } else if (vub300->command_res_urb->status) { - vub300->usb_transport_fail = vub300->command_res_urb->status; - cmd->error = -EPROTO == vub300->command_res_urb->status ? - -ESHUTDOWN : vub300->command_res_urb->status; - } else if (vub300->resp.common.header_type == 0x00) { - /* - * the command completed successfully - * and there was no piggybacked data - */ - } else if (vub300->resp.common.header_type == RESPONSE_ERROR) { - cmd->error = - vub300_response_error(vub300->resp.error.error_code); - if (vub300->data) - usb_sg_cancel(&vub300->sg_request); - } else if (vub300->resp.common.header_type == RESPONSE_PIGGYBACKED) { - int offloaded_data_length = - vub300->resp.common.header_size - - sizeof(struct sd_register_header); - int register_count = offloaded_data_length >> 3; - int ri = 0; - while (register_count--) { - add_offloaded_reg(vub300, &vub300->resp.pig.reg[ri]); - ri += 1; - } - vub300->resp.common.header_size = - sizeof(struct sd_register_header); - vub300->resp.common.header_type = 0x00; - cmd->error = 0; - } else if (vub300->resp.common.header_type == RESPONSE_PIG_DISABLED) { - int offloaded_data_length = - vub300->resp.common.header_size - - sizeof(struct sd_register_header); - int register_count = offloaded_data_length >> 3; - int ri = 0; - while (register_count--) { - add_offloaded_reg(vub300, &vub300->resp.pig.reg[ri]); - ri += 1; - } - mutex_lock(&vub300->irq_mutex); - if (vub300->irqs_queued) { - vub300->irqs_queued += 1; - } else if (vub300->irq_enabled) { - vub300->irqs_queued += 1; - vub300_queue_poll_work(vub300, 0); - } else { - vub300->irqs_queued += 1; - } - vub300->irq_disabled = 1; - mutex_unlock(&vub300->irq_mutex); - vub300->resp.common.header_size = - sizeof(struct sd_register_header); - vub300->resp.common.header_type = 0x00; - cmd->error = 0; - } else if (vub300->resp.common.header_type == RESPONSE_PIG_ENABLED) { - int offloaded_data_length = - vub300->resp.common.header_size - - sizeof(struct sd_register_header); - int register_count = offloaded_data_length >> 3; - int ri = 0; - while (register_count--) { - add_offloaded_reg(vub300, &vub300->resp.pig.reg[ri]); - ri += 1; - } - mutex_lock(&vub300->irq_mutex); - if (vub300->irqs_queued) { - vub300->irqs_queued += 1; - } else if (vub300->irq_enabled) { - vub300->irqs_queued += 1; - vub300_queue_poll_work(vub300, 0); - } else { - vub300->irqs_queued += 1; - } - vub300->irq_disabled = 0; - mutex_unlock(&vub300->irq_mutex); - vub300->resp.common.header_size = - sizeof(struct sd_register_header); - vub300->resp.common.header_type = 0x00; - cmd->error = 0; - } else { - cmd->error = -EINVAL; - } -} - -static void construct_request_response(struct vub300_mmc_host *vub300, - struct mmc_command *cmd) -{ - int resp_len = vub300->resp_len; - int less_cmd = (17 == resp_len) ? resp_len : resp_len - 1; - int bytes = 3 & less_cmd; - int words = less_cmd >> 2; - u8 *r = vub300->resp.response.command_response; - if (bytes == 3) { - cmd->resp[words] = (r[1 + (words << 2)] << 24) - | (r[2 + (words << 2)] << 16) - | (r[3 + (words << 2)] << 8); - } else if (bytes == 2) { - cmd->resp[words] = (r[1 + (words << 2)] << 24) - | (r[2 + (words << 2)] << 16); - } else if (bytes == 1) { - cmd->resp[words] = (r[1 + (words << 2)] << 24); - } - while (words-- > 0) { - cmd->resp[words] = (r[1 + (words << 2)] << 24) - | (r[2 + (words << 2)] << 16) - | (r[3 + (words << 2)] << 8) - | (r[4 + (words << 2)] << 0); - } - if ((cmd->opcode == 53) && (0x000000FF & cmd->resp[0])) - cmd->resp[0] &= 0xFFFFFF00; -} - -/* this thread runs only when there is an upper level command req outstanding */ -static void vub300_cmndwork_thread(struct work_struct *work) -{ - struct vub300_mmc_host *vub300 = - container_of(work, struct vub300_mmc_host, cmndwork); - if (!vub300->interface) { - kref_put(&vub300->kref, vub300_delete); - return; - } else { - struct mmc_request *req = vub300->req; - struct mmc_command *cmd = vub300->cmd; - struct mmc_data *data = vub300->data; - int data_length; - mutex_lock(&vub300->cmd_mutex); - init_completion(&vub300->command_complete); - if (likely(vub300->vub_name[0]) || !vub300->mmc->card || - !mmc_card_present(vub300->mmc->card)) { - /* - * the name of the EMPTY Pseudo firmware file - * is used as a flag to indicate that the file - * has been already downloaded to the VUB300 chip - */ - } else if (0 == vub300->mmc->card->sdio_funcs) { - strncpy(vub300->vub_name, "SD memory device", - sizeof(vub300->vub_name)); - } else { - download_offload_pseudocode(vub300); - } - send_command(vub300); - if (!data) - data_length = 0; - else if (MMC_DATA_READ & data->flags) - data_length = __command_read_data(vub300, cmd, data); - else - data_length = __command_write_data(vub300, cmd, data); - __vub300_command_response(vub300, cmd, data, data_length); - vub300->req = NULL; - vub300->cmd = NULL; - vub300->data = NULL; - if (cmd->error) { - if (cmd->error == -ENOMEDIUM) - check_vub300_port_status(vub300); - mutex_unlock(&vub300->cmd_mutex); - mmc_request_done(vub300->mmc, req); - kref_put(&vub300->kref, vub300_delete); - return; - } else { - construct_request_response(vub300, cmd); - vub300->resp_len = 0; - mutex_unlock(&vub300->cmd_mutex); - kref_put(&vub300->kref, vub300_delete); - mmc_request_done(vub300->mmc, req); - return; - } - } -} - -static int examine_cyclic_buffer(struct vub300_mmc_host *vub300, - struct mmc_command *cmd, u8 Function) -{ - /* cmd_mutex is held by vub300_mmc_request */ - u8 cmd0 = 0xFF & (cmd->arg >> 24); - u8 cmd1 = 0xFF & (cmd->arg >> 16); - u8 cmd2 = 0xFF & (cmd->arg >> 8); - u8 cmd3 = 0xFF & (cmd->arg >> 0); - int first = MAXREGMASK & vub300->fn[Function].offload_point; - struct offload_registers_access *rf = &vub300->fn[Function].reg[first]; - if (cmd0 == rf->command_byte[0] && - cmd1 == rf->command_byte[1] && - cmd2 == rf->command_byte[2] && - cmd3 == rf->command_byte[3]) { - u8 checksum = 0x00; - cmd->resp[1] = checksum << 24; - cmd->resp[0] = (rf->Respond_Byte[0] << 24) - | (rf->Respond_Byte[1] << 16) - | (rf->Respond_Byte[2] << 8) - | (rf->Respond_Byte[3] << 0); - vub300->fn[Function].offload_point += 1; - vub300->fn[Function].offload_count -= 1; - vub300->total_offload_count -= 1; - return 1; - } else { - int delta = 1; /* because it does not match the first one */ - u8 register_count = vub300->fn[Function].offload_count - 1; - u32 register_point = vub300->fn[Function].offload_point + 1; - while (0 < register_count) { - int point = MAXREGMASK & register_point; - struct offload_registers_access *r = - &vub300->fn[Function].reg[point]; - if (cmd0 == r->command_byte[0] && - cmd1 == r->command_byte[1] && - cmd2 == r->command_byte[2] && - cmd3 == r->command_byte[3]) { - u8 checksum = 0x00; - cmd->resp[1] = checksum << 24; - cmd->resp[0] = (r->Respond_Byte[0] << 24) - | (r->Respond_Byte[1] << 16) - | (r->Respond_Byte[2] << 8) - | (r->Respond_Byte[3] << 0); - vub300->fn[Function].offload_point += delta; - vub300->fn[Function].offload_count -= delta; - vub300->total_offload_count -= delta; - return 1; - } else { - register_point += 1; - register_count -= 1; - delta += 1; - continue; - } - } - return 0; - } -} - -static int satisfy_request_from_offloaded_data(struct vub300_mmc_host *vub300, - struct mmc_command *cmd) -{ - /* cmd_mutex is held by vub300_mmc_request */ - u8 regs = vub300->dynamic_register_count; - u8 i = 0; - u8 func = FUN(cmd); - u32 reg = REG(cmd); - while (0 < regs--) { - if ((vub300->sdio_register[i].func_num == func) && - (vub300->sdio_register[i].sdio_reg == reg)) { - if (!vub300->sdio_register[i].prepared) { - return 0; - } else if ((0x80000000 & cmd->arg) == 0x80000000) { - /* - * a write to a dynamic register - * nullifies our offloaded value - */ - vub300->sdio_register[i].prepared = 0; - return 0; - } else { - u8 checksum = 0x00; - u8 rsp0 = 0x00; - u8 rsp1 = 0x00; - u8 rsp2 = vub300->sdio_register[i].response; - u8 rsp3 = vub300->sdio_register[i].regvalue; - vub300->sdio_register[i].prepared = 0; - cmd->resp[1] = checksum << 24; - cmd->resp[0] = (rsp0 << 24) - | (rsp1 << 16) - | (rsp2 << 8) - | (rsp3 << 0); - return 1; - } - } else { - i += 1; - continue; - } - }; - if (vub300->total_offload_count == 0) - return 0; - else if (vub300->fn[func].offload_count == 0) - return 0; - else - return examine_cyclic_buffer(vub300, cmd, func); -} - -static void vub300_mmc_request(struct mmc_host *mmc, struct mmc_request *req) -{ /* NOT irq */ - struct mmc_command *cmd = req->cmd; - struct vub300_mmc_host *vub300 = mmc_priv(mmc); - if (!vub300->interface) { - cmd->error = -ESHUTDOWN; - mmc_request_done(mmc, req); - return; - } else { - struct mmc_data *data = req->data; - if (!vub300->card_powered) { - cmd->error = -ENOMEDIUM; - mmc_request_done(mmc, req); - return; - } - if (!vub300->card_present) { - cmd->error = -ENOMEDIUM; - mmc_request_done(mmc, req); - return; - } - if (vub300->usb_transport_fail) { - cmd->error = vub300->usb_transport_fail; - mmc_request_done(mmc, req); - return; - } - if (!vub300->interface) { - cmd->error = -ENODEV; - mmc_request_done(mmc, req); - return; - } - kref_get(&vub300->kref); - mutex_lock(&vub300->cmd_mutex); - mod_timer(&vub300->inactivity_timer, jiffies + HZ); - /* - * for performance we have to return immediately - * if the requested data has been offloaded - */ - if (cmd->opcode == 52 && - satisfy_request_from_offloaded_data(vub300, cmd)) { - cmd->error = 0; - mutex_unlock(&vub300->cmd_mutex); - kref_put(&vub300->kref, vub300_delete); - mmc_request_done(mmc, req); - return; - } else { - vub300->cmd = cmd; - vub300->req = req; - vub300->data = data; - if (data) - vub300->datasize = data->blksz * data->blocks; - else - vub300->datasize = 0; - vub300_queue_cmnd_work(vub300); - mutex_unlock(&vub300->cmd_mutex); - kref_put(&vub300->kref, vub300_delete); - /* - * the kernel lock diagnostics complain - * if the cmd_mutex * is "passed on" - * to the cmndwork thread, - * so we must release it now - * and re-acquire it in the cmndwork thread - */ - } - } -} - -static void __set_clock_speed(struct vub300_mmc_host *vub300, u8 buf[8], - struct mmc_ios *ios) -{ - int buf_array_size = 8; /* ARRAY_SIZE(buf) does not work !!! */ - int retval; - u32 kHzClock; - if (ios->clock >= 48000000) - kHzClock = 48000; - else if (ios->clock >= 24000000) - kHzClock = 24000; - else if (ios->clock >= 20000000) - kHzClock = 20000; - else if (ios->clock >= 15000000) - kHzClock = 15000; - else if (ios->clock >= 200000) - kHzClock = 200; - else - kHzClock = 0; - { - int i; - u64 c = kHzClock; - for (i = 0; i < buf_array_size; i++) { - buf[i] = c; - c >>= 8; - } - } - retval = - usb_control_msg(vub300->udev, usb_sndctrlpipe(vub300->udev, 0), - SET_CLOCK_SPEED, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 0x00, 0x00, buf, buf_array_size, HZ); - if (retval != 8) { - dev_err(&vub300->udev->dev, "SET_CLOCK_SPEED" - " %dkHz failed with retval=%d\n", kHzClock, retval); - } else { - dev_dbg(&vub300->udev->dev, "SET_CLOCK_SPEED" - " %dkHz\n", kHzClock); - } -} - -static void vub300_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) -{ /* NOT irq */ - struct vub300_mmc_host *vub300 = mmc_priv(mmc); - if (!vub300->interface) - return; - kref_get(&vub300->kref); - mutex_lock(&vub300->cmd_mutex); - if ((ios->power_mode == MMC_POWER_OFF) && vub300->card_powered) { - vub300->card_powered = 0; - usb_control_msg(vub300->udev, usb_sndctrlpipe(vub300->udev, 0), - SET_SD_POWER, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 0x0000, 0x0000, NULL, 0, HZ); - /* must wait for the VUB300 u-proc to boot up */ - msleep(600); - } else if ((ios->power_mode == MMC_POWER_UP) && !vub300->card_powered) { - usb_control_msg(vub300->udev, usb_sndctrlpipe(vub300->udev, 0), - SET_SD_POWER, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 0x0001, 0x0000, NULL, 0, HZ); - msleep(600); - vub300->card_powered = 1; - } else if (ios->power_mode == MMC_POWER_ON) { - u8 *buf = kmalloc(8, GFP_KERNEL); - if (buf) { - __set_clock_speed(vub300, buf, ios); - kfree(buf); - } - } else { - /* this should mean no change of state */ - } - mutex_unlock(&vub300->cmd_mutex); - kref_put(&vub300->kref, vub300_delete); -} - -static int vub300_mmc_get_ro(struct mmc_host *mmc) -{ - struct vub300_mmc_host *vub300 = mmc_priv(mmc); - return vub300->read_only; -} - -static void vub300_enable_sdio_irq(struct mmc_host *mmc, int enable) -{ /* NOT irq */ - struct vub300_mmc_host *vub300 = mmc_priv(mmc); - if (!vub300->interface) - return; - kref_get(&vub300->kref); - if (enable) { - mutex_lock(&vub300->irq_mutex); - if (vub300->irqs_queued) { - vub300->irqs_queued -= 1; - mmc_signal_sdio_irq(vub300->mmc); - } else if (vub300->irq_disabled) { - vub300->irq_disabled = 0; - vub300->irq_enabled = 1; - vub300_queue_poll_work(vub300, 0); - } else if (vub300->irq_enabled) { - /* this should not happen, so we will just ignore it */ - } else { - vub300->irq_enabled = 1; - vub300_queue_poll_work(vub300, 0); - } - mutex_unlock(&vub300->irq_mutex); - } else { - vub300->irq_enabled = 0; - } - kref_put(&vub300->kref, vub300_delete); -} - -void vub300_init_card(struct mmc_host *mmc, struct mmc_card *card) -{ /* NOT irq */ - struct vub300_mmc_host *vub300 = mmc_priv(mmc); - dev_info(&vub300->udev->dev, "NO host QUIRKS for this card\n"); -} - -static struct mmc_host_ops vub300_mmc_ops = { - .request = vub300_mmc_request, - .set_ios = vub300_mmc_set_ios, - .get_ro = vub300_mmc_get_ro, - .enable_sdio_irq = vub300_enable_sdio_irq, - .init_card = vub300_init_card, -}; - -static int vub300_probe(struct usb_interface *interface, - const struct usb_device_id *id) -{ /* NOT irq */ - struct vub300_mmc_host *vub300; - struct usb_host_interface *iface_desc; - struct usb_device *udev = usb_get_dev(interface_to_usbdev(interface)); - int i; - int retval = -ENOMEM; - struct urb *command_out_urb; - struct urb *command_res_urb; - struct mmc_host *mmc; - char manufacturer[48]; - char product[32]; - char serial_number[32]; - usb_string(udev, udev->descriptor.iManufacturer, manufacturer, - sizeof(manufacturer)); - usb_string(udev, udev->descriptor.iProduct, product, sizeof(product)); - usb_string(udev, udev->descriptor.iSerialNumber, serial_number, - sizeof(serial_number)); - dev_info(&udev->dev, "probing VID:PID(%04X:%04X) %s %s %s\n", - udev->descriptor.idVendor, udev->descriptor.idProduct, - manufacturer, product, serial_number); - command_out_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!command_out_urb) { - retval = -ENOMEM; - dev_err(&udev->dev, "not enough memory for command_out_urb\n"); - goto error0; - } - command_res_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!command_res_urb) { - retval = -ENOMEM; - dev_err(&udev->dev, "not enough memory for command_res_urb\n"); - goto error1; - } - /* this also allocates memory for our VUB300 mmc host device */ - mmc = mmc_alloc_host(sizeof(struct vub300_mmc_host), &udev->dev); - if (!mmc) { - retval = -ENOMEM; - dev_err(&udev->dev, "not enough memory for the mmc_host\n"); - goto error4; - } - /* MMC core transfer sizes tunable parameters */ - mmc->caps = 0; - if (!force_1_bit_data_xfers) - mmc->caps |= MMC_CAP_4_BIT_DATA; - if (!force_polling_for_irqs) - mmc->caps |= MMC_CAP_SDIO_IRQ; - mmc->caps &= ~MMC_CAP_NEEDS_POLL; - /* - * MMC_CAP_NEEDS_POLL causes core.c:mmc_rescan() to poll - * for devices which results in spurious CMD7's being - * issued which stops some SDIO cards from working - */ - if (limit_speed_to_24_MHz) { - mmc->caps |= MMC_CAP_MMC_HIGHSPEED; - mmc->caps |= MMC_CAP_SD_HIGHSPEED; - mmc->f_max = 24000000; - dev_info(&udev->dev, "limiting SDIO speed to 24_MHz\n"); - } else { - mmc->caps |= MMC_CAP_MMC_HIGHSPEED; - mmc->caps |= MMC_CAP_SD_HIGHSPEED; - mmc->f_max = 48000000; - } - mmc->f_min = 200000; - mmc->max_blk_count = 511; - mmc->max_blk_size = 512; - mmc->max_segs = 128; - if (force_max_req_size) - mmc->max_req_size = force_max_req_size * 1024; - else - mmc->max_req_size = 64 * 1024; - mmc->max_seg_size = mmc->max_req_size; - mmc->ocr_avail = 0; - mmc->ocr_avail |= MMC_VDD_165_195; - mmc->ocr_avail |= MMC_VDD_20_21; - mmc->ocr_avail |= MMC_VDD_21_22; - mmc->ocr_avail |= MMC_VDD_22_23; - mmc->ocr_avail |= MMC_VDD_23_24; - mmc->ocr_avail |= MMC_VDD_24_25; - mmc->ocr_avail |= MMC_VDD_25_26; - mmc->ocr_avail |= MMC_VDD_26_27; - mmc->ocr_avail |= MMC_VDD_27_28; - mmc->ocr_avail |= MMC_VDD_28_29; - mmc->ocr_avail |= MMC_VDD_29_30; - mmc->ocr_avail |= MMC_VDD_30_31; - mmc->ocr_avail |= MMC_VDD_31_32; - mmc->ocr_avail |= MMC_VDD_32_33; - mmc->ocr_avail |= MMC_VDD_33_34; - mmc->ocr_avail |= MMC_VDD_34_35; - mmc->ocr_avail |= MMC_VDD_35_36; - mmc->ops = &vub300_mmc_ops; - vub300 = mmc_priv(mmc); - vub300->mmc = mmc; - vub300->card_powered = 0; - vub300->bus_width = 0; - vub300->cmnd.head.block_size[0] = 0x00; - vub300->cmnd.head.block_size[1] = 0x00; - vub300->app_spec = 0; - mutex_init(&vub300->cmd_mutex); - mutex_init(&vub300->irq_mutex); - vub300->command_out_urb = command_out_urb; - vub300->command_res_urb = command_res_urb; - vub300->usb_timed_out = 0; - vub300->dynamic_register_count = 0; - - for (i = 0; i < ARRAY_SIZE(vub300->fn); i++) { - vub300->fn[i].offload_point = 0; - vub300->fn[i].offload_count = 0; - } - - vub300->total_offload_count = 0; - vub300->irq_enabled = 0; - vub300->irq_disabled = 0; - vub300->irqs_queued = 0; - - for (i = 0; i < ARRAY_SIZE(vub300->sdio_register); i++) - vub300->sdio_register[i++].activate = 0; - - vub300->udev = udev; - vub300->interface = interface; - vub300->cmnd_res_ep = 0; - vub300->cmnd_out_ep = 0; - vub300->data_inp_ep = 0; - vub300->data_out_ep = 0; - - for (i = 0; i < ARRAY_SIZE(vub300->fbs); i++) - vub300->fbs[i] = 512; - - /* - * set up the endpoint information - * - * use the first pair of bulk-in and bulk-out - * endpoints for Command/Response+Interrupt - * - * use the second pair of bulk-in and bulk-out - * endpoints for Data In/Out - */ - vub300->large_usb_packets = 0; - iface_desc = interface->cur_altsetting; - for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { - struct usb_endpoint_descriptor *endpoint = - &iface_desc->endpoint[i].desc; - dev_info(&vub300->udev->dev, - "vub300 testing %s EndPoint(%d) %02X\n", - usb_endpoint_is_bulk_in(endpoint) ? "BULK IN" : - usb_endpoint_is_bulk_out(endpoint) ? "BULK OUT" : - "UNKNOWN", i, endpoint->bEndpointAddress); - if (endpoint->wMaxPacketSize > 64) - vub300->large_usb_packets = 1; - if (usb_endpoint_is_bulk_in(endpoint)) { - if (!vub300->cmnd_res_ep) { - vub300->cmnd_res_ep = - endpoint->bEndpointAddress; - } else if (!vub300->data_inp_ep) { - vub300->data_inp_ep = - endpoint->bEndpointAddress; - } else { - dev_warn(&vub300->udev->dev, - "ignoring" - " unexpected bulk_in endpoint"); - } - } else if (usb_endpoint_is_bulk_out(endpoint)) { - if (!vub300->cmnd_out_ep) { - vub300->cmnd_out_ep = - endpoint->bEndpointAddress; - } else if (!vub300->data_out_ep) { - vub300->data_out_ep = - endpoint->bEndpointAddress; - } else { - dev_warn(&vub300->udev->dev, - "ignoring" - " unexpected bulk_out endpoint"); - } - } else { - dev_warn(&vub300->udev->dev, - "vub300 ignoring EndPoint(%d) %02X", i, - endpoint->bEndpointAddress); - } - } - if (vub300->cmnd_res_ep && vub300->cmnd_out_ep && - vub300->data_inp_ep && vub300->data_out_ep) { - dev_info(&vub300->udev->dev, - "vub300 %s packets" - " using EndPoints %02X %02X %02X %02X\n", - vub300->large_usb_packets ? "LARGE" : "SMALL", - vub300->cmnd_out_ep, vub300->cmnd_res_ep, - vub300->data_out_ep, vub300->data_inp_ep); - /* we have the expected EndPoints */ - } else { - dev_err(&vub300->udev->dev, - "Could not find two sets of bulk-in/out endpoint pairs\n"); - retval = -EINVAL; - goto error5; - } - retval = - usb_control_msg(vub300->udev, usb_rcvctrlpipe(vub300->udev, 0), - GET_HC_INF0, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 0x0000, 0x0000, &vub300->hc_info, - sizeof(vub300->hc_info), HZ); - if (retval < 0) - goto error5; - retval = - usb_control_msg(vub300->udev, usb_rcvctrlpipe(vub300->udev, 0), - SET_ROM_WAIT_STATES, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - firmware_rom_wait_states, 0x0000, NULL, 0, HZ); - if (retval < 0) - goto error5; - dev_info(&vub300->udev->dev, - "operating_mode = %s %s %d MHz %s %d byte USB packets\n", - (mmc->caps & MMC_CAP_SDIO_IRQ) ? "IRQs" : "POLL", - (mmc->caps & MMC_CAP_4_BIT_DATA) ? "4-bit" : "1-bit", - mmc->f_max / 1000000, - pad_input_to_usb_pkt ? "padding input data to" : "with", - vub300->large_usb_packets ? 512 : 64); - retval = - usb_control_msg(vub300->udev, usb_rcvctrlpipe(vub300->udev, 0), - GET_SYSTEM_PORT_STATUS, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 0x0000, 0x0000, &vub300->system_port_status, - sizeof(vub300->system_port_status), HZ); - if (retval < 0) { - goto error4; - } else if (sizeof(vub300->system_port_status) == retval) { - vub300->card_present = - (0x0001 & vub300->system_port_status.port_flags) ? 1 : 0; - vub300->read_only = - (0x0010 & vub300->system_port_status.port_flags) ? 1 : 0; - } else { - goto error4; - } - usb_set_intfdata(interface, vub300); - INIT_DELAYED_WORK(&vub300->pollwork, vub300_pollwork_thread); - INIT_WORK(&vub300->cmndwork, vub300_cmndwork_thread); - INIT_WORK(&vub300->deadwork, vub300_deadwork_thread); - kref_init(&vub300->kref); - init_timer(&vub300->sg_transfer_timer); - vub300->sg_transfer_timer.data = (unsigned long)vub300; - vub300->sg_transfer_timer.function = vub300_sg_timed_out; - kref_get(&vub300->kref); - init_timer(&vub300->inactivity_timer); - vub300->inactivity_timer.data = (unsigned long)vub300; - vub300->inactivity_timer.function = vub300_inactivity_timer_expired; - vub300->inactivity_timer.expires = jiffies + HZ; - add_timer(&vub300->inactivity_timer); - if (vub300->card_present) - dev_info(&vub300->udev->dev, - "USB vub300 remote SDIO host controller[%d]" - "connected with SD/SDIO card inserted\n", - interface_to_InterfaceNumber(interface)); - else - dev_info(&vub300->udev->dev, - "USB vub300 remote SDIO host controller[%d]" - "connected with no SD/SDIO card inserted\n", - interface_to_InterfaceNumber(interface)); - mmc_add_host(mmc); - return 0; -error5: - mmc_free_host(mmc); - /* - * and hence also frees vub300 - * which is contained at the end of struct mmc - */ -error4: - usb_free_urb(command_out_urb); -error1: - usb_free_urb(command_res_urb); -error0: - return retval; -} - -static void vub300_disconnect(struct usb_interface *interface) -{ /* NOT irq */ - struct vub300_mmc_host *vub300 = usb_get_intfdata(interface); - if (!vub300 || !vub300->mmc) { - return; - } else { - struct mmc_host *mmc = vub300->mmc; - if (!vub300->mmc) { - return; - } else { - int ifnum = interface_to_InterfaceNumber(interface); - usb_set_intfdata(interface, NULL); - /* prevent more I/O from starting */ - vub300->interface = NULL; - kref_put(&vub300->kref, vub300_delete); - mmc_remove_host(mmc); - pr_info("USB vub300 remote SDIO host controller[%d]" - " now disconnected", ifnum); - return; - } - } -} - -#ifdef CONFIG_PM -static int vub300_suspend(struct usb_interface *intf, pm_message_t message) -{ - struct vub300_mmc_host *vub300 = usb_get_intfdata(intf); - if (!vub300 || !vub300->mmc) { - return 0; - } else { - struct mmc_host *mmc = vub300->mmc; - mmc_suspend_host(mmc); - return 0; - } -} - -static int vub300_resume(struct usb_interface *intf) -{ - struct vub300_mmc_host *vub300 = usb_get_intfdata(intf); - if (!vub300 || !vub300->mmc) { - return 0; - } else { - struct mmc_host *mmc = vub300->mmc; - mmc_resume_host(mmc); - return 0; - } -} -#else -#define vub300_suspend NULL -#define vub300_resume NULL -#endif -static int vub300_pre_reset(struct usb_interface *intf) -{ /* NOT irq */ - struct vub300_mmc_host *vub300 = usb_get_intfdata(intf); - mutex_lock(&vub300->cmd_mutex); - return 0; -} - -static int vub300_post_reset(struct usb_interface *intf) -{ /* NOT irq */ - struct vub300_mmc_host *vub300 = usb_get_intfdata(intf); - /* we are sure no URBs are active - no locking needed */ - vub300->errors = -EPIPE; - mutex_unlock(&vub300->cmd_mutex); - return 0; -} - -static struct usb_driver vub300_driver = { - .name = "vub300", - .probe = vub300_probe, - .disconnect = vub300_disconnect, - .suspend = vub300_suspend, - .resume = vub300_resume, - .pre_reset = vub300_pre_reset, - .post_reset = vub300_post_reset, - .id_table = vub300_table, - .supports_autosuspend = 1, -}; - -static int __init vub300_init(void) -{ /* NOT irq */ - int result; - - pr_info("VUB300 Driver rom wait states = %02X irqpoll timeout = %04X", - firmware_rom_wait_states, 0x0FFFF & firmware_irqpoll_timeout); - cmndworkqueue = create_singlethread_workqueue("kvub300c"); - if (!cmndworkqueue) { - pr_err("not enough memory for the REQUEST workqueue"); - result = -ENOMEM; - goto out1; - } - pollworkqueue = create_singlethread_workqueue("kvub300p"); - if (!pollworkqueue) { - pr_err("not enough memory for the IRQPOLL workqueue"); - result = -ENOMEM; - goto out2; - } - deadworkqueue = create_singlethread_workqueue("kvub300d"); - if (!deadworkqueue) { - pr_err("not enough memory for the EXPIRED workqueue"); - result = -ENOMEM; - goto out3; - } - result = usb_register(&vub300_driver); - if (result) { - pr_err("usb_register failed. Error number %d", result); - goto out4; - } - return 0; -out4: - destroy_workqueue(deadworkqueue); -out3: - destroy_workqueue(pollworkqueue); -out2: - destroy_workqueue(cmndworkqueue); -out1: - return result; -} - -static void __exit vub300_exit(void) -{ - usb_deregister(&vub300_driver); - flush_workqueue(cmndworkqueue); - flush_workqueue(pollworkqueue); - flush_workqueue(deadworkqueue); - destroy_workqueue(cmndworkqueue); - destroy_workqueue(pollworkqueue); - destroy_workqueue(deadworkqueue); -} - -module_init(vub300_init); -module_exit(vub300_exit); - -MODULE_AUTHOR("Tony Olech <tony.olech@elandigitalsystems.com>"); -MODULE_DESCRIPTION("VUB300 USB to SD/MMC/SDIO adapter driver"); -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/mmc/host/wbsd.c b/ANDROID_3.4.5/drivers/mmc/host/wbsd.c deleted file mode 100644 index 64acd9ce..00000000 --- a/ANDROID_3.4.5/drivers/mmc/host/wbsd.c +++ /dev/null @@ -1,2047 +0,0 @@ -/* - * linux/drivers/mmc/host/wbsd.c - Winbond W83L51xD SD/MMC driver - * - * Copyright (C) 2004-2007 Pierre Ossman, All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at - * your option) any later version. - * - * - * Warning! - * - * Changes to the FIFO system should be done with extreme care since - * the hardware is full of bugs related to the FIFO. Known issues are: - * - * - FIFO size field in FSR is always zero. - * - * - FIFO interrupts tend not to work as they should. Interrupts are - * triggered only for full/empty events, not for threshold values. - * - * - On APIC systems the FIFO empty interrupt is sometimes lost. - */ - -#include <linux/module.h> -#include <linux/moduleparam.h> -#include <linux/init.h> -#include <linux/ioport.h> -#include <linux/platform_device.h> -#include <linux/interrupt.h> -#include <linux/dma-mapping.h> -#include <linux/delay.h> -#include <linux/pnp.h> -#include <linux/highmem.h> -#include <linux/mmc/host.h> -#include <linux/scatterlist.h> -#include <linux/slab.h> - -#include <asm/io.h> -#include <asm/dma.h> - -#include "wbsd.h" - -#define DRIVER_NAME "wbsd" - -#define DBG(x...) \ - pr_debug(DRIVER_NAME ": " x) -#define DBGF(f, x...) \ - pr_debug(DRIVER_NAME " [%s()]: " f, __func__ , ##x) - -/* - * Device resources - */ - -#ifdef CONFIG_PNP - -static const struct pnp_device_id pnp_dev_table[] = { - { "WEC0517", 0 }, - { "WEC0518", 0 }, - { "", 0 }, -}; - -MODULE_DEVICE_TABLE(pnp, pnp_dev_table); - -#endif /* CONFIG_PNP */ - -static const int config_ports[] = { 0x2E, 0x4E }; -static const int unlock_codes[] = { 0x83, 0x87 }; - -static const int valid_ids[] = { - 0x7112, -}; - -#ifdef CONFIG_PNP -static unsigned int param_nopnp = 0; -#else -static const unsigned int param_nopnp = 1; -#endif -static unsigned int param_io = 0x248; -static unsigned int param_irq = 6; -static int param_dma = 2; - -/* - * Basic functions - */ - -static inline void wbsd_unlock_config(struct wbsd_host *host) -{ - BUG_ON(host->config == 0); - - outb(host->unlock_code, host->config); - outb(host->unlock_code, host->config); -} - -static inline void wbsd_lock_config(struct wbsd_host *host) -{ - BUG_ON(host->config == 0); - - outb(LOCK_CODE, host->config); -} - -static inline void wbsd_write_config(struct wbsd_host *host, u8 reg, u8 value) -{ - BUG_ON(host->config == 0); - - outb(reg, host->config); - outb(value, host->config + 1); -} - -static inline u8 wbsd_read_config(struct wbsd_host *host, u8 reg) -{ - BUG_ON(host->config == 0); - - outb(reg, host->config); - return inb(host->config + 1); -} - -static inline void wbsd_write_index(struct wbsd_host *host, u8 index, u8 value) -{ - outb(index, host->base + WBSD_IDXR); - outb(value, host->base + WBSD_DATAR); -} - -static inline u8 wbsd_read_index(struct wbsd_host *host, u8 index) -{ - outb(index, host->base + WBSD_IDXR); - return inb(host->base + WBSD_DATAR); -} - -/* - * Common routines - */ - -static void wbsd_init_device(struct wbsd_host *host) -{ - u8 setup, ier; - - /* - * Reset chip (SD/MMC part) and fifo. - */ - setup = wbsd_read_index(host, WBSD_IDX_SETUP); - setup |= WBSD_FIFO_RESET | WBSD_SOFT_RESET; - wbsd_write_index(host, WBSD_IDX_SETUP, setup); - - /* - * Set DAT3 to input - */ - setup &= ~WBSD_DAT3_H; - wbsd_write_index(host, WBSD_IDX_SETUP, setup); - host->flags &= ~WBSD_FIGNORE_DETECT; - - /* - * Read back default clock. - */ - host->clk = wbsd_read_index(host, WBSD_IDX_CLK); - - /* - * Power down port. - */ - outb(WBSD_POWER_N, host->base + WBSD_CSR); - - /* - * Set maximum timeout. - */ - wbsd_write_index(host, WBSD_IDX_TAAC, 0x7F); - - /* - * Test for card presence - */ - if (inb(host->base + WBSD_CSR) & WBSD_CARDPRESENT) - host->flags |= WBSD_FCARD_PRESENT; - else - host->flags &= ~WBSD_FCARD_PRESENT; - - /* - * Enable interesting interrupts. - */ - ier = 0; - ier |= WBSD_EINT_CARD; - ier |= WBSD_EINT_FIFO_THRE; - ier |= WBSD_EINT_CRC; - ier |= WBSD_EINT_TIMEOUT; - ier |= WBSD_EINT_TC; - - outb(ier, host->base + WBSD_EIR); - - /* - * Clear interrupts. - */ - inb(host->base + WBSD_ISR); -} - -static void wbsd_reset(struct wbsd_host *host) -{ - u8 setup; - - pr_err("%s: Resetting chip\n", mmc_hostname(host->mmc)); - - /* - * Soft reset of chip (SD/MMC part). - */ - setup = wbsd_read_index(host, WBSD_IDX_SETUP); - setup |= WBSD_SOFT_RESET; - wbsd_write_index(host, WBSD_IDX_SETUP, setup); -} - -static void wbsd_request_end(struct wbsd_host *host, struct mmc_request *mrq) -{ - unsigned long dmaflags; - - if (host->dma >= 0) { - /* - * Release ISA DMA controller. - */ - dmaflags = claim_dma_lock(); - disable_dma(host->dma); - clear_dma_ff(host->dma); - release_dma_lock(dmaflags); - - /* - * Disable DMA on host. - */ - wbsd_write_index(host, WBSD_IDX_DMA, 0); - } - - host->mrq = NULL; - - /* - * MMC layer might call back into the driver so first unlock. - */ - spin_unlock(&host->lock); - mmc_request_done(host->mmc, mrq); - spin_lock(&host->lock); -} - -/* - * Scatter/gather functions - */ - -static inline void wbsd_init_sg(struct wbsd_host *host, struct mmc_data *data) -{ - /* - * Get info. about SG list from data structure. - */ - host->cur_sg = data->sg; - host->num_sg = data->sg_len; - - host->offset = 0; - host->remain = host->cur_sg->length; -} - -static inline int wbsd_next_sg(struct wbsd_host *host) -{ - /* - * Skip to next SG entry. - */ - host->cur_sg++; - host->num_sg--; - - /* - * Any entries left? - */ - if (host->num_sg > 0) { - host->offset = 0; - host->remain = host->cur_sg->length; - } - - return host->num_sg; -} - -static inline char *wbsd_sg_to_buffer(struct wbsd_host *host) -{ - return sg_virt(host->cur_sg); -} - -static inline void wbsd_sg_to_dma(struct wbsd_host *host, struct mmc_data *data) -{ - unsigned int len, i; - struct scatterlist *sg; - char *dmabuf = host->dma_buffer; - char *sgbuf; - - sg = data->sg; - len = data->sg_len; - - for (i = 0; i < len; i++) { - sgbuf = sg_virt(&sg[i]); - memcpy(dmabuf, sgbuf, sg[i].length); - dmabuf += sg[i].length; - } -} - -static inline void wbsd_dma_to_sg(struct wbsd_host *host, struct mmc_data *data) -{ - unsigned int len, i; - struct scatterlist *sg; - char *dmabuf = host->dma_buffer; - char *sgbuf; - - sg = data->sg; - len = data->sg_len; - - for (i = 0; i < len; i++) { - sgbuf = sg_virt(&sg[i]); - memcpy(sgbuf, dmabuf, sg[i].length); - dmabuf += sg[i].length; - } -} - -/* - * Command handling - */ - -static inline void wbsd_get_short_reply(struct wbsd_host *host, - struct mmc_command *cmd) -{ - /* - * Correct response type? - */ - if (wbsd_read_index(host, WBSD_IDX_RSPLEN) != WBSD_RSP_SHORT) { - cmd->error = -EILSEQ; - return; - } - - cmd->resp[0] = wbsd_read_index(host, WBSD_IDX_RESP12) << 24; - cmd->resp[0] |= wbsd_read_index(host, WBSD_IDX_RESP13) << 16; - cmd->resp[0] |= wbsd_read_index(host, WBSD_IDX_RESP14) << 8; - cmd->resp[0] |= wbsd_read_index(host, WBSD_IDX_RESP15) << 0; - cmd->resp[1] = wbsd_read_index(host, WBSD_IDX_RESP16) << 24; -} - -static inline void wbsd_get_long_reply(struct wbsd_host *host, - struct mmc_command *cmd) -{ - int i; - - /* - * Correct response type? - */ - if (wbsd_read_index(host, WBSD_IDX_RSPLEN) != WBSD_RSP_LONG) { - cmd->error = -EILSEQ; - return; - } - - for (i = 0; i < 4; i++) { - cmd->resp[i] = - wbsd_read_index(host, WBSD_IDX_RESP1 + i * 4) << 24; - cmd->resp[i] |= - wbsd_read_index(host, WBSD_IDX_RESP2 + i * 4) << 16; - cmd->resp[i] |= - wbsd_read_index(host, WBSD_IDX_RESP3 + i * 4) << 8; - cmd->resp[i] |= - wbsd_read_index(host, WBSD_IDX_RESP4 + i * 4) << 0; - } -} - -static void wbsd_send_command(struct wbsd_host *host, struct mmc_command *cmd) -{ - int i; - u8 status, isr; - - /* - * Clear accumulated ISR. The interrupt routine - * will fill this one with events that occur during - * transfer. - */ - host->isr = 0; - - /* - * Send the command (CRC calculated by host). - */ - outb(cmd->opcode, host->base + WBSD_CMDR); - for (i = 3; i >= 0; i--) - outb((cmd->arg >> (i * 8)) & 0xff, host->base + WBSD_CMDR); - - cmd->error = 0; - - /* - * Wait for the request to complete. - */ - do { - status = wbsd_read_index(host, WBSD_IDX_STATUS); - } while (status & WBSD_CARDTRAFFIC); - - /* - * Do we expect a reply? - */ - if (cmd->flags & MMC_RSP_PRESENT) { - /* - * Read back status. - */ - isr = host->isr; - - /* Card removed? */ - if (isr & WBSD_INT_CARD) - cmd->error = -ENOMEDIUM; - /* Timeout? */ - else if (isr & WBSD_INT_TIMEOUT) - cmd->error = -ETIMEDOUT; - /* CRC? */ - else if ((cmd->flags & MMC_RSP_CRC) && (isr & WBSD_INT_CRC)) - cmd->error = -EILSEQ; - /* All ok */ - else { - if (cmd->flags & MMC_RSP_136) - wbsd_get_long_reply(host, cmd); - else - wbsd_get_short_reply(host, cmd); - } - } -} - -/* - * Data functions - */ - -static void wbsd_empty_fifo(struct wbsd_host *host) -{ - struct mmc_data *data = host->mrq->cmd->data; - char *buffer; - int i, fsr, fifo; - - /* - * Handle excessive data. - */ - if (host->num_sg == 0) - return; - - buffer = wbsd_sg_to_buffer(host) + host->offset; - - /* - * Drain the fifo. This has a tendency to loop longer - * than the FIFO length (usually one block). - */ - while (!((fsr = inb(host->base + WBSD_FSR)) & WBSD_FIFO_EMPTY)) { - /* - * The size field in the FSR is broken so we have to - * do some guessing. - */ - if (fsr & WBSD_FIFO_FULL) - fifo = 16; - else if (fsr & WBSD_FIFO_FUTHRE) - fifo = 8; - else - fifo = 1; - - for (i = 0; i < fifo; i++) { - *buffer = inb(host->base + WBSD_DFR); - buffer++; - host->offset++; - host->remain--; - - data->bytes_xfered++; - - /* - * End of scatter list entry? - */ - if (host->remain == 0) { - /* - * Get next entry. Check if last. - */ - if (!wbsd_next_sg(host)) - return; - - buffer = wbsd_sg_to_buffer(host); - } - } - } - - /* - * This is a very dirty hack to solve a - * hardware problem. The chip doesn't trigger - * FIFO threshold interrupts properly. - */ - if ((data->blocks * data->blksz - data->bytes_xfered) < 16) - tasklet_schedule(&host->fifo_tasklet); -} - -static void wbsd_fill_fifo(struct wbsd_host *host) -{ - struct mmc_data *data = host->mrq->cmd->data; - char *buffer; - int i, fsr, fifo; - - /* - * Check that we aren't being called after the - * entire buffer has been transferred. - */ - if (host->num_sg == 0) - return; - - buffer = wbsd_sg_to_buffer(host) + host->offset; - - /* - * Fill the fifo. This has a tendency to loop longer - * than the FIFO length (usually one block). - */ - while (!((fsr = inb(host->base + WBSD_FSR)) & WBSD_FIFO_FULL)) { - /* - * The size field in the FSR is broken so we have to - * do some guessing. - */ - if (fsr & WBSD_FIFO_EMPTY) - fifo = 0; - else if (fsr & WBSD_FIFO_EMTHRE) - fifo = 8; - else - fifo = 15; - - for (i = 16; i > fifo; i--) { - outb(*buffer, host->base + WBSD_DFR); - buffer++; - host->offset++; - host->remain--; - - data->bytes_xfered++; - - /* - * End of scatter list entry? - */ - if (host->remain == 0) { - /* - * Get next entry. Check if last. - */ - if (!wbsd_next_sg(host)) - return; - - buffer = wbsd_sg_to_buffer(host); - } - } - } - - /* - * The controller stops sending interrupts for - * 'FIFO empty' under certain conditions. So we - * need to be a bit more pro-active. - */ - tasklet_schedule(&host->fifo_tasklet); -} - -static void wbsd_prepare_data(struct wbsd_host *host, struct mmc_data *data) -{ - u16 blksize; - u8 setup; - unsigned long dmaflags; - unsigned int size; - - /* - * Calculate size. - */ - size = data->blocks * data->blksz; - - /* - * Check timeout values for overflow. - * (Yes, some cards cause this value to overflow). - */ - if (data->timeout_ns > 127000000) - wbsd_write_index(host, WBSD_IDX_TAAC, 127); - else { - wbsd_write_index(host, WBSD_IDX_TAAC, - data->timeout_ns / 1000000); - } - - if (data->timeout_clks > 255) - wbsd_write_index(host, WBSD_IDX_NSAC, 255); - else - wbsd_write_index(host, WBSD_IDX_NSAC, data->timeout_clks); - - /* - * Inform the chip of how large blocks will be - * sent. It needs this to determine when to - * calculate CRC. - * - * Space for CRC must be included in the size. - * Two bytes are needed for each data line. - */ - if (host->bus_width == MMC_BUS_WIDTH_1) { - blksize = data->blksz + 2; - - wbsd_write_index(host, WBSD_IDX_PBSMSB, (blksize >> 4) & 0xF0); - wbsd_write_index(host, WBSD_IDX_PBSLSB, blksize & 0xFF); - } else if (host->bus_width == MMC_BUS_WIDTH_4) { - blksize = data->blksz + 2 * 4; - - wbsd_write_index(host, WBSD_IDX_PBSMSB, - ((blksize >> 4) & 0xF0) | WBSD_DATA_WIDTH); - wbsd_write_index(host, WBSD_IDX_PBSLSB, blksize & 0xFF); - } else { - data->error = -EINVAL; - return; - } - - /* - * Clear the FIFO. This is needed even for DMA - * transfers since the chip still uses the FIFO - * internally. - */ - setup = wbsd_read_index(host, WBSD_IDX_SETUP); - setup |= WBSD_FIFO_RESET; - wbsd_write_index(host, WBSD_IDX_SETUP, setup); - - /* - * DMA transfer? - */ - if (host->dma >= 0) { - /* - * The buffer for DMA is only 64 kB. - */ - BUG_ON(size > 0x10000); - if (size > 0x10000) { - data->error = -EINVAL; - return; - } - - /* - * Transfer data from the SG list to - * the DMA buffer. - */ - if (data->flags & MMC_DATA_WRITE) - wbsd_sg_to_dma(host, data); - - /* - * Initialise the ISA DMA controller. - */ - dmaflags = claim_dma_lock(); - disable_dma(host->dma); - clear_dma_ff(host->dma); - if (data->flags & MMC_DATA_READ) - set_dma_mode(host->dma, DMA_MODE_READ & ~0x40); - else - set_dma_mode(host->dma, DMA_MODE_WRITE & ~0x40); - set_dma_addr(host->dma, host->dma_addr); - set_dma_count(host->dma, size); - - enable_dma(host->dma); - release_dma_lock(dmaflags); - - /* - * Enable DMA on the host. - */ - wbsd_write_index(host, WBSD_IDX_DMA, WBSD_DMA_ENABLE); - } else { - /* - * This flag is used to keep printk - * output to a minimum. - */ - host->firsterr = 1; - - /* - * Initialise the SG list. - */ - wbsd_init_sg(host, data); - - /* - * Turn off DMA. - */ - wbsd_write_index(host, WBSD_IDX_DMA, 0); - - /* - * Set up FIFO threshold levels (and fill - * buffer if doing a write). - */ - if (data->flags & MMC_DATA_READ) { - wbsd_write_index(host, WBSD_IDX_FIFOEN, - WBSD_FIFOEN_FULL | 8); - } else { - wbsd_write_index(host, WBSD_IDX_FIFOEN, - WBSD_FIFOEN_EMPTY | 8); - wbsd_fill_fifo(host); - } - } - - data->error = 0; -} - -static void wbsd_finish_data(struct wbsd_host *host, struct mmc_data *data) -{ - unsigned long dmaflags; - int count; - u8 status; - - WARN_ON(host->mrq == NULL); - - /* - * Send a stop command if needed. - */ - if (data->stop) - wbsd_send_command(host, data->stop); - - /* - * Wait for the controller to leave data - * transfer state. - */ - do { - status = wbsd_read_index(host, WBSD_IDX_STATUS); - } while (status & (WBSD_BLOCK_READ | WBSD_BLOCK_WRITE)); - - /* - * DMA transfer? - */ - if (host->dma >= 0) { - /* - * Disable DMA on the host. - */ - wbsd_write_index(host, WBSD_IDX_DMA, 0); - - /* - * Turn of ISA DMA controller. - */ - dmaflags = claim_dma_lock(); - disable_dma(host->dma); - clear_dma_ff(host->dma); - count = get_dma_residue(host->dma); - release_dma_lock(dmaflags); - - data->bytes_xfered = host->mrq->data->blocks * - host->mrq->data->blksz - count; - data->bytes_xfered -= data->bytes_xfered % data->blksz; - - /* - * Any leftover data? - */ - if (count) { - pr_err("%s: Incomplete DMA transfer. " - "%d bytes left.\n", - mmc_hostname(host->mmc), count); - - if (!data->error) - data->error = -EIO; - } else { - /* - * Transfer data from DMA buffer to - * SG list. - */ - if (data->flags & MMC_DATA_READ) - wbsd_dma_to_sg(host, data); - } - - if (data->error) { - if (data->bytes_xfered) - data->bytes_xfered -= data->blksz; - } - } - - wbsd_request_end(host, host->mrq); -} - -/*****************************************************************************\ - * * - * MMC layer callbacks * - * * -\*****************************************************************************/ - -static void wbsd_request(struct mmc_host *mmc, struct mmc_request *mrq) -{ - struct wbsd_host *host = mmc_priv(mmc); - struct mmc_command *cmd; - - /* - * Disable tasklets to avoid a deadlock. - */ - spin_lock_bh(&host->lock); - - BUG_ON(host->mrq != NULL); - - cmd = mrq->cmd; - - host->mrq = mrq; - - /* - * Check that there is actually a card in the slot. - */ - if (!(host->flags & WBSD_FCARD_PRESENT)) { - cmd->error = -ENOMEDIUM; - goto done; - } - - if (cmd->data) { - /* - * The hardware is so delightfully stupid that it has a list - * of "data" commands. If a command isn't on this list, it'll - * just go back to the idle state and won't send any data - * interrupts. - */ - switch (cmd->opcode) { - case 11: - case 17: - case 18: - case 20: - case 24: - case 25: - case 26: - case 27: - case 30: - case 42: - case 56: - break; - - /* ACMDs. We don't keep track of state, so we just treat them - * like any other command. */ - case 51: - break; - - default: -#ifdef CONFIG_MMC_DEBUG - pr_warning("%s: Data command %d is not " - "supported by this controller.\n", - mmc_hostname(host->mmc), cmd->opcode); -#endif - cmd->error = -EINVAL; - - goto done; - }; - } - - /* - * Does the request include data? - */ - if (cmd->data) { - wbsd_prepare_data(host, cmd->data); - - if (cmd->data->error) - goto done; - } - - wbsd_send_command(host, cmd); - - /* - * If this is a data transfer the request - * will be finished after the data has - * transferred. - */ - if (cmd->data && !cmd->error) { - /* - * Dirty fix for hardware bug. - */ - if (host->dma == -1) - tasklet_schedule(&host->fifo_tasklet); - - spin_unlock_bh(&host->lock); - - return; - } - -done: - wbsd_request_end(host, mrq); - - spin_unlock_bh(&host->lock); -} - -static void wbsd_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) -{ - struct wbsd_host *host = mmc_priv(mmc); - u8 clk, setup, pwr; - - spin_lock_bh(&host->lock); - - /* - * Reset the chip on each power off. - * Should clear out any weird states. - */ - if (ios->power_mode == MMC_POWER_OFF) - wbsd_init_device(host); - - if (ios->clock >= 24000000) - clk = WBSD_CLK_24M; - else if (ios->clock >= 16000000) - clk = WBSD_CLK_16M; - else if (ios->clock >= 12000000) - clk = WBSD_CLK_12M; - else - clk = WBSD_CLK_375K; - - /* - * Only write to the clock register when - * there is an actual change. - */ - if (clk != host->clk) { - wbsd_write_index(host, WBSD_IDX_CLK, clk); - host->clk = clk; - } - - /* - * Power up card. - */ - if (ios->power_mode != MMC_POWER_OFF) { - pwr = inb(host->base + WBSD_CSR); - pwr &= ~WBSD_POWER_N; - outb(pwr, host->base + WBSD_CSR); - } - - /* - * MMC cards need to have pin 1 high during init. - * It wreaks havoc with the card detection though so - * that needs to be disabled. - */ - setup = wbsd_read_index(host, WBSD_IDX_SETUP); - if (ios->chip_select == MMC_CS_HIGH) { - BUG_ON(ios->bus_width != MMC_BUS_WIDTH_1); - setup |= WBSD_DAT3_H; - host->flags |= WBSD_FIGNORE_DETECT; - } else { - if (setup & WBSD_DAT3_H) { - setup &= ~WBSD_DAT3_H; - - /* - * We cannot resume card detection immediately - * because of capacitance and delays in the chip. - */ - mod_timer(&host->ignore_timer, jiffies + HZ / 100); - } - } - wbsd_write_index(host, WBSD_IDX_SETUP, setup); - - /* - * Store bus width for later. Will be used when - * setting up the data transfer. - */ - host->bus_width = ios->bus_width; - - spin_unlock_bh(&host->lock); -} - -static int wbsd_get_ro(struct mmc_host *mmc) -{ - struct wbsd_host *host = mmc_priv(mmc); - u8 csr; - - spin_lock_bh(&host->lock); - - csr = inb(host->base + WBSD_CSR); - csr |= WBSD_MSLED; - outb(csr, host->base + WBSD_CSR); - - mdelay(1); - - csr = inb(host->base + WBSD_CSR); - csr &= ~WBSD_MSLED; - outb(csr, host->base + WBSD_CSR); - - spin_unlock_bh(&host->lock); - - return !!(csr & WBSD_WRPT); -} - -static const struct mmc_host_ops wbsd_ops = { - .request = wbsd_request, - .set_ios = wbsd_set_ios, - .get_ro = wbsd_get_ro, -}; - -/*****************************************************************************\ - * * - * Interrupt handling * - * * -\*****************************************************************************/ - -/* - * Helper function to reset detection ignore - */ - -static void wbsd_reset_ignore(unsigned long data) -{ - struct wbsd_host *host = (struct wbsd_host *)data; - - BUG_ON(host == NULL); - - DBG("Resetting card detection ignore\n"); - - spin_lock_bh(&host->lock); - - host->flags &= ~WBSD_FIGNORE_DETECT; - - /* - * Card status might have changed during the - * blackout. - */ - tasklet_schedule(&host->card_tasklet); - - spin_unlock_bh(&host->lock); -} - -/* - * Tasklets - */ - -static inline struct mmc_data *wbsd_get_data(struct wbsd_host *host) -{ - WARN_ON(!host->mrq); - if (!host->mrq) - return NULL; - - WARN_ON(!host->mrq->cmd); - if (!host->mrq->cmd) - return NULL; - - WARN_ON(!host->mrq->cmd->data); - if (!host->mrq->cmd->data) - return NULL; - - return host->mrq->cmd->data; -} - -static void wbsd_tasklet_card(unsigned long param) -{ - struct wbsd_host *host = (struct wbsd_host *)param; - u8 csr; - int delay = -1; - - spin_lock(&host->lock); - - if (host->flags & WBSD_FIGNORE_DETECT) { - spin_unlock(&host->lock); - return; - } - - csr = inb(host->base + WBSD_CSR); - WARN_ON(csr == 0xff); - - if (csr & WBSD_CARDPRESENT) { - if (!(host->flags & WBSD_FCARD_PRESENT)) { - DBG("Card inserted\n"); - host->flags |= WBSD_FCARD_PRESENT; - - delay = 500; - } - } else if (host->flags & WBSD_FCARD_PRESENT) { - DBG("Card removed\n"); - host->flags &= ~WBSD_FCARD_PRESENT; - - if (host->mrq) { - pr_err("%s: Card removed during transfer!\n", - mmc_hostname(host->mmc)); - wbsd_reset(host); - - host->mrq->cmd->error = -ENOMEDIUM; - tasklet_schedule(&host->finish_tasklet); - } - - delay = 0; - } - - /* - * Unlock first since we might get a call back. - */ - - spin_unlock(&host->lock); - - if (delay != -1) - mmc_detect_change(host->mmc, msecs_to_jiffies(delay)); -} - -static void wbsd_tasklet_fifo(unsigned long param) -{ - struct wbsd_host *host = (struct wbsd_host *)param; - struct mmc_data *data; - - spin_lock(&host->lock); - - if (!host->mrq) - goto end; - - data = wbsd_get_data(host); - if (!data) - goto end; - - if (data->flags & MMC_DATA_WRITE) - wbsd_fill_fifo(host); - else - wbsd_empty_fifo(host); - - /* - * Done? - */ - if (host->num_sg == 0) { - wbsd_write_index(host, WBSD_IDX_FIFOEN, 0); - tasklet_schedule(&host->finish_tasklet); - } - -end: - spin_unlock(&host->lock); -} - -static void wbsd_tasklet_crc(unsigned long param) -{ - struct wbsd_host *host = (struct wbsd_host *)param; - struct mmc_data *data; - - spin_lock(&host->lock); - - if (!host->mrq) - goto end; - - data = wbsd_get_data(host); - if (!data) - goto end; - - DBGF("CRC error\n"); - - data->error = -EILSEQ; - - tasklet_schedule(&host->finish_tasklet); - -end: - spin_unlock(&host->lock); -} - -static void wbsd_tasklet_timeout(unsigned long param) -{ - struct wbsd_host *host = (struct wbsd_host *)param; - struct mmc_data *data; - - spin_lock(&host->lock); - - if (!host->mrq) - goto end; - - data = wbsd_get_data(host); - if (!data) - goto end; - - DBGF("Timeout\n"); - - data->error = -ETIMEDOUT; - - tasklet_schedule(&host->finish_tasklet); - -end: - spin_unlock(&host->lock); -} - -static void wbsd_tasklet_finish(unsigned long param) -{ - struct wbsd_host *host = (struct wbsd_host *)param; - struct mmc_data *data; - - spin_lock(&host->lock); - - WARN_ON(!host->mrq); - if (!host->mrq) - goto end; - - data = wbsd_get_data(host); - if (!data) - goto end; - - wbsd_finish_data(host, data); - -end: - spin_unlock(&host->lock); -} - -/* - * Interrupt handling - */ - -static irqreturn_t wbsd_irq(int irq, void *dev_id) -{ - struct wbsd_host *host = dev_id; - int isr; - - isr = inb(host->base + WBSD_ISR); - - /* - * Was it actually our hardware that caused the interrupt? - */ - if (isr == 0xff || isr == 0x00) - return IRQ_NONE; - - host->isr |= isr; - - /* - * Schedule tasklets as needed. - */ - if (isr & WBSD_INT_CARD) - tasklet_schedule(&host->card_tasklet); - if (isr & WBSD_INT_FIFO_THRE) - tasklet_schedule(&host->fifo_tasklet); - if (isr & WBSD_INT_CRC) - tasklet_hi_schedule(&host->crc_tasklet); - if (isr & WBSD_INT_TIMEOUT) - tasklet_hi_schedule(&host->timeout_tasklet); - if (isr & WBSD_INT_TC) - tasklet_schedule(&host->finish_tasklet); - - return IRQ_HANDLED; -} - -/*****************************************************************************\ - * * - * Device initialisation and shutdown * - * * -\*****************************************************************************/ - -/* - * Allocate/free MMC structure. - */ - -static int __devinit wbsd_alloc_mmc(struct device *dev) -{ - struct mmc_host *mmc; - struct wbsd_host *host; - - /* - * Allocate MMC structure. - */ - mmc = mmc_alloc_host(sizeof(struct wbsd_host), dev); - if (!mmc) - return -ENOMEM; - - host = mmc_priv(mmc); - host->mmc = mmc; - - host->dma = -1; - - /* - * Set host parameters. - */ - mmc->ops = &wbsd_ops; - mmc->f_min = 375000; - mmc->f_max = 24000000; - mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; - mmc->caps = MMC_CAP_4_BIT_DATA; - - spin_lock_init(&host->lock); - - /* - * Set up timers - */ - init_timer(&host->ignore_timer); - host->ignore_timer.data = (unsigned long)host; - host->ignore_timer.function = wbsd_reset_ignore; - - /* - * Maximum number of segments. Worst case is one sector per segment - * so this will be 64kB/512. - */ - mmc->max_segs = 128; - - /* - * Maximum request size. Also limited by 64KiB buffer. - */ - mmc->max_req_size = 65536; - - /* - * Maximum segment size. Could be one segment with the maximum number - * of bytes. - */ - mmc->max_seg_size = mmc->max_req_size; - - /* - * Maximum block size. We have 12 bits (= 4095) but have to subtract - * space for CRC. So the maximum is 4095 - 4*2 = 4087. - */ - mmc->max_blk_size = 4087; - - /* - * Maximum block count. There is no real limit so the maximum - * request size will be the only restriction. - */ - mmc->max_blk_count = mmc->max_req_size; - - dev_set_drvdata(dev, mmc); - - return 0; -} - -static void wbsd_free_mmc(struct device *dev) -{ - struct mmc_host *mmc; - struct wbsd_host *host; - - mmc = dev_get_drvdata(dev); - if (!mmc) - return; - - host = mmc_priv(mmc); - BUG_ON(host == NULL); - - del_timer_sync(&host->ignore_timer); - - mmc_free_host(mmc); - - dev_set_drvdata(dev, NULL); -} - -/* - * Scan for known chip id:s - */ - -static int __devinit wbsd_scan(struct wbsd_host *host) -{ - int i, j, k; - int id; - - /* - * Iterate through all ports, all codes to - * find hardware that is in our known list. - */ - for (i = 0; i < ARRAY_SIZE(config_ports); i++) { - if (!request_region(config_ports[i], 2, DRIVER_NAME)) - continue; - - for (j = 0; j < ARRAY_SIZE(unlock_codes); j++) { - id = 0xFFFF; - - host->config = config_ports[i]; - host->unlock_code = unlock_codes[j]; - - wbsd_unlock_config(host); - - outb(WBSD_CONF_ID_HI, config_ports[i]); - id = inb(config_ports[i] + 1) << 8; - - outb(WBSD_CONF_ID_LO, config_ports[i]); - id |= inb(config_ports[i] + 1); - - wbsd_lock_config(host); - - for (k = 0; k < ARRAY_SIZE(valid_ids); k++) { - if (id == valid_ids[k]) { - host->chip_id = id; - - return 0; - } - } - - if (id != 0xFFFF) { - DBG("Unknown hardware (id %x) found at %x\n", - id, config_ports[i]); - } - } - - release_region(config_ports[i], 2); - } - - host->config = 0; - host->unlock_code = 0; - - return -ENODEV; -} - -/* - * Allocate/free io port ranges - */ - -static int __devinit wbsd_request_region(struct wbsd_host *host, int base) -{ - if (base & 0x7) - return -EINVAL; - - if (!request_region(base, 8, DRIVER_NAME)) - return -EIO; - - host->base = base; - - return 0; -} - -static void wbsd_release_regions(struct wbsd_host *host) -{ - if (host->base) - release_region(host->base, 8); - - host->base = 0; - - if (host->config) - release_region(host->config, 2); - - host->config = 0; -} - -/* - * Allocate/free DMA port and buffer - */ - -static void __devinit wbsd_request_dma(struct wbsd_host *host, int dma) -{ - if (dma < 0) - return; - - if (request_dma(dma, DRIVER_NAME)) - goto err; - - /* - * We need to allocate a special buffer in - * order for ISA to be able to DMA to it. - */ - host->dma_buffer = kmalloc(WBSD_DMA_SIZE, - GFP_NOIO | GFP_DMA | __GFP_REPEAT | __GFP_NOWARN); - if (!host->dma_buffer) - goto free; - - /* - * Translate the address to a physical address. - */ - host->dma_addr = dma_map_single(mmc_dev(host->mmc), host->dma_buffer, - WBSD_DMA_SIZE, DMA_BIDIRECTIONAL); - - /* - * ISA DMA must be aligned on a 64k basis. - */ - if ((host->dma_addr & 0xffff) != 0) - goto kfree; - /* - * ISA cannot access memory above 16 MB. - */ - else if (host->dma_addr >= 0x1000000) - goto kfree; - - host->dma = dma; - - return; - -kfree: - /* - * If we've gotten here then there is some kind of alignment bug - */ - BUG_ON(1); - - dma_unmap_single(mmc_dev(host->mmc), host->dma_addr, - WBSD_DMA_SIZE, DMA_BIDIRECTIONAL); - host->dma_addr = 0; - - kfree(host->dma_buffer); - host->dma_buffer = NULL; - -free: - free_dma(dma); - -err: - pr_warning(DRIVER_NAME ": Unable to allocate DMA %d. " - "Falling back on FIFO.\n", dma); -} - -static void wbsd_release_dma(struct wbsd_host *host) -{ - if (host->dma_addr) { - dma_unmap_single(mmc_dev(host->mmc), host->dma_addr, - WBSD_DMA_SIZE, DMA_BIDIRECTIONAL); - } - kfree(host->dma_buffer); - if (host->dma >= 0) - free_dma(host->dma); - - host->dma = -1; - host->dma_buffer = NULL; - host->dma_addr = 0; -} - -/* - * Allocate/free IRQ. - */ - -static int __devinit wbsd_request_irq(struct wbsd_host *host, int irq) -{ - int ret; - - /* - * Set up tasklets. Must be done before requesting interrupt. - */ - tasklet_init(&host->card_tasklet, wbsd_tasklet_card, - (unsigned long)host); - tasklet_init(&host->fifo_tasklet, wbsd_tasklet_fifo, - (unsigned long)host); - tasklet_init(&host->crc_tasklet, wbsd_tasklet_crc, - (unsigned long)host); - tasklet_init(&host->timeout_tasklet, wbsd_tasklet_timeout, - (unsigned long)host); - tasklet_init(&host->finish_tasklet, wbsd_tasklet_finish, - (unsigned long)host); - - /* - * Allocate interrupt. - */ - ret = request_irq(irq, wbsd_irq, IRQF_SHARED, DRIVER_NAME, host); - if (ret) - return ret; - - host->irq = irq; - - return 0; -} - -static void wbsd_release_irq(struct wbsd_host *host) -{ - if (!host->irq) - return; - - free_irq(host->irq, host); - - host->irq = 0; - - tasklet_kill(&host->card_tasklet); - tasklet_kill(&host->fifo_tasklet); - tasklet_kill(&host->crc_tasklet); - tasklet_kill(&host->timeout_tasklet); - tasklet_kill(&host->finish_tasklet); -} - -/* - * Allocate all resources for the host. - */ - -static int __devinit wbsd_request_resources(struct wbsd_host *host, - int base, int irq, int dma) -{ - int ret; - - /* - * Allocate I/O ports. - */ - ret = wbsd_request_region(host, base); - if (ret) - return ret; - - /* - * Allocate interrupt. - */ - ret = wbsd_request_irq(host, irq); - if (ret) - return ret; - - /* - * Allocate DMA. - */ - wbsd_request_dma(host, dma); - - return 0; -} - -/* - * Release all resources for the host. - */ - -static void wbsd_release_resources(struct wbsd_host *host) -{ - wbsd_release_dma(host); - wbsd_release_irq(host); - wbsd_release_regions(host); -} - -/* - * Configure the resources the chip should use. - */ - -static void wbsd_chip_config(struct wbsd_host *host) -{ - wbsd_unlock_config(host); - - /* - * Reset the chip. - */ - wbsd_write_config(host, WBSD_CONF_SWRST, 1); - wbsd_write_config(host, WBSD_CONF_SWRST, 0); - - /* - * Select SD/MMC function. - */ - wbsd_write_config(host, WBSD_CONF_DEVICE, DEVICE_SD); - - /* - * Set up card detection. - */ - wbsd_write_config(host, WBSD_CONF_PINS, WBSD_PINS_DETECT_GP11); - - /* - * Configure chip - */ - wbsd_write_config(host, WBSD_CONF_PORT_HI, host->base >> 8); - wbsd_write_config(host, WBSD_CONF_PORT_LO, host->base & 0xff); - - wbsd_write_config(host, WBSD_CONF_IRQ, host->irq); - - if (host->dma >= 0) - wbsd_write_config(host, WBSD_CONF_DRQ, host->dma); - - /* - * Enable and power up chip. - */ - wbsd_write_config(host, WBSD_CONF_ENABLE, 1); - wbsd_write_config(host, WBSD_CONF_POWER, 0x20); - - wbsd_lock_config(host); -} - -/* - * Check that configured resources are correct. - */ - -static int wbsd_chip_validate(struct wbsd_host *host) -{ - int base, irq, dma; - - wbsd_unlock_config(host); - - /* - * Select SD/MMC function. - */ - wbsd_write_config(host, WBSD_CONF_DEVICE, DEVICE_SD); - - /* - * Read configuration. - */ - base = wbsd_read_config(host, WBSD_CONF_PORT_HI) << 8; - base |= wbsd_read_config(host, WBSD_CONF_PORT_LO); - - irq = wbsd_read_config(host, WBSD_CONF_IRQ); - - dma = wbsd_read_config(host, WBSD_CONF_DRQ); - - wbsd_lock_config(host); - - /* - * Validate against given configuration. - */ - if (base != host->base) - return 0; - if (irq != host->irq) - return 0; - if ((dma != host->dma) && (host->dma != -1)) - return 0; - - return 1; -} - -/* - * Powers down the SD function - */ - -static void wbsd_chip_poweroff(struct wbsd_host *host) -{ - wbsd_unlock_config(host); - - wbsd_write_config(host, WBSD_CONF_DEVICE, DEVICE_SD); - wbsd_write_config(host, WBSD_CONF_ENABLE, 0); - - wbsd_lock_config(host); -} - -/*****************************************************************************\ - * * - * Devices setup and shutdown * - * * -\*****************************************************************************/ - -static int __devinit wbsd_init(struct device *dev, int base, int irq, int dma, - int pnp) -{ - struct wbsd_host *host = NULL; - struct mmc_host *mmc = NULL; - int ret; - - ret = wbsd_alloc_mmc(dev); - if (ret) - return ret; - - mmc = dev_get_drvdata(dev); - host = mmc_priv(mmc); - - /* - * Scan for hardware. - */ - ret = wbsd_scan(host); - if (ret) { - if (pnp && (ret == -ENODEV)) { - pr_warning(DRIVER_NAME - ": Unable to confirm device presence. You may " - "experience lock-ups.\n"); - } else { - wbsd_free_mmc(dev); - return ret; - } - } - - /* - * Request resources. - */ - ret = wbsd_request_resources(host, base, irq, dma); - if (ret) { - wbsd_release_resources(host); - wbsd_free_mmc(dev); - return ret; - } - - /* - * See if chip needs to be configured. - */ - if (pnp) { - if ((host->config != 0) && !wbsd_chip_validate(host)) { - pr_warning(DRIVER_NAME - ": PnP active but chip not configured! " - "You probably have a buggy BIOS. " - "Configuring chip manually.\n"); - wbsd_chip_config(host); - } - } else - wbsd_chip_config(host); - - /* - * Power Management stuff. No idea how this works. - * Not tested. - */ -#ifdef CONFIG_PM - if (host->config) { - wbsd_unlock_config(host); - wbsd_write_config(host, WBSD_CONF_PME, 0xA0); - wbsd_lock_config(host); - } -#endif - /* - * Allow device to initialise itself properly. - */ - mdelay(5); - - /* - * Reset the chip into a known state. - */ - wbsd_init_device(host); - - mmc_add_host(mmc); - - pr_info("%s: W83L51xD", mmc_hostname(mmc)); - if (host->chip_id != 0) - printk(" id %x", (int)host->chip_id); - printk(" at 0x%x irq %d", (int)host->base, (int)host->irq); - if (host->dma >= 0) - printk(" dma %d", (int)host->dma); - else - printk(" FIFO"); - if (pnp) - printk(" PnP"); - printk("\n"); - - return 0; -} - -static void __devexit wbsd_shutdown(struct device *dev, int pnp) -{ - struct mmc_host *mmc = dev_get_drvdata(dev); - struct wbsd_host *host; - - if (!mmc) - return; - - host = mmc_priv(mmc); - - mmc_remove_host(mmc); - - /* - * Power down the SD/MMC function. - */ - if (!pnp) - wbsd_chip_poweroff(host); - - wbsd_release_resources(host); - - wbsd_free_mmc(dev); -} - -/* - * Non-PnP - */ - -static int __devinit wbsd_probe(struct platform_device *dev) -{ - /* Use the module parameters for resources */ - return wbsd_init(&dev->dev, param_io, param_irq, param_dma, 0); -} - -static int __devexit wbsd_remove(struct platform_device *dev) -{ - wbsd_shutdown(&dev->dev, 0); - - return 0; -} - -/* - * PnP - */ - -#ifdef CONFIG_PNP - -static int __devinit -wbsd_pnp_probe(struct pnp_dev *pnpdev, const struct pnp_device_id *dev_id) -{ - int io, irq, dma; - - /* - * Get resources from PnP layer. - */ - io = pnp_port_start(pnpdev, 0); - irq = pnp_irq(pnpdev, 0); - if (pnp_dma_valid(pnpdev, 0)) - dma = pnp_dma(pnpdev, 0); - else - dma = -1; - - DBGF("PnP resources: port %3x irq %d dma %d\n", io, irq, dma); - - return wbsd_init(&pnpdev->dev, io, irq, dma, 1); -} - -static void __devexit wbsd_pnp_remove(struct pnp_dev *dev) -{ - wbsd_shutdown(&dev->dev, 1); -} - -#endif /* CONFIG_PNP */ - -/* - * Power management - */ - -#ifdef CONFIG_PM - -static int wbsd_suspend(struct wbsd_host *host, pm_message_t state) -{ - BUG_ON(host == NULL); - - return mmc_suspend_host(host->mmc); -} - -static int wbsd_resume(struct wbsd_host *host) -{ - BUG_ON(host == NULL); - - wbsd_init_device(host); - - return mmc_resume_host(host->mmc); -} - -static int wbsd_platform_suspend(struct platform_device *dev, - pm_message_t state) -{ - struct mmc_host *mmc = platform_get_drvdata(dev); - struct wbsd_host *host; - int ret; - - if (mmc == NULL) - return 0; - - DBGF("Suspending...\n"); - - host = mmc_priv(mmc); - - ret = wbsd_suspend(host, state); - if (ret) - return ret; - - wbsd_chip_poweroff(host); - - return 0; -} - -static int wbsd_platform_resume(struct platform_device *dev) -{ - struct mmc_host *mmc = platform_get_drvdata(dev); - struct wbsd_host *host; - - if (mmc == NULL) - return 0; - - DBGF("Resuming...\n"); - - host = mmc_priv(mmc); - - wbsd_chip_config(host); - - /* - * Allow device to initialise itself properly. - */ - mdelay(5); - - return wbsd_resume(host); -} - -#ifdef CONFIG_PNP - -static int wbsd_pnp_suspend(struct pnp_dev *pnp_dev, pm_message_t state) -{ - struct mmc_host *mmc = dev_get_drvdata(&pnp_dev->dev); - struct wbsd_host *host; - - if (mmc == NULL) - return 0; - - DBGF("Suspending...\n"); - - host = mmc_priv(mmc); - - return wbsd_suspend(host, state); -} - -static int wbsd_pnp_resume(struct pnp_dev *pnp_dev) -{ - struct mmc_host *mmc = dev_get_drvdata(&pnp_dev->dev); - struct wbsd_host *host; - - if (mmc == NULL) - return 0; - - DBGF("Resuming...\n"); - - host = mmc_priv(mmc); - - /* - * See if chip needs to be configured. - */ - if (host->config != 0) { - if (!wbsd_chip_validate(host)) { - pr_warning(DRIVER_NAME - ": PnP active but chip not configured! " - "You probably have a buggy BIOS. " - "Configuring chip manually.\n"); - wbsd_chip_config(host); - } - } - - /* - * Allow device to initialise itself properly. - */ - mdelay(5); - - return wbsd_resume(host); -} - -#endif /* CONFIG_PNP */ - -#else /* CONFIG_PM */ - -#define wbsd_platform_suspend NULL -#define wbsd_platform_resume NULL - -#define wbsd_pnp_suspend NULL -#define wbsd_pnp_resume NULL - -#endif /* CONFIG_PM */ - -static struct platform_device *wbsd_device; - -static struct platform_driver wbsd_driver = { - .probe = wbsd_probe, - .remove = __devexit_p(wbsd_remove), - - .suspend = wbsd_platform_suspend, - .resume = wbsd_platform_resume, - .driver = { - .name = DRIVER_NAME, - .owner = THIS_MODULE, - }, -}; - -#ifdef CONFIG_PNP - -static struct pnp_driver wbsd_pnp_driver = { - .name = DRIVER_NAME, - .id_table = pnp_dev_table, - .probe = wbsd_pnp_probe, - .remove = __devexit_p(wbsd_pnp_remove), - - .suspend = wbsd_pnp_suspend, - .resume = wbsd_pnp_resume, -}; - -#endif /* CONFIG_PNP */ - -/* - * Module loading/unloading - */ - -static int __init wbsd_drv_init(void) -{ - int result; - - pr_info(DRIVER_NAME - ": Winbond W83L51xD SD/MMC card interface driver\n"); - pr_info(DRIVER_NAME ": Copyright(c) Pierre Ossman\n"); - -#ifdef CONFIG_PNP - - if (!param_nopnp) { - result = pnp_register_driver(&wbsd_pnp_driver); - if (result < 0) - return result; - } -#endif /* CONFIG_PNP */ - - if (param_nopnp) { - result = platform_driver_register(&wbsd_driver); - if (result < 0) - return result; - - wbsd_device = platform_device_alloc(DRIVER_NAME, -1); - if (!wbsd_device) { - platform_driver_unregister(&wbsd_driver); - return -ENOMEM; - } - - result = platform_device_add(wbsd_device); - if (result) { - platform_device_put(wbsd_device); - platform_driver_unregister(&wbsd_driver); - return result; - } - } - - return 0; -} - -static void __exit wbsd_drv_exit(void) -{ -#ifdef CONFIG_PNP - - if (!param_nopnp) - pnp_unregister_driver(&wbsd_pnp_driver); - -#endif /* CONFIG_PNP */ - - if (param_nopnp) { - platform_device_unregister(wbsd_device); - - platform_driver_unregister(&wbsd_driver); - } - - DBG("unloaded\n"); -} - -module_init(wbsd_drv_init); -module_exit(wbsd_drv_exit); -#ifdef CONFIG_PNP -module_param_named(nopnp, param_nopnp, uint, 0444); -#endif -module_param_named(io, param_io, uint, 0444); -module_param_named(irq, param_irq, uint, 0444); -module_param_named(dma, param_dma, int, 0444); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Pierre Ossman <pierre@ossman.eu>"); -MODULE_DESCRIPTION("Winbond W83L51xD SD/MMC card interface driver"); - -#ifdef CONFIG_PNP -MODULE_PARM_DESC(nopnp, "Scan for device instead of relying on PNP. (default 0)"); -#endif -MODULE_PARM_DESC(io, "I/O base to allocate. Must be 8 byte aligned. (default 0x248)"); -MODULE_PARM_DESC(irq, "IRQ to allocate. (default 6)"); -MODULE_PARM_DESC(dma, "DMA channel to allocate. -1 for no DMA. (default 2)"); diff --git a/ANDROID_3.4.5/drivers/mmc/host/wbsd.h b/ANDROID_3.4.5/drivers/mmc/host/wbsd.h deleted file mode 100644 index 0877866f..00000000 --- a/ANDROID_3.4.5/drivers/mmc/host/wbsd.h +++ /dev/null @@ -1,185 +0,0 @@ -/* - * linux/drivers/mmc/host/wbsd.h - Winbond W83L51xD SD/MMC driver - * - * Copyright (C) 2004-2007 Pierre Ossman, All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at - * your option) any later version. - */ - -#define LOCK_CODE 0xAA - -#define WBSD_CONF_SWRST 0x02 -#define WBSD_CONF_DEVICE 0x07 -#define WBSD_CONF_ID_HI 0x20 -#define WBSD_CONF_ID_LO 0x21 -#define WBSD_CONF_POWER 0x22 -#define WBSD_CONF_PME 0x23 -#define WBSD_CONF_PMES 0x24 - -#define WBSD_CONF_ENABLE 0x30 -#define WBSD_CONF_PORT_HI 0x60 -#define WBSD_CONF_PORT_LO 0x61 -#define WBSD_CONF_IRQ 0x70 -#define WBSD_CONF_DRQ 0x74 - -#define WBSD_CONF_PINS 0xF0 - -#define DEVICE_SD 0x03 - -#define WBSD_PINS_DAT3_HI 0x20 -#define WBSD_PINS_DAT3_OUT 0x10 -#define WBSD_PINS_GP11_HI 0x04 -#define WBSD_PINS_DETECT_GP11 0x02 -#define WBSD_PINS_DETECT_DAT3 0x01 - -#define WBSD_CMDR 0x00 -#define WBSD_DFR 0x01 -#define WBSD_EIR 0x02 -#define WBSD_ISR 0x03 -#define WBSD_FSR 0x04 -#define WBSD_IDXR 0x05 -#define WBSD_DATAR 0x06 -#define WBSD_CSR 0x07 - -#define WBSD_EINT_CARD 0x40 -#define WBSD_EINT_FIFO_THRE 0x20 -#define WBSD_EINT_CRC 0x10 -#define WBSD_EINT_TIMEOUT 0x08 -#define WBSD_EINT_PROGEND 0x04 -#define WBSD_EINT_BUSYEND 0x02 -#define WBSD_EINT_TC 0x01 - -#define WBSD_INT_PENDING 0x80 -#define WBSD_INT_CARD 0x40 -#define WBSD_INT_FIFO_THRE 0x20 -#define WBSD_INT_CRC 0x10 -#define WBSD_INT_TIMEOUT 0x08 -#define WBSD_INT_PROGEND 0x04 -#define WBSD_INT_BUSYEND 0x02 -#define WBSD_INT_TC 0x01 - -#define WBSD_FIFO_EMPTY 0x80 -#define WBSD_FIFO_FULL 0x40 -#define WBSD_FIFO_EMTHRE 0x20 -#define WBSD_FIFO_FUTHRE 0x10 -#define WBSD_FIFO_SZMASK 0x0F - -#define WBSD_MSLED 0x20 -#define WBSD_POWER_N 0x10 -#define WBSD_WRPT 0x04 -#define WBSD_CARDPRESENT 0x01 - -#define WBSD_IDX_CLK 0x01 -#define WBSD_IDX_PBSMSB 0x02 -#define WBSD_IDX_TAAC 0x03 -#define WBSD_IDX_NSAC 0x04 -#define WBSD_IDX_PBSLSB 0x05 -#define WBSD_IDX_SETUP 0x06 -#define WBSD_IDX_DMA 0x07 -#define WBSD_IDX_FIFOEN 0x08 -#define WBSD_IDX_STATUS 0x10 -#define WBSD_IDX_RSPLEN 0x1E -#define WBSD_IDX_RESP0 0x1F -#define WBSD_IDX_RESP1 0x20 -#define WBSD_IDX_RESP2 0x21 -#define WBSD_IDX_RESP3 0x22 -#define WBSD_IDX_RESP4 0x23 -#define WBSD_IDX_RESP5 0x24 -#define WBSD_IDX_RESP6 0x25 -#define WBSD_IDX_RESP7 0x26 -#define WBSD_IDX_RESP8 0x27 -#define WBSD_IDX_RESP9 0x28 -#define WBSD_IDX_RESP10 0x29 -#define WBSD_IDX_RESP11 0x2A -#define WBSD_IDX_RESP12 0x2B -#define WBSD_IDX_RESP13 0x2C -#define WBSD_IDX_RESP14 0x2D -#define WBSD_IDX_RESP15 0x2E -#define WBSD_IDX_RESP16 0x2F -#define WBSD_IDX_CRCSTATUS 0x30 -#define WBSD_IDX_ISR 0x3F - -#define WBSD_CLK_375K 0x00 -#define WBSD_CLK_12M 0x01 -#define WBSD_CLK_16M 0x02 -#define WBSD_CLK_24M 0x03 - -#define WBSD_DATA_WIDTH 0x01 - -#define WBSD_DAT3_H 0x08 -#define WBSD_FIFO_RESET 0x04 -#define WBSD_SOFT_RESET 0x02 -#define WBSD_INC_INDEX 0x01 - -#define WBSD_DMA_SINGLE 0x02 -#define WBSD_DMA_ENABLE 0x01 - -#define WBSD_FIFOEN_EMPTY 0x20 -#define WBSD_FIFOEN_FULL 0x10 -#define WBSD_FIFO_THREMASK 0x0F - -#define WBSD_BLOCK_READ 0x80 -#define WBSD_BLOCK_WRITE 0x40 -#define WBSD_BUSY 0x20 -#define WBSD_CARDTRAFFIC 0x04 -#define WBSD_SENDCMD 0x02 -#define WBSD_RECVRES 0x01 - -#define WBSD_RSP_SHORT 0x00 -#define WBSD_RSP_LONG 0x01 - -#define WBSD_CRC_MASK 0x1F -#define WBSD_CRC_OK 0x05 /* S010E (00101) */ -#define WBSD_CRC_FAIL 0x0B /* S101E (01011) */ - -#define WBSD_DMA_SIZE 65536 - -struct wbsd_host -{ - struct mmc_host* mmc; /* MMC structure */ - - spinlock_t lock; /* Mutex */ - - int flags; /* Driver states */ - -#define WBSD_FCARD_PRESENT (1<<0) /* Card is present */ -#define WBSD_FIGNORE_DETECT (1<<1) /* Ignore card detection */ - - struct mmc_request* mrq; /* Current request */ - - u8 isr; /* Accumulated ISR */ - - struct scatterlist* cur_sg; /* Current SG entry */ - unsigned int num_sg; /* Number of entries left */ - - unsigned int offset; /* Offset into current entry */ - unsigned int remain; /* Data left in curren entry */ - - char* dma_buffer; /* ISA DMA buffer */ - dma_addr_t dma_addr; /* Physical address for same */ - - int firsterr; /* See fifo functions */ - - u8 clk; /* Current clock speed */ - unsigned char bus_width; /* Current bus width */ - - int config; /* Config port */ - u8 unlock_code; /* Code to unlock config */ - - int chip_id; /* ID of controller */ - - int base; /* I/O port base */ - int irq; /* Interrupt */ - int dma; /* DMA channel */ - - struct tasklet_struct card_tasklet; /* Tasklet structures */ - struct tasklet_struct fifo_tasklet; - struct tasklet_struct crc_tasklet; - struct tasklet_struct timeout_tasklet; - struct tasklet_struct finish_tasklet; - - struct timer_list ignore_timer; /* Ignore detection timer */ -}; |