2014-02-25 17:01:01 -06:00
/*
* Copyright ( c ) 2011 Jamie Iles
*
* 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 .
*
* All enquiries to support @ picochip . com
*/
# include <linux/basic_mmio_gpio.h>
# include <linux/err.h>
# include <linux/init.h>
# include <linux/interrupt.h>
# include <linux/io.h>
# include <linux/ioport.h>
# include <linux/irq.h>
# include <linux/irqdomain.h>
# include <linux/module.h>
# include <linux/of.h>
# include <linux/of_address.h>
# include <linux/of_irq.h>
# include <linux/platform_device.h>
# include <linux/spinlock.h>
2014-09-17 09:18:39 -07:00
# include <linux/platform_data/gpio-dwapb.h>
# include <linux/slab.h>
2014-02-25 17:01:01 -06:00
# define GPIO_SWPORTA_DR 0x00
# define GPIO_SWPORTA_DDR 0x04
# define GPIO_SWPORTB_DR 0x0c
# define GPIO_SWPORTB_DDR 0x10
# define GPIO_SWPORTC_DR 0x18
# define GPIO_SWPORTC_DDR 0x1c
# define GPIO_SWPORTD_DR 0x24
# define GPIO_SWPORTD_DDR 0x28
# define GPIO_INTEN 0x30
# define GPIO_INTMASK 0x34
# define GPIO_INTTYPE_LEVEL 0x38
# define GPIO_INT_POLARITY 0x3c
# define GPIO_INTSTATUS 0x40
2014-09-17 09:18:41 -07:00
# define GPIO_PORTA_DEBOUNCE 0x48
2014-02-25 17:01:01 -06:00
# define GPIO_PORTA_EOI 0x4c
# define GPIO_EXT_PORTA 0x50
# define GPIO_EXT_PORTB 0x54
# define GPIO_EXT_PORTC 0x58
# define GPIO_EXT_PORTD 0x5c
# define DWAPB_MAX_PORTS 4
# define GPIO_EXT_PORT_SIZE (GPIO_EXT_PORTB - GPIO_EXT_PORTA)
# define GPIO_SWPORT_DR_SIZE (GPIO_SWPORTB_DR - GPIO_SWPORTA_DR)
# define GPIO_SWPORT_DDR_SIZE (GPIO_SWPORTB_DDR - GPIO_SWPORTA_DDR)
struct dwapb_gpio ;
2014-09-17 09:18:42 -07:00
# ifdef CONFIG_PM_SLEEP
/* Store GPIO context across system-wide suspend/resume transitions */
struct dwapb_context {
u32 data ;
u32 dir ;
u32 ext ;
u32 int_en ;
u32 int_mask ;
u32 int_type ;
u32 int_pol ;
u32 int_deb ;
} ;
# endif
2014-02-25 17:01:01 -06:00
struct dwapb_gpio_port {
struct bgpio_chip bgc ;
bool is_registered ;
struct dwapb_gpio * gpio ;
2014-09-17 09:18:42 -07:00
# ifdef CONFIG_PM_SLEEP
struct dwapb_context * ctx ;
# endif
unsigned int idx ;
2014-02-25 17:01:01 -06:00
} ;
struct dwapb_gpio {
struct device * dev ;
void __iomem * regs ;
struct dwapb_gpio_port * ports ;
unsigned int nr_ports ;
struct irq_domain * domain ;
} ;
2014-09-17 09:18:41 -07:00
static inline struct dwapb_gpio_port *
to_dwapb_gpio_port ( struct bgpio_chip * bgc )
{
return container_of ( bgc , struct dwapb_gpio_port , bgc ) ;
}
2014-09-17 09:18:40 -07:00
static inline u32 dwapb_read ( struct dwapb_gpio * gpio , unsigned int offset )
{
struct bgpio_chip * bgc = & gpio - > ports [ 0 ] . bgc ;
void __iomem * reg_base = gpio - > regs ;
return bgc - > read_reg ( reg_base + offset ) ;
}
static inline void dwapb_write ( struct dwapb_gpio * gpio , unsigned int offset ,
u32 val )
{
struct bgpio_chip * bgc = & gpio - > ports [ 0 ] . bgc ;
void __iomem * reg_base = gpio - > regs ;
bgc - > write_reg ( reg_base + offset , val ) ;
}
2014-02-25 17:01:01 -06:00
static int dwapb_gpio_to_irq ( struct gpio_chip * gc , unsigned offset )
{
struct bgpio_chip * bgc = to_bgpio_chip ( gc ) ;
2014-09-17 09:18:41 -07:00
struct dwapb_gpio_port * port = to_dwapb_gpio_port ( bgc ) ;
2014-02-25 17:01:01 -06:00
struct dwapb_gpio * gpio = port - > gpio ;
return irq_find_mapping ( gpio - > domain , offset ) ;
}
static void dwapb_toggle_trigger ( struct dwapb_gpio * gpio , unsigned int offs )
{
2014-09-17 09:18:40 -07:00
u32 v = dwapb_read ( gpio , GPIO_INT_POLARITY ) ;
2014-02-25 17:01:01 -06:00
if ( gpio_get_value ( gpio - > ports [ 0 ] . bgc . gc . base + offs ) )
v & = ~ BIT ( offs ) ;
else
v | = BIT ( offs ) ;
2014-09-17 09:18:40 -07:00
dwapb_write ( gpio , GPIO_INT_POLARITY , v ) ;
2014-02-25 17:01:01 -06:00
}
2014-09-17 09:18:39 -07:00
static u32 dwapb_do_irq ( struct dwapb_gpio * gpio )
2014-02-25 17:01:01 -06:00
{
u32 irq_status = readl_relaxed ( gpio - > regs + GPIO_INTSTATUS ) ;
2014-09-17 09:18:39 -07:00
u32 ret = irq_status ;
2014-02-25 17:01:01 -06:00
while ( irq_status ) {
int hwirq = fls ( irq_status ) - 1 ;
int gpio_irq = irq_find_mapping ( gpio - > domain , hwirq ) ;
generic_handle_irq ( gpio_irq ) ;
irq_status & = ~ BIT ( hwirq ) ;
if ( ( irq_get_trigger_type ( gpio_irq ) & IRQ_TYPE_SENSE_MASK )
= = IRQ_TYPE_EDGE_BOTH )
dwapb_toggle_trigger ( gpio , hwirq ) ;
}
2014-09-17 09:18:39 -07:00
return ret ;
}
2015-09-14 10:42:37 +02:00
static void dwapb_irq_handler ( struct irq_desc * desc )
2014-09-17 09:18:39 -07:00
{
2015-06-04 12:13:15 +08:00
struct dwapb_gpio * gpio = irq_desc_get_handler_data ( desc ) ;
2014-09-17 09:18:39 -07:00
struct irq_chip * chip = irq_desc_get_chip ( desc ) ;
dwapb_do_irq ( gpio ) ;
2014-02-25 17:01:01 -06:00
if ( chip - > irq_eoi )
chip - > irq_eoi ( irq_desc_get_irq_data ( desc ) ) ;
}
static void dwapb_irq_enable ( struct irq_data * d )
{
struct irq_chip_generic * igc = irq_data_get_irq_chip_data ( d ) ;
struct dwapb_gpio * gpio = igc - > private ;
struct bgpio_chip * bgc = & gpio - > ports [ 0 ] . bgc ;
unsigned long flags ;
u32 val ;
spin_lock_irqsave ( & bgc - > lock , flags ) ;
2014-09-17 09:18:40 -07:00
val = dwapb_read ( gpio , GPIO_INTEN ) ;
2014-02-25 17:01:01 -06:00
val | = BIT ( d - > hwirq ) ;
2014-09-17 09:18:40 -07:00
dwapb_write ( gpio , GPIO_INTEN , val ) ;
2014-02-25 17:01:01 -06:00
spin_unlock_irqrestore ( & bgc - > lock , flags ) ;
}
static void dwapb_irq_disable ( struct irq_data * d )
{
struct irq_chip_generic * igc = irq_data_get_irq_chip_data ( d ) ;
struct dwapb_gpio * gpio = igc - > private ;
struct bgpio_chip * bgc = & gpio - > ports [ 0 ] . bgc ;
unsigned long flags ;
u32 val ;
spin_lock_irqsave ( & bgc - > lock , flags ) ;
2014-09-17 09:18:40 -07:00
val = dwapb_read ( gpio , GPIO_INTEN ) ;
2014-02-25 17:01:01 -06:00
val & = ~ BIT ( d - > hwirq ) ;
2014-09-17 09:18:40 -07:00
dwapb_write ( gpio , GPIO_INTEN , val ) ;
2014-02-25 17:01:01 -06:00
spin_unlock_irqrestore ( & bgc - > lock , flags ) ;
}
2014-03-14 18:16:20 +01:00
static int dwapb_irq_reqres ( struct irq_data * d )
2014-02-25 17:01:01 -06:00
{
struct irq_chip_generic * igc = irq_data_get_irq_chip_data ( d ) ;
struct dwapb_gpio * gpio = igc - > private ;
struct bgpio_chip * bgc = & gpio - > ports [ 0 ] . bgc ;
2014-10-23 17:27:07 +09:00
if ( gpiochip_lock_as_irq ( & bgc - > gc , irqd_to_hwirq ( d ) ) ) {
2014-02-25 17:01:01 -06:00
dev_err ( gpio - > dev , " unable to lock HW IRQ %lu for IRQ \n " ,
irqd_to_hwirq ( d ) ) ;
2014-03-14 18:16:20 +01:00
return - EINVAL ;
}
2014-02-25 17:01:01 -06:00
return 0 ;
}
2014-03-14 18:16:20 +01:00
static void dwapb_irq_relres ( struct irq_data * d )
2014-02-25 17:01:01 -06:00
{
struct irq_chip_generic * igc = irq_data_get_irq_chip_data ( d ) ;
struct dwapb_gpio * gpio = igc - > private ;
struct bgpio_chip * bgc = & gpio - > ports [ 0 ] . bgc ;
2014-10-23 17:27:07 +09:00
gpiochip_unlock_as_irq ( & bgc - > gc , irqd_to_hwirq ( d ) ) ;
2014-02-25 17:01:01 -06:00
}
static int dwapb_irq_set_type ( struct irq_data * d , u32 type )
{
struct irq_chip_generic * igc = irq_data_get_irq_chip_data ( d ) ;
struct dwapb_gpio * gpio = igc - > private ;
struct bgpio_chip * bgc = & gpio - > ports [ 0 ] . bgc ;
int bit = d - > hwirq ;
unsigned long level , polarity , flags ;
if ( type & ~ ( IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING |
IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW ) )
return - EINVAL ;
spin_lock_irqsave ( & bgc - > lock , flags ) ;
2014-09-17 09:18:40 -07:00
level = dwapb_read ( gpio , GPIO_INTTYPE_LEVEL ) ;
polarity = dwapb_read ( gpio , GPIO_INT_POLARITY ) ;
2014-02-25 17:01:01 -06:00
switch ( type ) {
case IRQ_TYPE_EDGE_BOTH :
level | = BIT ( bit ) ;
dwapb_toggle_trigger ( gpio , bit ) ;
break ;
case IRQ_TYPE_EDGE_RISING :
level | = BIT ( bit ) ;
polarity | = BIT ( bit ) ;
break ;
case IRQ_TYPE_EDGE_FALLING :
level | = BIT ( bit ) ;
polarity & = ~ BIT ( bit ) ;
break ;
case IRQ_TYPE_LEVEL_HIGH :
level & = ~ BIT ( bit ) ;
polarity | = BIT ( bit ) ;
break ;
case IRQ_TYPE_LEVEL_LOW :
level & = ~ BIT ( bit ) ;
polarity & = ~ BIT ( bit ) ;
break ;
}
2014-05-26 22:58:14 +02:00
irq_setup_alt_chip ( d , type ) ;
2014-09-17 09:18:40 -07:00
dwapb_write ( gpio , GPIO_INTTYPE_LEVEL , level ) ;
dwapb_write ( gpio , GPIO_INT_POLARITY , polarity ) ;
2014-02-25 17:01:01 -06:00
spin_unlock_irqrestore ( & bgc - > lock , flags ) ;
return 0 ;
}
2014-09-17 09:18:41 -07:00
static int dwapb_gpio_set_debounce ( struct gpio_chip * gc ,
unsigned offset , unsigned debounce )
{
struct bgpio_chip * bgc = to_bgpio_chip ( gc ) ;
struct dwapb_gpio_port * port = to_dwapb_gpio_port ( bgc ) ;
struct dwapb_gpio * gpio = port - > gpio ;
unsigned long flags , val_deb ;
unsigned long mask = bgc - > pin2mask ( bgc , offset ) ;
spin_lock_irqsave ( & bgc - > lock , flags ) ;
val_deb = dwapb_read ( gpio , GPIO_PORTA_DEBOUNCE ) ;
if ( debounce )
dwapb_write ( gpio , GPIO_PORTA_DEBOUNCE , val_deb | mask ) ;
else
dwapb_write ( gpio , GPIO_PORTA_DEBOUNCE , val_deb & ~ mask ) ;
spin_unlock_irqrestore ( & bgc - > lock , flags ) ;
return 0 ;
}
2014-09-17 09:18:39 -07:00
static irqreturn_t dwapb_irq_handler_mfd ( int irq , void * dev_id )
{
u32 worked ;
struct dwapb_gpio * gpio = dev_id ;
worked = dwapb_do_irq ( gpio ) ;
return worked ? IRQ_HANDLED : IRQ_NONE ;
}
2014-02-25 17:01:01 -06:00
static void dwapb_configure_irqs ( struct dwapb_gpio * gpio ,
2014-09-17 09:18:39 -07:00
struct dwapb_gpio_port * port ,
struct dwapb_port_property * pp )
2014-02-25 17:01:01 -06:00
{
struct gpio_chip * gc = & port - > bgc . gc ;
2014-09-17 09:18:39 -07:00
struct device_node * node = pp - > node ;
struct irq_chip_generic * irq_gc = NULL ;
2014-02-25 17:01:01 -06:00
unsigned int hwirq , ngpio = gc - > ngpio ;
struct irq_chip_type * ct ;
2014-09-17 09:18:39 -07:00
int err , i ;
2014-02-25 17:01:01 -06:00
gpio - > domain = irq_domain_add_linear ( node , ngpio ,
& irq_generic_chip_ops , gpio ) ;
if ( ! gpio - > domain )
return ;
2014-05-26 22:58:14 +02:00
err = irq_alloc_domain_generic_chips ( gpio - > domain , ngpio , 2 ,
2014-02-25 17:01:01 -06:00
" gpio-dwapb " , handle_level_irq ,
IRQ_NOREQUEST , 0 ,
IRQ_GC_INIT_NESTED_LOCK ) ;
if ( err ) {
dev_info ( gpio - > dev , " irq_alloc_domain_generic_chips failed \n " ) ;
irq_domain_remove ( gpio - > domain ) ;
gpio - > domain = NULL ;
return ;
}
irq_gc = irq_get_domain_generic_chip ( gpio - > domain , 0 ) ;
if ( ! irq_gc ) {
irq_domain_remove ( gpio - > domain ) ;
gpio - > domain = NULL ;
return ;
}
irq_gc - > reg_base = gpio - > regs ;
irq_gc - > private = gpio ;
2014-05-26 22:58:14 +02:00
for ( i = 0 ; i < 2 ; i + + ) {
ct = & irq_gc - > chip_types [ i ] ;
ct - > chip . irq_ack = irq_gc_ack_set_bit ;
ct - > chip . irq_mask = irq_gc_mask_set_bit ;
ct - > chip . irq_unmask = irq_gc_mask_clr_bit ;
ct - > chip . irq_set_type = dwapb_irq_set_type ;
ct - > chip . irq_enable = dwapb_irq_enable ;
ct - > chip . irq_disable = dwapb_irq_disable ;
ct - > chip . irq_request_resources = dwapb_irq_reqres ;
ct - > chip . irq_release_resources = dwapb_irq_relres ;
ct - > regs . ack = GPIO_PORTA_EOI ;
ct - > regs . mask = GPIO_INTMASK ;
ct - > type = IRQ_TYPE_LEVEL_MASK ;
}
irq_gc - > chip_types [ 0 ] . type = IRQ_TYPE_LEVEL_MASK ;
irq_gc - > chip_types [ 1 ] . type = IRQ_TYPE_EDGE_BOTH ;
irq_gc - > chip_types [ 1 ] . handler = handle_edge_irq ;
2014-02-25 17:01:01 -06:00
2014-09-17 09:18:39 -07:00
if ( ! pp - > irq_shared ) {
gpio/dwapb: Fix race in installing chained IRQ handler
Fix a race where a pending interrupt could be received and the handler
called before the handler's data has been setup, by converting to
irq_set_chained_handler_and_data().
Search and conversion was done with coccinelle:
@@
expression E1, E2, E3;
@@
(
-if (irq_set_chained_handler(E1, E3) != 0)
- BUG();
|
-irq_set_chained_handler(E1, E3);
)
-irq_set_handler_data(E1, E2);
+irq_set_chained_handler_and_data(E1, E3, E2);
@@
expression E1, E2, E3;
@@
(
-if (irq_set_chained_handler(E1, E3) != 0)
- BUG();
...
|
-irq_set_chained_handler(E1, E3);
...
)
-irq_set_handler_data(E1, E2);
+irq_set_chained_handler_and_data(E1, E3, E2);
Reported-by: Russell King <rmk+kernel@arm.linux.org.uk>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Cc: Julia Lawall <Julia.Lawall@lip6.fr>
Cc: Linus Walleij <linus.walleij@linaro.org>
Cc: Alexandre Courbot <gnurou@gmail.com>
Cc: linux-gpio@vger.kernel.org
2015-06-21 20:16:05 +02:00
irq_set_chained_handler_and_data ( pp - > irq , dwapb_irq_handler ,
gpio ) ;
2014-09-17 09:18:39 -07:00
} else {
/*
* Request a shared IRQ since where MFD would have devices
* using the same irq pin
*/
err = devm_request_irq ( gpio - > dev , pp - > irq ,
dwapb_irq_handler_mfd ,
IRQF_SHARED , " gpio-dwapb-mfd " , gpio ) ;
if ( err ) {
dev_err ( gpio - > dev , " error requesting IRQ \n " ) ;
irq_domain_remove ( gpio - > domain ) ;
gpio - > domain = NULL ;
return ;
}
}
2014-02-25 17:01:01 -06:00
for ( hwirq = 0 ; hwirq < ngpio ; hwirq + + )
irq_create_mapping ( gpio - > domain , hwirq ) ;
port - > bgc . gc . to_irq = dwapb_gpio_to_irq ;
}
static void dwapb_irq_teardown ( struct dwapb_gpio * gpio )
{
struct dwapb_gpio_port * port = & gpio - > ports [ 0 ] ;
struct gpio_chip * gc = & port - > bgc . gc ;
unsigned int ngpio = gc - > ngpio ;
irq_hw_number_t hwirq ;
if ( ! gpio - > domain )
return ;
for ( hwirq = 0 ; hwirq < ngpio ; hwirq + + )
irq_dispose_mapping ( irq_find_mapping ( gpio - > domain , hwirq ) ) ;
irq_domain_remove ( gpio - > domain ) ;
gpio - > domain = NULL ;
}
static int dwapb_gpio_add_port ( struct dwapb_gpio * gpio ,
2014-09-17 09:18:39 -07:00
struct dwapb_port_property * pp ,
2014-02-25 17:01:01 -06:00
unsigned int offs )
{
struct dwapb_gpio_port * port ;
void __iomem * dat , * set , * dirout ;
int err ;
port = & gpio - > ports [ offs ] ;
port - > gpio = gpio ;
2014-09-17 09:18:42 -07:00
port - > idx = pp - > idx ;
# ifdef CONFIG_PM_SLEEP
port - > ctx = devm_kzalloc ( gpio - > dev , sizeof ( * port - > ctx ) , GFP_KERNEL ) ;
if ( ! port - > ctx )
return - ENOMEM ;
# endif
2014-02-25 17:01:01 -06:00
2014-09-17 09:18:39 -07:00
dat = gpio - > regs + GPIO_EXT_PORTA + ( pp - > idx * GPIO_EXT_PORT_SIZE ) ;
set = gpio - > regs + GPIO_SWPORTA_DR + ( pp - > idx * GPIO_SWPORT_DR_SIZE ) ;
2014-02-25 17:01:01 -06:00
dirout = gpio - > regs + GPIO_SWPORTA_DDR +
2014-09-17 09:18:39 -07:00
( pp - > idx * GPIO_SWPORT_DDR_SIZE ) ;
2014-02-25 17:01:01 -06:00
err = bgpio_init ( & port - > bgc , gpio - > dev , 4 , dat , set , NULL , dirout ,
NULL , false ) ;
if ( err ) {
dev_err ( gpio - > dev , " failed to init gpio chip for %s \n " ,
2014-09-17 09:18:39 -07:00
pp - > name ) ;
2014-02-25 17:01:01 -06:00
return err ;
}
2014-09-17 09:18:39 -07:00
# ifdef CONFIG_OF_GPIO
port - > bgc . gc . of_node = pp - > node ;
# endif
port - > bgc . gc . ngpio = pp - > ngpio ;
port - > bgc . gc . base = pp - > gpio_base ;
2014-02-25 17:01:01 -06:00
2014-09-17 09:18:41 -07:00
/* Only port A support debounce */
if ( pp - > idx = = 0 )
port - > bgc . gc . set_debounce = dwapb_gpio_set_debounce ;
2014-09-17 09:18:39 -07:00
if ( pp - > irq )
dwapb_configure_irqs ( gpio , port , pp ) ;
2014-02-25 17:01:01 -06:00
err = gpiochip_add ( & port - > bgc . gc ) ;
if ( err )
dev_err ( gpio - > dev , " failed to register gpiochip for %s \n " ,
2014-09-17 09:18:39 -07:00
pp - > name ) ;
2014-02-25 17:01:01 -06:00
else
port - > is_registered = true ;
return err ;
}
static void dwapb_gpio_unregister ( struct dwapb_gpio * gpio )
{
unsigned int m ;
for ( m = 0 ; m < gpio - > nr_ports ; + + m )
if ( gpio - > ports [ m ] . is_registered )
2014-07-12 22:30:12 +02:00
gpiochip_remove ( & gpio - > ports [ m ] . bgc . gc ) ;
2014-02-25 17:01:01 -06:00
}
2014-09-17 09:18:39 -07:00
static struct dwapb_platform_data *
dwapb_gpio_get_pdata_of ( struct device * dev )
{
struct device_node * node , * port_np ;
struct dwapb_platform_data * pdata ;
struct dwapb_port_property * pp ;
int nports ;
int i ;
node = dev - > of_node ;
if ( ! IS_ENABLED ( CONFIG_OF_GPIO ) | | ! node )
return ERR_PTR ( - ENODEV ) ;
nports = of_get_child_count ( node ) ;
if ( nports = = 0 )
return ERR_PTR ( - ENODEV ) ;
2014-12-28 15:23:14 +08:00
pdata = devm_kzalloc ( dev , sizeof ( * pdata ) , GFP_KERNEL ) ;
2014-09-17 09:18:39 -07:00
if ( ! pdata )
return ERR_PTR ( - ENOMEM ) ;
2014-12-28 15:23:14 +08:00
pdata - > properties = devm_kcalloc ( dev , nports , sizeof ( * pp ) , GFP_KERNEL ) ;
if ( ! pdata - > properties )
2014-09-17 09:18:39 -07:00
return ERR_PTR ( - ENOMEM ) ;
pdata - > nports = nports ;
i = 0 ;
for_each_child_of_node ( node , port_np ) {
pp = & pdata - > properties [ i + + ] ;
pp - > node = port_np ;
if ( of_property_read_u32 ( port_np , " reg " , & pp - > idx ) | |
pp - > idx > = DWAPB_MAX_PORTS ) {
dev_err ( dev , " missing/invalid port index for %s \n " ,
port_np - > full_name ) ;
return ERR_PTR ( - EINVAL ) ;
}
if ( of_property_read_u32 ( port_np , " snps,nr-gpios " ,
& pp - > ngpio ) ) {
dev_info ( dev , " failed to get number of gpios for %s \n " ,
port_np - > full_name ) ;
pp - > ngpio = 32 ;
}
/*
* Only port A can provide interrupts in all configurations of
* the IP .
*/
if ( pp - > idx = = 0 & &
of_property_read_bool ( port_np , " interrupt-controller " ) ) {
pp - > irq = irq_of_parse_and_map ( port_np , 0 ) ;
if ( ! pp - > irq ) {
dev_warn ( dev , " no irq for bank %s \n " ,
port_np - > full_name ) ;
}
}
pp - > irq_shared = false ;
pp - > gpio_base = - 1 ;
pp - > name = port_np - > full_name ;
}
return pdata ;
}
2014-02-25 17:01:01 -06:00
static int dwapb_gpio_probe ( struct platform_device * pdev )
{
2014-09-17 09:18:39 -07:00
unsigned int i ;
2014-02-25 17:01:01 -06:00
struct resource * res ;
struct dwapb_gpio * gpio ;
int err ;
2014-09-17 09:18:39 -07:00
struct device * dev = & pdev - > dev ;
struct dwapb_platform_data * pdata = dev_get_platdata ( dev ) ;
2014-12-28 15:23:14 +08:00
if ( ! pdata ) {
2014-09-17 09:18:39 -07:00
pdata = dwapb_gpio_get_pdata_of ( dev ) ;
if ( IS_ERR ( pdata ) )
return PTR_ERR ( pdata ) ;
}
2014-02-25 17:01:01 -06:00
2014-12-28 15:23:14 +08:00
if ( ! pdata - > nports )
return - ENODEV ;
2014-02-25 17:01:01 -06:00
2014-09-17 09:18:39 -07:00
gpio = devm_kzalloc ( & pdev - > dev , sizeof ( * gpio ) , GFP_KERNEL ) ;
2014-12-28 15:23:14 +08:00
if ( ! gpio )
return - ENOMEM ;
2014-09-17 09:18:39 -07:00
gpio - > dev = & pdev - > dev ;
gpio - > nr_ports = pdata - > nports ;
gpio - > ports = devm_kcalloc ( & pdev - > dev , gpio - > nr_ports ,
2014-02-25 17:01:01 -06:00
sizeof ( * gpio - > ports ) , GFP_KERNEL ) ;
2014-12-28 15:23:14 +08:00
if ( ! gpio - > ports )
return - ENOMEM ;
2014-02-25 17:01:01 -06:00
res = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
gpio - > regs = devm_ioremap_resource ( & pdev - > dev , res ) ;
2014-12-28 15:23:14 +08:00
if ( IS_ERR ( gpio - > regs ) )
return PTR_ERR ( gpio - > regs ) ;
2014-02-25 17:01:01 -06:00
2014-09-17 09:18:39 -07:00
for ( i = 0 ; i < gpio - > nr_ports ; i + + ) {
err = dwapb_gpio_add_port ( gpio , & pdata - > properties [ i ] , i ) ;
2014-02-25 17:01:01 -06:00
if ( err )
goto out_unregister ;
}
platform_set_drvdata ( pdev , gpio ) ;
2014-12-28 15:23:14 +08:00
return 0 ;
2014-02-25 17:01:01 -06:00
out_unregister :
dwapb_gpio_unregister ( gpio ) ;
dwapb_irq_teardown ( gpio ) ;
return err ;
}
static int dwapb_gpio_remove ( struct platform_device * pdev )
{
struct dwapb_gpio * gpio = platform_get_drvdata ( pdev ) ;
dwapb_gpio_unregister ( gpio ) ;
dwapb_irq_teardown ( gpio ) ;
return 0 ;
}
static const struct of_device_id dwapb_of_match [ ] = {
{ . compatible = " snps,dw-apb-gpio " } ,
{ /* Sentinel */ }
} ;
MODULE_DEVICE_TABLE ( of , dwapb_of_match ) ;
2014-09-17 09:18:42 -07:00
# ifdef CONFIG_PM_SLEEP
static int dwapb_gpio_suspend ( struct device * dev )
{
struct platform_device * pdev = to_platform_device ( dev ) ;
struct dwapb_gpio * gpio = platform_get_drvdata ( pdev ) ;
struct bgpio_chip * bgc = & gpio - > ports [ 0 ] . bgc ;
unsigned long flags ;
int i ;
spin_lock_irqsave ( & bgc - > lock , flags ) ;
for ( i = 0 ; i < gpio - > nr_ports ; i + + ) {
unsigned int offset ;
unsigned int idx = gpio - > ports [ i ] . idx ;
struct dwapb_context * ctx = gpio - > ports [ i ] . ctx ;
2014-09-24 13:30:24 +02:00
BUG_ON ( ! ctx ) ;
2014-09-17 09:18:42 -07:00
offset = GPIO_SWPORTA_DDR + idx * GPIO_SWPORT_DDR_SIZE ;
ctx - > dir = dwapb_read ( gpio , offset ) ;
offset = GPIO_SWPORTA_DR + idx * GPIO_SWPORT_DR_SIZE ;
ctx - > data = dwapb_read ( gpio , offset ) ;
offset = GPIO_EXT_PORTA + idx * GPIO_EXT_PORT_SIZE ;
ctx - > ext = dwapb_read ( gpio , offset ) ;
/* Only port A can provide interrupts */
if ( idx = = 0 ) {
ctx - > int_mask = dwapb_read ( gpio , GPIO_INTMASK ) ;
ctx - > int_en = dwapb_read ( gpio , GPIO_INTEN ) ;
ctx - > int_pol = dwapb_read ( gpio , GPIO_INT_POLARITY ) ;
ctx - > int_type = dwapb_read ( gpio , GPIO_INTTYPE_LEVEL ) ;
ctx - > int_deb = dwapb_read ( gpio , GPIO_PORTA_DEBOUNCE ) ;
/* Mask out interrupts */
dwapb_write ( gpio , GPIO_INTMASK , 0xffffffff ) ;
}
}
spin_unlock_irqrestore ( & bgc - > lock , flags ) ;
return 0 ;
}
static int dwapb_gpio_resume ( struct device * dev )
{
struct platform_device * pdev = to_platform_device ( dev ) ;
struct dwapb_gpio * gpio = platform_get_drvdata ( pdev ) ;
struct bgpio_chip * bgc = & gpio - > ports [ 0 ] . bgc ;
unsigned long flags ;
int i ;
spin_lock_irqsave ( & bgc - > lock , flags ) ;
for ( i = 0 ; i < gpio - > nr_ports ; i + + ) {
unsigned int offset ;
unsigned int idx = gpio - > ports [ i ] . idx ;
struct dwapb_context * ctx = gpio - > ports [ i ] . ctx ;
2014-09-24 13:30:24 +02:00
BUG_ON ( ! ctx ) ;
2014-09-17 09:18:42 -07:00
offset = GPIO_SWPORTA_DR + idx * GPIO_SWPORT_DR_SIZE ;
dwapb_write ( gpio , offset , ctx - > data ) ;
offset = GPIO_SWPORTA_DDR + idx * GPIO_SWPORT_DDR_SIZE ;
dwapb_write ( gpio , offset , ctx - > dir ) ;
offset = GPIO_EXT_PORTA + idx * GPIO_EXT_PORT_SIZE ;
dwapb_write ( gpio , offset , ctx - > ext ) ;
/* Only port A can provide interrupts */
if ( idx = = 0 ) {
dwapb_write ( gpio , GPIO_INTTYPE_LEVEL , ctx - > int_type ) ;
dwapb_write ( gpio , GPIO_INT_POLARITY , ctx - > int_pol ) ;
dwapb_write ( gpio , GPIO_PORTA_DEBOUNCE , ctx - > int_deb ) ;
dwapb_write ( gpio , GPIO_INTEN , ctx - > int_en ) ;
dwapb_write ( gpio , GPIO_INTMASK , ctx - > int_mask ) ;
/* Clear out spurious interrupts */
dwapb_write ( gpio , GPIO_PORTA_EOI , 0xffffffff ) ;
}
}
spin_unlock_irqrestore ( & bgc - > lock , flags ) ;
return 0 ;
}
# endif
static SIMPLE_DEV_PM_OPS ( dwapb_gpio_pm_ops , dwapb_gpio_suspend ,
dwapb_gpio_resume ) ;
2014-02-25 17:01:01 -06:00
static struct platform_driver dwapb_gpio_driver = {
. driver = {
. name = " gpio-dwapb " ,
2014-09-17 09:18:42 -07:00
. pm = & dwapb_gpio_pm_ops ,
2014-02-25 17:01:01 -06:00
. of_match_table = of_match_ptr ( dwapb_of_match ) ,
} ,
. probe = dwapb_gpio_probe ,
. remove = dwapb_gpio_remove ,
} ;
module_platform_driver ( dwapb_gpio_driver ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_AUTHOR ( " Jamie Iles " ) ;
MODULE_DESCRIPTION ( " Synopsys DesignWare APB GPIO driver " ) ;