summaryrefslogtreecommitdiff
path: root/arch/arm/plat-stmp3xxx/mmc.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/plat-stmp3xxx/mmc.c')
-rw-r--r--arch/arm/plat-stmp3xxx/mmc.c148
1 files changed, 148 insertions, 0 deletions
diff --git a/arch/arm/plat-stmp3xxx/mmc.c b/arch/arm/plat-stmp3xxx/mmc.c
new file mode 100644
index 000000000000..75dc3a9f282a
--- /dev/null
+++ b/arch/arm/plat-stmp3xxx/mmc.c
@@ -0,0 +1,148 @@
+/*
+ * Freescale STMP37XX/STMP378X MMC pin multiplexing
+ *
+ * Embedded Alley Solutions, Inc <source@embeddedalley.com>
+ *
+ * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/clk.h>
+#include <linux/gpio.h>
+#include <mach/pinmux.h>
+#include <mach/stmp3xxx.h>
+#include <mach/platform.h>
+#include <mach/mmc.h>
+#include <mach/regs-ssp.h>
+
+#if defined(CONFIG_MACH_STMP378X)
+#define MMC_POWER PINID_PWM3
+#define MMC_WP PINID_PWM4
+#elif defined(CONFIG_MACH_STMP37XX)
+#define MMC_POWER PINID_PWM3
+#define MMC_WP PINID_PWM4
+#else
+#define MMC_POWER PINID_NO_PIN
+#define MMC_WP PINID_NO_PIN
+#endif
+
+static int mmc_drive_power;
+static int mmc_wp_supported;
+
+static struct pin_desc mmc_pins_desc[] = {
+ { PINID_SSP1_DATA0, PIN_FUN1, PIN_8MA, PIN_3_3V, 1 },
+ { PINID_SSP1_DATA1, PIN_FUN1, PIN_8MA, PIN_3_3V, 1 },
+ { PINID_SSP1_DATA2, PIN_FUN1, PIN_8MA, PIN_3_3V, 1 },
+ { PINID_SSP1_DATA3, PIN_FUN1, PIN_8MA, PIN_3_3V, 1 },
+ { PINID_SSP1_CMD, PIN_FUN1, PIN_8MA, PIN_3_3V, 1 },
+ { PINID_SSP1_SCK, PIN_FUN1, PIN_8MA, PIN_3_3V, 0 },
+ { PINID_SSP1_DETECT, PIN_FUN1, PIN_8MA, PIN_3_3V, 0 },
+};
+
+static struct pin_group mmc_pins = {
+ .pins = mmc_pins_desc,
+ .nr_pins = ARRAY_SIZE(mmc_pins_desc),
+};
+
+int stmp3xxxmmc_get_wp(void)
+{
+ if (mmc_wp_supported)
+ return gpio_get_value(MMC_WP);
+
+ return 0;
+}
+
+int stmp3xxxmmc_hw_init_ssp1(void)
+{
+ int ret;
+
+ mmc_drive_power = stmp3xxx_valid_pin(MMC_POWER);
+ mmc_wp_supported = stmp3xxx_valid_pin(MMC_WP);
+
+ ret = stmp3xxx_request_pin_group(&mmc_pins, "mmc");
+ if (ret)
+ goto out;
+
+ if (mmc_wp_supported) {
+ /* Configure write protect GPIO pin */
+ ret = gpio_request(MMC_WP, "mmc wp");
+ if (ret)
+ goto out_wp;
+
+ gpio_set_value(MMC_WP, 0);
+ gpio_direction_input(MMC_WP);
+ }
+
+ if (mmc_drive_power) {
+ /* Configure POWER pin as gpio to drive power to MMC slot */
+ ret = gpio_request(MMC_POWER, "mmc power");
+ if (ret)
+ goto out_power;
+
+ gpio_direction_output(MMC_POWER, 0);
+ mdelay(100);
+ }
+
+ return 0;
+
+out_power:
+ if (mmc_wp_supported)
+ gpio_free(MMC_WP);
+out_wp:
+ stmp3xxx_release_pin_group(&mmc_pins, "mmc");
+out:
+ return ret;
+}
+
+void stmp3xxxmmc_hw_release_ssp1(void)
+{
+ if (mmc_drive_power)
+ gpio_free(MMC_POWER);
+
+ if (mmc_wp_supported)
+ gpio_free(MMC_WP);
+
+ stmp3xxx_release_pin_group(&mmc_pins, "mmc");
+}
+
+void stmp3xxxmmc_cmd_pullup_ssp1(int enable)
+{
+ stmp3xxx_pin_pullup(PINID_SSP1_CMD, enable, "mmc");
+}
+
+unsigned long stmp3xxxmmc_setclock_ssp1(unsigned long hz)
+{
+ struct clk *ssp = clk_get(NULL, "ssp"), *parent;
+ char *p;
+ long r;
+
+ /* using SSP1, no timeout, clock rate 1 */
+ __raw_writel(BF(2, SSP_TIMING_CLOCK_DIVIDE) |
+ BF(0xFFFF, SSP_TIMING_TIMEOUT),
+ REGS_SSP1_BASE + HW_SSP_TIMING);
+
+ if (hz > 1000000)
+ p = "io";
+ else
+ p = "osc_24M";
+
+ parent = clk_get(NULL, p);
+ clk_set_parent(ssp, parent);
+ r = clk_set_rate(ssp, 2 * hz / 1000);
+ clk_put(parent);
+ clk_put(ssp);
+
+ return hz;
+}