2018-04-04 22:52:52 +05:30
// SPDX-License-Identifier: GPL-2.0+
/*
* OWL SoC ' s Pinctrl driver
*
* Copyright ( c ) 2014 Actions Semi Inc .
* Author : David Liu < liuwei @ actions - semi . com >
*
* Copyright ( c ) 2018 Linaro Ltd .
* Author : Manivannan Sadhasivam < manivannan . sadhasivam @ linaro . org >
*/
# include <linux/clk.h>
# include <linux/err.h>
2018-05-20 10:47:35 +05:30
# include <linux/gpio/driver.h>
2018-04-04 22:52:52 +05:30
# include <linux/io.h>
2018-06-23 10:29:54 +05:30
# include <linux/irq.h>
2018-04-04 22:52:52 +05:30
# include <linux/module.h>
# include <linux/of.h>
# include <linux/platform_device.h>
# include <linux/pinctrl/machine.h>
# include <linux/pinctrl/pinctrl.h>
# include <linux/pinctrl/pinmux.h>
# include <linux/pinctrl/pinconf.h>
# include <linux/pinctrl/pinconf-generic.h>
# include <linux/slab.h>
# include <linux/spinlock.h>
# include "../core.h"
# include "../pinctrl-utils.h"
# include "pinctrl-owl.h"
/**
* struct owl_pinctrl - pinctrl state of the device
* @ dev : device handle
* @ pctrldev : pinctrl handle
2018-05-20 10:47:35 +05:30
* @ chip : gpio chip
2018-04-04 22:52:52 +05:30
* @ lock : spinlock to protect registers
2020-07-13 15:49:06 +01:00
* @ clk : clock control
2018-04-04 22:52:52 +05:30
* @ soc : reference to soc_data
* @ base : pinctrl register base address
2020-07-13 15:49:06 +01:00
* @ irq_chip : IRQ chip information
* @ num_irq : number of possible interrupts
* @ irq : interrupt numbers
2018-04-04 22:52:52 +05:30
*/
struct owl_pinctrl {
struct device * dev ;
struct pinctrl_dev * pctrldev ;
2018-05-20 10:47:35 +05:30
struct gpio_chip chip ;
2018-04-04 22:52:52 +05:30
raw_spinlock_t lock ;
struct clk * clk ;
const struct owl_pinctrl_soc_data * soc ;
void __iomem * base ;
2018-06-23 10:29:54 +05:30
struct irq_chip irq_chip ;
unsigned int num_irq ;
unsigned int * irq ;
2018-04-04 22:52:52 +05:30
} ;
static void owl_update_bits ( void __iomem * base , u32 mask , u32 val )
{
u32 reg_val ;
reg_val = readl_relaxed ( base ) ;
reg_val = ( reg_val & ~ mask ) | ( val & mask ) ;
writel_relaxed ( reg_val , base ) ;
}
static u32 owl_read_field ( struct owl_pinctrl * pctrl , u32 reg ,
u32 bit , u32 width )
{
u32 tmp , mask ;
tmp = readl_relaxed ( pctrl - > base + reg ) ;
mask = ( 1 < < width ) - 1 ;
return ( tmp > > bit ) & mask ;
}
static void owl_write_field ( struct owl_pinctrl * pctrl , u32 reg , u32 arg ,
u32 bit , u32 width )
{
u32 mask ;
mask = ( 1 < < width ) - 1 ;
mask = mask < < bit ;
owl_update_bits ( pctrl - > base + reg , mask , ( arg < < bit ) ) ;
}
static int owl_get_groups_count ( struct pinctrl_dev * pctrldev )
{
struct owl_pinctrl * pctrl = pinctrl_dev_get_drvdata ( pctrldev ) ;
return pctrl - > soc - > ngroups ;
}
static const char * owl_get_group_name ( struct pinctrl_dev * pctrldev ,
unsigned int group )
{
struct owl_pinctrl * pctrl = pinctrl_dev_get_drvdata ( pctrldev ) ;
return pctrl - > soc - > groups [ group ] . name ;
}
static int owl_get_group_pins ( struct pinctrl_dev * pctrldev ,
unsigned int group ,
const unsigned int * * pins ,
unsigned int * num_pins )
{
struct owl_pinctrl * pctrl = pinctrl_dev_get_drvdata ( pctrldev ) ;
* pins = pctrl - > soc - > groups [ group ] . pads ;
* num_pins = pctrl - > soc - > groups [ group ] . npads ;
return 0 ;
}
static void owl_pin_dbg_show ( struct pinctrl_dev * pctrldev ,
struct seq_file * s ,
unsigned int offset )
{
struct owl_pinctrl * pctrl = pinctrl_dev_get_drvdata ( pctrldev ) ;
seq_printf ( s , " %s " , dev_name ( pctrl - > dev ) ) ;
}
2020-08-31 00:43:09 +02:00
static const struct pinctrl_ops owl_pinctrl_ops = {
2018-04-04 22:52:52 +05:30
. get_groups_count = owl_get_groups_count ,
. get_group_name = owl_get_group_name ,
. get_group_pins = owl_get_group_pins ,
. pin_dbg_show = owl_pin_dbg_show ,
. dt_node_to_map = pinconf_generic_dt_node_to_map_all ,
. dt_free_map = pinctrl_utils_free_map ,
} ;
static int owl_get_funcs_count ( struct pinctrl_dev * pctrldev )
{
struct owl_pinctrl * pctrl = pinctrl_dev_get_drvdata ( pctrldev ) ;
return pctrl - > soc - > nfunctions ;
}
static const char * owl_get_func_name ( struct pinctrl_dev * pctrldev ,
unsigned int function )
{
struct owl_pinctrl * pctrl = pinctrl_dev_get_drvdata ( pctrldev ) ;
return pctrl - > soc - > functions [ function ] . name ;
}
static int owl_get_func_groups ( struct pinctrl_dev * pctrldev ,
unsigned int function ,
const char * const * * groups ,
unsigned int * const num_groups )
{
struct owl_pinctrl * pctrl = pinctrl_dev_get_drvdata ( pctrldev ) ;
* groups = pctrl - > soc - > functions [ function ] . groups ;
* num_groups = pctrl - > soc - > functions [ function ] . ngroups ;
return 0 ;
}
static inline int get_group_mfp_mask_val ( const struct owl_pingroup * g ,
int function ,
u32 * mask ,
u32 * val )
{
int id ;
u32 option_num ;
u32 option_mask ;
for ( id = 0 ; id < g - > nfuncs ; id + + ) {
if ( g - > funcs [ id ] = = function )
break ;
}
if ( WARN_ON ( id = = g - > nfuncs ) )
return - EINVAL ;
option_num = ( 1 < < g - > mfpctl_width ) ;
if ( id > option_num )
id - = option_num ;
option_mask = option_num - 1 ;
* mask = ( option_mask < < g - > mfpctl_shift ) ;
* val = ( id < < g - > mfpctl_shift ) ;
return 0 ;
}
static int owl_set_mux ( struct pinctrl_dev * pctrldev ,
unsigned int function ,
unsigned int group )
{
struct owl_pinctrl * pctrl = pinctrl_dev_get_drvdata ( pctrldev ) ;
const struct owl_pingroup * g ;
unsigned long flags ;
u32 val , mask ;
g = & pctrl - > soc - > groups [ group ] ;
if ( get_group_mfp_mask_val ( g , function , & mask , & val ) )
return - EINVAL ;
raw_spin_lock_irqsave ( & pctrl - > lock , flags ) ;
owl_update_bits ( pctrl - > base + g - > mfpctl_reg , mask , val ) ;
raw_spin_unlock_irqrestore ( & pctrl - > lock , flags ) ;
return 0 ;
}
2020-08-31 00:43:09 +02:00
static const struct pinmux_ops owl_pinmux_ops = {
2018-04-04 22:52:52 +05:30
. get_functions_count = owl_get_funcs_count ,
. get_function_name = owl_get_func_name ,
. get_function_groups = owl_get_func_groups ,
. set_mux = owl_set_mux ,
} ;
static int owl_pad_pinconf_reg ( const struct owl_padinfo * info ,
unsigned int param ,
u32 * reg ,
u32 * bit ,
u32 * width )
{
switch ( param ) {
case PIN_CONFIG_BIAS_BUS_HOLD :
case PIN_CONFIG_BIAS_HIGH_IMPEDANCE :
case PIN_CONFIG_BIAS_PULL_DOWN :
case PIN_CONFIG_BIAS_PULL_UP :
if ( ! info - > pullctl )
return - EINVAL ;
* reg = info - > pullctl - > reg ;
* bit = info - > pullctl - > shift ;
* width = info - > pullctl - > width ;
break ;
case PIN_CONFIG_INPUT_SCHMITT_ENABLE :
if ( ! info - > st )
return - EINVAL ;
* reg = info - > st - > reg ;
* bit = info - > st - > shift ;
* width = info - > st - > width ;
break ;
default :
return - ENOTSUPP ;
}
return 0 ;
}
static int owl_pin_config_get ( struct pinctrl_dev * pctrldev ,
unsigned int pin ,
unsigned long * config )
{
int ret = 0 ;
struct owl_pinctrl * pctrl = pinctrl_dev_get_drvdata ( pctrldev ) ;
const struct owl_padinfo * info ;
unsigned int param = pinconf_to_config_param ( * config ) ;
u32 reg , bit , width , arg ;
info = & pctrl - > soc - > padinfo [ pin ] ;
ret = owl_pad_pinconf_reg ( info , param , & reg , & bit , & width ) ;
if ( ret )
return ret ;
arg = owl_read_field ( pctrl , reg , bit , width ) ;
2018-11-15 13:47:45 +01:00
if ( ! pctrl - > soc - > padctl_val2arg )
return - ENOTSUPP ;
ret = pctrl - > soc - > padctl_val2arg ( info , param , & arg ) ;
2018-04-04 22:52:52 +05:30
if ( ret )
return ret ;
* config = pinconf_to_config_packed ( param , arg ) ;
return ret ;
}
static int owl_pin_config_set ( struct pinctrl_dev * pctrldev ,
unsigned int pin ,
unsigned long * configs ,
unsigned int num_configs )
{
struct owl_pinctrl * pctrl = pinctrl_dev_get_drvdata ( pctrldev ) ;
const struct owl_padinfo * info ;
unsigned long flags ;
unsigned int param ;
u32 reg , bit , width , arg ;
2018-06-08 12:05:47 +02:00
int ret = 0 , i ;
2018-04-04 22:52:52 +05:30
info = & pctrl - > soc - > padinfo [ pin ] ;
for ( i = 0 ; i < num_configs ; i + + ) {
param = pinconf_to_config_param ( configs [ i ] ) ;
arg = pinconf_to_config_argument ( configs [ i ] ) ;
ret = owl_pad_pinconf_reg ( info , param , & reg , & bit , & width ) ;
if ( ret )
return ret ;
2018-11-15 13:47:45 +01:00
if ( ! pctrl - > soc - > padctl_arg2val )
return - ENOTSUPP ;
ret = pctrl - > soc - > padctl_arg2val ( info , param , & arg ) ;
2018-04-04 22:52:52 +05:30
if ( ret )
return ret ;
raw_spin_lock_irqsave ( & pctrl - > lock , flags ) ;
owl_write_field ( pctrl , reg , arg , bit , width ) ;
raw_spin_unlock_irqrestore ( & pctrl - > lock , flags ) ;
}
return ret ;
}
static int owl_group_pinconf_reg ( const struct owl_pingroup * g ,
unsigned int param ,
u32 * reg ,
u32 * bit ,
u32 * width )
{
switch ( param ) {
case PIN_CONFIG_DRIVE_STRENGTH :
if ( g - > drv_reg < 0 )
return - EINVAL ;
* reg = g - > drv_reg ;
* bit = g - > drv_shift ;
* width = g - > drv_width ;
break ;
case PIN_CONFIG_SLEW_RATE :
if ( g - > sr_reg < 0 )
return - EINVAL ;
* reg = g - > sr_reg ;
* bit = g - > sr_shift ;
* width = g - > sr_width ;
break ;
default :
return - ENOTSUPP ;
}
return 0 ;
}
static int owl_group_pinconf_arg2val ( const struct owl_pingroup * g ,
unsigned int param ,
u32 * arg )
{
switch ( param ) {
case PIN_CONFIG_DRIVE_STRENGTH :
switch ( * arg ) {
case 2 :
* arg = OWL_PINCONF_DRV_2MA ;
break ;
case 4 :
* arg = OWL_PINCONF_DRV_4MA ;
break ;
case 8 :
* arg = OWL_PINCONF_DRV_8MA ;
break ;
case 12 :
* arg = OWL_PINCONF_DRV_12MA ;
break ;
default :
return - EINVAL ;
}
2018-04-30 14:22:59 +01:00
break ;
2018-04-04 22:52:52 +05:30
case PIN_CONFIG_SLEW_RATE :
if ( * arg )
* arg = OWL_PINCONF_SLEW_FAST ;
else
* arg = OWL_PINCONF_SLEW_SLOW ;
break ;
default :
return - ENOTSUPP ;
}
return 0 ;
}
static int owl_group_pinconf_val2arg ( const struct owl_pingroup * g ,
unsigned int param ,
u32 * arg )
{
switch ( param ) {
case PIN_CONFIG_DRIVE_STRENGTH :
switch ( * arg ) {
case OWL_PINCONF_DRV_2MA :
* arg = 2 ;
break ;
case OWL_PINCONF_DRV_4MA :
* arg = 4 ;
break ;
case OWL_PINCONF_DRV_8MA :
* arg = 8 ;
break ;
case OWL_PINCONF_DRV_12MA :
* arg = 12 ;
break ;
default :
return - EINVAL ;
}
2018-04-30 14:22:59 +01:00
break ;
2018-04-04 22:52:52 +05:30
case PIN_CONFIG_SLEW_RATE :
if ( * arg )
* arg = 1 ;
else
* arg = 0 ;
break ;
default :
return - ENOTSUPP ;
}
return 0 ;
}
static int owl_group_config_get ( struct pinctrl_dev * pctrldev ,
unsigned int group ,
unsigned long * config )
{
const struct owl_pingroup * g ;
struct owl_pinctrl * pctrl = pinctrl_dev_get_drvdata ( pctrldev ) ;
unsigned int param = pinconf_to_config_param ( * config ) ;
u32 reg , bit , width , arg ;
int ret ;
g = & pctrl - > soc - > groups [ group ] ;
ret = owl_group_pinconf_reg ( g , param , & reg , & bit , & width ) ;
if ( ret )
return ret ;
arg = owl_read_field ( pctrl , reg , bit , width ) ;
ret = owl_group_pinconf_val2arg ( g , param , & arg ) ;
if ( ret )
return ret ;
* config = pinconf_to_config_packed ( param , arg ) ;
return ret ;
}
static int owl_group_config_set ( struct pinctrl_dev * pctrldev ,
unsigned int group ,
unsigned long * configs ,
unsigned int num_configs )
{
const struct owl_pingroup * g ;
struct owl_pinctrl * pctrl = pinctrl_dev_get_drvdata ( pctrldev ) ;
unsigned long flags ;
unsigned int param ;
u32 reg , bit , width , arg ;
int ret , i ;
g = & pctrl - > soc - > groups [ group ] ;
for ( i = 0 ; i < num_configs ; i + + ) {
param = pinconf_to_config_param ( configs [ i ] ) ;
arg = pinconf_to_config_argument ( configs [ i ] ) ;
ret = owl_group_pinconf_reg ( g , param , & reg , & bit , & width ) ;
if ( ret )
return ret ;
ret = owl_group_pinconf_arg2val ( g , param , & arg ) ;
if ( ret )
return ret ;
/* Update register */
raw_spin_lock_irqsave ( & pctrl - > lock , flags ) ;
owl_write_field ( pctrl , reg , arg , bit , width ) ;
raw_spin_unlock_irqrestore ( & pctrl - > lock , flags ) ;
}
return 0 ;
}
static const struct pinconf_ops owl_pinconf_ops = {
. is_generic = true ,
. pin_config_get = owl_pin_config_get ,
. pin_config_set = owl_pin_config_set ,
. pin_config_group_get = owl_group_config_get ,
. pin_config_group_set = owl_group_config_set ,
} ;
static struct pinctrl_desc owl_pinctrl_desc = {
. pctlops = & owl_pinctrl_ops ,
. pmxops = & owl_pinmux_ops ,
. confops = & owl_pinconf_ops ,
. owner = THIS_MODULE ,
} ;
2018-05-20 10:47:35 +05:30
static const struct owl_gpio_port *
owl_gpio_get_port ( struct owl_pinctrl * pctrl , unsigned int * pin )
{
unsigned int start = 0 , i ;
for ( i = 0 ; i < pctrl - > soc - > nports ; i + + ) {
const struct owl_gpio_port * port = & pctrl - > soc - > ports [ i ] ;
if ( * pin > = start & & * pin < start + port - > pins ) {
* pin - = start ;
return port ;
}
start + = port - > pins ;
}
return NULL ;
}
static void owl_gpio_update_reg ( void __iomem * base , unsigned int pin , int flag )
{
u32 val ;
val = readl_relaxed ( base ) ;
if ( flag )
val | = BIT ( pin ) ;
else
val & = ~ BIT ( pin ) ;
writel_relaxed ( val , base ) ;
}
static int owl_gpio_request ( struct gpio_chip * chip , unsigned int offset )
{
struct owl_pinctrl * pctrl = gpiochip_get_data ( chip ) ;
const struct owl_gpio_port * port ;
void __iomem * gpio_base ;
unsigned long flags ;
port = owl_gpio_get_port ( pctrl , & offset ) ;
if ( WARN_ON ( port = = NULL ) )
return - ENODEV ;
gpio_base = pctrl - > base + port - > offset ;
/*
* GPIOs have higher priority over other modules , so either setting
* them as OUT or IN is sufficient
*/
raw_spin_lock_irqsave ( & pctrl - > lock , flags ) ;
owl_gpio_update_reg ( gpio_base + port - > outen , offset , true ) ;
raw_spin_unlock_irqrestore ( & pctrl - > lock , flags ) ;
return 0 ;
}
static void owl_gpio_free ( struct gpio_chip * chip , unsigned int offset )
{
struct owl_pinctrl * pctrl = gpiochip_get_data ( chip ) ;
const struct owl_gpio_port * port ;
void __iomem * gpio_base ;
unsigned long flags ;
port = owl_gpio_get_port ( pctrl , & offset ) ;
if ( WARN_ON ( port = = NULL ) )
return ;
gpio_base = pctrl - > base + port - > offset ;
raw_spin_lock_irqsave ( & pctrl - > lock , flags ) ;
/* disable gpio output */
owl_gpio_update_reg ( gpio_base + port - > outen , offset , false ) ;
/* disable gpio input */
owl_gpio_update_reg ( gpio_base + port - > inen , offset , false ) ;
raw_spin_unlock_irqrestore ( & pctrl - > lock , flags ) ;
}
static int owl_gpio_get ( struct gpio_chip * chip , unsigned int offset )
{
struct owl_pinctrl * pctrl = gpiochip_get_data ( chip ) ;
const struct owl_gpio_port * port ;
void __iomem * gpio_base ;
unsigned long flags ;
u32 val ;
port = owl_gpio_get_port ( pctrl , & offset ) ;
if ( WARN_ON ( port = = NULL ) )
return - ENODEV ;
gpio_base = pctrl - > base + port - > offset ;
raw_spin_lock_irqsave ( & pctrl - > lock , flags ) ;
val = readl_relaxed ( gpio_base + port - > dat ) ;
raw_spin_unlock_irqrestore ( & pctrl - > lock , flags ) ;
return ! ! ( val & BIT ( offset ) ) ;
}
static void owl_gpio_set ( struct gpio_chip * chip , unsigned int offset , int value )
{
struct owl_pinctrl * pctrl = gpiochip_get_data ( chip ) ;
const struct owl_gpio_port * port ;
void __iomem * gpio_base ;
unsigned long flags ;
port = owl_gpio_get_port ( pctrl , & offset ) ;
if ( WARN_ON ( port = = NULL ) )
return ;
gpio_base = pctrl - > base + port - > offset ;
raw_spin_lock_irqsave ( & pctrl - > lock , flags ) ;
owl_gpio_update_reg ( gpio_base + port - > dat , offset , value ) ;
raw_spin_unlock_irqrestore ( & pctrl - > lock , flags ) ;
}
static int owl_gpio_direction_input ( struct gpio_chip * chip , unsigned int offset )
{
struct owl_pinctrl * pctrl = gpiochip_get_data ( chip ) ;
const struct owl_gpio_port * port ;
void __iomem * gpio_base ;
unsigned long flags ;
port = owl_gpio_get_port ( pctrl , & offset ) ;
if ( WARN_ON ( port = = NULL ) )
return - ENODEV ;
gpio_base = pctrl - > base + port - > offset ;
raw_spin_lock_irqsave ( & pctrl - > lock , flags ) ;
owl_gpio_update_reg ( gpio_base + port - > outen , offset , false ) ;
owl_gpio_update_reg ( gpio_base + port - > inen , offset , true ) ;
raw_spin_unlock_irqrestore ( & pctrl - > lock , flags ) ;
return 0 ;
}
static int owl_gpio_direction_output ( struct gpio_chip * chip ,
unsigned int offset , int value )
{
struct owl_pinctrl * pctrl = gpiochip_get_data ( chip ) ;
const struct owl_gpio_port * port ;
void __iomem * gpio_base ;
unsigned long flags ;
port = owl_gpio_get_port ( pctrl , & offset ) ;
if ( WARN_ON ( port = = NULL ) )
return - ENODEV ;
gpio_base = pctrl - > base + port - > offset ;
raw_spin_lock_irqsave ( & pctrl - > lock , flags ) ;
owl_gpio_update_reg ( gpio_base + port - > inen , offset , false ) ;
owl_gpio_update_reg ( gpio_base + port - > outen , offset , true ) ;
owl_gpio_update_reg ( gpio_base + port - > dat , offset , value ) ;
raw_spin_unlock_irqrestore ( & pctrl - > lock , flags ) ;
return 0 ;
}
2018-06-23 10:29:54 +05:30
static void irq_set_type ( struct owl_pinctrl * pctrl , int gpio , unsigned int type )
{
const struct owl_gpio_port * port ;
void __iomem * gpio_base ;
unsigned long flags ;
unsigned int offset , value , irq_type = 0 ;
switch ( type ) {
case IRQ_TYPE_EDGE_BOTH :
/*
* Since the hardware doesn ' t support interrupts on both edges ,
* emulate it in the software by setting the single edge
* interrupt and switching to the opposite edge while ACKing
* the interrupt
*/
if ( owl_gpio_get ( & pctrl - > chip , gpio ) )
irq_type = OWL_GPIO_INT_EDGE_FALLING ;
else
irq_type = OWL_GPIO_INT_EDGE_RISING ;
break ;
case IRQ_TYPE_EDGE_RISING :
irq_type = OWL_GPIO_INT_EDGE_RISING ;
break ;
case IRQ_TYPE_EDGE_FALLING :
irq_type = OWL_GPIO_INT_EDGE_FALLING ;
break ;
case IRQ_TYPE_LEVEL_HIGH :
irq_type = OWL_GPIO_INT_LEVEL_HIGH ;
break ;
case IRQ_TYPE_LEVEL_LOW :
irq_type = OWL_GPIO_INT_LEVEL_LOW ;
break ;
default :
break ;
}
port = owl_gpio_get_port ( pctrl , & gpio ) ;
if ( WARN_ON ( port = = NULL ) )
return ;
gpio_base = pctrl - > base + port - > offset ;
raw_spin_lock_irqsave ( & pctrl - > lock , flags ) ;
offset = ( gpio < 16 ) ? 4 : 0 ;
value = readl_relaxed ( gpio_base + port - > intc_type + offset ) ;
value & = ~ ( OWL_GPIO_INT_MASK < < ( ( gpio % 16 ) * 2 ) ) ;
value | = irq_type < < ( ( gpio % 16 ) * 2 ) ;
writel_relaxed ( value , gpio_base + port - > intc_type + offset ) ;
raw_spin_unlock_irqrestore ( & pctrl - > lock , flags ) ;
}
static void owl_gpio_irq_mask ( struct irq_data * data )
{
struct gpio_chip * gc = irq_data_get_irq_chip_data ( data ) ;
struct owl_pinctrl * pctrl = gpiochip_get_data ( gc ) ;
const struct owl_gpio_port * port ;
void __iomem * gpio_base ;
unsigned long flags ;
unsigned int gpio = data - > hwirq ;
u32 val ;
port = owl_gpio_get_port ( pctrl , & gpio ) ;
if ( WARN_ON ( port = = NULL ) )
return ;
gpio_base = pctrl - > base + port - > offset ;
raw_spin_lock_irqsave ( & pctrl - > lock , flags ) ;
owl_gpio_update_reg ( gpio_base + port - > intc_msk , gpio , false ) ;
/* disable port interrupt if no interrupt pending bit is active */
val = readl_relaxed ( gpio_base + port - > intc_msk ) ;
if ( val = = 0 )
owl_gpio_update_reg ( gpio_base + port - > intc_ctl ,
2018-11-15 13:47:47 +01:00
OWL_GPIO_CTLR_ENABLE + port - > shared_ctl_offset * 5 , false ) ;
2018-06-23 10:29:54 +05:30
raw_spin_unlock_irqrestore ( & pctrl - > lock , flags ) ;
}
static void owl_gpio_irq_unmask ( struct irq_data * data )
{
struct gpio_chip * gc = irq_data_get_irq_chip_data ( data ) ;
struct owl_pinctrl * pctrl = gpiochip_get_data ( gc ) ;
const struct owl_gpio_port * port ;
void __iomem * gpio_base ;
unsigned long flags ;
unsigned int gpio = data - > hwirq ;
u32 value ;
port = owl_gpio_get_port ( pctrl , & gpio ) ;
if ( WARN_ON ( port = = NULL ) )
return ;
gpio_base = pctrl - > base + port - > offset ;
raw_spin_lock_irqsave ( & pctrl - > lock , flags ) ;
/* enable port interrupt */
value = readl_relaxed ( gpio_base + port - > intc_ctl ) ;
2018-11-15 13:47:47 +01:00
value | = ( ( BIT ( OWL_GPIO_CTLR_ENABLE ) | BIT ( OWL_GPIO_CTLR_SAMPLE_CLK_24M ) )
< < port - > shared_ctl_offset * 5 ) ;
2018-06-23 10:29:54 +05:30
writel_relaxed ( value , gpio_base + port - > intc_ctl ) ;
/* enable GPIO interrupt */
owl_gpio_update_reg ( gpio_base + port - > intc_msk , gpio , true ) ;
raw_spin_unlock_irqrestore ( & pctrl - > lock , flags ) ;
}
static void owl_gpio_irq_ack ( struct irq_data * data )
{
struct gpio_chip * gc = irq_data_get_irq_chip_data ( data ) ;
struct owl_pinctrl * pctrl = gpiochip_get_data ( gc ) ;
const struct owl_gpio_port * port ;
void __iomem * gpio_base ;
unsigned long flags ;
unsigned int gpio = data - > hwirq ;
/*
* Switch the interrupt edge to the opposite edge of the interrupt
* which got triggered for the case of emulating both edges
*/
if ( irqd_get_trigger_type ( data ) = = IRQ_TYPE_EDGE_BOTH ) {
if ( owl_gpio_get ( gc , gpio ) )
irq_set_type ( pctrl , gpio , IRQ_TYPE_EDGE_FALLING ) ;
else
irq_set_type ( pctrl , gpio , IRQ_TYPE_EDGE_RISING ) ;
}
port = owl_gpio_get_port ( pctrl , & gpio ) ;
if ( WARN_ON ( port = = NULL ) )
return ;
gpio_base = pctrl - > base + port - > offset ;
raw_spin_lock_irqsave ( & pctrl - > lock , flags ) ;
owl_gpio_update_reg ( gpio_base + port - > intc_ctl ,
2018-11-15 13:47:47 +01:00
OWL_GPIO_CTLR_PENDING + port - > shared_ctl_offset * 5 , true ) ;
2018-06-23 10:29:54 +05:30
raw_spin_unlock_irqrestore ( & pctrl - > lock , flags ) ;
}
static int owl_gpio_irq_set_type ( struct irq_data * data , unsigned int type )
{
struct gpio_chip * gc = irq_data_get_irq_chip_data ( data ) ;
struct owl_pinctrl * pctrl = gpiochip_get_data ( gc ) ;
if ( type & ( IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH ) )
irq_set_handler_locked ( data , handle_level_irq ) ;
else
irq_set_handler_locked ( data , handle_edge_irq ) ;
irq_set_type ( pctrl , data - > hwirq , type ) ;
return 0 ;
}
static void owl_gpio_irq_handler ( struct irq_desc * desc )
{
struct owl_pinctrl * pctrl = irq_desc_get_handler_data ( desc ) ;
struct irq_chip * chip = irq_desc_get_chip ( desc ) ;
struct irq_domain * domain = pctrl - > chip . irq . domain ;
unsigned int parent = irq_desc_get_irq ( desc ) ;
const struct owl_gpio_port * port ;
void __iomem * base ;
2021-05-04 17:42:18 +01:00
unsigned int pin , offset = 0 , i ;
2018-06-23 10:29:54 +05:30
unsigned long pending_irq ;
chained_irq_enter ( chip , desc ) ;
for ( i = 0 ; i < pctrl - > soc - > nports ; i + + ) {
port = & pctrl - > soc - > ports [ i ] ;
base = pctrl - > base + port - > offset ;
/* skip ports that are not associated with this irq */
if ( parent ! = pctrl - > irq [ i ] )
goto skip ;
pending_irq = readl_relaxed ( base + port - > intc_pd ) ;
for_each_set_bit ( pin , & pending_irq , port - > pins ) {
2021-05-04 17:42:18 +01:00
generic_handle_domain_irq ( domain , offset + pin ) ;
2018-06-23 10:29:54 +05:30
/* clear pending interrupt */
owl_gpio_update_reg ( base + port - > intc_pd , pin , true ) ;
}
skip :
offset + = port - > pins ;
}
chained_irq_exit ( chip , desc ) ;
}
2018-05-20 10:47:35 +05:30
static int owl_gpio_init ( struct owl_pinctrl * pctrl )
{
struct gpio_chip * chip ;
2018-06-23 10:29:54 +05:30
struct gpio_irq_chip * gpio_irq ;
int ret , i , j , offset ;
2018-05-20 10:47:35 +05:30
chip = & pctrl - > chip ;
chip - > base = - 1 ;
chip - > ngpio = pctrl - > soc - > ngpios ;
chip - > label = dev_name ( pctrl - > dev ) ;
chip - > parent = pctrl - > dev ;
chip - > owner = THIS_MODULE ;
2018-06-23 10:29:54 +05:30
pctrl - > irq_chip . name = chip - > of_node - > name ;
pctrl - > irq_chip . irq_ack = owl_gpio_irq_ack ;
pctrl - > irq_chip . irq_mask = owl_gpio_irq_mask ;
pctrl - > irq_chip . irq_unmask = owl_gpio_irq_unmask ;
pctrl - > irq_chip . irq_set_type = owl_gpio_irq_set_type ;
gpio_irq = & chip - > irq ;
gpio_irq - > chip = & pctrl - > irq_chip ;
gpio_irq - > handler = handle_simple_irq ;
gpio_irq - > default_type = IRQ_TYPE_NONE ;
gpio_irq - > parent_handler = owl_gpio_irq_handler ;
gpio_irq - > parent_handler_data = pctrl ;
gpio_irq - > num_parents = pctrl - > num_irq ;
gpio_irq - > parents = pctrl - > irq ;
gpio_irq - > map = devm_kcalloc ( pctrl - > dev , chip - > ngpio ,
sizeof ( * gpio_irq - > map ) , GFP_KERNEL ) ;
if ( ! gpio_irq - > map )
return - ENOMEM ;
for ( i = 0 , offset = 0 ; i < pctrl - > soc - > nports ; i + + ) {
const struct owl_gpio_port * port = & pctrl - > soc - > ports [ i ] ;
for ( j = 0 ; j < port - > pins ; j + + )
gpio_irq - > map [ offset + j ] = gpio_irq - > parents [ i ] ;
offset + = port - > pins ;
}
2018-05-20 10:47:35 +05:30
ret = gpiochip_add_data ( & pctrl - > chip , pctrl ) ;
if ( ret ) {
dev_err ( pctrl - > dev , " failed to register gpiochip \n " ) ;
return ret ;
}
return 0 ;
}
2018-04-04 22:52:52 +05:30
int owl_pinctrl_probe ( struct platform_device * pdev ,
struct owl_pinctrl_soc_data * soc_data )
{
struct owl_pinctrl * pctrl ;
2018-06-23 10:29:54 +05:30
int ret , i ;
2018-04-04 22:52:52 +05:30
pctrl = devm_kzalloc ( & pdev - > dev , sizeof ( * pctrl ) , GFP_KERNEL ) ;
if ( ! pctrl )
return - ENOMEM ;
2019-11-04 22:26:54 +08:00
pctrl - > base = devm_platform_ioremap_resource ( pdev , 0 ) ;
2018-04-04 22:52:52 +05:30
if ( IS_ERR ( pctrl - > base ) )
return PTR_ERR ( pctrl - > base ) ;
/* enable GPIO/MFP clock */
pctrl - > clk = devm_clk_get ( & pdev - > dev , NULL ) ;
if ( IS_ERR ( pctrl - > clk ) ) {
dev_err ( & pdev - > dev , " no clock defined \n " ) ;
return PTR_ERR ( pctrl - > clk ) ;
}
ret = clk_prepare_enable ( pctrl - > clk ) ;
if ( ret ) {
dev_err ( & pdev - > dev , " clk enable failed \n " ) ;
return ret ;
}
raw_spin_lock_init ( & pctrl - > lock ) ;
owl_pinctrl_desc . name = dev_name ( & pdev - > dev ) ;
owl_pinctrl_desc . pins = soc_data - > pins ;
owl_pinctrl_desc . npins = soc_data - > npins ;
2018-05-20 10:47:35 +05:30
pctrl - > chip . direction_input = owl_gpio_direction_input ;
pctrl - > chip . direction_output = owl_gpio_direction_output ;
pctrl - > chip . get = owl_gpio_get ;
pctrl - > chip . set = owl_gpio_set ;
pctrl - > chip . request = owl_gpio_request ;
pctrl - > chip . free = owl_gpio_free ;
2018-04-04 22:52:52 +05:30
pctrl - > soc = soc_data ;
pctrl - > dev = & pdev - > dev ;
pctrl - > pctrldev = devm_pinctrl_register ( & pdev - > dev ,
& owl_pinctrl_desc , pctrl ) ;
if ( IS_ERR ( pctrl - > pctrldev ) ) {
dev_err ( & pdev - > dev , " could not register Actions OWL pinmux driver \n " ) ;
2018-06-23 10:29:54 +05:30
ret = PTR_ERR ( pctrl - > pctrldev ) ;
goto err_exit ;
}
ret = platform_irq_count ( pdev ) ;
if ( ret < 0 )
goto err_exit ;
pctrl - > num_irq = ret ;
pctrl - > irq = devm_kcalloc ( & pdev - > dev , pctrl - > num_irq ,
sizeof ( * pctrl - > irq ) , GFP_KERNEL ) ;
if ( ! pctrl - > irq ) {
ret = - ENOMEM ;
goto err_exit ;
}
for ( i = 0 ; i < pctrl - > num_irq ; i + + ) {
2018-07-02 13:47:08 +01:00
ret = platform_get_irq ( pdev , i ) ;
if ( ret < 0 )
2018-06-23 10:29:54 +05:30
goto err_exit ;
2018-07-02 13:47:08 +01:00
pctrl - > irq [ i ] = ret ;
2018-04-04 22:52:52 +05:30
}
2018-05-20 10:47:35 +05:30
ret = owl_gpio_init ( pctrl ) ;
if ( ret )
2018-06-23 10:29:54 +05:30
goto err_exit ;
2018-05-20 10:47:35 +05:30
2018-04-04 22:52:52 +05:30
platform_set_drvdata ( pdev , pctrl ) ;
return 0 ;
2018-06-23 10:29:54 +05:30
err_exit :
clk_disable_unprepare ( pctrl - > clk ) ;
return ret ;
2018-04-04 22:52:52 +05:30
}