2017-04-05 17:18:04 +02:00
/*
* Marvell 37 xx SoC pinctrl driver
*
* Copyright ( C ) 2017 Marvell
*
* Gregory CLEMENT < gregory . clement @ free - electrons . com >
*
* This file is licensed under the terms of the GNU General Public
* License version 2 or later . This program is licensed " as is "
* without any warranty of any kind , whether express or implied .
*/
2017-04-05 17:18:05 +02:00
# include <linux/gpio/driver.h>
2017-04-05 17:18:04 +02:00
# include <linux/mfd/syscon.h>
# include <linux/of.h>
2017-04-28 16:01:33 +02:00
# include <linux/of_address.h>
2017-04-05 17:18:04 +02:00
# include <linux/of_device.h>
2020-03-26 00:20:38 +01:00
# include <linux/of_irq.h>
2017-04-05 17:18:04 +02:00
# include <linux/pinctrl/pinconf-generic.h>
# include <linux/pinctrl/pinconf.h>
# include <linux/pinctrl/pinctrl.h>
# include <linux/pinctrl/pinmux.h>
# include <linux/platform_device.h>
2022-04-01 13:36:03 +03:00
# include <linux/property.h>
2017-04-05 17:18:04 +02:00
# include <linux/regmap.h>
# include <linux/slab.h>
2021-11-05 14:42:35 +02:00
# include <linux/string_helpers.h>
2017-04-05 17:18:04 +02:00
# include "../pinctrl-utils.h"
# define OUTPUT_EN 0x0
2017-04-05 17:18:05 +02:00
# define INPUT_VAL 0x10
# define OUTPUT_VAL 0x18
2017-04-05 17:18:04 +02:00
# define OUTPUT_CTL 0x20
# define SELECTION 0x30
2017-04-28 16:01:33 +02:00
# define IRQ_EN 0x0
# define IRQ_POL 0x08
# define IRQ_STATUS 0x10
# define IRQ_WKUP 0x18
2017-08-01 17:57:19 +02:00
# define NB_FUNCS 3
2017-04-05 17:18:04 +02:00
# define GPIO_PER_REG 32
/**
* struct armada_37xx_pin_group : represents group of pins of a pinmux function .
* The pins of a pinmux groups are composed of one or two groups of contiguous
* pins .
* @ name : Name of the pin group , used to lookup the group .
2020-07-13 15:49:29 +01:00
* @ start_pin : Index of the first pin of the main range of pins belonging to
2017-04-05 17:18:04 +02:00
* the group
* @ npins : Number of pins included in the first range
* @ reg_mask : Bit mask matching the group in the selection register
2020-07-13 15:49:29 +01:00
* @ val : Value to write to the registers for a given function
* @ extra_pin : Index of the first pin of the optional second range of pins
2017-04-05 17:18:04 +02:00
* belonging to the group
2020-07-13 15:49:29 +01:00
* @ extra_npins : Number of pins included in the second optional range
2017-04-05 17:18:04 +02:00
* @ funcs : A list of pinmux functions that can be selected for this group .
* @ pins : List of the pins included in the group
*/
struct armada_37xx_pin_group {
const char * name ;
unsigned int start_pin ;
unsigned int npins ;
u32 reg_mask ;
u32 val [ NB_FUNCS ] ;
unsigned int extra_pin ;
unsigned int extra_npins ;
const char * funcs [ NB_FUNCS ] ;
unsigned int * pins ;
} ;
struct armada_37xx_pin_data {
u8 nr_pins ;
char * name ;
struct armada_37xx_pin_group * groups ;
int ngroups ;
} ;
struct armada_37xx_pmx_func {
const char * name ;
const char * * groups ;
unsigned int ngroups ;
} ;
2018-06-26 16:06:13 +02:00
struct armada_37xx_pm_state {
u32 out_en_l ;
u32 out_en_h ;
u32 out_val_l ;
u32 out_val_h ;
u32 irq_en_l ;
u32 irq_en_h ;
u32 irq_pol_l ;
u32 irq_pol_h ;
u32 selection ;
} ;
2017-04-05 17:18:04 +02:00
struct armada_37xx_pinctrl {
struct regmap * regmap ;
2017-04-28 16:01:33 +02:00
void __iomem * base ;
2017-04-05 17:18:04 +02:00
const struct armada_37xx_pin_data * data ;
struct device * dev ;
2017-04-05 17:18:05 +02:00
struct gpio_chip gpio_chip ;
2017-04-28 16:01:33 +02:00
struct irq_chip irq_chip ;
2022-07-17 02:37:44 +03:00
raw_spinlock_t irq_lock ;
2017-04-05 17:18:04 +02:00
struct pinctrl_desc pctl ;
struct pinctrl_dev * pctl_dev ;
struct armada_37xx_pin_group * groups ;
unsigned int ngroups ;
struct armada_37xx_pmx_func * funcs ;
unsigned int nfuncs ;
2018-06-26 16:06:13 +02:00
struct armada_37xx_pm_state pm ;
2017-04-05 17:18:04 +02:00
} ;
# define PIN_GRP(_name, _start, _nr, _mask, _func1, _func2) \
{ \
. name = _name , \
. start_pin = _start , \
. npins = _nr , \
. reg_mask = _mask , \
. val = { 0 , _mask } , \
. funcs = { _func1 , _func2 } \
}
# define PIN_GRP_GPIO(_name, _start, _nr, _mask, _func1) \
{ \
. name = _name , \
. start_pin = _start , \
. npins = _nr , \
. reg_mask = _mask , \
. val = { 0 , _mask } , \
. funcs = { _func1 , " gpio " } \
}
# define PIN_GRP_GPIO_2(_name, _start, _nr, _mask, _val1, _val2, _func1) \
{ \
. name = _name , \
. start_pin = _start , \
. npins = _nr , \
. reg_mask = _mask , \
. val = { _val1 , _val2 } , \
. funcs = { _func1 , " gpio " } \
}
2017-08-01 17:57:19 +02:00
# define PIN_GRP_GPIO_3(_name, _start, _nr, _mask, _v1, _v2, _v3, _f1, _f2) \
{ \
. name = _name , \
. start_pin = _start , \
. npins = _nr , \
. reg_mask = _mask , \
. val = { _v1 , _v2 , _v3 } , \
. funcs = { _f1 , _f2 , " gpio " } \
}
2017-04-05 17:18:04 +02:00
# define PIN_GRP_EXTRA(_name, _start, _nr, _mask, _v1, _v2, _start2, _nr2, \
_f1 , _f2 ) \
{ \
. name = _name , \
. start_pin = _start , \
. npins = _nr , \
. reg_mask = _mask , \
. val = { _v1 , _v2 } , \
. extra_pin = _start2 , \
. extra_npins = _nr2 , \
. funcs = { _f1 , _f2 } \
}
static struct armada_37xx_pin_group armada_37xx_nb_groups [ ] = {
PIN_GRP_GPIO ( " jtag " , 20 , 5 , BIT ( 0 ) , " jtag " ) ,
PIN_GRP_GPIO ( " sdio0 " , 8 , 3 , BIT ( 1 ) , " sdio " ) ,
PIN_GRP_GPIO ( " emmc_nb " , 27 , 9 , BIT ( 2 ) , " emmc " ) ,
2021-07-19 13:29:38 +02:00
PIN_GRP_GPIO_3 ( " pwm0 " , 11 , 1 , BIT ( 3 ) | BIT ( 20 ) , 0 , BIT ( 20 ) , BIT ( 3 ) ,
" pwm " , " led " ) ,
PIN_GRP_GPIO_3 ( " pwm1 " , 12 , 1 , BIT ( 4 ) | BIT ( 21 ) , 0 , BIT ( 21 ) , BIT ( 4 ) ,
" pwm " , " led " ) ,
PIN_GRP_GPIO_3 ( " pwm2 " , 13 , 1 , BIT ( 5 ) | BIT ( 22 ) , 0 , BIT ( 22 ) , BIT ( 5 ) ,
" pwm " , " led " ) ,
PIN_GRP_GPIO_3 ( " pwm3 " , 14 , 1 , BIT ( 6 ) | BIT ( 23 ) , 0 , BIT ( 23 ) , BIT ( 6 ) ,
" pwm " , " led " ) ,
2018-12-21 18:32:57 +01:00
PIN_GRP_GPIO ( " pmic1 " , 7 , 1 , BIT ( 7 ) , " pmic " ) ,
PIN_GRP_GPIO ( " pmic0 " , 6 , 1 , BIT ( 8 ) , " pmic " ) ,
2017-04-05 17:18:04 +02:00
PIN_GRP_GPIO ( " i2c2 " , 2 , 2 , BIT ( 9 ) , " i2c " ) ,
PIN_GRP_GPIO ( " i2c1 " , 0 , 2 , BIT ( 10 ) , " i2c " ) ,
PIN_GRP_GPIO ( " spi_cs1 " , 17 , 1 , BIT ( 12 ) , " spi " ) ,
PIN_GRP_GPIO_2 ( " spi_cs2 " , 18 , 1 , BIT ( 13 ) | BIT ( 19 ) , 0 , BIT ( 13 ) , " spi " ) ,
PIN_GRP_GPIO_2 ( " spi_cs3 " , 19 , 1 , BIT ( 14 ) | BIT ( 19 ) , 0 , BIT ( 14 ) , " spi " ) ,
PIN_GRP_GPIO ( " onewire " , 4 , 1 , BIT ( 16 ) , " onewire " ) ,
PIN_GRP_GPIO ( " uart1 " , 25 , 2 , BIT ( 17 ) , " uart " ) ,
PIN_GRP_GPIO ( " spi_quad " , 15 , 2 , BIT ( 18 ) , " spi " ) ,
2017-06-23 14:29:51 +02:00
PIN_GRP_EXTRA ( " uart2 " , 9 , 2 , BIT ( 1 ) | BIT ( 13 ) | BIT ( 14 ) | BIT ( 19 ) ,
BIT ( 1 ) | BIT ( 13 ) | BIT ( 14 ) , BIT ( 1 ) | BIT ( 19 ) ,
18 , 2 , " gpio " , " uart " ) ,
2017-04-05 17:18:04 +02:00
} ;
static struct armada_37xx_pin_group armada_37xx_sb_groups [ ] = {
PIN_GRP_GPIO ( " usb32_drvvbus0 " , 0 , 1 , BIT ( 0 ) , " drvbus " ) ,
PIN_GRP_GPIO ( " usb2_drvvbus1 " , 1 , 1 , BIT ( 1 ) , " drvbus " ) ,
2017-06-23 14:29:52 +02:00
PIN_GRP_GPIO ( " sdio_sb " , 24 , 6 , BIT ( 2 ) , " sdio " ) ,
2017-08-01 17:57:19 +02:00
PIN_GRP_GPIO ( " rgmii " , 6 , 12 , BIT ( 3 ) , " mii " ) ,
2018-12-21 18:32:57 +01:00
PIN_GRP_GPIO ( " smi " , 18 , 2 , BIT ( 4 ) , " smi " ) ,
2020-07-24 15:24:57 +02:00
PIN_GRP_GPIO ( " pcie1 " , 3 , 1 , BIT ( 5 ) , " pcie " ) , /* this actually controls "pcie1_reset" */
2018-12-21 18:32:57 +01:00
PIN_GRP_GPIO ( " pcie1_clkreq " , 4 , 1 , BIT ( 9 ) , " pcie " ) ,
2018-12-21 18:32:58 +01:00
PIN_GRP_GPIO ( " pcie1_wakeup " , 5 , 1 , BIT ( 10 ) , " pcie " ) ,
2018-12-21 18:32:57 +01:00
PIN_GRP_GPIO ( " ptp " , 20 , 3 , BIT ( 11 ) | BIT ( 12 ) | BIT ( 13 ) , " ptp " ) ,
2017-04-05 17:18:04 +02:00
PIN_GRP ( " ptp_clk " , 21 , 1 , BIT ( 6 ) , " ptp " , " mii " ) ,
PIN_GRP ( " ptp_trig " , 22 , 1 , BIT ( 7 ) , " ptp " , " mii " ) ,
2017-08-01 17:57:19 +02:00
PIN_GRP_GPIO_3 ( " mii_col " , 23 , 1 , BIT ( 8 ) | BIT ( 14 ) , 0 , BIT ( 8 ) , BIT ( 14 ) ,
" mii " , " mii_err " ) ,
2017-04-05 17:18:04 +02:00
} ;
2017-08-04 13:47:00 +09:00
static const struct armada_37xx_pin_data armada_37xx_pin_nb = {
2017-04-05 17:18:04 +02:00
. nr_pins = 36 ,
. name = " GPIO1 " ,
. groups = armada_37xx_nb_groups ,
. ngroups = ARRAY_SIZE ( armada_37xx_nb_groups ) ,
} ;
2017-08-04 13:47:00 +09:00
static const struct armada_37xx_pin_data armada_37xx_pin_sb = {
2017-08-01 17:57:20 +02:00
. nr_pins = 30 ,
2017-04-05 17:18:04 +02:00
. name = " GPIO2 " ,
. groups = armada_37xx_sb_groups ,
. ngroups = ARRAY_SIZE ( armada_37xx_sb_groups ) ,
} ;
2017-04-05 17:18:05 +02:00
static inline void armada_37xx_update_reg ( unsigned int * reg ,
2019-10-01 10:46:31 -05:00
unsigned int * offset )
2017-04-05 17:18:05 +02:00
{
/* We never have more than 2 registers */
2019-10-01 10:46:31 -05:00
if ( * offset > = GPIO_PER_REG ) {
* offset - = GPIO_PER_REG ;
2017-04-05 17:18:05 +02:00
* reg + = sizeof ( u32 ) ;
}
}
2017-04-05 17:18:04 +02:00
static struct armada_37xx_pin_group * armada_37xx_find_next_grp_by_pin (
struct armada_37xx_pinctrl * info , int pin , int * grp )
{
while ( * grp < info - > ngroups ) {
struct armada_37xx_pin_group * group = & info - > groups [ * grp ] ;
int j ;
* grp = * grp + 1 ;
for ( j = 0 ; j < ( group - > npins + group - > extra_npins ) ; j + + )
if ( group - > pins [ j ] = = pin )
return group ;
}
return NULL ;
}
static int armada_37xx_pin_config_group_get ( struct pinctrl_dev * pctldev ,
unsigned int selector , unsigned long * config )
{
return - ENOTSUPP ;
}
static int armada_37xx_pin_config_group_set ( struct pinctrl_dev * pctldev ,
unsigned int selector , unsigned long * configs ,
unsigned int num_configs )
{
return - ENOTSUPP ;
}
2017-08-10 12:06:15 +02:00
static const struct pinconf_ops armada_37xx_pinconf_ops = {
2017-04-05 17:18:04 +02:00
. is_generic = true ,
. pin_config_group_get = armada_37xx_pin_config_group_get ,
. pin_config_group_set = armada_37xx_pin_config_group_set ,
} ;
static int armada_37xx_get_groups_count ( struct pinctrl_dev * pctldev )
{
struct armada_37xx_pinctrl * info = pinctrl_dev_get_drvdata ( pctldev ) ;
return info - > ngroups ;
}
static const char * armada_37xx_get_group_name ( struct pinctrl_dev * pctldev ,
unsigned int group )
{
struct armada_37xx_pinctrl * info = pinctrl_dev_get_drvdata ( pctldev ) ;
return info - > groups [ group ] . name ;
}
static int armada_37xx_get_group_pins ( struct pinctrl_dev * pctldev ,
unsigned int selector ,
const unsigned int * * pins ,
unsigned int * npins )
{
struct armada_37xx_pinctrl * info = pinctrl_dev_get_drvdata ( pctldev ) ;
if ( selector > = info - > ngroups )
return - EINVAL ;
* pins = info - > groups [ selector ] . pins ;
* npins = info - > groups [ selector ] . npins +
info - > groups [ selector ] . extra_npins ;
return 0 ;
}
static const struct pinctrl_ops armada_37xx_pctrl_ops = {
. get_groups_count = armada_37xx_get_groups_count ,
. get_group_name = armada_37xx_get_group_name ,
. get_group_pins = armada_37xx_get_group_pins ,
. dt_node_to_map = pinconf_generic_dt_node_to_map_group ,
. dt_free_map = pinctrl_utils_free_map ,
} ;
/*
* Pinmux_ops handling
*/
static int armada_37xx_pmx_get_funcs_count ( struct pinctrl_dev * pctldev )
{
struct armada_37xx_pinctrl * info = pinctrl_dev_get_drvdata ( pctldev ) ;
return info - > nfuncs ;
}
static const char * armada_37xx_pmx_get_func_name ( struct pinctrl_dev * pctldev ,
unsigned int selector )
{
struct armada_37xx_pinctrl * info = pinctrl_dev_get_drvdata ( pctldev ) ;
return info - > funcs [ selector ] . name ;
}
static int armada_37xx_pmx_get_groups ( struct pinctrl_dev * pctldev ,
unsigned int selector ,
const char * const * * groups ,
unsigned int * const num_groups )
{
struct armada_37xx_pinctrl * info = pinctrl_dev_get_drvdata ( pctldev ) ;
* groups = info - > funcs [ selector ] . groups ;
* num_groups = info - > funcs [ selector ] . ngroups ;
return 0 ;
}
static int armada_37xx_pmx_set_by_name ( struct pinctrl_dev * pctldev ,
const char * name ,
struct armada_37xx_pin_group * grp )
{
struct armada_37xx_pinctrl * info = pinctrl_dev_get_drvdata ( pctldev ) ;
2021-11-05 14:42:32 +02:00
struct device * dev = info - > dev ;
2017-04-05 17:18:04 +02:00
unsigned int reg = SELECTION ;
unsigned int mask = grp - > reg_mask ;
int func , val ;
2021-11-05 14:42:32 +02:00
dev_dbg ( dev , " enable function %s group %s \n " , name , grp - > name ) ;
2017-04-05 17:18:04 +02:00
2018-05-03 20:26:42 +03:00
func = match_string ( grp - > funcs , NB_FUNCS , name ) ;
2017-04-05 17:18:04 +02:00
if ( func < 0 )
2018-05-03 20:26:42 +03:00
return - ENOTSUPP ;
2017-04-05 17:18:04 +02:00
val = grp - > val [ func ] ;
regmap_update_bits ( info - > regmap , reg , mask , val ) ;
return 0 ;
}
static int armada_37xx_pmx_set ( struct pinctrl_dev * pctldev ,
unsigned int selector ,
unsigned int group )
{
struct armada_37xx_pinctrl * info = pinctrl_dev_get_drvdata ( pctldev ) ;
struct armada_37xx_pin_group * grp = & info - > groups [ group ] ;
const char * name = info - > funcs [ selector ] . name ;
return armada_37xx_pmx_set_by_name ( pctldev , name , grp ) ;
}
2017-04-28 16:01:33 +02:00
static inline void armada_37xx_irq_update_reg ( unsigned int * reg ,
struct irq_data * d )
{
int offset = irqd_to_hwirq ( d ) ;
2019-10-01 10:46:31 -05:00
armada_37xx_update_reg ( reg , & offset ) ;
2017-04-28 16:01:33 +02:00
}
2017-04-05 17:18:05 +02:00
static int armada_37xx_gpio_direction_input ( struct gpio_chip * chip ,
unsigned int offset )
2017-04-05 17:18:04 +02:00
{
2017-04-05 17:18:05 +02:00
struct armada_37xx_pinctrl * info = gpiochip_get_data ( chip ) ;
2017-04-05 17:18:04 +02:00
unsigned int reg = OUTPUT_EN ;
unsigned int mask ;
2019-10-01 10:46:31 -05:00
armada_37xx_update_reg ( & reg , & offset ) ;
2017-04-05 17:18:04 +02:00
mask = BIT ( offset ) ;
return regmap_update_bits ( info - > regmap , reg , mask , 0 ) ;
}
2017-04-05 17:18:05 +02:00
static int armada_37xx_gpio_get_direction ( struct gpio_chip * chip ,
unsigned int offset )
2017-04-05 17:18:04 +02:00
{
2017-04-05 17:18:05 +02:00
struct armada_37xx_pinctrl * info = gpiochip_get_data ( chip ) ;
unsigned int reg = OUTPUT_EN ;
unsigned int val , mask ;
2019-10-01 10:46:31 -05:00
armada_37xx_update_reg ( & reg , & offset ) ;
2017-04-05 17:18:05 +02:00
mask = BIT ( offset ) ;
regmap_read ( info - > regmap , reg , & val ) ;
2020-02-14 15:57:12 +02:00
if ( val & mask )
return GPIO_LINE_DIRECTION_OUT ;
return GPIO_LINE_DIRECTION_IN ;
2017-04-05 17:18:05 +02:00
}
static int armada_37xx_gpio_direction_output ( struct gpio_chip * chip ,
unsigned int offset , int value )
{
struct armada_37xx_pinctrl * info = gpiochip_get_data ( chip ) ;
2017-04-05 17:18:04 +02:00
unsigned int reg = OUTPUT_EN ;
2017-11-14 17:51:50 +01:00
unsigned int mask , val , ret ;
2017-04-05 17:18:04 +02:00
2019-10-01 10:46:31 -05:00
armada_37xx_update_reg ( & reg , & offset ) ;
2017-04-05 17:18:04 +02:00
mask = BIT ( offset ) ;
2017-11-14 17:51:50 +01:00
ret = regmap_update_bits ( info - > regmap , reg , mask , mask ) ;
if ( ret )
return ret ;
reg = OUTPUT_VAL ;
val = value ? mask : 0 ;
regmap_update_bits ( info - > regmap , reg , mask , val ) ;
return 0 ;
2017-04-05 17:18:04 +02:00
}
2017-04-05 17:18:05 +02:00
static int armada_37xx_gpio_get ( struct gpio_chip * chip , unsigned int offset )
{
struct armada_37xx_pinctrl * info = gpiochip_get_data ( chip ) ;
unsigned int reg = INPUT_VAL ;
unsigned int val , mask ;
2019-10-01 10:46:31 -05:00
armada_37xx_update_reg ( & reg , & offset ) ;
2017-04-05 17:18:05 +02:00
mask = BIT ( offset ) ;
regmap_read ( info - > regmap , reg , & val ) ;
return ( val & mask ) ! = 0 ;
}
static void armada_37xx_gpio_set ( struct gpio_chip * chip , unsigned int offset ,
int value )
{
struct armada_37xx_pinctrl * info = gpiochip_get_data ( chip ) ;
unsigned int reg = OUTPUT_VAL ;
unsigned int mask , val ;
2019-10-01 10:46:31 -05:00
armada_37xx_update_reg ( & reg , & offset ) ;
2017-04-05 17:18:05 +02:00
mask = BIT ( offset ) ;
val = value ? mask : 0 ;
regmap_update_bits ( info - > regmap , reg , mask , val ) ;
}
2017-04-05 17:18:04 +02:00
static int armada_37xx_pmx_gpio_set_direction ( struct pinctrl_dev * pctldev ,
struct pinctrl_gpio_range * range ,
unsigned int offset , bool input )
{
struct armada_37xx_pinctrl * info = pinctrl_dev_get_drvdata ( pctldev ) ;
2017-04-05 17:18:05 +02:00
struct gpio_chip * chip = range - > gc ;
2017-04-05 17:18:04 +02:00
dev_dbg ( info - > dev , " gpio_direction for pin %u as %s-%d to %s \n " ,
offset , range - > name , offset , input ? " input " : " output " ) ;
if ( input )
2017-04-05 17:18:05 +02:00
armada_37xx_gpio_direction_input ( chip , offset ) ;
2017-04-05 17:18:04 +02:00
else
2017-04-05 17:18:05 +02:00
armada_37xx_gpio_direction_output ( chip , offset , 0 ) ;
2017-04-05 17:18:04 +02:00
return 0 ;
}
static int armada_37xx_gpio_request_enable ( struct pinctrl_dev * pctldev ,
struct pinctrl_gpio_range * range ,
unsigned int offset )
{
struct armada_37xx_pinctrl * info = pinctrl_dev_get_drvdata ( pctldev ) ;
struct armada_37xx_pin_group * group ;
int grp = 0 ;
dev_dbg ( info - > dev , " requesting gpio %d \n " , offset ) ;
while ( ( group = armada_37xx_find_next_grp_by_pin ( info , offset , & grp ) ) )
armada_37xx_pmx_set_by_name ( pctldev , " gpio " , group ) ;
return 0 ;
}
static const struct pinmux_ops armada_37xx_pmx_ops = {
. get_functions_count = armada_37xx_pmx_get_funcs_count ,
. get_function_name = armada_37xx_pmx_get_func_name ,
. get_function_groups = armada_37xx_pmx_get_groups ,
. set_mux = armada_37xx_pmx_set ,
. gpio_request_enable = armada_37xx_gpio_request_enable ,
. gpio_set_direction = armada_37xx_pmx_gpio_set_direction ,
} ;
2017-04-05 17:18:05 +02:00
static const struct gpio_chip armada_37xx_gpiolib_chip = {
. request = gpiochip_generic_request ,
. free = gpiochip_generic_free ,
. set = armada_37xx_gpio_set ,
. get = armada_37xx_gpio_get ,
. get_direction = armada_37xx_gpio_get_direction ,
. direction_input = armada_37xx_gpio_direction_input ,
. direction_output = armada_37xx_gpio_direction_output ,
. owner = THIS_MODULE ,
} ;
2017-04-28 16:01:33 +02:00
static void armada_37xx_irq_ack ( struct irq_data * d )
{
struct gpio_chip * chip = irq_data_get_irq_chip_data ( d ) ;
struct armada_37xx_pinctrl * info = gpiochip_get_data ( chip ) ;
u32 reg = IRQ_STATUS ;
unsigned long flags ;
armada_37xx_irq_update_reg ( & reg , d ) ;
2022-07-17 02:37:44 +03:00
raw_spin_lock_irqsave ( & info - > irq_lock , flags ) ;
2017-04-28 16:01:33 +02:00
writel ( d - > mask , info - > base + reg ) ;
2022-07-17 02:37:44 +03:00
raw_spin_unlock_irqrestore ( & info - > irq_lock , flags ) ;
2017-04-28 16:01:33 +02:00
}
static void armada_37xx_irq_mask ( struct irq_data * d )
{
struct gpio_chip * chip = irq_data_get_irq_chip_data ( d ) ;
struct armada_37xx_pinctrl * info = gpiochip_get_data ( chip ) ;
u32 val , reg = IRQ_EN ;
unsigned long flags ;
armada_37xx_irq_update_reg ( & reg , d ) ;
2022-07-17 02:37:44 +03:00
raw_spin_lock_irqsave ( & info - > irq_lock , flags ) ;
2017-04-28 16:01:33 +02:00
val = readl ( info - > base + reg ) ;
writel ( val & ~ d - > mask , info - > base + reg ) ;
2022-07-17 02:37:44 +03:00
raw_spin_unlock_irqrestore ( & info - > irq_lock , flags ) ;
2017-04-28 16:01:33 +02:00
}
static void armada_37xx_irq_unmask ( struct irq_data * d )
{
struct gpio_chip * chip = irq_data_get_irq_chip_data ( d ) ;
struct armada_37xx_pinctrl * info = gpiochip_get_data ( chip ) ;
u32 val , reg = IRQ_EN ;
unsigned long flags ;
armada_37xx_irq_update_reg ( & reg , d ) ;
2022-07-17 02:37:44 +03:00
raw_spin_lock_irqsave ( & info - > irq_lock , flags ) ;
2017-04-28 16:01:33 +02:00
val = readl ( info - > base + reg ) ;
writel ( val | d - > mask , info - > base + reg ) ;
2022-07-17 02:37:44 +03:00
raw_spin_unlock_irqrestore ( & info - > irq_lock , flags ) ;
2017-04-28 16:01:33 +02:00
}
static int armada_37xx_irq_set_wake ( struct irq_data * d , unsigned int on )
{
struct gpio_chip * chip = irq_data_get_irq_chip_data ( d ) ;
struct armada_37xx_pinctrl * info = gpiochip_get_data ( chip ) ;
u32 val , reg = IRQ_WKUP ;
unsigned long flags ;
armada_37xx_irq_update_reg ( & reg , d ) ;
2022-07-17 02:37:44 +03:00
raw_spin_lock_irqsave ( & info - > irq_lock , flags ) ;
2017-04-28 16:01:33 +02:00
val = readl ( info - > base + reg ) ;
if ( on )
2017-09-07 16:54:07 +02:00
val | = ( BIT ( d - > hwirq % GPIO_PER_REG ) ) ;
2017-04-28 16:01:33 +02:00
else
2017-09-07 16:54:07 +02:00
val & = ~ ( BIT ( d - > hwirq % GPIO_PER_REG ) ) ;
2017-04-28 16:01:33 +02:00
writel ( val , info - > base + reg ) ;
2022-07-17 02:37:44 +03:00
raw_spin_unlock_irqrestore ( & info - > irq_lock , flags ) ;
2017-04-28 16:01:33 +02:00
return 0 ;
}
static int armada_37xx_irq_set_type ( struct irq_data * d , unsigned int type )
{
struct gpio_chip * chip = irq_data_get_irq_chip_data ( d ) ;
struct armada_37xx_pinctrl * info = gpiochip_get_data ( chip ) ;
u32 val , reg = IRQ_POL ;
unsigned long flags ;
2022-07-17 02:37:44 +03:00
raw_spin_lock_irqsave ( & info - > irq_lock , flags ) ;
2017-04-28 16:01:33 +02:00
armada_37xx_irq_update_reg ( & reg , d ) ;
val = readl ( info - > base + reg ) ;
switch ( type ) {
case IRQ_TYPE_EDGE_RISING :
2017-09-07 16:54:07 +02:00
val & = ~ ( BIT ( d - > hwirq % GPIO_PER_REG ) ) ;
2017-04-28 16:01:33 +02:00
break ;
case IRQ_TYPE_EDGE_FALLING :
2017-09-07 16:54:07 +02:00
val | = ( BIT ( d - > hwirq % GPIO_PER_REG ) ) ;
2017-04-28 16:01:33 +02:00
break ;
2017-10-19 15:10:03 +02:00
case IRQ_TYPE_EDGE_BOTH : {
u32 in_val , in_reg = INPUT_VAL ;
armada_37xx_irq_update_reg ( & in_reg , d ) ;
regmap_read ( info - > regmap , in_reg , & in_val ) ;
/* Set initial polarity based on current input level. */
2019-11-15 16:57:52 +01:00
if ( in_val & BIT ( d - > hwirq % GPIO_PER_REG ) )
val | = BIT ( d - > hwirq % GPIO_PER_REG ) ; /* falling */
2017-10-19 15:10:03 +02:00
else
2019-11-15 16:57:52 +01:00
val & = ~ ( BIT ( d - > hwirq % GPIO_PER_REG ) ) ; /* rising */
2017-10-19 15:10:03 +02:00
break ;
}
2017-04-28 16:01:33 +02:00
default :
2022-07-17 02:37:44 +03:00
raw_spin_unlock_irqrestore ( & info - > irq_lock , flags ) ;
2017-04-28 16:01:33 +02:00
return - EINVAL ;
}
writel ( val , info - > base + reg ) ;
2022-07-17 02:37:44 +03:00
raw_spin_unlock_irqrestore ( & info - > irq_lock , flags ) ;
2017-04-28 16:01:33 +02:00
return 0 ;
}
2017-10-19 15:10:03 +02:00
static int armada_37xx_edge_both_irq_swap_pol ( struct armada_37xx_pinctrl * info ,
u32 pin_idx )
{
u32 reg_idx = pin_idx / GPIO_PER_REG ;
u32 bit_num = pin_idx % GPIO_PER_REG ;
u32 p , l , ret ;
unsigned long flags ;
regmap_read ( info - > regmap , INPUT_VAL + 4 * reg_idx , & l ) ;
2022-07-17 02:37:44 +03:00
raw_spin_lock_irqsave ( & info - > irq_lock , flags ) ;
2017-10-19 15:10:03 +02:00
p = readl ( info - > base + IRQ_POL + 4 * reg_idx ) ;
if ( ( p ^ l ) & ( 1 < < bit_num ) ) {
/*
* For the gpios which are used for both - edge irqs , when their
* interrupts happen , their input levels are changed ,
* yet their interrupt polarities are kept in old values , we
* should synchronize their interrupt polarities ; for example ,
* at first a gpio ' s input level is low and its interrupt
* polarity control is " Detect rising edge " , then the gpio has
* a interrupt , its level turns to high , we should change its
* polarity control to " Detect falling edge " correspondingly .
*/
p ^ = 1 < < bit_num ;
writel ( p , info - > base + IRQ_POL + 4 * reg_idx ) ;
ret = 0 ;
} else {
/* Spurious irq */
ret = - 1 ;
}
2022-07-17 02:37:44 +03:00
raw_spin_unlock_irqrestore ( & info - > irq_lock , flags ) ;
2017-10-19 15:10:03 +02:00
return ret ;
}
2017-04-28 16:01:33 +02:00
static void armada_37xx_irq_handler ( struct irq_desc * desc )
{
struct gpio_chip * gc = irq_desc_get_handler_data ( desc ) ;
struct irq_chip * chip = irq_desc_get_chip ( desc ) ;
struct armada_37xx_pinctrl * info = gpiochip_get_data ( gc ) ;
2017-11-07 19:15:47 +01:00
struct irq_domain * d = gc - > irq . domain ;
2017-04-28 16:01:33 +02:00
int i ;
chained_irq_enter ( chip , desc ) ;
for ( i = 0 ; i < = d - > revmap_size / GPIO_PER_REG ; i + + ) {
u32 status ;
unsigned long flags ;
2022-07-17 02:37:44 +03:00
raw_spin_lock_irqsave ( & info - > irq_lock , flags ) ;
2017-04-28 16:01:33 +02:00
status = readl_relaxed ( info - > base + IRQ_STATUS + 4 * i ) ;
/* Manage only the interrupt that was enabled */
status & = readl_relaxed ( info - > base + IRQ_EN + 4 * i ) ;
2022-07-17 02:37:44 +03:00
raw_spin_unlock_irqrestore ( & info - > irq_lock , flags ) ;
2017-04-28 16:01:33 +02:00
while ( status ) {
u32 hwirq = ffs ( status ) - 1 ;
u32 virq = irq_find_mapping ( d , hwirq +
i * GPIO_PER_REG ) ;
2017-10-19 15:10:03 +02:00
u32 t = irq_get_trigger_type ( virq ) ;
if ( ( t & IRQ_TYPE_SENSE_MASK ) = = IRQ_TYPE_EDGE_BOTH ) {
/* Swap polarity (race with GPIO line) */
if ( armada_37xx_edge_both_irq_swap_pol ( info ,
hwirq + i * GPIO_PER_REG ) ) {
/*
* For spurious irq , which gpio level
* is not as expected after incoming
* edge , just ack the gpio irq .
*/
writel ( 1 < < hwirq ,
info - > base +
IRQ_STATUS + 4 * i ) ;
2018-05-23 10:44:05 +02:00
goto update_status ;
2017-10-19 15:10:03 +02:00
}
}
2017-04-28 16:01:33 +02:00
generic_handle_irq ( virq ) ;
2018-05-23 10:44:05 +02:00
update_status :
2017-04-28 16:01:33 +02:00
/* Update status in case a new IRQ appears */
2022-07-17 02:37:44 +03:00
raw_spin_lock_irqsave ( & info - > irq_lock , flags ) ;
2017-04-28 16:01:33 +02:00
status = readl_relaxed ( info - > base +
IRQ_STATUS + 4 * i ) ;
/* Manage only the interrupt that was enabled */
status & = readl_relaxed ( info - > base + IRQ_EN + 4 * i ) ;
2022-07-17 02:37:44 +03:00
raw_spin_unlock_irqrestore ( & info - > irq_lock , flags ) ;
2017-04-28 16:01:33 +02:00
}
}
chained_irq_exit ( chip , desc ) ;
}
2017-09-07 16:54:07 +02:00
static unsigned int armada_37xx_irq_startup ( struct irq_data * d )
{
/*
* The mask field is a " precomputed bitmask for accessing the
* chip registers " which was introduced for the generic
* irqchip framework . As we don ' t use this framework , we can
* reuse this field for our own usage .
*/
2017-10-16 14:40:23 +02:00
d - > mask = BIT ( d - > hwirq % GPIO_PER_REG ) ;
2017-09-07 16:54:07 +02:00
armada_37xx_irq_unmask ( d ) ;
return 0 ;
}
2017-04-28 16:01:33 +02:00
static int armada_37xx_irqchip_register ( struct platform_device * pdev ,
struct armada_37xx_pinctrl * info )
{
struct gpio_chip * gc = & info - > gpio_chip ;
struct irq_chip * irqchip = & info - > irq_chip ;
2019-10-02 14:15:50 +02:00
struct gpio_irq_chip * girq = & gc - > irq ;
2022-04-01 13:36:04 +03:00
struct device_node * np = to_of_node ( gc - > fwnode ) ;
2019-10-02 14:15:50 +02:00
struct device * dev = & pdev - > dev ;
2022-04-01 13:36:04 +03:00
unsigned int i , nr_irq_parent ;
2017-04-28 16:01:33 +02:00
2022-07-17 02:37:44 +03:00
raw_spin_lock_init ( & info - > irq_lock ) ;
2017-04-28 16:01:33 +02:00
2022-04-01 13:36:04 +03:00
nr_irq_parent = of_irq_count ( np ) ;
2017-04-28 16:01:33 +02:00
if ( ! nr_irq_parent ) {
2019-10-02 14:15:50 +02:00
dev_err ( dev , " invalid or no IRQ \n " ) ;
2017-04-28 16:01:33 +02:00
return 0 ;
}
2021-11-05 14:42:33 +02:00
info - > base = devm_platform_ioremap_resource ( pdev , 1 ) ;
2017-04-28 16:01:33 +02:00
if ( IS_ERR ( info - > base ) )
return PTR_ERR ( info - > base ) ;
irqchip - > irq_ack = armada_37xx_irq_ack ;
irqchip - > irq_mask = armada_37xx_irq_mask ;
irqchip - > irq_unmask = armada_37xx_irq_unmask ;
irqchip - > irq_set_wake = armada_37xx_irq_set_wake ;
irqchip - > irq_set_type = armada_37xx_irq_set_type ;
2017-09-07 16:54:07 +02:00
irqchip - > irq_startup = armada_37xx_irq_startup ;
2017-04-28 16:01:33 +02:00
irqchip - > name = info - > data - > name ;
2019-10-02 14:15:50 +02:00
girq - > chip = irqchip ;
girq - > parent_handler = armada_37xx_irq_handler ;
2017-04-28 16:01:33 +02:00
/*
* Many interrupts are connected to the parent interrupt
* controller . But we do not take advantage of this and use
* the chained irq with all of them .
*/
2019-10-02 14:15:50 +02:00
girq - > num_parents = nr_irq_parent ;
2021-11-05 14:42:32 +02:00
girq - > parents = devm_kcalloc ( dev , nr_irq_parent , sizeof ( * girq - > parents ) , GFP_KERNEL ) ;
2019-10-02 14:15:50 +02:00
if ( ! girq - > parents )
return - ENOMEM ;
2017-04-28 16:01:33 +02:00
for ( i = 0 ; i < nr_irq_parent ; i + + ) {
2020-03-26 00:20:38 +01:00
int irq = irq_of_parse_and_map ( np , i ) ;
2017-04-28 16:01:33 +02:00
2022-04-22 12:53:38 +02:00
if ( ! irq )
2017-04-28 16:01:33 +02:00
continue ;
2019-10-02 14:15:50 +02:00
girq - > parents [ i ] = irq ;
2017-04-28 16:01:33 +02:00
}
2019-10-02 14:15:50 +02:00
girq - > default_type = IRQ_TYPE_NONE ;
girq - > handler = handle_edge_irq ;
2017-04-28 16:01:33 +02:00
return 0 ;
}
2017-04-05 17:18:05 +02:00
static int armada_37xx_gpiochip_register ( struct platform_device * pdev ,
struct armada_37xx_pinctrl * info )
{
2021-11-05 14:42:32 +02:00
struct device * dev = & pdev - > dev ;
2022-04-01 13:36:03 +03:00
struct fwnode_handle * fwnode ;
2017-04-05 17:18:05 +02:00
struct gpio_chip * gc ;
2022-04-01 13:36:03 +03:00
int ret ;
2017-04-05 17:18:05 +02:00
2022-04-01 13:36:03 +03:00
fwnode = gpiochip_node_get_first ( dev ) ;
if ( ! fwnode )
return - ENODEV ;
2017-04-05 17:18:05 +02:00
info - > gpio_chip = armada_37xx_gpiolib_chip ;
gc = & info - > gpio_chip ;
gc - > ngpio = info - > data - > nr_pins ;
2021-11-05 14:42:32 +02:00
gc - > parent = dev ;
2017-04-05 17:18:05 +02:00
gc - > base = - 1 ;
2022-04-01 13:36:03 +03:00
gc - > fwnode = fwnode ;
2017-04-05 17:18:05 +02:00
gc - > label = info - > data - > name ;
2019-10-02 14:15:50 +02:00
ret = armada_37xx_irqchip_register ( pdev , info ) ;
2017-04-05 17:18:05 +02:00
if ( ret )
return ret ;
2021-11-05 14:42:32 +02:00
return devm_gpiochip_add_data ( dev , gc , info ) ;
2017-04-05 17:18:05 +02:00
}
2017-04-05 17:18:04 +02:00
/**
* armada_37xx_add_function ( ) - Add a new function to the list
* @ funcs : array of function to add the new one
* @ funcsize : size of the remaining space for the function
* @ name : name of the function to add
*
* If it is a new function then create it by adding its name else
* increment the number of group associated to this function .
*/
static int armada_37xx_add_function ( struct armada_37xx_pmx_func * funcs ,
int * funcsize , const char * name )
{
int i = 0 ;
if ( * funcsize < = 0 )
return - EOVERFLOW ;
while ( funcs - > ngroups ) {
/* function already there */
if ( strcmp ( funcs - > name , name ) = = 0 ) {
funcs - > ngroups + + ;
return - EEXIST ;
}
funcs + + ;
i + + ;
}
/* append new unique function */
funcs - > name = name ;
funcs - > ngroups = 1 ;
( * funcsize ) - - ;
return 0 ;
}
/**
* armada_37xx_fill_group ( ) - complete the group array
* @ info : info driver instance
*
* Based on the data available from the armada_37xx_pin_group array
* completes the last member of the struct for each function : the list
* of the groups associated to this function .
*
*/
static int armada_37xx_fill_group ( struct armada_37xx_pinctrl * info )
{
int n , num = 0 , funcsize = info - > data - > nr_pins ;
2021-11-05 14:42:32 +02:00
struct device * dev = info - > dev ;
2017-04-05 17:18:04 +02:00
for ( n = 0 ; n < info - > ngroups ; n + + ) {
struct armada_37xx_pin_group * grp = & info - > groups [ n ] ;
int i , j , f ;
2021-11-05 14:42:32 +02:00
grp - > pins = devm_kcalloc ( dev , grp - > npins + grp - > extra_npins ,
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-12 14:07:58 -07:00
sizeof ( * grp - > pins ) ,
GFP_KERNEL ) ;
2017-04-05 17:18:04 +02:00
if ( ! grp - > pins )
return - ENOMEM ;
for ( i = 0 ; i < grp - > npins ; i + + )
grp - > pins [ i ] = grp - > start_pin + i ;
for ( j = 0 ; j < grp - > extra_npins ; j + + )
grp - > pins [ i + j ] = grp - > extra_pin + j ;
2017-08-01 17:57:19 +02:00
for ( f = 0 ; ( f < NB_FUNCS ) & & grp - > funcs [ f ] ; f + + ) {
2017-04-05 17:18:04 +02:00
int ret ;
/* check for unique functions and count groups */
ret = armada_37xx_add_function ( info - > funcs , & funcsize ,
grp - > funcs [ f ] ) ;
if ( ret = = - EOVERFLOW )
2021-11-05 14:42:32 +02:00
dev_err ( dev , " More functions than pins(%d) \n " ,
2017-04-05 17:18:04 +02:00
info - > data - > nr_pins ) ;
if ( ret < 0 )
continue ;
num + + ;
}
}
info - > nfuncs = num ;
return 0 ;
}
/**
2021-11-05 14:42:31 +02:00
* armada_37xx_fill_func ( ) - complete the funcs array
2017-04-05 17:18:04 +02:00
* @ info : info driver instance
*
* Based on the data available from the armada_37xx_pin_group array
* completes the last two member of the struct for each group :
* - the list of the pins included in the group
* - the list of pinmux functions that can be selected for this group
*
*/
static int armada_37xx_fill_func ( struct armada_37xx_pinctrl * info )
{
struct armada_37xx_pmx_func * funcs = info - > funcs ;
2021-11-05 14:42:32 +02:00
struct device * dev = info - > dev ;
2017-04-05 17:18:04 +02:00
int n ;
for ( n = 0 ; n < info - > nfuncs ; n + + ) {
const char * name = funcs [ n ] . name ;
const char * * groups ;
int g ;
2021-11-05 14:42:32 +02:00
funcs [ n ] . groups = devm_kcalloc ( dev , funcs [ n ] . ngroups ,
2017-04-05 17:18:04 +02:00
sizeof ( * ( funcs [ n ] . groups ) ) ,
GFP_KERNEL ) ;
if ( ! funcs [ n ] . groups )
return - ENOMEM ;
groups = funcs [ n ] . groups ;
for ( g = 0 ; g < info - > ngroups ; g + + ) {
struct armada_37xx_pin_group * gp = & info - > groups [ g ] ;
int f ;
2018-05-03 20:26:42 +03:00
f = match_string ( gp - > funcs , NB_FUNCS , name ) ;
if ( f < 0 )
continue ;
* groups = gp - > name ;
groups + + ;
2017-04-05 17:18:04 +02:00
}
}
return 0 ;
}
static int armada_37xx_pinctrl_register ( struct platform_device * pdev ,
struct armada_37xx_pinctrl * info )
{
const struct armada_37xx_pin_data * pin_data = info - > data ;
struct pinctrl_desc * ctrldesc = & info - > pctl ;
struct pinctrl_pin_desc * pindesc , * pdesc ;
2021-11-05 14:42:32 +02:00
struct device * dev = & pdev - > dev ;
2021-11-05 14:42:35 +02:00
char * * pin_names ;
2017-04-05 17:18:04 +02:00
int pin , ret ;
info - > groups = pin_data - > groups ;
info - > ngroups = pin_data - > ngroups ;
ctrldesc - > name = " armada_37xx-pinctrl " ;
ctrldesc - > owner = THIS_MODULE ;
ctrldesc - > pctlops = & armada_37xx_pctrl_ops ;
ctrldesc - > pmxops = & armada_37xx_pmx_ops ;
ctrldesc - > confops = & armada_37xx_pinconf_ops ;
2021-11-05 14:42:32 +02:00
pindesc = devm_kcalloc ( dev , pin_data - > nr_pins , sizeof ( * pindesc ) , GFP_KERNEL ) ;
2017-04-05 17:18:04 +02:00
if ( ! pindesc )
return - ENOMEM ;
ctrldesc - > pins = pindesc ;
ctrldesc - > npins = pin_data - > nr_pins ;
2021-11-05 14:42:35 +02:00
pin_names = devm_kasprintf_strarray ( dev , pin_data - > name , pin_data - > nr_pins ) ;
if ( IS_ERR ( pin_names ) )
return PTR_ERR ( pin_names ) ;
2017-04-05 17:18:04 +02:00
pdesc = pindesc ;
for ( pin = 0 ; pin < pin_data - > nr_pins ; pin + + ) {
pdesc - > number = pin ;
2021-11-05 14:42:35 +02:00
pdesc - > name = pin_names [ pin ] ;
2017-04-05 17:18:04 +02:00
pdesc + + ;
}
/*
* we allocate functions for number of pins and hope there are
* fewer unique functions than pins available
*/
2021-11-05 14:42:32 +02:00
info - > funcs = devm_kcalloc ( dev , pin_data - > nr_pins , sizeof ( * info - > funcs ) , GFP_KERNEL ) ;
2017-04-05 17:18:04 +02:00
if ( ! info - > funcs )
return - ENOMEM ;
ret = armada_37xx_fill_group ( info ) ;
if ( ret )
return ret ;
ret = armada_37xx_fill_func ( info ) ;
if ( ret )
return ret ;
2021-11-05 14:42:32 +02:00
info - > pctl_dev = devm_pinctrl_register ( dev , ctrldesc , info ) ;
2021-11-05 14:42:34 +02:00
if ( IS_ERR ( info - > pctl_dev ) )
return dev_err_probe ( dev , PTR_ERR ( info - > pctl_dev ) , " could not register pinctrl driver \n " ) ;
2017-04-05 17:18:04 +02:00
return 0 ;
}
2018-06-26 16:06:13 +02:00
# if defined(CONFIG_PM)
static int armada_3700_pinctrl_suspend ( struct device * dev )
{
struct armada_37xx_pinctrl * info = dev_get_drvdata ( dev ) ;
/* Save GPIO state */
regmap_read ( info - > regmap , OUTPUT_EN , & info - > pm . out_en_l ) ;
regmap_read ( info - > regmap , OUTPUT_EN + sizeof ( u32 ) , & info - > pm . out_en_h ) ;
regmap_read ( info - > regmap , OUTPUT_VAL , & info - > pm . out_val_l ) ;
regmap_read ( info - > regmap , OUTPUT_VAL + sizeof ( u32 ) ,
& info - > pm . out_val_h ) ;
info - > pm . irq_en_l = readl ( info - > base + IRQ_EN ) ;
info - > pm . irq_en_h = readl ( info - > base + IRQ_EN + sizeof ( u32 ) ) ;
info - > pm . irq_pol_l = readl ( info - > base + IRQ_POL ) ;
info - > pm . irq_pol_h = readl ( info - > base + IRQ_POL + sizeof ( u32 ) ) ;
/* Save pinctrl state */
regmap_read ( info - > regmap , SELECTION , & info - > pm . selection ) ;
return 0 ;
}
static int armada_3700_pinctrl_resume ( struct device * dev )
{
struct armada_37xx_pinctrl * info = dev_get_drvdata ( dev ) ;
struct gpio_chip * gc ;
struct irq_domain * d ;
int i ;
/* Restore GPIO state */
regmap_write ( info - > regmap , OUTPUT_EN , info - > pm . out_en_l ) ;
regmap_write ( info - > regmap , OUTPUT_EN + sizeof ( u32 ) ,
info - > pm . out_en_h ) ;
regmap_write ( info - > regmap , OUTPUT_VAL , info - > pm . out_val_l ) ;
regmap_write ( info - > regmap , OUTPUT_VAL + sizeof ( u32 ) ,
info - > pm . out_val_h ) ;
/*
* Input levels may change during suspend , which is not monitored at
* that time . GPIOs used for both - edge IRQs may not be synchronized
* anymore with their polarities ( rising / falling edge ) and must be
* re - configured manually .
*/
gc = & info - > gpio_chip ;
d = gc - > irq . domain ;
for ( i = 0 ; i < gc - > ngpio ; i + + ) {
u32 irq_bit = BIT ( i % GPIO_PER_REG ) ;
u32 mask , * irq_pol , input_reg , virq , type , level ;
if ( i < GPIO_PER_REG ) {
mask = info - > pm . irq_en_l ;
irq_pol = & info - > pm . irq_pol_l ;
input_reg = INPUT_VAL ;
} else {
mask = info - > pm . irq_en_h ;
irq_pol = & info - > pm . irq_pol_h ;
input_reg = INPUT_VAL + sizeof ( u32 ) ;
}
if ( ! ( mask & irq_bit ) )
continue ;
virq = irq_find_mapping ( d , i ) ;
type = irq_get_trigger_type ( virq ) ;
/*
* Synchronize level and polarity for both - edge irqs :
* - a high input level expects a falling edge ,
* - a low input level exepects a rising edge .
*/
if ( ( type & IRQ_TYPE_SENSE_MASK ) = =
IRQ_TYPE_EDGE_BOTH ) {
regmap_read ( info - > regmap , input_reg , & level ) ;
if ( ( * irq_pol ^ level ) & irq_bit )
* irq_pol ^ = irq_bit ;
}
}
writel ( info - > pm . irq_en_l , info - > base + IRQ_EN ) ;
writel ( info - > pm . irq_en_h , info - > base + IRQ_EN + sizeof ( u32 ) ) ;
writel ( info - > pm . irq_pol_l , info - > base + IRQ_POL ) ;
writel ( info - > pm . irq_pol_h , info - > base + IRQ_POL + sizeof ( u32 ) ) ;
/* Restore pinctrl state */
regmap_write ( info - > regmap , SELECTION , info - > pm . selection ) ;
return 0 ;
}
/*
* Since pinctrl is an infrastructure module , its resume should be issued prior
* to other IO drivers .
*/
static const struct dev_pm_ops armada_3700_pinctrl_pm_ops = {
2019-01-08 17:28:43 +01:00
. suspend_noirq = armada_3700_pinctrl_suspend ,
. resume_noirq = armada_3700_pinctrl_resume ,
2018-06-26 16:06:13 +02:00
} ;
# define PINCTRL_ARMADA_37XX_DEV_PM_OPS (&armada_3700_pinctrl_pm_ops)
# else
# define PINCTRL_ARMADA_37XX_DEV_PM_OPS NULL
# endif /* CONFIG_PM */
2017-04-05 17:18:04 +02:00
static const struct of_device_id armada_37xx_pinctrl_of_match [ ] = {
{
. compatible = " marvell,armada3710-sb-pinctrl " ,
2018-01-02 14:28:01 +01:00
. data = & armada_37xx_pin_sb ,
2017-04-05 17:18:04 +02:00
} ,
{
. compatible = " marvell,armada3710-nb-pinctrl " ,
2018-01-02 14:28:01 +01:00
. data = & armada_37xx_pin_nb ,
2017-04-05 17:18:04 +02:00
} ,
{ } ,
} ;
2022-07-17 02:37:45 +03:00
static const struct regmap_config armada_37xx_pinctrl_regmap_config = {
. reg_bits = 32 ,
. val_bits = 32 ,
. reg_stride = 4 ,
. use_raw_spinlock = true ,
} ;
2017-04-05 17:18:04 +02:00
static int __init armada_37xx_pinctrl_probe ( struct platform_device * pdev )
{
struct armada_37xx_pinctrl * info ;
struct device * dev = & pdev - > dev ;
struct regmap * regmap ;
2022-07-17 02:37:45 +03:00
void __iomem * base ;
2017-04-05 17:18:04 +02:00
int ret ;
2022-07-17 02:37:45 +03:00
base = devm_platform_get_and_ioremap_resource ( pdev , 0 , NULL ) ;
if ( IS_ERR ( base ) ) {
dev_err ( dev , " failed to ioremap base address: %pe \n " , base ) ;
return PTR_ERR ( base ) ;
}
regmap = devm_regmap_init_mmio ( dev , base ,
& armada_37xx_pinctrl_regmap_config ) ;
if ( IS_ERR ( regmap ) ) {
dev_err ( dev , " failed to create regmap: %pe \n " , regmap ) ;
return PTR_ERR ( regmap ) ;
}
2021-11-05 14:42:32 +02:00
info = devm_kzalloc ( dev , sizeof ( * info ) , GFP_KERNEL ) ;
2017-04-05 17:18:04 +02:00
if ( ! info )
return - ENOMEM ;
info - > dev = dev ;
info - > regmap = regmap ;
info - > data = of_device_get_match_data ( dev ) ;
ret = armada_37xx_pinctrl_register ( pdev , info ) ;
if ( ret )
return ret ;
2017-04-05 17:18:05 +02:00
ret = armada_37xx_gpiochip_register ( pdev , info ) ;
if ( ret )
return ret ;
2017-04-05 17:18:04 +02:00
platform_set_drvdata ( pdev , info ) ;
return 0 ;
}
static struct platform_driver armada_37xx_pinctrl_driver = {
. driver = {
. name = " armada-37xx-pinctrl " ,
. of_match_table = armada_37xx_pinctrl_of_match ,
2018-06-26 16:06:13 +02:00
. pm = PINCTRL_ARMADA_37XX_DEV_PM_OPS ,
2017-04-05 17:18:04 +02:00
} ,
} ;
builtin_platform_driver_probe ( armada_37xx_pinctrl_driver ,
armada_37xx_pinctrl_probe ) ;