Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b685004f authored by Ryan Mallon's avatar Ryan Mallon Committed by Russell King
Browse files

[ARM] 4988/1: Add GPIO lib support to the EP93xx



Adds support for the generic GPIO lib to the EP93xx family. The gpio
handling code has been moved from core.c to a new file called gpio.c.
The GPIO based IRQ code has not been changed.

Signed-off-by: default avatarRyan Mallon <ryan@bluewatersys.com>
Signed-off-by: default avatarRussell King <rmk+kernel@arm.linux.org.uk>
parent 05dda977
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -255,6 +255,7 @@ config ARCH_EP93XX
	select ARM_AMBA
	select ARM_AMBA
	select ARM_VIC
	select ARM_VIC
	select GENERIC_GPIO
	select GENERIC_GPIO
	select HAVE_GPIO_LIB
	help
	help
	  This enables support for the Cirrus EP93xx series of CPUs.
	  This enables support for the Cirrus EP93xx series of CPUs.


+1 −1
Original line number Original line Diff line number Diff line
#
#
# Makefile for the linux kernel.
# Makefile for the linux kernel.
#
#
obj-y			:= core.o clock.o
obj-y			:= core.o clock.o gpio.o
obj-m			:=
obj-m			:=
obj-n			:=
obj-n			:=
obj-			:=
obj-			:=
+12 −97
Original line number Original line Diff line number Diff line
@@ -159,7 +159,7 @@ static const u8 int_type2_register_offset[3] = { 0x94, 0xb0, 0x50 };
static const u8 eoi_register_offset[3]		= { 0x98, 0xb4, 0x54 };
static const u8 eoi_register_offset[3]		= { 0x98, 0xb4, 0x54 };
static const u8 int_en_register_offset[3]	= { 0x9c, 0xb8, 0x5c };
static const u8 int_en_register_offset[3]	= { 0x9c, 0xb8, 0x5c };


static void update_gpio_int_params(unsigned port)
void ep93xx_gpio_update_int_params(unsigned port)
{
{
	BUG_ON(port > 2);
	BUG_ON(port > 2);


@@ -175,99 +175,11 @@ static void update_gpio_int_params(unsigned port)
		EP93XX_GPIO_REG(int_en_register_offset[port]));
		EP93XX_GPIO_REG(int_en_register_offset[port]));
}
}


/* Port ordering is: A B F D E C G H */
void ep93xx_gpio_int_mask(unsigned line)
static const u8 data_register_offset[8] = {
	0x00, 0x04, 0x30, 0x0c, 0x20, 0x08, 0x38, 0x40,
};

static const u8 data_direction_register_offset[8] = {
	0x10, 0x14, 0x34, 0x1c, 0x24, 0x18, 0x3c, 0x44,
};

#define GPIO_IN		0
#define GPIO_OUT	1

static void ep93xx_gpio_set_direction(unsigned line, int direction)
{
{
	unsigned int data_direction_register;
	unsigned long flags;
	unsigned char v;

	data_direction_register =
		EP93XX_GPIO_REG(data_direction_register_offset[line >> 3]);

	local_irq_save(flags);
	if (direction == GPIO_OUT) {
		if (line >= 0 && line <= EP93XX_GPIO_LINE_MAX_IRQ) {
			/* Port A/B/F */
	gpio_int_unmasked[line >> 3] &= ~(1 << (line & 7));
	gpio_int_unmasked[line >> 3] &= ~(1 << (line & 7));
			update_gpio_int_params(line >> 3);
		}

		v = __raw_readb(data_direction_register);
		v |= 1 << (line & 7);
		__raw_writeb(v, data_direction_register);
	} else if (direction == GPIO_IN) {
		v = __raw_readb(data_direction_register);
		v &= ~(1 << (line & 7));
		__raw_writeb(v, data_direction_register);
	}
	local_irq_restore(flags);
}
}


int gpio_direction_input(unsigned gpio)
{
	if (gpio > EP93XX_GPIO_LINE_MAX)
		return -EINVAL;

	ep93xx_gpio_set_direction(gpio, GPIO_IN);

	return 0;
}
EXPORT_SYMBOL(gpio_direction_input);

int gpio_direction_output(unsigned gpio, int value)
{
	if (gpio > EP93XX_GPIO_LINE_MAX)
		return -EINVAL;

	gpio_set_value(gpio, value);
	ep93xx_gpio_set_direction(gpio, GPIO_OUT);

	return 0;
}
EXPORT_SYMBOL(gpio_direction_output);

int gpio_get_value(unsigned gpio)
{
	unsigned int data_register;

	data_register = EP93XX_GPIO_REG(data_register_offset[gpio >> 3]);

	return !!(__raw_readb(data_register) & (1 << (gpio & 7)));
}
EXPORT_SYMBOL(gpio_get_value);

void gpio_set_value(unsigned gpio, int value)
{
	unsigned int data_register;
	unsigned long flags;
	unsigned char v;

	data_register = EP93XX_GPIO_REG(data_register_offset[gpio >> 3]);

	local_irq_save(flags);
	v = __raw_readb(data_register);
	if (value)
		v |= 1 << (gpio & 7);
	else
		v &= ~(1 << (gpio & 7));
	__raw_writeb(v, data_register);
	local_irq_restore(flags);
}
EXPORT_SYMBOL(gpio_set_value);


/*************************************************************************
/*************************************************************************
 * EP93xx IRQ handling
 * EP93xx IRQ handling
 *************************************************************************/
 *************************************************************************/
@@ -316,7 +228,7 @@ static void ep93xx_gpio_irq_ack(unsigned int irq)


	if ((irq_desc[irq].status & IRQ_TYPE_SENSE_MASK) == IRQT_BOTHEDGE) {
	if ((irq_desc[irq].status & IRQ_TYPE_SENSE_MASK) == IRQT_BOTHEDGE) {
		gpio_int_type2[port] ^= port_mask; /* switch edge direction */
		gpio_int_type2[port] ^= port_mask; /* switch edge direction */
		update_gpio_int_params(port);
		ep93xx_gpio_update_int_params(port);
	}
	}


	__raw_writeb(port_mask, EP93XX_GPIO_REG(eoi_register_offset[port]));
	__raw_writeb(port_mask, EP93XX_GPIO_REG(eoi_register_offset[port]));
@@ -332,7 +244,7 @@ static void ep93xx_gpio_irq_mask_ack(unsigned int irq)
		gpio_int_type2[port] ^= port_mask; /* switch edge direction */
		gpio_int_type2[port] ^= port_mask; /* switch edge direction */


	gpio_int_unmasked[port] &= ~port_mask;
	gpio_int_unmasked[port] &= ~port_mask;
	update_gpio_int_params(port);
	ep93xx_gpio_update_int_params(port);


	__raw_writeb(port_mask, EP93XX_GPIO_REG(eoi_register_offset[port]));
	__raw_writeb(port_mask, EP93XX_GPIO_REG(eoi_register_offset[port]));
}
}
@@ -343,7 +255,7 @@ static void ep93xx_gpio_irq_mask(unsigned int irq)
	int port = line >> 3;
	int port = line >> 3;


	gpio_int_unmasked[port] &= ~(1 << (line & 7));
	gpio_int_unmasked[port] &= ~(1 << (line & 7));
	update_gpio_int_params(port);
	ep93xx_gpio_update_int_params(port);
}
}


static void ep93xx_gpio_irq_unmask(unsigned int irq)
static void ep93xx_gpio_irq_unmask(unsigned int irq)
@@ -352,7 +264,7 @@ static void ep93xx_gpio_irq_unmask(unsigned int irq)
	int port = line >> 3;
	int port = line >> 3;


	gpio_int_unmasked[port] |= 1 << (line & 7);
	gpio_int_unmasked[port] |= 1 << (line & 7);
	update_gpio_int_params(port);
	ep93xx_gpio_update_int_params(port);
}
}




@@ -368,7 +280,7 @@ static int ep93xx_gpio_irq_type(unsigned int irq, unsigned int type)
	const int port = gpio >> 3;
	const int port = gpio >> 3;
	const int port_mask = 1 << (gpio & 7);
	const int port_mask = 1 << (gpio & 7);


	ep93xx_gpio_set_direction(gpio, GPIO_IN);
	gpio_direction_output(gpio, gpio_get_value(gpio));


	switch (type) {
	switch (type) {
	case IRQT_RISING:
	case IRQT_RISING:
@@ -411,7 +323,7 @@ static int ep93xx_gpio_irq_type(unsigned int irq, unsigned int type)
	desc->status &= ~IRQ_TYPE_SENSE_MASK;
	desc->status &= ~IRQ_TYPE_SENSE_MASK;
	desc->status |= type & IRQ_TYPE_SENSE_MASK;
	desc->status |= type & IRQ_TYPE_SENSE_MASK;


	update_gpio_int_params(port);
	ep93xx_gpio_update_int_params(port);


	return 0;
	return 0;
}
}
@@ -549,6 +461,7 @@ static struct platform_device ep93xx_ohci_device = {
	.resource	= ep93xx_ohci_resources,
	.resource	= ep93xx_ohci_resources,
};
};


extern void ep93xx_gpio_init(void);


void __init ep93xx_init_devices(void)
void __init ep93xx_init_devices(void)
{
{
@@ -562,6 +475,8 @@ void __init ep93xx_init_devices(void)
	__raw_writel(0xaa, EP93XX_SYSCON_SWLOCK);
	__raw_writel(0xaa, EP93XX_SYSCON_SWLOCK);
	__raw_writel(v, EP93XX_SYSCON_DEVICE_CONFIG);
	__raw_writel(v, EP93XX_SYSCON_DEVICE_CONFIG);


	ep93xx_gpio_init();

	amba_device_register(&uart1_device, &iomem_resource);
	amba_device_register(&uart1_device, &iomem_resource);
	amba_device_register(&uart2_device, &iomem_resource);
	amba_device_register(&uart2_device, &iomem_resource);
	amba_device_register(&uart3_device, &iomem_resource);
	amba_device_register(&uart3_device, &iomem_resource);
+158 −0
Original line number Original line Diff line number Diff line
/*
 * linux/arch/arm/mach-ep93xx/gpio.c
 *
 * Generic EP93xx GPIO handling
 *
 * Copyright (c) 2008 Ryan Mallon <ryan@bluewatersys.com>
 *
 * Based on code originally from:
 *  linux/arch/arm/mach-ep93xx/core.c
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License version 2 as
 *  published by the Free Software Foundation.
 */

#include <linux/init.h>
#include <linux/module.h>
#include <linux/seq_file.h>

#include <asm/arch/ep93xx-regs.h>
#include <asm/io.h>
#include <asm/gpio.h>

struct ep93xx_gpio_chip {
	struct gpio_chip	chip;

	unsigned int		data_reg;
	unsigned int		data_dir_reg;
};

#define to_ep93xx_gpio_chip(c) container_of(c, struct ep93xx_gpio_chip, chip)

/* From core.c */
extern void ep93xx_gpio_int_mask(unsigned line);
extern void ep93xx_gpio_update_int_params(unsigned port);

static int ep93xx_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
{
	struct ep93xx_gpio_chip *ep93xx_chip = to_ep93xx_gpio_chip(chip);
	unsigned long flags;
	u8 v;

	local_irq_save(flags);
	v = __raw_readb(ep93xx_chip->data_dir_reg);
	v &= ~(1 << offset);
	__raw_writeb(v, ep93xx_chip->data_dir_reg);
	local_irq_restore(flags);

	return 0;
}

static int ep93xx_gpio_direction_output(struct gpio_chip *chip,
					unsigned offset, int val)
{
	struct ep93xx_gpio_chip *ep93xx_chip = to_ep93xx_gpio_chip(chip);
	unsigned long flags;
	int line;
	u8 v;

	local_irq_save(flags);

	/* Set the value */
	v = __raw_readb(ep93xx_chip->data_reg);
	if (val)
		v |= (1 << offset);
	else
		v &= ~(1 << offset);
	__raw_writeb(v, ep93xx_chip->data_reg);

	/* Drive as an output */
	line = chip->base + offset;
	if (line <= EP93XX_GPIO_LINE_MAX_IRQ) {
		/* Ports A/B/F */
		ep93xx_gpio_int_mask(line);
		ep93xx_gpio_update_int_params(line >> 3);
	}

	v = __raw_readb(ep93xx_chip->data_dir_reg);
	v |= (1 << offset);
	__raw_writeb(v, ep93xx_chip->data_dir_reg);

	local_irq_restore(flags);

	return 0;
}

static int ep93xx_gpio_get(struct gpio_chip *chip, unsigned offset)
{
	struct ep93xx_gpio_chip *ep93xx_chip = to_ep93xx_gpio_chip(chip);

	return !!(__raw_readb(ep93xx_chip->data_reg) & (1 << offset));
}

static void ep93xx_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
{
	struct ep93xx_gpio_chip *ep93xx_chip = to_ep93xx_gpio_chip(chip);
	unsigned long flags;
	u8 v;

	local_irq_save(flags);
	v = __raw_readb(ep93xx_chip->data_reg);
	if (val)
		v |= (1 << offset);
	else
		v &= ~(1 << offset);
	__raw_writeb(v, ep93xx_chip->data_reg);
	local_irq_restore(flags);
}

static void ep93xx_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
{
	struct ep93xx_gpio_chip *ep93xx_chip = to_ep93xx_gpio_chip(chip);
	u8 data_reg, data_dir_reg;
	int i;

	data_reg = __raw_readb(ep93xx_chip->data_reg);
	data_dir_reg = __raw_readb(ep93xx_chip->data_dir_reg);

	for (i = 0; i < chip->ngpio; i++)
		seq_printf(s, "GPIO %s%d: %s %s\n", chip->label, i,
			   (data_reg & (1 << i)) ? "set" : "clear",
			   (data_dir_reg & (1 << i)) ? "out" : "in");
}

#define EP93XX_GPIO_BANK(name, dr, ddr, base_gpio)			\
	{								\
		.chip = {						\
			.label		  = name,			\
			.direction_input  = ep93xx_gpio_direction_input, \
			.direction_output = ep93xx_gpio_direction_output, \
			.get		  = ep93xx_gpio_get,		\
			.set		  = ep93xx_gpio_set,		\
			.dbg_show	  = ep93xx_gpio_dbg_show,	\
			.base		  = base_gpio,			\
			.ngpio		  = 8,				\
		},							\
		.data_reg	= EP93XX_GPIO_REG(dr),			\
		.data_dir_reg	= EP93XX_GPIO_REG(ddr),			\
	}

static struct ep93xx_gpio_chip ep93xx_gpio_banks[] = {
	EP93XX_GPIO_BANK("A", 0x00, 0x10, 0),
	EP93XX_GPIO_BANK("B", 0x04, 0x14, 8),
	EP93XX_GPIO_BANK("C", 0x30, 0x34, 40),
	EP93XX_GPIO_BANK("D", 0x0c, 0x1c, 24),
	EP93XX_GPIO_BANK("E", 0x20, 0x24, 32),
	EP93XX_GPIO_BANK("F", 0x08, 0x18, 16),
	EP93XX_GPIO_BANK("G", 0x38, 0x3c, 48),
	EP93XX_GPIO_BANK("H", 0x40, 0x44, 56),
};

void __init ep93xx_gpio_init(void)
{
	int i;

	for (i = 0; i < ARRAY_SIZE(ep93xx_gpio_banks); i++)
		gpiochip_add(&ep93xx_gpio_banks[i].chip);
}
+4 −17
Original line number Original line Diff line number Diff line
@@ -101,30 +101,17 @@


/* new generic GPIO API - see Documentation/gpio.txt */
/* new generic GPIO API - see Documentation/gpio.txt */


static inline int gpio_request(unsigned gpio, const char *label)
#include <asm-generic/gpio.h>
{
	if (gpio > EP93XX_GPIO_LINE_MAX)
		return -EINVAL;
	return 0;
}

static inline void gpio_free(unsigned gpio)
{
}


int gpio_direction_input(unsigned gpio);
#define gpio_get_value	__gpio_get_value
int gpio_direction_output(unsigned gpio, int value);
#define gpio_set_value	__gpio_set_value
int gpio_get_value(unsigned gpio);
#define gpio_cansleep	__gpio_cansleep
void gpio_set_value(unsigned gpio, int value);

#include <asm-generic/gpio.h> /* cansleep wrappers */


/*
/*
 * Map GPIO A0..A7  (0..7)  to irq 64..71,
 * Map GPIO A0..A7  (0..7)  to irq 64..71,
 *          B0..B7  (7..15) to irq 72..79, and
 *          B0..B7  (7..15) to irq 72..79, and
 *          F0..F7 (16..24) to irq 80..87.
 *          F0..F7 (16..24) to irq 80..87.
 */
 */

static inline int gpio_to_irq(unsigned gpio)
static inline int gpio_to_irq(unsigned gpio)
{
{
	if (gpio <= EP93XX_GPIO_LINE_MAX_IRQ)
	if (gpio <= EP93XX_GPIO_LINE_MAX_IRQ)