2019-05-27 08:55:01 +02:00
// SPDX-License-Identifier: GPL-2.0-or-later
2016-12-06 09:51:32 +08:00
/*
* Copyright ( c ) 2016 - 2017 Linaro Ltd .
* Copyright ( c ) 2016 - 2017 HiSilicon Technologies Co . , Ltd .
*/
# include <linux/kernel.h>
# include <linux/mfd/syscon.h>
# include <linux/module.h>
# include <linux/of_device.h>
# include <linux/platform_device.h>
# include <linux/regmap.h>
# include <linux/reset-controller.h>
struct hi3660_reset_controller {
struct reset_controller_dev rst ;
struct regmap * map ;
} ;
# define to_hi3660_reset_controller(_rst) \
container_of ( _rst , struct hi3660_reset_controller , rst )
static int hi3660_reset_program_hw ( struct reset_controller_dev * rcdev ,
unsigned long idx , bool assert )
{
struct hi3660_reset_controller * rc = to_hi3660_reset_controller ( rcdev ) ;
unsigned int offset = idx > > 8 ;
unsigned int mask = BIT ( idx & 0x1f ) ;
if ( assert )
return regmap_write ( rc - > map , offset , mask ) ;
else
return regmap_write ( rc - > map , offset + 4 , mask ) ;
}
static int hi3660_reset_assert ( struct reset_controller_dev * rcdev ,
unsigned long idx )
{
return hi3660_reset_program_hw ( rcdev , idx , true ) ;
}
static int hi3660_reset_deassert ( struct reset_controller_dev * rcdev ,
unsigned long idx )
{
return hi3660_reset_program_hw ( rcdev , idx , false ) ;
}
static int hi3660_reset_dev ( struct reset_controller_dev * rcdev ,
unsigned long idx )
{
int err ;
err = hi3660_reset_assert ( rcdev , idx ) ;
if ( err )
return err ;
return hi3660_reset_deassert ( rcdev , idx ) ;
}
2017-05-12 14:24:50 +02:00
static const struct reset_control_ops hi3660_reset_ops = {
2016-12-06 09:51:32 +08:00
. reset = hi3660_reset_dev ,
. assert = hi3660_reset_assert ,
. deassert = hi3660_reset_deassert ,
} ;
static int hi3660_reset_xlate ( struct reset_controller_dev * rcdev ,
const struct of_phandle_args * reset_spec )
{
unsigned int offset , bit ;
offset = reset_spec - > args [ 0 ] ;
bit = reset_spec - > args [ 1 ] ;
return ( offset < < 8 ) | bit ;
}
static int hi3660_reset_probe ( struct platform_device * pdev )
{
struct hi3660_reset_controller * rc ;
struct device_node * np = pdev - > dev . of_node ;
struct device * dev = & pdev - > dev ;
rc = devm_kzalloc ( dev , sizeof ( * rc ) , GFP_KERNEL ) ;
if ( ! rc )
return - ENOMEM ;
rc - > map = syscon_regmap_lookup_by_phandle ( np , " hisi,rst-syscon " ) ;
if ( IS_ERR ( rc - > map ) ) {
dev_err ( dev , " failed to get hi3660,rst-syscon \n " ) ;
return PTR_ERR ( rc - > map ) ;
}
rc - > rst . ops = & hi3660_reset_ops ,
rc - > rst . of_node = np ;
rc - > rst . of_reset_n_cells = 2 ;
rc - > rst . of_xlate = hi3660_reset_xlate ;
return reset_controller_register ( & rc - > rst ) ;
}
static const struct of_device_id hi3660_reset_match [ ] = {
{ . compatible = " hisilicon,hi3660-reset " , } ,
{ } ,
} ;
MODULE_DEVICE_TABLE ( of , hi3660_reset_match ) ;
static struct platform_driver hi3660_reset_driver = {
. probe = hi3660_reset_probe ,
. driver = {
. name = " hi3660-reset " ,
. of_match_table = hi3660_reset_match ,
} ,
} ;
static int __init hi3660_reset_init ( void )
{
return platform_driver_register ( & hi3660_reset_driver ) ;
}
arch_initcall ( hi3660_reset_init ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_ALIAS ( " platform:hi3660-reset " ) ;
MODULE_DESCRIPTION ( " HiSilicon Hi3660 Reset Driver " ) ;