clk: ingenic: Handle setting the Low-Power Mode bit

The Low-Power Mode, when enabled, will make the "wait" MIPS instruction
suspend the system.

This is not really clock-related, but this bit happens to be in the
register set of the CGU.

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
Signed-off-by: Stephen Boyd <sboyd@kernel.org>
This commit is contained in:
Paul Cercueil 2019-06-11 20:07:54 +02:00 committed by Stephen Boyd
parent dbc38ad0e7
commit 2ee93e3c95
7 changed files with 69 additions and 32 deletions

View File

@ -1,4 +1,4 @@
obj-$(CONFIG_INGENIC_CGU_COMMON) += cgu.o
obj-$(CONFIG_INGENIC_CGU_COMMON) += cgu.o pm.o
obj-$(CONFIG_INGENIC_CGU_JZ4740) += jz4740-cgu.o
obj-$(CONFIG_INGENIC_CGU_JZ4725B) += jz4725b-cgu.o
obj-$(CONFIG_INGENIC_CGU_JZ4770) += jz4770-cgu.o

View File

@ -11,6 +11,7 @@
#include <linux/of.h>
#include <dt-bindings/clock/jz4725b-cgu.h>
#include "cgu.h"
#include "pm.h"
/* CGU register offsets */
#define CGU_REG_CPCCR 0x00
@ -253,5 +254,7 @@ static void __init jz4725b_cgu_init(struct device_node *np)
retval = ingenic_cgu_register_clocks(cgu);
if (retval)
pr_err("%s: failed to register CGU Clocks\n", __func__);
ingenic_cgu_register_syscore_ops(cgu);
}
CLK_OF_DECLARE(jz4725b_cgu, "ingenic,jz4725b-cgu", jz4725b_cgu_init);

View File

@ -22,6 +22,7 @@
#include <dt-bindings/clock/jz4740-cgu.h>
#include <asm/mach-jz4740/clock.h>
#include "cgu.h"
#include "pm.h"
/* CGU register offsets */
#define CGU_REG_CPCCR 0x00
@ -247,6 +248,8 @@ static void __init jz4740_cgu_init(struct device_node *np)
retval = ingenic_cgu_register_clocks(cgu);
if (retval)
pr_err("%s: failed to register CGU Clocks\n", __func__);
ingenic_cgu_register_syscore_ops(cgu);
}
CLK_OF_DECLARE(jz4740_cgu, "ingenic,jz4740-cgu", jz4740_cgu_init);

View File

@ -9,9 +9,9 @@
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/syscore_ops.h>
#include <dt-bindings/clock/jz4770-cgu.h>
#include "cgu.h"
#include "pm.h"
/*
* CPM registers offset address definition
@ -38,9 +38,6 @@
#define CGU_REG_MSC2CDR 0xA8
#define CGU_REG_BCHCDR 0xAC
/* bits within the LCR register */
#define LCR_LPM BIT(0) /* Low Power Mode */
/* bits within the OPCR register */
#define OPCR_SPENDH BIT(5) /* UHC PHY suspend */
@ -429,30 +426,6 @@ static const struct ingenic_cgu_clk_info jz4770_cgu_clocks[] = {
},
};
#if IS_ENABLED(CONFIG_PM_SLEEP)
static int jz4770_cgu_pm_suspend(void)
{
u32 val;
val = readl(cgu->base + CGU_REG_LCR);
writel(val | LCR_LPM, cgu->base + CGU_REG_LCR);
return 0;
}
static void jz4770_cgu_pm_resume(void)
{
u32 val;
val = readl(cgu->base + CGU_REG_LCR);
writel(val & ~LCR_LPM, cgu->base + CGU_REG_LCR);
}
static struct syscore_ops jz4770_cgu_pm_ops = {
.suspend = jz4770_cgu_pm_suspend,
.resume = jz4770_cgu_pm_resume,
};
#endif /* CONFIG_PM_SLEEP */
static void __init jz4770_cgu_init(struct device_node *np)
{
int retval;
@ -466,9 +439,7 @@ static void __init jz4770_cgu_init(struct device_node *np)
if (retval)
pr_err("%s: failed to register CGU Clocks\n", __func__);
#if IS_ENABLED(CONFIG_PM_SLEEP)
register_syscore_ops(&jz4770_cgu_pm_ops);
#endif
ingenic_cgu_register_syscore_ops(cgu);
}
/* We only probe via devicetree, no need for a platform driver */

View File

@ -21,6 +21,7 @@
#include <linux/of.h>
#include <dt-bindings/clock/jz4780-cgu.h>
#include "cgu.h"
#include "pm.h"
/* CGU register offsets */
#define CGU_REG_CLOCKCONTROL 0x00
@ -730,5 +731,7 @@ static void __init jz4780_cgu_init(struct device_node *np)
pr_err("%s: failed to register CGU Clocks\n", __func__);
return;
}
ingenic_cgu_register_syscore_ops(cgu);
}
CLK_OF_DECLARE(jz4780_cgu, "ingenic,jz4780-cgu", jz4780_cgu_init);

45
drivers/clk/ingenic/pm.c Normal file
View File

@ -0,0 +1,45 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2019 Paul Cercueil <paul@crapouillou.net>
*/
#include "cgu.h"
#include "pm.h"
#include <linux/io.h>
#include <linux/syscore_ops.h>
#define CGU_REG_LCR 0x04
#define LCR_LOW_POWER_MODE BIT(0)
static void __iomem * __maybe_unused ingenic_cgu_base;
static int __maybe_unused ingenic_cgu_pm_suspend(void)
{
u32 val = readl(ingenic_cgu_base + CGU_REG_LCR);
writel(val | LCR_LOW_POWER_MODE, ingenic_cgu_base + CGU_REG_LCR);
return 0;
}
static void __maybe_unused ingenic_cgu_pm_resume(void)
{
u32 val = readl(ingenic_cgu_base + CGU_REG_LCR);
writel(val & ~LCR_LOW_POWER_MODE, ingenic_cgu_base + CGU_REG_LCR);
}
static struct syscore_ops __maybe_unused ingenic_cgu_pm_ops = {
.suspend = ingenic_cgu_pm_suspend,
.resume = ingenic_cgu_pm_resume,
};
void ingenic_cgu_register_syscore_ops(struct ingenic_cgu *cgu)
{
if (IS_ENABLED(CONFIG_PM_SLEEP)) {
ingenic_cgu_base = cgu->base;
register_syscore_ops(&ingenic_cgu_pm_ops);
}
}

12
drivers/clk/ingenic/pm.h Normal file
View File

@ -0,0 +1,12 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) 2019 Paul Cercueil <paul@crapouillou.net>
*/
#ifndef DRIVERS_CLK_INGENIC_PM_H
#define DRIVERS_CLK_INGENIC_PM_H
struct ingenic_cgu;
void ingenic_cgu_register_syscore_ops(struct ingenic_cgu *cgu);
#endif /* DRIVERS_CLK_INGENIC_PM_H */