|
@@ -14,6 +14,7 @@
|
|
#include <linux/init.h>
|
|
#include <linux/init.h>
|
|
#include <linux/platform_device.h>
|
|
#include <linux/platform_device.h>
|
|
#include <linux/io.h>
|
|
#include <linux/io.h>
|
|
|
|
+#include <linux/clk.h>
|
|
|
|
|
|
#include <mach/hardware.h>
|
|
#include <mach/hardware.h>
|
|
#include <asm/mach-types.h>
|
|
#include <asm/mach-types.h>
|
|
@@ -299,6 +300,89 @@ static inline void omap_init_sha1_md5(void) { }
|
|
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
|
|
|
|
+#ifdef CONFIG_ARCH_OMAP3
|
|
|
|
+
|
|
|
|
+#define MMCHS_SYSCONFIG 0x0010
|
|
|
|
+#define MMCHS_SYSCONFIG_SWRESET (1 << 1)
|
|
|
|
+#define MMCHS_SYSSTATUS 0x0014
|
|
|
|
+#define MMCHS_SYSSTATUS_RESETDONE (1 << 0)
|
|
|
|
+
|
|
|
|
+static struct platform_device dummy_pdev = {
|
|
|
|
+ .dev = {
|
|
|
|
+ .bus = &platform_bus_type,
|
|
|
|
+ },
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * omap_hsmmc_reset() - Full reset of each HS-MMC controller
|
|
|
|
+ *
|
|
|
|
+ * Ensure that each MMC controller is fully reset. Controllers
|
|
|
|
+ * left in an unknown state (by bootloader) may prevent retention
|
|
|
|
+ * or OFF-mode. This is especially important in cases where the
|
|
|
|
+ * MMC driver is not enabled, _or_ built as a module.
|
|
|
|
+ *
|
|
|
|
+ * In order for reset to work, interface, functional and debounce
|
|
|
|
+ * clocks must be enabled. The debounce clock comes from func_32k_clk
|
|
|
|
+ * and is not under SW control, so we only enable i- and f-clocks.
|
|
|
|
+ **/
|
|
|
|
+static void __init omap_hsmmc_reset(void)
|
|
|
|
+{
|
|
|
|
+ u32 i, nr_controllers = cpu_is_omap34xx() ? OMAP34XX_NR_MMC :
|
|
|
|
+ OMAP24XX_NR_MMC;
|
|
|
|
+
|
|
|
|
+ for (i = 0; i < nr_controllers; i++) {
|
|
|
|
+ u32 v, base = 0;
|
|
|
|
+ struct clk *iclk, *fclk;
|
|
|
|
+ struct device *dev = &dummy_pdev.dev;
|
|
|
|
+
|
|
|
|
+ switch (i) {
|
|
|
|
+ case 0:
|
|
|
|
+ base = OMAP2_MMC1_BASE;
|
|
|
|
+ break;
|
|
|
|
+ case 1:
|
|
|
|
+ base = OMAP2_MMC2_BASE;
|
|
|
|
+ break;
|
|
|
|
+ case 2:
|
|
|
|
+ base = OMAP3_MMC3_BASE;
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ dummy_pdev.id = i;
|
|
|
|
+ iclk = clk_get(dev, "mmchs_ick");
|
|
|
|
+ if (iclk && clk_enable(iclk))
|
|
|
|
+ iclk = NULL;
|
|
|
|
+
|
|
|
|
+ fclk = clk_get(dev, "mmchs_fck");
|
|
|
|
+ if (fclk && clk_enable(fclk))
|
|
|
|
+ fclk = NULL;
|
|
|
|
+
|
|
|
|
+ if (!iclk || !fclk) {
|
|
|
|
+ printk(KERN_WARNING
|
|
|
|
+ "%s: Unable to enable clocks for MMC%d, "
|
|
|
|
+ "cannot reset.\n", __func__, i);
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ omap_writel(MMCHS_SYSCONFIG_SWRESET, base + MMCHS_SYSCONFIG);
|
|
|
|
+ v = omap_readl(base + MMCHS_SYSSTATUS);
|
|
|
|
+ while (!(omap_readl(base + MMCHS_SYSSTATUS) &
|
|
|
|
+ MMCHS_SYSSTATUS_RESETDONE))
|
|
|
|
+ cpu_relax();
|
|
|
|
+
|
|
|
|
+ if (fclk) {
|
|
|
|
+ clk_disable(fclk);
|
|
|
|
+ clk_put(fclk);
|
|
|
|
+ }
|
|
|
|
+ if (iclk) {
|
|
|
|
+ clk_disable(iclk);
|
|
|
|
+ clk_put(iclk);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+#else
|
|
|
|
+static inline void omap_hsmmc_reset(void) {}
|
|
|
|
+#endif
|
|
|
|
+
|
|
#if defined(CONFIG_MMC_OMAP) || defined(CONFIG_MMC_OMAP_MODULE) || \
|
|
#if defined(CONFIG_MMC_OMAP) || defined(CONFIG_MMC_OMAP_MODULE) || \
|
|
defined(CONFIG_MMC_OMAP_HS) || defined(CONFIG_MMC_OMAP_HS_MODULE)
|
|
defined(CONFIG_MMC_OMAP_HS) || defined(CONFIG_MMC_OMAP_HS_MODULE)
|
|
|
|
|
|
@@ -418,6 +502,7 @@ static int __init omap2_init_devices(void)
|
|
/* please keep these calls, and their implementations above,
|
|
/* please keep these calls, and their implementations above,
|
|
* in alphabetical order so they're easier to sort through.
|
|
* in alphabetical order so they're easier to sort through.
|
|
*/
|
|
*/
|
|
|
|
+ omap_hsmmc_reset();
|
|
omap_init_mbox();
|
|
omap_init_mbox();
|
|
omap_init_mcspi();
|
|
omap_init_mcspi();
|
|
omap_hdq_init();
|
|
omap_hdq_init();
|