Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 137535
b: refs/heads/master
c: 1df621a
h: refs/heads/master
i:
  137533: 1b5b5c9
  137531: 9ddacb9
  137527: e4b462b
  137519: 38476fc
  137503: b9fedce
  137471: 2e32a79
v: v3
  • Loading branch information
Paulius Zaleckas committed Mar 26, 2009
1 parent 8e35c73 commit 491e6bd
Show file tree
Hide file tree
Showing 7 changed files with 266 additions and 3 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 881a95f976e687307b41ba3c767561f533485c7e
refs/heads/master: 1df621ae2f3b03d557d962a7afec2b1d04558986
2 changes: 2 additions & 0 deletions trunk/arch/arm/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,8 @@ config ARCH_EP93XX
config ARCH_GEMINI
bool "Cortina Systems Gemini"
select CPU_FA526
select GENERIC_GPIO
select ARCH_REQUIRE_GPIOLIB
help
Support for the Cortina Systems Gemini family SoCs

Expand Down
2 changes: 1 addition & 1 deletion trunk/arch/arm/mach-gemini/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@

# Object file lists.

obj-y := irq.o mm.o time.o devices.o
obj-y := irq.o mm.o time.o devices.o gpio.o
1 change: 1 addition & 0 deletions trunk/arch/arm/mach-gemini/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ struct mtd_partition;
extern void gemini_map_io(void);
extern void gemini_init_irq(void);
extern void gemini_timer_init(void);
extern void gemini_gpio_init(void);

/* Common platform devices registration functions */
extern int platform_register_uart(void);
Expand Down
232 changes: 232 additions & 0 deletions trunk/arch/arm/mach-gemini/gpio.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,232 @@
/*
* Gemini gpiochip and interrupt routines
*
* Copyright (C) 2008-2009 Paulius Zaleckas <paulius.zaleckas@teltonika.lt>
*
* Based on plat-mxc/gpio.c:
* MXC GPIO support. (c) 2008 Daniel Mack <daniel@caiaq.de>
* Copyright 2008 Juergen Beisert, kernel@pengutronix.de
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/

#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/gpio.h>

#include <mach/hardware.h>
#include <mach/irqs.h>

#define GPIO_BASE(x) IO_ADDRESS(GEMINI_GPIO_BASE(x))

/* GPIO registers definition */
#define GPIO_DATA_OUT 0x0
#define GPIO_DATA_IN 0x4
#define GPIO_DIR 0x8
#define GPIO_DATA_SET 0x10
#define GPIO_DATA_CLR 0x14
#define GPIO_PULL_EN 0x18
#define GPIO_PULL_TYPE 0x1C
#define GPIO_INT_EN 0x20
#define GPIO_INT_STAT 0x24
#define GPIO_INT_MASK 0x2C
#define GPIO_INT_CLR 0x30
#define GPIO_INT_TYPE 0x34
#define GPIO_INT_BOTH_EDGE 0x38
#define GPIO_INT_LEVEL 0x3C
#define GPIO_DEBOUNCE_EN 0x40
#define GPIO_DEBOUNCE_PRESCALE 0x44

#define GPIO_PORT_NUM 3

static void _set_gpio_irqenable(unsigned int base, unsigned int index,
int enable)
{
unsigned int reg;

reg = __raw_readl(base + GPIO_INT_EN);
reg = (reg & (~(1 << index))) | (!!enable << index);
__raw_writel(reg, base + GPIO_INT_EN);
}

static void gpio_ack_irq(unsigned int irq)
{
unsigned int gpio = irq_to_gpio(irq);
unsigned int base = GPIO_BASE(gpio / 32);

__raw_writel(1 << (gpio % 32), base + GPIO_INT_CLR);
}

static void gpio_mask_irq(unsigned int irq)
{
unsigned int gpio = irq_to_gpio(irq);
unsigned int base = GPIO_BASE(gpio / 32);

_set_gpio_irqenable(base, gpio % 32, 0);
}

static void gpio_unmask_irq(unsigned int irq)
{
unsigned int gpio = irq_to_gpio(irq);
unsigned int base = GPIO_BASE(gpio / 32);

_set_gpio_irqenable(base, gpio % 32, 1);
}

static int gpio_set_irq_type(unsigned int irq, unsigned int type)
{
unsigned int gpio = irq_to_gpio(irq);
unsigned int gpio_mask = 1 << (gpio % 32);
unsigned int base = GPIO_BASE(gpio / 32);
unsigned int reg_both, reg_level, reg_type;

reg_type = __raw_readl(base + GPIO_INT_TYPE);
reg_level = __raw_readl(base + GPIO_INT_BOTH_EDGE);
reg_both = __raw_readl(base + GPIO_INT_BOTH_EDGE);

switch (type) {
case IRQ_TYPE_EDGE_BOTH:
reg_type &= ~gpio_mask;
reg_both |= gpio_mask;
break;
case IRQ_TYPE_EDGE_RISING:
reg_type &= ~gpio_mask;
reg_both &= ~gpio_mask;
reg_level &= ~gpio_mask;
break;
case IRQ_TYPE_EDGE_FALLING:
reg_type &= ~gpio_mask;
reg_both &= ~gpio_mask;
reg_level |= gpio_mask;
break;
case IRQ_TYPE_LEVEL_HIGH:
reg_type |= gpio_mask;
reg_level &= ~gpio_mask;
break;
case IRQ_TYPE_LEVEL_LOW:
reg_type |= gpio_mask;
reg_level |= gpio_mask;
break;
default:
return -EINVAL;
}

__raw_writel(reg_type, base + GPIO_INT_TYPE);
__raw_writel(reg_level, base + GPIO_INT_BOTH_EDGE);
__raw_writel(reg_both, base + GPIO_INT_BOTH_EDGE);

gpio_ack_irq(irq);

return 0;
}

static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
{
unsigned int gpio_irq_no, irq_stat;
unsigned int port = (unsigned int)get_irq_data(irq);

irq_stat = __raw_readl(GPIO_BASE(port) + GPIO_INT_STAT);

gpio_irq_no = GPIO_IRQ_BASE + port * 32;
for (; irq_stat != 0; irq_stat >>= 1, gpio_irq_no++) {

if ((irq_stat & 1) == 0)
continue;

BUG_ON(!(irq_desc[gpio_irq_no].handle_irq));
irq_desc[gpio_irq_no].handle_irq(gpio_irq_no,
&irq_desc[gpio_irq_no]);
}
}

static struct irq_chip gpio_irq_chip = {
.name = "GPIO",
.ack = gpio_ack_irq,
.mask = gpio_mask_irq,
.unmask = gpio_unmask_irq,
.set_type = gpio_set_irq_type,
};

static void _set_gpio_direction(struct gpio_chip *chip, unsigned offset,
int dir)
{
unsigned int base = GPIO_BASE(offset / 32);
unsigned int reg;

reg = __raw_readl(base + GPIO_DIR);
if (dir)
reg |= 1 << (offset % 32);
else
reg &= ~(1 << (offset % 32));
__raw_writel(reg, base + GPIO_DIR);
}

static void gemini_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
{
unsigned int base = GPIO_BASE(offset / 32);

if (value)
__raw_writel(1 << (offset % 32), base + GPIO_DATA_SET);
else
__raw_writel(1 << (offset % 32), base + GPIO_DATA_CLR);
}

static int gemini_gpio_get(struct gpio_chip *chip, unsigned offset)
{
unsigned int base = GPIO_BASE(offset / 32);

return (__raw_readl(base + GPIO_DATA_IN) >> (offset % 32)) & 1;
}

static int gemini_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
{
_set_gpio_direction(chip, offset, 0);
return 0;
}

static int gemini_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
int value)
{
_set_gpio_direction(chip, offset, 1);
gemini_gpio_set(chip, offset, value);
return 0;
}

static struct gpio_chip gemini_gpio_chip = {
.label = "Gemini",
.direction_input = gemini_gpio_direction_input,
.get = gemini_gpio_get,
.direction_output = gemini_gpio_direction_output,
.set = gemini_gpio_set,
.base = 0,
.ngpio = GPIO_PORT_NUM * 32,
};

void __init gemini_gpio_init(void)
{
int i, j;

for (i = 0; i < GPIO_PORT_NUM; i++) {
/* disable, unmask and clear all interrupts */
__raw_writel(0x0, GPIO_BASE(i) + GPIO_INT_EN);
__raw_writel(0x0, GPIO_BASE(i) + GPIO_INT_MASK);
__raw_writel(~0x0, GPIO_BASE(i) + GPIO_INT_CLR);

for (j = GPIO_IRQ_BASE + i * 32;
j < GPIO_IRQ_BASE + (i + 1) * 32; j++) {
set_irq_chip(j, &gpio_irq_chip);
set_irq_handler(j, handle_edge_irq);
set_irq_flags(j, IRQF_VALID);
}

set_irq_chained_handler(IRQ_GPIO(i), gpio_irq_handler);
set_irq_data(IRQ_GPIO(i), (void *)i);
}

BUG_ON(gpiochip_add(&gemini_gpio_chip));
}
25 changes: 25 additions & 0 deletions trunk/arch/arm/mach-gemini/include/mach/gpio.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* Gemini gpiolib specific defines
*
* Copyright (C) 2008-2009 Paulius Zaleckas <paulius.zaleckas@teltonika.lt>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/

#ifndef __MACH_GPIO_H__
#define __MACH_GPIO_H__

#include <mach/irqs.h>
#include <asm-generic/gpio.h>

#define gpio_get_value __gpio_get_value
#define gpio_set_value __gpio_set_value
#define gpio_cansleep __gpio_cansleep

#define gpio_to_irq(x) ((x) + GPIO_IRQ_BASE)
#define irq_to_gpio(x) ((x) - GPIO_IRQ_BASE)

#endif /* __MACH_GPIO_H__ */
5 changes: 4 additions & 1 deletion trunk/arch/arm/mach-gemini/include/mach/irqs.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,11 @@

#define NORMAL_IRQ_NUM 32

#define GPIO_IRQ_BASE NORMAL_IRQ_NUM
#define GPIO_IRQ_NUM (3 * 32)

#define ARCH_TIMER_IRQ IRQ_TIMER2

#define NR_IRQS NORMAL_IRQ_NUM
#define NR_IRQS (NORMAL_IRQ_NUM + GPIO_IRQ_NUM)

#endif /* __MACH_IRQS_H__ */

0 comments on commit 491e6bd

Please sign in to comment.