summaryrefslogtreecommitdiff
path: root/arch/arm/mach-mx21/gpio_mux.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-mx21/gpio_mux.c')
-rw-r--r--arch/arm/mach-mx21/gpio_mux.c302
1 files changed, 302 insertions, 0 deletions
diff --git a/arch/arm/mach-mx21/gpio_mux.c b/arch/arm/mach-mx21/gpio_mux.c
new file mode 100644
index 000000000000..bfb964fa53b8
--- /dev/null
+++ b/arch/arm/mach-mx21/gpio_mux.c
@@ -0,0 +1,302 @@
+/*
+ * Copyright 2007 Freescale Semiconductor, 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
+ */
+
+/*!
+ *@file gpio_mux.c
+ *@brief This file contains the IOMUX implementation details.
+ * @ingroup GPIO
+ */
+
+#include <linux/kernel.h>
+#include <linux/cache.h>
+#include <linux/spinlock.h>
+
+#include <asm/io.h>
+#include <asm/hardware.h>
+#include <asm/arch/gpio.h>
+#include "gpio_mux.h"
+
+/*!
+ * This structure defines the offset of registers in gpio module.
+ */
+enum gpio_reg {
+ GPIO_GIUS = 0x20,
+ GPIO_GPR = 0x38,
+ GPIO_PUEN = 0x40,
+ GPIO_DDIR = 0x00,
+ GPIO_OCR1 = 0x04,
+ GPIO_OCR2 = 0x08,
+ GPIO_ICONFA1 = 0x0C,
+ GPIO_ICONFA2 = 0x10,
+ GPIO_ICONFB1 = 0x14,
+ GPIO_ICONFB2 = 0x18,
+};
+
+/*!
+ * This enumeration data type defines the configuration for input mode.
+ */
+typedef enum {
+ GPIO_INPUT_GPIO = 0x00,
+ GPIO_INPUT_INTR = 0x01,
+ GPIO_INPUT_LOW = 0x02,
+ GPIO_INPUT_HIGH = 0x03
+} gpio_input_cfg_t;
+
+/*!
+ * This enumeration data type defines the configuration for output mode.
+ */
+typedef enum {
+ GPIO_OUTPUT_A = 0x00,
+ GPIO_OUTPUT_B = 0x01,
+ GPIO_OUTPUT_C = 0x02,
+ GPIO_OUTPUT_DR = 0x03
+} gpio_output_cfg_t;
+
+extern struct mxc_gpio_port mxc_gpio_ports[];
+
+/*!
+ * defines a spinlock to protected the accessing to gpio pin.
+ */
+DEFINE_SPINLOCK(gpio_mux_lock);
+
+/*!
+ * This function enable or disable the pullup feature to the pin.
+ * @param port a pointer of gpio port
+ * @param index the index of the pin in the port
+ * @param en 0 if disable pullup, otherwise enable it.
+ * @return none
+ */
+static inline void _gpio_set_puen(struct mxc_gpio_port *port, u32 index,
+ bool en)
+{
+ u32 reg;
+
+ reg = __raw_readl(port->base + GPIO_PUEN);
+ if (en) {
+ reg |= 1 << index;
+ } else {
+ reg &= ~(1 << index);
+ }
+ __raw_writel(reg, port->base + GPIO_PUEN);
+}
+
+/*!
+ * This function set the input configuration A.
+ * @param port a pointer of gpio port
+ * @param index the index of the pin in the port
+ * @param config a mode as define in \b #gpio_input_cfg_t
+ * @return none
+ */
+static inline void _gpio_set_iconfa(struct mxc_gpio_port *port, u32 index,
+ gpio_input_cfg_t config)
+{
+ u32 reg, val;
+ u32 mask;
+
+ mask = 0x3 << ((index % 16) << 1);
+
+ if (index >= 16) {
+ reg = port->base + GPIO_ICONFA2;
+ val = config << ((index - 16) * 2);
+ } else {
+ reg = port->base + GPIO_ICONFA1;
+ val = config << (index * 2);
+ }
+ val |= __raw_readl(reg) & ~(mask);
+ __raw_writel(val, reg);
+}
+
+/*!
+ * This function set the input configuration B.
+ * @param port a pointer of gpio port
+ * @param index the index of the pin in the port
+ * @param config a mode as define in \b #gpio_input_cfg_t
+ * @return none
+ */
+static inline void _gpio_set_iconfb(struct mxc_gpio_port *port, u32 index,
+ gpio_input_cfg_t config)
+{
+ u32 reg, val;
+ u32 mask;
+
+ mask = 0x3 << ((index % 16) << 1);
+
+ if (index >= 16) {
+ reg = port->base + GPIO_ICONFB2;
+ val = config << ((index - 16) * 2);
+ } else {
+ reg = port->base + GPIO_ICONFB1;
+ val = config << (index * 2);
+ }
+ val |= __raw_readl(reg) & (~mask);
+ __raw_writel(val, reg);
+}
+
+/*!
+ * This function set the output configuration.
+ * @param port a pointer of gpio port
+ * @param index the index of the pin in the port
+ * @param config a mode as define in \b #gpio_output_cfg_t
+ * @return none
+ */
+static inline void _gpio_set_ocr(struct mxc_gpio_port *port, u32 index,
+ gpio_output_cfg_t config)
+{
+ u32 reg, val;
+ u32 mask;
+
+ mask = 0x3 << ((index % 16) << 1);
+ if (index >= 16) {
+ reg = port->base + GPIO_OCR2;
+ val = config << ((index - 16) * 2);
+ } else {
+ reg = port->base + GPIO_OCR1;
+ val = config << (index * 2);
+ }
+ val |= __raw_readl(reg) & (~mask);
+ __raw_writel(val, reg);
+}
+
+/*!
+ *@brief gpio_config_mux - just configure the mode of the gpio pin.
+ *@param pin a pin number as defined in \b #iomux_pin_name_t
+ *@param mode a module as define in \b #gpio_mux_mode_t;
+ * GPIO_MUX_PRIMARY set pin to work as primary function.
+ * GPIO_MUX_ALT set pin to work as alternate function.
+ * GPIO_MUX_GPIO set pin to work as output function based the data register
+ * GPIO_MUX_INPUT1 set pin to work as input function connected with A_OUT
+ * GPIO_MUX_INPUT2 set pin to work as input function connected with B_OUT
+ * GPIO_MUX_OUTPUT1 set pin to work as output function connected with A_IN
+ * GPIO_MUX_OUTPUT2 set pin to work as output function connected with B_IN
+ * GPIO_MUX_OUTPUT3 set pin to work as output function connected with C_IN
+ *@return 0 if successful, Non-zero otherwise
+ */
+
+int gpio_config_mux(iomux_pin_name_t pin, gpio_mux_mode_t mode)
+{
+ unsigned long lock_flags;
+ u32 gius_reg, gpr_reg;
+ struct mxc_gpio_port *port;
+ u32 index, gpio = IOMUX_TO_GPIO(pin);
+
+ port = &(mxc_gpio_ports[GPIO_TO_PORT(gpio)]);
+ index = GPIO_TO_INDEX(gpio);
+
+ pr_debug("%s: Configuring PORT %c, bit %d\n",
+ __FUNCTION__, port->num + 'A', index);
+
+ spin_lock_irqsave(&gpio_mux_lock, lock_flags);
+
+ gius_reg = __raw_readl(port->base + GPIO_GIUS);
+ gpr_reg = __raw_readl(port->base + GPIO_GPR);
+
+ switch (mode) {
+ case GPIO_MUX_PRIMARY:
+ gius_reg &= ~(1L << index);
+ gpr_reg &= ~(1L << index);
+ break;
+ case GPIO_MUX_ALT:
+ gius_reg &= ~(1L << index);
+ gpr_reg |= (1L << index);
+ break;
+ case GPIO_MUX_GPIO:
+ gius_reg |= (1L << index);
+ _gpio_set_ocr(port, index, GPIO_OUTPUT_DR);
+ break;
+ case GPIO_MUX_INPUT1:
+ gius_reg |= (1L << index);
+ _gpio_set_iconfa(port, index, GPIO_INPUT_GPIO);
+ break;
+ case GPIO_MUX_INPUT2:
+ gius_reg |= (1L << index);
+ _gpio_set_iconfb(port, index, GPIO_INPUT_GPIO);
+ break;
+ case GPIO_MUX_OUTPUT1:
+ gius_reg |= (1L << index);
+ _gpio_set_ocr(port, index, GPIO_OUTPUT_A);
+ break;
+ case GPIO_MUX_OUTPUT2:
+ gius_reg |= (1L << index);
+ _gpio_set_ocr(port, index, GPIO_OUTPUT_B);
+ break;
+ case GPIO_MUX_OUTPUT3:
+ gius_reg |= (1L << index);
+ _gpio_set_ocr(port, index, GPIO_OUTPUT_C);
+ break;
+ default:
+ spin_unlock_irqrestore(&gpio_mux_lock, lock_flags);
+ return -1;
+ }
+
+ __raw_writel(gius_reg, port->base + GPIO_GIUS);
+ __raw_writel(gpr_reg, port->base + GPIO_GPR);
+
+ spin_unlock_irqrestore(&gpio_mux_lock, lock_flags);
+ return 0;
+}
+
+/*!
+ * This function is just used to enable or disable the pull up feature .
+ * @param pin a pin number as defined in \b #iomux_pin_name_t
+ * @param en 0 if disable, Non-zero enable
+ * @return 0 if successful, Non-zero otherwise
+ */
+int gpio_set_puen(iomux_pin_name_t pin, bool en)
+{
+ unsigned long lock_flags;
+
+ struct mxc_gpio_port *port;
+ u32 index, gpio = IOMUX_TO_GPIO(pin);
+
+ port = &(mxc_gpio_ports[GPIO_TO_PORT(gpio)]);
+ index = GPIO_TO_INDEX(gpio);
+
+ pr_debug("%s: Configuring output mode of PORT %c, bit %d\n",
+ __FUNCTION__, port->num + 'A', index);
+
+ spin_lock_irqsave(&gpio_mux_lock, lock_flags);
+
+ _gpio_set_puen(port, index, en);
+ spin_unlock_irqrestore(&gpio_mux_lock, lock_flags);
+ return 0;
+
+}
+
+/*!
+ * This function is just used to request a pin and configure it.
+ * @param pin a pin number as defined in \b #iomux_pin_name_t
+ * @param mode a module as define in \b #gpio_mux_mode_t;
+ * @return 0 if successful, Non-zero otherwise
+ */
+int gpio_request_mux(iomux_pin_name_t pin, gpio_mux_mode_t mode)
+{
+ int ret;
+ ret = mxc_request_gpio(pin);
+ if (ret == 0) {
+ ret = gpio_config_mux(pin, mode);
+ if (ret) {
+ mxc_free_gpio(pin);
+ }
+ }
+ return ret;
+}
+
+/*!
+ * This function is just used to release a pin.
+ * @param pin a pin number as defined in \b #iomux_pin_name_t
+ * @return none
+ */
+void gpio_free_mux(iomux_pin_name_t pin)
+{
+ mxc_free_gpio(pin);
+}