2012-08-28 14:44:59 +04:00
/*
* linux / drivers / pinctrl / pinctrl - lantiq . c
* based on linux / drivers / pinctrl / pinctrl - pxa3xx . c
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2 as
* publishhed by the Free Software Foundation .
*
2016-12-20 21:55:41 +03:00
* Copyright ( C ) 2012 John Crispin < john @ phrozen . org >
2012-08-28 14:44:59 +04:00
*/
# include <linux/module.h>
# include <linux/device.h>
# include <linux/io.h>
# include <linux/platform_device.h>
# include <linux/slab.h>
# include <linux/of.h>
# include "pinctrl-lantiq.h"
static int ltq_get_group_count ( struct pinctrl_dev * pctrldev )
{
struct ltq_pinmux_info * info = pinctrl_dev_get_drvdata ( pctrldev ) ;
return info - > num_grps ;
}
static const char * ltq_get_group_name ( struct pinctrl_dev * pctrldev ,
unsigned selector )
{
struct ltq_pinmux_info * info = pinctrl_dev_get_drvdata ( pctrldev ) ;
if ( selector > = info - > num_grps )
return NULL ;
return info - > grps [ selector ] . name ;
}
static int ltq_get_group_pins ( struct pinctrl_dev * pctrldev ,
unsigned selector ,
const unsigned * * pins ,
unsigned * num_pins )
{
struct ltq_pinmux_info * info = pinctrl_dev_get_drvdata ( pctrldev ) ;
if ( selector > = info - > num_grps )
return - EINVAL ;
* pins = info - > grps [ selector ] . pins ;
* num_pins = info - > grps [ selector ] . npins ;
return 0 ;
}
2012-11-07 20:10:17 +04:00
static void ltq_pinctrl_dt_free_map ( struct pinctrl_dev * pctldev ,
struct pinctrl_map * map , unsigned num_maps )
2012-08-28 14:44:59 +04:00
{
int i ;
for ( i = 0 ; i < num_maps ; i + + )
2013-05-14 19:00:38 +04:00
if ( map [ i ] . type = = PIN_MAP_TYPE_CONFIGS_PIN | |
map [ i ] . type = = PIN_MAP_TYPE_CONFIGS_GROUP )
2012-08-28 14:44:59 +04:00
kfree ( map [ i ] . data . configs . configs ) ;
kfree ( map ) ;
}
static void ltq_pinctrl_pin_dbg_show ( struct pinctrl_dev * pctldev ,
struct seq_file * s ,
unsigned offset )
{
seq_printf ( s , " %s " , dev_name ( pctldev - > dev ) ) ;
}
2013-02-01 16:04:57 +04:00
static void ltq_pinctrl_dt_subnode_to_map ( struct pinctrl_dev * pctldev ,
2012-08-28 14:44:59 +04:00
struct device_node * np ,
struct pinctrl_map * * map )
{
struct ltq_pinmux_info * info = pinctrl_dev_get_drvdata ( pctldev ) ;
2013-02-01 16:04:57 +04:00
struct property * pins = of_find_property ( np , " lantiq,pins " , NULL ) ;
struct property * groups = of_find_property ( np , " lantiq,groups " , NULL ) ;
2012-08-28 14:44:59 +04:00
unsigned long configs [ 3 ] ;
unsigned num_configs = 0 ;
struct property * prop ;
const char * group , * pin ;
const char * function ;
int ret , i ;
2013-02-01 16:04:57 +04:00
if ( ! pins & & ! groups ) {
dev_err ( pctldev - > dev , " %s defines neither pins nor groups \n " ,
np - > name ) ;
return ;
}
if ( pins & & groups ) {
dev_err ( pctldev - > dev , " %s defines both pins and groups \n " ,
np - > name ) ;
return ;
}
2012-08-28 14:44:59 +04:00
ret = of_property_read_string ( np , " lantiq,function " , & function ) ;
2013-02-01 16:04:57 +04:00
if ( groups & & ! ret ) {
2012-08-28 14:44:59 +04:00
of_property_for_each_string ( np , " lantiq,groups " , prop , group ) {
( * map ) - > type = PIN_MAP_TYPE_MUX_GROUP ;
( * map ) - > name = function ;
( * map ) - > data . mux . group = group ;
( * map ) - > data . mux . function = function ;
( * map ) + + ;
}
}
for ( i = 0 ; i < info - > num_params ; i + + ) {
u32 val ;
int ret = of_property_read_u32 ( np ,
info - > params [ i ] . property , & val ) ;
if ( ! ret )
configs [ num_configs + + ] =
LTQ_PINCONF_PACK ( info - > params [ i ] . param ,
val ) ;
}
if ( ! num_configs )
2013-02-01 16:04:57 +04:00
return ;
2012-08-28 14:44:59 +04:00
of_property_for_each_string ( np , " lantiq,pins " , prop , pin ) {
( * map ) - > data . configs . configs = kmemdup ( configs ,
num_configs * sizeof ( unsigned long ) ,
GFP_KERNEL ) ;
( * map ) - > type = PIN_MAP_TYPE_CONFIGS_PIN ;
( * map ) - > name = pin ;
( * map ) - > data . configs . group_or_pin = pin ;
( * map ) - > data . configs . num_configs = num_configs ;
( * map ) + + ;
}
2013-02-01 16:04:57 +04:00
of_property_for_each_string ( np , " lantiq,groups " , prop , group ) {
( * map ) - > data . configs . configs = kmemdup ( configs ,
num_configs * sizeof ( unsigned long ) ,
GFP_KERNEL ) ;
( * map ) - > type = PIN_MAP_TYPE_CONFIGS_GROUP ;
( * map ) - > name = group ;
( * map ) - > data . configs . group_or_pin = group ;
( * map ) - > data . configs . num_configs = num_configs ;
( * map ) + + ;
}
2012-08-28 14:44:59 +04:00
}
static int ltq_pinctrl_dt_subnode_size ( struct device_node * np )
{
int ret ;
ret = of_property_count_strings ( np , " lantiq,groups " ) ;
if ( ret < 0 )
ret = of_property_count_strings ( np , " lantiq,pins " ) ;
return ret ;
}
2012-11-07 20:10:17 +04:00
static int ltq_pinctrl_dt_node_to_map ( struct pinctrl_dev * pctldev ,
struct device_node * np_config ,
struct pinctrl_map * * map ,
unsigned * num_maps )
2012-08-28 14:44:59 +04:00
{
struct pinctrl_map * tmp ;
struct device_node * np ;
2013-02-01 16:04:57 +04:00
int max_maps = 0 ;
2012-08-28 14:44:59 +04:00
for_each_child_of_node ( np_config , np )
2013-02-01 16:04:57 +04:00
max_maps + = ltq_pinctrl_dt_subnode_size ( np ) ;
* map = kzalloc ( max_maps * sizeof ( struct pinctrl_map ) * 2 , GFP_KERNEL ) ;
2012-08-28 14:44:59 +04:00
if ( ! * map )
return - ENOMEM ;
tmp = * map ;
2013-02-01 16:04:57 +04:00
for_each_child_of_node ( np_config , np )
ltq_pinctrl_dt_subnode_to_map ( pctldev , np , & tmp ) ;
* num_maps = ( ( int ) ( tmp - * map ) ) ;
2012-08-28 14:44:59 +04:00
return 0 ;
}
2013-02-16 13:25:07 +04:00
static const struct pinctrl_ops ltq_pctrl_ops = {
2012-08-28 14:44:59 +04:00
. get_groups_count = ltq_get_group_count ,
. get_group_name = ltq_get_group_name ,
. get_group_pins = ltq_get_group_pins ,
. pin_dbg_show = ltq_pinctrl_pin_dbg_show ,
. dt_node_to_map = ltq_pinctrl_dt_node_to_map ,
. dt_free_map = ltq_pinctrl_dt_free_map ,
} ;
static int ltq_pmx_func_count ( struct pinctrl_dev * pctrldev )
{
struct ltq_pinmux_info * info = pinctrl_dev_get_drvdata ( pctrldev ) ;
return info - > num_funcs ;
}
static const char * ltq_pmx_func_name ( struct pinctrl_dev * pctrldev ,
unsigned selector )
{
struct ltq_pinmux_info * info = pinctrl_dev_get_drvdata ( pctrldev ) ;
if ( selector > = info - > num_funcs )
return NULL ;
return info - > funcs [ selector ] . name ;
}
static int ltq_pmx_get_groups ( struct pinctrl_dev * pctrldev ,
unsigned func ,
const char * const * * groups ,
unsigned * const num_groups )
{
struct ltq_pinmux_info * info = pinctrl_dev_get_drvdata ( pctrldev ) ;
* groups = info - > funcs [ func ] . groups ;
* num_groups = info - > funcs [ func ] . num_groups ;
return 0 ;
}
/* Return function number. If failure, return negative value. */
static int match_mux ( const struct ltq_mfp_pin * mfp , unsigned mux )
{
int i ;
for ( i = 0 ; i < LTQ_MAX_MUX ; i + + ) {
if ( mfp - > func [ i ] = = mux )
break ;
}
if ( i > = LTQ_MAX_MUX )
return - EINVAL ;
return i ;
}
/* dont assume .mfp is linearly mapped. find the mfp with the correct .pin */
static int match_mfp ( const struct ltq_pinmux_info * info , int pin )
{
int i ;
for ( i = 0 ; i < info - > num_mfp ; i + + ) {
if ( info - > mfp [ i ] . pin = = pin )
return i ;
}
return - 1 ;
}
/* check whether current pin configuration is valid. Negative for failure */
static int match_group_mux ( const struct ltq_pin_group * grp ,
const struct ltq_pinmux_info * info ,
unsigned mux )
{
int i , pin , ret = 0 ;
for ( i = 0 ; i < grp - > npins ; i + + ) {
pin = match_mfp ( info , grp - > pins [ i ] ) ;
if ( pin < 0 ) {
dev_err ( info - > dev , " could not find mfp for pin %d \n " ,
grp - > pins [ i ] ) ;
return - EINVAL ;
}
ret = match_mux ( & info - > mfp [ pin ] , mux ) ;
if ( ret < 0 ) {
dev_err ( info - > dev , " Can't find mux %d on pin%d \n " ,
mux , pin ) ;
break ;
}
}
return ret ;
}
2014-09-03 15:02:56 +04:00
static int ltq_pmx_set ( struct pinctrl_dev * pctrldev ,
unsigned func ,
unsigned group )
2012-08-28 14:44:59 +04:00
{
struct ltq_pinmux_info * info = pinctrl_dev_get_drvdata ( pctrldev ) ;
const struct ltq_pin_group * pin_grp = & info - > grps [ group ] ;
int i , pin , pin_func , ret ;
if ( ! pin_grp - > npins | |
( match_group_mux ( pin_grp , info , pin_grp - > mux ) < 0 ) ) {
dev_err ( info - > dev , " Failed to set the pin group: %s \n " ,
info - > grps [ group ] . name ) ;
return - EINVAL ;
}
for ( i = 0 ; i < pin_grp - > npins ; i + + ) {
pin = match_mfp ( info , pin_grp - > pins [ i ] ) ;
if ( pin < 0 ) {
dev_err ( info - > dev , " could not find mfp for pin %d \n " ,
pin_grp - > pins [ i ] ) ;
return - EINVAL ;
}
pin_func = match_mux ( & info - > mfp [ pin ] , pin_grp - > mux ) ;
ret = info - > apply_mux ( pctrldev , pin , pin_func ) ;
if ( ret ) {
dev_err ( info - > dev ,
" failed to apply mux %d for pin %d \n " ,
pin_func , pin ) ;
return ret ;
}
}
return 0 ;
}
static int ltq_pmx_gpio_request_enable ( struct pinctrl_dev * pctrldev ,
struct pinctrl_gpio_range * range ,
unsigned pin )
{
struct ltq_pinmux_info * info = pinctrl_dev_get_drvdata ( pctrldev ) ;
2013-02-01 16:05:05 +04:00
int mfp = match_mfp ( info , pin ) ;
2012-08-28 14:44:59 +04:00
int pin_func ;
if ( mfp < 0 ) {
dev_err ( info - > dev , " could not find mfp for pin %d \n " , pin ) ;
return - EINVAL ;
}
pin_func = match_mux ( & info - > mfp [ mfp ] , 0 ) ;
if ( pin_func < 0 ) {
dev_err ( info - > dev , " No GPIO function on pin%d \n " , mfp ) ;
return - EINVAL ;
}
return info - > apply_mux ( pctrldev , mfp , pin_func ) ;
}
2013-02-16 13:25:07 +04:00
static const struct pinmux_ops ltq_pmx_ops = {
2012-08-28 14:44:59 +04:00
. get_functions_count = ltq_pmx_func_count ,
. get_function_name = ltq_pmx_func_name ,
. get_function_groups = ltq_pmx_get_groups ,
2014-09-03 15:02:56 +04:00
. set_mux = ltq_pmx_set ,
2012-08-28 14:44:59 +04:00
. gpio_request_enable = ltq_pmx_gpio_request_enable ,
} ;
/*
* allow different socs to register with the generic part of the lanti
* pinctrl code
*/
int ltq_pinctrl_register ( struct platform_device * pdev ,
struct ltq_pinmux_info * info )
{
struct pinctrl_desc * desc ;
if ( ! info )
return - EINVAL ;
desc = info - > desc ;
desc - > pctlops = & ltq_pctrl_ops ;
desc - > pmxops = & ltq_pmx_ops ;
info - > dev = & pdev - > dev ;
2016-02-24 12:14:07 +03:00
info - > pctrl = devm_pinctrl_register ( & pdev - > dev , desc , info ) ;
2015-06-09 07:01:16 +03:00
if ( IS_ERR ( info - > pctrl ) ) {
2012-08-28 14:44:59 +04:00
dev_err ( & pdev - > dev , " failed to register LTQ pinmux driver \n " ) ;
2015-06-09 07:01:16 +03:00
return PTR_ERR ( info - > pctrl ) ;
2012-08-28 14:44:59 +04:00
}
platform_set_drvdata ( pdev , info ) ;
return 0 ;
}