2018-11-13 12:50:48 -06:00
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright ( C ) 2018 , Intel Corporation
* Copied from reset - sunxi . c
*/
# include <linux/err.h>
# include <linux/io.h>
# include <linux/init.h>
# include <linux/of.h>
# include <linux/of_address.h>
# include <linux/platform_device.h>
# include <linux/reset-controller.h>
2020-05-27 17:47:31 +02:00
# include <linux/reset/reset-simple.h>
2018-12-13 12:24:36 +01:00
# include <linux/reset/socfpga.h>
2018-11-13 12:50:48 -06:00
# include <linux/slab.h>
# include <linux/spinlock.h>
# include <linux/types.h>
# define SOCFPGA_NR_BANKS 8
static int a10_reset_init ( struct device_node * np )
{
struct reset_simple_data * data ;
struct resource res ;
resource_size_t size ;
int ret ;
u32 reg_offset = 0x10 ;
data = kzalloc ( sizeof ( * data ) , GFP_KERNEL ) ;
if ( ! data )
return - ENOMEM ;
ret = of_address_to_resource ( np , 0 , & res ) ;
if ( ret )
goto err_alloc ;
size = resource_size ( & res ) ;
if ( ! request_mem_region ( res . start , size , np - > name ) ) {
ret = - EBUSY ;
goto err_alloc ;
}
data - > membase = ioremap ( res . start , size ) ;
if ( ! data - > membase ) {
ret = - ENOMEM ;
2020-11-09 13:21:41 -06:00
goto release_region ;
2018-11-13 12:50:48 -06:00
}
if ( of_property_read_u32 ( np , " altr,modrst-offset " , & reg_offset ) )
pr_warn ( " missing altr,modrst-offset property, assuming 0x10 \n " ) ;
data - > membase + = reg_offset ;
spin_lock_init ( & data - > lock ) ;
data - > rcdev . owner = THIS_MODULE ;
data - > rcdev . nr_resets = SOCFPGA_NR_BANKS * 32 ;
data - > rcdev . ops = & reset_simple_ops ;
data - > rcdev . of_node = np ;
data - > status_active_low = true ;
2020-11-09 13:21:41 -06:00
ret = reset_controller_register ( & data - > rcdev ) ;
if ( ret )
pr_err ( " unable to register device \n " ) ;
return ret ;
release_region :
release_mem_region ( res . start , size ) ;
2018-11-13 12:50:48 -06:00
err_alloc :
kfree ( data ) ;
return ret ;
} ;
/*
* These are the reset controller we need to initialize early on in
* our system , before we can even think of using a regular device
* driver for it .
* The controllers that we can register through the regular device
* model are handled by the simple reset driver directly .
*/
static const struct of_device_id socfpga_early_reset_dt_ids [ ] __initconst = {
{ . compatible = " altr,rst-mgr " , } ,
{ /* sentinel */ } ,
} ;
void __init socfpga_reset_init ( void )
{
struct device_node * np ;
for_each_matching_node ( np , socfpga_early_reset_dt_ids )
a10_reset_init ( np ) ;
}
2021-09-20 14:41:41 +02:00
/*
* The early driver is problematic , because it doesn ' t register
* itself as a driver . This causes certain device links to prevent
* consumer devices from probing . The hacky solution is to register
* an empty driver , whose only job is to attach itself to the reset
* manager and call probe .
*/
static const struct of_device_id socfpga_reset_dt_ids [ ] = {
{ . compatible = " altr,rst-mgr " , } ,
{ /* sentinel */ } ,
} ;
static int reset_simple_probe ( struct platform_device * pdev )
{
return 0 ;
}
static struct platform_driver reset_socfpga_driver = {
. probe = reset_simple_probe ,
. driver = {
. name = " socfpga-reset " ,
. of_match_table = socfpga_reset_dt_ids ,
} ,
} ;
builtin_platform_driver ( reset_socfpga_driver ) ;