1/* 2 * arch/arm/plat-mxc/iomux-v1.c 3 * 4 * Copyright (C) 2004 Sascha Hauer, Synertronixx GmbH 5 * Copyright (C) 2009 Uwe Kleine-Koenig, Pengutronix 6 * 7 * Common code for i.MX1, i.MX21 and i.MX27 8 * 9 * This program is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License as published by 11 * the Free Software Foundation; either version 2 of the License, or 12 * (at your option) any later version. 13 * 14 * This program is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 * GNU General Public License for more details. 18 * 19 * You should have received a copy of the GNU General Public License 20 * along with this program; if not, write to the Free Software Foundation, Inc., 21 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. 22 */ 23 24#include <linux/errno.h> 25#include <linux/init.h> 26#include <linux/kernel.h> 27#include <linux/module.h> 28#include <linux/string.h> 29#include <linux/gpio.h> 30 31#include <mach/hardware.h> 32#include <asm/mach/map.h> 33#include <mach/iomux-v1.h> 34 35static void __iomem *imx_iomuxv1_baseaddr; 36static unsigned imx_iomuxv1_numports; 37 38static inline unsigned long imx_iomuxv1_readl(unsigned offset) 39{ 40 return __raw_readl(imx_iomuxv1_baseaddr + offset); 41} 42 43static inline void imx_iomuxv1_writel(unsigned long val, unsigned offset) 44{ 45 __raw_writel(val, imx_iomuxv1_baseaddr + offset); 46} 47 48static inline void imx_iomuxv1_rmwl(unsigned offset, 49 unsigned long mask, unsigned long value) 50{ 51 unsigned long reg = imx_iomuxv1_readl(offset); 52 53 reg &= ~mask; 54 reg |= value; 55 56 imx_iomuxv1_writel(reg, offset); 57} 58 59static inline void imx_iomuxv1_set_puen( 60 unsigned int port, unsigned int pin, int on) 61{ 62 unsigned long mask = 1 << pin; 63 64 imx_iomuxv1_rmwl(MXC_PUEN(port), mask, on ? mask : 0); 65} 66 67static inline void imx_iomuxv1_set_ddir( 68 unsigned int port, unsigned int pin, int out) 69{ 70 unsigned long mask = 1 << pin; 71 72 imx_iomuxv1_rmwl(MXC_DDIR(port), mask, out ? mask : 0); 73} 74 75static inline void imx_iomuxv1_set_gpr( 76 unsigned int port, unsigned int pin, int af) 77{ 78 unsigned long mask = 1 << pin; 79 80 imx_iomuxv1_rmwl(MXC_GPR(port), mask, af ? mask : 0); 81} 82 83static inline void imx_iomuxv1_set_gius( 84 unsigned int port, unsigned int pin, int inuse) 85{ 86 unsigned long mask = 1 << pin; 87 88 imx_iomuxv1_rmwl(MXC_GIUS(port), mask, inuse ? mask : 0); 89} 90 91static inline void imx_iomuxv1_set_ocr( 92 unsigned int port, unsigned int pin, unsigned int ocr) 93{ 94 unsigned long shift = (pin & 0xf) << 1; 95 unsigned long mask = 3 << shift; 96 unsigned long value = ocr << shift; 97 unsigned long offset = pin < 16 ? MXC_OCR1(port) : MXC_OCR2(port); 98 99 imx_iomuxv1_rmwl(offset, mask, value); 100} 101 102static inline void imx_iomuxv1_set_iconfa( 103 unsigned int port, unsigned int pin, unsigned int aout) 104{ 105 unsigned long shift = (pin & 0xf) << 1; 106 unsigned long mask = 3 << shift; 107 unsigned long value = aout << shift; 108 unsigned long offset = pin < 16 ? MXC_ICONFA1(port) : MXC_ICONFA2(port); 109 110 imx_iomuxv1_rmwl(offset, mask, value); 111} 112 113static inline void imx_iomuxv1_set_iconfb( 114 unsigned int port, unsigned int pin, unsigned int bout) 115{ 116 unsigned long shift = (pin & 0xf) << 1; 117 unsigned long mask = 3 << shift; 118 unsigned long value = bout << shift; 119 unsigned long offset = pin < 16 ? MXC_ICONFB1(port) : MXC_ICONFB2(port); 120 121 imx_iomuxv1_rmwl(offset, mask, value); 122} 123 124int mxc_gpio_mode(int gpio_mode) 125{ 126 unsigned int pin = gpio_mode & GPIO_PIN_MASK; 127 unsigned int port = (gpio_mode & GPIO_PORT_MASK) >> GPIO_PORT_SHIFT; 128 unsigned int ocr = (gpio_mode & GPIO_OCR_MASK) >> GPIO_OCR_SHIFT; 129 unsigned int aout = (gpio_mode >> GPIO_AOUT_SHIFT) & 3; 130 unsigned int bout = (gpio_mode >> GPIO_BOUT_SHIFT) & 3; 131 132 if (port >= imx_iomuxv1_numports) 133 return -EINVAL; 134 135 /* Pullup enable */ 136 imx_iomuxv1_set_puen(port, pin, gpio_mode & GPIO_PUEN); 137 138 /* Data direction */ 139 imx_iomuxv1_set_ddir(port, pin, gpio_mode & GPIO_OUT); 140 141 /* Primary / alternate function */ 142 imx_iomuxv1_set_gpr(port, pin, gpio_mode & GPIO_AF); 143 144 /* use as gpio? */ 145 imx_iomuxv1_set_gius(port, pin, !(gpio_mode & (GPIO_PF | GPIO_AF))); 146 147 imx_iomuxv1_set_ocr(port, pin, ocr); 148 149 imx_iomuxv1_set_iconfa(port, pin, aout); 150 151 imx_iomuxv1_set_iconfb(port, pin, bout); 152 153 return 0; 154} 155EXPORT_SYMBOL(mxc_gpio_mode); 156 157static int imx_iomuxv1_setup_multiple(const int *list, unsigned count) 158{ 159 size_t i; 160 int ret; 161 162 for (i = 0; i < count; ++i) { 163 ret = mxc_gpio_mode(list[i]); 164 165 if (ret) 166 return ret; 167 } 168 169 return ret; 170} 171 172int mxc_gpio_setup_multiple_pins(const int *pin_list, unsigned count, 173 const char *label) 174{ 175 size_t i; 176 int ret; 177 178 for (i = 0; i < count; ++i) { 179 unsigned gpio = pin_list[i] & (GPIO_PIN_MASK | GPIO_PORT_MASK); 180 181 ret = gpio_request(gpio, label); 182 if (ret) 183 goto err_gpio_request; 184 } 185 186 ret = imx_iomuxv1_setup_multiple(pin_list, count); 187 if (ret) 188 goto err_setup; 189 190 return 0; 191 192err_setup: 193 BUG_ON(i != count); 194 195err_gpio_request: 196 mxc_gpio_release_multiple_pins(pin_list, i); 197 198 return ret; 199} 200EXPORT_SYMBOL(mxc_gpio_setup_multiple_pins); 201 202void mxc_gpio_release_multiple_pins(const int *pin_list, int count) 203{ 204 size_t i; 205 206 for (i = 0; i < count; ++i) { 207 unsigned gpio = pin_list[i] & (GPIO_PIN_MASK | GPIO_PORT_MASK); 208 209 gpio_free(gpio); 210 } 211} 212EXPORT_SYMBOL(mxc_gpio_release_multiple_pins); 213 214static int imx_iomuxv1_init(void) 215{ 216#ifdef CONFIG_ARCH_MX1 217 if (cpu_is_mx1()) { 218 imx_iomuxv1_baseaddr = MX1_IO_ADDRESS(MX1_GPIO_BASE_ADDR); 219 imx_iomuxv1_numports = MX1_NUM_GPIO_PORT; 220 } else 221#endif 222#ifdef CONFIG_MACH_MX21 223 if (cpu_is_mx21()) { 224 imx_iomuxv1_baseaddr = MX21_IO_ADDRESS(MX21_GPIO_BASE_ADDR); 225 imx_iomuxv1_numports = MX21_NUM_GPIO_PORT; 226 } else 227#endif 228#ifdef CONFIG_MACH_MX27 229 if (cpu_is_mx27()) { 230 imx_iomuxv1_baseaddr = MX27_IO_ADDRESS(MX27_GPIO_BASE_ADDR); 231 imx_iomuxv1_numports = MX27_NUM_GPIO_PORT; 232 } else 233#endif 234 return -ENODEV; 235 236 return 0; 237} 238pure_initcall(imx_iomuxv1_init); 239