2019-06-04 11:11:33 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2009-06-19 03:48:58 +04:00
/*
2011-06-05 04:38:28 +04:00
* Copyright ( C ) 2008 , 2009 Provigent Ltd .
2009-06-19 03:48:58 +04:00
*
2016-03-27 18:44:46 +03:00
* Author : Baruch Siach < baruch @ tkos . co . il >
*
2009-06-19 03:48:58 +04: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-19 03:48:58 +04:00
# include <linux/errno.h>
2022-10-07 16:44:44 +03:00
# include <linux/gpio/driver.h>
2016-03-27 18:44:46 +03:00
# include <linux/init.h>
2022-10-07 16:44:44 +03:00
# include <linux/interrupt.h>
2009-06-19 03:48:58 +04:00
# include <linux/io.h>
# include <linux/ioport.h>
# include <linux/irq.h>
2013-01-18 19:31:37 +04:00
# include <linux/irqchip/chained_irq.h>
2020-04-09 04:41:10 +03:00
# include <linux/module.h>
2013-02-17 15:42:51 +04:00
# include <linux/pinctrl/consumer.h>
2011-11-18 13:50:12 +04:00
# 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-19 03:48:58 +04: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 13:50:12 +04:00
# 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-19 03:48:58 +04:00
2016-11-25 12:43:15 +03:00
struct pl061 {
2017-03-09 19:21:56 +03:00
raw_spinlock_t lock ;
2009-06-19 03:48:58 +04:00
void __iomem * base ;
struct gpio_chip gc ;
2016-11-25 12:41:37 +03:00
int parent_irq ;
2011-11-18 13:50:12 +04:00
# ifdef CONFIG_PM
struct pl061_context_save_regs csave_regs ;
# endif
2009-06-19 03:48:58 +04:00
} ;
2016-04-28 14:18:59 +03:00
static int pl061_get_direction ( struct gpio_chip * gc , unsigned offset )
{
2016-11-25 12:48:40 +03:00
struct pl061 * pl061 = gpiochip_get_data ( gc ) ;
2016-04-28 14:18:59 +03:00
2019-11-06 11:54:12 +03:00
if ( readb ( pl061 - > base + GPIODIR ) & BIT ( offset ) )
return GPIO_LINE_DIRECTION_OUT ;
return GPIO_LINE_DIRECTION_IN ;
2016-04-28 14:18:59 +03:00
}
2009-06-19 03:48:58 +04:00
static int pl061_direction_input ( struct gpio_chip * gc , unsigned offset )
{
2016-11-25 12:48:40 +03:00
struct pl061 * pl061 = gpiochip_get_data ( gc ) ;
2009-06-19 03:48:58 +04:00
unsigned long flags ;
unsigned char gpiodir ;
2017-03-09 19:21:56 +03:00
raw_spin_lock_irqsave ( & pl061 - > lock , flags ) ;
2016-11-25 12:48:40 +03:00
gpiodir = readb ( pl061 - > base + GPIODIR ) ;
2014-04-27 04:00:50 +04:00
gpiodir & = ~ ( BIT ( offset ) ) ;
2016-11-25 12:48:40 +03:00
writeb ( gpiodir , pl061 - > base + GPIODIR ) ;
2017-03-09 19:21:56 +03:00
raw_spin_unlock_irqrestore ( & pl061 - > lock , flags ) ;
2009-06-19 03:48:58 +04:00
return 0 ;
}
static int pl061_direction_output ( struct gpio_chip * gc , unsigned offset ,
int value )
{
2016-11-25 12:48:40 +03:00
struct pl061 * pl061 = gpiochip_get_data ( gc ) ;
2009-06-19 03:48:58 +04:00
unsigned long flags ;
unsigned char gpiodir ;
2017-03-09 19:21:56 +03:00
raw_spin_lock_irqsave ( & pl061 - > lock , flags ) ;
2016-11-25 12:48:40 +03:00
writeb ( ! ! value < < offset , pl061 - > base + ( BIT ( offset + 2 ) ) ) ;
gpiodir = readb ( pl061 - > base + GPIODIR ) ;
2014-04-27 04:00:50 +04:00
gpiodir | = BIT ( offset ) ;
2016-11-25 12:48:40 +03:00
writeb ( gpiodir , pl061 - > base + GPIODIR ) ;
2010-04-21 12:42:05 +04: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 12:48:40 +03:00
writeb ( ! ! value < < offset , pl061 - > base + ( BIT ( offset + 2 ) ) ) ;
2017-03-09 19:21:56 +03:00
raw_spin_unlock_irqrestore ( & pl061 - > lock , flags ) ;
2009-06-19 03:48:58 +04:00
return 0 ;
}
static int pl061_get_value ( struct gpio_chip * gc , unsigned offset )
{
2016-11-25 12:48:40 +03:00
struct pl061 * pl061 = gpiochip_get_data ( gc ) ;
2009-06-19 03:48:58 +04:00
2016-11-25 12:48:40 +03:00
return ! ! readb ( pl061 - > base + ( BIT ( offset + 2 ) ) ) ;
2009-06-19 03:48:58 +04:00
}
static void pl061_set_value ( struct gpio_chip * gc , unsigned offset , int value )
{
2016-11-25 12:48:40 +03:00
struct pl061 * pl061 = gpiochip_get_data ( gc ) ;
2009-06-19 03:48:58 +04:00
2016-11-25 12:48:40 +03:00
writeb ( ! ! value < < offset , pl061 - > base + ( BIT ( offset + 2 ) ) ) ;
2009-06-19 03:48:58 +04:00
}
2011-01-13 04:00:16 +03:00
static int pl061_irq_type ( struct irq_data * d , unsigned trigger )
2009-06-19 03:48:58 +04:00
{
2014-03-25 13:42:35 +04:00
struct gpio_chip * gc = irq_data_get_irq_chip_data ( d ) ;
2016-11-25 12:48:40 +03:00
struct pl061 * pl061 = gpiochip_get_data ( gc ) ;
2013-02-17 15:42:49 +04:00
int offset = irqd_to_hwirq ( d ) ;
2009-06-19 03:48:58 +04:00
unsigned long flags ;
u8 gpiois , gpioibe , gpioiev ;
2013-11-26 15:59:51 +04:00
u8 bit = BIT ( offset ) ;
2009-06-19 03:48:58 +04:00
2010-05-27 01:42:19 +04:00
if ( offset < 0 | | offset > = PL061_GPIO_NR )
2009-06-19 03:48:58 +04:00
return - EINVAL ;
2015-09-17 15:21:25 +03:00
if ( ( trigger & ( IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW ) ) & &
( trigger & ( IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING ) ) )
{
2015-11-04 11:56:26 +03:00
dev_err ( gc - > parent ,
2015-09-17 15:21:25 +03: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 19:21:56 +03:00
raw_spin_lock_irqsave ( & pl061 - > lock , flags ) ;
2015-10-08 10:12:01 +03:00
2016-11-25 12:48:40 +03: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-19 03:48:58 +04:00
if ( trigger & ( IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW ) ) {
2015-09-17 15:21:25 +03:00
bool polarity = trigger & IRQ_TYPE_LEVEL_HIGH ;
/* Disable edge detection */
gpioibe & = ~ bit ;
/* Enable level detection */
2013-11-26 15:59:51 +04:00
gpiois | = bit ;
2015-09-17 15:21:25 +03:00
/* Select polarity */
if ( polarity )
2013-11-26 15:59:51 +04:00
gpioiev | = bit ;
2009-06-19 03:48:58 +04:00
else
2013-11-26 15:59:51 +04:00
gpioiev & = ~ bit ;
2015-09-25 03:52:52 +03:00
irq_set_handler_locked ( d , handle_level_irq ) ;
2015-11-04 11:56:26 +03:00
dev_dbg ( gc - > parent , " line %d: IRQ on %s level \n " ,
2015-09-17 15:21:25 +03: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 15:59:51 +04:00
gpioibe | = bit ;
2015-09-25 03:52:52 +03:00
irq_set_handler_locked ( d , handle_edge_irq ) ;
2015-11-04 11:56:26 +03:00
dev_dbg ( gc - > parent , " line %d: IRQ on both edges \n " , offset ) ;
2015-09-17 15:21:25 +03: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 15:59:51 +04:00
gpioibe & = ~ bit ;
2015-09-17 15:21:25 +03:00
/* Select edge */
if ( rising )
2013-11-26 15:59:51 +04:00
gpioiev | = bit ;
2015-09-17 15:21:25 +03:00
else
2013-11-26 15:59:51 +04:00
gpioiev & = ~ bit ;
2015-09-25 03:52:52 +03:00
irq_set_handler_locked ( d , handle_edge_irq ) ;
2015-11-04 11:56:26 +03:00
dev_dbg ( gc - > parent , " line %d: IRQ on %s edge \n " ,
2015-09-17 15:21:25 +03:00
offset ,
rising ? " RISING " : " FALLING " ) ;
} else {
/* No trigger: disable everything */
gpiois & = ~ bit ;
gpioibe & = ~ bit ;
gpioiev & = ~ bit ;
2015-09-25 03:52:52 +03:00
irq_set_handler_locked ( d , handle_bad_irq ) ;
2015-11-04 11:56:26 +03:00
dev_warn ( gc - > parent , " no trigger selected for line %d \n " ,
2015-09-17 15:21:25 +03:00
offset ) ;
2009-06-19 03:48:58 +04:00
}
2016-11-25 12:48:40 +03:00
writeb ( gpiois , pl061 - > base + GPIOIS ) ;
writeb ( gpioibe , pl061 - > base + GPIOIBE ) ;
writeb ( gpioiev , pl061 - > base + GPIOIEV ) ;
2009-06-19 03:48:58 +04:00
2017-03-09 19:21:56 +03:00
raw_spin_unlock_irqrestore ( & pl061 - > lock , flags ) ;
2009-06-19 03:48:58 +04:00
return 0 ;
}
2015-09-14 11:42:37 +03:00
static void pl061_irq_handler ( struct irq_desc * desc )
2009-06-19 03:48:58 +04:00
{
2012-01-04 20:36:07 +04:00
unsigned long pending ;
int offset ;
2014-03-25 13:42:35 +04:00
struct gpio_chip * gc = irq_desc_get_handler_data ( desc ) ;
2016-11-25 12:48:40 +03:00
struct pl061 * pl061 = gpiochip_get_data ( gc ) ;
2011-12-10 00:12:53 +04:00
struct irq_chip * irqchip = irq_desc_get_chip ( desc ) ;
2009-06-19 03:48:58 +04:00
2011-12-10 00:12:53 +04:00
chained_irq_enter ( irqchip , desc ) ;
2009-06-19 03:48:58 +04:00
2016-11-25 12:48:40 +03:00
pending = readb ( pl061 - > base + GPIOMIS ) ;
2012-01-04 20:36:07 +04:00
if ( pending ) {
2010-03-06 00:41:37 +03:00
for_each_set_bit ( offset , & pending , PL061_GPIO_NR )
2021-05-04 19:42:18 +03:00
generic_handle_domain_irq ( gc - > irq . domain ,
offset ) ;
2009-06-19 03:48:58 +04:00
}
2012-01-04 20:36:07 +04:00
2011-12-10 00:12:53 +04:00
chained_irq_exit ( irqchip , desc ) ;
2009-06-19 03:48:58 +04:00
}
2013-02-17 15:42:49 +04:00
static void pl061_irq_mask ( struct irq_data * d )
2011-10-21 17:05:53 +04:00
{
2014-03-25 13:42:35 +04:00
struct gpio_chip * gc = irq_data_get_irq_chip_data ( d ) ;
2016-11-25 12:48:40 +03:00
struct pl061 * pl061 = gpiochip_get_data ( gc ) ;
2014-04-27 04:00:50 +04:00
u8 mask = BIT ( irqd_to_hwirq ( d ) % PL061_GPIO_NR ) ;
2013-02-17 15:42:49 +04:00
u8 gpioie ;
2017-03-09 19:21:56 +03:00
raw_spin_lock ( & pl061 - > lock ) ;
2016-11-25 12:48:40 +03:00
gpioie = readb ( pl061 - > base + GPIOIE ) & ~ mask ;
writeb ( gpioie , pl061 - > base + GPIOIE ) ;
2017-03-09 19:21:56 +03:00
raw_spin_unlock ( & pl061 - > lock ) ;
2022-04-19 17:18:41 +03:00
gpiochip_disable_irq ( gc , d - > hwirq ) ;
2013-02-17 15:42:49 +04:00
}
2011-10-21 17:05:53 +04:00
2013-02-17 15:42:49 +04:00
static void pl061_irq_unmask ( struct irq_data * d )
{
2014-03-25 13:42:35 +04:00
struct gpio_chip * gc = irq_data_get_irq_chip_data ( d ) ;
2016-11-25 12:48:40 +03:00
struct pl061 * pl061 = gpiochip_get_data ( gc ) ;
2014-04-27 04:00:50 +04:00
u8 mask = BIT ( irqd_to_hwirq ( d ) % PL061_GPIO_NR ) ;
2013-02-17 15:42:49 +04:00
u8 gpioie ;
2022-04-19 17:18:41 +03:00
gpiochip_enable_irq ( gc , d - > hwirq ) ;
2017-03-09 19:21:56 +03:00
raw_spin_lock ( & pl061 - > lock ) ;
2016-11-25 12:48:40 +03:00
gpioie = readb ( pl061 - > base + GPIOIE ) | mask ;
writeb ( gpioie , pl061 - > base + GPIOIE ) ;
2017-03-09 19:21:56 +03:00
raw_spin_unlock ( & pl061 - > lock ) ;
2013-02-17 15:42:49 +04:00
}
2015-09-25 03:52:52 +03: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 12:48:40 +03:00
struct pl061 * pl061 = gpiochip_get_data ( gc ) ;
2015-09-25 03:52:52 +03:00
u8 mask = BIT ( irqd_to_hwirq ( d ) % PL061_GPIO_NR ) ;
2017-03-09 19:21:56 +03:00
raw_spin_lock ( & pl061 - > lock ) ;
2016-11-25 12:48:40 +03:00
writeb ( mask , pl061 - > base + GPIOIC ) ;
2017-03-09 19:21:56 +03:00
raw_spin_unlock ( & pl061 - > lock ) ;
2015-09-25 03:52:52 +03:00
}
2015-11-27 20:19:15 +03: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 12:48:40 +03:00
struct pl061 * pl061 = gpiochip_get_data ( gc ) ;
2015-11-27 20:19:15 +03:00
2016-11-25 12:48:40 +03:00
return irq_set_irq_wake ( pl061 - > parent_irq , state ) ;
2015-11-27 20:19:15 +03:00
}
2022-04-19 17:18:41 +03: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 13:45:28 +04:00
static int pl061_probe ( struct amba_device * adev , const struct amba_id * id )
2009-06-19 03:48:58 +04:00
{
2012-10-05 13:45:28 +04:00
struct device * dev = & adev - > dev ;
2016-11-25 12:48:40 +03:00
struct pl061 * pl061 ;
2019-06-25 14:15:02 +03:00
struct gpio_irq_chip * girq ;
2016-11-25 13:02:19 +03:00
int ret , irq ;
2009-06-19 03:48:58 +04:00
2016-11-25 12:48:40 +03:00
pl061 = devm_kzalloc ( dev , sizeof ( * pl061 ) , GFP_KERNEL ) ;
if ( pl061 = = NULL )
2009-06-19 03:48:58 +04:00
return - ENOMEM ;
2016-11-25 12:48:40 +03:00
pl061 - > base = devm_ioremap_resource ( dev , & adev - > res ) ;
if ( IS_ERR ( pl061 - > base ) )
return PTR_ERR ( pl061 - > base ) ;
2009-06-19 03:48:58 +04:00
2017-03-09 19:21:56 +03:00
raw_spin_lock_init ( & pl061 - > lock ) ;
2020-04-01 23:05:26 +03:00
pl061 - > gc . request = gpiochip_generic_request ;
pl061 - > gc . free = gpiochip_generic_free ;
2016-11-25 13:02:19 +03:00
pl061 - > gc . base = - 1 ;
2016-11-25 12:48:40 +03: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-19 03:48:58 +04:00
/*
* irq_chip support
*/
2016-11-25 12:48:40 +03:00
writeb ( 0 , pl061 - > base + GPIOIE ) ; /* disable irqs */
2012-10-05 13:45:28 +04:00
irq = adev - > irq [ 0 ] ;
2020-03-03 12:28:28 +03:00
if ( ! irq )
dev_warn ( & adev - > dev , " IRQ support disabled \n " ) ;
2016-11-25 12:48:40 +03:00
pl061 - > parent_irq = irq ;
2012-10-05 13:45:28 +04:00
2019-06-25 14:15:02 +03:00
girq = & pl061 - > gc . irq ;
2022-04-19 17:18:41 +03:00
gpio_irq_chip_set_chip ( girq , & pl061_irq_chip ) ;
2019-06-25 14:15:02 +03: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 13:42:35 +04:00
return ret ;
2013-11-27 11:47:02 +04:00
2016-11-25 12:48:40 +03:00
amba_set_drvdata ( adev , pl061 ) ;
2019-07-03 12:42:24 +03:00
dev_info ( dev , " PL061 GPIO chip registered \n " ) ;
2011-11-18 13:50:12 +04:00
2009-06-19 03:48:58 +04:00
return 0 ;
}
2011-11-18 13:50:12 +04:00
# ifdef CONFIG_PM
static int pl061_suspend ( struct device * dev )
{
2016-11-25 12:48:40 +03:00
struct pl061 * pl061 = dev_get_drvdata ( dev ) ;
2011-11-18 13:50:12 +04:00
int offset ;
2016-11-25 12:48:40 +03: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 13:50:12 +04:00
for ( offset = 0 ; offset < PL061_GPIO_NR ; offset + + ) {
2016-11-25 12:48:40 +03:00
if ( pl061 - > csave_regs . gpio_dir & ( BIT ( offset ) ) )
pl061 - > csave_regs . gpio_data | =
pl061_get_value ( & pl061 - > gc , offset ) < < offset ;
2011-11-18 13:50:12 +04:00
}
return 0 ;
}
static int pl061_resume ( struct device * dev )
{
2016-11-25 12:48:40 +03:00
struct pl061 * pl061 = dev_get_drvdata ( dev ) ;
2011-11-18 13:50:12 +04:00
int offset ;
for ( offset = 0 ; offset < PL061_GPIO_NR ; offset + + ) {
2016-11-25 12:48:40 +03:00
if ( pl061 - > csave_regs . gpio_dir & ( BIT ( offset ) ) )
pl061_direction_output ( & pl061 - > gc , offset ,
pl061 - > csave_regs . gpio_data &
2014-04-27 04:00:50 +04:00
( BIT ( offset ) ) ) ;
2011-11-18 13:50:12 +04:00
else
2016-11-25 12:48:40 +03:00
pl061_direction_input ( & pl061 - > gc , offset ) ;
2011-11-18 13:50:12 +04:00
}
2016-11-25 12:48:40 +03: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 13:50:12 +04:00
return 0 ;
}
2012-01-11 13:55:20 +04:00
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 13:50:12 +04:00
# endif
2017-08-23 19:15:09 +03:00
static const struct amba_id pl061_ids [ ] = {
2009-06-19 03:48:58 +04:00
{
. id = 0x00041061 ,
. mask = 0x000fffff ,
} ,
{ 0 , 0 } ,
} ;
2020-04-09 04:41:10 +03:00
MODULE_DEVICE_TABLE ( amba , pl061_ids ) ;
2009-06-19 03:48:58 +04:00
static struct amba_driver pl061_gpio_driver = {
. drv = {
. name = " pl061_gpio " ,
2011-11-18 13:50:12 +04:00
# ifdef CONFIG_PM
. pm = & pl061_dev_pm_ops ,
# endif
2009-06-19 03:48:58 +04:00
} ,
. id_table = pl061_ids ,
. probe = pl061_probe ,
} ;
2020-04-09 04:41:10 +03:00
module_amba_driver ( pl061_gpio_driver ) ;
2009-06-19 03:48:58 +04:00
2020-04-09 04:41:10 +03:00
MODULE_LICENSE ( " GPL v2 " ) ;