summaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-mxs/iomux-imx.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-mxs/iomux-imx.c')
-rw-r--r--arch/arm/mach-mxs/iomux-imx.c201
1 files changed, 201 insertions, 0 deletions
diff --git a/arch/arm/mach-mxs/iomux-imx.c b/arch/arm/mach-mxs/iomux-imx.c
new file mode 100644
index 0000000000..bf6165f8d2
--- /dev/null
+++ b/arch/arm/mach-mxs/iomux-imx.c
@@ -0,0 +1,201 @@
+/*
+ * (C) Copyright 2010 Juergen Beisert - Pengutronix
+ *
+ * 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <init.h>
+#include <gpio.h>
+#include <errno.h>
+#include <asm/io.h>
+#include <mach/imx-regs.h>
+
+#define HW_PINCTRL_CTRL 0x000
+#define HW_PINCTRL_MUXSEL0 0x100
+
+#ifdef CONFIG_ARCH_IMX23
+#define HW_PINCTRL_DRIVE0 0x200
+#define HW_PINCTRL_PULL0 0x400
+#define HW_PINCTRL_DOUT0 0x500
+#define HW_PINCTRL_DIN0 0x600
+#define HW_PINCTRL_DOE0 0x700
+
+#define MAX_GPIO_NO 95
+#endif
+
+#ifdef CONFIG_ARCH_IMX28
+#define HW_PINCTRL_DRIVE0 0x300
+#define HW_PINCTRL_PULL0 0x600
+#define HW_PINCTRL_DOUT0 0x700
+#define HW_PINCTRL_DIN0 0x900
+#define HW_PINCTRL_DOE0 0xb00
+
+#define MAX_GPIO_NO 159
+#endif
+
+static unsigned calc_mux_reg(unsigned no)
+{
+ /* each register controls 16 pads */
+ return ((no >> 4) << 4) + HW_PINCTRL_MUXSEL0;
+}
+
+static unsigned calc_strength_reg(unsigned no)
+{
+ /* each register controls 8 pads */
+ return ((no >> 3) << 4) + HW_PINCTRL_DRIVE0;
+}
+
+static unsigned calc_pullup_reg(unsigned no)
+{
+ /* each register controls 32 pads */
+ return ((no >> 5) << 4) + HW_PINCTRL_PULL0;
+}
+
+static unsigned calc_output_enable_reg(unsigned no)
+{
+ /* each register controls 32 pads */
+ return ((no >> 5) << 4) + HW_PINCTRL_DOE0;
+}
+
+static unsigned calc_output_reg(unsigned no)
+{
+ /* each register controls 32 pads */
+ return ((no >> 5) << 4) + HW_PINCTRL_DOUT0;
+}
+
+static unsigned calc_input_reg(unsigned no)
+{
+ /* each register controls 32 pads */
+ return ((no >> 5) << 4) + HW_PINCTRL_DIN0;
+}
+
+/**
+ * @param[in] m One pin define per call from iomux-mx23.h/iomux-mx28.h
+ */
+void imx_gpio_mode(uint32_t m)
+{
+ uint32_t reg;
+ unsigned gpio_pin, reg_offset;
+
+ gpio_pin = GET_GPIO_NO(m);
+
+ /* configure the pad to its function (always) */
+ reg_offset = calc_mux_reg(gpio_pin);
+ reg = readl(IMX_IOMUXC_BASE + reg_offset) & ~(0x3 << ((gpio_pin % 16) << 1));
+ reg |= GET_FUNC(m) << ((gpio_pin % 16) << 1);
+ writel(reg, IMX_IOMUXC_BASE + reg_offset);
+
+ /* some pins are disabled when configured for GPIO */
+ if ((gpio_pin > MAX_GPIO_NO) && (GET_FUNC(m) == IS_GPIO)) {
+ printf("Cannot configure pad %d to GPIO\n", gpio_pin);
+ return;
+ }
+
+ if (SE_PRESENT(m)) {
+ reg_offset = calc_strength_reg(gpio_pin);
+ reg = readl(IMX_IOMUXC_BASE + reg_offset) & ~(0x3 << ((gpio_pin % 8) << 2));
+ reg |= GET_STRENGTH(m) << ((gpio_pin % 8) << 2);
+ writel(reg, IMX_IOMUXC_BASE + reg_offset);
+ }
+
+ if (VE_PRESENT(m)) {
+ reg_offset = calc_strength_reg(gpio_pin);
+ if (GET_VOLTAGE(m) == 1)
+ writel(0x1 << (((gpio_pin % 8) << 2) + 2),
+ IMX_IOMUXC_BASE + reg_offset + BIT_SET);
+ else
+ writel(0x1 << (((gpio_pin % 8) << 2) + 2),
+ IMX_IOMUXC_BASE + reg_offset + BIT_CLR);
+ }
+
+ if (PE_PRESENT(m)) {
+ reg_offset = calc_pullup_reg(gpio_pin);
+ writel(0x1 << (gpio_pin % 32), IMX_IOMUXC_BASE + reg_offset +
+ (GET_PULLUP(m) == 1 ? BIT_SET : BIT_CLR));
+ }
+
+ if (GET_FUNC(m) == IS_GPIO) {
+ if (GET_GPIODIR(m) == 1) {
+ /* first set the output value */
+ reg_offset = calc_output_reg(gpio_pin);
+ writel(0x1 << (gpio_pin % 32), IMX_IOMUXC_BASE +
+ reg_offset + (GET_GPIOVAL(m) == 1 ? BIT_SET : BIT_CLR));
+ /* then the direction */
+ reg_offset = calc_output_enable_reg(gpio_pin);
+ writel(0x1 << (gpio_pin % 32),
+ IMX_IOMUXC_BASE + reg_offset + BIT_SET);
+ } else {
+ /* then the direction */
+ reg_offset = calc_output_enable_reg(gpio_pin);
+ writel(0x1 << (gpio_pin % 32),
+ IMX_IOMUXC_BASE + reg_offset + BIT_CLR);
+ }
+ }
+}
+
+int gpio_direction_input(unsigned gpio)
+{
+ unsigned reg_offset;
+
+ if (gpio > MAX_GPIO_NO)
+ return -EINVAL;
+
+ reg_offset = calc_output_enable_reg(gpio);
+ writel(0x1 << (gpio % 32), IMX_IOMUXC_BASE + reg_offset + BIT_CLR);
+
+ return 0;
+}
+
+int gpio_direction_output(unsigned gpio, int val)
+{
+ unsigned reg_offset;
+
+ if (gpio > MAX_GPIO_NO)
+ return -EINVAL;
+
+ /* first set the output value... */
+ reg_offset = calc_output_reg(gpio);
+ writel(0x1 << (gpio % 32), IMX_IOMUXC_BASE +
+ reg_offset + (val != 0 ? BIT_SET : BIT_CLR));
+ /* ...then the direction */
+ reg_offset = calc_output_enable_reg(gpio);
+ writel(0x1 << (gpio % 32), IMX_IOMUXC_BASE + reg_offset + BIT_SET);
+
+ return 0;
+}
+
+void gpio_set_value(unsigned gpio, int val)
+{
+ unsigned reg_offset;
+
+ reg_offset = calc_output_reg(gpio);
+ writel(0x1 << (gpio % 32), IMX_IOMUXC_BASE +
+ reg_offset + (val != 0 ? BIT_SET : BIT_CLR));
+}
+
+int gpio_get_value(unsigned gpio)
+{
+ uint32_t reg;
+ unsigned reg_offset;
+
+ reg_offset = calc_input_reg(gpio);
+ reg = readl(IMX_IOMUXC_BASE + reg_offset);
+ if (reg & (0x1 << (gpio % 32)))
+ return 1;
+
+ return 0;
+}