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>
2021-06-04 21:50:13 +03:00
# include <linux/mod_devicetable.h>
2014-02-26 03:01:01 +04:00
# include <linux/module.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-09-17 20:18:39 +04:00
# include <linux/slab.h>
2021-06-04 21:50:13 +03:00
# include <linux/spinlock.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
2021-08-04 19:00:19 +03:00
# define DWAPB_MAX_GPIOS 32
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
2021-11-30 19:49:56 +03:00
# define GPIO_REG_OFFSET_V1 0
2017-02-21 22:32:43 +03:00
# define GPIO_REG_OFFSET_V2 1
2021-11-30 19:49:56 +03:00
# define GPIO_REG_OFFSET_MASK BIT(0)
2017-02-21 22:32:43 +03:00
# 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 ;
2021-08-04 19:00:19 +03:00
struct dwapb_port_property {
struct fwnode_handle * fwnode ;
unsigned int idx ;
unsigned int ngpio ;
unsigned int gpio_base ;
int irq [ DWAPB_MAX_GPIOS ] ;
} ;
struct dwapb_platform_data {
struct dwapb_port_property * properties ;
unsigned int nports ;
} ;
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
2020-07-30 18:28:02 +03:00
struct dwapb_gpio_port_irqchip {
unsigned int nr_irqs ;
unsigned int irq [ DWAPB_MAX_GPIOS ] ;
} ;
2014-02-26 03:01:01 +04:00
struct dwapb_gpio_port {
2015-12-04 16:02:58 +03:00
struct gpio_chip gc ;
2020-07-30 18:28:02 +03:00
struct dwapb_gpio_port_irqchip * pirq ;
2014-02-26 03:01:01 +04:00
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
} ;
2020-07-30 18:28:02 +03:00
# define to_dwapb_gpio(_gc) \
( container_of ( _gc , struct dwapb_gpio_port , gc ) - > gpio )
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 ;
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 )
{
2021-11-30 19:49:56 +03:00
if ( ( gpio - > flags & GPIO_REG_OFFSET_MASK ) = = GPIO_REG_OFFSET_V2 )
2017-02-21 22:32:43 +03:00
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
}
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 ] ;
2020-07-30 18:28:01 +03:00
if ( port - > idx = = offs / DWAPB_MAX_GPIOS )
2018-02-08 20:00:05 +03:00
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 */
2020-07-30 18:28:01 +03:00
val = gc - > get ( gc , offs % DWAPB_MAX_GPIOS ) ;
2018-02-08 20:00:05 +03:00
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-07-30 18:28:02 +03:00
struct gpio_chip * gc = & gpio - > ports [ 0 ] . gc ;
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 ) ;
2020-07-30 18:28:01 +03:00
for_each_set_bit ( hwirq , & irq_status , DWAPB_MAX_GPIOS ) {
2020-07-30 18:28:02 +03:00
int gpio_irq = irq_find_mapping ( gc - > irq . 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
}
2020-07-30 18:28:00 +03:00
static irqreturn_t dwapb_irq_handler_mfd ( int irq , void * dev_id )
{
return IRQ_RETVAL ( dwapb_do_irq ( dev_id ) ) ;
}
2020-07-30 18:28:02 +03:00
static void dwapb_irq_ack ( struct irq_data * d )
{
struct gpio_chip * gc = irq_data_get_irq_chip_data ( d ) ;
struct dwapb_gpio * gpio = to_dwapb_gpio ( gc ) ;
u32 val = BIT ( irqd_to_hwirq ( d ) ) ;
unsigned long flags ;
2022-04-19 04:28:10 +03:00
raw_spin_lock_irqsave ( & gc - > bgpio_lock , flags ) ;
2020-07-30 18:28:02 +03:00
dwapb_write ( gpio , GPIO_PORTA_EOI , val ) ;
2022-04-19 04:28:10 +03:00
raw_spin_unlock_irqrestore ( & gc - > bgpio_lock , flags ) ;
2020-07-30 18:28:02 +03:00
}
static void dwapb_irq_mask ( struct irq_data * d )
{
struct gpio_chip * gc = irq_data_get_irq_chip_data ( d ) ;
struct dwapb_gpio * gpio = to_dwapb_gpio ( gc ) ;
2022-05-20 13:23:18 +03:00
irq_hw_number_t hwirq = irqd_to_hwirq ( d ) ;
2020-07-30 18:28:02 +03:00
unsigned long flags ;
u32 val ;
2022-04-19 04:28:10 +03:00
raw_spin_lock_irqsave ( & gc - > bgpio_lock , flags ) ;
2022-05-20 13:23:18 +03:00
val = dwapb_read ( gpio , GPIO_INTMASK ) | BIT ( hwirq ) ;
2020-07-30 18:28:02 +03:00
dwapb_write ( gpio , GPIO_INTMASK , val ) ;
2022-04-19 04:28:10 +03:00
raw_spin_unlock_irqrestore ( & gc - > bgpio_lock , flags ) ;
2022-05-20 13:23:18 +03:00
gpiochip_disable_irq ( gc , hwirq ) ;
2020-07-30 18:28:02 +03:00
}
static void dwapb_irq_unmask ( struct irq_data * d )
{
struct gpio_chip * gc = irq_data_get_irq_chip_data ( d ) ;
struct dwapb_gpio * gpio = to_dwapb_gpio ( gc ) ;
2022-05-20 13:23:18 +03:00
irq_hw_number_t hwirq = irqd_to_hwirq ( d ) ;
2020-07-30 18:28:02 +03:00
unsigned long flags ;
u32 val ;
2022-05-20 13:23:18 +03:00
gpiochip_enable_irq ( gc , hwirq ) ;
2022-04-19 04:28:10 +03:00
raw_spin_lock_irqsave ( & gc - > bgpio_lock , flags ) ;
2022-05-20 13:23:18 +03:00
val = dwapb_read ( gpio , GPIO_INTMASK ) & ~ BIT ( hwirq ) ;
2020-07-30 18:28:02 +03:00
dwapb_write ( gpio , GPIO_INTMASK , val ) ;
2022-04-19 04:28:10 +03:00
raw_spin_unlock_irqrestore ( & gc - > bgpio_lock , flags ) ;
2020-07-30 18:28:02 +03:00
}
2014-02-26 03:01:01 +04:00
static void dwapb_irq_enable ( struct irq_data * d )
{
2020-07-30 18:28:02 +03:00
struct gpio_chip * gc = irq_data_get_irq_chip_data ( d ) ;
struct dwapb_gpio * gpio = to_dwapb_gpio ( gc ) ;
2014-02-26 03:01:01 +04:00
unsigned long flags ;
u32 val ;
2022-04-19 04:28:10 +03:00
raw_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 ) ;
2022-04-19 04:28:10 +03:00
raw_spin_unlock_irqrestore ( & gc - > bgpio_lock , flags ) ;
2014-02-26 03:01:01 +04:00
}
static void dwapb_irq_disable ( struct irq_data * d )
{
2020-07-30 18:28:02 +03:00
struct gpio_chip * gc = irq_data_get_irq_chip_data ( d ) ;
struct dwapb_gpio * gpio = to_dwapb_gpio ( gc ) ;
2014-02-26 03:01:01 +04:00
unsigned long flags ;
u32 val ;
2022-04-19 04:28:10 +03:00
raw_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 ) ;
2022-04-19 04:28:10 +03:00
raw_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 )
{
2020-07-30 18:28:02 +03:00
struct gpio_chip * gc = irq_data_get_irq_chip_data ( d ) ;
struct dwapb_gpio * gpio = to_dwapb_gpio ( 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 ;
2022-04-19 04:28:10 +03:00
raw_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 ;
}
2020-07-30 18:28:02 +03:00
if ( type & IRQ_TYPE_LEVEL_MASK )
irq_set_handler_locked ( d , handle_level_irq ) ;
else if ( type & IRQ_TYPE_EDGE_BOTH )
irq_set_handler_locked ( d , handle_edge_irq ) ;
2014-05-27 00:58:14 +04:00
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 ) ;
2022-04-19 04:28:10 +03:00
raw_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 )
{
2020-10-16 18:35:44 +03:00
struct gpio_chip * gc = irq_data_get_irq_chip_data ( d ) ;
struct dwapb_gpio * gpio = to_dwapb_gpio ( gc ) ;
2017-09-09 01:41:15 +03:00
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 ;
}
2022-05-20 13:23:18 +03:00
# else
# define dwapb_irq_set_wake NULL
2017-09-09 01:41:15 +03:00
# endif
2022-05-20 13:23:18 +03:00
static const struct irq_chip dwapb_irq_chip = {
. name = DWAPB_DRIVER_NAME ,
. irq_ack = dwapb_irq_ack ,
. irq_mask = dwapb_irq_mask ,
. irq_unmask = dwapb_irq_unmask ,
. irq_set_type = dwapb_irq_set_type ,
. irq_enable = dwapb_irq_enable ,
. irq_disable = dwapb_irq_disable ,
. irq_set_wake = dwapb_irq_set_wake ,
. flags = IRQCHIP_IMMUTABLE ,
GPIOCHIP_IRQ_RESOURCE_HELPERS ,
} ;
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
2022-04-19 04:28:10 +03:00
raw_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
2022-04-19 04:28:10 +03:00
raw_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 ) ;
}
2020-07-30 18:28:02 +03:00
static int dwapb_convert_irqs ( struct dwapb_gpio_port_irqchip * pirq ,
struct dwapb_port_property * pp )
{
int i ;
/* Group all available IRQs into an array of parental IRQs. */
for ( i = 0 ; i < pp - > ngpio ; + + i ) {
if ( ! pp - > irq [ i ] )
continue ;
pirq - > irq [ pirq - > nr_irqs + + ] = pp - > irq [ i ] ;
}
return pirq - > nr_irqs ? 0 : - ENOENT ;
}
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
{
2020-07-30 18:28:02 +03:00
struct dwapb_gpio_port_irqchip * pirq ;
2015-12-04 16:02:58 +03:00
struct gpio_chip * gc = & port - > gc ;
2020-07-30 18:28:02 +03:00
struct gpio_irq_chip * girq ;
int err ;
2014-02-26 03:01:01 +04:00
2020-07-30 18:28:02 +03:00
pirq = devm_kzalloc ( gpio - > dev , sizeof ( * pirq ) , GFP_KERNEL ) ;
if ( ! pirq )
2014-02-26 03:01:01 +04:00
return ;
2020-07-30 18:28:02 +03:00
if ( dwapb_convert_irqs ( pirq , pp ) ) {
dev_warn ( gpio - > dev , " no IRQ for port%d \n " , pp - > idx ) ;
goto err_kfree_pirq ;
2014-02-26 03:01:01 +04:00
}
2020-07-30 18:28:02 +03:00
girq = & gc - > irq ;
girq - > handler = handle_bad_irq ;
girq - > default_type = IRQ_TYPE_NONE ;
port - > pirq = pirq ;
2014-02-26 03:01:01 +04:00
2021-08-04 19:00:16 +03:00
/*
* Intel ACPI - based platforms mostly have the DesignWare APB GPIO
* IRQ lane shared between several devices . In that case the parental
* IRQ has to be handled in the shared way so to be properly delivered
* to all the connected devices .
*/
if ( has_acpi_companion ( gpio - > dev ) ) {
2020-07-30 18:28:02 +03:00
girq - > num_parents = 0 ;
girq - > parents = NULL ;
girq - > parent_handler = NULL ;
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 " ) ;
2020-07-30 18:28:02 +03:00
goto err_kfree_pirq ;
2014-09-17 20:18:39 +04:00
}
2021-08-04 19:00:16 +03:00
} else {
girq - > num_parents = pirq - > nr_irqs ;
girq - > parents = pirq - > irq ;
girq - > parent_handler_data = gpio ;
girq - > parent_handler = dwapb_irq_handler ;
2014-09-17 20:18:39 +04:00
}
2014-02-26 03:01:01 +04:00
2022-05-20 13:23:18 +03:00
gpio_irq_chip_set_chip ( girq , & dwapb_irq_chip ) ;
2014-02-26 03:01:01 +04:00
2020-07-30 18:28:02 +03:00
return ;
2014-02-26 03:01:01 +04:00
2020-07-30 18:28:02 +03:00
err_kfree_pirq :
devm_kfree ( gpio - > dev , pirq ) ;
2014-02-26 03:01:01 +04:00
}
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 ;
}
2021-12-23 13:38:09 +03:00
port - > gc . fwnode = pp - > fwnode ;
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
2020-05-19 16:12:33 +03:00
/* Only port A can provide interrupts in all configurations of the IP */
if ( pp - > idx = = 0 )
2014-09-17 20:18:39 +04:00
dwapb_configure_irqs ( gpio , port , pp ) ;
2014-02-26 03:01:01 +04:00
2020-07-30 18:28:07 +03:00
err = devm_gpiochip_add_data ( gpio - > dev , & 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
2020-05-19 16:12:30 +03:00
return 0 ;
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 )
{
2021-06-01 19:21:28 +03:00
int irq , j ;
2020-04-15 17:15:32 +03:00
for ( j = 0 ; j < pp - > ngpio ; j + + ) {
2021-06-01 19:21:28 +03:00
if ( has_acpi_companion ( dev ) )
2020-05-19 16:12:32 +03:00
irq = platform_get_irq_optional ( to_platform_device ( dev ) , j ) ;
2021-06-01 19:21:28 +03:00
else
irq = fwnode_irq_get ( fwnode , j ) ;
2020-05-19 16:12:32 +03:00
if ( irq > 0 )
pp - > irq [ j ] = irq ;
2020-04-15 17:15:32 +03:00
}
}
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-07-30 18:27:59 +03:00
if ( fwnode_property_read_u32 ( fwnode , " ngpios " , & pp - > ngpio ) & &
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 ) ;
2020-07-30 18:28:01 +03:00
pp - > ngpio = DWAPB_MAX_GPIOS ;
2014-09-17 20:18:39 +04:00
}
2018-05-23 11:52:44 +03:00
pp - > gpio_base = - 1 ;
2021-08-04 19:00:17 +03:00
/* For internal use only, new platforms mustn't exercise this */
if ( is_software_node ( fwnode ) )
fwnode_property_read_u32 ( fwnode , " gpio-base " , & pp - > gpio_base ) ;
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 ;
}
2020-07-30 18:28:05 +03:00
static void dwapb_assert_reset ( void * data )
{
struct dwapb_gpio * gpio = data ;
reset_control_assert ( gpio - > rst ) ;
}
static int dwapb_get_reset ( struct dwapb_gpio * gpio )
{
int err ;
gpio - > rst = devm_reset_control_get_optional_shared ( gpio - > dev , NULL ) ;
2020-11-30 13:57:49 +03:00
if ( IS_ERR ( gpio - > rst ) )
return dev_err_probe ( gpio - > dev , PTR_ERR ( gpio - > rst ) ,
" Cannot get reset descriptor \n " ) ;
2020-07-30 18:28:05 +03:00
err = reset_control_deassert ( gpio - > rst ) ;
if ( err ) {
dev_err ( gpio - > dev , " Cannot deassert reset lane \n " ) ;
return err ;
}
return devm_add_action_or_reset ( gpio - > dev , dwapb_assert_reset , gpio ) ;
}
2020-07-30 18:28:06 +03:00
static void dwapb_disable_clks ( void * data )
{
struct dwapb_gpio * gpio = data ;
clk_bulk_disable_unprepare ( DWAPB_NR_CLOCKS , gpio - > clks ) ;
}
static int dwapb_get_clks ( struct dwapb_gpio * gpio )
{
int err ;
/* Optional bus and debounce clocks */
gpio - > clks [ 0 ] . id = " bus " ;
gpio - > clks [ 1 ] . id = " db " ;
err = devm_clk_bulk_get_optional ( gpio - > dev , DWAPB_NR_CLOCKS ,
gpio - > clks ) ;
2022-06-10 13:45:00 +03:00
if ( err )
return dev_err_probe ( gpio - > dev , err ,
" Cannot get APB/Debounce clocks \n " ) ;
2020-07-30 18:28:06 +03:00
err = clk_bulk_prepare_enable ( DWAPB_NR_CLOCKS , gpio - > clks ) ;
if ( err ) {
dev_err ( gpio - > dev , " Cannot enable APB/Debounce clocks \n " ) ;
return err ;
}
return devm_add_action_or_reset ( gpio - > dev , dwapb_disable_clks , gpio ) ;
}
2017-02-21 22:32:43 +03:00
static const struct of_device_id dwapb_of_match [ ] = {
2021-11-30 19:49:56 +03:00
{ . compatible = " snps,dw-apb-gpio " , . data = ( void * ) GPIO_REG_OFFSET_V1 } ,
2017-02-21 22:32:43 +03:00
{ . 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 [ ] = {
2021-11-30 19:49:56 +03:00
{ " HISI0181 " , GPIO_REG_OFFSET_V1 } ,
{ " APMC0D07 " , GPIO_REG_OFFSET_V1 } ,
2017-02-21 22:32:43 +03:00
{ " 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 ;
2021-08-04 19:00:19 +03:00
struct dwapb_platform_data * pdata ;
2014-09-17 20:18:39 +04:00
struct device * dev = & pdev - > dev ;
2014-02-26 03:01:01 +04:00
2021-08-04 19:00:19 +03:00
pdata = dwapb_gpio_get_pdata ( dev ) ;
if ( IS_ERR ( pdata ) )
return PTR_ERR ( pdata ) ;
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 ;
2020-07-30 18:28:05 +03:00
err = dwapb_get_reset ( gpio ) ;
if ( err )
return err ;
2017-10-11 19:34:44 +03:00
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-07-30 18:28:06 +03:00
err = dwapb_get_clks ( gpio ) ;
if ( err )
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 )
2020-07-30 18:28:07 +03:00
return err ;
2014-02-26 03:01:01 +04:00
}
2020-11-27 11:50:02 +03:00
platform_set_drvdata ( pdev , gpio ) ;
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 ;
2022-04-19 04:28:10 +03:00
raw_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
}
}
2022-04-19 04:28:10 +03:00
raw_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
2022-04-19 04:28:10 +03:00
raw_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 ) ;
}
}
2022-04-19 04:28:10 +03:00
raw_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 ,
} ;
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 ) ;