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 <asm/mach/map.h> 32 33#include "hardware.h" 34#include "iomux-v1.h" 35 36static void __iomem *imx_iomuxv1_baseaddr; 37static unsigned imx_iomuxv1_numports; 38 39static inline unsigned long imx_iomuxv1_readl(unsigned offset) 40{ 41 return __raw_readl(imx_iomuxv1_baseaddr + offset); 42} 43 44static inline void imx_iomuxv1_writel(unsigned long val, unsigned offset) 45{ 46 __raw_writel(val, imx_iomuxv1_baseaddr + offset); 47} 48 49static inline void imx_iomuxv1_rmwl(unsigned offset, 50 unsigned long mask, unsigned long value) 51{ 52 unsigned long reg = imx_iomuxv1_readl(offset); 53 54 reg &= ~mask; 55 reg |= value; 56 57 imx_iomuxv1_writel(reg, offset); 58} 59 60static inline void imx_iomuxv1_set_puen( 61 unsigned int port, unsigned int pin, int on) 62{ 63 unsigned long mask = 1 << pin; 64 65 imx_iomuxv1_rmwl(MXC_PUEN(port), mask, on ? mask : 0); 66} 67 68static inline void imx_iomuxv1_set_ddir( 69 unsigned int port, unsigned int pin, int out) 70{ 71 unsigned long mask = 1 << pin; 72 73 imx_iomuxv1_rmwl(MXC_DDIR(port), mask, out ? mask : 0); 74} 75 76static inline void imx_iomuxv1_set_gpr( 77 unsigned int port, unsigned int pin, int af) 78{ 79 unsigned long mask = 1 << pin; 80 81 imx_iomuxv1_rmwl(MXC_GPR(port), mask, af ? mask : 0); 82} 83 84static inline void imx_iomuxv1_set_gius( 85 unsigned int port, unsigned int pin, int inuse) 86{ 87 unsigned long mask = 1 << pin; 88 89 imx_iomuxv1_rmwl(MXC_GIUS(port), mask, inuse ? mask : 0); 90} 91 92static inline void imx_iomuxv1_set_ocr( 93 unsigned int port, unsigned int pin, unsigned int ocr) 94{ 95 unsigned long shift = (pin & 0xf) << 1; 96 unsigned long mask = 3 << shift; 97 unsigned long value = ocr << shift; 98 unsigned long offset = pin < 16 ? MXC_OCR1(port) : MXC_OCR2(port); 99 100 imx_iomuxv1_rmwl(offset, mask, value); 101} 102 103static inline void imx_iomuxv1_set_iconfa( 104 unsigned int port, unsigned int pin, unsigned int aout) 105{ 106 unsigned long shift = (pin & 0xf) << 1; 107 unsigned long mask = 3 << shift; 108 unsigned long value = aout << shift; 109 unsigned long offset = pin < 16 ? MXC_ICONFA1(port) : MXC_ICONFA2(port); 110 111 imx_iomuxv1_rmwl(offset, mask, value); 112} 113 114static inline void imx_iomuxv1_set_iconfb( 115 unsigned int port, unsigned int pin, unsigned int bout) 116{ 117 unsigned long shift = (pin & 0xf) << 1; 118 unsigned long mask = 3 << shift; 119 unsigned long value = bout << shift; 120 unsigned long offset = pin < 16 ? MXC_ICONFB1(port) : MXC_ICONFB2(port); 121 122 imx_iomuxv1_rmwl(offset, mask, value); 123} 124 125int mxc_gpio_mode(int gpio_mode) 126{ 127 unsigned int pin = gpio_mode & GPIO_PIN_MASK; 128 unsigned int port = (gpio_mode & GPIO_PORT_MASK) >> GPIO_PORT_SHIFT; 129 unsigned int ocr = (gpio_mode & GPIO_OCR_MASK) >> GPIO_OCR_SHIFT; 130 unsigned int aout = (gpio_mode >> GPIO_AOUT_SHIFT) & 3; 131 unsigned int bout = (gpio_mode >> GPIO_BOUT_SHIFT) & 3; 132 133 if (port >= imx_iomuxv1_numports) 134 return -EINVAL; 135 136 /* Pullup enable */ 137 imx_iomuxv1_set_puen(port, pin, gpio_mode & GPIO_PUEN); 138 139 /* Data direction */ 140 imx_iomuxv1_set_ddir(port, pin, gpio_mode & GPIO_OUT); 141 142 /* Primary / alternate function */ 143 imx_iomuxv1_set_gpr(port, pin, gpio_mode & GPIO_AF); 144 145 /* use as gpio? */ 146 imx_iomuxv1_set_gius(port, pin, !(gpio_mode & (GPIO_PF | GPIO_AF))); 147 148 imx_iomuxv1_set_ocr(port, pin, ocr); 149 150 imx_iomuxv1_set_iconfa(port, pin, aout); 151 152 imx_iomuxv1_set_iconfb(port, pin, bout); 153 154 return 0; 155} 156 157static int imx_iomuxv1_setup_multiple(const int *list, unsigned count) 158{ 159 size_t i; 160 int ret = 0; 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 int ret; 176 177 ret = imx_iomuxv1_setup_multiple(pin_list, count); 178 return ret; 179} 180 181int __init imx_iomuxv1_init(void __iomem *base, int numports) 182{ 183 imx_iomuxv1_baseaddr = base; 184 imx_iomuxv1_numports = numports; 185 186 return 0; 187} 188