2012-11-21 02:24:30 +04:00
/*
* Broadcom specific AMBA
* GPIO driver
*
* Copyright 2011 , Broadcom Corporation
* Copyright 2012 , Hauke Mehrtens < hauke @ hauke - m . de >
*
* Licensed under the GNU / GPL . See COPYING for details .
*/
2015-08-14 01:21:45 +03:00
# include <linux/gpio/driver.h>
2013-12-12 16:46:03 +04:00
# include <linux/interrupt.h>
2012-11-21 02:24:30 +04:00
# include <linux/export.h>
# include <linux/bcma/bcma.h>
# include "bcma_private.h"
2015-03-15 21:43:14 +03:00
# define BCMA_GPIO_MAX_PINS 32
2012-11-21 02:24:30 +04:00
static int bcma_gpio_get_value ( struct gpio_chip * chip , unsigned gpio )
{
2015-12-08 18:17:02 +03:00
struct bcma_drv_cc * cc = gpiochip_get_data ( chip ) ;
2012-11-21 02:24:30 +04:00
return ! ! bcma_chipco_gpio_in ( cc , 1 < < gpio ) ;
}
static void bcma_gpio_set_value ( struct gpio_chip * chip , unsigned gpio ,
int value )
{
2015-12-08 18:17:02 +03:00
struct bcma_drv_cc * cc = gpiochip_get_data ( chip ) ;
2012-11-21 02:24:30 +04:00
bcma_chipco_gpio_out ( cc , 1 < < gpio , value ? 1 < < gpio : 0 ) ;
}
static int bcma_gpio_direction_input ( struct gpio_chip * chip , unsigned gpio )
{
2015-12-08 18:17:02 +03:00
struct bcma_drv_cc * cc = gpiochip_get_data ( chip ) ;
2012-11-21 02:24:30 +04:00
bcma_chipco_gpio_outen ( cc , 1 < < gpio , 0 ) ;
return 0 ;
}
static int bcma_gpio_direction_output ( struct gpio_chip * chip , unsigned gpio ,
int value )
{
2015-12-08 18:17:02 +03:00
struct bcma_drv_cc * cc = gpiochip_get_data ( chip ) ;
2012-11-21 02:24:30 +04:00
bcma_chipco_gpio_outen ( cc , 1 < < gpio , 1 < < gpio ) ;
bcma_chipco_gpio_out ( cc , 1 < < gpio , value ? 1 < < gpio : 0 ) ;
return 0 ;
}
static int bcma_gpio_request ( struct gpio_chip * chip , unsigned gpio )
{
2015-12-08 18:17:02 +03:00
struct bcma_drv_cc * cc = gpiochip_get_data ( chip ) ;
2012-11-21 02:24:30 +04:00
bcma_chipco_gpio_control ( cc , 1 < < gpio , 0 ) ;
/* clear pulldown */
bcma_chipco_gpio_pulldown ( cc , 1 < < gpio , 0 ) ;
/* Set pullup */
bcma_chipco_gpio_pullup ( cc , 1 < < gpio , 1 < < gpio ) ;
return 0 ;
}
static void bcma_gpio_free ( struct gpio_chip * chip , unsigned gpio )
{
2015-12-08 18:17:02 +03:00
struct bcma_drv_cc * cc = gpiochip_get_data ( chip ) ;
2012-11-21 02:24:30 +04:00
/* clear pullup */
bcma_chipco_gpio_pullup ( cc , 1 < < gpio , 0 ) ;
}
2015-02-20 13:49:05 +03:00
# if IS_BUILTIN(CONFIG_BCM47XX) || IS_BUILTIN(CONFIG_ARCH_BCM_5301X)
2013-01-27 00:39:44 +04:00
2013-12-12 16:46:03 +04:00
static void bcma_gpio_irq_unmask ( struct irq_data * d )
{
2015-08-14 01:21:45 +03:00
struct gpio_chip * gc = irq_data_get_irq_chip_data ( d ) ;
2015-12-08 18:17:02 +03:00
struct bcma_drv_cc * cc = gpiochip_get_data ( gc ) ;
2013-12-12 16:46:03 +04:00
int gpio = irqd_to_hwirq ( d ) ;
2014-01-02 22:01:08 +04:00
u32 val = bcma_chipco_gpio_in ( cc , BIT ( gpio ) ) ;
2013-12-12 16:46:03 +04:00
2014-01-02 22:01:08 +04:00
bcma_chipco_gpio_polarity ( cc , BIT ( gpio ) , val ) ;
2013-12-12 16:46:03 +04:00
bcma_chipco_gpio_intmask ( cc , BIT ( gpio ) , BIT ( gpio ) ) ;
}
static void bcma_gpio_irq_mask ( struct irq_data * d )
{
2015-08-14 01:21:45 +03:00
struct gpio_chip * gc = irq_data_get_irq_chip_data ( d ) ;
2015-12-08 18:17:02 +03:00
struct bcma_drv_cc * cc = gpiochip_get_data ( gc ) ;
2013-12-12 16:46:03 +04:00
int gpio = irqd_to_hwirq ( d ) ;
bcma_chipco_gpio_intmask ( cc , BIT ( gpio ) , 0 ) ;
}
static struct irq_chip bcma_gpio_irq_chip = {
. name = " BCMA-GPIO " ,
. irq_mask = bcma_gpio_irq_mask ,
. irq_unmask = bcma_gpio_irq_unmask ,
} ;
static irqreturn_t bcma_gpio_irq_handler ( int irq , void * dev_id )
{
struct bcma_drv_cc * cc = dev_id ;
2015-08-14 01:21:45 +03:00
struct gpio_chip * gc = & cc - > gpio ;
2013-12-12 16:46:03 +04:00
u32 val = bcma_cc_read32 ( cc , BCMA_CC_GPIOIN ) ;
u32 mask = bcma_cc_read32 ( cc , BCMA_CC_GPIOIRQ ) ;
u32 pol = bcma_cc_read32 ( cc , BCMA_CC_GPIOPOL ) ;
2014-01-13 23:05:17 +04:00
unsigned long irqs = ( val ^ pol ) & mask ;
2013-12-12 16:46:03 +04:00
int gpio ;
if ( ! irqs )
return IRQ_NONE ;
2015-08-14 01:21:45 +03:00
for_each_set_bit ( gpio , & irqs , gc - > ngpio )
generic_handle_irq ( irq_find_mapping ( gc - > irqdomain , gpio ) ) ;
2013-12-12 16:46:03 +04:00
bcma_chipco_gpio_polarity ( cc , irqs , val & irqs ) ;
return IRQ_HANDLED ;
}
2015-08-14 01:21:45 +03:00
static int bcma_gpio_irq_init ( struct bcma_drv_cc * cc )
2013-12-12 16:46:03 +04:00
{
struct gpio_chip * chip = & cc - > gpio ;
2015-08-14 01:21:45 +03:00
int hwirq , err ;
2013-12-12 16:46:03 +04:00
if ( cc - > core - > bus - > hosttype ! = BCMA_HOSTTYPE_SOC )
return 0 ;
2014-11-01 18:54:55 +03:00
hwirq = bcma_core_irq ( cc - > core , 0 ) ;
2013-12-12 16:46:03 +04:00
err = request_irq ( hwirq , bcma_gpio_irq_handler , IRQF_SHARED , " gpio " ,
cc ) ;
if ( err )
2015-08-14 01:21:45 +03:00
return err ;
2013-12-12 16:46:03 +04:00
2014-01-02 22:01:08 +04:00
bcma_chipco_gpio_intmask ( cc , ~ 0 , 0 ) ;
2013-12-12 16:46:03 +04:00
bcma_cc_set32 ( cc , BCMA_CC_IRQMASK , BCMA_CC_IRQ_GPIO ) ;
2015-08-14 01:21:45 +03:00
err = gpiochip_irqchip_add ( chip ,
& bcma_gpio_irq_chip ,
0 ,
handle_simple_irq ,
IRQ_TYPE_NONE ) ;
if ( err ) {
free_irq ( hwirq , cc ) ;
return err ;
2013-12-12 16:46:03 +04:00
}
2015-08-14 01:21:45 +03:00
return 0 ;
2013-12-12 16:46:03 +04:00
}
2015-08-14 01:21:45 +03:00
static void bcma_gpio_irq_exit ( struct bcma_drv_cc * cc )
2013-12-12 16:46:03 +04:00
{
if ( cc - > core - > bus - > hosttype ! = BCMA_HOSTTYPE_SOC )
return ;
bcma_cc_mask32 ( cc , BCMA_CC_IRQMASK , ~ BCMA_CC_IRQ_GPIO ) ;
2014-11-01 18:54:55 +03:00
free_irq ( bcma_core_irq ( cc - > core , 0 ) , cc ) ;
2013-12-12 16:46:03 +04:00
}
# else
2015-08-14 01:21:45 +03:00
static int bcma_gpio_irq_init ( struct bcma_drv_cc * cc )
2013-12-12 16:46:03 +04:00
{
return 0 ;
}
2015-08-14 01:21:45 +03:00
static void bcma_gpio_irq_exit ( struct bcma_drv_cc * cc )
2013-12-12 16:46:03 +04:00
{
}
# endif
2012-11-21 02:24:30 +04:00
int bcma_gpio_init ( struct bcma_drv_cc * cc )
{
2015-03-15 21:43:14 +03:00
struct bcma_bus * bus = cc - > core - > bus ;
2012-11-21 02:24:30 +04:00
struct gpio_chip * chip = & cc - > gpio ;
2013-12-12 16:46:03 +04:00
int err ;
2012-11-21 02:24:30 +04:00
chip - > label = " bcma_gpio " ;
chip - > owner = THIS_MODULE ;
chip - > request = bcma_gpio_request ;
chip - > free = bcma_gpio_free ;
chip - > get = bcma_gpio_get_value ;
chip - > set = bcma_gpio_set_value ;
chip - > direction_input = bcma_gpio_direction_input ;
chip - > direction_output = bcma_gpio_direction_output ;
2015-08-14 01:21:45 +03:00
chip - > owner = THIS_MODULE ;
2015-11-04 11:56:26 +03:00
chip - > parent = bcma_bus_get_host_dev ( bus ) ;
2014-09-30 14:55:48 +04:00
# if IS_BUILTIN(CONFIG_OF)
if ( cc - > core - > bus - > hosttype = = BCMA_HOSTTYPE_SOC )
chip - > of_node = cc - > core - > dev . of_node ;
2013-12-12 16:46:03 +04:00
# endif
2015-03-15 21:43:14 +03:00
switch ( bus - > chipinfo . id ) {
2015-04-15 16:07:53 +03:00
case BCMA_CHIP_ID_BCM4707 :
2014-03-21 00:09:07 +04:00
case BCMA_CHIP_ID_BCM5357 :
2014-06-05 22:20:44 +04:00
case BCMA_CHIP_ID_BCM53572 :
2016-01-24 18:37:33 +03:00
case BCMA_CHIP_ID_BCM47094 :
2014-03-21 00:09:07 +04:00
chip - > ngpio = 32 ;
break ;
default :
chip - > ngpio = 16 ;
}
2015-03-15 21:43:14 +03:00
/*
2015-04-15 16:07:52 +03:00
* Register SoC GPIO devices with absolute GPIO pin base .
* On MIPS , we don ' t have Device Tree and we can ' t use relative ( per chip )
* GPIO numbers .
* On some ARM devices , user space may want to access some system GPIO
* pins directly , which is easier to do with a predictable GPIO base .
2015-03-15 21:43:14 +03:00
*/
2015-04-15 16:07:52 +03:00
if ( IS_BUILTIN ( CONFIG_BCM47XX ) | |
cc - > core - > bus - > hosttype = = BCMA_HOSTTYPE_SOC )
chip - > base = bus - > num * BCMA_GPIO_MAX_PINS ;
else
chip - > base = - 1 ;
2012-11-21 02:24:30 +04:00
2015-12-08 18:17:02 +03:00
err = gpiochip_add_data ( chip , cc ) ;
2013-12-12 16:46:03 +04:00
if ( err )
return err ;
2015-08-14 01:21:45 +03:00
err = bcma_gpio_irq_init ( cc ) ;
2013-12-12 16:46:03 +04:00
if ( err ) {
2015-08-14 01:21:45 +03:00
gpiochip_remove ( chip ) ;
2013-12-12 16:46:03 +04:00
return err ;
}
return 0 ;
2012-11-21 02:24:30 +04:00
}
2013-02-04 02:25:33 +04:00
int bcma_gpio_unregister ( struct bcma_drv_cc * cc )
{
2015-08-14 01:21:45 +03:00
bcma_gpio_irq_exit ( cc ) ;
2014-07-13 00:30:14 +04:00
gpiochip_remove ( & cc - > gpio ) ;
return 0 ;
2013-02-04 02:25:33 +04:00
}