2012-09-20 00:52:58 +04:00
/*
* GPIO driver for Marvell SoCs
*
* Copyright ( C ) 2012 Marvell
*
* Thomas Petazzoni < thomas . petazzoni @ free - electrons . com >
* Andrew Lunn < andrew @ lunn . ch >
* Sebastian Hesselbarth < sebastian . hesselbarth @ gmail . com >
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed " as is " without any
* warranty of any kind , whether express or implied .
*
* This driver is a fairly straightforward GPIO driver for the
* complete family of Marvell EBU SoC platforms ( Orion , Dove ,
* Kirkwood , Discovery , Armada 370 / XP ) . The only complexity of this
* driver is the different register layout that exists between the
* non - SMP platforms ( Orion , Dove , Kirkwood , Armada 370 ) and the SMP
* platforms ( MV78200 from the Discovery family and the Armada
* XP ) . Therefore , this driver handles three variants of the GPIO
* block :
* - the basic variant , called " orion-gpio " , with the simplest
* register set . Used on Orion , Dove , Kirkwoord , Armada 370 and
* non - SMP Discovery systems
* - the mv78200 variant for MV78200 Discovery systems . This variant
* turns the edge mask and level mask registers into CPU0 edge
* mask / level mask registers , and adds CPU1 edge mask / level mask
* registers .
* - the armadaxp variant for Armada XP systems . This variant keeps
* the normal cause / edge mask / level mask registers when the global
* interrupts are used , but adds per - CPU cause / edge mask / level mask
* registers n a separate memory area for the per - CPU GPIO
* interrupts .
*/
2013-01-21 14:09:01 +04:00
# include <linux/err.h>
2016-03-27 18:44:45 +03:00
# include <linux/init.h>
2012-09-20 00:52:58 +04:00
# include <linux/gpio.h>
# include <linux/irq.h>
# include <linux/slab.h>
# include <linux/irqdomain.h>
# include <linux/io.h>
# include <linux/of_irq.h>
# include <linux/of_device.h>
2017-04-14 18:40:52 +03:00
# include <linux/pwm.h>
2013-02-03 14:34:26 +04:00
# include <linux/clk.h>
2012-09-20 00:52:58 +04:00
# include <linux/pinctrl/consumer.h>
2014-02-07 15:29:19 +04:00
# include <linux/irqchip/chained_irq.h>
2017-04-14 18:40:52 +03:00
# include <linux/platform_device.h>
2017-03-17 20:44:06 +03:00
# include <linux/bitops.h>
2012-09-20 00:52:58 +04:00
2017-04-14 18:40:52 +03:00
# include "gpiolib.h"
2012-09-20 00:52:58 +04:00
/*
* GPIO unit register offsets .
*/
2017-04-14 18:40:52 +03:00
# define GPIO_OUT_OFF 0x0000
# define GPIO_IO_CONF_OFF 0x0004
# define GPIO_BLINK_EN_OFF 0x0008
# define GPIO_IN_POL_OFF 0x000c
# define GPIO_DATA_IN_OFF 0x0010
# define GPIO_EDGE_CAUSE_OFF 0x0014
# define GPIO_EDGE_MASK_OFF 0x0018
# define GPIO_LEVEL_MASK_OFF 0x001c
# define GPIO_BLINK_CNT_SELECT_OFF 0x0020
/*
* PWM register offsets .
*/
# define PWM_BLINK_ON_DURATION_OFF 0x0
# define PWM_BLINK_OFF_DURATION_OFF 0x4
2012-09-20 00:52:58 +04:00
/* The MV78200 has per-CPU registers for edge mask and level mask */
2015-01-10 02:34:47 +03:00
# define GPIO_EDGE_MASK_MV78200_OFF(cpu) ((cpu) ? 0x30 : 0x18)
2012-09-20 00:52:58 +04:00
# define GPIO_LEVEL_MASK_MV78200_OFF(cpu) ((cpu) ? 0x34 : 0x1C)
2017-03-16 09:33:56 +03:00
/*
* The Armada XP has per - CPU registers for interrupt cause , interrupt
2012-09-20 00:52:58 +04:00
* mask and interrupt level mask . Those are relative to the
2017-03-16 09:33:56 +03:00
* percpu_membase .
*/
2012-09-20 00:52:58 +04:00
# define GPIO_EDGE_CAUSE_ARMADAXP_OFF(cpu) ((cpu) * 0x4)
# define GPIO_EDGE_MASK_ARMADAXP_OFF(cpu) (0x10 + (cpu) * 0x4)
# define GPIO_LEVEL_MASK_ARMADAXP_OFF(cpu) (0x20 + (cpu) * 0x4)
2015-01-10 02:34:47 +03:00
# define MVEBU_GPIO_SOC_VARIANT_ORION 0x1
# define MVEBU_GPIO_SOC_VARIANT_MV78200 0x2
2012-09-20 00:52:58 +04:00
# define MVEBU_GPIO_SOC_VARIANT_ARMADAXP 0x3
2015-01-10 02:34:47 +03:00
# define MVEBU_MAX_GPIO_PER_BANK 32
2012-09-20 00:52:58 +04:00
2017-04-14 18:40:52 +03:00
struct mvebu_pwm {
void __iomem * membase ;
unsigned long clk_rate ;
struct gpio_desc * gpiod ;
struct pwm_chip chip ;
spinlock_t lock ;
struct mvebu_gpio_chip * mvchip ;
/* Used to preserve GPIO/PWM registers across suspend/resume */
u32 blink_select ;
u32 blink_on_duration ;
u32 blink_off_duration ;
} ;
2012-09-20 00:52:58 +04:00
struct mvebu_gpio_chip {
struct gpio_chip chip ;
spinlock_t lock ;
void __iomem * membase ;
void __iomem * percpu_membase ;
2013-11-07 11:50:19 +04:00
int irqbase ;
2012-09-20 00:52:58 +04:00
struct irq_domain * domain ;
2015-01-10 02:34:47 +03:00
int soc_variant ;
2014-10-24 15:59:19 +04:00
2017-04-14 18:40:52 +03:00
/* Used for PWM support */
struct clk * clk ;
struct mvebu_pwm * mvpwm ;
2015-01-10 02:34:47 +03:00
/* Used to preserve GPIO registers across suspend/resume */
2017-03-16 09:34:00 +03:00
u32 out_reg ;
u32 io_conf_reg ;
u32 blink_en_reg ;
u32 in_pol_reg ;
u32 edge_mask_regs [ 4 ] ;
u32 level_mask_regs [ 4 ] ;
2012-09-20 00:52:58 +04:00
} ;
/*
* Functions returning addresses of individual registers for a given
* GPIO controller .
*/
2017-03-16 09:34:01 +03:00
static void __iomem * mvebu_gpioreg_out ( struct mvebu_gpio_chip * mvchip )
2012-09-20 00:52:58 +04:00
{
return mvchip - > membase + GPIO_OUT_OFF ;
}
2017-03-16 09:34:01 +03:00
static void __iomem * mvebu_gpioreg_blink ( struct mvebu_gpio_chip * mvchip )
2012-10-28 16:23:24 +04:00
{
return mvchip - > membase + GPIO_BLINK_EN_OFF ;
}
2017-04-14 18:40:52 +03:00
static void __iomem * mvebu_gpioreg_blink_counter_select ( struct mvebu_gpio_chip
* mvchip )
{
return mvchip - > membase + GPIO_BLINK_CNT_SELECT_OFF ;
}
2017-03-16 09:34:01 +03:00
static void __iomem * mvebu_gpioreg_io_conf ( struct mvebu_gpio_chip * mvchip )
2012-09-20 00:52:58 +04:00
{
return mvchip - > membase + GPIO_IO_CONF_OFF ;
}
2017-03-16 09:34:01 +03:00
static void __iomem * mvebu_gpioreg_in_pol ( struct mvebu_gpio_chip * mvchip )
2012-09-20 00:52:58 +04:00
{
return mvchip - > membase + GPIO_IN_POL_OFF ;
}
2017-03-16 09:34:01 +03:00
static void __iomem * mvebu_gpioreg_data_in ( struct mvebu_gpio_chip * mvchip )
2012-09-20 00:52:58 +04:00
{
return mvchip - > membase + GPIO_DATA_IN_OFF ;
}
2017-03-16 09:34:01 +03:00
static void __iomem * mvebu_gpioreg_edge_cause ( struct mvebu_gpio_chip * mvchip )
2012-09-20 00:52:58 +04:00
{
int cpu ;
2013-03-20 16:15:56 +04:00
switch ( mvchip - > soc_variant ) {
2012-09-20 00:52:58 +04:00
case MVEBU_GPIO_SOC_VARIANT_ORION :
case MVEBU_GPIO_SOC_VARIANT_MV78200 :
return mvchip - > membase + GPIO_EDGE_CAUSE_OFF ;
case MVEBU_GPIO_SOC_VARIANT_ARMADAXP :
cpu = smp_processor_id ( ) ;
2015-01-10 02:34:47 +03:00
return mvchip - > percpu_membase +
GPIO_EDGE_CAUSE_ARMADAXP_OFF ( cpu ) ;
2012-09-20 00:52:58 +04:00
default :
BUG ( ) ;
}
}
2017-03-16 09:34:01 +03:00
static void __iomem * mvebu_gpioreg_edge_mask ( struct mvebu_gpio_chip * mvchip )
2012-09-20 00:52:58 +04:00
{
int cpu ;
2013-03-20 16:15:56 +04:00
switch ( mvchip - > soc_variant ) {
2012-09-20 00:52:58 +04:00
case MVEBU_GPIO_SOC_VARIANT_ORION :
return mvchip - > membase + GPIO_EDGE_MASK_OFF ;
case MVEBU_GPIO_SOC_VARIANT_MV78200 :
cpu = smp_processor_id ( ) ;
return mvchip - > membase + GPIO_EDGE_MASK_MV78200_OFF ( cpu ) ;
case MVEBU_GPIO_SOC_VARIANT_ARMADAXP :
cpu = smp_processor_id ( ) ;
2015-01-10 02:34:47 +03:00
return mvchip - > percpu_membase +
GPIO_EDGE_MASK_ARMADAXP_OFF ( cpu ) ;
2012-09-20 00:52:58 +04:00
default :
BUG ( ) ;
}
}
static void __iomem * mvebu_gpioreg_level_mask ( struct mvebu_gpio_chip * mvchip )
{
int cpu ;
2013-03-20 16:15:56 +04:00
switch ( mvchip - > soc_variant ) {
2012-09-20 00:52:58 +04:00
case MVEBU_GPIO_SOC_VARIANT_ORION :
return mvchip - > membase + GPIO_LEVEL_MASK_OFF ;
case MVEBU_GPIO_SOC_VARIANT_MV78200 :
cpu = smp_processor_id ( ) ;
return mvchip - > membase + GPIO_LEVEL_MASK_MV78200_OFF ( cpu ) ;
case MVEBU_GPIO_SOC_VARIANT_ARMADAXP :
cpu = smp_processor_id ( ) ;
2015-01-10 02:34:47 +03:00
return mvchip - > percpu_membase +
GPIO_LEVEL_MASK_ARMADAXP_OFF ( cpu ) ;
2012-09-20 00:52:58 +04:00
default :
BUG ( ) ;
}
}
2017-04-14 18:40:52 +03:00
/*
* Functions returning addresses of individual registers for a given
* PWM controller .
*/
static void __iomem * mvebu_pwmreg_blink_on_duration ( struct mvebu_pwm * mvpwm )
{
return mvpwm - > membase + PWM_BLINK_ON_DURATION_OFF ;
}
static void __iomem * mvebu_pwmreg_blink_off_duration ( struct mvebu_pwm * mvpwm )
{
return mvpwm - > membase + PWM_BLINK_OFF_DURATION_OFF ;
}
2012-09-20 00:52:58 +04:00
/*
* Functions implementing the gpio_chip methods
*/
2017-03-16 09:33:58 +03:00
static void mvebu_gpio_set ( struct gpio_chip * chip , unsigned int pin , int value )
2012-09-20 00:52:58 +04:00
{
2015-12-07 13:09:24 +03:00
struct mvebu_gpio_chip * mvchip = gpiochip_get_data ( chip ) ;
2012-09-20 00:52:58 +04:00
unsigned long flags ;
u32 u ;
spin_lock_irqsave ( & mvchip - > lock , flags ) ;
u = readl_relaxed ( mvebu_gpioreg_out ( mvchip ) ) ;
if ( value )
2017-03-17 20:44:06 +03:00
u | = BIT ( pin ) ;
2012-09-20 00:52:58 +04:00
else
2017-03-17 20:44:06 +03:00
u & = ~ BIT ( pin ) ;
2012-09-20 00:52:58 +04:00
writel_relaxed ( u , mvebu_gpioreg_out ( mvchip ) ) ;
spin_unlock_irqrestore ( & mvchip - > lock , flags ) ;
}
2017-03-16 09:33:58 +03:00
static int mvebu_gpio_get ( struct gpio_chip * chip , unsigned int pin )
2012-09-20 00:52:58 +04:00
{
2015-12-07 13:09:24 +03:00
struct mvebu_gpio_chip * mvchip = gpiochip_get_data ( chip ) ;
2012-09-20 00:52:58 +04:00
u32 u ;
2017-03-17 20:44:06 +03:00
if ( readl_relaxed ( mvebu_gpioreg_io_conf ( mvchip ) ) & BIT ( pin ) ) {
2012-09-20 00:52:58 +04:00
u = readl_relaxed ( mvebu_gpioreg_data_in ( mvchip ) ) ^
readl_relaxed ( mvebu_gpioreg_in_pol ( mvchip ) ) ;
} else {
u = readl_relaxed ( mvebu_gpioreg_out ( mvchip ) ) ;
}
return ( u > > pin ) & 1 ;
}
2017-03-16 09:33:58 +03:00
static void mvebu_gpio_blink ( struct gpio_chip * chip , unsigned int pin ,
int value )
2012-10-28 16:23:24 +04:00
{
2015-12-07 13:09:24 +03:00
struct mvebu_gpio_chip * mvchip = gpiochip_get_data ( chip ) ;
2012-10-28 16:23:24 +04:00
unsigned long flags ;
u32 u ;
spin_lock_irqsave ( & mvchip - > lock , flags ) ;
u = readl_relaxed ( mvebu_gpioreg_blink ( mvchip ) ) ;
if ( value )
2017-03-17 20:44:06 +03:00
u | = BIT ( pin ) ;
2012-10-28 16:23:24 +04:00
else
2017-03-17 20:44:06 +03:00
u & = ~ BIT ( pin ) ;
2012-10-28 16:23:24 +04:00
writel_relaxed ( u , mvebu_gpioreg_blink ( mvchip ) ) ;
spin_unlock_irqrestore ( & mvchip - > lock , flags ) ;
}
2017-03-16 09:33:58 +03:00
static int mvebu_gpio_direction_input ( struct gpio_chip * chip , unsigned int pin )
2012-09-20 00:52:58 +04:00
{
2015-12-07 13:09:24 +03:00
struct mvebu_gpio_chip * mvchip = gpiochip_get_data ( chip ) ;
2012-09-20 00:52:58 +04:00
unsigned long flags ;
int ret ;
u32 u ;
2017-03-16 09:33:56 +03:00
/*
* Check with the pinctrl driver whether this pin is usable as
* an input GPIO
*/
2012-09-20 00:52:58 +04:00
ret = pinctrl_gpio_direction_input ( chip - > base + pin ) ;
if ( ret )
return ret ;
spin_lock_irqsave ( & mvchip - > lock , flags ) ;
u = readl_relaxed ( mvebu_gpioreg_io_conf ( mvchip ) ) ;
2017-03-17 20:44:06 +03:00
u | = BIT ( pin ) ;
2012-09-20 00:52:58 +04:00
writel_relaxed ( u , mvebu_gpioreg_io_conf ( mvchip ) ) ;
spin_unlock_irqrestore ( & mvchip - > lock , flags ) ;
return 0 ;
}
2017-03-16 09:33:58 +03:00
static int mvebu_gpio_direction_output ( struct gpio_chip * chip , unsigned int pin ,
2012-09-20 00:52:58 +04:00
int value )
{
2015-12-07 13:09:24 +03:00
struct mvebu_gpio_chip * mvchip = gpiochip_get_data ( chip ) ;
2012-09-20 00:52:58 +04:00
unsigned long flags ;
int ret ;
u32 u ;
2017-03-16 09:33:56 +03:00
/*
* Check with the pinctrl driver whether this pin is usable as
* an output GPIO
*/
2012-09-20 00:52:58 +04:00
ret = pinctrl_gpio_direction_output ( chip - > base + pin ) ;
if ( ret )
return ret ;
2012-10-28 16:23:24 +04:00
mvebu_gpio_blink ( chip , pin , 0 ) ;
2012-10-23 12:17:05 +04:00
mvebu_gpio_set ( chip , pin , value ) ;
2012-09-20 00:52:58 +04:00
spin_lock_irqsave ( & mvchip - > lock , flags ) ;
u = readl_relaxed ( mvebu_gpioreg_io_conf ( mvchip ) ) ;
2017-03-17 20:44:06 +03:00
u & = ~ BIT ( pin ) ;
2012-09-20 00:52:58 +04:00
writel_relaxed ( u , mvebu_gpioreg_io_conf ( mvchip ) ) ;
spin_unlock_irqrestore ( & mvchip - > lock , flags ) ;
return 0 ;
}
2017-03-16 09:33:58 +03:00
static int mvebu_gpio_to_irq ( struct gpio_chip * chip , unsigned int pin )
2012-09-20 00:52:58 +04:00
{
2015-12-07 13:09:24 +03:00
struct mvebu_gpio_chip * mvchip = gpiochip_get_data ( chip ) ;
2017-03-16 09:33:59 +03:00
2012-09-20 00:52:58 +04:00
return irq_create_mapping ( mvchip - > domain , pin ) ;
}
/*
* Functions implementing the irq_chip methods
*/
static void mvebu_gpio_irq_ack ( struct irq_data * d )
{
struct irq_chip_generic * gc = irq_data_get_irq_chip_data ( d ) ;
struct mvebu_gpio_chip * mvchip = gc - > private ;
2016-10-20 00:03:41 +03:00
u32 mask = d - > mask ;
2012-09-20 00:52:58 +04:00
irq_gc_lock ( gc ) ;
2016-10-20 00:03:41 +03:00
writel_relaxed ( ~ mask , mvebu_gpioreg_edge_cause ( mvchip ) ) ;
2012-09-20 00:52:58 +04:00
irq_gc_unlock ( gc ) ;
}
static void mvebu_gpio_edge_irq_mask ( struct irq_data * d )
{
struct irq_chip_generic * gc = irq_data_get_irq_chip_data ( d ) ;
struct mvebu_gpio_chip * mvchip = gc - > private ;
2015-04-02 18:11:11 +03:00
struct irq_chip_type * ct = irq_data_get_chip_type ( d ) ;
2016-10-20 00:03:41 +03:00
u32 mask = d - > mask ;
2012-09-20 00:52:58 +04:00
irq_gc_lock ( gc ) ;
2015-04-02 18:11:11 +03:00
ct - > mask_cache_priv & = ~ mask ;
writel_relaxed ( ct - > mask_cache_priv , mvebu_gpioreg_edge_mask ( mvchip ) ) ;
2012-09-20 00:52:58 +04:00
irq_gc_unlock ( gc ) ;
}
static void mvebu_gpio_edge_irq_unmask ( struct irq_data * d )
{
struct irq_chip_generic * gc = irq_data_get_irq_chip_data ( d ) ;
struct mvebu_gpio_chip * mvchip = gc - > private ;
2015-04-02 18:11:11 +03:00
struct irq_chip_type * ct = irq_data_get_chip_type ( d ) ;
2016-10-20 00:03:41 +03:00
u32 mask = d - > mask ;
2012-09-20 00:52:58 +04:00
irq_gc_lock ( gc ) ;
2015-04-02 18:11:11 +03:00
ct - > mask_cache_priv | = mask ;
writel_relaxed ( ct - > mask_cache_priv , mvebu_gpioreg_edge_mask ( mvchip ) ) ;
2012-09-20 00:52:58 +04:00
irq_gc_unlock ( gc ) ;
}
static void mvebu_gpio_level_irq_mask ( struct irq_data * d )
{
struct irq_chip_generic * gc = irq_data_get_irq_chip_data ( d ) ;
struct mvebu_gpio_chip * mvchip = gc - > private ;
2015-04-02 18:11:11 +03:00
struct irq_chip_type * ct = irq_data_get_chip_type ( d ) ;
2016-10-20 00:03:41 +03:00
u32 mask = d - > mask ;
2012-09-20 00:52:58 +04:00
irq_gc_lock ( gc ) ;
2015-04-02 18:11:11 +03:00
ct - > mask_cache_priv & = ~ mask ;
writel_relaxed ( ct - > mask_cache_priv , mvebu_gpioreg_level_mask ( mvchip ) ) ;
2012-09-20 00:52:58 +04:00
irq_gc_unlock ( gc ) ;
}
static void mvebu_gpio_level_irq_unmask ( struct irq_data * d )
{
struct irq_chip_generic * gc = irq_data_get_irq_chip_data ( d ) ;
struct mvebu_gpio_chip * mvchip = gc - > private ;
2015-04-02 18:11:11 +03:00
struct irq_chip_type * ct = irq_data_get_chip_type ( d ) ;
2016-10-20 00:03:41 +03:00
u32 mask = d - > mask ;
2012-09-20 00:52:58 +04:00
irq_gc_lock ( gc ) ;
2015-04-02 18:11:11 +03:00
ct - > mask_cache_priv | = mask ;
writel_relaxed ( ct - > mask_cache_priv , mvebu_gpioreg_level_mask ( mvchip ) ) ;
2012-09-20 00:52:58 +04:00
irq_gc_unlock ( gc ) ;
}
/*****************************************************************************
* MVEBU GPIO IRQ
*
* GPIO_IN_POL register controls whether GPIO_DATA_IN will hold the same
* value of the line or the opposite value .
*
* Level IRQ handlers : DATA_IN is used directly as cause register .
2015-01-10 02:34:47 +03:00
* Interrupt are masked by LEVEL_MASK registers .
2012-09-20 00:52:58 +04:00
* Edge IRQ handlers : Change in DATA_IN are latched in EDGE_CAUSE .
2015-01-10 02:34:47 +03:00
* Interrupt are masked by EDGE_MASK registers .
2012-09-20 00:52:58 +04:00
* Both - edge handlers : Similar to regular Edge handlers , but also swaps
2015-01-10 02:34:47 +03:00
* the polarity to catch the next line transaction .
* This is a race condition that might not perfectly
* work on some use cases .
2012-09-20 00:52:58 +04:00
*
* Every eight GPIO lines are grouped ( OR ' ed ) before going up to main
* cause register .
*
2015-01-10 02:34:47 +03:00
* EDGE cause mask
* data - in / - - - - - - - - | | - - - - - | | - - - - \
* - - - - - | | - - - - - - - - - to main cause reg
* X \ - - - - - - - - - - - - - - - - | | - - - - /
* polarity LEVEL mask
2012-09-20 00:52:58 +04:00
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static int mvebu_gpio_irq_set_type ( struct irq_data * d , unsigned int type )
{
struct irq_chip_generic * gc = irq_data_get_irq_chip_data ( d ) ;
struct irq_chip_type * ct = irq_data_get_chip_type ( d ) ;
struct mvebu_gpio_chip * mvchip = gc - > private ;
int pin ;
u32 u ;
pin = d - > hwirq ;
2017-03-17 20:44:06 +03:00
u = readl_relaxed ( mvebu_gpioreg_io_conf ( mvchip ) ) & BIT ( pin ) ;
2015-01-10 02:34:47 +03:00
if ( ! u )
2012-09-20 00:52:58 +04:00
return - EINVAL ;
type & = IRQ_TYPE_SENSE_MASK ;
if ( type = = IRQ_TYPE_NONE )
return - EINVAL ;
/* Check if we need to change chip and handler */
if ( ! ( ct - > type & type ) )
if ( irq_setup_alt_chip ( d , type ) )
return - EINVAL ;
/*
* Configure interrupt polarity .
*/
2013-03-20 16:15:56 +04:00
switch ( type ) {
2012-09-20 00:52:58 +04:00
case IRQ_TYPE_EDGE_RISING :
case IRQ_TYPE_LEVEL_HIGH :
u = readl_relaxed ( mvebu_gpioreg_in_pol ( mvchip ) ) ;
2017-03-17 20:44:06 +03:00
u & = ~ BIT ( pin ) ;
2012-09-20 00:52:58 +04:00
writel_relaxed ( u , mvebu_gpioreg_in_pol ( mvchip ) ) ;
2012-09-30 12:23:27 +04:00
break ;
2012-09-20 00:52:58 +04:00
case IRQ_TYPE_EDGE_FALLING :
case IRQ_TYPE_LEVEL_LOW :
u = readl_relaxed ( mvebu_gpioreg_in_pol ( mvchip ) ) ;
2017-03-17 20:44:06 +03:00
u | = BIT ( pin ) ;
2012-09-20 00:52:58 +04:00
writel_relaxed ( u , mvebu_gpioreg_in_pol ( mvchip ) ) ;
2012-09-30 12:23:27 +04:00
break ;
2012-09-20 00:52:58 +04:00
case IRQ_TYPE_EDGE_BOTH : {
u32 v ;
v = readl_relaxed ( mvebu_gpioreg_in_pol ( mvchip ) ) ^
readl_relaxed ( mvebu_gpioreg_data_in ( mvchip ) ) ;
/*
* set initial polarity based on current input level
*/
u = readl_relaxed ( mvebu_gpioreg_in_pol ( mvchip ) ) ;
2017-03-17 20:44:06 +03:00
if ( v & BIT ( pin ) )
u | = BIT ( pin ) ; /* falling */
2012-09-20 00:52:58 +04:00
else
2017-03-17 20:44:06 +03:00
u & = ~ BIT ( pin ) ; /* rising */
2012-09-20 00:52:58 +04:00
writel_relaxed ( u , mvebu_gpioreg_in_pol ( mvchip ) ) ;
2012-09-30 12:23:27 +04:00
break ;
2012-09-20 00:52:58 +04:00
}
}
return 0 ;
}
2015-09-14 11:42:37 +03:00
static void mvebu_gpio_irq_handler ( struct irq_desc * desc )
2012-09-20 00:52:58 +04:00
{
2015-06-04 07:13:15 +03:00
struct mvebu_gpio_chip * mvchip = irq_desc_get_handler_data ( desc ) ;
2014-02-07 15:29:19 +04:00
struct irq_chip * chip = irq_desc_get_chip ( desc ) ;
2012-09-20 00:52:58 +04:00
u32 cause , type ;
int i ;
if ( mvchip = = NULL )
return ;
2014-02-07 15:29:19 +04:00
chained_irq_enter ( chip , desc ) ;
2012-09-20 00:52:58 +04:00
cause = readl_relaxed ( mvebu_gpioreg_data_in ( mvchip ) ) &
readl_relaxed ( mvebu_gpioreg_level_mask ( mvchip ) ) ;
cause | = readl_relaxed ( mvebu_gpioreg_edge_cause ( mvchip ) ) &
readl_relaxed ( mvebu_gpioreg_edge_mask ( mvchip ) ) ;
for ( i = 0 ; i < mvchip - > chip . ngpio ; i + + ) {
int irq ;
2016-10-20 00:03:41 +03:00
irq = irq_find_mapping ( mvchip - > domain , i ) ;
2012-09-20 00:52:58 +04:00
2017-03-17 20:44:06 +03:00
if ( ! ( cause & BIT ( i ) ) )
2012-09-20 00:52:58 +04:00
continue ;
2013-06-14 20:40:44 +04:00
type = irq_get_trigger_type ( irq ) ;
2012-09-20 00:52:58 +04:00
if ( ( type & IRQ_TYPE_SENSE_MASK ) = = IRQ_TYPE_EDGE_BOTH ) {
/* Swap polarity (race with GPIO line) */
u32 polarity ;
polarity = readl_relaxed ( mvebu_gpioreg_in_pol ( mvchip ) ) ;
2017-03-17 20:44:06 +03:00
polarity ^ = BIT ( i ) ;
2012-09-20 00:52:58 +04:00
writel_relaxed ( polarity , mvebu_gpioreg_in_pol ( mvchip ) ) ;
}
2014-02-07 15:29:19 +04:00
2012-09-20 00:52:58 +04:00
generic_handle_irq ( irq ) ;
}
2014-02-07 15:29:19 +04:00
chained_irq_exit ( chip , desc ) ;
2012-09-20 00:52:58 +04:00
}
2017-04-14 18:40:52 +03:00
/*
* Functions implementing the pwm_chip methods
*/
static struct mvebu_pwm * to_mvebu_pwm ( struct pwm_chip * chip )
{
return container_of ( chip , struct mvebu_pwm , chip ) ;
}
static int mvebu_pwm_request ( struct pwm_chip * chip , struct pwm_device * pwm )
{
struct mvebu_pwm * mvpwm = to_mvebu_pwm ( chip ) ;
struct mvebu_gpio_chip * mvchip = mvpwm - > mvchip ;
struct gpio_desc * desc ;
unsigned long flags ;
int ret = 0 ;
spin_lock_irqsave ( & mvpwm - > lock , flags ) ;
if ( mvpwm - > gpiod ) {
ret = - EBUSY ;
} else {
desc = gpio_to_desc ( mvchip - > chip . base + pwm - > hwpwm ) ;
if ( ! desc ) {
ret = - ENODEV ;
goto out ;
}
ret = gpiod_request ( desc , " mvebu-pwm " ) ;
if ( ret )
goto out ;
ret = gpiod_direction_output ( desc , 0 ) ;
if ( ret ) {
gpiod_free ( desc ) ;
goto out ;
}
mvpwm - > gpiod = desc ;
}
out :
spin_unlock_irqrestore ( & mvpwm - > lock , flags ) ;
return ret ;
}
static void mvebu_pwm_free ( struct pwm_chip * chip , struct pwm_device * pwm )
{
struct mvebu_pwm * mvpwm = to_mvebu_pwm ( chip ) ;
unsigned long flags ;
spin_lock_irqsave ( & mvpwm - > lock , flags ) ;
gpiod_free ( mvpwm - > gpiod ) ;
mvpwm - > gpiod = NULL ;
spin_unlock_irqrestore ( & mvpwm - > lock , flags ) ;
}
static void mvebu_pwm_get_state ( struct pwm_chip * chip ,
struct pwm_device * pwm ,
struct pwm_state * state ) {
struct mvebu_pwm * mvpwm = to_mvebu_pwm ( chip ) ;
struct mvebu_gpio_chip * mvchip = mvpwm - > mvchip ;
unsigned long long val ;
unsigned long flags ;
u32 u ;
spin_lock_irqsave ( & mvpwm - > lock , flags ) ;
val = ( unsigned long long )
readl_relaxed ( mvebu_pwmreg_blink_on_duration ( mvpwm ) ) ;
val * = NSEC_PER_SEC ;
do_div ( val , mvpwm - > clk_rate ) ;
if ( val > UINT_MAX )
state - > duty_cycle = UINT_MAX ;
else if ( val )
state - > duty_cycle = val ;
else
state - > duty_cycle = 1 ;
val = ( unsigned long long )
readl_relaxed ( mvebu_pwmreg_blink_off_duration ( mvpwm ) ) ;
val * = NSEC_PER_SEC ;
do_div ( val , mvpwm - > clk_rate ) ;
if ( val < state - > duty_cycle ) {
state - > period = 1 ;
} else {
val - = state - > duty_cycle ;
if ( val > UINT_MAX )
state - > period = UINT_MAX ;
else if ( val )
state - > period = val ;
else
state - > period = 1 ;
}
u = readl_relaxed ( mvebu_gpioreg_blink ( mvchip ) ) ;
if ( u )
state - > enabled = true ;
else
state - > enabled = false ;
spin_unlock_irqrestore ( & mvpwm - > lock , flags ) ;
}
static int mvebu_pwm_apply ( struct pwm_chip * chip , struct pwm_device * pwm ,
struct pwm_state * state )
{
struct mvebu_pwm * mvpwm = to_mvebu_pwm ( chip ) ;
struct mvebu_gpio_chip * mvchip = mvpwm - > mvchip ;
unsigned long long val ;
unsigned long flags ;
unsigned int on , off ;
val = ( unsigned long long ) mvpwm - > clk_rate * state - > duty_cycle ;
do_div ( val , NSEC_PER_SEC ) ;
if ( val > UINT_MAX )
return - EINVAL ;
if ( val )
on = val ;
else
on = 1 ;
val = ( unsigned long long ) mvpwm - > clk_rate *
( state - > period - state - > duty_cycle ) ;
do_div ( val , NSEC_PER_SEC ) ;
if ( val > UINT_MAX )
return - EINVAL ;
if ( val )
off = val ;
else
off = 1 ;
spin_lock_irqsave ( & mvpwm - > lock , flags ) ;
writel_relaxed ( on , mvebu_pwmreg_blink_on_duration ( mvpwm ) ) ;
writel_relaxed ( off , mvebu_pwmreg_blink_off_duration ( mvpwm ) ) ;
if ( state - > enabled )
mvebu_gpio_blink ( & mvchip - > chip , pwm - > hwpwm , 1 ) ;
else
mvebu_gpio_blink ( & mvchip - > chip , pwm - > hwpwm , 0 ) ;
spin_unlock_irqrestore ( & mvpwm - > lock , flags ) ;
return 0 ;
}
static const struct pwm_ops mvebu_pwm_ops = {
. request = mvebu_pwm_request ,
. free = mvebu_pwm_free ,
. get_state = mvebu_pwm_get_state ,
. apply = mvebu_pwm_apply ,
. owner = THIS_MODULE ,
} ;
static void __maybe_unused mvebu_pwm_suspend ( struct mvebu_gpio_chip * mvchip )
{
struct mvebu_pwm * mvpwm = mvchip - > mvpwm ;
mvpwm - > blink_select =
readl_relaxed ( mvebu_gpioreg_blink_counter_select ( mvchip ) ) ;
mvpwm - > blink_on_duration =
readl_relaxed ( mvebu_pwmreg_blink_on_duration ( mvpwm ) ) ;
mvpwm - > blink_off_duration =
readl_relaxed ( mvebu_pwmreg_blink_off_duration ( mvpwm ) ) ;
}
static void __maybe_unused mvebu_pwm_resume ( struct mvebu_gpio_chip * mvchip )
{
struct mvebu_pwm * mvpwm = mvchip - > mvpwm ;
writel_relaxed ( mvpwm - > blink_select ,
mvebu_gpioreg_blink_counter_select ( mvchip ) ) ;
writel_relaxed ( mvpwm - > blink_on_duration ,
mvebu_pwmreg_blink_on_duration ( mvpwm ) ) ;
writel_relaxed ( mvpwm - > blink_off_duration ,
mvebu_pwmreg_blink_off_duration ( mvpwm ) ) ;
}
static int mvebu_pwm_probe ( struct platform_device * pdev ,
struct mvebu_gpio_chip * mvchip ,
int id )
{
struct device * dev = & pdev - > dev ;
struct mvebu_pwm * mvpwm ;
struct resource * res ;
u32 set ;
if ( ! of_device_is_compatible ( mvchip - > chip . of_node ,
" marvell,armada-370-xp-gpio " ) )
return 0 ;
if ( IS_ERR ( mvchip - > clk ) )
return PTR_ERR ( mvchip - > clk ) ;
/*
* There are only two sets of PWM configuration registers for
* all the GPIO lines on those SoCs which this driver reserves
* for the first two GPIO chips . So if the resource is missing
* we can ' t treat it as an error .
*/
res = platform_get_resource_byname ( pdev , IORESOURCE_MEM , " pwm " ) ;
if ( ! res )
return 0 ;
/*
* Use set A for lines of GPIO chip with id 0 , B for GPIO chip
* with id 1. Don ' t allow further GPIO chips to be used for PWM .
*/
if ( id = = 0 )
set = 0 ;
else if ( id = = 1 )
set = U32_MAX ;
else
return - EINVAL ;
writel_relaxed ( 0 , mvebu_gpioreg_blink_counter_select ( mvchip ) ) ;
mvpwm = devm_kzalloc ( dev , sizeof ( struct mvebu_pwm ) , GFP_KERNEL ) ;
if ( ! mvpwm )
return - ENOMEM ;
mvchip - > mvpwm = mvpwm ;
mvpwm - > mvchip = mvchip ;
mvpwm - > membase = devm_ioremap_resource ( dev , res ) ;
if ( IS_ERR ( mvpwm - > membase ) )
return PTR_ERR ( mvpwm - > membase ) ;
mvpwm - > clk_rate = clk_get_rate ( mvchip - > clk ) ;
if ( ! mvpwm - > clk_rate ) {
dev_err ( dev , " failed to get clock rate \n " ) ;
return - EINVAL ;
}
mvpwm - > chip . dev = dev ;
mvpwm - > chip . ops = & mvebu_pwm_ops ;
mvpwm - > chip . npwm = mvchip - > chip . ngpio ;
spin_lock_init ( & mvpwm - > lock ) ;
return pwmchip_add ( & mvpwm - > chip ) ;
}
2013-03-24 18:45:29 +04:00
# ifdef CONFIG_DEBUG_FS
# include <linux/seq_file.h>
static void mvebu_gpio_dbg_show ( struct seq_file * s , struct gpio_chip * chip )
{
2015-12-07 13:09:24 +03:00
struct mvebu_gpio_chip * mvchip = gpiochip_get_data ( chip ) ;
2013-03-24 18:45:29 +04:00
u32 out , io_conf , blink , in_pol , data_in , cause , edg_msk , lvl_msk ;
int i ;
out = readl_relaxed ( mvebu_gpioreg_out ( mvchip ) ) ;
io_conf = readl_relaxed ( mvebu_gpioreg_io_conf ( mvchip ) ) ;
blink = readl_relaxed ( mvebu_gpioreg_blink ( mvchip ) ) ;
in_pol = readl_relaxed ( mvebu_gpioreg_in_pol ( mvchip ) ) ;
data_in = readl_relaxed ( mvebu_gpioreg_data_in ( mvchip ) ) ;
cause = readl_relaxed ( mvebu_gpioreg_edge_cause ( mvchip ) ) ;
edg_msk = readl_relaxed ( mvebu_gpioreg_edge_mask ( mvchip ) ) ;
lvl_msk = readl_relaxed ( mvebu_gpioreg_level_mask ( mvchip ) ) ;
for ( i = 0 ; i < chip - > ngpio ; i + + ) {
const char * label ;
u32 msk ;
bool is_out ;
label = gpiochip_is_requested ( chip , i ) ;
if ( ! label )
continue ;
2017-03-17 20:44:06 +03:00
msk = BIT ( i ) ;
2013-03-24 18:45:29 +04:00
is_out = ! ( io_conf & msk ) ;
seq_printf ( s , " gpio-%-3d (%-20.20s) " , chip - > base + i , label ) ;
if ( is_out ) {
seq_printf ( s , " out %s %s \n " ,
out & msk ? " hi " : " lo " ,
blink & msk ? " (blink ) " : " " ) ;
continue ;
}
seq_printf ( s , " in %s (act %s) - IRQ " ,
( data_in ^ in_pol ) & msk ? " hi " : " lo " ,
in_pol & msk ? " lo " : " hi " ) ;
if ( ! ( ( edg_msk | lvl_msk ) & msk ) ) {
2015-01-10 02:34:47 +03:00
seq_puts ( s , " disabled \n " ) ;
2013-03-24 18:45:29 +04:00
continue ;
}
if ( edg_msk & msk )
2015-01-10 02:34:47 +03:00
seq_puts ( s , " edge " ) ;
2013-03-24 18:45:29 +04:00
if ( lvl_msk & msk )
2015-01-10 02:34:47 +03:00
seq_puts ( s , " level " ) ;
2013-03-24 18:45:29 +04:00
seq_printf ( s , " (%s) \n " , cause & msk ? " pending " : " clear " ) ;
}
}
# else
# define mvebu_gpio_dbg_show NULL
# endif
2014-05-07 13:06:08 +04:00
static const struct of_device_id mvebu_gpio_of_match [ ] = {
2012-09-20 00:52:58 +04:00
{
. compatible = " marvell,orion-gpio " ,
2015-01-10 02:34:47 +03:00
. data = ( void * ) MVEBU_GPIO_SOC_VARIANT_ORION ,
2012-09-20 00:52:58 +04:00
} ,
{
. compatible = " marvell,mv78200-gpio " ,
2015-01-10 02:34:47 +03:00
. data = ( void * ) MVEBU_GPIO_SOC_VARIANT_MV78200 ,
2012-09-20 00:52:58 +04:00
} ,
{
. compatible = " marvell,armadaxp-gpio " ,
2015-01-10 02:34:47 +03:00
. data = ( void * ) MVEBU_GPIO_SOC_VARIANT_ARMADAXP ,
2012-09-20 00:52:58 +04:00
} ,
2017-04-14 18:40:52 +03:00
{
. compatible = " marvell,armada-370-xp-gpio " ,
. data = ( void * ) MVEBU_GPIO_SOC_VARIANT_ORION ,
} ,
2012-09-20 00:52:58 +04:00
{
/* sentinel */
} ,
} ;
2014-10-24 15:59:19 +04:00
static int mvebu_gpio_suspend ( struct platform_device * pdev , pm_message_t state )
{
struct mvebu_gpio_chip * mvchip = platform_get_drvdata ( pdev ) ;
int i ;
mvchip - > out_reg = readl ( mvebu_gpioreg_out ( mvchip ) ) ;
mvchip - > io_conf_reg = readl ( mvebu_gpioreg_io_conf ( mvchip ) ) ;
mvchip - > blink_en_reg = readl ( mvebu_gpioreg_blink ( mvchip ) ) ;
mvchip - > in_pol_reg = readl ( mvebu_gpioreg_in_pol ( mvchip ) ) ;
switch ( mvchip - > soc_variant ) {
case MVEBU_GPIO_SOC_VARIANT_ORION :
mvchip - > edge_mask_regs [ 0 ] =
readl ( mvchip - > membase + GPIO_EDGE_MASK_OFF ) ;
mvchip - > level_mask_regs [ 0 ] =
readl ( mvchip - > membase + GPIO_LEVEL_MASK_OFF ) ;
break ;
case MVEBU_GPIO_SOC_VARIANT_MV78200 :
for ( i = 0 ; i < 2 ; i + + ) {
mvchip - > edge_mask_regs [ i ] =
readl ( mvchip - > membase +
GPIO_EDGE_MASK_MV78200_OFF ( i ) ) ;
mvchip - > level_mask_regs [ i ] =
readl ( mvchip - > membase +
GPIO_LEVEL_MASK_MV78200_OFF ( i ) ) ;
}
break ;
case MVEBU_GPIO_SOC_VARIANT_ARMADAXP :
for ( i = 0 ; i < 4 ; i + + ) {
mvchip - > edge_mask_regs [ i ] =
readl ( mvchip - > membase +
GPIO_EDGE_MASK_ARMADAXP_OFF ( i ) ) ;
mvchip - > level_mask_regs [ i ] =
readl ( mvchip - > membase +
GPIO_LEVEL_MASK_ARMADAXP_OFF ( i ) ) ;
}
break ;
default :
BUG ( ) ;
}
2017-04-14 18:40:52 +03:00
if ( IS_ENABLED ( CONFIG_PWM ) )
mvebu_pwm_suspend ( mvchip ) ;
2014-10-24 15:59:19 +04:00
return 0 ;
}
static int mvebu_gpio_resume ( struct platform_device * pdev )
{
struct mvebu_gpio_chip * mvchip = platform_get_drvdata ( pdev ) ;
int i ;
writel ( mvchip - > out_reg , mvebu_gpioreg_out ( mvchip ) ) ;
writel ( mvchip - > io_conf_reg , mvebu_gpioreg_io_conf ( mvchip ) ) ;
writel ( mvchip - > blink_en_reg , mvebu_gpioreg_blink ( mvchip ) ) ;
writel ( mvchip - > in_pol_reg , mvebu_gpioreg_in_pol ( mvchip ) ) ;
switch ( mvchip - > soc_variant ) {
case MVEBU_GPIO_SOC_VARIANT_ORION :
writel ( mvchip - > edge_mask_regs [ 0 ] ,
mvchip - > membase + GPIO_EDGE_MASK_OFF ) ;
writel ( mvchip - > level_mask_regs [ 0 ] ,
mvchip - > membase + GPIO_LEVEL_MASK_OFF ) ;
break ;
case MVEBU_GPIO_SOC_VARIANT_MV78200 :
for ( i = 0 ; i < 2 ; i + + ) {
writel ( mvchip - > edge_mask_regs [ i ] ,
mvchip - > membase + GPIO_EDGE_MASK_MV78200_OFF ( i ) ) ;
writel ( mvchip - > level_mask_regs [ i ] ,
mvchip - > membase +
GPIO_LEVEL_MASK_MV78200_OFF ( i ) ) ;
}
break ;
case MVEBU_GPIO_SOC_VARIANT_ARMADAXP :
for ( i = 0 ; i < 4 ; i + + ) {
writel ( mvchip - > edge_mask_regs [ i ] ,
mvchip - > membase +
GPIO_EDGE_MASK_ARMADAXP_OFF ( i ) ) ;
writel ( mvchip - > level_mask_regs [ i ] ,
mvchip - > membase +
GPIO_LEVEL_MASK_ARMADAXP_OFF ( i ) ) ;
}
break ;
default :
BUG ( ) ;
}
2017-04-14 18:40:52 +03:00
if ( IS_ENABLED ( CONFIG_PWM ) )
mvebu_pwm_resume ( mvchip ) ;
2014-10-24 15:59:19 +04:00
return 0 ;
}
2012-11-19 22:22:34 +04:00
static int mvebu_gpio_probe ( struct platform_device * pdev )
2012-09-20 00:52:58 +04:00
{
struct mvebu_gpio_chip * mvchip ;
const struct of_device_id * match ;
struct device_node * np = pdev - > dev . of_node ;
struct resource * res ;
struct irq_chip_generic * gc ;
struct irq_chip_type * ct ;
unsigned int ngpios ;
2016-10-20 00:03:41 +03:00
bool have_irqs ;
2012-09-20 00:52:58 +04:00
int soc_variant ;
int i , cpu , id ;
2015-01-10 02:34:48 +03:00
int err ;
2012-09-20 00:52:58 +04:00
match = of_match_device ( mvebu_gpio_of_match , & pdev - > dev ) ;
if ( match )
2017-01-11 01:53:28 +03:00
soc_variant = ( unsigned long ) match - > data ;
2012-09-20 00:52:58 +04:00
else
soc_variant = MVEBU_GPIO_SOC_VARIANT_ORION ;
2016-10-20 00:03:41 +03:00
/* Some gpio controllers do not provide irq support */
have_irqs = of_irq_count ( np ) ! = 0 ;
2015-01-10 02:34:47 +03:00
mvchip = devm_kzalloc ( & pdev - > dev , sizeof ( struct mvebu_gpio_chip ) ,
GFP_KERNEL ) ;
2014-04-29 12:38:21 +04:00
if ( ! mvchip )
2012-09-20 00:52:58 +04:00
return - ENOMEM ;
2014-10-24 15:59:19 +04:00
platform_set_drvdata ( pdev , mvchip ) ;
2012-09-20 00:52:58 +04:00
if ( of_property_read_u32 ( pdev - > dev . of_node , " ngpios " , & ngpios ) ) {
dev_err ( & pdev - > dev , " Missing ngpios OF property \n " ) ;
return - ENODEV ;
}
id = of_alias_get_id ( pdev - > dev . of_node , " gpio " ) ;
if ( id < 0 ) {
dev_err ( & pdev - > dev , " Couldn't get OF id \n " ) ;
return id ;
}
2017-04-14 18:40:52 +03:00
mvchip - > clk = devm_clk_get ( & pdev - > dev , NULL ) ;
2013-02-03 14:34:26 +04:00
/* Not all SoCs require a clock.*/
2017-04-14 18:40:52 +03:00
if ( ! IS_ERR ( mvchip - > clk ) )
clk_prepare_enable ( mvchip - > clk ) ;
2013-02-03 14:34:26 +04:00
2012-09-20 00:52:58 +04:00
mvchip - > soc_variant = soc_variant ;
mvchip - > chip . label = dev_name ( & pdev - > dev ) ;
2015-11-04 11:56:26 +03:00
mvchip - > chip . parent = & pdev - > dev ;
2015-10-11 18:34:16 +03:00
mvchip - > chip . request = gpiochip_generic_request ;
mvchip - > chip . free = gpiochip_generic_free ;
2012-09-20 00:52:58 +04:00
mvchip - > chip . direction_input = mvebu_gpio_direction_input ;
mvchip - > chip . get = mvebu_gpio_get ;
mvchip - > chip . direction_output = mvebu_gpio_direction_output ;
mvchip - > chip . set = mvebu_gpio_set ;
2016-10-20 00:03:41 +03:00
if ( have_irqs )
mvchip - > chip . to_irq = mvebu_gpio_to_irq ;
2012-09-20 00:52:58 +04:00
mvchip - > chip . base = id * MVEBU_MAX_GPIO_PER_BANK ;
mvchip - > chip . ngpio = ngpios ;
2013-12-04 17:42:46 +04:00
mvchip - > chip . can_sleep = false ;
2012-09-20 00:52:58 +04:00
mvchip - > chip . of_node = np ;
2013-03-24 18:45:29 +04:00
mvchip - > chip . dbg_show = mvebu_gpio_dbg_show ;
2012-09-20 00:52:58 +04:00
spin_lock_init ( & mvchip - > lock ) ;
2013-08-14 13:11:07 +04:00
res = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
2013-01-21 14:09:01 +04:00
mvchip - > membase = devm_ioremap_resource ( & pdev - > dev , res ) ;
2013-01-26 09:06:30 +04:00
if ( IS_ERR ( mvchip - > membase ) )
2013-01-21 14:09:01 +04:00
return PTR_ERR ( mvchip - > membase ) ;
2012-09-20 00:52:58 +04:00
2017-03-16 09:33:56 +03:00
/*
* The Armada XP has a second range of registers for the
* per - CPU registers
*/
2012-09-20 00:52:58 +04:00
if ( soc_variant = = MVEBU_GPIO_SOC_VARIANT_ARMADAXP ) {
res = platform_get_resource ( pdev , IORESOURCE_MEM , 1 ) ;
2013-01-21 14:09:01 +04:00
mvchip - > percpu_membase = devm_ioremap_resource ( & pdev - > dev ,
res ) ;
2013-03-20 16:15:56 +04:00
if ( IS_ERR ( mvchip - > percpu_membase ) )
2013-01-21 14:09:01 +04:00
return PTR_ERR ( mvchip - > percpu_membase ) ;
2012-09-20 00:52:58 +04:00
}
/*
* Mask and clear GPIO interrupts .
*/
2013-03-20 16:15:56 +04:00
switch ( soc_variant ) {
2012-09-20 00:52:58 +04:00
case MVEBU_GPIO_SOC_VARIANT_ORION :
writel_relaxed ( 0 , mvchip - > membase + GPIO_EDGE_CAUSE_OFF ) ;
writel_relaxed ( 0 , mvchip - > membase + GPIO_EDGE_MASK_OFF ) ;
writel_relaxed ( 0 , mvchip - > membase + GPIO_LEVEL_MASK_OFF ) ;
break ;
case MVEBU_GPIO_SOC_VARIANT_MV78200 :
writel_relaxed ( 0 , mvchip - > membase + GPIO_EDGE_CAUSE_OFF ) ;
for ( cpu = 0 ; cpu < 2 ; cpu + + ) {
writel_relaxed ( 0 , mvchip - > membase +
GPIO_EDGE_MASK_MV78200_OFF ( cpu ) ) ;
writel_relaxed ( 0 , mvchip - > membase +
GPIO_LEVEL_MASK_MV78200_OFF ( cpu ) ) ;
}
break ;
case MVEBU_GPIO_SOC_VARIANT_ARMADAXP :
writel_relaxed ( 0 , mvchip - > membase + GPIO_EDGE_CAUSE_OFF ) ;
writel_relaxed ( 0 , mvchip - > membase + GPIO_EDGE_MASK_OFF ) ;
writel_relaxed ( 0 , mvchip - > membase + GPIO_LEVEL_MASK_OFF ) ;
for ( cpu = 0 ; cpu < 4 ; cpu + + ) {
writel_relaxed ( 0 , mvchip - > percpu_membase +
GPIO_EDGE_CAUSE_ARMADAXP_OFF ( cpu ) ) ;
writel_relaxed ( 0 , mvchip - > percpu_membase +
GPIO_EDGE_MASK_ARMADAXP_OFF ( cpu ) ) ;
writel_relaxed ( 0 , mvchip - > percpu_membase +
GPIO_LEVEL_MASK_ARMADAXP_OFF ( cpu ) ) ;
}
break ;
default :
BUG ( ) ;
}
2016-02-22 15:13:28 +03:00
devm_gpiochip_add_data ( & pdev - > dev , & mvchip - > chip , mvchip ) ;
2012-09-20 00:52:58 +04:00
/* Some gpio controllers do not provide irq support */
2016-10-20 00:03:41 +03:00
if ( ! have_irqs )
2012-09-20 00:52:58 +04:00
return 0 ;
2016-10-20 00:03:41 +03:00
mvchip - > domain =
irq_domain_add_linear ( np , ngpios , & irq_generic_chip_ops , NULL ) ;
if ( ! mvchip - > domain ) {
dev_err ( & pdev - > dev , " couldn't allocate irq domain %s (DT). \n " ,
mvchip - > chip . label ) ;
return - ENODEV ;
2012-09-20 00:52:58 +04:00
}
2016-10-20 00:03:41 +03:00
err = irq_alloc_domain_generic_chips (
mvchip - > domain , ngpios , 2 , np - > name , handle_level_irq ,
IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_LEVEL , 0 , 0 ) ;
if ( err ) {
dev_err ( & pdev - > dev , " couldn't allocate irq chips %s (DT). \n " ,
mvchip - > chip . label ) ;
goto err_domain ;
2012-09-20 00:52:58 +04:00
}
2017-03-16 09:33:57 +03:00
/*
* NOTE : The common accessors cannot be used because of the percpu
2016-10-20 00:03:41 +03:00
* access to the mask registers
*/
gc = irq_get_domain_generic_chip ( mvchip - > domain , 0 ) ;
2012-09-20 00:52:58 +04:00
gc - > private = mvchip ;
ct = & gc - > chip_types [ 0 ] ;
ct - > type = IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW ;
ct - > chip . irq_mask = mvebu_gpio_level_irq_mask ;
ct - > chip . irq_unmask = mvebu_gpio_level_irq_unmask ;
ct - > chip . irq_set_type = mvebu_gpio_irq_set_type ;
ct - > chip . name = mvchip - > chip . label ;
ct = & gc - > chip_types [ 1 ] ;
ct - > type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING ;
ct - > chip . irq_ack = mvebu_gpio_irq_ack ;
ct - > chip . irq_mask = mvebu_gpio_edge_irq_mask ;
ct - > chip . irq_unmask = mvebu_gpio_edge_irq_unmask ;
ct - > chip . irq_set_type = mvebu_gpio_irq_set_type ;
ct - > handler = handle_edge_irq ;
ct - > chip . name = mvchip - > chip . label ;
2017-03-16 09:33:57 +03:00
/*
* Setup the interrupt handlers . Each chip can have up to 4
2016-10-20 00:03:41 +03:00
* interrupt handlers , with each handler dealing with 8 GPIO
* pins .
*/
for ( i = 0 ; i < 4 ; i + + ) {
int irq = platform_get_irq ( pdev , i ) ;
2012-09-20 00:52:58 +04:00
2016-10-20 00:03:41 +03:00
if ( irq < 0 )
continue ;
irq_set_chained_handler_and_data ( irq , mvebu_gpio_irq_handler ,
mvchip ) ;
2012-09-20 00:52:58 +04:00
}
2017-04-14 18:40:52 +03:00
/* Armada 370/XP has simple PWM support for GPIO lines */
if ( IS_ENABLED ( CONFIG_PWM ) )
return mvebu_pwm_probe ( pdev , mvchip , id ) ;
2012-09-20 00:52:58 +04:00
return 0 ;
2015-01-10 02:34:48 +03:00
2016-10-20 00:03:41 +03:00
err_domain :
irq_domain_remove ( mvchip - > domain ) ;
2015-01-10 02:34:48 +03:00
return err ;
2012-09-20 00:52:58 +04:00
}
static struct platform_driver mvebu_gpio_driver = {
. driver = {
2015-01-10 02:34:47 +03:00
. name = " mvebu-gpio " ,
2012-09-20 00:52:58 +04:00
. of_match_table = mvebu_gpio_of_match ,
} ,
. probe = mvebu_gpio_probe ,
2014-10-24 15:59:19 +04:00
. suspend = mvebu_gpio_suspend ,
. resume = mvebu_gpio_resume ,
2012-09-20 00:52:58 +04:00
} ;
2016-03-27 18:44:45 +03:00
builtin_platform_driver ( mvebu_gpio_driver ) ;