#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/clk/renesas.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/of_address.h>
#include <linux/platform_device.h>
#include <linux/pm_clock.h>
#include <linux/pm_domain.h>
#include <linux/psci.h>
#include <linux/reset-controller.h>
#include <linux/slab.h>
#include <dt-bindings/clock/renesas-cpg-mssr.h>
#include "renesas-cpg-mssr.h"
#include "clk-div6.h"
#ifdef DEBUG
#define WARN_DEBUG …
#else
#define WARN_DEBUG(x) …
#endif
static const u16 mstpsr[] = …;
static const u16 mstpsr_for_gen4[] = …;
static const u16 smstpcr[] = …;
static const u16 mstpcr_for_gen4[] = …;
static const u16 stbcr[] = …;
static const u16 srcr[] = …;
static const u16 srcr_for_gen4[] = …;
static const u16 srstclr[] = …;
static const u16 srstclr_for_gen4[] = …;
struct cpg_mssr_priv { … };
static struct cpg_mssr_priv *cpg_mssr_priv;
struct mstp_clock { … };
#define to_mstp_clock(_hw) …
static int cpg_mstp_clock_endisable(struct clk_hw *hw, bool enable)
{ … }
static int cpg_mstp_clock_enable(struct clk_hw *hw)
{ … }
static void cpg_mstp_clock_disable(struct clk_hw *hw)
{ … }
static int cpg_mstp_clock_is_enabled(struct clk_hw *hw)
{ … }
static const struct clk_ops cpg_mstp_clock_ops = …;
static
struct clk *cpg_mssr_clk_src_twocell_get(struct of_phandle_args *clkspec,
void *data)
{ … }
static void __init cpg_mssr_register_core_clk(const struct cpg_core_clk *core,
const struct cpg_mssr_info *info,
struct cpg_mssr_priv *priv)
{ … }
static void __init cpg_mssr_register_mod_clk(const struct mssr_mod_clk *mod,
const struct cpg_mssr_info *info,
struct cpg_mssr_priv *priv)
{ … }
struct cpg_mssr_clk_domain { … };
static struct cpg_mssr_clk_domain *cpg_mssr_clk_domain;
static bool cpg_mssr_is_pm_clk(const struct of_phandle_args *clkspec,
struct cpg_mssr_clk_domain *pd)
{ … }
int cpg_mssr_attach_dev(struct generic_pm_domain *unused, struct device *dev)
{ … }
void cpg_mssr_detach_dev(struct generic_pm_domain *unused, struct device *dev)
{ … }
static void cpg_mssr_genpd_remove(void *data)
{ … }
static int __init cpg_mssr_add_clk_domain(struct device *dev,
const unsigned int *core_pm_clks,
unsigned int num_core_pm_clks)
{ … }
#ifdef CONFIG_RESET_CONTROLLER
#define rcdev_to_priv(x) …
static int cpg_mssr_reset(struct reset_controller_dev *rcdev,
unsigned long id)
{ … }
static int cpg_mssr_assert(struct reset_controller_dev *rcdev, unsigned long id)
{ … }
static int cpg_mssr_deassert(struct reset_controller_dev *rcdev,
unsigned long id)
{ … }
static int cpg_mssr_status(struct reset_controller_dev *rcdev,
unsigned long id)
{ … }
static const struct reset_control_ops cpg_mssr_reset_ops = …;
static int cpg_mssr_reset_xlate(struct reset_controller_dev *rcdev,
const struct of_phandle_args *reset_spec)
{ … }
static int cpg_mssr_reset_controller_register(struct cpg_mssr_priv *priv)
{ … }
#else
static inline int cpg_mssr_reset_controller_register(struct cpg_mssr_priv *priv)
{
return 0;
}
#endif
static const struct of_device_id cpg_mssr_match[] = …;
static void cpg_mssr_del_clk_provider(void *data)
{ … }
#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_ARM_PSCI_FW)
static int cpg_mssr_suspend_noirq(struct device *dev)
{
struct cpg_mssr_priv *priv = dev_get_drvdata(dev);
unsigned int reg;
if (!psci_ops.cpu_suspend)
return 0;
for (reg = 0; reg < ARRAY_SIZE(priv->smstpcr_saved); reg++) {
if (priv->smstpcr_saved[reg].mask)
priv->smstpcr_saved[reg].val =
priv->reg_layout == CLK_REG_LAYOUT_RZ_A ?
readb(priv->base + priv->control_regs[reg]) :
readl(priv->base + priv->control_regs[reg]);
}
raw_notifier_call_chain(&priv->notifiers, PM_EVENT_SUSPEND, NULL);
return 0;
}
static int cpg_mssr_resume_noirq(struct device *dev)
{
struct cpg_mssr_priv *priv = dev_get_drvdata(dev);
unsigned int reg;
u32 mask, oldval, newval;
int error;
if (!psci_ops.cpu_suspend)
return 0;
raw_notifier_call_chain(&priv->notifiers, PM_EVENT_RESUME, NULL);
for (reg = 0; reg < ARRAY_SIZE(priv->smstpcr_saved); reg++) {
mask = priv->smstpcr_saved[reg].mask;
if (!mask)
continue;
if (priv->reg_layout == CLK_REG_LAYOUT_RZ_A)
oldval = readb(priv->base + priv->control_regs[reg]);
else
oldval = readl(priv->base + priv->control_regs[reg]);
newval = oldval & ~mask;
newval |= priv->smstpcr_saved[reg].val & mask;
if (newval == oldval)
continue;
if (priv->reg_layout == CLK_REG_LAYOUT_RZ_A) {
writeb(newval, priv->base + priv->control_regs[reg]);
readb(priv->base + priv->control_regs[reg]);
barrier_data(priv->base + priv->control_regs[reg]);
continue;
} else
writel(newval, priv->base + priv->control_regs[reg]);
mask &= ~priv->smstpcr_saved[reg].val;
if (!mask)
continue;
error = readl_poll_timeout_atomic(priv->base + priv->status_regs[reg],
oldval, !(oldval & mask), 0, 10);
if (error)
dev_warn(dev, "Failed to enable SMSTP%u[0x%x]\n", reg,
oldval & mask);
}
return 0;
}
static const struct dev_pm_ops cpg_mssr_pm = {
SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(cpg_mssr_suspend_noirq,
cpg_mssr_resume_noirq)
};
#define DEV_PM_OPS …
#else
#define DEV_PM_OPS …
#endif
static void __init cpg_mssr_reserved_exit(struct cpg_mssr_priv *priv)
{ … }
static int __init cpg_mssr_reserved_init(struct cpg_mssr_priv *priv,
const struct cpg_mssr_info *info)
{ … }
static int __init cpg_mssr_common_init(struct device *dev,
struct device_node *np,
const struct cpg_mssr_info *info)
{ … }
void __init cpg_mssr_early_init(struct device_node *np,
const struct cpg_mssr_info *info)
{ … }
static int __init cpg_mssr_probe(struct platform_device *pdev)
{ … }
static struct platform_driver cpg_mssr_driver = …;
static int __init cpg_mssr_init(void)
{ … }
subsys_initcall(cpg_mssr_init);
void __init mssr_mod_nullify(struct mssr_mod_clk *mod_clks,
unsigned int num_mod_clks,
const unsigned int *clks, unsigned int n)
{ … }
MODULE_DESCRIPTION(…) …;