2018-12-28 00:31:46 -08:00
// SPDX-License-Identifier: GPL-2.0
2010-10-04 02:59:29 +09:00
/*
* arch / sh / boards / mach - x3proto / gpio . c
*
* Renesas SH - X3 Prototype Baseboard GPIO Support .
*
2012-05-24 15:24:39 +09:00
* Copyright ( C ) 2010 - 2012 Paul Mundt
2010-10-04 02:59:29 +09:00
*/
# define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
# include <linux/init.h>
# include <linux/interrupt.h>
2015-12-08 16:02:00 +01:00
# include <linux/gpio/driver.h>
2010-10-04 02:59:29 +09:00
# include <linux/irq.h>
# include <linux/kernel.h>
# include <linux/spinlock.h>
2012-05-24 15:24:39 +09:00
# include <linux/irqdomain.h>
2010-10-04 02:59:29 +09:00
# include <linux/io.h>
# include <mach/ilsel.h>
# include <mach/hardware.h>
# define KEYCTLR 0xb81c0000
# define KEYOUTR 0xb81c0002
# define KEYDETR 0xb81c0004
static DEFINE_SPINLOCK ( x3proto_gpio_lock ) ;
2012-05-24 15:24:39 +09:00
static struct irq_domain * x3proto_irq_domain ;
2010-10-04 02:59:29 +09:00
static int x3proto_gpio_direction_input ( struct gpio_chip * chip , unsigned gpio )
{
unsigned long flags ;
unsigned int data ;
spin_lock_irqsave ( & x3proto_gpio_lock , flags ) ;
data = __raw_readw ( KEYCTLR ) ;
data | = ( 1 < < gpio ) ;
__raw_writew ( data , KEYCTLR ) ;
spin_unlock_irqrestore ( & x3proto_gpio_lock , flags ) ;
return 0 ;
}
static int x3proto_gpio_get ( struct gpio_chip * chip , unsigned gpio )
{
return ! ! ( __raw_readw ( KEYDETR ) & ( 1 < < gpio ) ) ;
}
static int x3proto_gpio_to_irq ( struct gpio_chip * chip , unsigned gpio )
{
2012-05-24 15:24:39 +09:00
int virq ;
if ( gpio < chip - > ngpio )
virq = irq_create_mapping ( x3proto_irq_domain , gpio ) ;
else
virq = - ENXIO ;
return virq ;
2010-10-04 02:59:29 +09:00
}
2015-09-14 10:42:37 +02:00
static void x3proto_gpio_irq_handler ( struct irq_desc * desc )
2010-10-04 02:59:29 +09:00
{
2015-07-13 20:51:25 +00:00
struct irq_data * data = irq_desc_get_irq_data ( desc ) ;
2010-10-27 15:11:01 +09:00
struct irq_chip * chip = irq_data_get_irq_chip ( data ) ;
2010-10-04 02:59:29 +09:00
unsigned long mask ;
int pin ;
2010-10-27 15:11:01 +09:00
chip - > irq_mask_ack ( data ) ;
2010-10-04 02:59:29 +09:00
mask = __raw_readw ( KEYDETR ) ;
for_each_set_bit ( pin , & mask , NR_BASEBOARD_GPIOS )
2012-05-24 15:24:39 +09:00
generic_handle_irq ( irq_linear_revmap ( x3proto_irq_domain , pin ) ) ;
2010-10-04 02:59:29 +09:00
2010-10-27 15:11:01 +09:00
chip - > irq_unmask ( data ) ;
2010-10-04 02:59:29 +09:00
}
struct gpio_chip x3proto_gpio_chip = {
. label = " x3proto-gpio " ,
. direction_input = x3proto_gpio_direction_input ,
. get = x3proto_gpio_get ,
. to_irq = x3proto_gpio_to_irq ,
. base = - 1 ,
. ngpio = NR_BASEBOARD_GPIOS ,
} ;
2012-05-24 15:24:39 +09:00
static int x3proto_gpio_irq_map ( struct irq_domain * domain , unsigned int virq ,
irq_hw_number_t hwirq )
{
irq_set_chip_and_handler_name ( virq , & dummy_irq_chip , handle_simple_irq ,
" gpio " ) ;
return 0 ;
}
static struct irq_domain_ops x3proto_gpio_irq_ops = {
. map = x3proto_gpio_irq_map ,
. xlate = irq_domain_xlate_twocell ,
} ;
2010-10-04 02:59:29 +09:00
int __init x3proto_gpio_setup ( void )
{
2012-05-24 15:24:39 +09:00
int ilsel , ret ;
2010-10-04 02:59:29 +09:00
ilsel = ilsel_enable ( ILSEL_KEY ) ;
if ( unlikely ( ilsel < 0 ) )
return ilsel ;
2015-12-08 16:02:00 +01:00
ret = gpiochip_add_data ( & x3proto_gpio_chip , NULL ) ;
2010-10-04 02:59:29 +09:00
if ( unlikely ( ret ) )
goto err_gpio ;
2012-05-24 15:24:39 +09:00
x3proto_irq_domain = irq_domain_add_linear ( NULL , NR_BASEBOARD_GPIOS ,
& x3proto_gpio_irq_ops , NULL ) ;
if ( unlikely ( ! x3proto_irq_domain ) )
goto err_irq ;
2010-10-04 02:59:29 +09:00
pr_info ( " registering '%s' support, handling GPIOs %u -> %u, "
" bound to IRQ %u \n " ,
x3proto_gpio_chip . label , x3proto_gpio_chip . base ,
x3proto_gpio_chip . base + x3proto_gpio_chip . ngpio ,
ilsel ) ;
2011-03-24 16:31:17 +01:00
irq_set_chained_handler ( ilsel , x3proto_gpio_irq_handler ) ;
irq_set_irq_wake ( ilsel , 1 ) ;
2010-10-04 02:59:29 +09:00
return 0 ;
err_irq :
2014-07-12 22:30:14 +02:00
gpiochip_remove ( & x3proto_gpio_chip ) ;
ret = 0 ;
2010-10-04 02:59:29 +09:00
err_gpio :
synchronize_irq ( ilsel ) ;
ilsel_disable ( ILSEL_KEY ) ;
return ret ;
}