1/* 2 * Copyright 2004-2006 Freescale Semiconductor, Inc. All Rights Reserved. 3 * Copyright (C) 2008 by Sascha Hauer <kernel@pengutronix.de> 4 * Copyright (C) 2009 by Valentin Longchamp <valentin.longchamp@epfl.ch> 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public License 8 * as published by the Free Software Foundation; either version 2 9 * of the License, or (at your option) any later version. 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software 17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 18 * MA 02110-1301, USA. 19 */ 20 21#include <linux/module.h> 22#include <linux/spinlock.h> 23#include <linux/io.h> 24#include <linux/kernel.h> 25#include <mach/hardware.h> 26#include <mach/gpio.h> 27#include <mach/iomux-mx3.h> 28 29/* 30 * IOMUX register (base) addresses 31 */ 32#define IOMUX_BASE MX31_IO_ADDRESS(MX31_IOMUXC_BASE_ADDR) 33#define IOMUXINT_OBS1 (IOMUX_BASE + 0x000) 34#define IOMUXINT_OBS2 (IOMUX_BASE + 0x004) 35#define IOMUXGPR (IOMUX_BASE + 0x008) 36#define IOMUXSW_MUX_CTL (IOMUX_BASE + 0x00C) 37#define IOMUXSW_PAD_CTL (IOMUX_BASE + 0x154) 38 39static DEFINE_SPINLOCK(gpio_mux_lock); 40 41#define IOMUX_REG_MASK (IOMUX_PADNUM_MASK & ~0x3) 42 43unsigned long mxc_pin_alloc_map[NB_PORTS * 32 / BITS_PER_LONG]; 44/* 45 * set the mode for a IOMUX pin. 46 */ 47int mxc_iomux_mode(unsigned int pin_mode) 48{ 49 u32 field, l, mode, ret = 0; 50 void __iomem *reg; 51 52 reg = IOMUXSW_MUX_CTL + (pin_mode & IOMUX_REG_MASK); 53 field = pin_mode & 0x3; 54 mode = (pin_mode & IOMUX_MODE_MASK) >> IOMUX_MODE_SHIFT; 55 56 spin_lock(&gpio_mux_lock); 57 58 l = __raw_readl(reg); 59 l &= ~(0xff << (field * 8)); 60 l |= mode << (field * 8); 61 __raw_writel(l, reg); 62 63 spin_unlock(&gpio_mux_lock); 64 65 return ret; 66} 67EXPORT_SYMBOL(mxc_iomux_mode); 68 69/* 70 * This function configures the pad value for a IOMUX pin. 71 */ 72void mxc_iomux_set_pad(enum iomux_pins pin, u32 config) 73{ 74 u32 field, l; 75 void __iomem *reg; 76 77 pin &= IOMUX_PADNUM_MASK; 78 reg = IOMUXSW_PAD_CTL + (pin + 2) / 3 * 4; 79 field = (pin + 2) % 3; 80 81 pr_debug("%s: reg offset = 0x%x, field = %d\n", 82 __func__, (pin + 2) / 3, field); 83 84 spin_lock(&gpio_mux_lock); 85 86 l = __raw_readl(reg); 87 l &= ~(0x1ff << (field * 10)); 88 l |= config << (field * 10); 89 __raw_writel(l, reg); 90 91 spin_unlock(&gpio_mux_lock); 92} 93EXPORT_SYMBOL(mxc_iomux_set_pad); 94 95/* 96 * allocs a single pin: 97 * - reserves the pin so that it is not claimed by another driver 98 * - setups the iomux according to the configuration 99 */ 100int mxc_iomux_alloc_pin(const unsigned int pin, const char *label) 101{ 102 unsigned pad = pin & IOMUX_PADNUM_MASK; 103 104 if (pad >= (PIN_MAX + 1)) { 105 printk(KERN_ERR "mxc_iomux: Attempt to request nonexistant pin %u for \"%s\"\n", 106 pad, label ? label : "?"); 107 return -EINVAL; 108 } 109 110 if (test_and_set_bit(pad, mxc_pin_alloc_map)) { 111 printk(KERN_ERR "mxc_iomux: pin %u already used. Allocation for \"%s\" failed\n", 112 pad, label ? label : "?"); 113 return -EBUSY; 114 } 115 mxc_iomux_mode(pin); 116 117 return 0; 118} 119EXPORT_SYMBOL(mxc_iomux_alloc_pin); 120 121int mxc_iomux_setup_multiple_pins(unsigned int *pin_list, unsigned count, 122 const char *label) 123{ 124 unsigned int *p = pin_list; 125 int i; 126 int ret = -EINVAL; 127 128 for (i = 0; i < count; i++) { 129 ret = mxc_iomux_alloc_pin(*p, label); 130 if (ret) 131 goto setup_error; 132 p++; 133 } 134 return 0; 135 136setup_error: 137 mxc_iomux_release_multiple_pins(pin_list, i); 138 return ret; 139} 140EXPORT_SYMBOL(mxc_iomux_setup_multiple_pins); 141 142void mxc_iomux_release_pin(const unsigned int pin) 143{ 144 unsigned pad = pin & IOMUX_PADNUM_MASK; 145 146 if (pad < (PIN_MAX + 1)) 147 clear_bit(pad, mxc_pin_alloc_map); 148} 149EXPORT_SYMBOL(mxc_iomux_release_pin); 150 151void mxc_iomux_release_multiple_pins(unsigned int *pin_list, int count) 152{ 153 unsigned int *p = pin_list; 154 int i; 155 156 for (i = 0; i < count; i++) { 157 mxc_iomux_release_pin(*p); 158 p++; 159 } 160} 161EXPORT_SYMBOL(mxc_iomux_release_multiple_pins); 162 163/* 164 * This function enables/disables the general purpose function for a particular 165 * signal. 166 */ 167void mxc_iomux_set_gpr(enum iomux_gp_func gp, bool en) 168{ 169 u32 l; 170 171 spin_lock(&gpio_mux_lock); 172 l = __raw_readl(IOMUXGPR); 173 if (en) 174 l |= gp; 175 else 176 l &= ~gp; 177 178 __raw_writel(l, IOMUXGPR); 179 spin_unlock(&gpio_mux_lock); 180} 181EXPORT_SYMBOL(mxc_iomux_set_gpr); 182