Trivial fix in a typo (enalbed for enabled). Signed-off-by: Davidlohr Bueso <dave@gnu.org> Signed-off-by: Jiri Kosina <jkosina@suse.cz>
		
			
				
	
	
		
			164 lines
		
	
	
	
		
			3.8 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			164 lines
		
	
	
	
		
			3.8 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 * arch/arm/plat-spear/include/plat/padmux.c
 | 
						|
 *
 | 
						|
 * SPEAr platform specific gpio pads muxing source file
 | 
						|
 *
 | 
						|
 * Copyright (C) 2009 ST Microelectronics
 | 
						|
 * Viresh Kumar<viresh.kumar@st.com>
 | 
						|
 *
 | 
						|
 * This file is licensed under the terms of the GNU General Public
 | 
						|
 * License version 2. This program is licensed "as is" without any
 | 
						|
 * warranty of any kind, whether express or implied.
 | 
						|
 */
 | 
						|
 | 
						|
#include <linux/err.h>
 | 
						|
#include <linux/io.h>
 | 
						|
#include <linux/slab.h>
 | 
						|
#include <plat/padmux.h>
 | 
						|
 | 
						|
/*
 | 
						|
 * struct pmx: pmx definition structure
 | 
						|
 *
 | 
						|
 * base: base address of configuration registers
 | 
						|
 * mode_reg: mode configurations
 | 
						|
 * mux_reg: muxing configurations
 | 
						|
 * active_mode: pointer to current active mode
 | 
						|
 */
 | 
						|
struct pmx {
 | 
						|
	u32 base;
 | 
						|
	struct pmx_reg mode_reg;
 | 
						|
	struct pmx_reg mux_reg;
 | 
						|
	struct pmx_mode *active_mode;
 | 
						|
};
 | 
						|
 | 
						|
static struct pmx *pmx;
 | 
						|
 | 
						|
/**
 | 
						|
 * pmx_mode_set - Enables an multiplexing mode
 | 
						|
 * @mode - pointer to pmx mode
 | 
						|
 *
 | 
						|
 * It will set mode of operation in hardware.
 | 
						|
 * Returns -ve on Err otherwise 0
 | 
						|
 */
 | 
						|
static int pmx_mode_set(struct pmx_mode *mode)
 | 
						|
{
 | 
						|
	u32 val;
 | 
						|
 | 
						|
	if (!mode->name)
 | 
						|
		return -EFAULT;
 | 
						|
 | 
						|
	pmx->active_mode = mode;
 | 
						|
 | 
						|
	val = readl(pmx->base + pmx->mode_reg.offset);
 | 
						|
	val &= ~pmx->mode_reg.mask;
 | 
						|
	val |= mode->mask & pmx->mode_reg.mask;
 | 
						|
	writel(val, pmx->base + pmx->mode_reg.offset);
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * pmx_devs_enable - Enables list of devices
 | 
						|
 * @devs - pointer to pmx device array
 | 
						|
 * @count - number of devices to enable
 | 
						|
 *
 | 
						|
 * It will enable pads for all required peripherals once and only once.
 | 
						|
 * If peripheral is not supported by current mode then request is rejected.
 | 
						|
 * Conflicts between peripherals are not handled and peripherals will be
 | 
						|
 * enabled in the order they are present in pmx_dev array.
 | 
						|
 * In case of conflicts last peripheral enabled will be present.
 | 
						|
 * Returns -ve on Err otherwise 0
 | 
						|
 */
 | 
						|
static int pmx_devs_enable(struct pmx_dev **devs, u8 count)
 | 
						|
{
 | 
						|
	u32 val, i, mask;
 | 
						|
 | 
						|
	if (!count)
 | 
						|
		return -EINVAL;
 | 
						|
 | 
						|
	val = readl(pmx->base + pmx->mux_reg.offset);
 | 
						|
	for (i = 0; i < count; i++) {
 | 
						|
		u8 j = 0;
 | 
						|
 | 
						|
		if (!devs[i]->name || !devs[i]->modes) {
 | 
						|
			printk(KERN_ERR "padmux: dev name or modes is null\n");
 | 
						|
			continue;
 | 
						|
		}
 | 
						|
		/* check if peripheral exists in active mode */
 | 
						|
		if (pmx->active_mode) {
 | 
						|
			bool found = false;
 | 
						|
			for (j = 0; j < devs[i]->mode_count; j++) {
 | 
						|
				if (devs[i]->modes[j].ids &
 | 
						|
						pmx->active_mode->id) {
 | 
						|
					found = true;
 | 
						|
					break;
 | 
						|
				}
 | 
						|
			}
 | 
						|
			if (found == false) {
 | 
						|
				printk(KERN_ERR "%s device not available in %s"\
 | 
						|
						"mode\n", devs[i]->name,
 | 
						|
						pmx->active_mode->name);
 | 
						|
				continue;
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		/* enable peripheral */
 | 
						|
		mask = devs[i]->modes[j].mask & pmx->mux_reg.mask;
 | 
						|
		if (devs[i]->enb_on_reset)
 | 
						|
			val &= ~mask;
 | 
						|
		else
 | 
						|
			val |= mask;
 | 
						|
 | 
						|
		devs[i]->is_active = true;
 | 
						|
	}
 | 
						|
	writel(val, pmx->base + pmx->mux_reg.offset);
 | 
						|
	kfree(pmx);
 | 
						|
 | 
						|
	/* this will ensure that multiplexing can't be changed now */
 | 
						|
	pmx = (struct pmx *)-1;
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * pmx_register - registers a platform requesting pad mux feature
 | 
						|
 * @driver - pointer to driver structure containing driver specific parameters
 | 
						|
 *
 | 
						|
 * Also this must be called only once. This will allocate memory for pmx
 | 
						|
 * structure, will call pmx_mode_set, will call pmx_devs_enable.
 | 
						|
 * Returns -ve on Err otherwise 0
 | 
						|
 */
 | 
						|
int pmx_register(struct pmx_driver *driver)
 | 
						|
{
 | 
						|
	int ret = 0;
 | 
						|
 | 
						|
	if (pmx)
 | 
						|
		return -EPERM;
 | 
						|
	if (!driver->base || !driver->devs)
 | 
						|
		return -EFAULT;
 | 
						|
 | 
						|
	pmx = kzalloc(sizeof(*pmx), GFP_KERNEL);
 | 
						|
	if (!pmx)
 | 
						|
		return -ENOMEM;
 | 
						|
 | 
						|
	pmx->base = (u32)driver->base;
 | 
						|
	pmx->mode_reg.offset = driver->mode_reg.offset;
 | 
						|
	pmx->mode_reg.mask = driver->mode_reg.mask;
 | 
						|
	pmx->mux_reg.offset = driver->mux_reg.offset;
 | 
						|
	pmx->mux_reg.mask = driver->mux_reg.mask;
 | 
						|
 | 
						|
	/* choose mode to enable */
 | 
						|
	if (driver->mode) {
 | 
						|
		ret = pmx_mode_set(driver->mode);
 | 
						|
		if (ret)
 | 
						|
			goto pmx_fail;
 | 
						|
	}
 | 
						|
	ret = pmx_devs_enable(driver->devs, driver->devs_count);
 | 
						|
	if (ret)
 | 
						|
		goto pmx_fail;
 | 
						|
 | 
						|
	return 0;
 | 
						|
 | 
						|
pmx_fail:
 | 
						|
	return ret;
 | 
						|
}
 |