2019-06-04 11:11:33 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2014-02-26 03:01:01 +04:00
/*
* Copyright ( c ) 2011 Jamie Iles
*
* All enquiries to support @ picochip . com
*/
gpio: dwapb: add gpio-signaled acpi event support
This patch adds gpio-signaled acpi event support. It is used for
power button on hisilicon D02 board, an arm64 platform.
The corresponding DSDT file is defined as follows:
Device(GPI0) {
Name(_HID, "HISI0181")
Name(_ADR, 0)
Name(_UID, 0)
Name (_CRS, ResourceTemplate () {
Memory32Fixed (ReadWrite, 0x802e0000, 0x10000)
Interrupt (ResourceConsumer, Level, ActiveHigh,
Exclusive,,,) {344}
})
Device(PRTa) {
Name (_DSD, Package () {
Package () {
Package () {"reg",0},
Package () {"snps,nr-gpios",32},
}
})
}
Name (_AEI, ResourceTemplate () {
GpioInt(Edge, ActiveLow, ExclusiveAndWake,
PullUp, , " \\_SB.GPI0") {8}
})
Method (_E08, 0x0, NotSerialized) {
Notify (\_SB.PWRB, 0x80)
}
}
Acked-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
Signed-off-by: Jiang Qiu <qiujiang@huawei.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
2016-04-28 12:32:03 +03:00
# include <linux/acpi.h>
2018-03-12 21:30:56 +03:00
# include <linux/clk.h>
2014-02-26 03:01:01 +04:00
# include <linux/err.h>
2018-03-12 21:30:56 +03:00
# include <linux/gpio/driver.h>
2014-02-26 03:01:01 +04:00
# 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>
2017-02-21 22:32:43 +03:00
# include <linux/of_device.h>
2014-02-26 03:01:01 +04:00
# include <linux/of_irq.h>
# include <linux/platform_device.h>
2016-04-28 12:32:02 +03:00
# include <linux/property.h>
2017-10-11 19:34:44 +03:00
# include <linux/reset.h>
2014-02-26 03:01:01 +04:00
# include <linux/spinlock.h>
2014-09-17 20:18:39 +04:00
# include <linux/platform_data/gpio-dwapb.h>
# include <linux/slab.h>
2014-02-26 03:01:01 +04:00
gpio: dwapb: add gpio-signaled acpi event support
This patch adds gpio-signaled acpi event support. It is used for
power button on hisilicon D02 board, an arm64 platform.
The corresponding DSDT file is defined as follows:
Device(GPI0) {
Name(_HID, "HISI0181")
Name(_ADR, 0)
Name(_UID, 0)
Name (_CRS, ResourceTemplate () {
Memory32Fixed (ReadWrite, 0x802e0000, 0x10000)
Interrupt (ResourceConsumer, Level, ActiveHigh,
Exclusive,,,) {344}
})
Device(PRTa) {
Name (_DSD, Package () {
Package () {
Package () {"reg",0},
Package () {"snps,nr-gpios",32},
}
})
}
Name (_AEI, ResourceTemplate () {
GpioInt(Edge, ActiveLow, ExclusiveAndWake,
PullUp, , " \\_SB.GPI0") {8}
})
Method (_E08, 0x0, NotSerialized) {
Notify (\_SB.PWRB, 0x80)
}
}
Acked-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
Signed-off-by: Jiang Qiu <qiujiang@huawei.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
2016-04-28 12:32:03 +03:00
# include "gpiolib.h"
2019-07-30 13:43:36 +03:00
# include "gpiolib-acpi.h"
gpio: dwapb: add gpio-signaled acpi event support
This patch adds gpio-signaled acpi event support. It is used for
power button on hisilicon D02 board, an arm64 platform.
The corresponding DSDT file is defined as follows:
Device(GPI0) {
Name(_HID, "HISI0181")
Name(_ADR, 0)
Name(_UID, 0)
Name (_CRS, ResourceTemplate () {
Memory32Fixed (ReadWrite, 0x802e0000, 0x10000)
Interrupt (ResourceConsumer, Level, ActiveHigh,
Exclusive,,,) {344}
})
Device(PRTa) {
Name (_DSD, Package () {
Package () {
Package () {"reg",0},
Package () {"snps,nr-gpios",32},
}
})
}
Name (_AEI, ResourceTemplate () {
GpioInt(Edge, ActiveLow, ExclusiveAndWake,
PullUp, , " \\_SB.GPI0") {8}
})
Method (_E08, 0x0, NotSerialized) {
Notify (\_SB.PWRB, 0x80)
}
}
Acked-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
Signed-off-by: Jiang Qiu <qiujiang@huawei.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
2016-04-28 12:32:03 +03:00
2014-02-26 03:01:01 +04: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 20:18:41 +04:00
# define GPIO_PORTA_DEBOUNCE 0x48
2014-02-26 03:01:01 +04: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
2020-04-15 17:15:21 +03:00
# define DWAPB_DRIVER_NAME "gpio-dwapb"
2014-02-26 03:01:01 +04:00
# define DWAPB_MAX_PORTS 4
2020-04-15 17:15:21 +03:00
2018-02-08 19:03:58 +03:00
# define GPIO_EXT_PORT_STRIDE 0x04 /* register stride 32 bits */
# define GPIO_SWPORT_DR_STRIDE 0x0c /* register stride 3*32 bits */
# define GPIO_SWPORT_DDR_STRIDE 0x0c /* register stride 3*32 bits */
2014-02-26 03:01:01 +04:00
2017-02-21 22:32:43 +03:00
# define GPIO_REG_OFFSET_V2 1
# define GPIO_INTMASK_V2 0x44
# define GPIO_INTTYPE_LEVEL_V2 0x34
# define GPIO_INT_POLARITY_V2 0x38
# define GPIO_INTSTATUS_V2 0x3c
# define GPIO_PORTA_EOI_V2 0x40
2020-03-23 22:54:00 +03:00
# define DWAPB_NR_CLOCKS 2
2014-02-26 03:01:01 +04:00
struct dwapb_gpio ;
2014-09-17 20:18:42 +04: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 ;
2017-09-09 01:41:15 +03:00
u32 wake_en ;
2014-09-17 20:18:42 +04:00
} ;
# endif
2014-02-26 03:01:01 +04:00
struct dwapb_gpio_port {
2015-12-04 16:02:58 +03:00
struct gpio_chip gc ;
2014-02-26 03:01:01 +04:00
bool is_registered ;
struct dwapb_gpio * gpio ;
2014-09-17 20:18:42 +04:00
# ifdef CONFIG_PM_SLEEP
struct dwapb_context * ctx ;
# endif
unsigned int idx ;
2014-02-26 03:01:01 +04:00
} ;
struct dwapb_gpio {
struct device * dev ;
void __iomem * regs ;
struct dwapb_gpio_port * ports ;
unsigned int nr_ports ;
struct irq_domain * domain ;
2017-02-21 22:32:43 +03:00
unsigned int flags ;
2017-10-11 19:34:44 +03:00
struct reset_control * rst ;
2020-03-23 22:54:00 +03:00
struct clk_bulk_data clks [ DWAPB_NR_CLOCKS ] ;
2014-02-26 03:01:01 +04:00
} ;
2017-02-21 22:32:43 +03:00
static inline u32 gpio_reg_v2_convert ( unsigned int offset )
{
switch ( offset ) {
case GPIO_INTMASK :
return GPIO_INTMASK_V2 ;
case GPIO_INTTYPE_LEVEL :
return GPIO_INTTYPE_LEVEL_V2 ;
case GPIO_INT_POLARITY :
return GPIO_INT_POLARITY_V2 ;
case GPIO_INTSTATUS :
return GPIO_INTSTATUS_V2 ;
case GPIO_PORTA_EOI :
return GPIO_PORTA_EOI_V2 ;
}
return offset ;
}
static inline u32 gpio_reg_convert ( struct dwapb_gpio * gpio , unsigned int offset )
{
if ( gpio - > flags & GPIO_REG_OFFSET_V2 )
return gpio_reg_v2_convert ( offset ) ;
return offset ;
}
2014-09-17 20:18:40 +04:00
static inline u32 dwapb_read ( struct dwapb_gpio * gpio , unsigned int offset )
{
2015-12-04 16:02:58 +03:00
struct gpio_chip * gc = & gpio - > ports [ 0 ] . gc ;
2014-09-17 20:18:40 +04:00
void __iomem * reg_base = gpio - > regs ;
2017-02-21 22:32:43 +03:00
return gc - > read_reg ( reg_base + gpio_reg_convert ( gpio , offset ) ) ;
2014-09-17 20:18:40 +04:00
}
static inline void dwapb_write ( struct dwapb_gpio * gpio , unsigned int offset ,
u32 val )
{
2015-12-04 16:02:58 +03:00
struct gpio_chip * gc = & gpio - > ports [ 0 ] . gc ;
2014-09-17 20:18:40 +04:00
void __iomem * reg_base = gpio - > regs ;
2017-02-21 22:32:43 +03:00
gc - > write_reg ( reg_base + gpio_reg_convert ( gpio , offset ) , val ) ;
2014-09-17 20:18:40 +04:00
}
2014-02-26 03:01:01 +04:00
static int dwapb_gpio_to_irq ( struct gpio_chip * gc , unsigned offset )
{
2015-12-04 16:02:58 +03:00
struct dwapb_gpio_port * port = gpiochip_get_data ( gc ) ;
2014-02-26 03:01:01 +04:00
struct dwapb_gpio * gpio = port - > gpio ;
return irq_find_mapping ( gpio - > domain , offset ) ;
}
2018-02-08 20:00:05 +03:00
static struct dwapb_gpio_port * dwapb_offs_to_port ( struct dwapb_gpio * gpio , unsigned int offs )
{
struct dwapb_gpio_port * port ;
int i ;
for ( i = 0 ; i < gpio - > nr_ports ; i + + ) {
port = & gpio - > ports [ i ] ;
if ( port - > idx = = offs / 32 )
return port ;
}
return NULL ;
}
2014-02-26 03:01:01 +04:00
static void dwapb_toggle_trigger ( struct dwapb_gpio * gpio , unsigned int offs )
{
2018-02-08 20:00:05 +03:00
struct dwapb_gpio_port * port = dwapb_offs_to_port ( gpio , offs ) ;
struct gpio_chip * gc ;
u32 pol ;
int val ;
if ( ! port )
return ;
gc = & port - > gc ;
2014-02-26 03:01:01 +04:00
2018-02-08 20:00:05 +03:00
pol = dwapb_read ( gpio , GPIO_INT_POLARITY ) ;
/* Just read the current value right out of the data register */
val = gc - > get ( gc , offs % 32 ) ;
if ( val )
pol & = ~ BIT ( offs ) ;
2014-02-26 03:01:01 +04:00
else
2018-02-08 20:00:05 +03:00
pol | = BIT ( offs ) ;
2014-02-26 03:01:01 +04:00
2018-02-08 20:00:05 +03:00
dwapb_write ( gpio , GPIO_INT_POLARITY , pol ) ;
2014-02-26 03:01:01 +04:00
}
2014-09-17 20:18:39 +04:00
static u32 dwapb_do_irq ( struct dwapb_gpio * gpio )
2014-02-26 03:01:01 +04:00
{
2020-04-15 17:15:22 +03:00
unsigned long irq_status ;
2020-04-15 17:15:26 +03:00
irq_hw_number_t hwirq ;
2014-02-26 03:01:01 +04:00
2020-04-15 17:15:22 +03:00
irq_status = dwapb_read ( gpio , GPIO_INTSTATUS ) ;
for_each_set_bit ( hwirq , & irq_status , 32 ) {
2014-02-26 03:01:01 +04:00
int gpio_irq = irq_find_mapping ( gpio - > domain , hwirq ) ;
2020-04-15 17:15:22 +03:00
u32 irq_type = irq_get_trigger_type ( gpio_irq ) ;
2014-02-26 03:01:01 +04:00
generic_handle_irq ( gpio_irq ) ;
2020-04-15 17:15:22 +03:00
if ( ( irq_type & IRQ_TYPE_SENSE_MASK ) = = IRQ_TYPE_EDGE_BOTH )
2014-02-26 03:01:01 +04:00
dwapb_toggle_trigger ( gpio , hwirq ) ;
}
2020-04-15 17:15:22 +03:00
return irq_status ;
2014-09-17 20:18:39 +04:00
}
2015-09-14 11:42:37 +03:00
static void dwapb_irq_handler ( struct irq_desc * desc )
2014-09-17 20:18:39 +04:00
{
2015-06-04 07:13:15 +03:00
struct dwapb_gpio * gpio = irq_desc_get_handler_data ( desc ) ;
2014-09-17 20:18:39 +04:00
struct irq_chip * chip = irq_desc_get_chip ( desc ) ;
2020-04-15 17:15:23 +03:00
chained_irq_enter ( chip , desc ) ;
2014-09-17 20:18:39 +04:00
dwapb_do_irq ( gpio ) ;
2020-04-15 17:15:23 +03:00
chained_irq_exit ( chip , desc ) ;
2014-02-26 03:01:01 +04:00
}
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 ;
2015-12-04 16:02:58 +03:00
struct gpio_chip * gc = & gpio - > ports [ 0 ] . gc ;
2014-02-26 03:01:01 +04:00
unsigned long flags ;
u32 val ;
2015-12-04 16:02:58 +03:00
spin_lock_irqsave ( & gc - > bgpio_lock , flags ) ;
2014-09-17 20:18:40 +04:00
val = dwapb_read ( gpio , GPIO_INTEN ) ;
2020-04-15 17:15:26 +03:00
val | = BIT ( irqd_to_hwirq ( d ) ) ;
2014-09-17 20:18:40 +04:00
dwapb_write ( gpio , GPIO_INTEN , val ) ;
2015-12-04 16:02:58 +03:00
spin_unlock_irqrestore ( & gc - > bgpio_lock , flags ) ;
2014-02-26 03:01:01 +04:00
}
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 ;
2015-12-04 16:02:58 +03:00
struct gpio_chip * gc = & gpio - > ports [ 0 ] . gc ;
2014-02-26 03:01:01 +04:00
unsigned long flags ;
u32 val ;
2015-12-04 16:02:58 +03:00
spin_lock_irqsave ( & gc - > bgpio_lock , flags ) ;
2014-09-17 20:18:40 +04:00
val = dwapb_read ( gpio , GPIO_INTEN ) ;
2020-04-15 17:15:26 +03:00
val & = ~ BIT ( irqd_to_hwirq ( d ) ) ;
2014-09-17 20:18:40 +04:00
dwapb_write ( gpio , GPIO_INTEN , val ) ;
2015-12-04 16:02:58 +03:00
spin_unlock_irqrestore ( & gc - > bgpio_lock , flags ) ;
2014-02-26 03:01:01 +04: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 ;
2015-12-04 16:02:58 +03:00
struct gpio_chip * gc = & gpio - > ports [ 0 ] . gc ;
2020-04-15 17:15:26 +03:00
irq_hw_number_t bit = irqd_to_hwirq ( d ) ;
2014-02-26 03:01:01 +04:00
unsigned long level , polarity , flags ;
2020-04-15 17:15:28 +03:00
if ( type & ~ IRQ_TYPE_SENSE_MASK )
2014-02-26 03:01:01 +04:00
return - EINVAL ;
2015-12-04 16:02:58 +03:00
spin_lock_irqsave ( & gc - > bgpio_lock , flags ) ;
2014-09-17 20:18:40 +04:00
level = dwapb_read ( gpio , GPIO_INTTYPE_LEVEL ) ;
polarity = dwapb_read ( gpio , GPIO_INT_POLARITY ) ;
2014-02-26 03:01:01 +04: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-27 00:58:14 +04:00
irq_setup_alt_chip ( d , type ) ;
2014-09-17 20:18:40 +04:00
dwapb_write ( gpio , GPIO_INTTYPE_LEVEL , level ) ;
2017-06-02 02:27:15 +03:00
if ( type ! = IRQ_TYPE_EDGE_BOTH )
dwapb_write ( gpio , GPIO_INT_POLARITY , polarity ) ;
2015-12-04 16:02:58 +03:00
spin_unlock_irqrestore ( & gc - > bgpio_lock , flags ) ;
2014-02-26 03:01:01 +04:00
return 0 ;
}
2017-09-09 01:41:15 +03:00
# ifdef CONFIG_PM_SLEEP
static int dwapb_irq_set_wake ( struct irq_data * d , unsigned int enable )
{
struct irq_chip_generic * igc = irq_data_get_irq_chip_data ( d ) ;
struct dwapb_gpio * gpio = igc - > private ;
struct dwapb_context * ctx = gpio - > ports [ 0 ] . ctx ;
2020-04-15 17:15:26 +03:00
irq_hw_number_t bit = irqd_to_hwirq ( d ) ;
2017-09-09 01:41:15 +03:00
if ( enable )
2020-04-15 17:15:26 +03:00
ctx - > wake_en | = BIT ( bit ) ;
2017-09-09 01:41:15 +03:00
else
2020-04-15 17:15:26 +03:00
ctx - > wake_en & = ~ BIT ( bit ) ;
2017-09-09 01:41:15 +03:00
return 0 ;
}
# endif
2014-09-17 20:18:41 +04:00
static int dwapb_gpio_set_debounce ( struct gpio_chip * gc ,
unsigned offset , unsigned debounce )
{
2015-12-04 16:02:58 +03:00
struct dwapb_gpio_port * port = gpiochip_get_data ( gc ) ;
2014-09-17 20:18:41 +04:00
struct dwapb_gpio * gpio = port - > gpio ;
unsigned long flags , val_deb ;
2017-10-20 13:26:51 +03:00
unsigned long mask = BIT ( offset ) ;
2014-09-17 20:18:41 +04:00
2015-12-04 16:02:58 +03:00
spin_lock_irqsave ( & gc - > bgpio_lock , flags ) ;
2014-09-17 20:18:41 +04:00
val_deb = dwapb_read ( gpio , GPIO_PORTA_DEBOUNCE ) ;
if ( debounce )
2020-04-15 17:15:29 +03:00
val_deb | = mask ;
2014-09-17 20:18:41 +04:00
else
2020-04-15 17:15:29 +03:00
val_deb & = ~ mask ;
dwapb_write ( gpio , GPIO_PORTA_DEBOUNCE , val_deb ) ;
2014-09-17 20:18:41 +04:00
2015-12-04 16:02:58 +03:00
spin_unlock_irqrestore ( & gc - > bgpio_lock , flags ) ;
2014-09-17 20:18:41 +04:00
return 0 ;
}
2017-01-23 15:34:34 +03:00
static int dwapb_gpio_set_config ( struct gpio_chip * gc , unsigned offset ,
unsigned long config )
{
u32 debounce ;
if ( pinconf_to_config_param ( config ) ! = PIN_CONFIG_INPUT_DEBOUNCE )
return - ENOTSUPP ;
debounce = pinconf_to_config_argument ( config ) ;
return dwapb_gpio_set_debounce ( gc , offset , debounce ) ;
}
2014-09-17 20:18:39 +04:00
static irqreturn_t dwapb_irq_handler_mfd ( int irq , void * dev_id )
{
2020-04-15 17:15:28 +03:00
return IRQ_RETVAL ( dwapb_do_irq ( dev_id ) ) ;
2014-09-17 20:18:39 +04:00
}
2014-02-26 03:01:01 +04:00
static void dwapb_configure_irqs ( struct dwapb_gpio * gpio ,
2014-09-17 20:18:39 +04:00
struct dwapb_gpio_port * port ,
struct dwapb_port_property * pp )
2014-02-26 03:01:01 +04:00
{
2015-12-04 16:02:58 +03:00
struct gpio_chip * gc = & port - > gc ;
2016-04-28 12:32:02 +03:00
struct fwnode_handle * fwnode = pp - > fwnode ;
2014-09-17 20:18:39 +04:00
struct irq_chip_generic * irq_gc = NULL ;
2020-04-15 17:15:26 +03:00
unsigned int ngpio = gc - > ngpio ;
2014-02-26 03:01:01 +04:00
struct irq_chip_type * ct ;
2020-04-15 17:15:26 +03:00
irq_hw_number_t hwirq ;
2014-09-17 20:18:39 +04:00
int err , i ;
2014-02-26 03:01:01 +04:00
2016-04-28 12:32:02 +03:00
gpio - > domain = irq_domain_create_linear ( fwnode , ngpio ,
& irq_generic_chip_ops , gpio ) ;
2014-02-26 03:01:01 +04:00
if ( ! gpio - > domain )
return ;
2014-05-27 00:58:14 +04:00
err = irq_alloc_domain_generic_chips ( gpio - > domain , ngpio , 2 ,
2020-04-15 17:15:24 +03:00
DWAPB_DRIVER_NAME , handle_bad_irq ,
2014-02-26 03:01:01 +04:00
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-27 00:58:14 +04: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 ;
2017-09-09 01:41:15 +03:00
# ifdef CONFIG_PM_SLEEP
ct - > chip . irq_set_wake = dwapb_irq_set_wake ;
# endif
2017-02-21 22:32:43 +03:00
ct - > regs . ack = gpio_reg_convert ( gpio , GPIO_PORTA_EOI ) ;
ct - > regs . mask = gpio_reg_convert ( gpio , GPIO_INTMASK ) ;
2014-05-27 00:58:14 +04:00
ct - > type = IRQ_TYPE_LEVEL_MASK ;
}
irq_gc - > chip_types [ 0 ] . type = IRQ_TYPE_LEVEL_MASK ;
2020-04-15 17:15:24 +03:00
irq_gc - > chip_types [ 0 ] . handler = handle_level_irq ;
2014-05-27 00:58:14 +04:00
irq_gc - > chip_types [ 1 ] . type = IRQ_TYPE_EDGE_BOTH ;
irq_gc - > chip_types [ 1 ] . handler = handle_edge_irq ;
2014-02-26 03:01:01 +04:00
2014-09-17 20:18:39 +04:00
if ( ! pp - > irq_shared ) {
2018-04-26 19:19:47 +03:00
int i ;
for ( i = 0 ; i < pp - > ngpio ; i + + ) {
2020-05-19 16:12:32 +03:00
if ( pp - > irq [ i ] )
2018-04-26 19:19:47 +03:00
irq_set_chained_handler_and_data ( pp - > irq [ i ] ,
dwapb_irq_handler , gpio ) ;
}
2014-09-17 20:18:39 +04:00
} else {
/*
* Request a shared IRQ since where MFD would have devices
* using the same irq pin
*/
2018-04-26 19:19:47 +03:00
err = devm_request_irq ( gpio - > dev , pp - > irq [ 0 ] ,
2014-09-17 20:18:39 +04:00
dwapb_irq_handler_mfd ,
2020-04-15 17:15:21 +03:00
IRQF_SHARED , DWAPB_DRIVER_NAME , gpio ) ;
2014-09-17 20:18:39 +04:00
if ( err ) {
dev_err ( gpio - > dev , " error requesting IRQ \n " ) ;
irq_domain_remove ( gpio - > domain ) ;
gpio - > domain = NULL ;
return ;
}
}
2014-02-26 03:01:01 +04:00
2020-04-22 14:06:54 +03:00
for ( hwirq = 0 ; hwirq < ngpio ; hwirq + + )
2014-02-26 03:01:01 +04:00
irq_create_mapping ( gpio - > domain , hwirq ) ;
2015-12-04 16:02:58 +03:00
port - > gc . to_irq = dwapb_gpio_to_irq ;
2014-02-26 03:01:01 +04:00
}
static void dwapb_irq_teardown ( struct dwapb_gpio * gpio )
{
struct dwapb_gpio_port * port = & gpio - > ports [ 0 ] ;
2015-12-04 16:02:58 +03:00
struct gpio_chip * gc = & port - > gc ;
2014-02-26 03:01:01 +04:00
unsigned int ngpio = gc - > ngpio ;
irq_hw_number_t hwirq ;
if ( ! gpio - > domain )
return ;
2020-04-22 14:06:54 +03:00
for ( hwirq = 0 ; hwirq < ngpio ; hwirq + + )
2014-02-26 03:01:01 +04:00
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 20:18:39 +04:00
struct dwapb_port_property * pp ,
2014-02-26 03:01:01 +04: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 20:18:42 +04: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-26 03:01:01 +04:00
2020-04-22 14:06:54 +03:00
dat = gpio - > regs + GPIO_EXT_PORTA + pp - > idx * GPIO_EXT_PORT_STRIDE ;
set = gpio - > regs + GPIO_SWPORTA_DR + pp - > idx * GPIO_SWPORT_DR_STRIDE ;
dirout = gpio - > regs + GPIO_SWPORTA_DDR + pp - > idx * GPIO_SWPORT_DDR_STRIDE ;
2014-02-26 03:01:01 +04:00
2018-02-08 20:00:05 +03:00
/* This registers 32 GPIO lines per port */
2015-12-04 16:02:58 +03:00
err = bgpio_init ( & port - > gc , gpio - > dev , 4 , dat , set , NULL , dirout ,
2017-10-20 13:26:51 +03:00
NULL , 0 ) ;
2014-02-26 03:01:01 +04:00
if ( err ) {
2016-04-28 12:32:01 +03:00
dev_err ( gpio - > dev , " failed to init gpio chip for port%d \n " ,
port - > idx ) ;
2014-02-26 03:01:01 +04:00
return err ;
}
2014-09-17 20:18:39 +04:00
# ifdef CONFIG_OF_GPIO
2016-04-28 12:32:02 +03:00
port - > gc . of_node = to_of_node ( pp - > fwnode ) ;
2014-09-17 20:18:39 +04:00
# endif
2015-12-04 16:02:58 +03:00
port - > gc . ngpio = pp - > ngpio ;
port - > gc . base = pp - > gpio_base ;
2014-02-26 03:01:01 +04:00
2014-09-17 20:18:41 +04:00
/* Only port A support debounce */
if ( pp - > idx = = 0 )
2017-01-23 15:34:34 +03:00
port - > gc . set_config = dwapb_gpio_set_config ;
2014-09-17 20:18:41 +04:00
2018-04-26 19:19:47 +03:00
if ( pp - > has_irq )
2014-09-17 20:18:39 +04:00
dwapb_configure_irqs ( gpio , port , pp ) ;
2014-02-26 03:01:01 +04:00
2015-12-04 16:02:58 +03:00
err = gpiochip_add_data ( & port - > gc , port ) ;
2020-05-19 16:12:30 +03:00
if ( err ) {
2016-04-28 12:32:01 +03:00
dev_err ( gpio - > dev , " failed to register gpiochip for port%d \n " ,
port - > idx ) ;
2020-05-19 16:12:30 +03:00
return err ;
}
2014-02-26 03:01:01 +04:00
gpio: dwapb: add gpio-signaled acpi event support
This patch adds gpio-signaled acpi event support. It is used for
power button on hisilicon D02 board, an arm64 platform.
The corresponding DSDT file is defined as follows:
Device(GPI0) {
Name(_HID, "HISI0181")
Name(_ADR, 0)
Name(_UID, 0)
Name (_CRS, ResourceTemplate () {
Memory32Fixed (ReadWrite, 0x802e0000, 0x10000)
Interrupt (ResourceConsumer, Level, ActiveHigh,
Exclusive,,,) {344}
})
Device(PRTa) {
Name (_DSD, Package () {
Package () {
Package () {"reg",0},
Package () {"snps,nr-gpios",32},
}
})
}
Name (_AEI, ResourceTemplate () {
GpioInt(Edge, ActiveLow, ExclusiveAndWake,
PullUp, , " \\_SB.GPI0") {8}
})
Method (_E08, 0x0, NotSerialized) {
Notify (\_SB.PWRB, 0x80)
}
}
Acked-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
Signed-off-by: Jiang Qiu <qiujiang@huawei.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
2016-04-28 12:32:03 +03:00
/* Add GPIO-signaled ACPI event support */
2020-05-19 16:12:30 +03:00
acpi_gpiochip_request_interrupts ( & port - > gc ) ;
gpio: dwapb: add gpio-signaled acpi event support
This patch adds gpio-signaled acpi event support. It is used for
power button on hisilicon D02 board, an arm64 platform.
The corresponding DSDT file is defined as follows:
Device(GPI0) {
Name(_HID, "HISI0181")
Name(_ADR, 0)
Name(_UID, 0)
Name (_CRS, ResourceTemplate () {
Memory32Fixed (ReadWrite, 0x802e0000, 0x10000)
Interrupt (ResourceConsumer, Level, ActiveHigh,
Exclusive,,,) {344}
})
Device(PRTa) {
Name (_DSD, Package () {
Package () {
Package () {"reg",0},
Package () {"snps,nr-gpios",32},
}
})
}
Name (_AEI, ResourceTemplate () {
GpioInt(Edge, ActiveLow, ExclusiveAndWake,
PullUp, , " \\_SB.GPI0") {8}
})
Method (_E08, 0x0, NotSerialized) {
Notify (\_SB.PWRB, 0x80)
}
}
Acked-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
Signed-off-by: Jiang Qiu <qiujiang@huawei.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
2016-04-28 12:32:03 +03:00
2020-05-19 16:12:30 +03:00
port - > is_registered = true ;
return 0 ;
2014-02-26 03:01:01 +04:00
}
static void dwapb_gpio_unregister ( struct dwapb_gpio * gpio )
{
unsigned int m ;
2020-05-19 16:12:30 +03:00
for ( m = 0 ; m < gpio - > nr_ports ; + + m ) {
struct dwapb_gpio_port * port = & gpio - > ports [ m ] ;
if ( ! port - > is_registered )
continue ;
acpi_gpiochip_free_interrupts ( & port - > gc ) ;
gpiochip_remove ( & port - > gc ) ;
}
2014-02-26 03:01:01 +04:00
}
2020-04-15 17:15:32 +03:00
static void dwapb_get_irq ( struct device * dev , struct fwnode_handle * fwnode ,
struct dwapb_port_property * pp )
{
struct device_node * np = NULL ;
2020-05-19 16:12:32 +03:00
int irq = - ENXIO , j ;
2020-04-15 17:15:32 +03:00
if ( fwnode_property_read_bool ( fwnode , " interrupt-controller " ) )
np = to_of_node ( fwnode ) ;
for ( j = 0 ; j < pp - > ngpio ; j + + ) {
if ( np )
2020-05-19 16:12:32 +03:00
irq = of_irq_get ( np , j ) ;
2020-04-15 17:15:32 +03:00
else if ( has_acpi_companion ( dev ) )
2020-05-19 16:12:32 +03:00
irq = platform_get_irq_optional ( to_platform_device ( dev ) , j ) ;
if ( irq > 0 )
pp - > irq [ j ] = irq ;
2020-04-15 17:15:32 +03:00
2020-05-19 16:12:32 +03:00
if ( pp - > irq [ j ] )
2020-04-15 17:15:32 +03:00
pp - > has_irq = true ;
}
if ( ! pp - > has_irq )
dev_warn ( dev , " no irq for port%d \n " , pp - > idx ) ;
}
static struct dwapb_platform_data * dwapb_gpio_get_pdata ( struct device * dev )
2014-09-17 20:18:39 +04:00
{
2016-04-28 12:32:02 +03:00
struct fwnode_handle * fwnode ;
2014-09-17 20:18:39 +04:00
struct dwapb_platform_data * pdata ;
struct dwapb_port_property * pp ;
int nports ;
2020-04-15 17:15:32 +03:00
int i ;
2014-09-17 20:18:39 +04:00
2016-04-28 12:32:02 +03:00
nports = device_get_child_node_count ( dev ) ;
2014-09-17 20:18:39 +04:00
if ( nports = = 0 )
return ERR_PTR ( - ENODEV ) ;
2014-12-28 10:23:14 +03:00
pdata = devm_kzalloc ( dev , sizeof ( * pdata ) , GFP_KERNEL ) ;
2014-09-17 20:18:39 +04:00
if ( ! pdata )
return ERR_PTR ( - ENOMEM ) ;
2014-12-28 10:23:14 +03:00
pdata - > properties = devm_kcalloc ( dev , nports , sizeof ( * pp ) , GFP_KERNEL ) ;
if ( ! pdata - > properties )
2014-09-17 20:18:39 +04:00
return ERR_PTR ( - ENOMEM ) ;
pdata - > nports = nports ;
i = 0 ;
2016-04-28 12:32:02 +03:00
device_for_each_child_node ( dev , fwnode ) {
2014-09-17 20:18:39 +04:00
pp = & pdata - > properties [ i + + ] ;
2016-04-28 12:32:02 +03:00
pp - > fwnode = fwnode ;
2014-09-17 20:18:39 +04:00
2016-04-28 12:32:02 +03:00
if ( fwnode_property_read_u32 ( fwnode , " reg " , & pp - > idx ) | |
2014-09-17 20:18:39 +04:00
pp - > idx > = DWAPB_MAX_PORTS ) {
2016-04-28 12:32:01 +03:00
dev_err ( dev ,
" missing/invalid port index for port%d \n " , i ) ;
2016-07-10 05:17:36 +03:00
fwnode_handle_put ( fwnode ) ;
2014-09-17 20:18:39 +04:00
return ERR_PTR ( - EINVAL ) ;
}
2020-04-22 14:06:54 +03:00
if ( fwnode_property_read_u32 ( fwnode , " snps,nr-gpios " , & pp - > ngpio ) ) {
2016-04-28 12:32:01 +03:00
dev_info ( dev ,
" failed to get number of gpios for port%d \n " ,
i ) ;
2014-09-17 20:18:39 +04:00
pp - > ngpio = 32 ;
}
2018-05-23 11:52:44 +03:00
pp - > irq_shared = false ;
pp - > gpio_base = - 1 ;
2014-09-17 20:18:39 +04:00
/*
* Only port A can provide interrupts in all configurations of
* the IP .
*/
2020-04-15 17:15:32 +03:00
if ( pp - > idx = = 0 )
dwapb_get_irq ( dev , fwnode , pp ) ;
2014-09-17 20:18:39 +04:00
}
return pdata ;
}
2017-02-21 22:32:43 +03:00
static const struct of_device_id dwapb_of_match [ ] = {
{ . compatible = " snps,dw-apb-gpio " , . data = ( void * ) 0 } ,
{ . compatible = " apm,xgene-gpio-v2 " , . data = ( void * ) GPIO_REG_OFFSET_V2 } ,
{ /* Sentinel */ }
} ;
MODULE_DEVICE_TABLE ( of , dwapb_of_match ) ;
static const struct acpi_device_id dwapb_acpi_match [ ] = {
{ " HISI0181 " , 0 } ,
{ " APMC0D07 " , 0 } ,
{ " APMC0D81 " , GPIO_REG_OFFSET_V2 } ,
{ }
} ;
MODULE_DEVICE_TABLE ( acpi , dwapb_acpi_match ) ;
2014-02-26 03:01:01 +04:00
static int dwapb_gpio_probe ( struct platform_device * pdev )
{
2014-09-17 20:18:39 +04:00
unsigned int i ;
2014-02-26 03:01:01 +04:00
struct dwapb_gpio * gpio ;
int err ;
2014-09-17 20:18:39 +04:00
struct device * dev = & pdev - > dev ;
struct dwapb_platform_data * pdata = dev_get_platdata ( dev ) ;
2014-12-28 10:23:14 +03:00
if ( ! pdata ) {
2016-04-28 12:32:02 +03:00
pdata = dwapb_gpio_get_pdata ( dev ) ;
2014-09-17 20:18:39 +04:00
if ( IS_ERR ( pdata ) )
return PTR_ERR ( pdata ) ;
}
2014-02-26 03:01:01 +04:00
2014-12-28 10:23:14 +03:00
if ( ! pdata - > nports )
return - ENODEV ;
2014-02-26 03:01:01 +04:00
2014-09-17 20:18:39 +04:00
gpio = devm_kzalloc ( & pdev - > dev , sizeof ( * gpio ) , GFP_KERNEL ) ;
2014-12-28 10:23:14 +03:00
if ( ! gpio )
return - ENOMEM ;
2014-09-17 20:18:39 +04:00
gpio - > dev = & pdev - > dev ;
gpio - > nr_ports = pdata - > nports ;
2017-10-11 19:34:44 +03:00
gpio - > rst = devm_reset_control_get_optional_shared ( dev , NULL ) ;
if ( IS_ERR ( gpio - > rst ) )
return PTR_ERR ( gpio - > rst ) ;
reset_control_deassert ( gpio - > rst ) ;
2014-09-17 20:18:39 +04:00
gpio - > ports = devm_kcalloc ( & pdev - > dev , gpio - > nr_ports ,
2014-02-26 03:01:01 +04:00
sizeof ( * gpio - > ports ) , GFP_KERNEL ) ;
2014-12-28 10:23:14 +03:00
if ( ! gpio - > ports )
return - ENOMEM ;
2014-02-26 03:01:01 +04:00
2019-03-11 21:54:47 +03:00
gpio - > regs = devm_platform_ioremap_resource ( pdev , 0 ) ;
2014-12-28 10:23:14 +03:00
if ( IS_ERR ( gpio - > regs ) )
return PTR_ERR ( gpio - > regs ) ;
2014-02-26 03:01:01 +04:00
2020-03-23 22:54:00 +03:00
/* Optional bus and debounce clocks */
gpio - > clks [ 0 ] . id = " bus " ;
gpio - > clks [ 1 ] . id = " db " ;
err = devm_clk_bulk_get_optional ( & pdev - > dev , DWAPB_NR_CLOCKS ,
gpio - > clks ) ;
if ( err ) {
dev_err ( & pdev - > dev , " Cannot get APB/Debounce clocks \n " ) ;
return err ;
2020-03-23 22:53:59 +03:00
}
2020-03-23 22:54:00 +03:00
err = clk_bulk_prepare_enable ( DWAPB_NR_CLOCKS , gpio - > clks ) ;
2020-03-23 22:53:59 +03:00
if ( err ) {
2020-03-23 22:54:00 +03:00
dev_err ( & pdev - > dev , " Cannot enable APB/Debounce clocks \n " ) ;
2020-03-23 22:53:59 +03:00
return err ;
2018-03-12 21:30:56 +03:00
}
2020-04-15 17:15:27 +03:00
gpio - > flags = ( uintptr_t ) device_get_match_data ( dev ) ;
2017-02-21 22:32:43 +03:00
2014-09-17 20:18:39 +04:00
for ( i = 0 ; i < gpio - > nr_ports ; i + + ) {
err = dwapb_gpio_add_port ( gpio , & pdata - > properties [ i ] , i ) ;
2014-02-26 03:01:01 +04:00
if ( err )
goto out_unregister ;
}
platform_set_drvdata ( pdev , gpio ) ;
2014-12-28 10:23:14 +03:00
return 0 ;
2014-02-26 03:01:01 +04:00
out_unregister :
dwapb_gpio_unregister ( gpio ) ;
dwapb_irq_teardown ( gpio ) ;
2020-03-23 22:54:00 +03:00
clk_bulk_disable_unprepare ( DWAPB_NR_CLOCKS , gpio - > clks ) ;
2014-02-26 03:01:01 +04:00
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 ) ;
2017-10-11 19:34:44 +03:00
reset_control_assert ( gpio - > rst ) ;
2020-03-23 22:54:00 +03:00
clk_bulk_disable_unprepare ( DWAPB_NR_CLOCKS , gpio - > clks ) ;
2014-02-26 03:01:01 +04:00
return 0 ;
}
2014-09-17 20:18:42 +04:00
# ifdef CONFIG_PM_SLEEP
static int dwapb_gpio_suspend ( struct device * dev )
{
2018-10-21 22:59:56 +03:00
struct dwapb_gpio * gpio = dev_get_drvdata ( dev ) ;
2015-12-04 16:02:58 +03:00
struct gpio_chip * gc = & gpio - > ports [ 0 ] . gc ;
2014-09-17 20:18:42 +04:00
unsigned long flags ;
int i ;
2015-12-04 16:02:58 +03:00
spin_lock_irqsave ( & gc - > bgpio_lock , flags ) ;
2014-09-17 20:18:42 +04:00
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 ;
2018-02-08 19:03:58 +03:00
offset = GPIO_SWPORTA_DDR + idx * GPIO_SWPORT_DDR_STRIDE ;
2014-09-17 20:18:42 +04:00
ctx - > dir = dwapb_read ( gpio , offset ) ;
2018-02-08 19:03:58 +03:00
offset = GPIO_SWPORTA_DR + idx * GPIO_SWPORT_DR_STRIDE ;
2014-09-17 20:18:42 +04:00
ctx - > data = dwapb_read ( gpio , offset ) ;
2018-02-08 19:03:58 +03:00
offset = GPIO_EXT_PORTA + idx * GPIO_EXT_PORT_STRIDE ;
2014-09-17 20:18:42 +04:00
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 */
2020-04-22 14:06:53 +03:00
dwapb_write ( gpio , GPIO_INTMASK , ~ ctx - > wake_en ) ;
2014-09-17 20:18:42 +04:00
}
}
2015-12-04 16:02:58 +03:00
spin_unlock_irqrestore ( & gc - > bgpio_lock , flags ) ;
2014-09-17 20:18:42 +04:00
2020-03-23 22:54:00 +03:00
clk_bulk_disable_unprepare ( DWAPB_NR_CLOCKS , gpio - > clks ) ;
2018-03-12 21:30:56 +03:00
2014-09-17 20:18:42 +04:00
return 0 ;
}
static int dwapb_gpio_resume ( struct device * dev )
{
2018-10-21 22:59:56 +03:00
struct dwapb_gpio * gpio = dev_get_drvdata ( dev ) ;
2015-12-04 16:02:58 +03:00
struct gpio_chip * gc = & gpio - > ports [ 0 ] . gc ;
2014-09-17 20:18:42 +04:00
unsigned long flags ;
2020-03-23 22:54:00 +03:00
int i , err ;
2014-09-17 20:18:42 +04:00
2020-03-23 22:54:00 +03:00
err = clk_bulk_prepare_enable ( DWAPB_NR_CLOCKS , gpio - > clks ) ;
if ( err ) {
dev_err ( gpio - > dev , " Cannot reenable APB/Debounce clocks \n " ) ;
return err ;
}
2018-03-12 21:30:56 +03:00
2015-12-04 16:02:58 +03:00
spin_lock_irqsave ( & gc - > bgpio_lock , flags ) ;
2014-09-17 20:18:42 +04:00
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 ;
2018-02-08 19:03:58 +03:00
offset = GPIO_SWPORTA_DR + idx * GPIO_SWPORT_DR_STRIDE ;
2014-09-17 20:18:42 +04:00
dwapb_write ( gpio , offset , ctx - > data ) ;
2018-02-08 19:03:58 +03:00
offset = GPIO_SWPORTA_DDR + idx * GPIO_SWPORT_DDR_STRIDE ;
2014-09-17 20:18:42 +04:00
dwapb_write ( gpio , offset , ctx - > dir ) ;
2018-02-08 19:03:58 +03:00
offset = GPIO_EXT_PORTA + idx * GPIO_EXT_PORT_STRIDE ;
2014-09-17 20:18:42 +04:00
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 ) ;
}
}
2015-12-04 16:02:58 +03:00
spin_unlock_irqrestore ( & gc - > bgpio_lock , flags ) ;
2014-09-17 20:18:42 +04:00
return 0 ;
}
# endif
static SIMPLE_DEV_PM_OPS ( dwapb_gpio_pm_ops , dwapb_gpio_suspend ,
dwapb_gpio_resume ) ;
2014-02-26 03:01:01 +04:00
static struct platform_driver dwapb_gpio_driver = {
. driver = {
2020-04-15 17:15:21 +03:00
. name = DWAPB_DRIVER_NAME ,
2014-09-17 20:18:42 +04:00
. pm = & dwapb_gpio_pm_ops ,
2020-04-15 17:15:31 +03:00
. of_match_table = dwapb_of_match ,
. acpi_match_table = dwapb_acpi_match ,
2014-02-26 03:01:01 +04:00
} ,
. 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 " ) ;
2020-04-15 17:15:21 +03:00
MODULE_ALIAS ( " platform: " DWAPB_DRIVER_NAME ) ;