From a6a6464a0ecd20c5f1594a4fe5b24af6181b7366 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 14 Sep 2009 12:56:14 +0100 Subject: ARM: 5697/1: MMCI Break out clock divider setup This breaks out the clock divider set-up code from the mmci_set_ios() code and surrounds the two register writes with a host lock so we don't get collisions if (in future code) two code paths want to change the clock divider at the same time as can be the case if we get something like pre/post- clock frequency change notifications soonish. Signed-off-by: Linus Walleij Signed-off-by: Russell King --- drivers/mmc/host/mmci.c | 51 ++++++++++++++++++++++++++++++++----------------- 1 file changed, 34 insertions(+), 17 deletions(-) (limited to 'drivers/mmc/host/mmci.c') diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 8741d0f5146..031141a7c87 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -38,6 +38,33 @@ static unsigned int fmax = 515633; +/* + * This must be called with host->lock held + */ +static void mmci_set_clkreg(struct mmci_host *host, unsigned int desired) +{ + u32 clk = 0; + + if (desired) { + if (desired >= host->mclk) { + clk = MCI_CLK_BYPASS; + host->cclk = host->mclk; + } else { + clk = host->mclk / (2 * desired) - 1; + if (clk >= 256) + clk = 255; + host->cclk = host->mclk / (2 * (clk + 1)); + } + if (host->hw_designer == 0x80) + clk |= MCI_FCEN; /* Bug fix in ST IP block */ + clk |= MCI_CLK_ENABLE; + /* This hasn't proven to be worthwhile */ + /* clk |= MCI_CLK_PWRSAVE; */ + } + + writel(clk, host->base + MMCICLOCK); +} + static void mmci_request_end(struct mmci_host *host, struct mmc_request *mrq) { @@ -419,22 +446,8 @@ 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); - u32 clk = 0, pwr = 0; - - if (ios->clock) { - if (ios->clock >= host->mclk) { - clk = MCI_CLK_BYPASS; - host->cclk = host->mclk; - } else { - clk = host->mclk / (2 * ios->clock) - 1; - if (clk >= 256) - clk = 255; - host->cclk = host->mclk / (2 * (clk + 1)); - } - if (host->hw_designer == AMBA_VENDOR_ST) - clk |= MCI_FCEN; /* Bug fix in ST IP block */ - clk |= MCI_CLK_ENABLE; - } + u32 pwr = 0; + unsigned long flags; if (host->plat->translate_vdd) pwr |= host->plat->translate_vdd(mmc_dev(mmc), ios->vdd); @@ -465,12 +478,16 @@ static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) } } - writel(clk, host->base + MMCICLOCK); + spin_lock_irqsave(&host->lock, flags); + + mmci_set_clkreg(host, ios->clock); if (host->pwr != pwr) { host->pwr = pwr; writel(pwr, host->base + MMCIPOWER); } + + spin_unlock_irqrestore(&host->lock, flags); } static int mmci_get_ro(struct mmc_host *mmc) -- cgit v1.2.3-70-g09d2 From 9e6c82cd3e1a739ef48bf8c1decc8e7a7d8de3ac Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 14 Sep 2009 12:57:11 +0100 Subject: ARM: 5698/1: MMCI pass capabilities in platform data This makes it possible to pass down the host controller capabilities for the MMCI driver using the platform data. It also provides the capabilties for the U300 implementation as an example, and makes sure the 4bit wide mode is set if this is requested by the ios() now that we can actually set that capability for a platform. Signed-off-by: Linus Walleij Signed-off-by: Russell King --- arch/arm/include/asm/mach/mmc.h | 1 + arch/arm/mach-u300/mmc.c | 2 ++ drivers/mmc/host/mmci.c | 4 ++++ 3 files changed, 7 insertions(+) (limited to 'drivers/mmc/host/mmci.c') diff --git a/arch/arm/include/asm/mach/mmc.h b/arch/arm/include/asm/mach/mmc.h index b490ecc79de..27bec555ee1 100644 --- a/arch/arm/include/asm/mach/mmc.h +++ b/arch/arm/include/asm/mach/mmc.h @@ -12,6 +12,7 @@ struct mmc_platform_data { unsigned int (*status)(struct device *); int gpio_wp; int gpio_cd; + unsigned long capabilities; }; #endif diff --git a/arch/arm/mach-u300/mmc.c b/arch/arm/mach-u300/mmc.c index 585cc013639..089b9957b6a 100644 --- a/arch/arm/mach-u300/mmc.c +++ b/arch/arm/mach-u300/mmc.c @@ -158,6 +158,8 @@ int __devinit mmc_init(struct amba_device *adev) mmci_card->mmc0_plat_data.status = mmc_status; mmci_card->mmc0_plat_data.gpio_wp = -1; mmci_card->mmc0_plat_data.gpio_cd = -1; + mmci_card->mmc0_plat_data.capabilities = MMC_CAP_MMC_HIGHSPEED | + MMC_CAP_SD_HIGHSPEED | MMC_CAP_4_BIT_DATA; mmcsd_device->platform_data = (void *) &mmci_card->mmc0_plat_data; diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 031141a7c87..bf7c05b29e2 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -62,6 +62,9 @@ static void mmci_set_clkreg(struct mmci_host *host, unsigned int desired) /* clk |= MCI_CLK_PWRSAVE; */ } + if (host->mmc->ios.bus_width == MMC_BUS_WIDTH_4) + clk |= MCI_WIDE_BUS; + writel(clk, host->base + MMCICLOCK); } @@ -601,6 +604,7 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id) mmc->f_min = (host->mclk + 511) / 512; mmc->f_max = min(host->mclk, fmax); mmc->ocr_avail = plat->ocr_mask; + mmc->caps = plat->capabilities; /* * We can do SGIO -- cgit v1.2.3-70-g09d2 From 6ef297f86b62f187c59475784208f75c2ed8ccd8 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 22 Sep 2009 14:29:36 +0100 Subject: ARM: 5720/1: Move MMCI header to amba include dir This moves the mmci platform data definition struct away from arch/arm/include/asm/mach/mmc.h into the more proper place among the other primecells in include/linux/amba/mmci.h and at the same time renames it to "mmci.h", and also the struct in this file confusingly named mmc_platform_data has been renamed mmci_platform_data for clarity. Cc: Catalin Marinas Signed-off-by: Linus Walleij Signed-off-by: Russell King --- arch/arm/include/asm/mach/mmc.h | 18 ------------------ arch/arm/mach-integrator/integrator_cp.c | 4 ++-- arch/arm/mach-realview/core.c | 6 +++--- arch/arm/mach-realview/core.h | 4 ++-- arch/arm/mach-realview/realview_eb.c | 2 +- arch/arm/mach-realview/realview_pb1176.c | 2 +- arch/arm/mach-realview/realview_pb11mp.c | 2 +- arch/arm/mach-realview/realview_pba8.c | 2 +- arch/arm/mach-realview/realview_pbx.c | 2 +- arch/arm/mach-u300/mmc.c | 4 ++-- arch/arm/mach-versatile/core.c | 4 ++-- arch/arm/mach-versatile/versatile_pb.c | 4 ++-- drivers/mmc/host/mmci.c | 4 ++-- drivers/mmc/host/mmci.h | 2 +- include/linux/amba/mmci.h | 18 ++++++++++++++++++ 15 files changed, 39 insertions(+), 39 deletions(-) delete mode 100644 arch/arm/include/asm/mach/mmc.h create mode 100644 include/linux/amba/mmci.h (limited to 'drivers/mmc/host/mmci.c') diff --git a/arch/arm/include/asm/mach/mmc.h b/arch/arm/include/asm/mach/mmc.h deleted file mode 100644 index 27bec555ee1..00000000000 --- a/arch/arm/include/asm/mach/mmc.h +++ /dev/null @@ -1,18 +0,0 @@ -/* - * arch/arm/include/asm/mach/mmc.h - */ -#ifndef ASMARM_MACH_MMC_H -#define ASMARM_MACH_MMC_H - -#include - -struct mmc_platform_data { - unsigned int ocr_mask; /* available voltages */ - u32 (*translate_vdd)(struct device *, unsigned int); - unsigned int (*status)(struct device *); - int gpio_wp; - int gpio_cd; - unsigned long capabilities; -}; - -#endif diff --git a/arch/arm/mach-integrator/integrator_cp.c b/arch/arm/mach-integrator/integrator_cp.c index 2a318eba1b0..3f35293d457 100644 --- a/arch/arm/mach-integrator/integrator_cp.c +++ b/arch/arm/mach-integrator/integrator_cp.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -35,7 +36,6 @@ #include #include #include -#include #include #include @@ -400,7 +400,7 @@ static unsigned int mmc_status(struct device *dev) return status & 8; } -static struct mmc_platform_data mmc_data = { +static struct mmci_platform_data mmc_data = { .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34, .status = mmc_status, .gpio_wp = -1, diff --git a/arch/arm/mach-realview/core.c b/arch/arm/mach-realview/core.c index 5a5e1f72461..a2083b60e3f 100644 --- a/arch/arm/mach-realview/core.c +++ b/arch/arm/mach-realview/core.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -44,7 +45,6 @@ #include #include #include -#include #include @@ -237,14 +237,14 @@ static unsigned int realview_mmc_status(struct device *dev) return readl(REALVIEW_SYSMCI) & mask; } -struct mmc_platform_data realview_mmc0_plat_data = { +struct mmci_platform_data realview_mmc0_plat_data = { .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34, .status = realview_mmc_status, .gpio_wp = 17, .gpio_cd = 16, }; -struct mmc_platform_data realview_mmc1_plat_data = { +struct mmci_platform_data realview_mmc1_plat_data = { .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34, .status = realview_mmc_status, .gpio_wp = 19, diff --git a/arch/arm/mach-realview/core.h b/arch/arm/mach-realview/core.h index 59a337ba4be..46cd6acb4d4 100644 --- a/arch/arm/mach-realview/core.h +++ b/arch/arm/mach-realview/core.h @@ -47,8 +47,8 @@ static struct amba_device name##_device = { \ extern struct platform_device realview_flash_device; extern struct platform_device realview_cf_device; extern struct platform_device realview_i2c_device; -extern struct mmc_platform_data realview_mmc0_plat_data; -extern struct mmc_platform_data realview_mmc1_plat_data; +extern struct mmci_platform_data realview_mmc0_plat_data; +extern struct mmci_platform_data realview_mmc1_plat_data; extern struct clcd_board clcd_plat_data; extern void __iomem *gic_cpu_base_addr; extern void __iomem *timer0_va_base; diff --git a/arch/arm/mach-realview/realview_eb.c b/arch/arm/mach-realview/realview_eb.c index c0795ea3b3a..1d65e64ae57 100644 --- a/arch/arm/mach-realview/realview_eb.c +++ b/arch/arm/mach-realview/realview_eb.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -37,7 +38,6 @@ #include #include -#include #include #include diff --git a/arch/arm/mach-realview/realview_pb1176.c b/arch/arm/mach-realview/realview_pb1176.c index 395dc18070b..2817fe09931 100644 --- a/arch/arm/mach-realview/realview_pb1176.c +++ b/arch/arm/mach-realview/realview_pb1176.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -37,7 +38,6 @@ #include #include #include -#include #include #include diff --git a/arch/arm/mach-realview/realview_pb11mp.c b/arch/arm/mach-realview/realview_pb11mp.c index c0c9e35e6e3..94680fcf726 100644 --- a/arch/arm/mach-realview/realview_pb11mp.c +++ b/arch/arm/mach-realview/realview_pb11mp.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -38,7 +39,6 @@ #include #include #include -#include #include #include diff --git a/arch/arm/mach-realview/realview_pba8.c b/arch/arm/mach-realview/realview_pba8.c index 4fc64e146c3..941beb2b970 100644 --- a/arch/arm/mach-realview/realview_pba8.c +++ b/arch/arm/mach-realview/realview_pba8.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -34,7 +35,6 @@ #include #include -#include #include #include diff --git a/arch/arm/mach-realview/realview_pbx.c b/arch/arm/mach-realview/realview_pbx.c index cf68b542606..7e4bc6cdca5 100644 --- a/arch/arm/mach-realview/realview_pbx.c +++ b/arch/arm/mach-realview/realview_pbx.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -34,7 +35,6 @@ #include #include -#include #include #include diff --git a/arch/arm/mach-u300/mmc.c b/arch/arm/mach-u300/mmc.c index 82af247760e..7b6b016786b 100644 --- a/arch/arm/mach-u300/mmc.c +++ b/arch/arm/mach-u300/mmc.c @@ -19,8 +19,8 @@ #include #include #include +#include -#include #include "mmc.h" #include "padmux.h" @@ -28,7 +28,7 @@ struct mmci_card_event { struct input_dev *mmc_input; int mmc_inserted; struct work_struct workq; - struct mmc_platform_data mmc0_plat_data; + struct mmci_platform_data mmc0_plat_data; }; static unsigned int mmc_status(struct device *dev) diff --git a/arch/arm/mach-versatile/core.c b/arch/arm/mach-versatile/core.c index 975eae41ee6..e13be7c444c 100644 --- a/arch/arm/mach-versatile/core.c +++ b/arch/arm/mach-versatile/core.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -47,7 +48,6 @@ #include #include #include -#include #include "core.h" #include "clock.h" @@ -369,7 +369,7 @@ unsigned int mmc_status(struct device *dev) return readl(VERSATILE_SYSMCI) & mask; } -static struct mmc_platform_data mmc0_plat_data = { +static struct mmci_platform_data mmc0_plat_data = { .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34, .status = mmc_status, .gpio_wp = -1, diff --git a/arch/arm/mach-versatile/versatile_pb.c b/arch/arm/mach-versatile/versatile_pb.c index 9af8d8154df..239cd30fc4f 100644 --- a/arch/arm/mach-versatile/versatile_pb.c +++ b/arch/arm/mach-versatile/versatile_pb.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -31,7 +32,6 @@ #include #include -#include #include "core.h" @@ -41,7 +41,7 @@ #define IRQ_MMCI1A IRQ_SIC_MMCI1A #endif -static struct mmc_platform_data mmc1_plat_data = { +static struct mmci_platform_data mmc1_plat_data = { .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34, .status = mmc_status, .gpio_wp = -1, diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index bf7c05b29e2..79205e565c0 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -22,12 +22,12 @@ #include #include #include +#include #include #include #include #include -#include #include "mmci.h" @@ -537,7 +537,7 @@ static void mmci_check_status(unsigned long data) static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id) { - struct mmc_platform_data *plat = dev->dev.platform_data; + struct mmci_platform_data *plat = dev->dev.platform_data; struct mmci_host *host; struct mmc_host *mmc; int ret; diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h index 839f264c972..a7f9a51a0a3 100644 --- a/drivers/mmc/host/mmci.h +++ b/drivers/mmc/host/mmci.h @@ -161,7 +161,7 @@ struct mmci_host { unsigned int mclk; unsigned int cclk; u32 pwr; - struct mmc_platform_data *plat; + struct mmci_platform_data *plat; u8 hw_designer; u8 hw_revision:4; diff --git a/include/linux/amba/mmci.h b/include/linux/amba/mmci.h new file mode 100644 index 00000000000..6b4241748dd --- /dev/null +++ b/include/linux/amba/mmci.h @@ -0,0 +1,18 @@ +/* + * include/linux/amba/mmci.h + */ +#ifndef AMBA_MMCI_H +#define AMBA_MMCI_H + +#include + +struct mmci_platform_data { + unsigned int ocr_mask; /* available voltages */ + u32 (*translate_vdd)(struct device *, unsigned int); + unsigned int (*status)(struct device *); + int gpio_wp; + int gpio_cd; + unsigned long capabilities; +}; + +#endif -- cgit v1.2.3-70-g09d2 From 34e84f39a27d059a3e6ec6e8b94aafa702e6f220 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 22 Sep 2009 14:41:40 +0100 Subject: ARM: 5721/1: MMCI enable the use of a regulator This enables the use of a regulator to power the MMCI/PL180 PrimeCell. The OCR mask is calculated and voltage is set using the new MMC core functions for discovering voltage ranges in regulators. The platform translate_vdd function which basically controls the 4 lines out of the PL180 is disabled if you use a regulator instead. Signed-off-by: Linus Walleij Signed-off-by: Russell King --- drivers/mmc/host/mmci.c | 50 +++++++++++++++++++++++++++++++++++++++++++++---- drivers/mmc/host/mmci.h | 1 + 2 files changed, 47 insertions(+), 4 deletions(-) (limited to 'drivers/mmc/host/mmci.c') diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 79205e565c0..3d1e5329da1 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -452,13 +453,28 @@ static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) u32 pwr = 0; unsigned long flags; - if (host->plat->translate_vdd) - pwr |= host->plat->translate_vdd(mmc_dev(mmc), ios->vdd); - switch (ios->power_mode) { case MMC_POWER_OFF: + if(host->vcc && + regulator_is_enabled(host->vcc)) + regulator_disable(host->vcc); break; case MMC_POWER_UP: +#ifdef CONFIG_REGULATOR + if (host->vcc) + /* This implicitly enables the regulator */ + mmc_regulator_set_ocr(host->vcc, ios->vdd); +#endif + /* + * The translate_vdd function is not used if you have + * an external regulator, or your design is really weird. + * Using it would mean sending in power control BOTH using + * a regulator AND the 4 MMCIPWR bits. If we don't have + * a regulator, we might have some other platform specific + * power control behind this translate function. + */ + if (!host->vcc && host->plat->translate_vdd) + pwr |= host->plat->translate_vdd(mmc_dev(mmc), ios->vdd); /* The ST version does not have this, fall through to POWER_ON */ if (host->hw_designer != AMBA_VENDOR_ST) { pwr |= MCI_PWR_UP; @@ -603,7 +619,29 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id) mmc->ops = &mmci_ops; mmc->f_min = (host->mclk + 511) / 512; mmc->f_max = min(host->mclk, fmax); - mmc->ocr_avail = plat->ocr_mask; +#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; /* @@ -741,6 +779,10 @@ static int __devexit mmci_remove(struct amba_device *dev) clk_disable(host->clk); clk_put(host->clk); + if (regulator_is_enabled(host->vcc)) + regulator_disable(host->vcc); + regulator_put(host->vcc); + mmc_free_host(mmc); amba_release_regions(dev); diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h index a7f9a51a0a3..1ceb9a90f59 100644 --- a/drivers/mmc/host/mmci.h +++ b/drivers/mmc/host/mmci.h @@ -175,6 +175,7 @@ struct mmci_host { struct scatterlist *sg_ptr; unsigned int sg_off; unsigned int size; + struct regulator *vcc; }; static inline void mmci_init_sg(struct mmci_host *host, struct mmc_data *data) -- cgit v1.2.3-70-g09d2