mirror of
https://github.com/torvalds/linux.git
synced 2024-11-11 06:31:49 +00:00
Merge branch 'amba' of git://git.linaro.org/people/rmk/linux-arm
Pull #2 ARM updates from Russell King: "Further ARM AMBA primecell updates which aren't included directly in the previous commit. I wanted to keep these separate as they're touching stuff outside arch/arm/." * 'amba' of git://git.linaro.org/people/rmk/linux-arm: ARM: 7362/1: AMBA: Add module_amba_driver() helper macro for amba_driver ARM: 7335/1: mach-u300: do away with MMC config files ARM: 7280/1: mmc: mmci: Cache MMCICLOCK and MMCIPOWER register ARM: 7309/1: realview: fix unconnected interrupts on EB11MP ARM: 7230/1: mmc: mmci: Fix PIO read for small SDIO packets ARM: 7227/1: mmc: mmci: Prepare for SDIO before setting up DMA job ARM: 7223/1: mmc: mmci: Fixup use of runtime PM and use autosuspend ARM: 7221/1: mmc: mmci: Change from using legacy suspend ARM: 7219/1: mmc: mmci: Change vdd_handler to a generic ios_handler ARM: 7218/1: mmc: mmci: Provide option to configure bus signal direction ARM: 7217/1: mmc: mmci: Put power register deviations in variant data ARM: 7216/1: mmc: mmci: Do not release spinlock in request_end ARM: 7215/1: mmc: mmci: Increase max_segs from 16 to 128
This commit is contained in:
commit
0d19eac120
@ -96,16 +96,19 @@
|
||||
#define IRQ_EB11MP_L220_SLAVE (IRQ_EB_GIC_START + 30)
|
||||
#define IRQ_EB11MP_L220_DECODE (IRQ_EB_GIC_START + 31)
|
||||
|
||||
#define IRQ_EB11MP_UART2 -1
|
||||
#define IRQ_EB11MP_UART3 -1
|
||||
#define IRQ_EB11MP_CLCD -1
|
||||
#define IRQ_EB11MP_DMA -1
|
||||
#define IRQ_EB11MP_WDOG -1
|
||||
#define IRQ_EB11MP_GPIO0 -1
|
||||
#define IRQ_EB11MP_GPIO1 -1
|
||||
#define IRQ_EB11MP_GPIO2 -1
|
||||
#define IRQ_EB11MP_SCI -1
|
||||
#define IRQ_EB11MP_SSP -1
|
||||
/*
|
||||
* The 11MPcore tile leaves the following unconnected.
|
||||
*/
|
||||
#define IRQ_EB11MP_UART2 0
|
||||
#define IRQ_EB11MP_UART3 0
|
||||
#define IRQ_EB11MP_CLCD 0
|
||||
#define IRQ_EB11MP_DMA 0
|
||||
#define IRQ_EB11MP_WDOG 0
|
||||
#define IRQ_EB11MP_GPIO0 0
|
||||
#define IRQ_EB11MP_GPIO1 0
|
||||
#define IRQ_EB11MP_GPIO2 0
|
||||
#define IRQ_EB11MP_SCI 0
|
||||
#define IRQ_EB11MP_SSP 0
|
||||
|
||||
#define NR_GIC_EB11MP 2
|
||||
|
||||
|
@ -8,7 +8,6 @@ obj-n :=
|
||||
obj- :=
|
||||
|
||||
obj-$(CONFIG_ARCH_U300) += u300.o
|
||||
obj-$(CONFIG_MMC) += mmc.o
|
||||
obj-$(CONFIG_SPI_PL022) += spi.o
|
||||
obj-$(CONFIG_MACH_U300_SPIDUMMY) += dummyspichip.o
|
||||
obj-$(CONFIG_I2C_STU300) += i2c.o
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include <linux/termios.h>
|
||||
#include <linux/dmaengine.h>
|
||||
#include <linux/amba/bus.h>
|
||||
#include <linux/amba/mmci.h>
|
||||
#include <linux/amba/serial.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/gpio.h>
|
||||
@ -44,9 +45,9 @@
|
||||
#include <mach/gpio-u300.h>
|
||||
|
||||
#include "clock.h"
|
||||
#include "mmc.h"
|
||||
#include "spi.h"
|
||||
#include "i2c.h"
|
||||
#include "u300-gpio.h"
|
||||
|
||||
/*
|
||||
* Static I/O mappings that are needed for booting the U300 platforms. The
|
||||
@ -117,11 +118,6 @@ static AMBA_APB_DEVICE(uart1, "uart1", 0, U300_UART1_BASE,
|
||||
/* AHB device at 0x4000 offset */
|
||||
static AMBA_APB_DEVICE(pl172, "pl172", 0, U300_EMIF_CFG_BASE, { }, NULL);
|
||||
|
||||
|
||||
/*
|
||||
* Everything within this next ifdef deals with external devices connected to
|
||||
* the APP SPI bus.
|
||||
*/
|
||||
/* Fast device at 0x6000 offset */
|
||||
static AMBA_APB_DEVICE(pl022, "pl022", 0, U300_SPI_BASE,
|
||||
{ IRQ_U300_SPI }, NULL);
|
||||
@ -129,8 +125,26 @@ static AMBA_APB_DEVICE(pl022, "pl022", 0, U300_SPI_BASE,
|
||||
/* Fast device at 0x1000 offset */
|
||||
#define U300_MMCSD_IRQS { IRQ_U300_MMCSD_MCIINTR0, IRQ_U300_MMCSD_MCIINTR1 }
|
||||
|
||||
static struct mmci_platform_data mmcsd_platform_data = {
|
||||
/*
|
||||
* Do not set ocr_mask or voltage translation function,
|
||||
* we have a regulator we can control instead.
|
||||
*/
|
||||
.f_max = 24000000,
|
||||
.gpio_wp = -1,
|
||||
.gpio_cd = U300_GPIO_PIN_MMC_CD,
|
||||
.cd_invert = true,
|
||||
.capabilities = MMC_CAP_MMC_HIGHSPEED |
|
||||
MMC_CAP_SD_HIGHSPEED | MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA,
|
||||
#ifdef CONFIG_COH901318
|
||||
.dma_filter = coh901318_filter_id,
|
||||
.dma_rx_param = (void *) U300_DMA_MMCSD_RX_TX,
|
||||
/* Don't specify a TX channel, this RX channel is bidirectional */
|
||||
#endif
|
||||
};
|
||||
|
||||
static AMBA_APB_DEVICE(mmcsd, "mmci", 0, U300_MMCSD_BASE,
|
||||
U300_MMCSD_IRQS, NULL);
|
||||
U300_MMCSD_IRQS, &mmcsd_platform_data);
|
||||
|
||||
/*
|
||||
* The order of device declaration may be important, since some devices
|
||||
@ -1830,16 +1844,6 @@ void __init u300_init_devices(void)
|
||||
writew(val, U300_SYSCON_VBASE + U300_SYSCON_SMCR);
|
||||
}
|
||||
|
||||
static int core_module_init(void)
|
||||
{
|
||||
/*
|
||||
* This needs to be initialized later: it needs the input framework
|
||||
* to be initialized first.
|
||||
*/
|
||||
return mmc_init(&mmcsd_device);
|
||||
}
|
||||
module_init(core_module_init);
|
||||
|
||||
/* Forward declare this function from the watchdog */
|
||||
void coh901327_watchdog_reset(void);
|
||||
|
||||
|
@ -1,52 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* arch/arm/mach-u300/mmc.c
|
||||
*
|
||||
*
|
||||
* Copyright (C) 2009 ST-Ericsson SA
|
||||
* License terms: GNU General Public License (GPL) version 2
|
||||
*
|
||||
* Author: Linus Walleij <linus.walleij@stericsson.com>
|
||||
* Author: Johan Lundin
|
||||
* Author: Jonas Aaberg <jonas.aberg@stericsson.com>
|
||||
*/
|
||||
#include <linux/device.h>
|
||||
#include <linux/amba/bus.h>
|
||||
#include <linux/mmc/host.h>
|
||||
#include <linux/dmaengine.h>
|
||||
#include <linux/amba/mmci.h>
|
||||
#include <linux/slab.h>
|
||||
#include <mach/coh901318.h>
|
||||
#include <mach/dma_channels.h>
|
||||
|
||||
#include "u300-gpio.h"
|
||||
#include "mmc.h"
|
||||
|
||||
static struct mmci_platform_data mmc0_plat_data = {
|
||||
/*
|
||||
* Do not set ocr_mask or voltage translation function,
|
||||
* we have a regulator we can control instead.
|
||||
*/
|
||||
/* Nominally 2.85V on our platform */
|
||||
.f_max = 24000000,
|
||||
.gpio_wp = -1,
|
||||
.gpio_cd = U300_GPIO_PIN_MMC_CD,
|
||||
.cd_invert = true,
|
||||
.capabilities = MMC_CAP_MMC_HIGHSPEED |
|
||||
MMC_CAP_SD_HIGHSPEED | MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA,
|
||||
#ifdef CONFIG_COH901318
|
||||
.dma_filter = coh901318_filter_id,
|
||||
.dma_rx_param = (void *) U300_DMA_MMCSD_RX_TX,
|
||||
/* Don't specify a TX channel, this RX channel is bidirectional */
|
||||
#endif
|
||||
};
|
||||
|
||||
int __devinit mmc_init(struct amba_device *adev)
|
||||
{
|
||||
struct device *mmcsd_device = &adev->dev;
|
||||
int ret = 0;
|
||||
|
||||
mmcsd_device->platform_data = &mmc0_plat_data;
|
||||
|
||||
return ret;
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* arch/arm/mach-u300/mmc.h
|
||||
*
|
||||
*
|
||||
* Copyright (C) 2009 ST-Ericsson AB
|
||||
* License terms: GNU General Public License (GPL) version 2
|
||||
*
|
||||
* Author: Jonas Aaberg <jonas.aberg@stericsson.com>
|
||||
*/
|
||||
#ifndef MMC_H
|
||||
#define MMC_H
|
||||
|
||||
#include <linux/amba/bus.h>
|
||||
|
||||
int __devinit mmc_init(struct amba_device *adev);
|
||||
|
||||
#endif
|
@ -31,21 +31,13 @@
|
||||
* SDI 0 (MicroSD slot)
|
||||
*/
|
||||
|
||||
/* MMCIPOWER bits */
|
||||
#define MCI_DATA2DIREN (1 << 2)
|
||||
#define MCI_CMDDIREN (1 << 3)
|
||||
#define MCI_DATA0DIREN (1 << 4)
|
||||
#define MCI_DATA31DIREN (1 << 5)
|
||||
#define MCI_FBCLKEN (1 << 7)
|
||||
|
||||
/* GPIO pins used by the sdi0 level shifter */
|
||||
static int sdi0_en = -1;
|
||||
static int sdi0_vsel = -1;
|
||||
|
||||
static u32 mop500_sdi0_vdd_handler(struct device *dev, unsigned int vdd,
|
||||
unsigned char power_mode)
|
||||
static int mop500_sdi0_ios_handler(struct device *dev, struct mmc_ios *ios)
|
||||
{
|
||||
switch (power_mode) {
|
||||
switch (ios->power_mode) {
|
||||
case MMC_POWER_UP:
|
||||
case MMC_POWER_ON:
|
||||
/*
|
||||
@ -65,8 +57,7 @@ static u32 mop500_sdi0_vdd_handler(struct device *dev, unsigned int vdd,
|
||||
break;
|
||||
}
|
||||
|
||||
return MCI_FBCLKEN | MCI_CMDDIREN | MCI_DATA0DIREN |
|
||||
MCI_DATA2DIREN | MCI_DATA31DIREN;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_STE_DMA40
|
||||
@ -90,13 +81,17 @@ static struct stedma40_chan_cfg mop500_sdi0_dma_cfg_tx = {
|
||||
#endif
|
||||
|
||||
static struct mmci_platform_data mop500_sdi0_data = {
|
||||
.vdd_handler = mop500_sdi0_vdd_handler,
|
||||
.ios_handler = mop500_sdi0_ios_handler,
|
||||
.ocr_mask = MMC_VDD_29_30,
|
||||
.f_max = 50000000,
|
||||
.capabilities = MMC_CAP_4_BIT_DATA |
|
||||
MMC_CAP_SD_HIGHSPEED |
|
||||
MMC_CAP_MMC_HIGHSPEED,
|
||||
.gpio_wp = -1,
|
||||
.sigdir = MCI_ST_FBCLKEN |
|
||||
MCI_ST_CMDDIREN |
|
||||
MCI_ST_DATA0DIREN |
|
||||
MCI_ST_DATA2DIREN,
|
||||
#ifdef CONFIG_STE_DMA40
|
||||
.dma_filter = stedma40_filter,
|
||||
.dma_rx_param = &mop500_sdi0_dma_cfg_rx,
|
||||
|
@ -107,17 +107,6 @@ static struct amba_driver nmk_rng_driver = {
|
||||
.id_table = nmk_rng_ids,
|
||||
};
|
||||
|
||||
static int __init nmk_rng_init(void)
|
||||
{
|
||||
return amba_driver_register(&nmk_rng_driver);
|
||||
}
|
||||
|
||||
static void __devexit nmk_rng_exit(void)
|
||||
{
|
||||
amba_driver_unregister(&nmk_rng_driver);
|
||||
}
|
||||
|
||||
module_init(nmk_rng_init);
|
||||
module_exit(nmk_rng_exit);
|
||||
module_amba_driver(nmk_rng_driver);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -1035,18 +1035,7 @@ static struct amba_driver pl330_driver = {
|
||||
.remove = pl330_remove,
|
||||
};
|
||||
|
||||
static int __init pl330_init(void)
|
||||
{
|
||||
return amba_driver_register(&pl330_driver);
|
||||
}
|
||||
module_init(pl330_init);
|
||||
|
||||
static void __exit pl330_exit(void)
|
||||
{
|
||||
amba_driver_unregister(&pl330_driver);
|
||||
return;
|
||||
}
|
||||
module_exit(pl330_exit);
|
||||
module_amba_driver(pl330_driver);
|
||||
|
||||
MODULE_AUTHOR("Jaswinder Singh <jassi.brar@samsung.com>");
|
||||
MODULE_DESCRIPTION("API Driver for PL330 DMAC");
|
||||
|
@ -208,18 +208,7 @@ static struct amba_driver ambakmi_driver = {
|
||||
.resume = amba_kmi_resume,
|
||||
};
|
||||
|
||||
static int __init amba_kmi_init(void)
|
||||
{
|
||||
return amba_driver_register(&ambakmi_driver);
|
||||
}
|
||||
|
||||
static void __exit amba_kmi_exit(void)
|
||||
{
|
||||
amba_driver_unregister(&ambakmi_driver);
|
||||
}
|
||||
|
||||
module_init(amba_kmi_init);
|
||||
module_exit(amba_kmi_exit);
|
||||
module_amba_driver(ambakmi_driver);
|
||||
|
||||
MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");
|
||||
MODULE_DESCRIPTION("AMBA KMI controller driver");
|
||||
|
@ -53,6 +53,8 @@ static unsigned int fmax = 515633;
|
||||
* @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;
|
||||
@ -63,18 +65,22 @@ struct variant_data {
|
||||
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 = {
|
||||
@ -83,6 +89,8 @@ static struct variant_data variant_u300 = {
|
||||
.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 = {
|
||||
@ -93,6 +101,8 @@ static struct variant_data variant_ux500 = {
|
||||
.datalength_bits = 24,
|
||||
.sdio = true,
|
||||
.st_clkdiv = true,
|
||||
.pwrreg_powerup = MCI_PWR_ON,
|
||||
.signal_direction = true,
|
||||
};
|
||||
|
||||
static struct variant_data variant_ux500v2 = {
|
||||
@ -104,8 +114,32 @@ static struct variant_data variant_ux500v2 = {
|
||||
.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
|
||||
*/
|
||||
@ -153,7 +187,7 @@ static void mmci_set_clkreg(struct mmci_host *host, unsigned int desired)
|
||||
if (host->mmc->ios.bus_width == MMC_BUS_WIDTH_8)
|
||||
clk |= MCI_ST_8BIT_BUS;
|
||||
|
||||
writel(clk, host->base + MMCICLOCK);
|
||||
mmci_write_clkreg(host, clk);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -166,14 +200,10 @@ mmci_request_end(struct mmci_host *host, struct mmc_request *mrq)
|
||||
host->mrq = NULL;
|
||||
host->cmd = NULL;
|
||||
|
||||
/*
|
||||
* Need to drop the host lock here; mmc_request_done may call
|
||||
* back into the driver...
|
||||
*/
|
||||
spin_unlock(&host->lock);
|
||||
pm_runtime_put(mmc_dev(host->mmc));
|
||||
mmc_request_done(host->mmc, mrq);
|
||||
spin_lock(&host->lock);
|
||||
|
||||
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)
|
||||
@ -607,6 +637,11 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data)
|
||||
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
|
||||
@ -635,11 +670,6 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data)
|
||||
irqmask = MCI_TXFIFOHALFEMPTYMASK;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
|
||||
writel(datactrl, base + MMCIDATACTRL);
|
||||
writel(readl(base + MMCIMASK0) & ~MCI_DATAENDMASK, base + MMCIMASK0);
|
||||
mmci_set_mask1(host, irqmask);
|
||||
@ -786,7 +816,24 @@ static int mmci_pio_read(struct mmci_host *host, char *buffer, unsigned int rema
|
||||
if (count <= 0)
|
||||
break;
|
||||
|
||||
readsl(base + MMCIFIFO, ptr, count >> 2);
|
||||
/*
|
||||
* 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;
|
||||
@ -821,14 +868,13 @@ static int mmci_pio_write(struct mmci_host *host, char *buffer, unsigned int rem
|
||||
*/
|
||||
if (variant->sdio &&
|
||||
mmc_card_sdio(host->mmc->card)) {
|
||||
u32 clk;
|
||||
if (count < 8)
|
||||
writel(readl(host->base + MMCICLOCK) &
|
||||
~variant->clkreg_enable,
|
||||
host->base + MMCICLOCK);
|
||||
clk = host->clk_reg & ~variant->clkreg_enable;
|
||||
else
|
||||
writel(readl(host->base + MMCICLOCK) |
|
||||
variant->clkreg_enable,
|
||||
host->base + MMCICLOCK);
|
||||
clk = host->clk_reg | variant->clkreg_enable;
|
||||
|
||||
mmci_write_clkreg(host, clk);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1015,10 +1061,17 @@ static void mmci_request(struct mmc_host *mmc, struct mmc_request *mrq)
|
||||
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)
|
||||
@ -1035,22 +1088,38 @@ static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
|
||||
* power should be rare so we print an error
|
||||
* and return here.
|
||||
*/
|
||||
return;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
if (host->plat->vdd_handler)
|
||||
pwr |= host->plat->vdd_handler(mmc_dev(mmc), ios->vdd,
|
||||
ios->power_mode);
|
||||
/* The ST version does not have this, fall through to POWER_ON */
|
||||
if (host->hw_designer != AMBA_VENDOR_ST) {
|
||||
pwr |= MCI_PWR_UP;
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* 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;
|
||||
@ -1066,13 +1135,13 @@ static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
|
||||
spin_lock_irqsave(&host->lock, flags);
|
||||
|
||||
mmci_set_clkreg(host, ios->clock);
|
||||
|
||||
if (host->pwr != pwr) {
|
||||
host->pwr = pwr;
|
||||
writel(pwr, host->base + MMCIPOWER);
|
||||
}
|
||||
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)
|
||||
@ -1346,6 +1415,8 @@ static int __devinit mmci_probe(struct amba_device *dev,
|
||||
|
||||
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);
|
||||
@ -1430,43 +1501,49 @@ static int __devexit mmci_remove(struct amba_device *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int mmci_suspend(struct amba_device *dev, pm_message_t state)
|
||||
#ifdef CONFIG_SUSPEND
|
||||
static int mmci_suspend(struct device *dev)
|
||||
{
|
||||
struct mmc_host *mmc = amba_get_drvdata(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)
|
||||
if (ret == 0) {
|
||||
pm_runtime_get_sync(dev);
|
||||
writel(0, host->base + MMCIMASK0);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mmci_resume(struct amba_device *dev)
|
||||
static int mmci_resume(struct device *dev)
|
||||
{
|
||||
struct mmc_host *mmc = amba_get_drvdata(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;
|
||||
}
|
||||
#else
|
||||
#define mmci_suspend NULL
|
||||
#define mmci_resume NULL
|
||||
#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,
|
||||
@ -1512,26 +1589,15 @@ 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),
|
||||
.suspend = mmci_suspend,
|
||||
.resume = mmci_resume,
|
||||
.id_table = mmci_ids,
|
||||
};
|
||||
|
||||
static int __init mmci_init(void)
|
||||
{
|
||||
return amba_driver_register(&mmci_driver);
|
||||
}
|
||||
module_amba_driver(mmci_driver);
|
||||
|
||||
static void __exit mmci_exit(void)
|
||||
{
|
||||
amba_driver_unregister(&mmci_driver);
|
||||
}
|
||||
|
||||
module_init(mmci_init);
|
||||
module_exit(mmci_exit);
|
||||
module_param(fmax, uint, 0444);
|
||||
|
||||
MODULE_DESCRIPTION("ARM PrimeCell PL180/181 Multimedia Card Interface driver");
|
||||
|
@ -13,16 +13,6 @@
|
||||
#define MCI_PWR_ON 0x03
|
||||
#define MCI_OD (1 << 6)
|
||||
#define MCI_ROD (1 << 7)
|
||||
/*
|
||||
* The ST Micro version does not have ROD and reuse the voltage registers
|
||||
* for direction settings
|
||||
*/
|
||||
#define MCI_ST_DATA2DIREN (1 << 2)
|
||||
#define MCI_ST_CMDDIREN (1 << 3)
|
||||
#define MCI_ST_DATA0DIREN (1 << 4)
|
||||
#define MCI_ST_DATA31DIREN (1 << 5)
|
||||
#define MCI_ST_FBCLKEN (1 << 7)
|
||||
#define MCI_ST_DATA74DIREN (1 << 8)
|
||||
|
||||
#define MMCICLOCK 0x004
|
||||
#define MCI_CLK_ENABLE (1 << 8)
|
||||
@ -160,7 +150,7 @@
|
||||
(MCI_RXFIFOHALFFULLMASK | MCI_RXDATAAVLBLMASK | \
|
||||
MCI_TXFIFOHALFEMPTYMASK)
|
||||
|
||||
#define NR_SG 16
|
||||
#define NR_SG 128
|
||||
|
||||
struct clk;
|
||||
struct variant_data;
|
||||
@ -189,7 +179,8 @@ struct mmci_host {
|
||||
|
||||
unsigned int mclk;
|
||||
unsigned int cclk;
|
||||
u32 pwr;
|
||||
u32 pwr_reg;
|
||||
u32 clk_reg;
|
||||
struct mmci_platform_data *plat;
|
||||
struct variant_data *variant;
|
||||
|
||||
|
@ -185,18 +185,7 @@ static struct amba_driver pl030_driver = {
|
||||
.id_table = pl030_ids,
|
||||
};
|
||||
|
||||
static int __init pl030_init(void)
|
||||
{
|
||||
return amba_driver_register(&pl030_driver);
|
||||
}
|
||||
|
||||
static void __exit pl030_exit(void)
|
||||
{
|
||||
amba_driver_unregister(&pl030_driver);
|
||||
}
|
||||
|
||||
module_init(pl030_init);
|
||||
module_exit(pl030_exit);
|
||||
module_amba_driver(pl030_driver);
|
||||
|
||||
MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");
|
||||
MODULE_DESCRIPTION("ARM AMBA PL030 RTC Driver");
|
||||
|
@ -431,18 +431,7 @@ static struct amba_driver pl031_driver = {
|
||||
.remove = pl031_remove,
|
||||
};
|
||||
|
||||
static int __init pl031_init(void)
|
||||
{
|
||||
return amba_driver_register(&pl031_driver);
|
||||
}
|
||||
|
||||
static void __exit pl031_exit(void)
|
||||
{
|
||||
amba_driver_unregister(&pl031_driver);
|
||||
}
|
||||
|
||||
module_init(pl031_init);
|
||||
module_exit(pl031_exit);
|
||||
module_amba_driver(pl031_driver);
|
||||
|
||||
MODULE_AUTHOR("Deepak Saxena <dsaxena@plexity.net");
|
||||
MODULE_DESCRIPTION("ARM AMBA PL031 RTC Driver");
|
||||
|
@ -370,17 +370,7 @@ static struct amba_driver sp805_wdt_driver = {
|
||||
.remove = __devexit_p(sp805_wdt_remove),
|
||||
};
|
||||
|
||||
static int __init sp805_wdt_init(void)
|
||||
{
|
||||
return amba_driver_register(&sp805_wdt_driver);
|
||||
}
|
||||
module_init(sp805_wdt_init);
|
||||
|
||||
static void __exit sp805_wdt_exit(void)
|
||||
{
|
||||
amba_driver_unregister(&sp805_wdt_driver);
|
||||
}
|
||||
module_exit(sp805_wdt_exit);
|
||||
module_amba_driver(sp805_wdt_driver);
|
||||
|
||||
module_param(nowayout, int, 0);
|
||||
MODULE_PARM_DESC(nowayout,
|
||||
|
@ -125,4 +125,13 @@ struct amba_device name##_device = { \
|
||||
.periphid = id, \
|
||||
}
|
||||
|
||||
/*
|
||||
* module_amba_driver() - Helper macro for drivers that don't do anything
|
||||
* special in module init/exit. This eliminates a lot of boilerplate. Each
|
||||
* module may only use this macro once, and calling it replaces module_init()
|
||||
* and module_exit()
|
||||
*/
|
||||
#define module_amba_driver(__amba_drv) \
|
||||
module_driver(__amba_drv, amba_driver_register, amba_driver_unregister)
|
||||
|
||||
#endif
|
||||
|
@ -6,6 +6,19 @@
|
||||
|
||||
#include <linux/mmc/host.h>
|
||||
|
||||
|
||||
/*
|
||||
* These defines is places here due to access is needed from machine
|
||||
* configuration files. The ST Micro version does not have ROD and
|
||||
* reuse the voltage registers for direction settings.
|
||||
*/
|
||||
#define MCI_ST_DATA2DIREN (1 << 2)
|
||||
#define MCI_ST_CMDDIREN (1 << 3)
|
||||
#define MCI_ST_DATA0DIREN (1 << 4)
|
||||
#define MCI_ST_DATA31DIREN (1 << 5)
|
||||
#define MCI_ST_FBCLKEN (1 << 7)
|
||||
#define MCI_ST_DATA74DIREN (1 << 8)
|
||||
|
||||
/* Just some dummy forwarding */
|
||||
struct dma_chan;
|
||||
|
||||
@ -18,7 +31,8 @@ struct dma_chan;
|
||||
* @ocr_mask: available voltages on the 4 pins from the block, this
|
||||
* is ignored if a regulator is used, see the MMC_VDD_* masks in
|
||||
* mmc/host.h
|
||||
* @vdd_handler: a callback function to translate a MMC_VDD_*
|
||||
* @ios_handler: a callback function to act on specfic ios changes,
|
||||
* used for example to control a levelshifter
|
||||
* mask into a value to be binary (or set some other custom bits
|
||||
* in MMCIPWR) or:ed and written into the MMCIPWR register of the
|
||||
* block. May also control external power based on the power_mode.
|
||||
@ -31,6 +45,8 @@ struct dma_chan;
|
||||
* @capabilities: the capabilities of the block as implemented in
|
||||
* this platform, signify anything MMC_CAP_* from mmc/host.h
|
||||
* @capabilities2: more capabilities, MMC_CAP2_* from mmc/host.h
|
||||
* @sigdir: a bit field indicating for what bits in the MMC bus the host
|
||||
* should enable signal direction indication.
|
||||
* @dma_filter: function used to select an appropriate RX and TX
|
||||
* DMA channel to be used for DMA, if and only if you're deploying the
|
||||
* generic DMA engine
|
||||
@ -46,14 +62,14 @@ struct dma_chan;
|
||||
struct mmci_platform_data {
|
||||
unsigned int f_max;
|
||||
unsigned int ocr_mask;
|
||||
u32 (*vdd_handler)(struct device *, unsigned int vdd,
|
||||
unsigned char power_mode);
|
||||
int (*ios_handler)(struct device *, struct mmc_ios *);
|
||||
unsigned int (*status)(struct device *);
|
||||
int gpio_wp;
|
||||
int gpio_cd;
|
||||
bool cd_invert;
|
||||
unsigned long capabilities;
|
||||
unsigned long capabilities2;
|
||||
u32 sigdir;
|
||||
bool (*dma_filter)(struct dma_chan *chan, void *filter_param);
|
||||
void *dma_rx_param;
|
||||
void *dma_tx_param;
|
||||
|
@ -1110,18 +1110,7 @@ static struct amba_driver aaci_driver = {
|
||||
.id_table = aaci_ids,
|
||||
};
|
||||
|
||||
static int __init aaci_init(void)
|
||||
{
|
||||
return amba_driver_register(&aaci_driver);
|
||||
}
|
||||
|
||||
static void __exit aaci_exit(void)
|
||||
{
|
||||
amba_driver_unregister(&aaci_driver);
|
||||
}
|
||||
|
||||
module_init(aaci_init);
|
||||
module_exit(aaci_exit);
|
||||
module_amba_driver(aaci_driver);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("ARM PrimeCell PL041 Advanced Audio CODEC Interface driver");
|
||||
|
Loading…
Reference in New Issue
Block a user