2013-09-10 22:07:01 +04:00
/*
2016-03-27 18:44:41 +03:00
* Broadcom Kona GPIO Driver
*
* Author : Broadcom Corporation < bcm - kernel - feedback - list @ broadcom . com >
2014-02-04 01:43:00 +04:00
* Copyright ( C ) 2012 - 2014 Broadcom Corporation
2013-09-10 22:07:01 +04:00
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation version 2.
*
* This program is distributed " as is " WITHOUT ANY WARRANTY of any
* kind , whether express or implied ; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*/
# include <linux/bitops.h>
# include <linux/err.h>
# include <linux/io.h>
2018-01-14 00:52:33 +03:00
# include <linux/gpio/driver.h>
2013-09-10 22:07:01 +04:00
# include <linux/of_device.h>
2016-03-27 18:44:41 +03:00
# include <linux/init.h>
2013-09-10 22:07:01 +04:00
# include <linux/irqdomain.h>
# include <linux/irqchip/chained_irq.h>
# define BCM_GPIO_PASSWD 0x00a5a501
# define GPIO_PER_BANK 32
# define GPIO_MAX_BANK_NUM 8
# define GPIO_BANK(gpio) ((gpio) >> 5)
# define GPIO_BIT(gpio) ((gpio) & (GPIO_PER_BANK - 1))
2014-01-22 04:10:04 +04:00
/* There is a GPIO control register for each GPIO */
# define GPIO_CONTROL(gpio) (0x00000100 + ((gpio) << 2))
/* The remaining registers are per GPIO bank */
2013-09-10 22:07:01 +04:00
# define GPIO_OUT_STATUS(bank) (0x00000000 + ((bank) << 2))
# define GPIO_IN_STATUS(bank) (0x00000020 + ((bank) << 2))
# define GPIO_OUT_SET(bank) (0x00000040 + ((bank) << 2))
# define GPIO_OUT_CLEAR(bank) (0x00000060 + ((bank) << 2))
# define GPIO_INT_STATUS(bank) (0x00000080 + ((bank) << 2))
# define GPIO_INT_MASK(bank) (0x000000a0 + ((bank) << 2))
# define GPIO_INT_MSKCLR(bank) (0x000000c0 + ((bank) << 2))
# define GPIO_PWD_STATUS(bank) (0x00000500 + ((bank) << 2))
# define GPIO_GPPWR_OFFSET 0x00000520
# define GPIO_GPCTR0_DBR_SHIFT 5
# define GPIO_GPCTR0_DBR_MASK 0x000001e0
# define GPIO_GPCTR0_ITR_SHIFT 3
# define GPIO_GPCTR0_ITR_MASK 0x00000018
# define GPIO_GPCTR0_ITR_CMD_RISING_EDGE 0x00000001
# define GPIO_GPCTR0_ITR_CMD_FALLING_EDGE 0x00000002
# define GPIO_GPCTR0_ITR_CMD_BOTH_EDGE 0x00000003
# define GPIO_GPCTR0_IOTR_MASK 0x00000001
# define GPIO_GPCTR0_IOTR_CMD_0UTPUT 0x00000000
# define GPIO_GPCTR0_IOTR_CMD_INPUT 0x00000001
# define GPIO_GPCTR0_DB_ENABLE_MASK 0x00000100
# define LOCK_CODE 0xffffffff
# define UNLOCK_CODE 0x00000000
struct bcm_kona_gpio {
void __iomem * reg_base ;
int num_bank ;
2017-03-09 19:21:54 +03:00
raw_spinlock_t lock ;
2013-09-10 22:07:01 +04:00
struct gpio_chip gpio_chip ;
struct irq_domain * irq_domain ;
struct bcm_kona_gpio_bank * banks ;
struct platform_device * pdev ;
} ;
struct bcm_kona_gpio_bank {
int id ;
int irq ;
/* Used in the interrupt handler */
struct bcm_kona_gpio * kona_gpio ;
} ;
2014-01-22 04:10:41 +04:00
static inline void bcm_kona_gpio_write_lock_regs ( void __iomem * reg_base ,
int bank_id , u32 lockcode )
2013-09-10 22:07:01 +04:00
{
writel ( BCM_GPIO_PASSWD , reg_base + GPIO_GPPWR_OFFSET ) ;
writel ( lockcode , reg_base + GPIO_PWD_STATUS ( bank_id ) ) ;
}
2014-01-22 04:10:41 +04:00
static void bcm_kona_gpio_lock_gpio ( struct bcm_kona_gpio * kona_gpio ,
unsigned gpio )
2013-09-10 22:07:01 +04:00
{
2014-01-22 04:10:41 +04:00
u32 val ;
unsigned long flags ;
int bank_id = GPIO_BANK ( gpio ) ;
2017-03-09 19:21:54 +03:00
raw_spin_lock_irqsave ( & kona_gpio - > lock , flags ) ;
2014-01-22 04:10:41 +04:00
val = readl ( kona_gpio - > reg_base + GPIO_PWD_STATUS ( bank_id ) ) ;
val | = BIT ( gpio ) ;
bcm_kona_gpio_write_lock_regs ( kona_gpio - > reg_base , bank_id , val ) ;
2017-03-09 19:21:54 +03:00
raw_spin_unlock_irqrestore ( & kona_gpio - > lock , flags ) ;
2013-09-10 22:07:01 +04:00
}
2014-01-22 04:10:41 +04:00
static void bcm_kona_gpio_unlock_gpio ( struct bcm_kona_gpio * kona_gpio ,
unsigned gpio )
2013-09-10 22:07:01 +04:00
{
2014-01-22 04:10:41 +04:00
u32 val ;
unsigned long flags ;
int bank_id = GPIO_BANK ( gpio ) ;
2017-03-09 19:21:54 +03:00
raw_spin_lock_irqsave ( & kona_gpio - > lock , flags ) ;
2014-01-22 04:10:41 +04:00
val = readl ( kona_gpio - > reg_base + GPIO_PWD_STATUS ( bank_id ) ) ;
val & = ~ BIT ( gpio ) ;
bcm_kona_gpio_write_lock_regs ( kona_gpio - > reg_base , bank_id , val ) ;
2017-03-09 19:21:54 +03:00
raw_spin_unlock_irqrestore ( & kona_gpio - > lock , flags ) ;
2013-09-10 22:07:01 +04:00
}
2015-04-13 10:56:00 +03:00
static int bcm_kona_gpio_get_dir ( struct gpio_chip * chip , unsigned gpio )
{
2015-12-04 17:39:50 +03:00
struct bcm_kona_gpio * kona_gpio = gpiochip_get_data ( chip ) ;
2015-04-13 10:56:00 +03:00
void __iomem * reg_base = kona_gpio - > reg_base ;
u32 val ;
val = readl ( reg_base + GPIO_CONTROL ( gpio ) ) & GPIO_GPCTR0_IOTR_MASK ;
2019-11-06 11:54:12 +03:00
return val ? GPIO_LINE_DIRECTION_IN : GPIO_LINE_DIRECTION_OUT ;
2015-04-13 10:56:00 +03:00
}
2013-09-10 22:07:01 +04:00
static void bcm_kona_gpio_set ( struct gpio_chip * chip , unsigned gpio , int value )
{
struct bcm_kona_gpio * kona_gpio ;
void __iomem * reg_base ;
int bank_id = GPIO_BANK ( gpio ) ;
int bit = GPIO_BIT ( gpio ) ;
u32 val , reg_offset ;
unsigned long flags ;
2015-12-04 17:39:50 +03:00
kona_gpio = gpiochip_get_data ( chip ) ;
2013-09-10 22:07:01 +04:00
reg_base = kona_gpio - > reg_base ;
2017-03-09 19:21:54 +03:00
raw_spin_lock_irqsave ( & kona_gpio - > lock , flags ) ;
2013-09-10 22:07:01 +04:00
/* this function only applies to output pin */
2019-11-06 11:54:12 +03:00
if ( bcm_kona_gpio_get_dir ( chip , gpio ) = = GPIO_LINE_DIRECTION_IN )
2013-09-10 22:07:01 +04:00
goto out ;
reg_offset = value ? GPIO_OUT_SET ( bank_id ) : GPIO_OUT_CLEAR ( bank_id ) ;
val = readl ( reg_base + reg_offset ) ;
val | = BIT ( bit ) ;
writel ( val , reg_base + reg_offset ) ;
out :
2017-03-09 19:21:54 +03:00
raw_spin_unlock_irqrestore ( & kona_gpio - > lock , flags ) ;
2013-09-10 22:07:01 +04:00
}
static int bcm_kona_gpio_get ( struct gpio_chip * chip , unsigned gpio )
{
struct bcm_kona_gpio * kona_gpio ;
void __iomem * reg_base ;
int bank_id = GPIO_BANK ( gpio ) ;
int bit = GPIO_BIT ( gpio ) ;
u32 val , reg_offset ;
unsigned long flags ;
2015-12-04 17:39:50 +03:00
kona_gpio = gpiochip_get_data ( chip ) ;
2013-09-10 22:07:01 +04:00
reg_base = kona_gpio - > reg_base ;
2017-03-09 19:21:54 +03:00
raw_spin_lock_irqsave ( & kona_gpio - > lock , flags ) ;
2013-09-10 22:07:01 +04:00
2019-11-06 11:54:12 +03:00
if ( bcm_kona_gpio_get_dir ( chip , gpio ) = = GPIO_LINE_DIRECTION_IN )
2015-04-13 10:56:00 +03:00
reg_offset = GPIO_IN_STATUS ( bank_id ) ;
else
reg_offset = GPIO_OUT_STATUS ( bank_id ) ;
2013-09-10 22:07:01 +04:00
/* read the GPIO bank status */
val = readl ( reg_base + reg_offset ) ;
2017-03-09 19:21:54 +03:00
raw_spin_unlock_irqrestore ( & kona_gpio - > lock , flags ) ;
2013-09-10 22:07:01 +04:00
/* return the specified bit status */
2013-11-22 03:12:46 +04:00
return ! ! ( val & BIT ( bit ) ) ;
2013-09-10 22:07:01 +04:00
}
2014-01-22 04:10:41 +04:00
static int bcm_kona_gpio_request ( struct gpio_chip * chip , unsigned gpio )
{
2015-12-04 17:39:50 +03:00
struct bcm_kona_gpio * kona_gpio = gpiochip_get_data ( chip ) ;
2014-01-22 04:10:41 +04:00
bcm_kona_gpio_unlock_gpio ( kona_gpio , gpio ) ;
return 0 ;
}
static void bcm_kona_gpio_free ( struct gpio_chip * chip , unsigned gpio )
{
2015-12-04 17:39:50 +03:00
struct bcm_kona_gpio * kona_gpio = gpiochip_get_data ( chip ) ;
2014-01-22 04:10:41 +04:00
bcm_kona_gpio_lock_gpio ( kona_gpio , gpio ) ;
}
2013-09-10 22:07:01 +04:00
static int bcm_kona_gpio_direction_input ( struct gpio_chip * chip , unsigned gpio )
{
struct bcm_kona_gpio * kona_gpio ;
void __iomem * reg_base ;
u32 val ;
unsigned long flags ;
2015-12-04 17:39:50 +03:00
kona_gpio = gpiochip_get_data ( chip ) ;
2013-09-10 22:07:01 +04:00
reg_base = kona_gpio - > reg_base ;
2017-03-09 19:21:54 +03:00
raw_spin_lock_irqsave ( & kona_gpio - > lock , flags ) ;
2013-09-10 22:07:01 +04:00
val = readl ( reg_base + GPIO_CONTROL ( gpio ) ) ;
val & = ~ GPIO_GPCTR0_IOTR_MASK ;
val | = GPIO_GPCTR0_IOTR_CMD_INPUT ;
writel ( val , reg_base + GPIO_CONTROL ( gpio ) ) ;
2017-03-09 19:21:54 +03:00
raw_spin_unlock_irqrestore ( & kona_gpio - > lock , flags ) ;
2013-09-10 22:07:01 +04:00
return 0 ;
}
static int bcm_kona_gpio_direction_output ( struct gpio_chip * chip ,
unsigned gpio , int value )
{
struct bcm_kona_gpio * kona_gpio ;
void __iomem * reg_base ;
int bank_id = GPIO_BANK ( gpio ) ;
int bit = GPIO_BIT ( gpio ) ;
u32 val , reg_offset ;
unsigned long flags ;
2015-12-04 17:39:50 +03:00
kona_gpio = gpiochip_get_data ( chip ) ;
2013-09-10 22:07:01 +04:00
reg_base = kona_gpio - > reg_base ;
2017-03-09 19:21:54 +03:00
raw_spin_lock_irqsave ( & kona_gpio - > lock , flags ) ;
2013-09-10 22:07:01 +04:00
val = readl ( reg_base + GPIO_CONTROL ( gpio ) ) ;
val & = ~ GPIO_GPCTR0_IOTR_MASK ;
val | = GPIO_GPCTR0_IOTR_CMD_0UTPUT ;
writel ( val , reg_base + GPIO_CONTROL ( gpio ) ) ;
reg_offset = value ? GPIO_OUT_SET ( bank_id ) : GPIO_OUT_CLEAR ( bank_id ) ;
val = readl ( reg_base + reg_offset ) ;
val | = BIT ( bit ) ;
writel ( val , reg_base + reg_offset ) ;
2017-03-09 19:21:54 +03:00
raw_spin_unlock_irqrestore ( & kona_gpio - > lock , flags ) ;
2013-09-10 22:07:01 +04:00
return 0 ;
}
static int bcm_kona_gpio_to_irq ( struct gpio_chip * chip , unsigned gpio )
{
struct bcm_kona_gpio * kona_gpio ;
2015-12-04 17:39:50 +03:00
kona_gpio = gpiochip_get_data ( chip ) ;
2013-09-10 22:07:01 +04:00
if ( gpio > = kona_gpio - > gpio_chip . ngpio )
return - ENXIO ;
return irq_create_mapping ( kona_gpio - > irq_domain , gpio ) ;
}
static int bcm_kona_gpio_set_debounce ( struct gpio_chip * chip , unsigned gpio ,
unsigned debounce )
{
struct bcm_kona_gpio * kona_gpio ;
void __iomem * reg_base ;
u32 val , res ;
unsigned long flags ;
2015-12-04 17:39:50 +03:00
kona_gpio = gpiochip_get_data ( chip ) ;
2013-09-10 22:07:01 +04:00
reg_base = kona_gpio - > reg_base ;
/* debounce must be 1-128ms (or 0) */
if ( ( debounce > 0 & & debounce < 1000 ) | | debounce > 128000 ) {
2015-11-04 11:56:26 +03:00
dev_err ( chip - > parent , " Debounce value %u not in range \n " ,
2013-09-10 22:07:01 +04:00
debounce ) ;
return - EINVAL ;
}
/* calculate debounce bit value */
if ( debounce ! = 0 ) {
/* Convert to ms */
debounce / = 1000 ;
/* find the MSB */
res = fls ( debounce ) - 1 ;
/* Check if MSB-1 is set (round up or down) */
if ( res > 0 & & ( debounce & BIT ( res - 1 ) ) )
res + + ;
}
/* spin lock for read-modify-write of the GPIO register */
2017-03-09 19:21:54 +03:00
raw_spin_lock_irqsave ( & kona_gpio - > lock , flags ) ;
2013-09-10 22:07:01 +04:00
val = readl ( reg_base + GPIO_CONTROL ( gpio ) ) ;
val & = ~ GPIO_GPCTR0_DBR_MASK ;
if ( debounce = = 0 ) {
/* disable debounce */
val & = ~ GPIO_GPCTR0_DB_ENABLE_MASK ;
} else {
val | = GPIO_GPCTR0_DB_ENABLE_MASK |
( res < < GPIO_GPCTR0_DBR_SHIFT ) ;
}
writel ( val , reg_base + GPIO_CONTROL ( gpio ) ) ;
2017-03-09 19:21:54 +03:00
raw_spin_unlock_irqrestore ( & kona_gpio - > lock , flags ) ;
2013-09-10 22:07:01 +04:00
return 0 ;
}
2017-01-23 15:34:34 +03:00
static int bcm_kona_gpio_set_config ( struct gpio_chip * chip , unsigned gpio ,
unsigned long config )
{
u32 debounce ;
if ( pinconf_to_config_param ( config ) ! = PIN_CONFIG_INPUT_DEBOUNCE )
return - ENOTSUPP ;
debounce = pinconf_to_config_argument ( config ) ;
return bcm_kona_gpio_set_debounce ( chip , gpio , debounce ) ;
}
2016-09-11 15:14:37 +03:00
static const struct gpio_chip template_chip = {
2013-09-10 22:07:01 +04:00
. label = " bcm-kona-gpio " ,
2013-10-29 07:49:20 +04:00
. owner = THIS_MODULE ,
2014-01-22 04:10:41 +04:00
. request = bcm_kona_gpio_request ,
. free = bcm_kona_gpio_free ,
2015-04-13 10:56:00 +03:00
. get_direction = bcm_kona_gpio_get_dir ,
2013-09-10 22:07:01 +04:00
. direction_input = bcm_kona_gpio_direction_input ,
. get = bcm_kona_gpio_get ,
. direction_output = bcm_kona_gpio_direction_output ,
. set = bcm_kona_gpio_set ,
2017-01-23 15:34:34 +03:00
. set_config = bcm_kona_gpio_set_config ,
2013-09-10 22:07:01 +04:00
. to_irq = bcm_kona_gpio_to_irq ,
. base = 0 ,
} ;
static void bcm_kona_gpio_irq_ack ( struct irq_data * d )
{
struct bcm_kona_gpio * kona_gpio ;
void __iomem * reg_base ;
2014-01-28 05:32:18 +04:00
unsigned gpio = d - > hwirq ;
2013-09-10 22:07:01 +04:00
int bank_id = GPIO_BANK ( gpio ) ;
int bit = GPIO_BIT ( gpio ) ;
u32 val ;
unsigned long flags ;
kona_gpio = irq_data_get_irq_chip_data ( d ) ;
reg_base = kona_gpio - > reg_base ;
2017-03-09 19:21:54 +03:00
raw_spin_lock_irqsave ( & kona_gpio - > lock , flags ) ;
2013-09-10 22:07:01 +04:00
val = readl ( reg_base + GPIO_INT_STATUS ( bank_id ) ) ;
val | = BIT ( bit ) ;
writel ( val , reg_base + GPIO_INT_STATUS ( bank_id ) ) ;
2017-03-09 19:21:54 +03:00
raw_spin_unlock_irqrestore ( & kona_gpio - > lock , flags ) ;
2013-09-10 22:07:01 +04:00
}
static void bcm_kona_gpio_irq_mask ( struct irq_data * d )
{
struct bcm_kona_gpio * kona_gpio ;
void __iomem * reg_base ;
2014-01-28 05:32:18 +04:00
unsigned gpio = d - > hwirq ;
2013-09-10 22:07:01 +04:00
int bank_id = GPIO_BANK ( gpio ) ;
int bit = GPIO_BIT ( gpio ) ;
u32 val ;
unsigned long flags ;
kona_gpio = irq_data_get_irq_chip_data ( d ) ;
reg_base = kona_gpio - > reg_base ;
2017-03-09 19:21:54 +03:00
raw_spin_lock_irqsave ( & kona_gpio - > lock , flags ) ;
2013-09-10 22:07:01 +04:00
val = readl ( reg_base + GPIO_INT_MASK ( bank_id ) ) ;
val | = BIT ( bit ) ;
writel ( val , reg_base + GPIO_INT_MASK ( bank_id ) ) ;
2018-09-08 12:23:19 +03:00
gpiochip_disable_irq ( & kona_gpio - > gpio_chip , gpio ) ;
2013-09-10 22:07:01 +04:00
2017-03-09 19:21:54 +03:00
raw_spin_unlock_irqrestore ( & kona_gpio - > lock , flags ) ;
2013-09-10 22:07:01 +04:00
}
static void bcm_kona_gpio_irq_unmask ( struct irq_data * d )
{
struct bcm_kona_gpio * kona_gpio ;
void __iomem * reg_base ;
2014-01-28 05:32:18 +04:00
unsigned gpio = d - > hwirq ;
2013-09-10 22:07:01 +04:00
int bank_id = GPIO_BANK ( gpio ) ;
int bit = GPIO_BIT ( gpio ) ;
u32 val ;
unsigned long flags ;
kona_gpio = irq_data_get_irq_chip_data ( d ) ;
reg_base = kona_gpio - > reg_base ;
2017-03-09 19:21:54 +03:00
raw_spin_lock_irqsave ( & kona_gpio - > lock , flags ) ;
2013-09-10 22:07:01 +04:00
val = readl ( reg_base + GPIO_INT_MSKCLR ( bank_id ) ) ;
val | = BIT ( bit ) ;
writel ( val , reg_base + GPIO_INT_MSKCLR ( bank_id ) ) ;
2018-09-08 12:23:19 +03:00
gpiochip_enable_irq ( & kona_gpio - > gpio_chip , gpio ) ;
2013-09-10 22:07:01 +04:00
2017-03-09 19:21:54 +03:00
raw_spin_unlock_irqrestore ( & kona_gpio - > lock , flags ) ;
2013-09-10 22:07:01 +04:00
}
static int bcm_kona_gpio_irq_set_type ( struct irq_data * d , unsigned int type )
{
struct bcm_kona_gpio * kona_gpio ;
void __iomem * reg_base ;
2014-01-28 05:32:18 +04:00
unsigned gpio = d - > hwirq ;
2013-09-10 22:07:01 +04:00
u32 lvl_type ;
u32 val ;
unsigned long flags ;
kona_gpio = irq_data_get_irq_chip_data ( d ) ;
reg_base = kona_gpio - > reg_base ;
switch ( type & IRQ_TYPE_SENSE_MASK ) {
case IRQ_TYPE_EDGE_RISING :
lvl_type = GPIO_GPCTR0_ITR_CMD_RISING_EDGE ;
break ;
case IRQ_TYPE_EDGE_FALLING :
lvl_type = GPIO_GPCTR0_ITR_CMD_FALLING_EDGE ;
break ;
case IRQ_TYPE_EDGE_BOTH :
lvl_type = GPIO_GPCTR0_ITR_CMD_BOTH_EDGE ;
break ;
case IRQ_TYPE_LEVEL_HIGH :
case IRQ_TYPE_LEVEL_LOW :
/* BCM GPIO doesn't support level triggering */
default :
2015-11-04 11:56:26 +03:00
dev_err ( kona_gpio - > gpio_chip . parent ,
2013-09-10 22:07:01 +04:00
" Invalid BCM GPIO irq type 0x%x \n " , type ) ;
return - EINVAL ;
}
2017-03-09 19:21:54 +03:00
raw_spin_lock_irqsave ( & kona_gpio - > lock , flags ) ;
2013-09-10 22:07:01 +04:00
val = readl ( reg_base + GPIO_CONTROL ( gpio ) ) ;
val & = ~ GPIO_GPCTR0_ITR_MASK ;
val | = lvl_type < < GPIO_GPCTR0_ITR_SHIFT ;
writel ( val , reg_base + GPIO_CONTROL ( gpio ) ) ;
2017-03-09 19:21:54 +03:00
raw_spin_unlock_irqrestore ( & kona_gpio - > lock , flags ) ;
2013-09-10 22:07:01 +04:00
return 0 ;
}
2015-09-14 11:42:37 +03:00
static void bcm_kona_gpio_irq_handler ( struct irq_desc * desc )
2013-09-10 22:07:01 +04:00
{
void __iomem * reg_base ;
int bit , bank_id ;
unsigned long sta ;
2015-06-04 07:13:15 +03:00
struct bcm_kona_gpio_bank * bank = irq_desc_get_handler_data ( desc ) ;
2013-09-10 22:07:01 +04:00
struct irq_chip * chip = irq_desc_get_chip ( desc ) ;
chained_irq_enter ( chip , desc ) ;
/*
* For bank interrupts , we can ' t use chip_data to store the kona_gpio
* pointer , since GIC needs it for its own purposes . Therefore , we get
* our pointer from the bank structure .
*/
reg_base = bank - > kona_gpio - > reg_base ;
bank_id = bank - > id ;
while ( ( sta = readl ( reg_base + GPIO_INT_STATUS ( bank_id ) ) &
( ~ ( readl ( reg_base + GPIO_INT_MASK ( bank_id ) ) ) ) ) ) {
for_each_set_bit ( bit , & sta , 32 ) {
2013-10-11 21:14:50 +04:00
int hwirq = GPIO_PER_BANK * bank_id + bit ;
int child_irq =
irq_find_mapping ( bank - > kona_gpio - > irq_domain ,
hwirq ) ;
2013-09-10 22:07:01 +04:00
/*
* Clear interrupt before handler is called so we don ' t
* miss any interrupt occurred during executing them .
*/
writel ( readl ( reg_base + GPIO_INT_STATUS ( bank_id ) ) |
BIT ( bit ) , reg_base + GPIO_INT_STATUS ( bank_id ) ) ;
/* Invoke interrupt handler */
2013-10-11 21:14:50 +04:00
generic_handle_irq ( child_irq ) ;
2013-09-10 22:07:01 +04:00
}
}
chained_irq_exit ( chip , desc ) ;
}
2014-03-14 21:16:20 +04:00
static int bcm_kona_gpio_irq_reqres ( struct irq_data * d )
2013-11-19 17:14:50 +04:00
{
struct bcm_kona_gpio * kona_gpio = irq_data_get_irq_chip_data ( d ) ;
2018-09-08 12:23:19 +03:00
return gpiochip_reqres_irq ( & kona_gpio - > gpio_chip , d - > hwirq ) ;
2013-11-19 17:14:50 +04:00
}
2014-03-14 21:16:20 +04:00
static void bcm_kona_gpio_irq_relres ( struct irq_data * d )
2013-11-19 17:14:50 +04:00
{
struct bcm_kona_gpio * kona_gpio = irq_data_get_irq_chip_data ( d ) ;
2018-09-08 12:23:19 +03:00
gpiochip_relres_irq ( & kona_gpio - > gpio_chip , d - > hwirq ) ;
2013-11-19 17:14:50 +04:00
}
2013-09-10 22:07:01 +04:00
static struct irq_chip bcm_gpio_irq_chip = {
. name = " bcm-kona-gpio " ,
. irq_ack = bcm_kona_gpio_irq_ack ,
. irq_mask = bcm_kona_gpio_irq_mask ,
. irq_unmask = bcm_kona_gpio_irq_unmask ,
. irq_set_type = bcm_kona_gpio_irq_set_type ,
2014-03-14 21:16:20 +04:00
. irq_request_resources = bcm_kona_gpio_irq_reqres ,
. irq_release_resources = bcm_kona_gpio_irq_relres ,
2013-09-10 22:07:01 +04:00
} ;
2014-09-24 02:55:07 +04:00
static struct of_device_id const bcm_kona_gpio_of_match [ ] = {
2013-09-10 22:07:01 +04:00
{ . compatible = " brcm,kona-gpio " } ,
{ }
} ;
/*
* This lock class tells lockdep that GPIO irqs are in a different
* category than their parents , so it won ' t report false recursion .
*/
static struct lock_class_key gpio_lock_class ;
2017-12-02 20:11:04 +03:00
static struct lock_class_key gpio_request_class ;
2013-09-10 22:07:01 +04:00
2013-09-21 01:14:18 +04:00
static int bcm_kona_gpio_irq_map ( struct irq_domain * d , unsigned int irq ,
2013-09-10 22:07:01 +04:00
irq_hw_number_t hwirq )
{
int ret ;
2013-09-21 01:14:18 +04:00
ret = irq_set_chip_data ( irq , d - > host_data ) ;
2013-09-10 22:07:01 +04:00
if ( ret < 0 )
return ret ;
2017-12-02 20:11:04 +03:00
irq_set_lockdep_class ( irq , & gpio_lock_class , & gpio_request_class ) ;
2013-09-21 01:14:18 +04:00
irq_set_chip_and_handler ( irq , & bcm_gpio_irq_chip , handle_simple_irq ) ;
irq_set_noprobe ( irq ) ;
2013-09-10 22:07:01 +04:00
return 0 ;
}
2013-10-11 21:14:50 +04:00
static void bcm_kona_gpio_irq_unmap ( struct irq_domain * d , unsigned int irq )
2013-09-10 22:07:01 +04:00
{
2013-10-11 21:14:50 +04:00
irq_set_chip_and_handler ( irq , NULL , NULL ) ;
irq_set_chip_data ( irq , NULL ) ;
2013-09-10 22:07:01 +04:00
}
2015-04-27 15:54:07 +03:00
static const struct irq_domain_ops bcm_kona_irq_ops = {
2013-09-10 22:07:01 +04:00
. map = bcm_kona_gpio_irq_map ,
. unmap = bcm_kona_gpio_irq_unmap ,
. xlate = irq_domain_xlate_twocell ,
} ;
static void bcm_kona_gpio_reset ( struct bcm_kona_gpio * kona_gpio )
{
void __iomem * reg_base ;
int i ;
reg_base = kona_gpio - > reg_base ;
/* disable interrupts and clear status */
for ( i = 0 ; i < kona_gpio - > num_bank ; i + + ) {
2014-01-22 04:10:41 +04:00
/* Unlock the entire bank first */
2016-06-07 19:22:17 +03:00
bcm_kona_gpio_write_lock_regs ( reg_base , i , UNLOCK_CODE ) ;
2013-09-10 22:07:01 +04:00
writel ( 0xffffffff , reg_base + GPIO_INT_MASK ( i ) ) ;
writel ( 0xffffffff , reg_base + GPIO_INT_STATUS ( i ) ) ;
2014-01-22 04:10:41 +04:00
/* Now re-lock the bank */
2016-06-07 19:22:17 +03:00
bcm_kona_gpio_write_lock_regs ( reg_base , i , LOCK_CODE ) ;
2013-09-10 22:07:01 +04:00
}
}
static int bcm_kona_gpio_probe ( struct platform_device * pdev )
{
struct device * dev = & pdev - > dev ;
const struct of_device_id * match ;
struct bcm_kona_gpio_bank * bank ;
struct bcm_kona_gpio * kona_gpio ;
struct gpio_chip * chip ;
int ret ;
int i ;
match = of_match_device ( bcm_kona_gpio_of_match , dev ) ;
if ( ! match ) {
dev_err ( dev , " Failed to find gpio controller \n " ) ;
return - ENODEV ;
}
kona_gpio = devm_kzalloc ( dev , sizeof ( * kona_gpio ) , GFP_KERNEL ) ;
if ( ! kona_gpio )
return - ENOMEM ;
kona_gpio - > gpio_chip = template_chip ;
chip = & kona_gpio - > gpio_chip ;
2019-12-04 12:24:39 +03:00
ret = platform_irq_count ( pdev ) ;
if ( ! ret ) {
2013-09-10 22:07:01 +04:00
dev_err ( dev , " Couldn't determine # GPIO banks \n " ) ;
return - ENOENT ;
2019-12-04 12:24:39 +03:00
} else if ( ret < 0 ) {
if ( ret ! = - EPROBE_DEFER )
dev_err ( dev , " Couldn't determine GPIO banks: (%pe) \n " ,
ERR_PTR ( ret ) ) ;
return ret ;
2013-09-10 22:07:01 +04:00
}
2019-12-04 12:24:39 +03:00
kona_gpio - > num_bank = ret ;
2013-09-10 22:07:01 +04:00
if ( kona_gpio - > num_bank > GPIO_MAX_BANK_NUM ) {
dev_err ( dev , " Too many GPIO banks configured (max=%d) \n " ,
GPIO_MAX_BANK_NUM ) ;
return - ENXIO ;
}
treewide: devm_kzalloc() -> devm_kcalloc()
The devm_kzalloc() function has a 2-factor argument form, devm_kcalloc().
This patch replaces cases of:
devm_kzalloc(handle, a * b, gfp)
with:
devm_kcalloc(handle, a * b, gfp)
as well as handling cases of:
devm_kzalloc(handle, a * b * c, gfp)
with:
devm_kzalloc(handle, array3_size(a, b, c), gfp)
as it's slightly less ugly than:
devm_kcalloc(handle, array_size(a, b), c, gfp)
This does, however, attempt to ignore constant size factors like:
devm_kzalloc(handle, 4 * 1024, gfp)
though any constants defined via macros get caught up in the conversion.
Any factors with a sizeof() of "unsigned char", "char", and "u8" were
dropped, since they're redundant.
Some manual whitespace fixes were needed in this patch, as Coccinelle
really liked to write "=devm_kcalloc..." instead of "= devm_kcalloc...".
The Coccinelle script used for this was:
// Fix redundant parens around sizeof().
@@
expression HANDLE;
type TYPE;
expression THING, E;
@@
(
devm_kzalloc(HANDLE,
- (sizeof(TYPE)) * E
+ sizeof(TYPE) * E
, ...)
|
devm_kzalloc(HANDLE,
- (sizeof(THING)) * E
+ sizeof(THING) * E
, ...)
)
// Drop single-byte sizes and redundant parens.
@@
expression HANDLE;
expression COUNT;
typedef u8;
typedef __u8;
@@
(
devm_kzalloc(HANDLE,
- sizeof(u8) * (COUNT)
+ COUNT
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(__u8) * (COUNT)
+ COUNT
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(char) * (COUNT)
+ COUNT
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(unsigned char) * (COUNT)
+ COUNT
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(u8) * COUNT
+ COUNT
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(__u8) * COUNT
+ COUNT
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(char) * COUNT
+ COUNT
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(unsigned char) * COUNT
+ COUNT
, ...)
)
// 2-factor product with sizeof(type/expression) and identifier or constant.
@@
expression HANDLE;
type TYPE;
expression THING;
identifier COUNT_ID;
constant COUNT_CONST;
@@
(
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(TYPE) * (COUNT_ID)
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(TYPE) * COUNT_ID
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(TYPE) * (COUNT_CONST)
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(TYPE) * COUNT_CONST
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(THING) * (COUNT_ID)
+ COUNT_ID, sizeof(THING)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(THING) * COUNT_ID
+ COUNT_ID, sizeof(THING)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(THING) * (COUNT_CONST)
+ COUNT_CONST, sizeof(THING)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(THING) * COUNT_CONST
+ COUNT_CONST, sizeof(THING)
, ...)
)
// 2-factor product, only identifiers.
@@
expression HANDLE;
identifier SIZE, COUNT;
@@
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- SIZE * COUNT
+ COUNT, SIZE
, ...)
// 3-factor product with 1 sizeof(type) or sizeof(expression), with
// redundant parens removed.
@@
expression HANDLE;
expression THING;
identifier STRIDE, COUNT;
type TYPE;
@@
(
devm_kzalloc(HANDLE,
- sizeof(TYPE) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(TYPE) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(TYPE) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(TYPE) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(THING) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(THING) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(THING) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(THING) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
)
// 3-factor product with 2 sizeof(variable), with redundant parens removed.
@@
expression HANDLE;
expression THING1, THING2;
identifier COUNT;
type TYPE1, TYPE2;
@@
(
devm_kzalloc(HANDLE,
- sizeof(TYPE1) * sizeof(TYPE2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(THING1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(THING1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(TYPE1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
)
// 3-factor product, only identifiers, with redundant parens removed.
@@
expression HANDLE;
identifier STRIDE, SIZE, COUNT;
@@
(
devm_kzalloc(HANDLE,
- (COUNT) * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
devm_kzalloc(HANDLE,
- COUNT * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
devm_kzalloc(HANDLE,
- COUNT * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
devm_kzalloc(HANDLE,
- (COUNT) * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
devm_kzalloc(HANDLE,
- COUNT * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
devm_kzalloc(HANDLE,
- (COUNT) * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
devm_kzalloc(HANDLE,
- (COUNT) * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
devm_kzalloc(HANDLE,
- COUNT * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
)
// Any remaining multi-factor products, first at least 3-factor products,
// when they're not all constants...
@@
expression HANDLE;
expression E1, E2, E3;
constant C1, C2, C3;
@@
(
devm_kzalloc(HANDLE, C1 * C2 * C3, ...)
|
devm_kzalloc(HANDLE,
- (E1) * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
|
devm_kzalloc(HANDLE,
- (E1) * (E2) * E3
+ array3_size(E1, E2, E3)
, ...)
|
devm_kzalloc(HANDLE,
- (E1) * (E2) * (E3)
+ array3_size(E1, E2, E3)
, ...)
|
devm_kzalloc(HANDLE,
- E1 * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
)
// And then all remaining 2 factors products when they're not all constants,
// keeping sizeof() as the second factor argument.
@@
expression HANDLE;
expression THING, E1, E2;
type TYPE;
constant C1, C2, C3;
@@
(
devm_kzalloc(HANDLE, sizeof(THING) * C2, ...)
|
devm_kzalloc(HANDLE, sizeof(TYPE) * C2, ...)
|
devm_kzalloc(HANDLE, C1 * C2 * C3, ...)
|
devm_kzalloc(HANDLE, C1 * C2, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(TYPE) * (E2)
+ E2, sizeof(TYPE)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(TYPE) * E2
+ E2, sizeof(TYPE)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(THING) * (E2)
+ E2, sizeof(THING)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(THING) * E2
+ E2, sizeof(THING)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- (E1) * E2
+ E1, E2
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- (E1) * (E2)
+ E1, E2
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- E1 * E2
+ E1, E2
, ...)
)
Signed-off-by: Kees Cook <keescook@chromium.org>
2018-06-13 00:07:58 +03:00
kona_gpio - > banks = devm_kcalloc ( dev ,
kona_gpio - > num_bank ,
sizeof ( * kona_gpio - > banks ) ,
GFP_KERNEL ) ;
2013-09-10 22:07:01 +04:00
if ( ! kona_gpio - > banks )
return - ENOMEM ;
kona_gpio - > pdev = pdev ;
platform_set_drvdata ( pdev , kona_gpio ) ;
chip - > of_node = dev - > of_node ;
chip - > ngpio = kona_gpio - > num_bank * GPIO_PER_BANK ;
kona_gpio - > irq_domain = irq_domain_add_linear ( dev - > of_node ,
chip - > ngpio ,
& bcm_kona_irq_ops ,
kona_gpio ) ;
if ( ! kona_gpio - > irq_domain ) {
dev_err ( dev , " Couldn't allocate IRQ domain \n " ) ;
return - ENXIO ;
}
2019-03-11 21:54:44 +03:00
kona_gpio - > reg_base = devm_platform_ioremap_resource ( pdev , 0 ) ;
2013-09-10 22:07:01 +04:00
if ( IS_ERR ( kona_gpio - > reg_base ) ) {
2020-05-22 07:12:18 +03:00
ret = PTR_ERR ( kona_gpio - > reg_base ) ;
2013-09-10 22:07:01 +04:00
goto err_irq_domain ;
}
for ( i = 0 ; i < kona_gpio - > num_bank ; i + + ) {
bank = & kona_gpio - > banks [ i ] ;
bank - > id = i ;
bank - > irq = platform_get_irq ( pdev , i ) ;
bank - > kona_gpio = kona_gpio ;
if ( bank - > irq < 0 ) {
dev_err ( dev , " Couldn't get IRQ for bank %d " , i ) ;
ret = - ENOENT ;
goto err_irq_domain ;
}
}
2013-10-18 22:50:03 +04:00
dev_info ( & pdev - > dev , " Setting up Kona GPIO \n " ) ;
2013-09-10 22:07:01 +04:00
bcm_kona_gpio_reset ( kona_gpio ) ;
2016-02-22 15:13:28 +03:00
ret = devm_gpiochip_add_data ( dev , chip , kona_gpio ) ;
2013-09-10 22:07:01 +04:00
if ( ret < 0 ) {
dev_err ( dev , " Couldn't add GPIO chip -- %d \n " , ret ) ;
goto err_irq_domain ;
}
for ( i = 0 ; i < kona_gpio - > num_bank ; i + + ) {
bank = & kona_gpio - > banks [ i ] ;
gpio/bcm-kona: Fix race in installing chained IRQ handler
Fix a race where a pending interrupt could be received and the handler
called before the handler's data has been setup, by converting to
irq_set_chained_handler_and_data().
Search and conversion was done with coccinelle:
@@
expression E1, E2, E3;
@@
(
-if (irq_set_chained_handler(E1, E3) != 0)
- BUG();
|
-irq_set_chained_handler(E1, E3);
)
-irq_set_handler_data(E1, E2);
+irq_set_chained_handler_and_data(E1, E3, E2);
@@
expression E1, E2, E3;
@@
(
-if (irq_set_chained_handler(E1, E3) != 0)
- BUG();
...
|
-irq_set_chained_handler(E1, E3);
...
)
-irq_set_handler_data(E1, E2);
+irq_set_chained_handler_and_data(E1, E3, E2);
Reported-by: Russell King <rmk+kernel@arm.linux.org.uk>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Cc: Julia Lawall <Julia.Lawall@lip6.fr>
Cc: Ray Jui <rjui@broadcom.com>
Cc: Linus Walleij <linus.walleij@linaro.org>
Cc: Alexandre Courbot <gnurou@gmail.com>
Cc: bcm-kernel-feedback-list@broadcom.com
Cc: linux-gpio@vger.kernel.org
2015-06-21 21:16:04 +03:00
irq_set_chained_handler_and_data ( bank - > irq ,
bcm_kona_gpio_irq_handler ,
bank ) ;
2013-09-10 22:07:01 +04:00
}
2017-03-09 19:21:54 +03:00
raw_spin_lock_init ( & kona_gpio - > lock ) ;
2013-09-10 22:07:01 +04:00
return 0 ;
err_irq_domain :
irq_domain_remove ( kona_gpio - > irq_domain ) ;
return ret ;
}
static struct platform_driver bcm_kona_gpio_driver = {
. driver = {
. name = " bcm-kona-gpio " ,
. of_match_table = bcm_kona_gpio_of_match ,
} ,
. probe = bcm_kona_gpio_probe ,
} ;
2016-03-27 18:44:41 +03:00
builtin_platform_driver ( bcm_kona_gpio_driver ) ;