2016-01-14 15:16:30 +03:00
/*
* Copyright ( C ) Maxime Coquelin 2015
* Author : Maxime Coquelin < mcoquelin . stm32 @ gmail . com >
* License terms : GNU General Public License ( GPL ) , version 2
*
* Heavily based on Mediatek ' s pinctrl driver
*/
# include <linux/clk.h>
2016-02-06 01:47:13 +03:00
# include <linux/gpio/driver.h>
2016-01-14 15:16:30 +03:00
# include <linux/io.h>
2016-09-09 17:42:01 +03:00
# include <linux/irq.h>
# include <linux/mfd/syscon.h>
2016-01-14 15:16:30 +03:00
# include <linux/module.h>
# include <linux/of.h>
# include <linux/of_address.h>
# include <linux/of_device.h>
# include <linux/of_irq.h>
# include <linux/pinctrl/consumer.h>
# include <linux/pinctrl/machine.h>
# include <linux/pinctrl/pinconf.h>
# include <linux/pinctrl/pinconf-generic.h>
# include <linux/pinctrl/pinctrl.h>
# include <linux/pinctrl/pinmux.h>
# include <linux/platform_device.h>
2016-09-09 17:42:01 +03:00
# include <linux/regmap.h>
2016-01-14 15:16:30 +03:00
# include <linux/reset.h>
# include <linux/slab.h>
# include "../core.h"
# include "../pinconf.h"
# include "../pinctrl-utils.h"
# include "pinctrl-stm32.h"
# define STM32_GPIO_MODER 0x00
# define STM32_GPIO_TYPER 0x04
# define STM32_GPIO_SPEEDR 0x08
# define STM32_GPIO_PUPDR 0x0c
# define STM32_GPIO_IDR 0x10
# define STM32_GPIO_ODR 0x14
# define STM32_GPIO_BSRR 0x18
# define STM32_GPIO_LCKR 0x1c
# define STM32_GPIO_AFRL 0x20
# define STM32_GPIO_AFRH 0x24
# define STM32_GPIO_PINS_PER_BANK 16
2016-09-09 17:42:01 +03:00
# define STM32_GPIO_IRQ_LINE 16
2016-01-14 15:16:30 +03:00
# define gpio_range_to_bank(chip) \
container_of ( chip , struct stm32_gpio_bank , range )
static const char * const stm32_gpio_functions [ ] = {
" gpio " , " af0 " , " af1 " ,
" af2 " , " af3 " , " af4 " ,
" af5 " , " af6 " , " af7 " ,
" af8 " , " af9 " , " af10 " ,
" af11 " , " af12 " , " af13 " ,
" af14 " , " af15 " , " analog " ,
} ;
struct stm32_pinctrl_group {
const char * name ;
unsigned long config ;
unsigned pin ;
} ;
struct stm32_gpio_bank {
void __iomem * base ;
struct clk * clk ;
spinlock_t lock ;
struct gpio_chip gpio_chip ;
struct pinctrl_gpio_range range ;
2016-09-09 17:42:01 +03:00
struct fwnode_handle * fwnode ;
struct irq_domain * domain ;
2017-04-07 15:42:58 +03:00
u32 bank_nr ;
2016-01-14 15:16:30 +03:00
} ;
struct stm32_pinctrl {
struct device * dev ;
struct pinctrl_dev * pctl_dev ;
struct pinctrl_desc pctl_desc ;
struct stm32_pinctrl_group * groups ;
unsigned ngroups ;
const char * * grp_names ;
struct stm32_gpio_bank * banks ;
unsigned nbanks ;
const struct stm32_pinctrl_match_data * match_data ;
2016-09-09 17:42:01 +03:00
struct irq_domain * domain ;
struct regmap * regmap ;
struct regmap_field * irqmux [ STM32_GPIO_PINS_PER_BANK ] ;
2016-01-14 15:16:30 +03:00
} ;
static inline int stm32_gpio_pin ( int gpio )
{
return gpio % STM32_GPIO_PINS_PER_BANK ;
}
static inline u32 stm32_gpio_get_mode ( u32 function )
{
switch ( function ) {
case STM32_PIN_GPIO :
return 0 ;
case STM32_PIN_AF ( 0 ) . . . STM32_PIN_AF ( 15 ) :
return 2 ;
case STM32_PIN_ANALOG :
return 3 ;
}
return 0 ;
}
static inline u32 stm32_gpio_get_alt ( u32 function )
{
switch ( function ) {
case STM32_PIN_GPIO :
return 0 ;
case STM32_PIN_AF ( 0 ) . . . STM32_PIN_AF ( 15 ) :
return function - 1 ;
case STM32_PIN_ANALOG :
return 0 ;
}
return 0 ;
}
/* GPIO functions */
static inline void __stm32_gpio_set ( struct stm32_gpio_bank * bank ,
unsigned offset , int value )
{
if ( ! value )
offset + = STM32_GPIO_PINS_PER_BANK ;
clk_enable ( bank - > clk ) ;
writel_relaxed ( BIT ( offset ) , bank - > base + STM32_GPIO_BSRR ) ;
clk_disable ( bank - > clk ) ;
}
static int stm32_gpio_request ( struct gpio_chip * chip , unsigned offset )
{
2017-04-07 15:42:58 +03:00
struct stm32_gpio_bank * bank = gpiochip_get_data ( chip ) ;
struct stm32_pinctrl * pctl = dev_get_drvdata ( bank - > gpio_chip . parent ) ;
struct pinctrl_gpio_range * range ;
int pin = offset + ( bank - > bank_nr * STM32_GPIO_PINS_PER_BANK ) ;
range = pinctrl_find_gpio_range_from_pin_nolock ( pctl - > pctl_dev , pin ) ;
if ( ! range ) {
dev_err ( pctl - > dev , " pin %d not in range. \n " , pin ) ;
return - EINVAL ;
}
2016-01-14 15:16:30 +03:00
return pinctrl_request_gpio ( chip - > base + offset ) ;
}
static void stm32_gpio_free ( struct gpio_chip * chip , unsigned offset )
{
pinctrl_free_gpio ( chip - > base + offset ) ;
}
static int stm32_gpio_get ( struct gpio_chip * chip , unsigned offset )
{
2016-02-06 01:47:13 +03:00
struct stm32_gpio_bank * bank = gpiochip_get_data ( chip ) ;
2016-01-14 15:16:30 +03:00
int ret ;
clk_enable ( bank - > clk ) ;
ret = ! ! ( readl_relaxed ( bank - > base + STM32_GPIO_IDR ) & BIT ( offset ) ) ;
clk_disable ( bank - > clk ) ;
return ret ;
}
static void stm32_gpio_set ( struct gpio_chip * chip , unsigned offset , int value )
{
2016-02-06 01:47:13 +03:00
struct stm32_gpio_bank * bank = gpiochip_get_data ( chip ) ;
2016-01-14 15:16:30 +03:00
__stm32_gpio_set ( bank , offset , value ) ;
}
static int stm32_gpio_direction_input ( struct gpio_chip * chip , unsigned offset )
{
return pinctrl_gpio_direction_input ( chip - > base + offset ) ;
}
static int stm32_gpio_direction_output ( struct gpio_chip * chip ,
unsigned offset , int value )
{
2016-02-06 01:47:13 +03:00
struct stm32_gpio_bank * bank = gpiochip_get_data ( chip ) ;
2016-01-14 15:16:30 +03:00
__stm32_gpio_set ( bank , offset , value ) ;
pinctrl_gpio_direction_output ( chip - > base + offset ) ;
return 0 ;
}
2016-09-09 17:42:01 +03:00
static int stm32_gpio_to_irq ( struct gpio_chip * chip , unsigned int offset )
{
struct stm32_gpio_bank * bank = gpiochip_get_data ( chip ) ;
struct irq_fwspec fwspec ;
fwspec . fwnode = bank - > fwnode ;
fwspec . param_count = 2 ;
fwspec . param [ 0 ] = offset ;
fwspec . param [ 1 ] = IRQ_TYPE_NONE ;
return irq_create_fwspec_mapping ( & fwspec ) ;
}
2017-05-29 19:17:32 +03:00
static int stm32_gpio_get_direction ( struct gpio_chip * chip , unsigned int offset )
{
struct stm32_gpio_bank * bank = gpiochip_get_data ( chip ) ;
int pin = stm32_gpio_pin ( offset ) ;
int ret ;
u32 mode , alt ;
stm32_pmx_get_mode ( bank , pin , & mode , & alt ) ;
if ( ( alt = = 0 ) & & ( mode = = 0 ) )
ret = 1 ;
else if ( ( alt = = 0 ) & & ( mode = = 1 ) )
ret = 0 ;
else
ret = - EINVAL ;
return ret ;
}
2016-09-11 15:14:40 +03:00
static const struct gpio_chip stm32_gpio_template = {
2016-01-14 15:16:30 +03:00
. request = stm32_gpio_request ,
. free = stm32_gpio_free ,
. get = stm32_gpio_get ,
. set = stm32_gpio_set ,
. direction_input = stm32_gpio_direction_input ,
. direction_output = stm32_gpio_direction_output ,
2016-09-09 17:42:01 +03:00
. to_irq = stm32_gpio_to_irq ,
2017-05-29 19:17:32 +03:00
. get_direction = stm32_gpio_get_direction ,
2016-01-14 15:16:30 +03:00
} ;
2017-05-29 19:17:31 +03:00
static int stm32_gpio_irq_request_resources ( struct irq_data * irq_data )
{
struct stm32_gpio_bank * bank = irq_data - > domain - > host_data ;
struct stm32_pinctrl * pctl = dev_get_drvdata ( bank - > gpio_chip . parent ) ;
int ret ;
ret = stm32_gpio_direction_input ( & bank - > gpio_chip , irq_data - > hwirq ) ;
if ( ret )
return ret ;
ret = gpiochip_lock_as_irq ( & bank - > gpio_chip , irq_data - > hwirq ) ;
if ( ret ) {
dev_err ( pctl - > dev , " unable to lock HW IRQ %lu for IRQ \n " ,
irq_data - > hwirq ) ;
return ret ;
}
return 0 ;
}
static void stm32_gpio_irq_release_resources ( struct irq_data * irq_data )
{
struct stm32_gpio_bank * bank = irq_data - > domain - > host_data ;
gpiochip_unlock_as_irq ( & bank - > gpio_chip , irq_data - > hwirq ) ;
}
2016-09-09 17:42:01 +03:00
static struct irq_chip stm32_gpio_irq_chip = {
. name = " stm32gpio " ,
. irq_eoi = irq_chip_eoi_parent ,
. irq_mask = irq_chip_mask_parent ,
. irq_unmask = irq_chip_unmask_parent ,
. irq_set_type = irq_chip_set_type_parent ,
2017-05-29 19:17:31 +03:00
. irq_request_resources = stm32_gpio_irq_request_resources ,
. irq_release_resources = stm32_gpio_irq_release_resources ,
2016-09-09 17:42:01 +03:00
} ;
static int stm32_gpio_domain_translate ( struct irq_domain * d ,
struct irq_fwspec * fwspec ,
unsigned long * hwirq ,
unsigned int * type )
{
if ( ( fwspec - > param_count ! = 2 ) | |
( fwspec - > param [ 0 ] > = STM32_GPIO_IRQ_LINE ) )
return - EINVAL ;
* hwirq = fwspec - > param [ 0 ] ;
* type = fwspec - > param [ 1 ] ;
return 0 ;
}
2016-01-14 15:16:30 +03:00
2016-09-09 17:42:01 +03:00
static void stm32_gpio_domain_activate ( struct irq_domain * d ,
struct irq_data * irq_data )
{
struct stm32_gpio_bank * bank = d - > host_data ;
struct stm32_pinctrl * pctl = dev_get_drvdata ( bank - > gpio_chip . parent ) ;
2017-04-07 15:42:58 +03:00
regmap_field_write ( pctl - > irqmux [ irq_data - > hwirq ] , bank - > bank_nr ) ;
2016-09-09 17:42:01 +03:00
}
static int stm32_gpio_domain_alloc ( struct irq_domain * d ,
unsigned int virq ,
unsigned int nr_irqs , void * data )
{
struct stm32_gpio_bank * bank = d - > host_data ;
struct irq_fwspec * fwspec = data ;
struct irq_fwspec parent_fwspec ;
irq_hw_number_t hwirq ;
hwirq = fwspec - > param [ 0 ] ;
parent_fwspec . fwnode = d - > parent - > fwnode ;
parent_fwspec . param_count = 2 ;
parent_fwspec . param [ 0 ] = fwspec - > param [ 0 ] ;
parent_fwspec . param [ 1 ] = fwspec - > param [ 1 ] ;
irq_domain_set_hwirq_and_chip ( d , virq , hwirq , & stm32_gpio_irq_chip ,
bank ) ;
2017-01-27 19:15:14 +03:00
return irq_domain_alloc_irqs_parent ( d , virq , nr_irqs , & parent_fwspec ) ;
2016-09-09 17:42:01 +03:00
}
static const struct irq_domain_ops stm32_gpio_domain_ops = {
. translate = stm32_gpio_domain_translate ,
. alloc = stm32_gpio_domain_alloc ,
2017-01-27 19:15:14 +03:00
. free = irq_domain_free_irqs_common ,
2016-09-09 17:42:01 +03:00
. activate = stm32_gpio_domain_activate ,
} ;
/* Pinctrl functions */
2016-01-14 15:16:30 +03:00
static struct stm32_pinctrl_group *
stm32_pctrl_find_group_by_pin ( struct stm32_pinctrl * pctl , u32 pin )
{
int i ;
for ( i = 0 ; i < pctl - > ngroups ; i + + ) {
struct stm32_pinctrl_group * grp = pctl - > groups + i ;
if ( grp - > pin = = pin )
return grp ;
}
return NULL ;
}
static bool stm32_pctrl_is_function_valid ( struct stm32_pinctrl * pctl ,
u32 pin_num , u32 fnum )
{
int i ;
for ( i = 0 ; i < pctl - > match_data - > npins ; i + + ) {
const struct stm32_desc_pin * pin = pctl - > match_data - > pins + i ;
const struct stm32_desc_function * func = pin - > functions ;
if ( pin - > pin . number ! = pin_num )
continue ;
while ( func & & func - > name ) {
if ( func - > num = = fnum )
return true ;
func + + ;
}
break ;
}
return false ;
}
static int stm32_pctrl_dt_node_to_map_func ( struct stm32_pinctrl * pctl ,
u32 pin , u32 fnum , struct stm32_pinctrl_group * grp ,
struct pinctrl_map * * map , unsigned * reserved_maps ,
unsigned * num_maps )
{
if ( * num_maps = = * reserved_maps )
return - ENOSPC ;
( * map ) [ * num_maps ] . type = PIN_MAP_TYPE_MUX_GROUP ;
( * map ) [ * num_maps ] . data . mux . group = grp - > name ;
if ( ! stm32_pctrl_is_function_valid ( pctl , pin , fnum ) ) {
dev_err ( pctl - > dev , " invalid function %d on pin %d . \n " ,
fnum , pin ) ;
return - EINVAL ;
}
( * map ) [ * num_maps ] . data . mux . function = stm32_gpio_functions [ fnum ] ;
( * num_maps ) + + ;
return 0 ;
}
static int stm32_pctrl_dt_subnode_to_map ( struct pinctrl_dev * pctldev ,
struct device_node * node ,
struct pinctrl_map * * map ,
unsigned * reserved_maps ,
unsigned * num_maps )
{
struct stm32_pinctrl * pctl ;
struct stm32_pinctrl_group * grp ;
struct property * pins ;
u32 pinfunc , pin , func ;
unsigned long * configs ;
unsigned int num_configs ;
bool has_config = 0 ;
unsigned reserve = 0 ;
int num_pins , num_funcs , maps_per_pin , i , err ;
pctl = pinctrl_dev_get_drvdata ( pctldev ) ;
pins = of_find_property ( node , " pinmux " , NULL ) ;
if ( ! pins ) {
dev_err ( pctl - > dev , " missing pins property in node %s . \n " ,
node - > name ) ;
return - EINVAL ;
}
err = pinconf_generic_parse_dt_config ( node , pctldev , & configs ,
& num_configs ) ;
if ( err )
return err ;
if ( num_configs )
has_config = 1 ;
num_pins = pins - > length / sizeof ( u32 ) ;
num_funcs = num_pins ;
maps_per_pin = 0 ;
if ( num_funcs )
maps_per_pin + + ;
if ( has_config & & num_pins > = 1 )
maps_per_pin + + ;
if ( ! num_pins | | ! maps_per_pin )
return - EINVAL ;
reserve = num_pins * maps_per_pin ;
err = pinctrl_utils_reserve_map ( pctldev , map ,
reserved_maps , num_maps , reserve ) ;
if ( err )
return err ;
for ( i = 0 ; i < num_pins ; i + + ) {
err = of_property_read_u32_index ( node , " pinmux " ,
i , & pinfunc ) ;
if ( err )
return err ;
pin = STM32_GET_PIN_NO ( pinfunc ) ;
func = STM32_GET_PIN_FUNC ( pinfunc ) ;
if ( ! stm32_pctrl_is_function_valid ( pctl , pin , func ) ) {
dev_err ( pctl - > dev , " invalid function. \n " ) ;
return - EINVAL ;
}
grp = stm32_pctrl_find_group_by_pin ( pctl , pin ) ;
if ( ! grp ) {
dev_err ( pctl - > dev , " unable to match pin %d to group \n " ,
pin ) ;
return - EINVAL ;
}
err = stm32_pctrl_dt_node_to_map_func ( pctl , pin , func , grp , map ,
reserved_maps , num_maps ) ;
if ( err )
return err ;
if ( has_config ) {
err = pinctrl_utils_add_map_configs ( pctldev , map ,
reserved_maps , num_maps , grp - > name ,
configs , num_configs ,
PIN_MAP_TYPE_CONFIGS_GROUP ) ;
if ( err )
return err ;
}
}
return 0 ;
}
static int stm32_pctrl_dt_node_to_map ( struct pinctrl_dev * pctldev ,
struct device_node * np_config ,
struct pinctrl_map * * map , unsigned * num_maps )
{
struct device_node * np ;
unsigned reserved_maps ;
int ret ;
* map = NULL ;
* num_maps = 0 ;
reserved_maps = 0 ;
for_each_child_of_node ( np_config , np ) {
ret = stm32_pctrl_dt_subnode_to_map ( pctldev , np , map ,
& reserved_maps , num_maps ) ;
if ( ret < 0 ) {
2016-03-31 14:44:42 +03:00
pinctrl_utils_free_map ( pctldev , * map , * num_maps ) ;
2016-01-14 15:16:30 +03:00
return ret ;
}
}
return 0 ;
}
static int stm32_pctrl_get_groups_count ( struct pinctrl_dev * pctldev )
{
struct stm32_pinctrl * pctl = pinctrl_dev_get_drvdata ( pctldev ) ;
return pctl - > ngroups ;
}
static const char * stm32_pctrl_get_group_name ( struct pinctrl_dev * pctldev ,
unsigned group )
{
struct stm32_pinctrl * pctl = pinctrl_dev_get_drvdata ( pctldev ) ;
return pctl - > groups [ group ] . name ;
}
static int stm32_pctrl_get_group_pins ( struct pinctrl_dev * pctldev ,
unsigned group ,
const unsigned * * pins ,
unsigned * num_pins )
{
struct stm32_pinctrl * pctl = pinctrl_dev_get_drvdata ( pctldev ) ;
* pins = ( unsigned * ) & pctl - > groups [ group ] . pin ;
* num_pins = 1 ;
return 0 ;
}
static const struct pinctrl_ops stm32_pctrl_ops = {
. dt_node_to_map = stm32_pctrl_dt_node_to_map ,
2016-03-31 14:44:42 +03:00
. dt_free_map = pinctrl_utils_free_map ,
2016-01-14 15:16:30 +03:00
. get_groups_count = stm32_pctrl_get_groups_count ,
. get_group_name = stm32_pctrl_get_group_name ,
. get_group_pins = stm32_pctrl_get_group_pins ,
} ;
/* Pinmux functions */
static int stm32_pmx_get_funcs_cnt ( struct pinctrl_dev * pctldev )
{
return ARRAY_SIZE ( stm32_gpio_functions ) ;
}
static const char * stm32_pmx_get_func_name ( struct pinctrl_dev * pctldev ,
unsigned selector )
{
return stm32_gpio_functions [ selector ] ;
}
static int stm32_pmx_get_func_groups ( struct pinctrl_dev * pctldev ,
unsigned function ,
const char * const * * groups ,
unsigned * const num_groups )
{
struct stm32_pinctrl * pctl = pinctrl_dev_get_drvdata ( pctldev ) ;
* groups = pctl - > grp_names ;
* num_groups = pctl - > ngroups ;
return 0 ;
}
static void stm32_pmx_set_mode ( struct stm32_gpio_bank * bank ,
int pin , u32 mode , u32 alt )
{
u32 val ;
int alt_shift = ( pin % 8 ) * 4 ;
int alt_offset = STM32_GPIO_AFRL + ( pin / 8 ) * 4 ;
unsigned long flags ;
clk_enable ( bank - > clk ) ;
spin_lock_irqsave ( & bank - > lock , flags ) ;
val = readl_relaxed ( bank - > base + alt_offset ) ;
val & = ~ GENMASK ( alt_shift + 3 , alt_shift ) ;
val | = ( alt < < alt_shift ) ;
writel_relaxed ( val , bank - > base + alt_offset ) ;
val = readl_relaxed ( bank - > base + STM32_GPIO_MODER ) ;
val & = ~ GENMASK ( pin * 2 + 1 , pin * 2 ) ;
val | = mode < < ( pin * 2 ) ;
writel_relaxed ( val , bank - > base + STM32_GPIO_MODER ) ;
spin_unlock_irqrestore ( & bank - > lock , flags ) ;
clk_disable ( bank - > clk ) ;
}
2017-05-29 19:17:32 +03:00
void stm32_pmx_get_mode ( struct stm32_gpio_bank * bank , int pin , u32 * mode ,
u32 * alt )
2016-04-29 17:25:43 +03:00
{
u32 val ;
int alt_shift = ( pin % 8 ) * 4 ;
int alt_offset = STM32_GPIO_AFRL + ( pin / 8 ) * 4 ;
unsigned long flags ;
clk_enable ( bank - > clk ) ;
spin_lock_irqsave ( & bank - > lock , flags ) ;
val = readl_relaxed ( bank - > base + alt_offset ) ;
val & = GENMASK ( alt_shift + 3 , alt_shift ) ;
* alt = val > > alt_shift ;
val = readl_relaxed ( bank - > base + STM32_GPIO_MODER ) ;
val & = GENMASK ( pin * 2 + 1 , pin * 2 ) ;
* mode = val > > ( pin * 2 ) ;
spin_unlock_irqrestore ( & bank - > lock , flags ) ;
clk_disable ( bank - > clk ) ;
}
2016-01-14 15:16:30 +03:00
static int stm32_pmx_set_mux ( struct pinctrl_dev * pctldev ,
unsigned function ,
unsigned group )
{
bool ret ;
struct stm32_pinctrl * pctl = pinctrl_dev_get_drvdata ( pctldev ) ;
struct stm32_pinctrl_group * g = pctl - > groups + group ;
struct pinctrl_gpio_range * range ;
struct stm32_gpio_bank * bank ;
u32 mode , alt ;
int pin ;
ret = stm32_pctrl_is_function_valid ( pctl , g - > pin , function ) ;
if ( ! ret ) {
dev_err ( pctl - > dev , " invalid function %d on group %d . \n " ,
function , group ) ;
return - EINVAL ;
}
range = pinctrl_find_gpio_range_from_pin ( pctldev , g - > pin ) ;
2017-04-07 15:42:58 +03:00
bank = gpiochip_get_data ( range - > gc ) ;
2016-01-14 15:16:30 +03:00
pin = stm32_gpio_pin ( g - > pin ) ;
mode = stm32_gpio_get_mode ( function ) ;
alt = stm32_gpio_get_alt ( function ) ;
stm32_pmx_set_mode ( bank , pin , mode , alt ) ;
return 0 ;
}
static int stm32_pmx_gpio_set_direction ( struct pinctrl_dev * pctldev ,
struct pinctrl_gpio_range * range , unsigned gpio ,
bool input )
{
2017-04-07 15:42:58 +03:00
struct stm32_gpio_bank * bank = gpiochip_get_data ( range - > gc ) ;
2016-01-14 15:16:30 +03:00
int pin = stm32_gpio_pin ( gpio ) ;
stm32_pmx_set_mode ( bank , pin , ! input , 0 ) ;
return 0 ;
}
static const struct pinmux_ops stm32_pmx_ops = {
. get_functions_count = stm32_pmx_get_funcs_cnt ,
. get_function_name = stm32_pmx_get_func_name ,
. get_function_groups = stm32_pmx_get_func_groups ,
. set_mux = stm32_pmx_set_mux ,
. gpio_set_direction = stm32_pmx_gpio_set_direction ,
2016-12-14 17:24:16 +03:00
. strict = true ,
2016-01-14 15:16:30 +03:00
} ;
/* Pinconf functions */
static void stm32_pconf_set_driving ( struct stm32_gpio_bank * bank ,
unsigned offset , u32 drive )
{
unsigned long flags ;
u32 val ;
clk_enable ( bank - > clk ) ;
spin_lock_irqsave ( & bank - > lock , flags ) ;
val = readl_relaxed ( bank - > base + STM32_GPIO_TYPER ) ;
val & = ~ BIT ( offset ) ;
val | = drive < < offset ;
writel_relaxed ( val , bank - > base + STM32_GPIO_TYPER ) ;
spin_unlock_irqrestore ( & bank - > lock , flags ) ;
clk_disable ( bank - > clk ) ;
}
2016-04-29 17:25:43 +03:00
static u32 stm32_pconf_get_driving ( struct stm32_gpio_bank * bank ,
unsigned int offset )
{
unsigned long flags ;
u32 val ;
clk_enable ( bank - > clk ) ;
spin_lock_irqsave ( & bank - > lock , flags ) ;
val = readl_relaxed ( bank - > base + STM32_GPIO_TYPER ) ;
val & = BIT ( offset ) ;
spin_unlock_irqrestore ( & bank - > lock , flags ) ;
clk_disable ( bank - > clk ) ;
return ( val > > offset ) ;
}
2016-01-14 15:16:30 +03:00
static void stm32_pconf_set_speed ( struct stm32_gpio_bank * bank ,
unsigned offset , u32 speed )
{
unsigned long flags ;
u32 val ;
clk_enable ( bank - > clk ) ;
spin_lock_irqsave ( & bank - > lock , flags ) ;
val = readl_relaxed ( bank - > base + STM32_GPIO_SPEEDR ) ;
val & = ~ GENMASK ( offset * 2 + 1 , offset * 2 ) ;
val | = speed < < ( offset * 2 ) ;
writel_relaxed ( val , bank - > base + STM32_GPIO_SPEEDR ) ;
spin_unlock_irqrestore ( & bank - > lock , flags ) ;
clk_disable ( bank - > clk ) ;
}
2016-04-29 17:25:43 +03:00
static u32 stm32_pconf_get_speed ( struct stm32_gpio_bank * bank ,
unsigned int offset )
{
unsigned long flags ;
u32 val ;
clk_enable ( bank - > clk ) ;
spin_lock_irqsave ( & bank - > lock , flags ) ;
val = readl_relaxed ( bank - > base + STM32_GPIO_SPEEDR ) ;
val & = GENMASK ( offset * 2 + 1 , offset * 2 ) ;
spin_unlock_irqrestore ( & bank - > lock , flags ) ;
clk_disable ( bank - > clk ) ;
return ( val > > ( offset * 2 ) ) ;
}
2016-01-14 15:16:30 +03:00
static void stm32_pconf_set_bias ( struct stm32_gpio_bank * bank ,
unsigned offset , u32 bias )
{
unsigned long flags ;
u32 val ;
clk_enable ( bank - > clk ) ;
spin_lock_irqsave ( & bank - > lock , flags ) ;
val = readl_relaxed ( bank - > base + STM32_GPIO_PUPDR ) ;
val & = ~ GENMASK ( offset * 2 + 1 , offset * 2 ) ;
val | = bias < < ( offset * 2 ) ;
writel_relaxed ( val , bank - > base + STM32_GPIO_PUPDR ) ;
spin_unlock_irqrestore ( & bank - > lock , flags ) ;
clk_disable ( bank - > clk ) ;
}
2016-04-29 17:25:43 +03:00
static u32 stm32_pconf_get_bias ( struct stm32_gpio_bank * bank ,
unsigned int offset )
{
unsigned long flags ;
u32 val ;
clk_enable ( bank - > clk ) ;
spin_lock_irqsave ( & bank - > lock , flags ) ;
val = readl_relaxed ( bank - > base + STM32_GPIO_PUPDR ) ;
val & = GENMASK ( offset * 2 + 1 , offset * 2 ) ;
spin_unlock_irqrestore ( & bank - > lock , flags ) ;
clk_disable ( bank - > clk ) ;
return ( val > > ( offset * 2 ) ) ;
}
2016-05-24 14:57:43 +03:00
static bool stm32_pconf_get ( struct stm32_gpio_bank * bank ,
unsigned int offset , bool dir )
2016-04-29 17:25:43 +03:00
{
unsigned long flags ;
u32 val ;
clk_enable ( bank - > clk ) ;
spin_lock_irqsave ( & bank - > lock , flags ) ;
2016-05-24 14:57:43 +03:00
if ( dir )
val = ! ! ( readl_relaxed ( bank - > base + STM32_GPIO_IDR ) &
BIT ( offset ) ) ;
else
val = ! ! ( readl_relaxed ( bank - > base + STM32_GPIO_ODR ) &
BIT ( offset ) ) ;
2016-04-29 17:25:43 +03:00
spin_unlock_irqrestore ( & bank - > lock , flags ) ;
clk_disable ( bank - > clk ) ;
return val ;
}
2016-01-14 15:16:30 +03:00
static int stm32_pconf_parse_conf ( struct pinctrl_dev * pctldev ,
unsigned int pin , enum pin_config_param param ,
enum pin_config_param arg )
{
struct pinctrl_gpio_range * range ;
struct stm32_gpio_bank * bank ;
int offset , ret = 0 ;
range = pinctrl_find_gpio_range_from_pin ( pctldev , pin ) ;
2017-04-07 15:42:58 +03:00
bank = gpiochip_get_data ( range - > gc ) ;
2016-01-14 15:16:30 +03:00
offset = stm32_gpio_pin ( pin ) ;
switch ( param ) {
case PIN_CONFIG_DRIVE_PUSH_PULL :
stm32_pconf_set_driving ( bank , offset , 0 ) ;
break ;
case PIN_CONFIG_DRIVE_OPEN_DRAIN :
stm32_pconf_set_driving ( bank , offset , 1 ) ;
break ;
case PIN_CONFIG_SLEW_RATE :
stm32_pconf_set_speed ( bank , offset , arg ) ;
break ;
case PIN_CONFIG_BIAS_DISABLE :
stm32_pconf_set_bias ( bank , offset , 0 ) ;
break ;
case PIN_CONFIG_BIAS_PULL_UP :
stm32_pconf_set_bias ( bank , offset , 1 ) ;
break ;
case PIN_CONFIG_BIAS_PULL_DOWN :
stm32_pconf_set_bias ( bank , offset , 2 ) ;
break ;
case PIN_CONFIG_OUTPUT :
__stm32_gpio_set ( bank , offset , arg ) ;
2017-05-30 17:43:04 +03:00
ret = stm32_pmx_gpio_set_direction ( pctldev , range , pin , false ) ;
2016-01-14 15:16:30 +03:00
break ;
default :
ret = - EINVAL ;
}
return ret ;
}
static int stm32_pconf_group_get ( struct pinctrl_dev * pctldev ,
unsigned group ,
unsigned long * config )
{
struct stm32_pinctrl * pctl = pinctrl_dev_get_drvdata ( pctldev ) ;
* config = pctl - > groups [ group ] . config ;
return 0 ;
}
static int stm32_pconf_group_set ( struct pinctrl_dev * pctldev , unsigned group ,
unsigned long * configs , unsigned num_configs )
{
struct stm32_pinctrl * pctl = pinctrl_dev_get_drvdata ( pctldev ) ;
struct stm32_pinctrl_group * g = & pctl - > groups [ group ] ;
int i , ret ;
for ( i = 0 ; i < num_configs ; i + + ) {
ret = stm32_pconf_parse_conf ( pctldev , g - > pin ,
pinconf_to_config_param ( configs [ i ] ) ,
pinconf_to_config_argument ( configs [ i ] ) ) ;
if ( ret < 0 )
return ret ;
g - > config = configs [ i ] ;
}
return 0 ;
}
2016-04-29 17:25:43 +03:00
static void stm32_pconf_dbg_show ( struct pinctrl_dev * pctldev ,
struct seq_file * s ,
unsigned int pin )
{
struct pinctrl_gpio_range * range ;
struct stm32_gpio_bank * bank ;
int offset ;
u32 mode , alt , drive , speed , bias ;
static const char * const modes [ ] = {
" input " , " output " , " alternate " , " analog " } ;
static const char * const speeds [ ] = {
" low " , " medium " , " high " , " very high " } ;
static const char * const biasing [ ] = {
" floating " , " pull up " , " pull down " , " " } ;
bool val ;
range = pinctrl_find_gpio_range_from_pin_nolock ( pctldev , pin ) ;
2017-04-07 15:42:58 +03:00
bank = gpiochip_get_data ( range - > gc ) ;
2016-04-29 17:25:43 +03:00
offset = stm32_gpio_pin ( pin ) ;
stm32_pmx_get_mode ( bank , offset , & mode , & alt ) ;
bias = stm32_pconf_get_bias ( bank , offset ) ;
seq_printf ( s , " %s " , modes [ mode ] ) ;
switch ( mode ) {
/* input */
case 0 :
2016-05-24 14:57:43 +03:00
val = stm32_pconf_get ( bank , offset , true ) ;
2016-04-29 17:25:43 +03:00
seq_printf ( s , " - %s - %s " ,
val ? " high " : " low " ,
biasing [ bias ] ) ;
break ;
/* output */
case 1 :
drive = stm32_pconf_get_driving ( bank , offset ) ;
speed = stm32_pconf_get_speed ( bank , offset ) ;
2016-05-24 14:57:43 +03:00
val = stm32_pconf_get ( bank , offset , false ) ;
2016-04-29 17:25:43 +03:00
seq_printf ( s , " - %s - %s - %s - %s %s " ,
val ? " high " : " low " ,
drive ? " open drain " : " push pull " ,
biasing [ bias ] ,
speeds [ speed ] , " speed " ) ;
break ;
/* alternate */
case 2 :
drive = stm32_pconf_get_driving ( bank , offset ) ;
speed = stm32_pconf_get_speed ( bank , offset ) ;
Pin control bulk changes for the v4.7 kernel cycle:
Core changes:
- Add the devm_pinctrl_register() API and switch all applicable drivers
to use it, saving lots of lines of code all over the place.
New drivers:
- New driver for the Broadcom NS2 SoC.
- New subdriver for the PXA25x SoCs.
- New subdriver for the AMLogic Meson GXBB SoC.
Driver improvements:
- The Intel Baytrail driver now properly supports pin control.
- The Nomadik, Rockchip, Broadcom BCM2835 supports the .get_direction() callback in
the GPIO portions.
- Continued development and stabilization of several SH-PFC
SoC subdrivers: r8a7795, r8a7790, r8a7794 etc.
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1
iQIcBAABAgAGBQJXPZ9PAAoJEEEQszewGV1zboIQALtGX/tyKFzaOsj7WxHHjmfb
yufqU62NE0sPT6/hzUY3a1U9dpakbMehBXy0go0vcShmPSznX2glFv4GR6LEeE0+
o0JNv0d13f2s5WPEqn6L/ePuSuNNjfkwjZ7YJlAXx/WqAWI9c70H8/VHsXEObWOe
ZsAZx2FdUFDOxugDWsCmU6kt7RXbqTzEz2M/dDANr4B2cRH/3yny797P2y9tLy3w
Rqsdqw1C1A9SICSIRZ+YBWctXhRq5APsB75IncUYIQJF5hXoAcBCp6v+cNZHpXOw
X9J+zKDeMjOSsVvOyHA+4P+vPYgkOPl9GuUVJRvnbfCZYKEhDM1e5F393Cf7gYYz
dIEAzIFlPmZCMxog7AWEA0yDp2rJ2W/5WoN7pg+a5cKSHgriIry1sxDslBD2b9ZW
XxdVm4pMOiVw6yokHI4g2hcDsZOEW8zhPQi1wPuVuJ3k1m7T/d13mFAFTSWwOLVx
WFDLuD20ybkCVmxEs0ePrDzLcgEnxW40src6lqSzIx8bUBCH+iWPkIPH0fAJ6bNK
TFtfcCFrtE2YmpxrCgZceTLER/7jAGkXFegbJq1epNmz7+0wbEbRxcVFE1IbYUBW
ejslgTtLDvnzzkR7UISZF/Qna066tCGT52sEA82ZcrqytGkSTLB4kUDkQvXaCB0r
4DLJ47K32mQu3MrOPLjE
=tlvn
-----END PGP SIGNATURE-----
Merge tag 'pinctrl-v4.7-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-pinctrl
Pull pin control updates from Linus Walleij:
"This kernel cycle was quite calm when it comes to pin control and
there is really just one major change, and that is the introduction of
devm_pinctrl_register() managed resources.
Apart from that linear development, details below.
Core changes:
- Add the devm_pinctrl_register() API and switch all applicable
drivers to use it, saving lots of lines of code all over the place.
New drivers:
- driver for the Broadcom NS2 SoC
- subdriver for the PXA25x SoCs
- subdriver for the AMLogic Meson GXBB SoC
Driver improvements:
- the Intel Baytrail driver now properly supports pin control
- Nomadik, Rockchip, Broadcom BCM2835 support the .get_direction()
callback in the GPIO portions
- continued development and stabilization of several SH-PFC SoC
subdrivers: r8a7795, r8a7790, r8a7794 etc"
* tag 'pinctrl-v4.7-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-pinctrl: (85 commits)
Revert "pinctrl: tegra: avoid parked_reg and parked_bank"
pinctrl: meson: Fix eth_tx_en bit index
pinctrl: tegra: avoid parked_reg and parked_bank
pinctrl: tegra: Correctly check the supported configuration
pinctrl: amlogic: Add support for Amlogic Meson GXBB SoC
pinctrl: rockchip: fix pull setting error for rk3399
pinctrl: stm32: Implement .pin_config_dbg_show()
pinctrl: nomadik: hide nmk_gpio_get_mode when unused
pinctrl: ns2: rename pinctrl_utils_dt_free_map
pinctrl: at91: Merge clk_prepare and clk_enable into clk_prepare_enable
pinctrl: at91: Make at91_gpio_template const
pinctrl: baytrail: fix some error handling in debugfs
pinctrl: ns2: add pinmux driver support for Broadcom NS2 SoC
pinctrl: sirf/atlas7: trivial fix of spelling mistake on flagged
pinctrl: sh-pfc: Kill unused variable in sh_pfc_remove()
pinctrl: nomadik: implement .get_direction()
pinctrl: nomadik: use BIT() with offsets consequently
pinctrl: exynos5440: Use off-stack memory for pinctrl_gpio_range
pinctrl: zynq: Use devm_pinctrl_register() for pinctrl registration
pinctrl: u300: Use devm_pinctrl_register() for pinctrl registration
...
2016-05-19 22:50:56 +03:00
seq_printf ( s , " %d - %s - %s - %s %s " , alt ,
2016-04-29 17:25:43 +03:00
drive ? " open drain " : " push pull " ,
biasing [ bias ] ,
speeds [ speed ] , " speed " ) ;
break ;
/* analog */
case 3 :
break ;
}
}
2016-01-14 15:16:30 +03:00
static const struct pinconf_ops stm32_pconf_ops = {
. pin_config_group_get = stm32_pconf_group_get ,
. pin_config_group_set = stm32_pconf_group_set ,
2016-04-29 17:25:43 +03:00
. pin_config_dbg_show = stm32_pconf_dbg_show ,
2016-01-14 15:16:30 +03:00
} ;
static int stm32_gpiolib_register_bank ( struct stm32_pinctrl * pctl ,
struct device_node * np )
{
2017-04-07 15:42:58 +03:00
struct stm32_gpio_bank * bank = & pctl - > banks [ pctl - > nbanks ] ;
2016-01-14 15:16:30 +03:00
struct pinctrl_gpio_range * range = & bank - > range ;
2017-04-07 15:42:58 +03:00
struct of_phandle_args args ;
2016-01-14 15:16:30 +03:00
struct device * dev = pctl - > dev ;
struct resource res ;
struct reset_control * rstc ;
2017-04-07 15:42:58 +03:00
int npins = STM32_GPIO_PINS_PER_BANK ;
int bank_nr , err ;
2016-01-14 15:16:30 +03:00
2017-07-19 18:26:10 +03:00
rstc = of_reset_control_get_exclusive ( np , NULL ) ;
2016-01-14 15:16:30 +03:00
if ( ! IS_ERR ( rstc ) )
reset_control_deassert ( rstc ) ;
if ( of_address_to_resource ( np , 0 , & res ) )
return - ENODEV ;
bank - > base = devm_ioremap_resource ( dev , & res ) ;
if ( IS_ERR ( bank - > base ) )
return PTR_ERR ( bank - > base ) ;
bank - > clk = of_clk_get_by_name ( np , NULL ) ;
if ( IS_ERR ( bank - > clk ) ) {
dev_err ( dev , " failed to get clk (%ld) \n " , PTR_ERR ( bank - > clk ) ) ;
return PTR_ERR ( bank - > clk ) ;
}
err = clk_prepare ( bank - > clk ) ;
if ( err ) {
dev_err ( dev , " failed to prepare clk (%d) \n " , err ) ;
return err ;
}
bank - > gpio_chip = stm32_gpio_template ;
2017-04-07 15:42:58 +03:00
of_property_read_string ( np , " st,bank-name " , & bank - > gpio_chip . label ) ;
if ( ! of_parse_phandle_with_fixed_args ( np , " gpio-ranges " , 3 , 0 , & args ) ) {
bank_nr = args . args [ 1 ] / STM32_GPIO_PINS_PER_BANK ;
bank - > gpio_chip . base = args . args [ 1 ] ;
} else {
bank_nr = pctl - > nbanks ;
bank - > gpio_chip . base = bank_nr * STM32_GPIO_PINS_PER_BANK ;
range - > name = bank - > gpio_chip . label ;
range - > id = bank_nr ;
range - > pin_base = range - > id * STM32_GPIO_PINS_PER_BANK ;
range - > base = range - > id * STM32_GPIO_PINS_PER_BANK ;
range - > npins = npins ;
range - > gc = & bank - > gpio_chip ;
pinctrl_add_gpio_range ( pctl - > pctl_dev ,
& pctl - > banks [ bank_nr ] . range ) ;
}
2016-01-14 15:16:30 +03:00
bank - > gpio_chip . base = bank_nr * STM32_GPIO_PINS_PER_BANK ;
2017-04-07 15:42:58 +03:00
2016-01-14 15:16:30 +03:00
bank - > gpio_chip . ngpio = npins ;
bank - > gpio_chip . of_node = np ;
2016-02-06 01:47:13 +03:00
bank - > gpio_chip . parent = dev ;
2017-04-07 15:42:58 +03:00
bank - > bank_nr = bank_nr ;
2016-01-14 15:16:30 +03:00
spin_lock_init ( & bank - > lock ) ;
2016-09-09 17:42:01 +03:00
/* create irq hierarchical domain */
bank - > fwnode = of_node_to_fwnode ( np ) ;
bank - > domain = irq_domain_create_hierarchy ( pctl - > domain , 0 ,
STM32_GPIO_IRQ_LINE , bank - > fwnode ,
& stm32_gpio_domain_ops , bank ) ;
if ( ! bank - > domain )
return - ENODEV ;
2016-02-06 01:47:13 +03:00
err = gpiochip_add_data ( & bank - > gpio_chip , bank ) ;
2016-01-14 15:16:30 +03:00
if ( err ) {
dev_err ( dev , " Failed to add gpiochip(%d)! \n " , bank_nr ) ;
return err ;
}
2017-04-07 15:42:58 +03:00
dev_info ( dev , " %s bank added \n " , bank - > gpio_chip . label ) ;
2016-01-14 15:16:30 +03:00
return 0 ;
}
2016-09-09 17:42:01 +03:00
static int stm32_pctrl_dt_setup_irq ( struct platform_device * pdev ,
struct stm32_pinctrl * pctl )
{
struct device_node * np = pdev - > dev . of_node , * parent ;
struct device * dev = & pdev - > dev ;
struct regmap * rm ;
int offset , ret , i ;
parent = of_irq_find_parent ( np ) ;
if ( ! parent )
return - ENXIO ;
pctl - > domain = irq_find_host ( parent ) ;
if ( ! pctl - > domain )
return - ENXIO ;
pctl - > regmap = syscon_regmap_lookup_by_phandle ( np , " st,syscfg " ) ;
if ( IS_ERR ( pctl - > regmap ) )
return PTR_ERR ( pctl - > regmap ) ;
rm = pctl - > regmap ;
ret = of_property_read_u32_index ( np , " st,syscfg " , 1 , & offset ) ;
if ( ret )
return ret ;
for ( i = 0 ; i < STM32_GPIO_PINS_PER_BANK ; i + + ) {
struct reg_field mux ;
mux . reg = offset + ( i / 4 ) * 4 ;
mux . lsb = ( i % 4 ) * 4 ;
mux . msb = mux . lsb + 3 ;
pctl - > irqmux [ i ] = devm_regmap_field_alloc ( dev , rm , mux ) ;
if ( IS_ERR ( pctl - > irqmux [ i ] ) )
return PTR_ERR ( pctl - > irqmux [ i ] ) ;
}
return 0 ;
}
2016-01-14 15:16:30 +03:00
static int stm32_pctrl_build_state ( struct platform_device * pdev )
{
struct stm32_pinctrl * pctl = platform_get_drvdata ( pdev ) ;
int i ;
pctl - > ngroups = pctl - > match_data - > npins ;
/* Allocate groups */
pctl - > groups = devm_kcalloc ( & pdev - > dev , pctl - > ngroups ,
sizeof ( * pctl - > groups ) , GFP_KERNEL ) ;
if ( ! pctl - > groups )
return - ENOMEM ;
/* We assume that one pin is one group, use pin name as group name. */
pctl - > grp_names = devm_kcalloc ( & pdev - > dev , pctl - > ngroups ,
sizeof ( * pctl - > grp_names ) , GFP_KERNEL ) ;
if ( ! pctl - > grp_names )
return - ENOMEM ;
for ( i = 0 ; i < pctl - > match_data - > npins ; i + + ) {
const struct stm32_desc_pin * pin = pctl - > match_data - > pins + i ;
struct stm32_pinctrl_group * group = pctl - > groups + i ;
group - > name = pin - > pin . name ;
group - > pin = pin - > pin . number ;
pctl - > grp_names [ i ] = pin - > pin . name ;
}
return 0 ;
}
int stm32_pctl_probe ( struct platform_device * pdev )
{
struct device_node * np = pdev - > dev . of_node ;
struct device_node * child ;
const struct of_device_id * match ;
struct device * dev = & pdev - > dev ;
struct stm32_pinctrl * pctl ;
struct pinctrl_pin_desc * pins ;
int i , ret , banks = 0 ;
if ( ! np )
return - EINVAL ;
match = of_match_device ( dev - > driver - > of_match_table , dev ) ;
if ( ! match | | ! match - > data )
return - EINVAL ;
if ( ! of_find_property ( np , " pins-are-numbered " , NULL ) ) {
dev_err ( dev , " only support pins-are-numbered format \n " ) ;
return - EINVAL ;
}
pctl = devm_kzalloc ( dev , sizeof ( * pctl ) , GFP_KERNEL ) ;
if ( ! pctl )
return - ENOMEM ;
platform_set_drvdata ( pdev , pctl ) ;
pctl - > dev = dev ;
pctl - > match_data = match - > data ;
ret = stm32_pctrl_build_state ( pdev ) ;
if ( ret ) {
dev_err ( dev , " build state failed: %d \n " , ret ) ;
return - EINVAL ;
}
2016-10-20 16:26:51 +03:00
if ( of_find_property ( np , " interrupt-parent " , NULL ) ) {
ret = stm32_pctrl_dt_setup_irq ( pdev , pctl ) ;
if ( ret )
return ret ;
}
2016-09-09 17:42:01 +03:00
2016-01-14 15:16:30 +03:00
pins = devm_kcalloc ( & pdev - > dev , pctl - > match_data - > npins , sizeof ( * pins ) ,
GFP_KERNEL ) ;
if ( ! pins )
return - ENOMEM ;
for ( i = 0 ; i < pctl - > match_data - > npins ; i + + )
pins [ i ] = pctl - > match_data - > pins [ i ] . pin ;
pctl - > pctl_desc . name = dev_name ( & pdev - > dev ) ;
pctl - > pctl_desc . owner = THIS_MODULE ;
pctl - > pctl_desc . pins = pins ;
pctl - > pctl_desc . npins = pctl - > match_data - > npins ;
pctl - > pctl_desc . confops = & stm32_pconf_ops ;
pctl - > pctl_desc . pctlops = & stm32_pctrl_ops ;
pctl - > pctl_desc . pmxops = & stm32_pmx_ops ;
pctl - > dev = & pdev - > dev ;
2016-02-24 12:14:07 +03:00
pctl - > pctl_dev = devm_pinctrl_register ( & pdev - > dev , & pctl - > pctl_desc ,
pctl ) ;
2017-04-07 15:42:58 +03:00
2016-02-24 12:14:07 +03:00
if ( IS_ERR ( pctl - > pctl_dev ) ) {
2016-01-14 15:16:30 +03:00
dev_err ( & pdev - > dev , " Failed pinctrl registration \n " ) ;
2016-02-24 12:14:07 +03:00
return PTR_ERR ( pctl - > pctl_dev ) ;
2016-01-14 15:16:30 +03:00
}
2017-04-07 15:42:58 +03:00
for_each_child_of_node ( np , child )
if ( of_property_read_bool ( child , " gpio-controller " ) )
banks + + ;
if ( ! banks ) {
dev_err ( dev , " at least one GPIO bank is required \n " ) ;
return - EINVAL ;
}
pctl - > banks = devm_kcalloc ( dev , banks , sizeof ( * pctl - > banks ) ,
GFP_KERNEL ) ;
if ( ! pctl - > banks )
return - ENOMEM ;
for_each_child_of_node ( np , child ) {
if ( of_property_read_bool ( child , " gpio-controller " ) ) {
ret = stm32_gpiolib_register_bank ( pctl , child ) ;
if ( ret )
return ret ;
pctl - > nbanks + + ;
}
}
2016-01-14 15:16:30 +03:00
dev_info ( dev , " Pinctrl STM32 initialized \n " ) ;
return 0 ;
}