| /* |
| * (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; |
| } |