2009-03-26 10:06:27 +02:00
/*
* 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))
2013-10-01 10:45:42 +02:00
# define irq_to_gpio(x) ((x) - GPIO_IRQ_BASE)
2009-03-26 10:06:27 +02:00
/* 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
2013-01-04 13:38:03 +00:00
static void _set_gpio_irqenable ( void __iomem * base , unsigned int index ,
2009-03-26 10:06:27 +02:00
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 ) ;
}
2010-11-29 10:30:40 +01:00
static void gpio_ack_irq ( struct irq_data * d )
2009-03-26 10:06:27 +02:00
{
2010-11-29 10:30:40 +01:00
unsigned int gpio = irq_to_gpio ( d - > irq ) ;
2013-01-04 13:38:03 +00:00
void __iomem * base = GPIO_BASE ( gpio / 32 ) ;
2009-03-26 10:06:27 +02:00
__raw_writel ( 1 < < ( gpio % 32 ) , base + GPIO_INT_CLR ) ;
}
2010-11-29 10:30:40 +01:00
static void gpio_mask_irq ( struct irq_data * d )
2009-03-26 10:06:27 +02:00
{
2010-11-29 10:30:40 +01:00
unsigned int gpio = irq_to_gpio ( d - > irq ) ;
2013-01-04 13:38:03 +00:00
void __iomem * base = GPIO_BASE ( gpio / 32 ) ;
2009-03-26 10:06:27 +02:00
_set_gpio_irqenable ( base , gpio % 32 , 0 ) ;
}
2010-11-29 10:30:40 +01:00
static void gpio_unmask_irq ( struct irq_data * d )
2009-03-26 10:06:27 +02:00
{
2010-11-29 10:30:40 +01:00
unsigned int gpio = irq_to_gpio ( d - > irq ) ;
2013-01-04 13:38:03 +00:00
void __iomem * base = GPIO_BASE ( gpio / 32 ) ;
2009-03-26 10:06:27 +02:00
_set_gpio_irqenable ( base , gpio % 32 , 1 ) ;
}
2010-11-29 10:30:40 +01:00
static int gpio_set_irq_type ( struct irq_data * d , unsigned int type )
2009-03-26 10:06:27 +02:00
{
2010-11-29 10:30:40 +01:00
unsigned int gpio = irq_to_gpio ( d - > irq ) ;
2009-03-26 10:06:27 +02:00
unsigned int gpio_mask = 1 < < ( gpio % 32 ) ;
2013-01-04 13:38:03 +00:00
void __iomem * base = GPIO_BASE ( gpio / 32 ) ;
2009-03-26 10:06:27 +02:00
unsigned int reg_both , reg_level , reg_type ;
reg_type = __raw_readl ( base + GPIO_INT_TYPE ) ;
2010-02-18 21:54:11 +02:00
reg_level = __raw_readl ( base + GPIO_INT_LEVEL ) ;
2009-03-26 10:06:27 +02:00
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 ) ;
2010-02-18 21:54:11 +02:00
__raw_writel ( reg_level , base + GPIO_INT_LEVEL ) ;
2009-03-26 10:06:27 +02:00
__raw_writel ( reg_both , base + GPIO_INT_BOTH_EDGE ) ;
2013-01-04 13:38:03 +00:00
gpio_ack_irq ( d ) ;
2009-03-26 10:06:27 +02:00
return 0 ;
}
static void gpio_irq_handler ( unsigned int irq , struct irq_desc * desc )
{
2011-03-24 12:44:54 +01:00
unsigned int port = ( unsigned int ) irq_desc_get_handler_data ( desc ) ;
2009-03-26 10:06:27 +02:00
unsigned int gpio_irq_no , irq_stat ;
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 ;
2011-03-24 12:44:54 +01:00
generic_handle_irq ( gpio_irq_no ) ;
2009-03-26 10:06:27 +02:00
}
}
static struct irq_chip gpio_irq_chip = {
. name = " GPIO " ,
2010-11-29 10:30:40 +01:00
. irq_ack = gpio_ack_irq ,
. irq_mask = gpio_mask_irq ,
. irq_unmask = gpio_unmask_irq ,
. irq_set_type = gpio_set_irq_type ,
2009-03-26 10:06:27 +02:00
} ;
static void _set_gpio_direction ( struct gpio_chip * chip , unsigned offset ,
int dir )
{
2013-01-04 13:38:03 +00:00
void __iomem * base = GPIO_BASE ( offset / 32 ) ;
2009-03-26 10:06:27 +02:00
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 )
{
2013-01-04 13:38:03 +00:00
void __iomem * base = GPIO_BASE ( offset / 32 ) ;
2009-03-26 10:06:27 +02:00
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 )
{
2013-01-04 13:38:03 +00:00
void __iomem * base = GPIO_BASE ( offset / 32 ) ;
2009-03-26 10:06:27 +02:00
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 + + ) {
2011-03-24 13:35:09 +01:00
irq_set_chip_and_handler ( j , & gpio_irq_chip ,
handle_edge_irq ) ;
2009-03-26 10:06:27 +02:00
set_irq_flags ( j , IRQF_VALID ) ;
}
2011-03-24 13:25:22 +01:00
irq_set_chained_handler ( IRQ_GPIO ( i ) , gpio_irq_handler ) ;
irq_set_handler_data ( IRQ_GPIO ( i ) , ( void * ) i ) ;
2009-03-26 10:06:27 +02:00
}
BUG_ON ( gpiochip_add ( & gemini_gpio_chip ) ) ;
}