2009-06-10 18:49:32 +04:00
/*
2009-08-21 10:07:46 +04:00
* linux / arch / arm / mach - w90x900 / gpio . c
2009-06-10 18:49:32 +04:00
*
2009-08-21 10:07:46 +04:00
* Generic nuc900 GPIO handling
2009-06-10 18:49:32 +04:00
*
* Wan ZongShun < mcuos . com @ gmail . com >
*
* 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/clk.h>
# include <linux/errno.h>
# include <linux/interrupt.h>
# include <linux/irq.h>
# include <linux/debugfs.h>
# include <linux/seq_file.h>
# include <linux/kernel.h>
# include <linux/list.h>
# include <linux/module.h>
# include <linux/io.h>
# include <linux/gpio.h>
# include <mach/hardware.h>
# define GPIO_BASE (W90X900_VA_GPIO)
# define GPIO_DIR (0x04)
# define GPIO_OUT (0x08)
# define GPIO_IN (0x0C)
# define GROUPINERV (0x10)
# define GPIO_GPIO(Nb) (0x00000001 << (Nb))
2009-08-21 10:07:46 +04:00
# define to_nuc900_gpio_chip(c) container_of(c, struct nuc900_gpio_chip, chip)
2009-06-10 18:49:32 +04:00
2009-08-21 10:07:46 +04:00
# define NUC900_GPIO_CHIP(name, base_gpio, nr_gpio) \
2009-06-10 18:49:32 +04:00
{ \
. chip = { \
. label = name , \
2009-08-21 10:07:46 +04:00
. direction_input = nuc900_dir_input , \
. direction_output = nuc900_dir_output , \
. get = nuc900_gpio_get , \
. set = nuc900_gpio_set , \
2009-06-10 18:49:32 +04:00
. base = base_gpio , \
. ngpio = nr_gpio , \
} \
}
2009-08-21 10:07:46 +04:00
struct nuc900_gpio_chip {
2009-06-10 18:49:32 +04:00
struct gpio_chip chip ;
void __iomem * regbase ; /* Base of group register*/
spinlock_t gpio_lock ;
} ;
2009-08-21 10:07:46 +04:00
static int nuc900_gpio_get ( struct gpio_chip * chip , unsigned offset )
2009-06-10 18:49:32 +04:00
{
2009-08-21 10:07:46 +04:00
struct nuc900_gpio_chip * nuc900_gpio = to_nuc900_gpio_chip ( chip ) ;
void __iomem * pio = nuc900_gpio - > regbase + GPIO_IN ;
2009-06-10 18:49:32 +04:00
unsigned int regval ;
regval = __raw_readl ( pio ) ;
regval & = GPIO_GPIO ( offset ) ;
return ( regval ! = 0 ) ;
}
2009-08-21 10:07:46 +04:00
static void nuc900_gpio_set ( struct gpio_chip * chip , unsigned offset , int val )
2009-06-10 18:49:32 +04:00
{
2009-08-21 10:07:46 +04:00
struct nuc900_gpio_chip * nuc900_gpio = to_nuc900_gpio_chip ( chip ) ;
void __iomem * pio = nuc900_gpio - > regbase + GPIO_OUT ;
2009-06-10 18:49:32 +04:00
unsigned int regval ;
unsigned long flags ;
2009-08-21 10:07:46 +04:00
spin_lock_irqsave ( & nuc900_gpio - > gpio_lock , flags ) ;
2009-06-10 18:49:32 +04:00
regval = __raw_readl ( pio ) ;
if ( val )
regval | = GPIO_GPIO ( offset ) ;
else
regval & = ~ GPIO_GPIO ( offset ) ;
__raw_writel ( regval , pio ) ;
2009-08-21 10:07:46 +04:00
spin_unlock_irqrestore ( & nuc900_gpio - > gpio_lock , flags ) ;
2009-06-10 18:49:32 +04:00
}
2009-08-21 10:07:46 +04:00
static int nuc900_dir_input ( struct gpio_chip * chip , unsigned offset )
2009-06-10 18:49:32 +04:00
{
2009-08-21 10:07:46 +04:00
struct nuc900_gpio_chip * nuc900_gpio = to_nuc900_gpio_chip ( chip ) ;
void __iomem * pio = nuc900_gpio - > regbase + GPIO_DIR ;
2009-06-10 18:49:32 +04:00
unsigned int regval ;
unsigned long flags ;
2009-08-21 10:07:46 +04:00
spin_lock_irqsave ( & nuc900_gpio - > gpio_lock , flags ) ;
2009-06-10 18:49:32 +04:00
regval = __raw_readl ( pio ) ;
regval & = ~ GPIO_GPIO ( offset ) ;
__raw_writel ( regval , pio ) ;
2009-08-21 10:07:46 +04:00
spin_unlock_irqrestore ( & nuc900_gpio - > gpio_lock , flags ) ;
2009-06-10 18:49:32 +04:00
return 0 ;
}
2009-08-21 10:07:46 +04:00
static int nuc900_dir_output ( struct gpio_chip * chip , unsigned offset , int val )
2009-06-10 18:49:32 +04:00
{
2009-08-21 10:07:46 +04:00
struct nuc900_gpio_chip * nuc900_gpio = to_nuc900_gpio_chip ( chip ) ;
void __iomem * outreg = nuc900_gpio - > regbase + GPIO_OUT ;
void __iomem * pio = nuc900_gpio - > regbase + GPIO_DIR ;
2009-06-10 18:49:32 +04:00
unsigned int regval ;
unsigned long flags ;
2009-08-21 10:07:46 +04:00
spin_lock_irqsave ( & nuc900_gpio - > gpio_lock , flags ) ;
2009-06-10 18:49:32 +04:00
regval = __raw_readl ( pio ) ;
regval | = GPIO_GPIO ( offset ) ;
__raw_writel ( regval , pio ) ;
regval = __raw_readl ( outreg ) ;
if ( val )
regval | = GPIO_GPIO ( offset ) ;
else
regval & = ~ GPIO_GPIO ( offset ) ;
__raw_writel ( regval , outreg ) ;
2009-08-21 10:07:46 +04:00
spin_unlock_irqrestore ( & nuc900_gpio - > gpio_lock , flags ) ;
2009-06-10 18:49:32 +04:00
return 0 ;
}
2009-08-21 10:07:46 +04:00
static struct nuc900_gpio_chip nuc900_gpio [ ] = {
NUC900_GPIO_CHIP ( " GROUPC " , 0 , 16 ) ,
NUC900_GPIO_CHIP ( " GROUPD " , 16 , 10 ) ,
NUC900_GPIO_CHIP ( " GROUPE " , 26 , 14 ) ,
NUC900_GPIO_CHIP ( " GROUPF " , 40 , 10 ) ,
NUC900_GPIO_CHIP ( " GROUPG " , 50 , 17 ) ,
NUC900_GPIO_CHIP ( " GROUPH " , 67 , 8 ) ,
NUC900_GPIO_CHIP ( " GROUPI " , 75 , 17 ) ,
2009-06-10 18:49:32 +04:00
} ;
2009-08-21 10:07:46 +04:00
void __init nuc900_init_gpio ( int nr_group )
2009-06-10 18:49:32 +04:00
{
unsigned i ;
2009-08-21 10:07:46 +04:00
struct nuc900_gpio_chip * gpio_chip ;
2009-06-10 18:49:32 +04:00
for ( i = 0 ; i < nr_group ; i + + ) {
2009-08-21 10:07:46 +04:00
gpio_chip = & nuc900_gpio [ i ] ;
2009-06-10 18:49:32 +04:00
spin_lock_init ( & gpio_chip - > gpio_lock ) ;
gpio_chip - > regbase = GPIO_BASE + i * GROUPINERV ;
gpiochip_add ( & gpio_chip - > chip ) ;
}
}