2019-06-04 10:11:33 +02:00
// SPDX-License-Identifier: GPL-2.0-only
2009-06-18 16:48:58 -07:00
/*
2011-06-04 18:38:28 -06:00
* Copyright ( C ) 2008 , 2009 Provigent Ltd .
2009-06-18 16:48:58 -07:00
*
2016-03-27 11:44:46 -04:00
* Author : Baruch Siach < baruch @ tkos . co . il >
*
2009-06-18 16:48:58 -07:00
* Driver for the ARM PrimeCell ( tm ) General Purpose Input / Output ( PL061 )
*
* Data sheet : ARM DDI 01 90 B , September 2000
*/
2022-10-07 16:44:44 +03:00
# include <linux/amba/bus.h>
# include <linux/bitops.h>
# include <linux/device.h>
2009-06-18 16:48:58 -07:00
# include <linux/errno.h>
2022-10-07 16:44:44 +03:00
# include <linux/gpio/driver.h>
2016-03-27 11:44:46 -04:00
# include <linux/init.h>
2022-10-07 16:44:44 +03:00
# include <linux/interrupt.h>
2009-06-18 16:48:58 -07:00
# include <linux/io.h>
# include <linux/ioport.h>
# include <linux/irq.h>
2013-01-18 15:31:37 +00:00
# include <linux/irqchip/chained_irq.h>
2020-04-08 19:41:10 -06:00
# include <linux/module.h>
2013-02-17 19:42:51 +08:00
# include <linux/pinctrl/consumer.h>
2011-11-18 15:20:12 +05:30
# include <linux/pm.h>
2022-10-07 16:44:44 +03:00
# include <linux/seq_file.h>
# include <linux/slab.h>
# include <linux/spinlock.h>
2009-06-18 16:48:58 -07:00
# define GPIODIR 0x400
# define GPIOIS 0x404
# define GPIOIBE 0x408
# define GPIOIEV 0x40C
# define GPIOIE 0x410
# define GPIORIS 0x414
# define GPIOMIS 0x418
# define GPIOIC 0x41C
# define PL061_GPIO_NR 8
2011-11-18 15:20:12 +05:30
# ifdef CONFIG_PM
struct pl061_context_save_regs {
u8 gpio_data ;
u8 gpio_dir ;
u8 gpio_is ;
u8 gpio_ibe ;
u8 gpio_iev ;
u8 gpio_ie ;
} ;
# endif
2009-06-18 16:48:58 -07:00
2016-11-25 10:43:15 +01:00
struct pl061 {
2017-03-09 10:21:56 -06:00
raw_spinlock_t lock ;
2009-06-18 16:48:58 -07:00
void __iomem * base ;
struct gpio_chip gc ;
2016-11-25 10:41:37 +01:00
int parent_irq ;
2011-11-18 15:20:12 +05:30
# ifdef CONFIG_PM
struct pl061_context_save_regs csave_regs ;
# endif
2009-06-18 16:48:58 -07:00
} ;
2016-04-28 13:18:59 +02:00
static int pl061_get_direction ( struct gpio_chip * gc , unsigned offset )
{
2016-11-25 10:48:40 +01:00
struct pl061 * pl061 = gpiochip_get_data ( gc ) ;
2016-04-28 13:18:59 +02:00
2019-11-06 10:54:12 +02:00
if ( readb ( pl061 - > base + GPIODIR ) & BIT ( offset ) )
return GPIO_LINE_DIRECTION_OUT ;
return GPIO_LINE_DIRECTION_IN ;
2016-04-28 13:18:59 +02:00
}
2009-06-18 16:48:58 -07:00
static int pl061_direction_input ( struct gpio_chip * gc , unsigned offset )
{
2016-11-25 10:48:40 +01:00
struct pl061 * pl061 = gpiochip_get_data ( gc ) ;
2009-06-18 16:48:58 -07:00
unsigned long flags ;
unsigned char gpiodir ;
2017-03-09 10:21:56 -06:00
raw_spin_lock_irqsave ( & pl061 - > lock , flags ) ;
2016-11-25 10:48:40 +01:00
gpiodir = readb ( pl061 - > base + GPIODIR ) ;
2014-04-27 02:00:50 +02:00
gpiodir & = ~ ( BIT ( offset ) ) ;
2016-11-25 10:48:40 +01:00
writeb ( gpiodir , pl061 - > base + GPIODIR ) ;
2017-03-09 10:21:56 -06:00
raw_spin_unlock_irqrestore ( & pl061 - > lock , flags ) ;
2009-06-18 16:48:58 -07:00
return 0 ;
}
static int pl061_direction_output ( struct gpio_chip * gc , unsigned offset ,
int value )
{
2016-11-25 10:48:40 +01:00
struct pl061 * pl061 = gpiochip_get_data ( gc ) ;
2009-06-18 16:48:58 -07:00
unsigned long flags ;
unsigned char gpiodir ;
2017-03-09 10:21:56 -06:00
raw_spin_lock_irqsave ( & pl061 - > lock , flags ) ;
2016-11-25 10:48:40 +01:00
writeb ( ! ! value < < offset , pl061 - > base + ( BIT ( offset + 2 ) ) ) ;
gpiodir = readb ( pl061 - > base + GPIODIR ) ;
2014-04-27 02:00:50 +02:00
gpiodir | = BIT ( offset ) ;
2016-11-25 10:48:40 +01:00
writeb ( gpiodir , pl061 - > base + GPIODIR ) ;
2010-04-21 09:42:05 +01:00
/*
* gpio value is set again , because pl061 doesn ' t allow to set value of
* a gpio pin before configuring it in OUT mode .
*/
2016-11-25 10:48:40 +01:00
writeb ( ! ! value < < offset , pl061 - > base + ( BIT ( offset + 2 ) ) ) ;
2017-03-09 10:21:56 -06:00
raw_spin_unlock_irqrestore ( & pl061 - > lock , flags ) ;
2009-06-18 16:48:58 -07:00
return 0 ;
}
static int pl061_get_value ( struct gpio_chip * gc , unsigned offset )
{
2016-11-25 10:48:40 +01:00
struct pl061 * pl061 = gpiochip_get_data ( gc ) ;
2009-06-18 16:48:58 -07:00
2016-11-25 10:48:40 +01:00
return ! ! readb ( pl061 - > base + ( BIT ( offset + 2 ) ) ) ;
2009-06-18 16:48:58 -07:00
}
static void pl061_set_value ( struct gpio_chip * gc , unsigned offset , int value )
{
2016-11-25 10:48:40 +01:00
struct pl061 * pl061 = gpiochip_get_data ( gc ) ;
2009-06-18 16:48:58 -07:00
2016-11-25 10:48:40 +01:00
writeb ( ! ! value < < offset , pl061 - > base + ( BIT ( offset + 2 ) ) ) ;
2009-06-18 16:48:58 -07:00
}
2011-01-12 17:00:16 -08:00
static int pl061_irq_type ( struct irq_data * d , unsigned trigger )
2009-06-18 16:48:58 -07:00
{
2014-03-25 10:42:35 +01:00
struct gpio_chip * gc = irq_data_get_irq_chip_data ( d ) ;
2016-11-25 10:48:40 +01:00
struct pl061 * pl061 = gpiochip_get_data ( gc ) ;
2013-02-17 19:42:49 +08:00
int offset = irqd_to_hwirq ( d ) ;
2009-06-18 16:48:58 -07:00
unsigned long flags ;
u8 gpiois , gpioibe , gpioiev ;
2013-11-26 12:59:51 +01:00
u8 bit = BIT ( offset ) ;
2009-06-18 16:48:58 -07:00
2010-05-26 14:42:19 -07:00
if ( offset < 0 | | offset > = PL061_GPIO_NR )
2009-06-18 16:48:58 -07:00
return - EINVAL ;
2015-09-17 14:21:25 +02:00
if ( ( trigger & ( IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW ) ) & &
( trigger & ( IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING ) ) )
{
2015-11-04 09:56:26 +01:00
dev_err ( gc - > parent ,
2015-09-17 14:21:25 +02:00
" trying to configure line %d for both level and edge "
" detection, choose one! \n " ,
offset ) ;
return - EINVAL ;
}
2015-10-08 10:12:01 +03:00
2017-03-09 10:21:56 -06:00
raw_spin_lock_irqsave ( & pl061 - > lock , flags ) ;
2015-10-08 10:12:01 +03:00
2016-11-25 10:48:40 +01:00
gpioiev = readb ( pl061 - > base + GPIOIEV ) ;
gpiois = readb ( pl061 - > base + GPIOIS ) ;
gpioibe = readb ( pl061 - > base + GPIOIBE ) ;
2015-10-08 10:12:01 +03:00
2009-06-18 16:48:58 -07:00
if ( trigger & ( IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW ) ) {
2015-09-17 14:21:25 +02:00
bool polarity = trigger & IRQ_TYPE_LEVEL_HIGH ;
/* Disable edge detection */
gpioibe & = ~ bit ;
/* Enable level detection */
2013-11-26 12:59:51 +01:00
gpiois | = bit ;
2015-09-17 14:21:25 +02:00
/* Select polarity */
if ( polarity )
2013-11-26 12:59:51 +01:00
gpioiev | = bit ;
2009-06-18 16:48:58 -07:00
else
2013-11-26 12:59:51 +01:00
gpioiev & = ~ bit ;
2015-09-24 17:52:52 -07:00
irq_set_handler_locked ( d , handle_level_irq ) ;
2015-11-04 09:56:26 +01:00
dev_dbg ( gc - > parent , " line %d: IRQ on %s level \n " ,
2015-09-17 14:21:25 +02:00
offset ,
polarity ? " HIGH " : " LOW " ) ;
} else if ( ( trigger & IRQ_TYPE_EDGE_BOTH ) = = IRQ_TYPE_EDGE_BOTH ) {
/* Disable level detection */
gpiois & = ~ bit ;
/* Select both edges, setting this makes GPIOEV be ignored */
2013-11-26 12:59:51 +01:00
gpioibe | = bit ;
2015-09-24 17:52:52 -07:00
irq_set_handler_locked ( d , handle_edge_irq ) ;
2015-11-04 09:56:26 +01:00
dev_dbg ( gc - > parent , " line %d: IRQ on both edges \n " , offset ) ;
2015-09-17 14:21:25 +02:00
} else if ( ( trigger & IRQ_TYPE_EDGE_RISING ) | |
( trigger & IRQ_TYPE_EDGE_FALLING ) ) {
bool rising = trigger & IRQ_TYPE_EDGE_RISING ;
/* Disable level detection */
gpiois & = ~ bit ;
/* Clear detection on both edges */
2013-11-26 12:59:51 +01:00
gpioibe & = ~ bit ;
2015-09-17 14:21:25 +02:00
/* Select edge */
if ( rising )
2013-11-26 12:59:51 +01:00
gpioiev | = bit ;
2015-09-17 14:21:25 +02:00
else
2013-11-26 12:59:51 +01:00
gpioiev & = ~ bit ;
2015-09-24 17:52:52 -07:00
irq_set_handler_locked ( d , handle_edge_irq ) ;
2015-11-04 09:56:26 +01:00
dev_dbg ( gc - > parent , " line %d: IRQ on %s edge \n " ,
2015-09-17 14:21:25 +02:00
offset ,
rising ? " RISING " : " FALLING " ) ;
} else {
/* No trigger: disable everything */
gpiois & = ~ bit ;
gpioibe & = ~ bit ;
gpioiev & = ~ bit ;
2015-09-24 17:52:52 -07:00
irq_set_handler_locked ( d , handle_bad_irq ) ;
2015-11-04 09:56:26 +01:00
dev_warn ( gc - > parent , " no trigger selected for line %d \n " ,
2015-09-17 14:21:25 +02:00
offset ) ;
2009-06-18 16:48:58 -07:00
}
2016-11-25 10:48:40 +01:00
writeb ( gpiois , pl061 - > base + GPIOIS ) ;
writeb ( gpioibe , pl061 - > base + GPIOIBE ) ;
writeb ( gpioiev , pl061 - > base + GPIOIEV ) ;
2009-06-18 16:48:58 -07:00
2017-03-09 10:21:56 -06:00
raw_spin_unlock_irqrestore ( & pl061 - > lock , flags ) ;
2009-06-18 16:48:58 -07:00
return 0 ;
}
2015-09-14 10:42:37 +02:00
static void pl061_irq_handler ( struct irq_desc * desc )
2009-06-18 16:48:58 -07:00
{
2012-01-04 10:36:07 -06:00
unsigned long pending ;
int offset ;
2014-03-25 10:42:35 +01:00
struct gpio_chip * gc = irq_desc_get_handler_data ( desc ) ;
2016-11-25 10:48:40 +01:00
struct pl061 * pl061 = gpiochip_get_data ( gc ) ;
2011-12-09 14:12:53 -06:00
struct irq_chip * irqchip = irq_desc_get_chip ( desc ) ;
2009-06-18 16:48:58 -07:00
2011-12-09 14:12:53 -06:00
chained_irq_enter ( irqchip , desc ) ;
2009-06-18 16:48:58 -07:00
2016-11-25 10:48:40 +01:00
pending = readb ( pl061 - > base + GPIOMIS ) ;
2012-01-04 10:36:07 -06:00
if ( pending ) {
2010-03-05 13:41:37 -08:00
for_each_set_bit ( offset , & pending , PL061_GPIO_NR )
2021-05-04 17:42:18 +01:00
generic_handle_domain_irq ( gc - > irq . domain ,
offset ) ;
2009-06-18 16:48:58 -07:00
}
2012-01-04 10:36:07 -06:00
2011-12-09 14:12:53 -06:00
chained_irq_exit ( irqchip , desc ) ;
2009-06-18 16:48:58 -07:00
}
2013-02-17 19:42:49 +08:00
static void pl061_irq_mask ( struct irq_data * d )
2011-10-21 08:05:53 -05:00
{
2014-03-25 10:42:35 +01:00
struct gpio_chip * gc = irq_data_get_irq_chip_data ( d ) ;
2016-11-25 10:48:40 +01:00
struct pl061 * pl061 = gpiochip_get_data ( gc ) ;
2014-04-27 02:00:50 +02:00
u8 mask = BIT ( irqd_to_hwirq ( d ) % PL061_GPIO_NR ) ;
2013-02-17 19:42:49 +08:00
u8 gpioie ;
2017-03-09 10:21:56 -06:00
raw_spin_lock ( & pl061 - > lock ) ;
2016-11-25 10:48:40 +01:00
gpioie = readb ( pl061 - > base + GPIOIE ) & ~ mask ;
writeb ( gpioie , pl061 - > base + GPIOIE ) ;
2017-03-09 10:21:56 -06:00
raw_spin_unlock ( & pl061 - > lock ) ;
2022-04-19 15:18:41 +01:00
gpiochip_disable_irq ( gc , d - > hwirq ) ;
2013-02-17 19:42:49 +08:00
}
2011-10-21 08:05:53 -05:00
2013-02-17 19:42:49 +08:00
static void pl061_irq_unmask ( struct irq_data * d )
{
2014-03-25 10:42:35 +01:00
struct gpio_chip * gc = irq_data_get_irq_chip_data ( d ) ;
2016-11-25 10:48:40 +01:00
struct pl061 * pl061 = gpiochip_get_data ( gc ) ;
2014-04-27 02:00:50 +02:00
u8 mask = BIT ( irqd_to_hwirq ( d ) % PL061_GPIO_NR ) ;
2013-02-17 19:42:49 +08:00
u8 gpioie ;
2022-04-19 15:18:41 +01:00
gpiochip_enable_irq ( gc , d - > hwirq ) ;
2017-03-09 10:21:56 -06:00
raw_spin_lock ( & pl061 - > lock ) ;
2016-11-25 10:48:40 +01:00
gpioie = readb ( pl061 - > base + GPIOIE ) | mask ;
writeb ( gpioie , pl061 - > base + GPIOIE ) ;
2017-03-09 10:21:56 -06:00
raw_spin_unlock ( & pl061 - > lock ) ;
2013-02-17 19:42:49 +08:00
}
2015-09-24 17:52:52 -07:00
/**
* pl061_irq_ack ( ) - ACK an edge IRQ
* @ d : IRQ data for this IRQ
*
* This gets called from the edge IRQ handler to ACK the edge IRQ
* in the GPIOIC ( interrupt - clear ) register . For level IRQs this is
* not needed : these go away when the level signal goes away .
*/
static void pl061_irq_ack ( struct irq_data * d )
{
struct gpio_chip * gc = irq_data_get_irq_chip_data ( d ) ;
2016-11-25 10:48:40 +01:00
struct pl061 * pl061 = gpiochip_get_data ( gc ) ;
2015-09-24 17:52:52 -07:00
u8 mask = BIT ( irqd_to_hwirq ( d ) % PL061_GPIO_NR ) ;
2017-03-09 10:21:56 -06:00
raw_spin_lock ( & pl061 - > lock ) ;
2016-11-25 10:48:40 +01:00
writeb ( mask , pl061 - > base + GPIOIC ) ;
2017-03-09 10:21:56 -06:00
raw_spin_unlock ( & pl061 - > lock ) ;
2015-09-24 17:52:52 -07:00
}
2015-11-27 17:19:15 +00:00
static int pl061_irq_set_wake ( struct irq_data * d , unsigned int state )
{
struct gpio_chip * gc = irq_data_get_irq_chip_data ( d ) ;
2016-11-25 10:48:40 +01:00
struct pl061 * pl061 = gpiochip_get_data ( gc ) ;
2015-11-27 17:19:15 +00:00
2016-11-25 10:48:40 +01:00
return irq_set_irq_wake ( pl061 - > parent_irq , state ) ;
2015-11-27 17:19:15 +00:00
}
2022-04-19 15:18:41 +01:00
static void pl061_irq_print_chip ( struct irq_data * data , struct seq_file * p )
{
struct gpio_chip * gc = irq_data_get_irq_chip_data ( data ) ;
seq_printf ( p , dev_name ( gc - > parent ) ) ;
}
static const struct irq_chip pl061_irq_chip = {
. irq_ack = pl061_irq_ack ,
. irq_mask = pl061_irq_mask ,
. irq_unmask = pl061_irq_unmask ,
. irq_set_type = pl061_irq_type ,
. irq_set_wake = pl061_irq_set_wake ,
. irq_print_chip = pl061_irq_print_chip ,
. flags = IRQCHIP_IMMUTABLE ,
GPIOCHIP_IRQ_RESOURCE_HELPERS ,
} ;
2012-10-05 11:45:28 +02:00
static int pl061_probe ( struct amba_device * adev , const struct amba_id * id )
2009-06-18 16:48:58 -07:00
{
2012-10-05 11:45:28 +02:00
struct device * dev = & adev - > dev ;
2016-11-25 10:48:40 +01:00
struct pl061 * pl061 ;
2019-06-25 13:15:02 +02:00
struct gpio_irq_chip * girq ;
2016-11-25 11:02:19 +01:00
int ret , irq ;
2009-06-18 16:48:58 -07:00
2016-11-25 10:48:40 +01:00
pl061 = devm_kzalloc ( dev , sizeof ( * pl061 ) , GFP_KERNEL ) ;
if ( pl061 = = NULL )
2009-06-18 16:48:58 -07:00
return - ENOMEM ;
2016-11-25 10:48:40 +01:00
pl061 - > base = devm_ioremap_resource ( dev , & adev - > res ) ;
if ( IS_ERR ( pl061 - > base ) )
return PTR_ERR ( pl061 - > base ) ;
2009-06-18 16:48:58 -07:00
2017-03-09 10:21:56 -06:00
raw_spin_lock_init ( & pl061 - > lock ) ;
2020-04-01 22:05:26 +02:00
pl061 - > gc . request = gpiochip_generic_request ;
pl061 - > gc . free = gpiochip_generic_free ;
2016-11-25 11:02:19 +01:00
pl061 - > gc . base = - 1 ;
2016-11-25 10:48:40 +01:00
pl061 - > gc . get_direction = pl061_get_direction ;
pl061 - > gc . direction_input = pl061_direction_input ;
pl061 - > gc . direction_output = pl061_direction_output ;
pl061 - > gc . get = pl061_get_value ;
pl061 - > gc . set = pl061_set_value ;
pl061 - > gc . ngpio = PL061_GPIO_NR ;
pl061 - > gc . label = dev_name ( dev ) ;
pl061 - > gc . parent = dev ;
pl061 - > gc . owner = THIS_MODULE ;
2009-06-18 16:48:58 -07:00
/*
* irq_chip support
*/
2016-11-25 10:48:40 +01:00
writeb ( 0 , pl061 - > base + GPIOIE ) ; /* disable irqs */
2012-10-05 11:45:28 +02:00
irq = adev - > irq [ 0 ] ;
2020-03-03 10:28:28 +01:00
if ( ! irq )
dev_warn ( & adev - > dev , " IRQ support disabled \n " ) ;
2016-11-25 10:48:40 +01:00
pl061 - > parent_irq = irq ;
2012-10-05 11:45:28 +02:00
2019-06-25 13:15:02 +02:00
girq = & pl061 - > gc . irq ;
2022-04-19 15:18:41 +01:00
gpio_irq_chip_set_chip ( girq , & pl061_irq_chip ) ;
2019-06-25 13:15:02 +02:00
girq - > parent_handler = pl061_irq_handler ;
girq - > num_parents = 1 ;
girq - > parents = devm_kcalloc ( dev , 1 , sizeof ( * girq - > parents ) ,
GFP_KERNEL ) ;
if ( ! girq - > parents )
return - ENOMEM ;
girq - > parents [ 0 ] = irq ;
girq - > default_type = IRQ_TYPE_NONE ;
girq - > handler = handle_bad_irq ;
ret = devm_gpiochip_add_data ( dev , & pl061 - > gc , pl061 ) ;
if ( ret )
2014-03-25 10:42:35 +01:00
return ret ;
2013-11-27 08:47:02 +01:00
2016-11-25 10:48:40 +01:00
amba_set_drvdata ( adev , pl061 ) ;
2019-07-03 11:42:24 +02:00
dev_info ( dev , " PL061 GPIO chip registered \n " ) ;
2011-11-18 15:20:12 +05:30
2009-06-18 16:48:58 -07:00
return 0 ;
}
2011-11-18 15:20:12 +05:30
# ifdef CONFIG_PM
static int pl061_suspend ( struct device * dev )
{
2016-11-25 10:48:40 +01:00
struct pl061 * pl061 = dev_get_drvdata ( dev ) ;
2011-11-18 15:20:12 +05:30
int offset ;
2016-11-25 10:48:40 +01:00
pl061 - > csave_regs . gpio_data = 0 ;
pl061 - > csave_regs . gpio_dir = readb ( pl061 - > base + GPIODIR ) ;
pl061 - > csave_regs . gpio_is = readb ( pl061 - > base + GPIOIS ) ;
pl061 - > csave_regs . gpio_ibe = readb ( pl061 - > base + GPIOIBE ) ;
pl061 - > csave_regs . gpio_iev = readb ( pl061 - > base + GPIOIEV ) ;
pl061 - > csave_regs . gpio_ie = readb ( pl061 - > base + GPIOIE ) ;
2011-11-18 15:20:12 +05:30
for ( offset = 0 ; offset < PL061_GPIO_NR ; offset + + ) {
2016-11-25 10:48:40 +01:00
if ( pl061 - > csave_regs . gpio_dir & ( BIT ( offset ) ) )
pl061 - > csave_regs . gpio_data | =
pl061_get_value ( & pl061 - > gc , offset ) < < offset ;
2011-11-18 15:20:12 +05:30
}
return 0 ;
}
static int pl061_resume ( struct device * dev )
{
2016-11-25 10:48:40 +01:00
struct pl061 * pl061 = dev_get_drvdata ( dev ) ;
2011-11-18 15:20:12 +05:30
int offset ;
for ( offset = 0 ; offset < PL061_GPIO_NR ; offset + + ) {
2016-11-25 10:48:40 +01:00
if ( pl061 - > csave_regs . gpio_dir & ( BIT ( offset ) ) )
pl061_direction_output ( & pl061 - > gc , offset ,
pl061 - > csave_regs . gpio_data &
2014-04-27 02:00:50 +02:00
( BIT ( offset ) ) ) ;
2011-11-18 15:20:12 +05:30
else
2016-11-25 10:48:40 +01:00
pl061_direction_input ( & pl061 - > gc , offset ) ;
2011-11-18 15:20:12 +05:30
}
2016-11-25 10:48:40 +01:00
writeb ( pl061 - > csave_regs . gpio_is , pl061 - > base + GPIOIS ) ;
writeb ( pl061 - > csave_regs . gpio_ibe , pl061 - > base + GPIOIBE ) ;
writeb ( pl061 - > csave_regs . gpio_iev , pl061 - > base + GPIOIEV ) ;
writeb ( pl061 - > csave_regs . gpio_ie , pl061 - > base + GPIOIE ) ;
2011-11-18 15:20:12 +05:30
return 0 ;
}
2012-01-11 15:25:20 +05:30
static const struct dev_pm_ops pl061_dev_pm_ops = {
. suspend = pl061_suspend ,
. resume = pl061_resume ,
. freeze = pl061_suspend ,
. restore = pl061_resume ,
} ;
2011-11-18 15:20:12 +05:30
# endif
2017-08-23 21:45:09 +05:30
static const struct amba_id pl061_ids [ ] = {
2009-06-18 16:48:58 -07:00
{
. id = 0x00041061 ,
. mask = 0x000fffff ,
} ,
{ 0 , 0 } ,
} ;
2020-04-08 19:41:10 -06:00
MODULE_DEVICE_TABLE ( amba , pl061_ids ) ;
2009-06-18 16:48:58 -07:00
static struct amba_driver pl061_gpio_driver = {
. drv = {
. name = " pl061_gpio " ,
2011-11-18 15:20:12 +05:30
# ifdef CONFIG_PM
. pm = & pl061_dev_pm_ops ,
# endif
2009-06-18 16:48:58 -07:00
} ,
. id_table = pl061_ids ,
. probe = pl061_probe ,
} ;
2020-04-08 19:41:10 -06:00
module_amba_driver ( pl061_gpio_driver ) ;
2009-06-18 16:48:58 -07:00
2020-04-08 19:41:10 -06:00
MODULE_LICENSE ( " GPL v2 " ) ;