2012-01-27 10:25:00 +04:00
/*
* 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 .
*
* 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/err.h>
# include <linux/slab.h>
# include <linux/pm_domain.h>
2014-07-11 03:02:15 +04:00
# include <linux/clk.h>
2012-01-27 10:25:00 +04:00
# include <linux/delay.h>
# include <linux/of_address.h>
2012-11-21 19:21:17 +04:00
# include <linux/of_platform.h>
# include <linux/sched.h>
2012-01-27 10:25:00 +04:00
2014-07-11 03:02:15 +04:00
# define MAX_CLK_PER_DOMAIN 4
2016-05-10 16:52:21 +03:00
struct exynos_pm_domain_config {
/* Value for LOCAL_PWR_CFG and STATUS fields for each domain */
u32 local_pwr_cfg ;
} ;
2012-01-27 10:25:00 +04:00
/*
* Exynos specific wrapper around the generic power domain
*/
struct exynos_pm_domain {
void __iomem * base ;
char const * name ;
bool is_off ;
struct generic_pm_domain pd ;
2014-07-11 03:02:15 +04:00
struct clk * oscclk ;
struct clk * clk [ MAX_CLK_PER_DOMAIN ] ;
struct clk * pclk [ MAX_CLK_PER_DOMAIN ] ;
2015-03-17 20:12:23 +03:00
struct clk * asb_clk [ MAX_CLK_PER_DOMAIN ] ;
2016-05-10 16:52:21 +03:00
u32 local_pwr_cfg ;
2012-01-27 10:25:00 +04: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 ;
2015-03-17 20:12:23 +03:00
int i ;
2012-01-27 10:25:00 +04:00
pd = container_of ( domain , struct exynos_pm_domain , pd ) ;
base = pd - > base ;
2015-03-17 20:12:23 +03:00
for ( i = 0 ; i < MAX_CLK_PER_DOMAIN ; i + + ) {
if ( IS_ERR ( pd - > asb_clk [ i ] ) )
break ;
clk_prepare_enable ( pd - > asb_clk [ i ] ) ;
}
2014-07-11 03:02:15 +04:00
/* Set oscclk before powering off a domain*/
if ( ! power_on ) {
for ( i = 0 ; i < MAX_CLK_PER_DOMAIN ; i + + ) {
if ( IS_ERR ( pd - > clk [ i ] ) )
break ;
2015-04-03 12:25:54 +03:00
pd - > pclk [ i ] = clk_get_parent ( pd - > clk [ i ] ) ;
2014-07-11 03:02:15 +04:00
if ( clk_set_parent ( pd - > clk [ i ] , pd - > oscclk ) )
pr_err ( " %s: error setting oscclk as parent to clock %d \n " ,
pd - > name , i ) ;
}
}
2016-05-10 16:52:21 +03:00
pwr = power_on ? pd - > local_pwr_cfg : 0 ;
2016-06-21 13:20:25 +03:00
writel_relaxed ( pwr , base ) ;
2012-01-27 10:25:00 +04: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-02 01:36:01 +03:00
while ( ( readl_relaxed ( base + 0x4 ) & pd - > local_pwr_cfg ) ! = pwr ) {
2012-01-27 10:25:00 +04: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 03:02:15 +04:00
/* Restore clocks after powering on a domain*/
if ( power_on ) {
for ( i = 0 ; i < MAX_CLK_PER_DOMAIN ; i + + ) {
if ( IS_ERR ( pd - > clk [ i ] ) )
break ;
2015-04-03 12:25:54 +03:00
2016-04-22 10:26:52 +03:00
if ( IS_ERR ( pd - > pclk [ i ] ) )
2015-04-03 12:25:54 +03:00
continue ; /* Skip on first power up */
2014-07-11 03:02:15 +04:00
if ( clk_set_parent ( pd - > clk [ i ] , pd - > pclk [ i ] ) )
pr_err ( " %s: error setting parent to clock%d \n " ,
pd - > name , i ) ;
}
}
2015-03-17 20:12:23 +03:00
for ( i = 0 ; i < MAX_CLK_PER_DOMAIN ; i + + ) {
if ( IS_ERR ( pd - > asb_clk [ i ] ) )
break ;
clk_disable_unprepare ( pd - > asb_clk [ i ] ) ;
}
2012-01-27 10:25:00 +04: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 ) ;
}
2016-05-10 16:52:21 +03:00
static const struct exynos_pm_domain_config exynos4210_cfg __initconst = {
. local_pwr_cfg = 0x7 ,
} ;
static const struct of_device_id exynos_pm_domain_of_match [ ] __initconst = {
{
. compatible = " samsung,exynos4210-pd " ,
. data = & exynos4210_cfg ,
} ,
{ } ,
} ;
2013-06-15 04:13:25 +04:00
static __init int exynos4_pm_init_power_domain ( void )
2012-01-27 10:25:00 +04:00
{
struct device_node * np ;
2016-05-10 16:52:21 +03:00
const struct of_device_id * match ;
2012-01-27 10:25:00 +04:00
2016-05-10 16:52:21 +03:00
for_each_matching_node_and_match ( np , exynos_pm_domain_of_match , & match ) {
const struct exynos_pm_domain_config * pm_domain_cfg ;
2012-01-27 10:25:00 +04:00
struct exynos_pm_domain * pd ;
2014-07-11 03:02:15 +04:00
int on , i ;
2012-11-21 19:21:17 +04:00
2016-05-10 16:52:21 +03:00
pm_domain_cfg = match - > data ;
2012-01-27 10:25:00 +04:00
pd = kzalloc ( sizeof ( * pd ) , GFP_KERNEL ) ;
if ( ! pd ) {
pr_err ( " %s: failed to allocate memory for domain \n " ,
__func__ ) ;
2015-03-27 15:21:28 +03:00
of_node_put ( np ) ;
2012-01-27 10:25:00 +04:00
return - ENOMEM ;
}
2015-06-04 02:09:27 +03:00
pd - > pd . name = kstrdup_const ( strrchr ( np - > full_name , ' / ' ) + 1 ,
GFP_KERNEL ) ;
2015-03-27 15:12:00 +03:00
if ( ! pd - > pd . name ) {
kfree ( pd ) ;
of_node_put ( np ) ;
return - ENOMEM ;
}
2012-11-21 19:21:12 +04:00
pd - > name = pd - > pd . name ;
2012-01-27 10:25:00 +04:00
pd - > base = of_iomap ( np , 0 ) ;
2015-03-27 15:10:06 +03:00
if ( ! pd - > base ) {
2015-06-04 02:09:27 +03:00
pr_warn ( " %s: failed to map memory \n " , __func__ ) ;
2015-07-31 03:09:49 +03:00
kfree_const ( pd - > pd . name ) ;
2015-03-27 15:10:06 +03:00
kfree ( pd ) ;
continue ;
}
2012-01-27 10:25:00 +04:00
pd - > pd . power_off = exynos_pd_power_off ;
pd - > pd . power_on = exynos_pd_power_on ;
2016-05-10 16:52:21 +03:00
pd - > local_pwr_cfg = pm_domain_cfg - > local_pwr_cfg ;
2012-11-21 19:21:08 +04:00
2015-03-17 20:12:23 +03:00
for ( i = 0 ; i < MAX_CLK_PER_DOMAIN ; i + + ) {
char clk_name [ 8 ] ;
snprintf ( clk_name , sizeof ( clk_name ) , " asb%d " , i ) ;
2015-06-04 02:09:27 +03:00
pd - > asb_clk [ i ] = of_clk_get_by_name ( np , clk_name ) ;
2015-03-17 20:12:23 +03:00
if ( IS_ERR ( pd - > asb_clk [ i ] ) )
break ;
}
2015-06-04 02:09:27 +03:00
pd - > oscclk = of_clk_get_by_name ( np , " oscclk " ) ;
2014-07-11 03:02:15 +04:00
if ( IS_ERR ( pd - > oscclk ) )
goto no_clk ;
for ( i = 0 ; i < MAX_CLK_PER_DOMAIN ; i + + ) {
char clk_name [ 8 ] ;
snprintf ( clk_name , sizeof ( clk_name ) , " clk%d " , i ) ;
2015-06-04 02:09:27 +03:00
pd - > clk [ i ] = of_clk_get_by_name ( np , clk_name ) ;
2014-07-11 03:02:15 +04:00
if ( IS_ERR ( pd - > clk [ i ] ) )
break ;
2015-04-03 12:25:54 +03:00
/*
* Skip setting parent on first power up .
* The parent at this time may not be useful at all .
*/
pd - > pclk [ i ] = ERR_PTR ( - EINVAL ) ;
2014-07-11 03:02:15 +04:00
}
if ( IS_ERR ( pd - > clk [ 0 ] ) )
clk_put ( pd - > oscclk ) ;
no_clk :
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-02 01:36:01 +03:00
on = readl_relaxed ( pd - > base + 0x4 ) & pd - > local_pwr_cfg ;
2012-11-21 19:21:08 +04:00
pm_genpd_init ( & pd - > pd , NULL , ! on ) ;
2014-09-19 22:27:43 +04:00
of_genpd_add_provider_simple ( np , & pd - > pd ) ;
2012-01-27 10:25:00 +04:00
}
2012-11-21 19:21:17 +04:00
2015-02-04 17:44:15 +03:00
/* Assign the child power domains to their parents */
2016-05-10 16:52:21 +03:00
for_each_matching_node ( np , exynos_pm_domain_of_match ) {
2016-09-12 14:01:06 +03:00
struct of_phandle_args child , parent ;
2015-02-04 17:44:15 +03:00
2016-09-12 14:01:06 +03:00
child . np = np ;
child . args_count = 0 ;
2015-02-04 17:44:15 +03:00
if ( of_parse_phandle_with_args ( np , " power-domains " ,
2016-09-12 14:01:06 +03:00
" #power-domain-cells " , 0 ,
& parent ) ! = 0 )
2015-10-12 22:32:49 +03:00
continue ;
2015-02-04 17:44:15 +03:00
2016-09-12 14:01:06 +03:00
if ( of_genpd_add_subdomain ( & parent , & child ) )
2015-02-04 17:44:15 +03:00
pr_warn ( " %s failed to add subdomain: %s \n " ,
2016-09-12 14:01:06 +03:00
parent . np - > name , child . np - > name ) ;
2015-02-04 17:44:15 +03:00
else
pr_info ( " %s has as child subdomain: %s. \n " ,
2016-09-12 14:01:06 +03:00
parent . np - > name , child . np - > name ) ;
2015-02-04 17:44:15 +03:00
}
2012-01-27 10:25:00 +04:00
return 0 ;
}
2015-06-04 02:09:27 +03:00
core_initcall ( exynos4_pm_init_power_domain ) ;