2011-01-04 23:28:15 +03:00
/*
* Atheros AR71XX / AR724X / AR913X GPIO API support
*
2012-03-14 13:45:23 +04:00
* Copyright ( C ) 2010 - 2011 Jaiganesh Narayanan < jnarayanan @ atheros . com >
* Copyright ( C ) 2008 - 2011 Gabor Juhos < juhosg @ openwrt . org >
2011-01-04 23:28:15 +03:00
* Copyright ( C ) 2008 Imre Kaloz < kaloz @ openwrt . org >
*
2012-03-14 13:45:23 +04:00
* Parts of this file are based on Atheros ' 2.6 .15 / 2.6 .31 BSP
*
2011-01-04 23:28:15 +03:00
* 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/kernel.h>
# include <linux/init.h>
# include <linux/module.h>
# include <linux/types.h>
# include <linux/spinlock.h>
# include <linux/io.h>
# include <linux/ioport.h>
# include <linux/gpio.h>
# include <asm/mach-ath79/ar71xx_regs.h>
# include <asm/mach-ath79/ath79.h>
# include "common.h"
static void __iomem * ath79_gpio_base ;
static unsigned long ath79_gpio_count ;
static DEFINE_SPINLOCK ( ath79_gpio_lock ) ;
static void __ath79_gpio_set_value ( unsigned gpio , int value )
{
void __iomem * base = ath79_gpio_base ;
if ( value )
__raw_writel ( 1 < < gpio , base + AR71XX_GPIO_REG_SET ) ;
else
__raw_writel ( 1 < < gpio , base + AR71XX_GPIO_REG_CLEAR ) ;
}
static int __ath79_gpio_get_value ( unsigned gpio )
{
return ( __raw_readl ( ath79_gpio_base + AR71XX_GPIO_REG_IN ) > > gpio ) & 1 ;
}
static int ath79_gpio_get_value ( struct gpio_chip * chip , unsigned offset )
{
return __ath79_gpio_get_value ( offset ) ;
}
static void ath79_gpio_set_value ( struct gpio_chip * chip ,
unsigned offset , int value )
{
__ath79_gpio_set_value ( offset , value ) ;
}
static int ath79_gpio_direction_input ( struct gpio_chip * chip ,
unsigned offset )
{
void __iomem * base = ath79_gpio_base ;
unsigned long flags ;
spin_lock_irqsave ( & ath79_gpio_lock , flags ) ;
__raw_writel ( __raw_readl ( base + AR71XX_GPIO_REG_OE ) & ~ ( 1 < < offset ) ,
base + AR71XX_GPIO_REG_OE ) ;
spin_unlock_irqrestore ( & ath79_gpio_lock , flags ) ;
return 0 ;
}
static int ath79_gpio_direction_output ( struct gpio_chip * chip ,
unsigned offset , int value )
{
void __iomem * base = ath79_gpio_base ;
unsigned long flags ;
spin_lock_irqsave ( & ath79_gpio_lock , flags ) ;
if ( value )
__raw_writel ( 1 < < offset , base + AR71XX_GPIO_REG_SET ) ;
else
__raw_writel ( 1 < < offset , base + AR71XX_GPIO_REG_CLEAR ) ;
__raw_writel ( __raw_readl ( base + AR71XX_GPIO_REG_OE ) | ( 1 < < offset ) ,
base + AR71XX_GPIO_REG_OE ) ;
spin_unlock_irqrestore ( & ath79_gpio_lock , flags ) ;
return 0 ;
}
2012-03-14 13:45:23 +04:00
static int ar934x_gpio_direction_input ( struct gpio_chip * chip , unsigned offset )
{
void __iomem * base = ath79_gpio_base ;
unsigned long flags ;
spin_lock_irqsave ( & ath79_gpio_lock , flags ) ;
__raw_writel ( __raw_readl ( base + AR71XX_GPIO_REG_OE ) | ( 1 < < offset ) ,
base + AR71XX_GPIO_REG_OE ) ;
spin_unlock_irqrestore ( & ath79_gpio_lock , flags ) ;
return 0 ;
}
static int ar934x_gpio_direction_output ( struct gpio_chip * chip , unsigned offset ,
int value )
{
void __iomem * base = ath79_gpio_base ;
unsigned long flags ;
spin_lock_irqsave ( & ath79_gpio_lock , flags ) ;
if ( value )
__raw_writel ( 1 < < offset , base + AR71XX_GPIO_REG_SET ) ;
else
__raw_writel ( 1 < < offset , base + AR71XX_GPIO_REG_CLEAR ) ;
__raw_writel ( __raw_readl ( base + AR71XX_GPIO_REG_OE ) & ~ ( 1 < < offset ) ,
base + AR71XX_GPIO_REG_OE ) ;
spin_unlock_irqrestore ( & ath79_gpio_lock , flags ) ;
return 0 ;
}
2011-01-04 23:28:15 +03:00
static struct gpio_chip ath79_gpio_chip = {
. label = " ath79 " ,
. get = ath79_gpio_get_value ,
. set = ath79_gpio_set_value ,
. direction_input = ath79_gpio_direction_input ,
. direction_output = ath79_gpio_direction_output ,
. base = 0 ,
} ;
2013-01-29 12:19:12 +04:00
static void __iomem * ath79_gpio_get_function_reg ( void )
{
u32 reg = 0 ;
if ( soc_is_ar71xx ( ) | |
soc_is_ar724x ( ) | |
soc_is_ar913x ( ) | |
soc_is_ar933x ( ) )
reg = AR71XX_GPIO_REG_FUNC ;
else if ( soc_is_ar934x ( ) )
reg = AR934X_GPIO_REG_FUNC ;
else
BUG ( ) ;
return ath79_gpio_base + reg ;
}
2013-01-29 12:19:13 +04:00
void ath79_gpio_function_setup ( u32 set , u32 clear )
2011-01-04 23:28:15 +03:00
{
2013-01-29 12:19:12 +04:00
void __iomem * reg = ath79_gpio_get_function_reg ( ) ;
2011-01-04 23:28:15 +03:00
unsigned long flags ;
spin_lock_irqsave ( & ath79_gpio_lock , flags ) ;
2013-01-29 12:19:13 +04:00
__raw_writel ( ( __raw_readl ( reg ) & ~ clear ) | set , reg ) ;
2011-01-04 23:28:15 +03:00
/* flush write */
2013-01-29 12:19:12 +04:00
__raw_readl ( reg ) ;
2011-01-04 23:28:15 +03:00
spin_unlock_irqrestore ( & ath79_gpio_lock , flags ) ;
}
2013-01-29 12:19:13 +04:00
void ath79_gpio_function_enable ( u32 mask )
2011-01-04 23:28:15 +03:00
{
2013-01-29 12:19:13 +04:00
ath79_gpio_function_setup ( mask , 0 ) ;
2011-01-04 23:28:15 +03:00
}
2013-01-29 12:19:13 +04:00
void ath79_gpio_function_disable ( u32 mask )
2011-01-04 23:28:15 +03:00
{
2013-01-29 12:19:13 +04:00
ath79_gpio_function_setup ( 0 , mask ) ;
2011-01-04 23:28:15 +03:00
}
void __init ath79_gpio_init ( void )
{
int err ;
if ( soc_is_ar71xx ( ) )
ath79_gpio_count = AR71XX_GPIO_COUNT ;
2012-08-04 20:01:24 +04:00
else if ( soc_is_ar7240 ( ) )
ath79_gpio_count = AR7240_GPIO_COUNT ;
else if ( soc_is_ar7241 ( ) | | soc_is_ar7242 ( ) )
ath79_gpio_count = AR7241_GPIO_COUNT ;
2011-01-04 23:28:15 +03:00
else if ( soc_is_ar913x ( ) )
ath79_gpio_count = AR913X_GPIO_COUNT ;
2011-06-20 23:26:07 +04:00
else if ( soc_is_ar933x ( ) )
ath79_gpio_count = AR933X_GPIO_COUNT ;
2012-03-14 13:45:23 +04:00
else if ( soc_is_ar934x ( ) )
ath79_gpio_count = AR934X_GPIO_COUNT ;
2013-02-15 17:38:19 +04:00
else if ( soc_is_qca955x ( ) )
ath79_gpio_count = QCA955X_GPIO_COUNT ;
2011-01-04 23:28:15 +03:00
else
BUG ( ) ;
ath79_gpio_base = ioremap_nocache ( AR71XX_GPIO_BASE , AR71XX_GPIO_SIZE ) ;
ath79_gpio_chip . ngpio = ath79_gpio_count ;
2013-02-15 17:38:19 +04:00
if ( soc_is_ar934x ( ) | | soc_is_qca955x ( ) ) {
2012-03-14 13:45:23 +04:00
ath79_gpio_chip . direction_input = ar934x_gpio_direction_input ;
ath79_gpio_chip . direction_output = ar934x_gpio_direction_output ;
}
2011-01-04 23:28:15 +03:00
err = gpiochip_add ( & ath79_gpio_chip ) ;
if ( err )
panic ( " cannot add AR71xx GPIO chip, error=%d " , err ) ;
}
int gpio_get_value ( unsigned gpio )
{
if ( gpio < ath79_gpio_count )
return __ath79_gpio_get_value ( gpio ) ;
return __gpio_get_value ( gpio ) ;
}
EXPORT_SYMBOL ( gpio_get_value ) ;
void gpio_set_value ( unsigned gpio , int value )
{
if ( gpio < ath79_gpio_count )
__ath79_gpio_set_value ( gpio , value ) ;
else
__gpio_set_value ( gpio , value ) ;
}
EXPORT_SYMBOL ( gpio_set_value ) ;
int gpio_to_irq ( unsigned gpio )
{
/* FIXME */
return - EINVAL ;
}
EXPORT_SYMBOL ( gpio_to_irq ) ;
int irq_to_gpio ( unsigned irq )
{
/* FIXME */
return - EINVAL ;
}
EXPORT_SYMBOL ( irq_to_gpio ) ;