2016-06-27 20:12:17 +03:00
/*
* TI SYSCON regmap reset driver
*
* Copyright ( C ) 2015 - 2016 Texas Instruments Incorporated - http : //www.ti.com/
* Andrew F . Davis < afd @ ti . com >
* Suman Anna < afd @ ti . com >
*
* 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
* published by the Free Software Foundation .
*
* This program is distributed " as is " WITHOUT ANY WARRANTY of any
* kind , whether express or implied ; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*/
# include <linux/mfd/syscon.h>
# include <linux/module.h>
# include <linux/of.h>
# include <linux/platform_device.h>
# include <linux/regmap.h>
# include <linux/reset-controller.h>
# include <dt-bindings/reset/ti-syscon.h>
/**
* struct ti_syscon_reset_control - reset control structure
* @ assert_offset : reset assert control register offset from syscon base
* @ assert_bit : reset assert bit in the reset assert control register
* @ deassert_offset : reset deassert control register offset from syscon base
* @ deassert_bit : reset deassert bit in the reset deassert control register
* @ status_offset : reset status register offset from syscon base
* @ status_bit : reset status bit in the reset status register
* @ flags : reset flag indicating how the ( de ) assert and status are handled
*/
struct ti_syscon_reset_control {
unsigned int assert_offset ;
unsigned int assert_bit ;
unsigned int deassert_offset ;
unsigned int deassert_bit ;
unsigned int status_offset ;
unsigned int status_bit ;
u32 flags ;
} ;
/**
* struct ti_syscon_reset_data - reset controller information structure
* @ rcdev : reset controller entity
* @ regmap : regmap handle containing the memory - mapped reset registers
* @ controls : array of reset controls
* @ nr_controls : number of controls in control array
*/
struct ti_syscon_reset_data {
struct reset_controller_dev rcdev ;
struct regmap * regmap ;
struct ti_syscon_reset_control * controls ;
unsigned int nr_controls ;
} ;
# define to_ti_syscon_reset_data(rcdev) \
container_of ( rcdev , struct ti_syscon_reset_data , rcdev )
/**
* ti_syscon_reset_assert ( ) - assert device reset
* @ rcdev : reset controller entity
* @ id : ID of the reset to be asserted
*
* This function implements the reset driver op to assert a device ' s reset .
* This asserts the reset in a manner prescribed by the reset flags .
*
* Return : 0 for successful request , else a corresponding error value
*/
static int ti_syscon_reset_assert ( struct reset_controller_dev * rcdev ,
unsigned long id )
{
struct ti_syscon_reset_data * data = to_ti_syscon_reset_data ( rcdev ) ;
struct ti_syscon_reset_control * control ;
unsigned int mask , value ;
if ( id > = data - > nr_controls )
return - EINVAL ;
control = & data - > controls [ id ] ;
if ( control - > flags & ASSERT_NONE )
return - ENOTSUPP ; /* assert not supported for this reset */
mask = BIT ( control - > assert_bit ) ;
value = ( control - > flags & ASSERT_SET ) ? mask : 0x0 ;
return regmap_update_bits ( data - > regmap , control - > assert_offset , mask , value ) ;
}
/**
* ti_syscon_reset_deassert ( ) - deassert device reset
* @ rcdev : reset controller entity
* @ id : ID of reset to be deasserted
*
* This function implements the reset driver op to deassert a device ' s reset .
* This deasserts the reset in a manner prescribed by the reset flags .
*
* Return : 0 for successful request , else a corresponding error value
*/
static int ti_syscon_reset_deassert ( struct reset_controller_dev * rcdev ,
unsigned long id )
{
struct ti_syscon_reset_data * data = to_ti_syscon_reset_data ( rcdev ) ;
struct ti_syscon_reset_control * control ;
unsigned int mask , value ;
if ( id > = data - > nr_controls )
return - EINVAL ;
control = & data - > controls [ id ] ;
if ( control - > flags & DEASSERT_NONE )
return - ENOTSUPP ; /* deassert not supported for this reset */
mask = BIT ( control - > deassert_bit ) ;
value = ( control - > flags & DEASSERT_SET ) ? mask : 0x0 ;
return regmap_update_bits ( data - > regmap , control - > deassert_offset , mask , value ) ;
}
/**
* ti_syscon_reset_status ( ) - check device reset status
* @ rcdev : reset controller entity
* @ id : ID of the reset for which the status is being requested
*
* This function implements the reset driver op to return the status of a
* device ' s reset .
*
* Return : 0 if reset is deasserted , true if reset is asserted , else a
* corresponding error value
*/
static int ti_syscon_reset_status ( struct reset_controller_dev * rcdev ,
unsigned long id )
{
struct ti_syscon_reset_data * data = to_ti_syscon_reset_data ( rcdev ) ;
struct ti_syscon_reset_control * control ;
unsigned int reset_state ;
int ret ;
if ( id > = data - > nr_controls )
return - EINVAL ;
control = & data - > controls [ id ] ;
if ( control - > flags & STATUS_NONE )
return - ENOTSUPP ; /* status not supported for this reset */
ret = regmap_read ( data - > regmap , control - > status_offset , & reset_state ) ;
if ( ret )
return ret ;
2016-11-30 04:03:32 +03:00
return ! ( reset_state & BIT ( control - > status_bit ) ) = =
! ( control - > flags & STATUS_SET ) ;
2016-06-27 20:12:17 +03:00
}
2017-01-09 19:53:55 +03:00
static const struct reset_control_ops ti_syscon_reset_ops = {
2016-06-27 20:12:17 +03:00
. assert = ti_syscon_reset_assert ,
. deassert = ti_syscon_reset_deassert ,
. status = ti_syscon_reset_status ,
} ;
static int ti_syscon_reset_probe ( struct platform_device * pdev )
{
struct device * dev = & pdev - > dev ;
struct device_node * np = dev - > of_node ;
struct ti_syscon_reset_data * data ;
struct regmap * regmap ;
const __be32 * list ;
struct ti_syscon_reset_control * controls ;
int size , nr_controls , i ;
data = devm_kzalloc ( dev , sizeof ( * data ) , GFP_KERNEL ) ;
if ( ! data )
return - ENOMEM ;
regmap = syscon_node_to_regmap ( np - > parent ) ;
if ( IS_ERR ( regmap ) )
return PTR_ERR ( regmap ) ;
list = of_get_property ( np , " ti,reset-bits " , & size ) ;
if ( ! list | | ( size / sizeof ( * list ) ) % 7 ! = 0 ) {
dev_err ( dev , " invalid DT reset description \n " ) ;
return - EINVAL ;
}
nr_controls = ( size / sizeof ( * list ) ) / 7 ;
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-13 00:07:58 +03:00
controls = devm_kcalloc ( dev , nr_controls , sizeof ( * controls ) ,
GFP_KERNEL ) ;
2016-06-27 20:12:17 +03:00
if ( ! controls )
return - ENOMEM ;
for ( i = 0 ; i < nr_controls ; i + + ) {
controls [ i ] . assert_offset = be32_to_cpup ( list + + ) ;
controls [ i ] . assert_bit = be32_to_cpup ( list + + ) ;
controls [ i ] . deassert_offset = be32_to_cpup ( list + + ) ;
controls [ i ] . deassert_bit = be32_to_cpup ( list + + ) ;
controls [ i ] . status_offset = be32_to_cpup ( list + + ) ;
controls [ i ] . status_bit = be32_to_cpup ( list + + ) ;
controls [ i ] . flags = be32_to_cpup ( list + + ) ;
}
data - > rcdev . ops = & ti_syscon_reset_ops ;
data - > rcdev . owner = THIS_MODULE ;
data - > rcdev . of_node = np ;
data - > rcdev . nr_resets = nr_controls ;
data - > regmap = regmap ;
data - > controls = controls ;
data - > nr_controls = nr_controls ;
platform_set_drvdata ( pdev , data ) ;
return devm_reset_controller_register ( dev , & data - > rcdev ) ;
}
static const struct of_device_id ti_syscon_reset_of_match [ ] = {
{ . compatible = " ti,syscon-reset " , } ,
{ /* sentinel */ } ,
} ;
MODULE_DEVICE_TABLE ( of , ti_syscon_reset_of_match ) ;
static struct platform_driver ti_syscon_reset_driver = {
. probe = ti_syscon_reset_probe ,
. driver = {
. name = " ti-syscon-reset " ,
. of_match_table = ti_syscon_reset_of_match ,
} ,
} ;
module_platform_driver ( ti_syscon_reset_driver ) ;
MODULE_AUTHOR ( " Andrew F. Davis <afd@ti.com> " ) ;
MODULE_AUTHOR ( " Suman Anna <s-anna@ti.com> " ) ;
MODULE_DESCRIPTION ( " TI SYSCON Regmap Reset Driver " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;