1/* 2 * arch/arm/plat-spear/include/plat/padmux.c 3 * 4 * SPEAr platform specific gpio pads muxing source file 5 * 6 * Copyright (C) 2009 ST Microelectronics 7 * Viresh Kumar<viresh.kumar@st.com> 8 * 9 * This file is licensed under the terms of the GNU General Public 10 * License version 2. This program is licensed "as is" without any 11 * warranty of any kind, whether express or implied. 12 */ 13 14#include <linux/err.h> 15#include <linux/io.h> 16#include <linux/slab.h> 17#include <plat/padmux.h> 18 19/* 20 * struct pmx: pmx definition structure 21 * 22 * base: base address of configuration registers 23 * mode_reg: mode configurations 24 * mux_reg: muxing configurations 25 * active_mode: pointer to current active mode 26 */ 27struct pmx { 28 u32 base; 29 struct pmx_reg mode_reg; 30 struct pmx_reg mux_reg; 31 struct pmx_mode *active_mode; 32}; 33 34static struct pmx *pmx; 35 36/** 37 * pmx_mode_set - Enables an multiplexing mode 38 * @mode - pointer to pmx mode 39 * 40 * It will set mode of operation in hardware. 41 * Returns -ve on Err otherwise 0 42 */ 43static int pmx_mode_set(struct pmx_mode *mode) 44{ 45 u32 val; 46 47 if (!mode->name) 48 return -EFAULT; 49 50 pmx->active_mode = mode; 51 52 val = readl(pmx->base + pmx->mode_reg.offset); 53 val &= ~pmx->mode_reg.mask; 54 val |= mode->mask & pmx->mode_reg.mask; 55 writel(val, pmx->base + pmx->mode_reg.offset); 56 57 return 0; 58} 59 60/** 61 * pmx_devs_enable - Enables list of devices 62 * @devs - pointer to pmx device array 63 * @count - number of devices to enable 64 * 65 * It will enable pads for all required peripherals once and only once. 66 * If peripheral is not supported by current mode then request is rejected. 67 * Conflicts between peripherals are not handled and peripherals will be 68 * enabled in the order they are present in pmx_dev array. 69 * In case of conflicts last peripheral enabled will be present. 70 * Returns -ve on Err otherwise 0 71 */ 72static int pmx_devs_enable(struct pmx_dev **devs, u8 count) 73{ 74 u32 val, i, mask; 75 76 if (!count) 77 return -EINVAL; 78 79 val = readl(pmx->base + pmx->mux_reg.offset); 80 for (i = 0; i < count; i++) { 81 u8 j = 0; 82 83 if (!devs[i]->name || !devs[i]->modes) { 84 printk(KERN_ERR "padmux: dev name or modes is null\n"); 85 continue; 86 } 87 /* check if peripheral exists in active mode */ 88 if (pmx->active_mode) { 89 bool found = false; 90 for (j = 0; j < devs[i]->mode_count; j++) { 91 if (devs[i]->modes[j].ids & 92 pmx->active_mode->id) { 93 found = true; 94 break; 95 } 96 } 97 if (found == false) { 98 printk(KERN_ERR "%s device not available in %s"\ 99 "mode\n", devs[i]->name, 100 pmx->active_mode->name); 101 continue; 102 } 103 } 104 105 /* enable peripheral */ 106 mask = devs[i]->modes[j].mask & pmx->mux_reg.mask; 107 if (devs[i]->enb_on_reset) 108 val &= ~mask; 109 else 110 val |= mask; 111 112 devs[i]->is_active = true; 113 } 114 writel(val, pmx->base + pmx->mux_reg.offset); 115 kfree(pmx); 116 117 /* this will ensure that multiplexing can't be changed now */ 118 pmx = (struct pmx *)-1; 119 120 return 0; 121} 122 123/** 124 * pmx_register - registers a platform requesting pad mux feature 125 * @driver - pointer to driver structure containing driver specific parameters 126 * 127 * Also this must be called only once. This will allocate memory for pmx 128 * structure, will call pmx_mode_set, will call pmx_devs_enable. 129 * Returns -ve on Err otherwise 0 130 */ 131int pmx_register(struct pmx_driver *driver) 132{ 133 int ret = 0; 134 135 if (pmx) 136 return -EPERM; 137 if (!driver->base || !driver->devs) 138 return -EFAULT; 139 140 pmx = kzalloc(sizeof(*pmx), GFP_KERNEL); 141 if (!pmx) 142 return -ENOMEM; 143 144 pmx->base = (u32)driver->base; 145 pmx->mode_reg.offset = driver->mode_reg.offset; 146 pmx->mode_reg.mask = driver->mode_reg.mask; 147 pmx->mux_reg.offset = driver->mux_reg.offset; 148 pmx->mux_reg.mask = driver->mux_reg.mask; 149 150 /* choose mode to enable */ 151 if (driver->mode) { 152 ret = pmx_mode_set(driver->mode); 153 if (ret) 154 goto pmx_fail; 155 } 156 ret = pmx_devs_enable(driver->devs, driver->devs_count); 157 if (ret) 158 goto pmx_fail; 159 160 return 0; 161 162pmx_fail: 163 return ret; 164} 165

