2017-12-25 21:17:59 +01:00
// SPDX-License-Identifier: GPL-2.0
//
// Exynos Generic power domain support.
//
// Copyright (c) 2012 Samsung Electronics Co., Ltd.
// http://www.samsung.com
//
// Implementation of Exynos specific power domain control which is used in
// conjunction with runtime-pm. Support for both device-tree and non-device-tree
// based power domain support is included.
2012-01-27 15:25:00 +09:00
# include <linux/io.h>
# include <linux/err.h>
2023-07-14 11:51:46 -06:00
# include <linux/platform_device.h>
2012-01-27 15:25:00 +09:00
# include <linux/slab.h>
# include <linux/pm_domain.h>
# include <linux/delay.h>
2023-07-14 11:51:46 -06:00
# include <linux/of.h>
2012-01-27 15:25:00 +09:00
# include <linux/of_address.h>
2021-01-13 12:03:20 +01:00
# include <linux/pm_runtime.h>
2012-01-27 15:25:00 +09:00
2016-05-10 15:52:21 +02:00
struct exynos_pm_domain_config {
/* Value for LOCAL_PWR_CFG and STATUS fields for each domain */
u32 local_pwr_cfg ;
} ;
2012-01-27 15:25:00 +09:00
/*
* Exynos specific wrapper around the generic power domain
*/
struct exynos_pm_domain {
void __iomem * base ;
struct generic_pm_domain pd ;
2016-05-10 15:52:21 +02:00
u32 local_pwr_cfg ;
2012-01-27 15:25:00 +09:00
} ;
static int exynos_pd_power ( struct generic_pm_domain * domain , bool power_on )
{
struct exynos_pm_domain * pd ;
void __iomem * base ;
u32 timeout , pwr ;
char * op ;
pd = container_of ( domain , struct exynos_pm_domain , pd ) ;
base = pd - > base ;
2016-05-10 15:52:21 +02:00
pwr = power_on ? pd - > local_pwr_cfg : 0 ;
2016-06-21 11:20:25 +01:00
writel_relaxed ( pwr , base ) ;
2012-01-27 15:25:00 +09:00
/* Wait max 1ms */
timeout = 10 ;
ARM: SoC driver updates for v4.8
Driver updates for ARM SoCs.
A slew of changes this release cycle. The reset driver tree, that we merge
through arm-soc for historical reasons, is also sizable this time around.
Among the changes:
- clps711x: Treewide changes to compatible strings, merged here for simplicity.
- Qualcomm: SCM firmware driver cleanups, move to platform driver
- ux500: Major cleanups, removal of old mach-specific infrastructure.
- Atmel external bus memory driver
- Move of brcmstb platform to the rest of bcm
- PMC driver updates for tegra, various fixes and improvements
- Samsung platform driver updates to support 64-bit Exynos platforms
- Reset controller cleanups moving to devm_reset_controller_register() APIs
- Reset controller driver for Amlogic Meson
- Reset controller driver for Hisilicon hi6220
- ARM SCPI power domain support
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1
iQIcBAABAgAGBQJXnm1XAAoJEIwa5zzehBx35lcP/ApuQarIXeZCQZtjlUBV9McW
o3o7FhKFHePmEPeoYCvVeK5D8NykTkQv3WpnCknoxPJzxGJF7jbPWQJcVnXfKOXD
kTcyIK15WL2HHtSE3lYyLfyUPz8AbJyRt0l0cxgcg6jvo+uzlWooNz1y78rLIYzg
UwRssj7OiHv4dsyYRHZIsjnB8gMWw8rYMk154gP2xy6MnNXXzzOVVnOiVqxSZBm+
EgIIcROMOqkkHuFlClMYKluIgrmgz1Ypjf+FuAg7dqXZd+TGRrmGXeI7SkGThfLu
nyvY3N18NViNu7xOUkI9zg7+ifyYM8Si9ylalSICSJdIAxZfiwFqFaLJvVWKU1rY
rBOBjKckQI0/X9WYusFNFHcijhIFV8/FgGAnVRRMPdvlCss7Zp03C9mR4AEhmKMX
rLG49x81hU1C+LftC59ml3iB8dhZrrRkbxNHjLFHVGWNrKMrmJKa8JhXGRAoNM+u
LRauiuJZatqvLfISNvpfcoW2EashVoU3f+uC8ymT3QCyME3wZm0t7T4tllxhMfBl
sOgJqNkTKDmPLofwm/dASiLML7ZF1WePScrFyOACnj9K4mUD+OaCnowtWoQPu0eI
aNmT84oosJ2S9F/iUDPtFHXdzQ+1QPPfSiQ9FXMoauciVq/2F+pqq68yYgqoxFOG
vmkmG2YM4Wyq43u0BONR
=O8+y
-----END PGP SIGNATURE-----
Merge tag 'armsoc-drivers' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc
Pull ARM SoC driver updates from Olof Johansson:
"Driver updates for ARM SoCs.
A slew of changes this release cycle. The reset driver tree, that we
merge through arm-soc for historical reasons, is also sizable this
time around.
Among the changes:
- clps711x: Treewide changes to compatible strings, merged here for simplicity.
- Qualcomm: SCM firmware driver cleanups, move to platform driver
- ux500: Major cleanups, removal of old mach-specific infrastructure.
- Atmel external bus memory driver
- Move of brcmstb platform to the rest of bcm
- PMC driver updates for tegra, various fixes and improvements
- Samsung platform driver updates to support 64-bit Exynos platforms
- Reset controller cleanups moving to devm_reset_controller_register() APIs
- Reset controller driver for Amlogic Meson
- Reset controller driver for Hisilicon hi6220
- ARM SCPI power domain support"
* tag 'armsoc-drivers' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc: (100 commits)
ARM: ux500: consolidate base platform files
ARM: ux500: move soc_id driver to drivers/soc
ARM: ux500: call ux500_setup_id later
ARM: ux500: consolidate soc_device code in id.c
ARM: ux500: remove cpu_is_u* helpers
ARM: ux500: use CLK_OF_DECLARE()
ARM: ux500: move l2x0 init to .init_irq
mfd: db8500 stop passing around platform data
ASoC: ab8500-codec: remove platform data based probe
ARM: ux500: move ab8500_regulator_plat_data into driver
ARM: ux500: remove unused regulator data
soc: raspberrypi-power: add CONFIG_OF dependency
firmware: scpi: add CONFIG_OF dependency
video: clps711x-fb: Changing the compatibility string to match with the smallest supported chip
input: clps711x-keypad: Changing the compatibility string to match with the smallest supported chip
pwm: clps711x: Changing the compatibility string to match with the smallest supported chip
serial: clps711x: Changing the compatibility string to match with the smallest supported chip
irqchip: clps711x: Changing the compatibility string to match with the smallest supported chip
clocksource: clps711x: Changing the compatibility string to match with the smallest supported chip
clk: clps711x: Changing the compatibility string to match with the smallest supported chip
...
2016-08-01 18:36:01 -04:00
while ( ( readl_relaxed ( base + 0x4 ) & pd - > local_pwr_cfg ) ! = pwr ) {
2012-01-27 15:25:00 +09:00
if ( ! timeout ) {
op = ( power_on ) ? " enable " : " disable " ;
pr_err ( " Power domain %s %s failed \n " , domain - > name , op ) ;
return - ETIMEDOUT ;
}
timeout - - ;
cpu_relax ( ) ;
usleep_range ( 80 , 100 ) ;
}
2014-07-11 08:02:15 +09:00
2012-01-27 15:25:00 +09:00
return 0 ;
}
static int exynos_pd_power_on ( struct generic_pm_domain * domain )
{
return exynos_pd_power ( domain , true ) ;
}
static int exynos_pd_power_off ( struct generic_pm_domain * domain )
{
return exynos_pd_power ( domain , false ) ;
}
2021-01-13 12:03:20 +01:00
static const struct exynos_pm_domain_config exynos4210_cfg = {
2016-05-10 15:52:21 +02:00
. local_pwr_cfg = 0x7 ,
} ;
2021-01-13 12:03:20 +01:00
static const struct exynos_pm_domain_config exynos5433_cfg = {
2017-01-25 12:55:35 +01:00
. local_pwr_cfg = 0xf ,
} ;
2021-01-13 12:03:20 +01:00
static const struct of_device_id exynos_pm_domain_of_match [ ] = {
2016-05-10 15:52:21 +02:00
{
. compatible = " samsung,exynos4210-pd " ,
. data = & exynos4210_cfg ,
2017-01-25 12:55:35 +01:00
} , {
. compatible = " samsung,exynos5433-pd " ,
. data = & exynos5433_cfg ,
2016-05-10 15:52:21 +02:00
} ,
{ } ,
} ;
2021-01-13 12:03:20 +01:00
static const char * exynos_get_domain_name ( struct device_node * node )
2017-01-30 13:18:59 +01:00
{
const char * name ;
if ( of_property_read_string ( node , " label " , & name ) < 0 )
2017-07-18 16:43:30 -05:00
name = kbasename ( node - > full_name ) ;
2017-01-30 13:18:59 +01:00
return kstrdup_const ( name , GFP_KERNEL ) ;
}
2021-01-13 12:03:20 +01:00
static int exynos_pd_probe ( struct platform_device * pdev )
2012-01-27 15:25:00 +09:00
{
2021-01-13 12:03:20 +01:00
const struct exynos_pm_domain_config * pm_domain_cfg ;
struct device * dev = & pdev - > dev ;
struct device_node * np = dev - > of_node ;
struct of_phandle_args child , parent ;
struct exynos_pm_domain * pd ;
int on , ret ;
2012-11-22 00:21:17 +09:00
2021-01-13 12:03:20 +01:00
pm_domain_cfg = of_device_get_match_data ( dev ) ;
pd = devm_kzalloc ( dev , sizeof ( * pd ) , GFP_KERNEL ) ;
if ( ! pd )
return - ENOMEM ;
2016-05-10 15:52:21 +02:00
2021-01-13 12:03:20 +01:00
pd - > pd . name = exynos_get_domain_name ( np ) ;
if ( ! pd - > pd . name )
return - ENOMEM ;
2015-03-27 13:12:00 +01:00
2021-01-13 12:03:20 +01:00
pd - > base = of_iomap ( np , 0 ) ;
if ( ! pd - > base ) {
kfree_const ( pd - > pd . name ) ;
return - ENODEV ;
}
2012-11-22 00:21:08 +09:00
2021-01-13 12:03:20 +01:00
pd - > pd . power_off = exynos_pd_power_off ;
pd - > pd . power_on = exynos_pd_power_on ;
pd - > local_pwr_cfg = pm_domain_cfg - > local_pwr_cfg ;
2012-11-22 00:21:08 +09:00
2021-01-13 12:03:20 +01:00
on = readl_relaxed ( pd - > base + 0x4 ) & pd - > local_pwr_cfg ;
2012-11-22 00:21:17 +09:00
2021-01-13 12:03:20 +01:00
pm_genpd_init ( & pd - > pd , NULL , ! on ) ;
ret = of_genpd_add_provider_simple ( np , & pd - > pd ) ;
2015-02-04 23:44:15 +09:00
2021-01-13 12:03:20 +01:00
if ( ret = = 0 & & of_parse_phandle_with_args ( np , " power-domains " ,
" #power-domain-cells " , 0 , & parent ) = = 0 ) {
2016-09-12 12:01:06 +01:00
child . np = np ;
child . args_count = 0 ;
2015-02-04 23:44:15 +09:00
2016-09-12 12:01:06 +01:00
if ( of_genpd_add_subdomain ( & parent , & child ) )
2017-07-18 16:43:29 -05:00
pr_warn ( " %pOF failed to add subdomain: %pOF \n " ,
parent . np , child . np ) ;
2015-02-04 23:44:15 +09:00
else
2017-07-18 16:43:29 -05:00
pr_info ( " %pOF has as child subdomain: %pOF. \n " ,
parent . np , child . np ) ;
2015-02-04 23:44:15 +09:00
}
2021-01-13 12:03:20 +01:00
pm_runtime_enable ( dev ) ;
return ret ;
}
static struct platform_driver exynos_pd_driver = {
. probe = exynos_pd_probe ,
. driver = {
. name = " exynos-pd " ,
. of_match_table = exynos_pm_domain_of_match ,
. suppress_bind_attrs = true ,
}
} ;
static __init int exynos4_pm_init_power_domain ( void )
{
return platform_driver_register ( & exynos_pd_driver ) ;
2012-01-27 15:25:00 +09:00
}
2015-06-04 08:09:27 +09:00
core_initcall ( exynos4_pm_init_power_domain ) ;