Skip to content

Commit

Permalink
ARM / shmobile: Support for I/O power domains for SH7372 (v9)
Browse files Browse the repository at this point in the history
Use the generic power domains support introduced by the previous
patch to implement support for power domains on SH7372.

Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
Acked-by: Paul Mundt <lethal@linux-sh.org>
  • Loading branch information
Rafael J. Wysocki committed Jul 2, 2011
1 parent 3d5c303 commit e3e0109
Show file tree
Hide file tree
Showing 4 changed files with 131 additions and 0 deletions.
1 change: 1 addition & 0 deletions arch/arm/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -642,6 +642,7 @@ config ARCH_SHMOBILE
select NO_IOPORT
select SPARSE_IRQ
select MULTI_IRQ_HANDLER
select PM_GENERIC_DOMAINS if PM
help
Support for Renesas's SH-Mobile and R-Mobile ARM platforms.

Expand Down
4 changes: 4 additions & 0 deletions arch/arm/mach-shmobile/board-mackerel.c
Original file line number Diff line number Diff line change
Expand Up @@ -1582,6 +1582,10 @@ static void __init mackerel_init(void)

platform_add_devices(mackerel_devices, ARRAY_SIZE(mackerel_devices));

sh7372_init_pm_domain(&sh7372_a4lc);
sh7372_add_device_to_domain(&sh7372_a4lc, &lcdc_device);
sh7372_add_device_to_domain(&sh7372_a4lc, &hdmi_lcdc_device);

hdmi_init_pm_clock();
sh7372_pm_init();
}
Expand Down
24 changes: 24 additions & 0 deletions arch/arm/mach-shmobile/include/mach/sh7372.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#define __ASM_SH7372_H__

#include <linux/sh_clk.h>
#include <linux/pm_domain.h>

/*
* Pin Function Controller:
Expand Down Expand Up @@ -470,4 +471,27 @@ extern struct clk sh7372_fsibck_clk;
extern struct clk sh7372_fsidiva_clk;
extern struct clk sh7372_fsidivb_clk;

struct platform_device;

struct sh7372_pm_domain {
struct generic_pm_domain genpd;
unsigned int bit_shift;
};

static inline struct sh7372_pm_domain *to_sh7372_pd(struct generic_pm_domain *d)
{
return container_of(d, struct sh7372_pm_domain, genpd);
}

#ifdef CONFIG_PM
extern struct sh7372_pm_domain sh7372_a4lc;

extern void sh7372_init_pm_domain(struct sh7372_pm_domain *sh7372_pd);
extern void sh7372_add_device_to_domain(struct sh7372_pm_domain *sh7372_pd,
struct platform_device *pdev);
#else
#define sh7372_init_pm_domain(pd) do { } while(0)
#define sh7372_add_device_to_domain(pd, pdev) do { } while(0)
#endif /* CONFIG_PM */

#endif /* __ASM_SH7372_H__ */
102 changes: 102 additions & 0 deletions arch/arm/mach-shmobile/pm-sh7372.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,118 @@
#include <linux/list.h>
#include <linux/err.h>
#include <linux/slab.h>
#include <linux/pm_runtime.h>
#include <linux/platform_device.h>
#include <linux/delay.h>
#include <asm/system.h>
#include <asm/io.h>
#include <asm/tlbflush.h>
#include <mach/common.h>
#include <mach/sh7372.h>

#define SMFRAM 0xe6a70000
#define SYSTBCR 0xe6150024
#define SBAR 0xe6180020
#define APARMBAREA 0xe6f10020

#define SPDCR 0xe6180008
#define SWUCR 0xe6180014
#define PSTR 0xe6180080

#define PSTR_RETRIES 100
#define PSTR_DELAY_US 10

#ifdef CONFIG_PM

static int pd_power_down(struct generic_pm_domain *genpd)
{
struct sh7372_pm_domain *sh7372_pd = to_sh7372_pd(genpd);
unsigned int mask = 1 << sh7372_pd->bit_shift;

if (__raw_readl(PSTR) & mask) {
unsigned int retry_count;

__raw_writel(mask, SPDCR);

for (retry_count = PSTR_RETRIES; retry_count; retry_count--) {
if (!(__raw_readl(SPDCR) & mask))
break;
cpu_relax();
}
}

pr_debug("sh7372 power domain down 0x%08x -> PSTR = 0x%08x\n",
mask, __raw_readl(PSTR));

return 0;
}

static int pd_power_up(struct generic_pm_domain *genpd)
{
struct sh7372_pm_domain *sh7372_pd = to_sh7372_pd(genpd);
unsigned int mask = 1 << sh7372_pd->bit_shift;
unsigned int retry_count;
int ret = 0;

if (__raw_readl(PSTR) & mask)
goto out;

__raw_writel(mask, SWUCR);

for (retry_count = 2 * PSTR_RETRIES; retry_count; retry_count--) {
if (!(__raw_readl(SWUCR) & mask))
goto out;
if (retry_count > PSTR_RETRIES)
udelay(PSTR_DELAY_US);
else
cpu_relax();
}
if (__raw_readl(SWUCR) & mask)
ret = -EIO;

out:
pr_debug("sh7372 power domain up 0x%08x -> PSTR = 0x%08x\n",
mask, __raw_readl(PSTR));

return ret;
}

static bool pd_active_wakeup(struct device *dev)
{
return true;
}

void sh7372_init_pm_domain(struct sh7372_pm_domain *sh7372_pd)
{
struct generic_pm_domain *genpd = &sh7372_pd->genpd;

pm_genpd_init(genpd, NULL, false);
genpd->stop_device = pm_clk_suspend;
genpd->start_device = pm_clk_resume;
genpd->active_wakeup = pd_active_wakeup;
genpd->power_off = pd_power_down;
genpd->power_on = pd_power_up;
pd_power_up(&sh7372_pd->genpd);
}

void sh7372_add_device_to_domain(struct sh7372_pm_domain *sh7372_pd,
struct platform_device *pdev)
{
struct device *dev = &pdev->dev;

if (!dev->power.subsys_data) {
pm_clk_init(dev);
pm_clk_add(dev, NULL);
}
pm_genpd_add_device(&sh7372_pd->genpd, dev);
}

struct sh7372_pm_domain sh7372_a4lc = {
.bit_shift = 1,
};

#endif /* CONFIG_PM */

static void sh7372_enter_core_standby(void)
{
void __iomem *smfram = (void __iomem *)SMFRAM;
Expand Down

0 comments on commit e3e0109

Please sign in to comment.