2010-04-29 13:58:54 +04:00
/*
2015-04-01 05:20:09 +03:00
* Loongson - 2F / 3 A / 3 B GPIO Support
2010-04-29 13:58:54 +04:00
*
2013-01-22 15:59:30 +04:00
* Copyright ( c ) 2008 Richard Liu , STMicroelectronics < richard . liu @ st . com >
2010-04-29 13:58:54 +04:00
* Copyright ( c ) 2008 - 2010 Arnaud Patard < apatard @ mandriva . com >
2015-04-01 05:20:09 +03:00
* Copyright ( c ) 2013 Hongbing Hu < huhb @ lemote . com >
* Copyright ( c ) 2014 Huacai Chen < chenhc @ lemote . com >
2010-04-29 13:58:54 +04:00
*
* 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/module.h>
# include <linux/spinlock.h>
# include <linux/err.h>
# include <asm/types.h>
# include <loongson.h>
# include <linux/gpio.h>
# define STLS2F_N_GPIO 4
2015-04-01 05:20:09 +03:00
# define STLS3A_N_GPIO 16
# ifdef CONFIG_CPU_LOONGSON3
# define LOONGSON_N_GPIO STLS3A_N_GPIO
# else
# define LOONGSON_N_GPIO STLS2F_N_GPIO
# endif
# define LOONGSON_GPIO_IN_OFFSET 16
2010-04-29 13:58:54 +04:00
static DEFINE_SPINLOCK ( gpio_lock ) ;
2015-04-01 05:20:09 +03:00
static int loongson_gpio_direction_input ( struct gpio_chip * chip , unsigned gpio )
2010-04-29 13:58:54 +04:00
{
u32 temp ;
u32 mask ;
spin_lock ( & gpio_lock ) ;
mask = 1 < < gpio ;
temp = LOONGSON_GPIOIE ;
temp | = mask ;
LOONGSON_GPIOIE = temp ;
spin_unlock ( & gpio_lock ) ;
return 0 ;
}
2015-04-01 05:20:09 +03:00
static int loongson_gpio_direction_output ( struct gpio_chip * chip ,
2010-04-29 13:58:54 +04:00
unsigned gpio , int level )
{
u32 temp ;
u32 mask ;
gpio_set_value ( gpio , level ) ;
spin_lock ( & gpio_lock ) ;
mask = 1 < < gpio ;
temp = LOONGSON_GPIOIE ;
temp & = ( ~ mask ) ;
LOONGSON_GPIOIE = temp ;
spin_unlock ( & gpio_lock ) ;
return 0 ;
}
2015-04-01 05:20:09 +03:00
static int loongson_gpio_get_value ( struct gpio_chip * chip , unsigned gpio )
2010-04-29 13:58:54 +04:00
{
2015-04-01 05:20:07 +03:00
u32 val ;
u32 mask ;
2015-04-01 05:20:09 +03:00
mask = 1 < < ( gpio + LOONGSON_GPIO_IN_OFFSET ) ;
2015-04-01 05:20:07 +03:00
spin_lock ( & gpio_lock ) ;
val = LOONGSON_GPIODATA ;
spin_unlock ( & gpio_lock ) ;
return ( val & mask ) ! = 0 ;
2010-04-29 13:58:54 +04:00
}
2015-04-01 05:20:09 +03:00
static void loongson_gpio_set_value ( struct gpio_chip * chip ,
2010-04-29 13:58:54 +04:00
unsigned gpio , int value )
{
2015-04-01 05:20:07 +03:00
u32 val ;
u32 mask ;
mask = 1 < < gpio ;
spin_lock ( & gpio_lock ) ;
val = LOONGSON_GPIODATA ;
if ( value )
val | = mask ;
else
val & = ( ~ mask ) ;
LOONGSON_GPIODATA = val ;
spin_unlock ( & gpio_lock ) ;
2010-04-29 13:58:54 +04:00
}
2015-04-01 05:20:09 +03:00
static struct gpio_chip loongson_chip = {
. label = " Loongson-gpio-chip " ,
. direction_input = loongson_gpio_direction_input ,
. get = loongson_gpio_get_value ,
. direction_output = loongson_gpio_direction_output ,
. set = loongson_gpio_set_value ,
2013-01-22 15:59:30 +04:00
. base = 0 ,
2015-04-01 05:20:09 +03:00
. ngpio = LOONGSON_N_GPIO ,
2015-04-01 05:20:07 +03:00
. can_sleep = false ,
2010-04-29 13:58:54 +04:00
} ;
2015-04-01 05:20:09 +03:00
static int __init loongson_gpio_setup ( void )
2010-04-29 13:58:54 +04:00
{
2015-04-01 05:20:09 +03:00
return gpiochip_add ( & loongson_chip ) ;
2010-04-29 13:58:54 +04:00
}
2015-04-01 05:20:09 +03:00
postcore_initcall ( loongson_gpio_setup ) ;