diff mbox series

soc: samsung: pm_domains: Convert to regular platform driver

Message ID 20210113110320.13149-1-m.szyprowski@samsung.com (mailing list archive)
State Accepted
Commit f9e152f183105567e050b08cd666e12a0661e635
Headers show
Series soc: samsung: pm_domains: Convert to regular platform driver | expand

Commit Message

Marek Szyprowski Jan. 13, 2021, 11:03 a.m. UTC
When Exynos power domain driver was introduced, the only way to ensure
that power domains will be instantiated before the devices which belongs
to them was to initialize them early enough, before the devices are
instantiated in the system. This in turn required not to use any platform
device infrastructure at all, as there have been no way to ensure proper
probe order between devices.

This has been finally changed and patch e590474768f1 ("driver core: Set
fw_devlink=on by default") ensures that each device will be probbed only
when its resource providers are ready. This allows to convert Exynos
power domain driver to regular platform driver.

This is also required by the mentioned commit to enable probing any
device which belongs to the Exynos power domains, as otherwise the core
won't notice that the power domains are in fact available.

Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
---
Some more comments are in the following thread:
https://lore.kernel.org/lkml/2556a69b-5da5-bf80-e051-df2d02fbc40f@samsung.com/
---
 drivers/soc/samsung/pm_domains.c | 97 ++++++++++++++++----------------
 1 file changed, 48 insertions(+), 49 deletions(-)

Comments

Saravana Kannan Jan. 13, 2021, 8:27 p.m. UTC | #1
On Wed, Jan 13, 2021 at 3:03 AM Marek Szyprowski
<m.szyprowski@samsung.com> wrote:
>
> When Exynos power domain driver was introduced, the only way to ensure
> that power domains will be instantiated before the devices which belongs
> to them was to initialize them early enough, before the devices are
> instantiated in the system. This in turn required not to use any platform
> device infrastructure at all, as there have been no way to ensure proper
> probe order between devices.
>
> This has been finally changed and patch e590474768f1 ("driver core: Set
> fw_devlink=on by default") ensures that each device will be probbed only
> when its resource providers are ready. This allows to convert Exynos
> power domain driver to regular platform driver.
>
> This is also required by the mentioned commit to enable probing any
> device which belongs to the Exynos power domains, as otherwise the core
> won't notice that the power domains are in fact available.
>
> Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
> ---
> Some more comments are in the following thread:
> https://lore.kernel.org/lkml/2556a69b-5da5-bf80-e051-df2d02fbc40f@samsung.com/
> ---
>  drivers/soc/samsung/pm_domains.c | 97 ++++++++++++++++----------------
>  1 file changed, 48 insertions(+), 49 deletions(-)
>
> diff --git a/drivers/soc/samsung/pm_domains.c b/drivers/soc/samsung/pm_domains.c
> index ab8582971bfc..5ec0c13f0aaf 100644
> --- a/drivers/soc/samsung/pm_domains.c
> +++ b/drivers/soc/samsung/pm_domains.c
> @@ -16,7 +16,7 @@
>  #include <linux/delay.h>
>  #include <linux/of_address.h>
>  #include <linux/of_platform.h>
> -#include <linux/sched.h>
> +#include <linux/pm_runtime.h>
>
>  struct exynos_pm_domain_config {
>         /* Value for LOCAL_PWR_CFG and STATUS fields for each domain */
> @@ -73,15 +73,15 @@ static int exynos_pd_power_off(struct generic_pm_domain *domain)
>         return exynos_pd_power(domain, false);
>  }
>
> -static const struct exynos_pm_domain_config exynos4210_cfg __initconst = {
> +static const struct exynos_pm_domain_config exynos4210_cfg = {
>         .local_pwr_cfg          = 0x7,
>  };
>
> -static const struct exynos_pm_domain_config exynos5433_cfg __initconst = {
> +static const struct exynos_pm_domain_config exynos5433_cfg = {
>         .local_pwr_cfg          = 0xf,
>  };
>
> -static const struct of_device_id exynos_pm_domain_of_match[] __initconst = {
> +static const struct of_device_id exynos_pm_domain_of_match[] = {
>         {
>                 .compatible = "samsung,exynos4210-pd",
>                 .data = &exynos4210_cfg,
> @@ -92,7 +92,7 @@ static const struct of_device_id exynos_pm_domain_of_match[] __initconst = {
>         { },
>  };
>
> -static __init const char *exynos_get_domain_name(struct device_node *node)
> +static const char *exynos_get_domain_name(struct device_node *node)
>  {
>         const char *name;
>
> @@ -101,60 +101,44 @@ static __init const char *exynos_get_domain_name(struct device_node *node)
>         return kstrdup_const(name, GFP_KERNEL);
>  }
>
> -static __init int exynos4_pm_init_power_domain(void)
> +static int exynos_pd_probe(struct platform_device *pdev)
>  {
> -       struct device_node *np;
> -       const struct of_device_id *match;
> -
> -       for_each_matching_node_and_match(np, exynos_pm_domain_of_match, &match) {
> -               const struct exynos_pm_domain_config *pm_domain_cfg;
> -               struct exynos_pm_domain *pd;
> -               int on;
> +       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;
>
> -               pm_domain_cfg = match->data;
> +       pm_domain_cfg = of_device_get_match_data(dev);
> +       pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL);
> +       if (!pd)
> +               return -ENOMEM;
>
> -               pd = kzalloc(sizeof(*pd), GFP_KERNEL);
> -               if (!pd) {
> -                       of_node_put(np);
> -                       return -ENOMEM;
> -               }
> -               pd->pd.name = exynos_get_domain_name(np);
> -               if (!pd->pd.name) {
> -                       kfree(pd);
> -                       of_node_put(np);
> -                       return -ENOMEM;
> -               }
> +       pd->pd.name = exynos_get_domain_name(np);
> +       if (!pd->pd.name)
> +               return -ENOMEM;
>
> -               pd->base = of_iomap(np, 0);
> -               if (!pd->base) {
> -                       pr_warn("%s: failed to map memory\n", __func__);
> -                       kfree_const(pd->pd.name);
> -                       kfree(pd);
> -                       continue;
> -               }
> -
> -               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;
> +       pd->base = of_iomap(np, 0);
> +       if (!pd->base) {
> +               kfree_const(pd->pd.name);
> +               return -ENODEV;
> +       }
>
> -               on = readl_relaxed(pd->base + 0x4) & pd->local_pwr_cfg;
> +       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;
>
> -               pm_genpd_init(&pd->pd, NULL, !on);
> -               of_genpd_add_provider_simple(np, &pd->pd);
> -       }
> +       on = readl_relaxed(pd->base + 0x4) & pd->local_pwr_cfg;
>
> -       /* Assign the child power domains to their parents */
> -       for_each_matching_node(np, exynos_pm_domain_of_match) {
> -               struct of_phandle_args child, parent;
> +       pm_genpd_init(&pd->pd, NULL, !on);
> +       ret = of_genpd_add_provider_simple(np, &pd->pd);
>
> +       if (ret == 0 && of_parse_phandle_with_args(np, "power-domains",
> +                                     "#power-domain-cells", 0, &parent) == 0) {
>                 child.np = np;
>                 child.args_count = 0;
>
> -               if (of_parse_phandle_with_args(np, "power-domains",
> -                                              "#power-domain-cells", 0,
> -                                              &parent) != 0)
> -                       continue;
> -
>                 if (of_genpd_add_subdomain(&parent, &child))
>                         pr_warn("%pOF failed to add subdomain: %pOF\n",
>                                 parent.np, child.np);
> @@ -163,6 +147,21 @@ static __init int exynos4_pm_init_power_domain(void)
>                                 parent.np, child.np);
>         }
>
> -       return 0;
> +       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);
>  }
>  core_initcall(exynos4_pm_init_power_domain);
> --
> 2.17.1
>

Skimmed through this patch and at a high level, it looks good for what
it's trying to do. Thanks for doing this!

Btw, I assume that this won't work with fw_devlink=off/permissive
(default since 5.10 or earlier)? My concern is that we might
temporarily set fw_devlink=permissive by default if the other
breakages aren't fixed in time for 5.12? How do you want to handle that?

-Saravana
Marek Szyprowski Jan. 14, 2021, 7:03 p.m. UTC | #2
Hi Saravana,

On 13.01.2021 21:27, Saravana Kannan wrote:
> On Wed, Jan 13, 2021 at 3:03 AM Marek Szyprowski
> <m.szyprowski@samsung.com> wrote:
>> When Exynos power domain driver was introduced, the only way to ensure
>> that power domains will be instantiated before the devices which belongs
>> to them was to initialize them early enough, before the devices are
>> instantiated in the system. This in turn required not to use any platform
>> device infrastructure at all, as there have been no way to ensure proper
>> probe order between devices.
>>
>> This has been finally changed and patch e590474768f1 ("driver core: Set
>> fw_devlink=on by default") ensures that each device will be probbed only
>> when its resource providers are ready. This allows to convert Exynos
>> power domain driver to regular platform driver.
>>
>> This is also required by the mentioned commit to enable probing any
>> device which belongs to the Exynos power domains, as otherwise the core
>> won't notice that the power domains are in fact available.
>>
>> Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
>> ---
>> Some more comments are in the following thread:
>> https://protect2.fireeye.com/v1/url?k=8ac052ac-d55b6ba4-8ac1d9e3-0cc47a31c8b4-9068b559b0fd155d&q=1&e=b393c3ff-16ba-48a4-9d72-6805d02971d5&u=https%3A%2F%2Flore.kernel.org%2Flkml%2F2556a69b-5da5-bf80-e051-df2d02fbc40f%40samsung.com%2F
>> ---
>> ...
> Skimmed through this patch and at a high level, it looks good for what
> it's trying to do. Thanks for doing this!
>
> Btw, I assume that this won't work with fw_devlink=off/permissive
> (default since 5.10 or earlier)? My concern is that we might
> temporarily set fw_devlink=permissive by default if the other
> breakages aren't fixed in time for 5.12? How do you want to handle that?

I've applied my patch on top of vanilla v5.10 and checked on my test 
boards. Surprisingly everything works fine, so something must have been 
changed during the last few years as the power domain driver in the 
current form has been written long time ago. I remember that the moment 
when platform devices are created from the of nodes has been change at 
some point, so maybe this is somehow related. Anyway, the platform 
driver for Exynos power domains registered from core_initcall works fine 
with v5.10 kernel.

I have no strong opinion on the way of merging this fix. It can go via 
Samsung tree, so in the end the v5.12-rc1 will have both my fix and your 
change, but won't be fully bisectable in-between. Krzysztof, what's your 
opinion?

Best regards
Saravana Kannan Jan. 14, 2021, 7:07 p.m. UTC | #3
On Thu, Jan 14, 2021 at 11:03 AM Marek Szyprowski
<m.szyprowski@samsung.com> wrote:
>
> Hi Saravana,
>
> On 13.01.2021 21:27, Saravana Kannan wrote:
> > On Wed, Jan 13, 2021 at 3:03 AM Marek Szyprowski
> > <m.szyprowski@samsung.com> wrote:
> >> When Exynos power domain driver was introduced, the only way to ensure
> >> that power domains will be instantiated before the devices which belongs
> >> to them was to initialize them early enough, before the devices are
> >> instantiated in the system. This in turn required not to use any platform
> >> device infrastructure at all, as there have been no way to ensure proper
> >> probe order between devices.
> >>
> >> This has been finally changed and patch e590474768f1 ("driver core: Set
> >> fw_devlink=on by default") ensures that each device will be probbed only
> >> when its resource providers are ready. This allows to convert Exynos
> >> power domain driver to regular platform driver.
> >>
> >> This is also required by the mentioned commit to enable probing any
> >> device which belongs to the Exynos power domains, as otherwise the core
> >> won't notice that the power domains are in fact available.
> >>
> >> Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
> >> ---
> >> Some more comments are in the following thread:
> >> https://protect2.fireeye.com/v1/url?k=8ac052ac-d55b6ba4-8ac1d9e3-0cc47a31c8b4-9068b559b0fd155d&q=1&e=b393c3ff-16ba-48a4-9d72-6805d02971d5&u=https%3A%2F%2Flore.kernel.org%2Flkml%2F2556a69b-5da5-bf80-e051-df2d02fbc40f%40samsung.com%2F
> >> ---
> >> ...
> > Skimmed through this patch and at a high level, it looks good for what
> > it's trying to do. Thanks for doing this!
> >
> > Btw, I assume that this won't work with fw_devlink=off/permissive
> > (default since 5.10 or earlier)? My concern is that we might
> > temporarily set fw_devlink=permissive by default if the other
> > breakages aren't fixed in time for 5.12? How do you want to handle that?
>
> I've applied my patch on top of vanilla v5.10 and checked on my test
> boards. Surprisingly everything works fine, so something must have been
> changed during the last few years as the power domain driver in the
> current form has been written long time ago. I remember that the moment
> when platform devices are created from the of nodes has been change at
> some point, so maybe this is somehow related. Anyway, the platform
> driver for Exynos power domains registered from core_initcall works fine
> with v5.10 kernel.
>
> I have no strong opinion on the way of merging this fix. It can go via
> Samsung tree, so in the end the v5.12-rc1 will have both my fix and your
> change, but won't be fully bisectable in-between. Krzysztof, what's your
> opinion?

If it doesn't break anything without my changes, then let's try to get
it merged independent of my series. This is a good change even without
my changes.

-Saravana
Krzysztof Kozlowski Jan. 15, 2021, 3:15 p.m. UTC | #4
On Thu, Jan 14, 2021 at 11:07:30AM -0800, Saravana Kannan wrote:
> On Thu, Jan 14, 2021 at 11:03 AM Marek Szyprowski
> <m.szyprowski@samsung.com> wrote:
> >
> > Hi Saravana,
> >
> > On 13.01.2021 21:27, Saravana Kannan wrote:
> > > On Wed, Jan 13, 2021 at 3:03 AM Marek Szyprowski
> > > <m.szyprowski@samsung.com> wrote:
> > >> When Exynos power domain driver was introduced, the only way to ensure
> > >> that power domains will be instantiated before the devices which belongs
> > >> to them was to initialize them early enough, before the devices are
> > >> instantiated in the system. This in turn required not to use any platform
> > >> device infrastructure at all, as there have been no way to ensure proper
> > >> probe order between devices.
> > >>
> > >> This has been finally changed and patch e590474768f1 ("driver core: Set
> > >> fw_devlink=on by default") ensures that each device will be probbed only
> > >> when its resource providers are ready. This allows to convert Exynos
> > >> power domain driver to regular platform driver.
> > >>
> > >> This is also required by the mentioned commit to enable probing any
> > >> device which belongs to the Exynos power domains, as otherwise the core
> > >> won't notice that the power domains are in fact available.
> > >>
> > >> Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
> > >> ---
> > >> Some more comments are in the following thread:
> > >> https://protect2.fireeye.com/v1/url?k=8ac052ac-d55b6ba4-8ac1d9e3-0cc47a31c8b4-9068b559b0fd155d&q=1&e=b393c3ff-16ba-48a4-9d72-6805d02971d5&u=https%3A%2F%2Flore.kernel.org%2Flkml%2F2556a69b-5da5-bf80-e051-df2d02fbc40f%40samsung.com%2F
> > >> ---
> > >> ...
> > > Skimmed through this patch and at a high level, it looks good for what
> > > it's trying to do. Thanks for doing this!
> > >
> > > Btw, I assume that this won't work with fw_devlink=off/permissive
> > > (default since 5.10 or earlier)? My concern is that we might
> > > temporarily set fw_devlink=permissive by default if the other
> > > breakages aren't fixed in time for 5.12? How do you want to handle that?
> >
> > I've applied my patch on top of vanilla v5.10 and checked on my test
> > boards. Surprisingly everything works fine, so something must have been
> > changed during the last few years as the power domain driver in the
> > current form has been written long time ago. I remember that the moment
> > when platform devices are created from the of nodes has been change at
> > some point, so maybe this is somehow related. Anyway, the platform
> > driver for Exynos power domains registered from core_initcall works fine
> > with v5.10 kernel.
> >
> > I have no strong opinion on the way of merging this fix. It can go via
> > Samsung tree, so in the end the v5.12-rc1 will have both my fix and your
> > change, but won't be fully bisectable in-between. Krzysztof, what's your
> > opinion?
> 
> If it doesn't break anything without my changes, then let's try to get
> it merged independent of my series. This is a good change even without
> my changes.

I agree, I'll take it via Samsung SoC. It's not the perfect solution -
as Marek said, the tree won't be bisectable. Have in mind that some
other boards/architectures might be broken where no one reported it yet,
so fw_devlink=off/permissive might still be good choice for v5.12.

Best regards,
Krzysztof
Krzysztof Kozlowski Jan. 15, 2021, 5:04 p.m. UTC | #5
On Wed, 13 Jan 2021 12:03:20 +0100, Marek Szyprowski wrote:
> When Exynos power domain driver was introduced, the only way to ensure
> that power domains will be instantiated before the devices which belongs
> to them was to initialize them early enough, before the devices are
> instantiated in the system. This in turn required not to use any platform
> device infrastructure at all, as there have been no way to ensure proper
> probe order between devices.
> 
> [...]

Applied, thanks!

[1/1] soc: samsung: pm_domains: Convert to regular platform driver
      commit: 9fcdb21857cf42c0da7b9a929e6781eca557a2f5

Best regards,
Krzysztof Kozlowski Jan. 16, 2021, 8:25 a.m. UTC | #6
On Fri, Jan 15, 2021 at 01:11:36PM -0800, Saravana Kannan wrote:
> Hi Krzysztof,
> 
> When you pull this in, can you please add this tag too for completeness?
> 
> Fixes: e590474768f1 ("driver core: Set fw_devlink=on by default")

I actually removed that commit SHA from the message because it's still
only in next. It might not be valid and I don't have a control whether
it will be changed or not.

Best regards,
Krzysztof
diff mbox series

Patch

diff --git a/drivers/soc/samsung/pm_domains.c b/drivers/soc/samsung/pm_domains.c
index ab8582971bfc..5ec0c13f0aaf 100644
--- a/drivers/soc/samsung/pm_domains.c
+++ b/drivers/soc/samsung/pm_domains.c
@@ -16,7 +16,7 @@ 
 #include <linux/delay.h>
 #include <linux/of_address.h>
 #include <linux/of_platform.h>
-#include <linux/sched.h>
+#include <linux/pm_runtime.h>
 
 struct exynos_pm_domain_config {
 	/* Value for LOCAL_PWR_CFG and STATUS fields for each domain */
@@ -73,15 +73,15 @@  static int exynos_pd_power_off(struct generic_pm_domain *domain)
 	return exynos_pd_power(domain, false);
 }
 
-static const struct exynos_pm_domain_config exynos4210_cfg __initconst = {
+static const struct exynos_pm_domain_config exynos4210_cfg = {
 	.local_pwr_cfg		= 0x7,
 };
 
-static const struct exynos_pm_domain_config exynos5433_cfg __initconst = {
+static const struct exynos_pm_domain_config exynos5433_cfg = {
 	.local_pwr_cfg		= 0xf,
 };
 
-static const struct of_device_id exynos_pm_domain_of_match[] __initconst = {
+static const struct of_device_id exynos_pm_domain_of_match[] = {
 	{
 		.compatible = "samsung,exynos4210-pd",
 		.data = &exynos4210_cfg,
@@ -92,7 +92,7 @@  static const struct of_device_id exynos_pm_domain_of_match[] __initconst = {
 	{ },
 };
 
-static __init const char *exynos_get_domain_name(struct device_node *node)
+static const char *exynos_get_domain_name(struct device_node *node)
 {
 	const char *name;
 
@@ -101,60 +101,44 @@  static __init const char *exynos_get_domain_name(struct device_node *node)
 	return kstrdup_const(name, GFP_KERNEL);
 }
 
-static __init int exynos4_pm_init_power_domain(void)
+static int exynos_pd_probe(struct platform_device *pdev)
 {
-	struct device_node *np;
-	const struct of_device_id *match;
-
-	for_each_matching_node_and_match(np, exynos_pm_domain_of_match, &match) {
-		const struct exynos_pm_domain_config *pm_domain_cfg;
-		struct exynos_pm_domain *pd;
-		int on;
+	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;
 
-		pm_domain_cfg = match->data;
+	pm_domain_cfg = of_device_get_match_data(dev);
+	pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL);
+	if (!pd)
+		return -ENOMEM;
 
-		pd = kzalloc(sizeof(*pd), GFP_KERNEL);
-		if (!pd) {
-			of_node_put(np);
-			return -ENOMEM;
-		}
-		pd->pd.name = exynos_get_domain_name(np);
-		if (!pd->pd.name) {
-			kfree(pd);
-			of_node_put(np);
-			return -ENOMEM;
-		}
+	pd->pd.name = exynos_get_domain_name(np);
+	if (!pd->pd.name)
+		return -ENOMEM;
 
-		pd->base = of_iomap(np, 0);
-		if (!pd->base) {
-			pr_warn("%s: failed to map memory\n", __func__);
-			kfree_const(pd->pd.name);
-			kfree(pd);
-			continue;
-		}
-
-		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;
+	pd->base = of_iomap(np, 0);
+	if (!pd->base) {
+		kfree_const(pd->pd.name);
+		return -ENODEV;
+	}
 
-		on = readl_relaxed(pd->base + 0x4) & pd->local_pwr_cfg;
+	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;
 
-		pm_genpd_init(&pd->pd, NULL, !on);
-		of_genpd_add_provider_simple(np, &pd->pd);
-	}
+	on = readl_relaxed(pd->base + 0x4) & pd->local_pwr_cfg;
 
-	/* Assign the child power domains to their parents */
-	for_each_matching_node(np, exynos_pm_domain_of_match) {
-		struct of_phandle_args child, parent;
+	pm_genpd_init(&pd->pd, NULL, !on);
+	ret = of_genpd_add_provider_simple(np, &pd->pd);
 
+	if (ret == 0 && of_parse_phandle_with_args(np, "power-domains",
+				      "#power-domain-cells", 0, &parent) == 0) {
 		child.np = np;
 		child.args_count = 0;
 
-		if (of_parse_phandle_with_args(np, "power-domains",
-					       "#power-domain-cells", 0,
-					       &parent) != 0)
-			continue;
-
 		if (of_genpd_add_subdomain(&parent, &child))
 			pr_warn("%pOF failed to add subdomain: %pOF\n",
 				parent.np, child.np);
@@ -163,6 +147,21 @@  static __init int exynos4_pm_init_power_domain(void)
 				parent.np, child.np);
 	}
 
-	return 0;
+	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);
 }
 core_initcall(exynos4_pm_init_power_domain);