2015-11-20 05:10:05 +03:00
/*
* Hisilicon Hi6220 reset controller driver
*
2016-06-20 06:50:06 +03:00
* Copyright ( c ) 2016 Linaro Limited .
* Copyright ( c ) 2015 - 2016 Hisilicon Limited .
2015-11-20 05:10:05 +03:00
*
* Author : Feng Chen < puck . chen @ hisilicon . 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 .
*/
# include <linux/io.h>
# include <linux/init.h>
2015-12-12 10:53:21 +03:00
# include <linux/module.h>
2015-11-20 05:10:05 +03:00
# include <linux/bitops.h>
# include <linux/of.h>
2016-06-20 06:50:06 +03:00
# include <linux/of_device.h>
# include <linux/regmap.h>
# include <linux/mfd/syscon.h>
2015-11-20 05:10:05 +03:00
# include <linux/reset-controller.h>
# include <linux/reset.h>
# include <linux/platform_device.h>
2016-06-20 06:50:06 +03:00
# define PERIPH_ASSERT_OFFSET 0x300
# define PERIPH_DEASSERT_OFFSET 0x304
# define PERIPH_MAX_INDEX 0x509
2015-11-20 05:10:05 +03:00
2016-06-20 06:50:07 +03:00
# define SC_MEDIA_RSTEN 0x052C
# define SC_MEDIA_RSTDIS 0x0530
# define MEDIA_MAX_INDEX 8
2015-11-20 05:10:05 +03:00
# define to_reset_data(x) container_of(x, struct hi6220_reset_data, rc_dev)
2016-06-20 06:50:07 +03:00
enum hi6220_reset_ctrl_type {
PERIPHERAL ,
MEDIA ,
} ;
2015-11-20 05:10:05 +03:00
struct hi6220_reset_data {
2016-06-20 06:50:06 +03:00
struct reset_controller_dev rc_dev ;
struct regmap * regmap ;
2015-11-20 05:10:05 +03:00
} ;
2016-06-20 06:50:06 +03:00
static int hi6220_peripheral_assert ( struct reset_controller_dev * rc_dev ,
unsigned long idx )
2015-11-20 05:10:05 +03:00
{
struct hi6220_reset_data * data = to_reset_data ( rc_dev ) ;
2016-06-20 06:50:06 +03:00
struct regmap * regmap = data - > regmap ;
u32 bank = idx > > 8 ;
u32 offset = idx & 0xff ;
u32 reg = PERIPH_ASSERT_OFFSET + bank * 0x10 ;
2015-11-20 05:10:05 +03:00
2016-06-20 06:50:06 +03:00
return regmap_write ( regmap , reg , BIT ( offset ) ) ;
2015-11-20 05:10:05 +03:00
}
2016-06-20 06:50:06 +03:00
static int hi6220_peripheral_deassert ( struct reset_controller_dev * rc_dev ,
unsigned long idx )
2015-11-20 05:10:05 +03:00
{
struct hi6220_reset_data * data = to_reset_data ( rc_dev ) ;
2016-06-20 06:50:06 +03:00
struct regmap * regmap = data - > regmap ;
u32 bank = idx > > 8 ;
u32 offset = idx & 0xff ;
u32 reg = PERIPH_DEASSERT_OFFSET + bank * 0x10 ;
2015-11-20 05:10:05 +03:00
2016-06-20 06:50:06 +03:00
return regmap_write ( regmap , reg , BIT ( offset ) ) ;
2015-11-20 05:10:05 +03:00
}
2016-06-20 06:50:06 +03:00
static const struct reset_control_ops hi6220_peripheral_reset_ops = {
. assert = hi6220_peripheral_assert ,
. deassert = hi6220_peripheral_deassert ,
2015-11-20 05:10:05 +03:00
} ;
2016-06-20 06:50:07 +03:00
static int hi6220_media_assert ( struct reset_controller_dev * rc_dev ,
unsigned long idx )
{
struct hi6220_reset_data * data = to_reset_data ( rc_dev ) ;
struct regmap * regmap = data - > regmap ;
return regmap_write ( regmap , SC_MEDIA_RSTEN , BIT ( idx ) ) ;
}
static int hi6220_media_deassert ( struct reset_controller_dev * rc_dev ,
unsigned long idx )
{
struct hi6220_reset_data * data = to_reset_data ( rc_dev ) ;
struct regmap * regmap = data - > regmap ;
return regmap_write ( regmap , SC_MEDIA_RSTDIS , BIT ( idx ) ) ;
}
static const struct reset_control_ops hi6220_media_reset_ops = {
. assert = hi6220_media_assert ,
. deassert = hi6220_media_deassert ,
} ;
2015-11-20 05:10:05 +03:00
static int hi6220_reset_probe ( struct platform_device * pdev )
{
2016-06-20 06:50:06 +03:00
struct device_node * np = pdev - > dev . of_node ;
struct device * dev = & pdev - > dev ;
2016-06-20 06:50:07 +03:00
enum hi6220_reset_ctrl_type type ;
2015-11-20 05:10:05 +03:00
struct hi6220_reset_data * data ;
2016-06-20 06:50:06 +03:00
struct regmap * regmap ;
2015-11-20 05:10:05 +03:00
2016-06-20 06:50:06 +03:00
data = devm_kzalloc ( dev , sizeof ( * data ) , GFP_KERNEL ) ;
2015-11-20 05:10:05 +03:00
if ( ! data )
return - ENOMEM ;
2016-06-20 06:50:07 +03:00
type = ( enum hi6220_reset_ctrl_type ) of_device_get_match_data ( dev ) ;
2016-06-20 06:50:06 +03:00
regmap = syscon_node_to_regmap ( np ) ;
if ( IS_ERR ( regmap ) ) {
dev_err ( dev , " failed to get reset controller regmap \n " ) ;
return PTR_ERR ( regmap ) ;
}
2015-11-20 05:10:05 +03:00
2016-06-20 06:50:06 +03:00
data - > regmap = regmap ;
data - > rc_dev . of_node = np ;
2016-06-20 06:50:07 +03:00
if ( type = = MEDIA ) {
data - > rc_dev . ops = & hi6220_media_reset_ops ;
data - > rc_dev . nr_resets = MEDIA_MAX_INDEX ;
} else {
data - > rc_dev . ops = & hi6220_peripheral_reset_ops ;
data - > rc_dev . nr_resets = PERIPH_MAX_INDEX ;
}
2015-11-20 05:10:05 +03:00
2016-01-23 19:19:57 +03:00
return reset_controller_register ( & data - > rc_dev ) ;
2015-11-20 05:10:05 +03:00
}
static const struct of_device_id hi6220_reset_match [ ] = {
2016-06-20 06:50:06 +03:00
{
. compatible = " hisilicon,hi6220-sysctrl " ,
2016-06-20 06:50:07 +03:00
. data = ( void * ) PERIPHERAL ,
} ,
{
. compatible = " hisilicon,hi6220-mediactrl " ,
. data = ( void * ) MEDIA ,
2016-06-20 06:50:06 +03:00
} ,
{ /* sentinel */ } ,
2015-11-20 05:10:05 +03:00
} ;
2016-06-20 06:50:06 +03:00
MODULE_DEVICE_TABLE ( of , hi6220_reset_match ) ;
2015-11-20 05:10:05 +03:00
static struct platform_driver hi6220_reset_driver = {
. probe = hi6220_reset_probe ,
. driver = {
. name = " reset-hi6220 " ,
. of_match_table = hi6220_reset_match ,
} ,
} ;
static int __init hi6220_reset_init ( void )
{
return platform_driver_register ( & hi6220_reset_driver ) ;
}
postcore_initcall ( hi6220_reset_init ) ;
2017-04-08 10:18:40 +03:00
MODULE_LICENSE ( " GPL v2 " ) ;