2018-05-16 15:33:37 +08:00
// SPDX-License-Identifier: GPL-2.0
2014-05-19 19:36:29 +02:00
/*
* Marvell Berlin SoC pinctrl core driver
*
* Copyright ( C ) 2014 Marvell Technology Group Ltd .
*
2015-10-13 23:31:41 +02:00
* Antoine Ténart < antoine . tenart @ free - electrons . com >
2014-05-19 19:36:29 +02:00
*/
# include <linux/io.h>
2015-05-16 01:16:09 +02:00
# include <linux/mfd/syscon.h>
2014-05-19 19:36:29 +02:00
# include <linux/module.h>
# include <linux/of.h>
# include <linux/of_address.h>
# include <linux/of_device.h>
# include <linux/pinctrl/pinctrl.h>
# include <linux/pinctrl/pinmux.h>
# include <linux/platform_device.h>
# include <linux/regmap.h>
# include <linux/slab.h>
# include "../core.h"
# include "../pinctrl-utils.h"
# include "berlin.h"
struct berlin_pinctrl {
struct regmap * regmap ;
struct device * dev ;
const struct berlin_pinctrl_desc * desc ;
struct berlin_pinctrl_function * functions ;
unsigned nfunctions ;
struct pinctrl_dev * pctrl_dev ;
} ;
static int berlin_pinctrl_get_group_count ( struct pinctrl_dev * pctrl_dev )
{
struct berlin_pinctrl * pctrl = pinctrl_dev_get_drvdata ( pctrl_dev ) ;
return pctrl - > desc - > ngroups ;
}
static const char * berlin_pinctrl_get_group_name ( struct pinctrl_dev * pctrl_dev ,
unsigned group )
{
struct berlin_pinctrl * pctrl = pinctrl_dev_get_drvdata ( pctrl_dev ) ;
return pctrl - > desc - > groups [ group ] . name ;
}
static int berlin_pinctrl_dt_node_to_map ( struct pinctrl_dev * pctrl_dev ,
struct device_node * node ,
struct pinctrl_map * * map ,
unsigned * num_maps )
{
struct berlin_pinctrl * pctrl = pinctrl_dev_get_drvdata ( pctrl_dev ) ;
struct property * prop ;
const char * function_name , * group_name ;
unsigned reserved_maps = 0 ;
int ret , ngroups ;
* map = NULL ;
* num_maps = 0 ;
ret = of_property_read_string ( node , " function " , & function_name ) ;
if ( ret ) {
dev_err ( pctrl - > dev ,
" missing function property in node %s \n " ,
node - > name ) ;
return - EINVAL ;
}
ngroups = of_property_count_strings ( node , " groups " ) ;
if ( ngroups < 0 ) {
dev_err ( pctrl - > dev ,
" missing groups property in node %s \n " ,
node - > name ) ;
return - EINVAL ;
}
ret = pinctrl_utils_reserve_map ( pctrl_dev , map , & reserved_maps ,
num_maps , ngroups ) ;
if ( ret ) {
dev_err ( pctrl - > dev , " can't reserve map: %d \n " , ret ) ;
return ret ;
}
of_property_for_each_string ( node , " groups " , prop , group_name ) {
ret = pinctrl_utils_add_map_mux ( pctrl_dev , map , & reserved_maps ,
num_maps , group_name ,
function_name ) ;
if ( ret ) {
dev_err ( pctrl - > dev , " can't add map: %d \n " , ret ) ;
return ret ;
}
}
return 0 ;
}
static const struct pinctrl_ops berlin_pinctrl_ops = {
. get_groups_count = & berlin_pinctrl_get_group_count ,
. get_group_name = & berlin_pinctrl_get_group_name ,
. dt_node_to_map = & berlin_pinctrl_dt_node_to_map ,
2016-03-31 14:44:42 +03:00
. dt_free_map = & pinctrl_utils_free_map ,
2014-05-19 19:36:29 +02:00
} ;
static int berlin_pinmux_get_functions_count ( struct pinctrl_dev * pctrl_dev )
{
struct berlin_pinctrl * pctrl = pinctrl_dev_get_drvdata ( pctrl_dev ) ;
return pctrl - > nfunctions ;
}
static const char * berlin_pinmux_get_function_name ( struct pinctrl_dev * pctrl_dev ,
unsigned function )
{
struct berlin_pinctrl * pctrl = pinctrl_dev_get_drvdata ( pctrl_dev ) ;
return pctrl - > functions [ function ] . name ;
}
static int berlin_pinmux_get_function_groups ( struct pinctrl_dev * pctrl_dev ,
unsigned function ,
const char * const * * groups ,
unsigned * const num_groups )
{
struct berlin_pinctrl * pctrl = pinctrl_dev_get_drvdata ( pctrl_dev ) ;
* groups = pctrl - > functions [ function ] . groups ;
* num_groups = pctrl - > functions [ function ] . ngroups ;
return 0 ;
}
static struct berlin_desc_function *
berlin_pinctrl_find_function_by_name ( struct berlin_pinctrl * pctrl ,
const struct berlin_desc_group * group ,
const char * fname )
{
struct berlin_desc_function * function = group - > functions ;
while ( function - > name ) {
if ( ! strcmp ( function - > name , fname ) )
return function ;
function + + ;
}
return NULL ;
}
2014-09-03 13:02:56 +02:00
static int berlin_pinmux_set ( struct pinctrl_dev * pctrl_dev ,
unsigned function ,
unsigned group )
2014-05-19 19:36:29 +02:00
{
struct berlin_pinctrl * pctrl = pinctrl_dev_get_drvdata ( pctrl_dev ) ;
const struct berlin_desc_group * group_desc = pctrl - > desc - > groups + group ;
struct berlin_pinctrl_function * func = pctrl - > functions + function ;
struct berlin_desc_function * function_desc =
berlin_pinctrl_find_function_by_name ( pctrl , group_desc ,
func - > name ) ;
u32 mask , val ;
if ( ! function_desc )
return - EINVAL ;
mask = GENMASK ( group_desc - > lsb + group_desc - > bit_width - 1 ,
group_desc - > lsb ) ;
val = function_desc - > muxval < < group_desc - > lsb ;
regmap_update_bits ( pctrl - > regmap , group_desc - > offset , mask , val ) ;
return 0 ;
}
static const struct pinmux_ops berlin_pinmux_ops = {
. get_functions_count = & berlin_pinmux_get_functions_count ,
. get_function_name = & berlin_pinmux_get_function_name ,
. get_function_groups = & berlin_pinmux_get_function_groups ,
2014-09-03 13:02:56 +02:00
. set_mux = & berlin_pinmux_set ,
2014-05-19 19:36:29 +02:00
} ;
static int berlin_pinctrl_add_function ( struct berlin_pinctrl * pctrl ,
const char * name )
{
struct berlin_pinctrl_function * function = pctrl - > functions ;
while ( function - > name ) {
if ( ! strcmp ( function - > name , name ) ) {
function - > ngroups + + ;
return - EEXIST ;
}
function + + ;
}
function - > name = name ;
function - > ngroups = 1 ;
pctrl - > nfunctions + + ;
return 0 ;
}
static int berlin_pinctrl_build_state ( struct platform_device * pdev )
{
struct berlin_pinctrl * pctrl = platform_get_drvdata ( pdev ) ;
2017-08-04 11:22:31 +09:00
const struct berlin_desc_group * desc_group ;
const struct berlin_desc_function * desc_function ;
2014-05-19 19:36:29 +02:00
int i , max_functions = 0 ;
pctrl - > nfunctions = 0 ;
for ( i = 0 ; i < pctrl - > desc - > ngroups ; i + + ) {
desc_group = pctrl - > desc - > groups + i ;
/* compute the maxiumum number of functions a group can have */
max_functions + = 1 < < ( desc_group - > bit_width + 1 ) ;
}
/* we will reallocate later */
2018-08-01 13:10:49 +08:00
pctrl - > functions = kcalloc ( max_functions ,
sizeof ( * pctrl - > functions ) , GFP_KERNEL ) ;
2014-05-19 19:36:29 +02:00
if ( ! pctrl - > functions )
return - ENOMEM ;
/* register all functions */
for ( i = 0 ; i < pctrl - > desc - > ngroups ; i + + ) {
desc_group = pctrl - > desc - > groups + i ;
desc_function = desc_group - > functions ;
while ( desc_function - > name ) {
berlin_pinctrl_add_function ( pctrl , desc_function - > name ) ;
desc_function + + ;
}
}
pctrl - > functions = krealloc ( pctrl - > functions ,
pctrl - > nfunctions * sizeof ( * pctrl - > functions ) ,
GFP_KERNEL ) ;
/* map functions to theirs groups */
for ( i = 0 ; i < pctrl - > desc - > ngroups ; i + + ) {
desc_group = pctrl - > desc - > groups + i ;
desc_function = desc_group - > functions ;
while ( desc_function - > name ) {
struct berlin_pinctrl_function
* function = pctrl - > functions ;
const char * * groups ;
bool found = false ;
while ( function - > name ) {
if ( ! strcmp ( desc_function - > name , function - > name ) ) {
found = true ;
break ;
}
function + + ;
}
2018-08-01 13:10:49 +08:00
if ( ! found ) {
kfree ( pctrl - > functions ) ;
2014-05-19 19:36:29 +02:00
return - EINVAL ;
2018-08-01 13:10:49 +08:00
}
2014-05-19 19:36:29 +02:00
if ( ! function - > groups ) {
function - > groups =
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
devm_kcalloc ( & pdev - > dev ,
function - > ngroups ,
sizeof ( char * ) ,
2014-05-19 19:36:29 +02:00
GFP_KERNEL ) ;
2018-08-01 13:10:49 +08:00
if ( ! function - > groups ) {
kfree ( pctrl - > functions ) ;
2014-05-19 19:36:29 +02:00
return - ENOMEM ;
2018-08-01 13:10:49 +08:00
}
2014-05-19 19:36:29 +02:00
}
groups = function - > groups ;
while ( * groups )
groups + + ;
* groups = desc_group - > name ;
desc_function + + ;
}
}
return 0 ;
}
static struct pinctrl_desc berlin_pctrl_desc = {
. name = " berlin-pinctrl " ,
. pctlops = & berlin_pinctrl_ops ,
. pmxops = & berlin_pinmux_ops ,
. owner = THIS_MODULE ,
} ;
2015-10-16 15:37:06 +08:00
int berlin_pinctrl_probe_regmap ( struct platform_device * pdev ,
const struct berlin_pinctrl_desc * desc ,
struct regmap * regmap )
2014-05-19 19:36:29 +02:00
{
struct device * dev = & pdev - > dev ;
struct berlin_pinctrl * pctrl ;
int ret ;
pctrl = devm_kzalloc ( dev , sizeof ( * pctrl ) , GFP_KERNEL ) ;
if ( ! pctrl )
return - ENOMEM ;
platform_set_drvdata ( pdev , pctrl ) ;
pctrl - > regmap = regmap ;
pctrl - > dev = & pdev - > dev ;
pctrl - > desc = desc ;
ret = berlin_pinctrl_build_state ( pdev ) ;
if ( ret ) {
dev_err ( dev , " cannot build driver state: %d \n " , ret ) ;
return ret ;
}
2016-02-24 14:44:07 +05:30
pctrl - > pctrl_dev = devm_pinctrl_register ( dev , & berlin_pctrl_desc ,
pctrl ) ;
2015-06-09 13:01:16 +09:00
if ( IS_ERR ( pctrl - > pctrl_dev ) ) {
2014-05-19 19:36:29 +02:00
dev_err ( dev , " failed to register pinctrl driver \n " ) ;
2015-06-09 13:01:16 +09:00
return PTR_ERR ( pctrl - > pctrl_dev ) ;
2014-05-19 19:36:29 +02:00
}
return 0 ;
}
2015-10-16 15:37:06 +08:00
int berlin_pinctrl_probe ( struct platform_device * pdev ,
const struct berlin_pinctrl_desc * desc )
{
struct device * dev = & pdev - > dev ;
struct device_node * parent_np = of_get_parent ( dev - > of_node ) ;
struct regmap * regmap = syscon_node_to_regmap ( parent_np ) ;
of_node_put ( parent_np ) ;
if ( IS_ERR ( regmap ) )
return PTR_ERR ( regmap ) ;
return berlin_pinctrl_probe_regmap ( pdev , desc , regmap ) ;
}