Re-architect how we save/restore the gpio/port logic that only pertains to bf538/bf539 parts by pulling it out of the core code paths and pushing it out to bf538-specific locations. Signed-off-by: Mike Frysinger <vapier@gentoo.org>
		
			
				
	
	
		
			158 lines
		
	
	
	
		
			4.2 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			158 lines
		
	
	
	
		
			4.2 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 * GPIOLIB interface for BF538/9 PORT C, D, and E GPIOs
 | 
						|
 *
 | 
						|
 * Copyright 2009-2011 Analog Devices Inc.
 | 
						|
 *
 | 
						|
 * Licensed under the GPL-2 or later.
 | 
						|
 */
 | 
						|
 | 
						|
#include <linux/module.h>
 | 
						|
#include <linux/err.h>
 | 
						|
#include <asm/blackfin.h>
 | 
						|
#include <asm/gpio.h>
 | 
						|
#include <asm/portmux.h>
 | 
						|
 | 
						|
#define DEFINE_REG(reg, off) \
 | 
						|
static inline u16 read_##reg(void __iomem *port) \
 | 
						|
	{ return bfin_read16(port + off); } \
 | 
						|
static inline void write_##reg(void __iomem *port, u16 v) \
 | 
						|
	{ bfin_write16(port + off, v); }
 | 
						|
 | 
						|
DEFINE_REG(PORTIO, 0x00)
 | 
						|
DEFINE_REG(PORTIO_CLEAR, 0x10)
 | 
						|
DEFINE_REG(PORTIO_SET, 0x20)
 | 
						|
DEFINE_REG(PORTIO_DIR, 0x40)
 | 
						|
DEFINE_REG(PORTIO_INEN, 0x50)
 | 
						|
 | 
						|
static void __iomem *gpio_chip_to_mmr(struct gpio_chip *chip)
 | 
						|
{
 | 
						|
	switch (chip->base) {
 | 
						|
	default: /* not really needed, but keeps gcc happy */
 | 
						|
	case GPIO_PC0: return (void __iomem *)PORTCIO;
 | 
						|
	case GPIO_PD0: return (void __iomem *)PORTDIO;
 | 
						|
	case GPIO_PE0: return (void __iomem *)PORTEIO;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static int bf538_gpio_get_value(struct gpio_chip *chip, unsigned gpio)
 | 
						|
{
 | 
						|
	void __iomem *port = gpio_chip_to_mmr(chip);
 | 
						|
	return !!(read_PORTIO(port) & (1u << gpio));
 | 
						|
}
 | 
						|
 | 
						|
static void bf538_gpio_set_value(struct gpio_chip *chip, unsigned gpio, int value)
 | 
						|
{
 | 
						|
	void __iomem *port = gpio_chip_to_mmr(chip);
 | 
						|
	if (value)
 | 
						|
		write_PORTIO_SET(port, (1u << gpio));
 | 
						|
	else
 | 
						|
		write_PORTIO_CLEAR(port, (1u << gpio));
 | 
						|
}
 | 
						|
 | 
						|
static int bf538_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
 | 
						|
{
 | 
						|
	void __iomem *port = gpio_chip_to_mmr(chip);
 | 
						|
	write_PORTIO_DIR(port, read_PORTIO_DIR(port) & ~(1u << gpio));
 | 
						|
	write_PORTIO_INEN(port, read_PORTIO_INEN(port) | (1u << gpio));
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
static int bf538_gpio_direction_output(struct gpio_chip *chip, unsigned gpio, int value)
 | 
						|
{
 | 
						|
	void __iomem *port = gpio_chip_to_mmr(chip);
 | 
						|
	write_PORTIO_INEN(port, read_PORTIO_INEN(port) & ~(1u << gpio));
 | 
						|
	bf538_gpio_set_value(port, gpio, value);
 | 
						|
	write_PORTIO_DIR(port, read_PORTIO_DIR(port) | (1u << gpio));
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
static int bf538_gpio_request(struct gpio_chip *chip, unsigned gpio)
 | 
						|
{
 | 
						|
	return bfin_special_gpio_request(chip->base + gpio, chip->label);
 | 
						|
}
 | 
						|
 | 
						|
static void bf538_gpio_free(struct gpio_chip *chip, unsigned gpio)
 | 
						|
{
 | 
						|
	return bfin_special_gpio_free(chip->base + gpio);
 | 
						|
}
 | 
						|
 | 
						|
/* We don't set the irq fields as these banks cannot generate interrupts */
 | 
						|
 | 
						|
static struct gpio_chip bf538_portc_chip = {
 | 
						|
	.label = "GPIO-PC",
 | 
						|
	.direction_input = bf538_gpio_direction_input,
 | 
						|
	.get = bf538_gpio_get_value,
 | 
						|
	.direction_output = bf538_gpio_direction_output,
 | 
						|
	.set = bf538_gpio_set_value,
 | 
						|
	.request = bf538_gpio_request,
 | 
						|
	.free = bf538_gpio_free,
 | 
						|
	.base = GPIO_PC0,
 | 
						|
	.ngpio = GPIO_PC9 - GPIO_PC0 + 1,
 | 
						|
};
 | 
						|
 | 
						|
static struct gpio_chip bf538_portd_chip = {
 | 
						|
	.label = "GPIO-PD",
 | 
						|
	.direction_input = bf538_gpio_direction_input,
 | 
						|
	.get = bf538_gpio_get_value,
 | 
						|
	.direction_output = bf538_gpio_direction_output,
 | 
						|
	.set = bf538_gpio_set_value,
 | 
						|
	.request = bf538_gpio_request,
 | 
						|
	.free = bf538_gpio_free,
 | 
						|
	.base = GPIO_PD0,
 | 
						|
	.ngpio = GPIO_PD13 - GPIO_PD0 + 1,
 | 
						|
};
 | 
						|
 | 
						|
static struct gpio_chip bf538_porte_chip = {
 | 
						|
	.label = "GPIO-PE",
 | 
						|
	.direction_input = bf538_gpio_direction_input,
 | 
						|
	.get = bf538_gpio_get_value,
 | 
						|
	.direction_output = bf538_gpio_direction_output,
 | 
						|
	.set = bf538_gpio_set_value,
 | 
						|
	.request = bf538_gpio_request,
 | 
						|
	.free = bf538_gpio_free,
 | 
						|
	.base = GPIO_PE0,
 | 
						|
	.ngpio = GPIO_PE15 - GPIO_PE0 + 1,
 | 
						|
};
 | 
						|
 | 
						|
static int __init bf538_extgpio_setup(void)
 | 
						|
{
 | 
						|
	return gpiochip_add(&bf538_portc_chip) |
 | 
						|
		gpiochip_add(&bf538_portd_chip) |
 | 
						|
		gpiochip_add(&bf538_porte_chip);
 | 
						|
}
 | 
						|
arch_initcall(bf538_extgpio_setup);
 | 
						|
 | 
						|
#ifdef CONFIG_PM
 | 
						|
static struct {
 | 
						|
	u16 data, dir, inen;
 | 
						|
} gpio_bank_saved[3];
 | 
						|
 | 
						|
static void __iomem * const port_bases[3] = {
 | 
						|
	(void *)PORTCIO,
 | 
						|
	(void *)PORTDIO,
 | 
						|
	(void *)PORTEIO,
 | 
						|
};
 | 
						|
 | 
						|
void bfin_special_gpio_pm_hibernate_suspend(void)
 | 
						|
{
 | 
						|
	int i;
 | 
						|
 | 
						|
	for (i = 0; i < ARRAY_SIZE(port_bases); ++i) {
 | 
						|
		gpio_bank_saved[i].data = read_PORTIO(port_bases[i]);
 | 
						|
		gpio_bank_saved[i].inen = read_PORTIO_INEN(port_bases[i]);
 | 
						|
		gpio_bank_saved[i].dir = read_PORTIO_DIR(port_bases[i]);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
void bfin_special_gpio_pm_hibernate_restore(void)
 | 
						|
{
 | 
						|
	int i;
 | 
						|
 | 
						|
	for (i = 0; i < ARRAY_SIZE(port_bases); ++i) {
 | 
						|
		write_PORTIO_INEN(port_bases[i], gpio_bank_saved[i].inen);
 | 
						|
		write_PORTIO_SET(port_bases[i],
 | 
						|
			gpio_bank_saved[i].data & gpio_bank_saved[i].dir);
 | 
						|
		write_PORTIO_DIR(port_bases[i], gpio_bank_saved[i].dir);
 | 
						|
	}
 | 
						|
}
 | 
						|
#endif
 |