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#include <linux/gpio.h> 21#include <linux/module.h> 22#include <linux/spinlock.h> 23#include <linux/io.h> 24#include <linux/kernel.h> 25 26#include "hardware.h" 27#include "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 43static unsigned long mxc_pin_alloc_map[NB_PORTS * 32 / BITS_PER_LONG]; 44/* 45 * set the mode for a IOMUX pin. 46 */ 47void mxc_iomux_mode(unsigned int pin_mode) 48{ 49 u32 field; 50 u32 l; 51 u32 mode; 52 void __iomem *reg; 53 54 reg = IOMUXSW_MUX_CTL + (pin_mode & IOMUX_REG_MASK); 55 field = pin_mode & 0x3; 56 mode = (pin_mode & IOMUX_MODE_MASK) >> IOMUX_MODE_SHIFT; 57 58 spin_lock(&gpio_mux_lock); 59 60 l = __raw_readl(reg); 61 l &= ~(0xff << (field * 8)); 62 l |= mode << (field * 8); 63 __raw_writel(l, reg); 64 65 spin_unlock(&gpio_mux_lock); 66} 67 68/* 69 * This function configures the pad value for a IOMUX pin. 70 */ 71void mxc_iomux_set_pad(enum iomux_pins pin, u32 config) 72{ 73 u32 field, l; 74 void __iomem *reg; 75 76 pin &= IOMUX_PADNUM_MASK; 77 reg = IOMUXSW_PAD_CTL + (pin + 2) / 3 * 4; 78 field = (pin + 2) % 3; 79 80 pr_debug("%s: reg offset = 0x%x, field = %d\n", 81 __func__, (pin + 2) / 3, field); 82 83 spin_lock(&gpio_mux_lock); 84 85 l = __raw_readl(reg); 86 l &= ~(0x1ff << (field * 10)); 87 l |= config << (field * 10); 88 __raw_writel(l, reg); 89 90 spin_unlock(&gpio_mux_lock); 91} 92 93/* 94 * allocs a single pin: 95 * - reserves the pin so that it is not claimed by another driver 96 * - setups the iomux according to the configuration 97 */ 98int mxc_iomux_alloc_pin(unsigned int pin, const char *label) 99{ 100 unsigned pad = pin & IOMUX_PADNUM_MASK; 101 102 if (pad >= (PIN_MAX + 1)) { 103 printk(KERN_ERR "mxc_iomux: Attempt to request nonexistant pin %u for \"%s\"\n", 104 pad, label ? label : "?"); 105 return -EINVAL; 106 } 107 108 if (test_and_set_bit(pad, mxc_pin_alloc_map)) { 109 printk(KERN_ERR "mxc_iomux: pin %u already used. Allocation for \"%s\" failed\n", 110 pad, label ? label : "?"); 111 return -EBUSY; 112 } 113 mxc_iomux_mode(pin); 114 115 return 0; 116} 117 118int mxc_iomux_setup_multiple_pins(const unsigned int *pin_list, unsigned count, 119 const char *label) 120{ 121 const unsigned int *p = pin_list; 122 int i; 123 int ret = -EINVAL; 124 125 for (i = 0; i < count; i++) { 126 ret = mxc_iomux_alloc_pin(*p, label); 127 if (ret) 128 goto setup_error; 129 p++; 130 } 131 return 0; 132 133setup_error: 134 mxc_iomux_release_multiple_pins(pin_list, i); 135 return ret; 136} 137 138void mxc_iomux_release_pin(unsigned int pin) 139{ 140 unsigned pad = pin & IOMUX_PADNUM_MASK; 141 142 if (pad < (PIN_MAX + 1)) 143 clear_bit(pad, mxc_pin_alloc_map); 144} 145 146void mxc_iomux_release_multiple_pins(const unsigned int *pin_list, int count) 147{ 148 const unsigned int *p = pin_list; 149 int i; 150 151 for (i = 0; i < count; i++) { 152 mxc_iomux_release_pin(*p); 153 p++; 154 } 155} 156 157/* 158 * This function enables/disables the general purpose function for a particular 159 * signal. 160 */ 161void mxc_iomux_set_gpr(enum iomux_gp_func gp, bool en) 162{ 163 u32 l; 164 165 spin_lock(&gpio_mux_lock); 166 l = __raw_readl(IOMUXGPR); 167 if (en) 168 l |= gp; 169 else 170 l &= ~gp; 171 172 __raw_writel(l, IOMUXGPR); 173 spin_unlock(&gpio_mux_lock); 174} 175