Merge branch 'clk-pm-runtime' into clk-next
* clk-pm-runtime: clk: samsung: exynos-audss: Add support for runtime PM clk: samsung: exynos-audss: Use local variable for controller's device clk: samsung: exynos5433: Add support for runtime PM clk: samsung: Add support for runtime PM clk: Add support for runtime PM
This commit is contained in:
commit
e7cc33358a
@ -33,6 +33,12 @@ Required Properties:
|
|||||||
- clock-names: Aliases for the above clocks. They should be "pll_ref",
|
- clock-names: Aliases for the above clocks. They should be "pll_ref",
|
||||||
"pll_in", "cdclk", "sclk_audio", and "sclk_pcm_in" respectively.
|
"pll_in", "cdclk", "sclk_audio", and "sclk_pcm_in" respectively.
|
||||||
|
|
||||||
|
Optional Properties:
|
||||||
|
|
||||||
|
- power-domains: a phandle to respective power domain node as described by
|
||||||
|
generic PM domain bindings (see power/power_domain.txt for more
|
||||||
|
information).
|
||||||
|
|
||||||
The following is the list of clocks generated by the controller. Each clock is
|
The following is the list of clocks generated by the controller. Each clock is
|
||||||
assigned an identifier and client nodes use this identifier to specify the
|
assigned an identifier and client nodes use this identifier to specify the
|
||||||
clock which they consume. Some of the clocks are available only on a particular
|
clock which they consume. Some of the clocks are available only on a particular
|
||||||
|
@ -168,6 +168,11 @@ Required Properties:
|
|||||||
- aclk_cam1_400
|
- aclk_cam1_400
|
||||||
- aclk_cam1_552
|
- aclk_cam1_552
|
||||||
|
|
||||||
|
Optional properties:
|
||||||
|
- power-domains: a phandle to respective power domain node as described by
|
||||||
|
generic PM domain bindings (see power/power_domain.txt for more
|
||||||
|
information).
|
||||||
|
|
||||||
Each clock is assigned an identifier and client nodes can use this identifier
|
Each clock is assigned an identifier and client nodes can use this identifier
|
||||||
to specify the clock which they consume.
|
to specify the clock which they consume.
|
||||||
|
|
||||||
@ -270,6 +275,7 @@ Example 2: Examples of clock controller nodes are listed below.
|
|||||||
clocks = <&xxti>,
|
clocks = <&xxti>,
|
||||||
<&cmu_top CLK_ACLK_G2D_266>,
|
<&cmu_top CLK_ACLK_G2D_266>,
|
||||||
<&cmu_top CLK_ACLK_G2D_400>;
|
<&cmu_top CLK_ACLK_G2D_400>;
|
||||||
|
power-domains = <&pd_g2d>;
|
||||||
};
|
};
|
||||||
|
|
||||||
cmu_disp: clock-controller@13b90000 {
|
cmu_disp: clock-controller@13b90000 {
|
||||||
@ -295,6 +301,7 @@ Example 2: Examples of clock controller nodes are listed below.
|
|||||||
<&cmu_mif CLK_SCLK_DECON_ECLK_DISP>,
|
<&cmu_mif CLK_SCLK_DECON_ECLK_DISP>,
|
||||||
<&cmu_mif CLK_SCLK_DECON_TV_VCLK_DISP>,
|
<&cmu_mif CLK_SCLK_DECON_TV_VCLK_DISP>,
|
||||||
<&cmu_mif CLK_ACLK_DISP_333>;
|
<&cmu_mif CLK_ACLK_DISP_333>;
|
||||||
|
power-domains = <&pd_disp>;
|
||||||
};
|
};
|
||||||
|
|
||||||
cmu_aud: clock-controller@114c0000 {
|
cmu_aud: clock-controller@114c0000 {
|
||||||
@ -304,6 +311,7 @@ Example 2: Examples of clock controller nodes are listed below.
|
|||||||
|
|
||||||
clock-names = "oscclk", "fout_aud_pll";
|
clock-names = "oscclk", "fout_aud_pll";
|
||||||
clocks = <&xxti>, <&cmu_top CLK_FOUT_AUD_PLL>;
|
clocks = <&xxti>, <&cmu_top CLK_FOUT_AUD_PLL>;
|
||||||
|
power-domains = <&pd_aud>;
|
||||||
};
|
};
|
||||||
|
|
||||||
cmu_bus0: clock-controller@13600000 {
|
cmu_bus0: clock-controller@13600000 {
|
||||||
@ -340,6 +348,7 @@ Example 2: Examples of clock controller nodes are listed below.
|
|||||||
|
|
||||||
clock-names = "oscclk", "aclk_g3d_400";
|
clock-names = "oscclk", "aclk_g3d_400";
|
||||||
clocks = <&xxti>, <&cmu_top CLK_ACLK_G3D_400>;
|
clocks = <&xxti>, <&cmu_top CLK_ACLK_G3D_400>;
|
||||||
|
power-domains = <&pd_g3d>;
|
||||||
};
|
};
|
||||||
|
|
||||||
cmu_gscl: clock-controller@13cf0000 {
|
cmu_gscl: clock-controller@13cf0000 {
|
||||||
@ -353,6 +362,7 @@ Example 2: Examples of clock controller nodes are listed below.
|
|||||||
clocks = <&xxti>,
|
clocks = <&xxti>,
|
||||||
<&cmu_top CLK_ACLK_GSCL_111>,
|
<&cmu_top CLK_ACLK_GSCL_111>,
|
||||||
<&cmu_top CLK_ACLK_GSCL_333>;
|
<&cmu_top CLK_ACLK_GSCL_333>;
|
||||||
|
power-domains = <&pd_gscl>;
|
||||||
};
|
};
|
||||||
|
|
||||||
cmu_apollo: clock-controller@11900000 {
|
cmu_apollo: clock-controller@11900000 {
|
||||||
@ -384,6 +394,7 @@ Example 2: Examples of clock controller nodes are listed below.
|
|||||||
clocks = <&xxti>,
|
clocks = <&xxti>,
|
||||||
<&cmu_top CLK_SCLK_JPEG_MSCL>,
|
<&cmu_top CLK_SCLK_JPEG_MSCL>,
|
||||||
<&cmu_top CLK_ACLK_MSCL_400>;
|
<&cmu_top CLK_ACLK_MSCL_400>;
|
||||||
|
power-domains = <&pd_mscl>;
|
||||||
};
|
};
|
||||||
|
|
||||||
cmu_mfc: clock-controller@15280000 {
|
cmu_mfc: clock-controller@15280000 {
|
||||||
@ -393,6 +404,7 @@ Example 2: Examples of clock controller nodes are listed below.
|
|||||||
|
|
||||||
clock-names = "oscclk", "aclk_mfc_400";
|
clock-names = "oscclk", "aclk_mfc_400";
|
||||||
clocks = <&xxti>, <&cmu_top CLK_ACLK_MFC_400>;
|
clocks = <&xxti>, <&cmu_top CLK_ACLK_MFC_400>;
|
||||||
|
power-domains = <&pd_mfc>;
|
||||||
};
|
};
|
||||||
|
|
||||||
cmu_hevc: clock-controller@14f80000 {
|
cmu_hevc: clock-controller@14f80000 {
|
||||||
@ -402,6 +414,7 @@ Example 2: Examples of clock controller nodes are listed below.
|
|||||||
|
|
||||||
clock-names = "oscclk", "aclk_hevc_400";
|
clock-names = "oscclk", "aclk_hevc_400";
|
||||||
clocks = <&xxti>, <&cmu_top CLK_ACLK_HEVC_400>;
|
clocks = <&xxti>, <&cmu_top CLK_ACLK_HEVC_400>;
|
||||||
|
power-domains = <&pd_hevc>;
|
||||||
};
|
};
|
||||||
|
|
||||||
cmu_isp: clock-controller@146d0000 {
|
cmu_isp: clock-controller@146d0000 {
|
||||||
@ -415,6 +428,7 @@ Example 2: Examples of clock controller nodes are listed below.
|
|||||||
clocks = <&xxti>,
|
clocks = <&xxti>,
|
||||||
<&cmu_top CLK_ACLK_ISP_DIS_400>,
|
<&cmu_top CLK_ACLK_ISP_DIS_400>,
|
||||||
<&cmu_top CLK_ACLK_ISP_400>;
|
<&cmu_top CLK_ACLK_ISP_400>;
|
||||||
|
power-domains = <&pd_isp>;
|
||||||
};
|
};
|
||||||
|
|
||||||
cmu_cam0: clock-controller@120d0000 {
|
cmu_cam0: clock-controller@120d0000 {
|
||||||
@ -430,6 +444,7 @@ Example 2: Examples of clock controller nodes are listed below.
|
|||||||
<&cmu_top CLK_ACLK_CAM0_333>,
|
<&cmu_top CLK_ACLK_CAM0_333>,
|
||||||
<&cmu_top CLK_ACLK_CAM0_400>,
|
<&cmu_top CLK_ACLK_CAM0_400>,
|
||||||
<&cmu_top CLK_ACLK_CAM0_552>;
|
<&cmu_top CLK_ACLK_CAM0_552>;
|
||||||
|
power-domains = <&pd_cam0>;
|
||||||
};
|
};
|
||||||
|
|
||||||
cmu_cam1: clock-controller@145d0000 {
|
cmu_cam1: clock-controller@145d0000 {
|
||||||
@ -451,6 +466,7 @@ Example 2: Examples of clock controller nodes are listed below.
|
|||||||
<&cmu_top CLK_ACLK_CAM1_333>,
|
<&cmu_top CLK_ACLK_CAM1_333>,
|
||||||
<&cmu_top CLK_ACLK_CAM1_400>,
|
<&cmu_top CLK_ACLK_CAM1_400>,
|
||||||
<&cmu_top CLK_ACLK_CAM1_552>;
|
<&cmu_top CLK_ACLK_CAM1_552>;
|
||||||
|
power-domains = <&pd_cam1>;
|
||||||
};
|
};
|
||||||
|
|
||||||
Example 3: UART controller node that consumes the clock generated by the clock
|
Example 3: UART controller node that consumes the clock generated by the clock
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
#include <linux/of.h>
|
#include <linux/of.h>
|
||||||
#include <linux/device.h>
|
#include <linux/device.h>
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
|
#include <linux/pm_runtime.h>
|
||||||
#include <linux/sched.h>
|
#include <linux/sched.h>
|
||||||
#include <linux/clkdev.h>
|
#include <linux/clkdev.h>
|
||||||
|
|
||||||
@ -46,6 +47,7 @@ struct clk_core {
|
|||||||
const struct clk_ops *ops;
|
const struct clk_ops *ops;
|
||||||
struct clk_hw *hw;
|
struct clk_hw *hw;
|
||||||
struct module *owner;
|
struct module *owner;
|
||||||
|
struct device *dev;
|
||||||
struct clk_core *parent;
|
struct clk_core *parent;
|
||||||
const char **parent_names;
|
const char **parent_names;
|
||||||
struct clk_core **parents;
|
struct clk_core **parents;
|
||||||
@ -87,6 +89,26 @@ struct clk {
|
|||||||
struct hlist_node clks_node;
|
struct hlist_node clks_node;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*** runtime pm ***/
|
||||||
|
static int clk_pm_runtime_get(struct clk_core *core)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
if (!core->dev)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
ret = pm_runtime_get_sync(core->dev);
|
||||||
|
return ret < 0 ? ret : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void clk_pm_runtime_put(struct clk_core *core)
|
||||||
|
{
|
||||||
|
if (!core->dev)
|
||||||
|
return;
|
||||||
|
|
||||||
|
pm_runtime_put_sync(core->dev);
|
||||||
|
}
|
||||||
|
|
||||||
/*** locking ***/
|
/*** locking ***/
|
||||||
static void clk_prepare_lock(void)
|
static void clk_prepare_lock(void)
|
||||||
{
|
{
|
||||||
@ -150,6 +172,8 @@ static void clk_enable_unlock(unsigned long flags)
|
|||||||
|
|
||||||
static bool clk_core_is_prepared(struct clk_core *core)
|
static bool clk_core_is_prepared(struct clk_core *core)
|
||||||
{
|
{
|
||||||
|
bool ret = false;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* .is_prepared is optional for clocks that can prepare
|
* .is_prepared is optional for clocks that can prepare
|
||||||
* fall back to software usage counter if it is missing
|
* fall back to software usage counter if it is missing
|
||||||
@ -157,11 +181,18 @@ static bool clk_core_is_prepared(struct clk_core *core)
|
|||||||
if (!core->ops->is_prepared)
|
if (!core->ops->is_prepared)
|
||||||
return core->prepare_count;
|
return core->prepare_count;
|
||||||
|
|
||||||
return core->ops->is_prepared(core->hw);
|
if (!clk_pm_runtime_get(core)) {
|
||||||
|
ret = core->ops->is_prepared(core->hw);
|
||||||
|
clk_pm_runtime_put(core);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool clk_core_is_enabled(struct clk_core *core)
|
static bool clk_core_is_enabled(struct clk_core *core)
|
||||||
{
|
{
|
||||||
|
bool ret = false;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* .is_enabled is only mandatory for clocks that gate
|
* .is_enabled is only mandatory for clocks that gate
|
||||||
* fall back to software usage counter if .is_enabled is missing
|
* fall back to software usage counter if .is_enabled is missing
|
||||||
@ -169,7 +200,29 @@ static bool clk_core_is_enabled(struct clk_core *core)
|
|||||||
if (!core->ops->is_enabled)
|
if (!core->ops->is_enabled)
|
||||||
return core->enable_count;
|
return core->enable_count;
|
||||||
|
|
||||||
return core->ops->is_enabled(core->hw);
|
/*
|
||||||
|
* Check if clock controller's device is runtime active before
|
||||||
|
* calling .is_enabled callback. If not, assume that clock is
|
||||||
|
* disabled, because we might be called from atomic context, from
|
||||||
|
* which pm_runtime_get() is not allowed.
|
||||||
|
* This function is called mainly from clk_disable_unused_subtree,
|
||||||
|
* which ensures proper runtime pm activation of controller before
|
||||||
|
* taking enable spinlock, but the below check is needed if one tries
|
||||||
|
* to call it from other places.
|
||||||
|
*/
|
||||||
|
if (core->dev) {
|
||||||
|
pm_runtime_get_noresume(core->dev);
|
||||||
|
if (!pm_runtime_active(core->dev)) {
|
||||||
|
ret = false;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = core->ops->is_enabled(core->hw);
|
||||||
|
done:
|
||||||
|
clk_pm_runtime_put(core);
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*** helper functions ***/
|
/*** helper functions ***/
|
||||||
@ -489,6 +542,8 @@ static void clk_core_unprepare(struct clk_core *core)
|
|||||||
if (core->ops->unprepare)
|
if (core->ops->unprepare)
|
||||||
core->ops->unprepare(core->hw);
|
core->ops->unprepare(core->hw);
|
||||||
|
|
||||||
|
clk_pm_runtime_put(core);
|
||||||
|
|
||||||
trace_clk_unprepare_complete(core);
|
trace_clk_unprepare_complete(core);
|
||||||
clk_core_unprepare(core->parent);
|
clk_core_unprepare(core->parent);
|
||||||
}
|
}
|
||||||
@ -530,10 +585,14 @@ static int clk_core_prepare(struct clk_core *core)
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (core->prepare_count == 0) {
|
if (core->prepare_count == 0) {
|
||||||
ret = clk_core_prepare(core->parent);
|
ret = clk_pm_runtime_get(core);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
ret = clk_core_prepare(core->parent);
|
||||||
|
if (ret)
|
||||||
|
goto runtime_put;
|
||||||
|
|
||||||
trace_clk_prepare(core);
|
trace_clk_prepare(core);
|
||||||
|
|
||||||
if (core->ops->prepare)
|
if (core->ops->prepare)
|
||||||
@ -541,15 +600,18 @@ static int clk_core_prepare(struct clk_core *core)
|
|||||||
|
|
||||||
trace_clk_prepare_complete(core);
|
trace_clk_prepare_complete(core);
|
||||||
|
|
||||||
if (ret) {
|
if (ret)
|
||||||
clk_core_unprepare(core->parent);
|
goto unprepare;
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
core->prepare_count++;
|
core->prepare_count++;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
unprepare:
|
||||||
|
clk_core_unprepare(core->parent);
|
||||||
|
runtime_put:
|
||||||
|
clk_pm_runtime_put(core);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int clk_core_prepare_lock(struct clk_core *core)
|
static int clk_core_prepare_lock(struct clk_core *core)
|
||||||
@ -745,6 +807,9 @@ static void clk_unprepare_unused_subtree(struct clk_core *core)
|
|||||||
if (core->flags & CLK_IGNORE_UNUSED)
|
if (core->flags & CLK_IGNORE_UNUSED)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (clk_pm_runtime_get(core))
|
||||||
|
return;
|
||||||
|
|
||||||
if (clk_core_is_prepared(core)) {
|
if (clk_core_is_prepared(core)) {
|
||||||
trace_clk_unprepare(core);
|
trace_clk_unprepare(core);
|
||||||
if (core->ops->unprepare_unused)
|
if (core->ops->unprepare_unused)
|
||||||
@ -753,6 +818,8 @@ static void clk_unprepare_unused_subtree(struct clk_core *core)
|
|||||||
core->ops->unprepare(core->hw);
|
core->ops->unprepare(core->hw);
|
||||||
trace_clk_unprepare_complete(core);
|
trace_clk_unprepare_complete(core);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
clk_pm_runtime_put(core);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void clk_disable_unused_subtree(struct clk_core *core)
|
static void clk_disable_unused_subtree(struct clk_core *core)
|
||||||
@ -768,6 +835,9 @@ static void clk_disable_unused_subtree(struct clk_core *core)
|
|||||||
if (core->flags & CLK_OPS_PARENT_ENABLE)
|
if (core->flags & CLK_OPS_PARENT_ENABLE)
|
||||||
clk_core_prepare_enable(core->parent);
|
clk_core_prepare_enable(core->parent);
|
||||||
|
|
||||||
|
if (clk_pm_runtime_get(core))
|
||||||
|
goto unprepare_out;
|
||||||
|
|
||||||
flags = clk_enable_lock();
|
flags = clk_enable_lock();
|
||||||
|
|
||||||
if (core->enable_count)
|
if (core->enable_count)
|
||||||
@ -792,6 +862,8 @@ static void clk_disable_unused_subtree(struct clk_core *core)
|
|||||||
|
|
||||||
unlock_out:
|
unlock_out:
|
||||||
clk_enable_unlock(flags);
|
clk_enable_unlock(flags);
|
||||||
|
clk_pm_runtime_put(core);
|
||||||
|
unprepare_out:
|
||||||
if (core->flags & CLK_OPS_PARENT_ENABLE)
|
if (core->flags & CLK_OPS_PARENT_ENABLE)
|
||||||
clk_core_disable_unprepare(core->parent);
|
clk_core_disable_unprepare(core->parent);
|
||||||
}
|
}
|
||||||
@ -1038,9 +1110,13 @@ EXPORT_SYMBOL_GPL(clk_get_accuracy);
|
|||||||
static unsigned long clk_recalc(struct clk_core *core,
|
static unsigned long clk_recalc(struct clk_core *core,
|
||||||
unsigned long parent_rate)
|
unsigned long parent_rate)
|
||||||
{
|
{
|
||||||
if (core->ops->recalc_rate)
|
unsigned long rate = parent_rate;
|
||||||
return core->ops->recalc_rate(core->hw, parent_rate);
|
|
||||||
return parent_rate;
|
if (core->ops->recalc_rate && !clk_pm_runtime_get(core)) {
|
||||||
|
rate = core->ops->recalc_rate(core->hw, parent_rate);
|
||||||
|
clk_pm_runtime_put(core);
|
||||||
|
}
|
||||||
|
return rate;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1565,6 +1641,7 @@ static int clk_core_set_rate_nolock(struct clk_core *core,
|
|||||||
{
|
{
|
||||||
struct clk_core *top, *fail_clk;
|
struct clk_core *top, *fail_clk;
|
||||||
unsigned long rate = req_rate;
|
unsigned long rate = req_rate;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
if (!core)
|
if (!core)
|
||||||
return 0;
|
return 0;
|
||||||
@ -1581,21 +1658,28 @@ static int clk_core_set_rate_nolock(struct clk_core *core,
|
|||||||
if (!top)
|
if (!top)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
ret = clk_pm_runtime_get(core);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
/* notify that we are about to change rates */
|
/* notify that we are about to change rates */
|
||||||
fail_clk = clk_propagate_rate_change(top, PRE_RATE_CHANGE);
|
fail_clk = clk_propagate_rate_change(top, PRE_RATE_CHANGE);
|
||||||
if (fail_clk) {
|
if (fail_clk) {
|
||||||
pr_debug("%s: failed to set %s rate\n", __func__,
|
pr_debug("%s: failed to set %s rate\n", __func__,
|
||||||
fail_clk->name);
|
fail_clk->name);
|
||||||
clk_propagate_rate_change(top, ABORT_RATE_CHANGE);
|
clk_propagate_rate_change(top, ABORT_RATE_CHANGE);
|
||||||
return -EBUSY;
|
ret = -EBUSY;
|
||||||
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* change the rates */
|
/* change the rates */
|
||||||
clk_change_rate(top);
|
clk_change_rate(top);
|
||||||
|
|
||||||
core->req_rate = req_rate;
|
core->req_rate = req_rate;
|
||||||
|
err:
|
||||||
|
clk_pm_runtime_put(core);
|
||||||
|
|
||||||
return 0;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1826,12 +1910,16 @@ static int clk_core_set_parent(struct clk_core *core, struct clk_core *parent)
|
|||||||
p_rate = parent->rate;
|
p_rate = parent->rate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ret = clk_pm_runtime_get(core);
|
||||||
|
if (ret)
|
||||||
|
goto out;
|
||||||
|
|
||||||
/* propagate PRE_RATE_CHANGE notifications */
|
/* propagate PRE_RATE_CHANGE notifications */
|
||||||
ret = __clk_speculate_rates(core, p_rate);
|
ret = __clk_speculate_rates(core, p_rate);
|
||||||
|
|
||||||
/* abort if a driver objects */
|
/* abort if a driver objects */
|
||||||
if (ret & NOTIFY_STOP_MASK)
|
if (ret & NOTIFY_STOP_MASK)
|
||||||
goto out;
|
goto runtime_put;
|
||||||
|
|
||||||
/* do the re-parent */
|
/* do the re-parent */
|
||||||
ret = __clk_set_parent(core, parent, p_index);
|
ret = __clk_set_parent(core, parent, p_index);
|
||||||
@ -1844,6 +1932,8 @@ static int clk_core_set_parent(struct clk_core *core, struct clk_core *parent)
|
|||||||
__clk_recalc_accuracies(core);
|
__clk_recalc_accuracies(core);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
runtime_put:
|
||||||
|
clk_pm_runtime_put(core);
|
||||||
out:
|
out:
|
||||||
clk_prepare_unlock();
|
clk_prepare_unlock();
|
||||||
|
|
||||||
@ -2350,7 +2440,7 @@ static inline void clk_debug_unregister(struct clk_core *core)
|
|||||||
*/
|
*/
|
||||||
static int __clk_core_init(struct clk_core *core)
|
static int __clk_core_init(struct clk_core *core)
|
||||||
{
|
{
|
||||||
int i, ret = 0;
|
int i, ret;
|
||||||
struct clk_core *orphan;
|
struct clk_core *orphan;
|
||||||
struct hlist_node *tmp2;
|
struct hlist_node *tmp2;
|
||||||
unsigned long rate;
|
unsigned long rate;
|
||||||
@ -2360,6 +2450,10 @@ static int __clk_core_init(struct clk_core *core)
|
|||||||
|
|
||||||
clk_prepare_lock();
|
clk_prepare_lock();
|
||||||
|
|
||||||
|
ret = clk_pm_runtime_get(core);
|
||||||
|
if (ret)
|
||||||
|
goto unlock;
|
||||||
|
|
||||||
/* check to see if a clock with this name is already registered */
|
/* check to see if a clock with this name is already registered */
|
||||||
if (clk_core_lookup(core->name)) {
|
if (clk_core_lookup(core->name)) {
|
||||||
pr_debug("%s: clk %s already initialized\n",
|
pr_debug("%s: clk %s already initialized\n",
|
||||||
@ -2512,6 +2606,8 @@ static int __clk_core_init(struct clk_core *core)
|
|||||||
|
|
||||||
kref_init(&core->ref);
|
kref_init(&core->ref);
|
||||||
out:
|
out:
|
||||||
|
clk_pm_runtime_put(core);
|
||||||
|
unlock:
|
||||||
clk_prepare_unlock();
|
clk_prepare_unlock();
|
||||||
|
|
||||||
if (!ret)
|
if (!ret)
|
||||||
@ -2583,6 +2679,8 @@ struct clk *clk_register(struct device *dev, struct clk_hw *hw)
|
|||||||
goto fail_name;
|
goto fail_name;
|
||||||
}
|
}
|
||||||
core->ops = hw->init->ops;
|
core->ops = hw->init->ops;
|
||||||
|
if (dev && pm_runtime_enabled(dev))
|
||||||
|
core->dev = dev;
|
||||||
if (dev && dev->driver)
|
if (dev && dev->driver)
|
||||||
core->owner = dev->driver->owner;
|
core->owner = dev->driver->owner;
|
||||||
core->hw = hw;
|
core->hw = hw;
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
#include <linux/syscore_ops.h>
|
#include <linux/syscore_ops.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/pm_runtime.h>
|
||||||
|
|
||||||
#include <dt-bindings/clock/exynos-audss-clk.h>
|
#include <dt-bindings/clock/exynos-audss-clk.h>
|
||||||
|
|
||||||
@ -36,14 +37,13 @@ static struct clk *epll;
|
|||||||
#define ASS_CLK_DIV 0x4
|
#define ASS_CLK_DIV 0x4
|
||||||
#define ASS_CLK_GATE 0x8
|
#define ASS_CLK_GATE 0x8
|
||||||
|
|
||||||
#ifdef CONFIG_PM_SLEEP
|
|
||||||
static unsigned long reg_save[][2] = {
|
static unsigned long reg_save[][2] = {
|
||||||
{ ASS_CLK_SRC, 0 },
|
{ ASS_CLK_SRC, 0 },
|
||||||
{ ASS_CLK_DIV, 0 },
|
{ ASS_CLK_DIV, 0 },
|
||||||
{ ASS_CLK_GATE, 0 },
|
{ ASS_CLK_GATE, 0 },
|
||||||
};
|
};
|
||||||
|
|
||||||
static int exynos_audss_clk_suspend(struct device *dev)
|
static int __maybe_unused exynos_audss_clk_suspend(struct device *dev)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
@ -53,7 +53,7 @@ static int exynos_audss_clk_suspend(struct device *dev)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int exynos_audss_clk_resume(struct device *dev)
|
static int __maybe_unused exynos_audss_clk_resume(struct device *dev)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
@ -62,7 +62,6 @@ static int exynos_audss_clk_resume(struct device *dev)
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_PM_SLEEP */
|
|
||||||
|
|
||||||
struct exynos_audss_clk_drvdata {
|
struct exynos_audss_clk_drvdata {
|
||||||
unsigned int has_adma_clk:1;
|
unsigned int has_adma_clk:1;
|
||||||
@ -135,6 +134,7 @@ static int exynos_audss_clk_probe(struct platform_device *pdev)
|
|||||||
const struct exynos_audss_clk_drvdata *variant;
|
const struct exynos_audss_clk_drvdata *variant;
|
||||||
struct clk_hw **clk_table;
|
struct clk_hw **clk_table;
|
||||||
struct resource *res;
|
struct resource *res;
|
||||||
|
struct device *dev = &pdev->dev;
|
||||||
int i, ret = 0;
|
int i, ret = 0;
|
||||||
|
|
||||||
variant = of_device_get_match_data(&pdev->dev);
|
variant = of_device_get_match_data(&pdev->dev);
|
||||||
@ -142,15 +142,15 @@ static int exynos_audss_clk_probe(struct platform_device *pdev)
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||||
reg_base = devm_ioremap_resource(&pdev->dev, res);
|
reg_base = devm_ioremap_resource(dev, res);
|
||||||
if (IS_ERR(reg_base)) {
|
if (IS_ERR(reg_base)) {
|
||||||
dev_err(&pdev->dev, "failed to map audss registers\n");
|
dev_err(dev, "failed to map audss registers\n");
|
||||||
return PTR_ERR(reg_base);
|
return PTR_ERR(reg_base);
|
||||||
}
|
}
|
||||||
|
|
||||||
epll = ERR_PTR(-ENODEV);
|
epll = ERR_PTR(-ENODEV);
|
||||||
|
|
||||||
clk_data = devm_kzalloc(&pdev->dev,
|
clk_data = devm_kzalloc(dev,
|
||||||
sizeof(*clk_data) +
|
sizeof(*clk_data) +
|
||||||
sizeof(*clk_data->hws) * EXYNOS_AUDSS_MAX_CLKS,
|
sizeof(*clk_data->hws) * EXYNOS_AUDSS_MAX_CLKS,
|
||||||
GFP_KERNEL);
|
GFP_KERNEL);
|
||||||
@ -160,8 +160,8 @@ static int exynos_audss_clk_probe(struct platform_device *pdev)
|
|||||||
clk_data->num = variant->num_clks;
|
clk_data->num = variant->num_clks;
|
||||||
clk_table = clk_data->hws;
|
clk_table = clk_data->hws;
|
||||||
|
|
||||||
pll_ref = devm_clk_get(&pdev->dev, "pll_ref");
|
pll_ref = devm_clk_get(dev, "pll_ref");
|
||||||
pll_in = devm_clk_get(&pdev->dev, "pll_in");
|
pll_in = devm_clk_get(dev, "pll_in");
|
||||||
if (!IS_ERR(pll_ref))
|
if (!IS_ERR(pll_ref))
|
||||||
mout_audss_p[0] = __clk_get_name(pll_ref);
|
mout_audss_p[0] = __clk_get_name(pll_ref);
|
||||||
if (!IS_ERR(pll_in)) {
|
if (!IS_ERR(pll_in)) {
|
||||||
@ -172,88 +172,103 @@ static int exynos_audss_clk_probe(struct platform_device *pdev)
|
|||||||
|
|
||||||
ret = clk_prepare_enable(epll);
|
ret = clk_prepare_enable(epll);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(&pdev->dev,
|
dev_err(dev,
|
||||||
"failed to prepare the epll clock\n");
|
"failed to prepare the epll clock\n");
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
clk_table[EXYNOS_MOUT_AUDSS] = clk_hw_register_mux(NULL, "mout_audss",
|
|
||||||
|
/*
|
||||||
|
* Enable runtime PM here to allow the clock core using runtime PM
|
||||||
|
* for the registered clocks. Additionally, we increase the runtime
|
||||||
|
* PM usage count before registering the clocks, to prevent the
|
||||||
|
* clock core from runtime suspending the device.
|
||||||
|
*/
|
||||||
|
pm_runtime_get_noresume(dev);
|
||||||
|
pm_runtime_set_active(dev);
|
||||||
|
pm_runtime_enable(dev);
|
||||||
|
|
||||||
|
clk_table[EXYNOS_MOUT_AUDSS] = clk_hw_register_mux(dev, "mout_audss",
|
||||||
mout_audss_p, ARRAY_SIZE(mout_audss_p),
|
mout_audss_p, ARRAY_SIZE(mout_audss_p),
|
||||||
CLK_SET_RATE_NO_REPARENT | CLK_SET_RATE_PARENT,
|
CLK_SET_RATE_NO_REPARENT | CLK_SET_RATE_PARENT,
|
||||||
reg_base + ASS_CLK_SRC, 0, 1, 0, &lock);
|
reg_base + ASS_CLK_SRC, 0, 1, 0, &lock);
|
||||||
|
|
||||||
cdclk = devm_clk_get(&pdev->dev, "cdclk");
|
cdclk = devm_clk_get(dev, "cdclk");
|
||||||
sclk_audio = devm_clk_get(&pdev->dev, "sclk_audio");
|
sclk_audio = devm_clk_get(dev, "sclk_audio");
|
||||||
if (!IS_ERR(cdclk))
|
if (!IS_ERR(cdclk))
|
||||||
mout_i2s_p[1] = __clk_get_name(cdclk);
|
mout_i2s_p[1] = __clk_get_name(cdclk);
|
||||||
if (!IS_ERR(sclk_audio))
|
if (!IS_ERR(sclk_audio))
|
||||||
mout_i2s_p[2] = __clk_get_name(sclk_audio);
|
mout_i2s_p[2] = __clk_get_name(sclk_audio);
|
||||||
clk_table[EXYNOS_MOUT_I2S] = clk_hw_register_mux(NULL, "mout_i2s",
|
clk_table[EXYNOS_MOUT_I2S] = clk_hw_register_mux(dev, "mout_i2s",
|
||||||
mout_i2s_p, ARRAY_SIZE(mout_i2s_p),
|
mout_i2s_p, ARRAY_SIZE(mout_i2s_p),
|
||||||
CLK_SET_RATE_NO_REPARENT,
|
CLK_SET_RATE_NO_REPARENT,
|
||||||
reg_base + ASS_CLK_SRC, 2, 2, 0, &lock);
|
reg_base + ASS_CLK_SRC, 2, 2, 0, &lock);
|
||||||
|
|
||||||
clk_table[EXYNOS_DOUT_SRP] = clk_hw_register_divider(NULL, "dout_srp",
|
clk_table[EXYNOS_DOUT_SRP] = clk_hw_register_divider(dev, "dout_srp",
|
||||||
"mout_audss", CLK_SET_RATE_PARENT,
|
"mout_audss", CLK_SET_RATE_PARENT,
|
||||||
reg_base + ASS_CLK_DIV, 0, 4, 0, &lock);
|
reg_base + ASS_CLK_DIV, 0, 4, 0, &lock);
|
||||||
|
|
||||||
clk_table[EXYNOS_DOUT_AUD_BUS] = clk_hw_register_divider(NULL,
|
clk_table[EXYNOS_DOUT_AUD_BUS] = clk_hw_register_divider(dev,
|
||||||
"dout_aud_bus", "dout_srp", CLK_SET_RATE_PARENT,
|
"dout_aud_bus", "dout_srp", CLK_SET_RATE_PARENT,
|
||||||
reg_base + ASS_CLK_DIV, 4, 4, 0, &lock);
|
reg_base + ASS_CLK_DIV, 4, 4, 0, &lock);
|
||||||
|
|
||||||
clk_table[EXYNOS_DOUT_I2S] = clk_hw_register_divider(NULL, "dout_i2s",
|
clk_table[EXYNOS_DOUT_I2S] = clk_hw_register_divider(dev, "dout_i2s",
|
||||||
"mout_i2s", 0, reg_base + ASS_CLK_DIV, 8, 4, 0,
|
"mout_i2s", 0, reg_base + ASS_CLK_DIV, 8, 4, 0,
|
||||||
&lock);
|
&lock);
|
||||||
|
|
||||||
clk_table[EXYNOS_SRP_CLK] = clk_hw_register_gate(NULL, "srp_clk",
|
clk_table[EXYNOS_SRP_CLK] = clk_hw_register_gate(dev, "srp_clk",
|
||||||
"dout_srp", CLK_SET_RATE_PARENT,
|
"dout_srp", CLK_SET_RATE_PARENT,
|
||||||
reg_base + ASS_CLK_GATE, 0, 0, &lock);
|
reg_base + ASS_CLK_GATE, 0, 0, &lock);
|
||||||
|
|
||||||
clk_table[EXYNOS_I2S_BUS] = clk_hw_register_gate(NULL, "i2s_bus",
|
clk_table[EXYNOS_I2S_BUS] = clk_hw_register_gate(dev, "i2s_bus",
|
||||||
"dout_aud_bus", CLK_SET_RATE_PARENT,
|
"dout_aud_bus", CLK_SET_RATE_PARENT,
|
||||||
reg_base + ASS_CLK_GATE, 2, 0, &lock);
|
reg_base + ASS_CLK_GATE, 2, 0, &lock);
|
||||||
|
|
||||||
clk_table[EXYNOS_SCLK_I2S] = clk_hw_register_gate(NULL, "sclk_i2s",
|
clk_table[EXYNOS_SCLK_I2S] = clk_hw_register_gate(dev, "sclk_i2s",
|
||||||
"dout_i2s", CLK_SET_RATE_PARENT,
|
"dout_i2s", CLK_SET_RATE_PARENT,
|
||||||
reg_base + ASS_CLK_GATE, 3, 0, &lock);
|
reg_base + ASS_CLK_GATE, 3, 0, &lock);
|
||||||
|
|
||||||
clk_table[EXYNOS_PCM_BUS] = clk_hw_register_gate(NULL, "pcm_bus",
|
clk_table[EXYNOS_PCM_BUS] = clk_hw_register_gate(dev, "pcm_bus",
|
||||||
"sclk_pcm", CLK_SET_RATE_PARENT,
|
"sclk_pcm", CLK_SET_RATE_PARENT,
|
||||||
reg_base + ASS_CLK_GATE, 4, 0, &lock);
|
reg_base + ASS_CLK_GATE, 4, 0, &lock);
|
||||||
|
|
||||||
sclk_pcm_in = devm_clk_get(&pdev->dev, "sclk_pcm_in");
|
sclk_pcm_in = devm_clk_get(dev, "sclk_pcm_in");
|
||||||
if (!IS_ERR(sclk_pcm_in))
|
if (!IS_ERR(sclk_pcm_in))
|
||||||
sclk_pcm_p = __clk_get_name(sclk_pcm_in);
|
sclk_pcm_p = __clk_get_name(sclk_pcm_in);
|
||||||
clk_table[EXYNOS_SCLK_PCM] = clk_hw_register_gate(NULL, "sclk_pcm",
|
clk_table[EXYNOS_SCLK_PCM] = clk_hw_register_gate(dev, "sclk_pcm",
|
||||||
sclk_pcm_p, CLK_SET_RATE_PARENT,
|
sclk_pcm_p, CLK_SET_RATE_PARENT,
|
||||||
reg_base + ASS_CLK_GATE, 5, 0, &lock);
|
reg_base + ASS_CLK_GATE, 5, 0, &lock);
|
||||||
|
|
||||||
if (variant->has_adma_clk) {
|
if (variant->has_adma_clk) {
|
||||||
clk_table[EXYNOS_ADMA] = clk_hw_register_gate(NULL, "adma",
|
clk_table[EXYNOS_ADMA] = clk_hw_register_gate(dev, "adma",
|
||||||
"dout_srp", CLK_SET_RATE_PARENT,
|
"dout_srp", CLK_SET_RATE_PARENT,
|
||||||
reg_base + ASS_CLK_GATE, 9, 0, &lock);
|
reg_base + ASS_CLK_GATE, 9, 0, &lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < clk_data->num; i++) {
|
for (i = 0; i < clk_data->num; i++) {
|
||||||
if (IS_ERR(clk_table[i])) {
|
if (IS_ERR(clk_table[i])) {
|
||||||
dev_err(&pdev->dev, "failed to register clock %d\n", i);
|
dev_err(dev, "failed to register clock %d\n", i);
|
||||||
ret = PTR_ERR(clk_table[i]);
|
ret = PTR_ERR(clk_table[i]);
|
||||||
goto unregister;
|
goto unregister;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = of_clk_add_hw_provider(pdev->dev.of_node, of_clk_hw_onecell_get,
|
ret = of_clk_add_hw_provider(dev->of_node, of_clk_hw_onecell_get,
|
||||||
clk_data);
|
clk_data);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(&pdev->dev, "failed to add clock provider\n");
|
dev_err(dev, "failed to add clock provider\n");
|
||||||
goto unregister;
|
goto unregister;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pm_runtime_put_sync(dev);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
unregister:
|
unregister:
|
||||||
exynos_audss_clk_teardown();
|
exynos_audss_clk_teardown();
|
||||||
|
pm_runtime_put_sync(dev);
|
||||||
|
pm_runtime_disable(dev);
|
||||||
|
|
||||||
if (!IS_ERR(epll))
|
if (!IS_ERR(epll))
|
||||||
clk_disable_unprepare(epll);
|
clk_disable_unprepare(epll);
|
||||||
@ -266,6 +281,7 @@ static int exynos_audss_clk_remove(struct platform_device *pdev)
|
|||||||
of_clk_del_provider(pdev->dev.of_node);
|
of_clk_del_provider(pdev->dev.of_node);
|
||||||
|
|
||||||
exynos_audss_clk_teardown();
|
exynos_audss_clk_teardown();
|
||||||
|
pm_runtime_disable(&pdev->dev);
|
||||||
|
|
||||||
if (!IS_ERR(epll))
|
if (!IS_ERR(epll))
|
||||||
clk_disable_unprepare(epll);
|
clk_disable_unprepare(epll);
|
||||||
@ -274,8 +290,10 @@ static int exynos_audss_clk_remove(struct platform_device *pdev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static const struct dev_pm_ops exynos_audss_clk_pm_ops = {
|
static const struct dev_pm_ops exynos_audss_clk_pm_ops = {
|
||||||
SET_LATE_SYSTEM_SLEEP_PM_OPS(exynos_audss_clk_suspend,
|
SET_RUNTIME_PM_OPS(exynos_audss_clk_suspend, exynos_audss_clk_resume,
|
||||||
exynos_audss_clk_resume)
|
NULL)
|
||||||
|
SET_LATE_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
|
||||||
|
pm_runtime_force_resume)
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct platform_driver exynos_audss_clk_driver = {
|
static struct platform_driver exynos_audss_clk_driver = {
|
||||||
|
@ -9,9 +9,13 @@
|
|||||||
* Common Clock Framework support for Exynos5433 SoC.
|
* Common Clock Framework support for Exynos5433 SoC.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <linux/clk.h>
|
||||||
#include <linux/clk-provider.h>
|
#include <linux/clk-provider.h>
|
||||||
#include <linux/of.h>
|
#include <linux/of.h>
|
||||||
#include <linux/of_address.h>
|
#include <linux/of_address.h>
|
||||||
|
#include <linux/of_device.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/pm_runtime.h>
|
||||||
|
|
||||||
#include <dt-bindings/clock/exynos5433.h>
|
#include <dt-bindings/clock/exynos5433.h>
|
||||||
|
|
||||||
@ -1991,6 +1995,14 @@ static const unsigned long fsys_clk_regs[] __initconst = {
|
|||||||
ENABLE_IP_FSYS1,
|
ENABLE_IP_FSYS1,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const struct samsung_clk_reg_dump fsys_suspend_regs[] = {
|
||||||
|
{ MUX_SEL_FSYS0, 0 },
|
||||||
|
{ MUX_SEL_FSYS1, 0 },
|
||||||
|
{ MUX_SEL_FSYS2, 0 },
|
||||||
|
{ MUX_SEL_FSYS3, 0 },
|
||||||
|
{ MUX_SEL_FSYS4, 0 },
|
||||||
|
};
|
||||||
|
|
||||||
static const struct samsung_fixed_rate_clock fsys_fixed_clks[] __initconst = {
|
static const struct samsung_fixed_rate_clock fsys_fixed_clks[] __initconst = {
|
||||||
/* PHY clocks from USBDRD30_PHY */
|
/* PHY clocks from USBDRD30_PHY */
|
||||||
FRATE(CLK_PHYCLK_USBDRD30_UDRD30_PHYCLOCK_PHY,
|
FRATE(CLK_PHYCLK_USBDRD30_UDRD30_PHYCLOCK_PHY,
|
||||||
@ -2296,16 +2308,11 @@ static const struct samsung_cmu_info fsys_cmu_info __initconst = {
|
|||||||
.nr_clk_ids = FSYS_NR_CLK,
|
.nr_clk_ids = FSYS_NR_CLK,
|
||||||
.clk_regs = fsys_clk_regs,
|
.clk_regs = fsys_clk_regs,
|
||||||
.nr_clk_regs = ARRAY_SIZE(fsys_clk_regs),
|
.nr_clk_regs = ARRAY_SIZE(fsys_clk_regs),
|
||||||
|
.suspend_regs = fsys_suspend_regs,
|
||||||
|
.nr_suspend_regs = ARRAY_SIZE(fsys_suspend_regs),
|
||||||
|
.clk_name = "aclk_fsys_200",
|
||||||
};
|
};
|
||||||
|
|
||||||
static void __init exynos5433_cmu_fsys_init(struct device_node *np)
|
|
||||||
{
|
|
||||||
samsung_cmu_register_one(np, &fsys_cmu_info);
|
|
||||||
}
|
|
||||||
|
|
||||||
CLK_OF_DECLARE(exynos5433_cmu_fsys, "samsung,exynos5433-cmu-fsys",
|
|
||||||
exynos5433_cmu_fsys_init);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Register offset definitions for CMU_G2D
|
* Register offset definitions for CMU_G2D
|
||||||
*/
|
*/
|
||||||
@ -2335,6 +2342,10 @@ static const unsigned long g2d_clk_regs[] __initconst = {
|
|||||||
DIV_ENABLE_IP_G2D_SECURE_SMMU_G2D,
|
DIV_ENABLE_IP_G2D_SECURE_SMMU_G2D,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const struct samsung_clk_reg_dump g2d_suspend_regs[] = {
|
||||||
|
{ MUX_SEL_G2D0, 0 },
|
||||||
|
};
|
||||||
|
|
||||||
/* list of all parent clock list */
|
/* list of all parent clock list */
|
||||||
PNAME(mout_aclk_g2d_266_user_p) = { "oscclk", "aclk_g2d_266", };
|
PNAME(mout_aclk_g2d_266_user_p) = { "oscclk", "aclk_g2d_266", };
|
||||||
PNAME(mout_aclk_g2d_400_user_p) = { "oscclk", "aclk_g2d_400", };
|
PNAME(mout_aclk_g2d_400_user_p) = { "oscclk", "aclk_g2d_400", };
|
||||||
@ -2420,16 +2431,11 @@ static const struct samsung_cmu_info g2d_cmu_info __initconst = {
|
|||||||
.nr_clk_ids = G2D_NR_CLK,
|
.nr_clk_ids = G2D_NR_CLK,
|
||||||
.clk_regs = g2d_clk_regs,
|
.clk_regs = g2d_clk_regs,
|
||||||
.nr_clk_regs = ARRAY_SIZE(g2d_clk_regs),
|
.nr_clk_regs = ARRAY_SIZE(g2d_clk_regs),
|
||||||
|
.suspend_regs = g2d_suspend_regs,
|
||||||
|
.nr_suspend_regs = ARRAY_SIZE(g2d_suspend_regs),
|
||||||
|
.clk_name = "aclk_g2d_400",
|
||||||
};
|
};
|
||||||
|
|
||||||
static void __init exynos5433_cmu_g2d_init(struct device_node *np)
|
|
||||||
{
|
|
||||||
samsung_cmu_register_one(np, &g2d_cmu_info);
|
|
||||||
}
|
|
||||||
|
|
||||||
CLK_OF_DECLARE(exynos5433_cmu_g2d, "samsung,exynos5433-cmu-g2d",
|
|
||||||
exynos5433_cmu_g2d_init);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Register offset definitions for CMU_DISP
|
* Register offset definitions for CMU_DISP
|
||||||
*/
|
*/
|
||||||
@ -2494,6 +2500,18 @@ static const unsigned long disp_clk_regs[] __initconst = {
|
|||||||
CLKOUT_CMU_DISP_DIV_STAT,
|
CLKOUT_CMU_DISP_DIV_STAT,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const struct samsung_clk_reg_dump disp_suspend_regs[] = {
|
||||||
|
/* PLL has to be enabled for suspend */
|
||||||
|
{ DISP_PLL_CON0, 0x85f40502 },
|
||||||
|
/* ignore status of external PHY muxes during suspend to avoid hangs */
|
||||||
|
{ MUX_IGNORE_DISP2, 0x00111111 },
|
||||||
|
{ MUX_SEL_DISP0, 0 },
|
||||||
|
{ MUX_SEL_DISP1, 0 },
|
||||||
|
{ MUX_SEL_DISP2, 0 },
|
||||||
|
{ MUX_SEL_DISP3, 0 },
|
||||||
|
{ MUX_SEL_DISP4, 0 },
|
||||||
|
};
|
||||||
|
|
||||||
/* list of all parent clock list */
|
/* list of all parent clock list */
|
||||||
PNAME(mout_disp_pll_p) = { "oscclk", "fout_disp_pll", };
|
PNAME(mout_disp_pll_p) = { "oscclk", "fout_disp_pll", };
|
||||||
PNAME(mout_sclk_dsim1_user_p) = { "oscclk", "sclk_dsim1_disp", };
|
PNAME(mout_sclk_dsim1_user_p) = { "oscclk", "sclk_dsim1_disp", };
|
||||||
@ -2841,16 +2859,11 @@ static const struct samsung_cmu_info disp_cmu_info __initconst = {
|
|||||||
.nr_clk_ids = DISP_NR_CLK,
|
.nr_clk_ids = DISP_NR_CLK,
|
||||||
.clk_regs = disp_clk_regs,
|
.clk_regs = disp_clk_regs,
|
||||||
.nr_clk_regs = ARRAY_SIZE(disp_clk_regs),
|
.nr_clk_regs = ARRAY_SIZE(disp_clk_regs),
|
||||||
|
.suspend_regs = disp_suspend_regs,
|
||||||
|
.nr_suspend_regs = ARRAY_SIZE(disp_suspend_regs),
|
||||||
|
.clk_name = "aclk_disp_333",
|
||||||
};
|
};
|
||||||
|
|
||||||
static void __init exynos5433_cmu_disp_init(struct device_node *np)
|
|
||||||
{
|
|
||||||
samsung_cmu_register_one(np, &disp_cmu_info);
|
|
||||||
}
|
|
||||||
|
|
||||||
CLK_OF_DECLARE(exynos5433_cmu_disp, "samsung,exynos5433-cmu-disp",
|
|
||||||
exynos5433_cmu_disp_init);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Register offset definitions for CMU_AUD
|
* Register offset definitions for CMU_AUD
|
||||||
*/
|
*/
|
||||||
@ -2885,6 +2898,11 @@ static const unsigned long aud_clk_regs[] __initconst = {
|
|||||||
ENABLE_IP_AUD1,
|
ENABLE_IP_AUD1,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const struct samsung_clk_reg_dump aud_suspend_regs[] = {
|
||||||
|
{ MUX_SEL_AUD0, 0 },
|
||||||
|
{ MUX_SEL_AUD1, 0 },
|
||||||
|
};
|
||||||
|
|
||||||
/* list of all parent clock list */
|
/* list of all parent clock list */
|
||||||
PNAME(mout_aud_pll_user_aud_p) = { "oscclk", "fout_aud_pll", };
|
PNAME(mout_aud_pll_user_aud_p) = { "oscclk", "fout_aud_pll", };
|
||||||
PNAME(mout_sclk_aud_pcm_p) = { "mout_aud_pll_user", "ioclk_audiocdclk0",};
|
PNAME(mout_sclk_aud_pcm_p) = { "mout_aud_pll_user", "ioclk_audiocdclk0",};
|
||||||
@ -3011,16 +3029,11 @@ static const struct samsung_cmu_info aud_cmu_info __initconst = {
|
|||||||
.nr_clk_ids = AUD_NR_CLK,
|
.nr_clk_ids = AUD_NR_CLK,
|
||||||
.clk_regs = aud_clk_regs,
|
.clk_regs = aud_clk_regs,
|
||||||
.nr_clk_regs = ARRAY_SIZE(aud_clk_regs),
|
.nr_clk_regs = ARRAY_SIZE(aud_clk_regs),
|
||||||
|
.suspend_regs = aud_suspend_regs,
|
||||||
|
.nr_suspend_regs = ARRAY_SIZE(aud_suspend_regs),
|
||||||
|
.clk_name = "fout_aud_pll",
|
||||||
};
|
};
|
||||||
|
|
||||||
static void __init exynos5433_cmu_aud_init(struct device_node *np)
|
|
||||||
{
|
|
||||||
samsung_cmu_register_one(np, &aud_cmu_info);
|
|
||||||
}
|
|
||||||
CLK_OF_DECLARE(exynos5433_cmu_aud, "samsung,exynos5433-cmu-aud",
|
|
||||||
exynos5433_cmu_aud_init);
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Register offset definitions for CMU_BUS{0|1|2}
|
* Register offset definitions for CMU_BUS{0|1|2}
|
||||||
*/
|
*/
|
||||||
@ -3222,6 +3235,10 @@ static const unsigned long g3d_clk_regs[] __initconst = {
|
|||||||
CLK_STOPCTRL,
|
CLK_STOPCTRL,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const struct samsung_clk_reg_dump g3d_suspend_regs[] = {
|
||||||
|
{ MUX_SEL_G3D, 0 },
|
||||||
|
};
|
||||||
|
|
||||||
/* list of all parent clock list */
|
/* list of all parent clock list */
|
||||||
PNAME(mout_aclk_g3d_400_p) = { "mout_g3d_pll", "aclk_g3d_400", };
|
PNAME(mout_aclk_g3d_400_p) = { "mout_g3d_pll", "aclk_g3d_400", };
|
||||||
PNAME(mout_g3d_pll_p) = { "oscclk", "fout_g3d_pll", };
|
PNAME(mout_g3d_pll_p) = { "oscclk", "fout_g3d_pll", };
|
||||||
@ -3295,15 +3312,11 @@ static const struct samsung_cmu_info g3d_cmu_info __initconst = {
|
|||||||
.nr_clk_ids = G3D_NR_CLK,
|
.nr_clk_ids = G3D_NR_CLK,
|
||||||
.clk_regs = g3d_clk_regs,
|
.clk_regs = g3d_clk_regs,
|
||||||
.nr_clk_regs = ARRAY_SIZE(g3d_clk_regs),
|
.nr_clk_regs = ARRAY_SIZE(g3d_clk_regs),
|
||||||
|
.suspend_regs = g3d_suspend_regs,
|
||||||
|
.nr_suspend_regs = ARRAY_SIZE(g3d_suspend_regs),
|
||||||
|
.clk_name = "aclk_g3d_400",
|
||||||
};
|
};
|
||||||
|
|
||||||
static void __init exynos5433_cmu_g3d_init(struct device_node *np)
|
|
||||||
{
|
|
||||||
samsung_cmu_register_one(np, &g3d_cmu_info);
|
|
||||||
}
|
|
||||||
CLK_OF_DECLARE(exynos5433_cmu_g3d, "samsung,exynos5433-cmu-g3d",
|
|
||||||
exynos5433_cmu_g3d_init);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Register offset definitions for CMU_GSCL
|
* Register offset definitions for CMU_GSCL
|
||||||
*/
|
*/
|
||||||
@ -3342,6 +3355,12 @@ static const unsigned long gscl_clk_regs[] __initconst = {
|
|||||||
ENABLE_IP_GSCL_SECURE_SMMU_GSCL2,
|
ENABLE_IP_GSCL_SECURE_SMMU_GSCL2,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const struct samsung_clk_reg_dump gscl_suspend_regs[] = {
|
||||||
|
{ MUX_SEL_GSCL, 0 },
|
||||||
|
{ ENABLE_ACLK_GSCL, 0xfff },
|
||||||
|
{ ENABLE_PCLK_GSCL, 0xff },
|
||||||
|
};
|
||||||
|
|
||||||
/* list of all parent clock list */
|
/* list of all parent clock list */
|
||||||
PNAME(aclk_gscl_111_user_p) = { "oscclk", "aclk_gscl_111", };
|
PNAME(aclk_gscl_111_user_p) = { "oscclk", "aclk_gscl_111", };
|
||||||
PNAME(aclk_gscl_333_user_p) = { "oscclk", "aclk_gscl_333", };
|
PNAME(aclk_gscl_333_user_p) = { "oscclk", "aclk_gscl_333", };
|
||||||
@ -3436,15 +3455,11 @@ static const struct samsung_cmu_info gscl_cmu_info __initconst = {
|
|||||||
.nr_clk_ids = GSCL_NR_CLK,
|
.nr_clk_ids = GSCL_NR_CLK,
|
||||||
.clk_regs = gscl_clk_regs,
|
.clk_regs = gscl_clk_regs,
|
||||||
.nr_clk_regs = ARRAY_SIZE(gscl_clk_regs),
|
.nr_clk_regs = ARRAY_SIZE(gscl_clk_regs),
|
||||||
|
.suspend_regs = gscl_suspend_regs,
|
||||||
|
.nr_suspend_regs = ARRAY_SIZE(gscl_suspend_regs),
|
||||||
|
.clk_name = "aclk_gscl_111",
|
||||||
};
|
};
|
||||||
|
|
||||||
static void __init exynos5433_cmu_gscl_init(struct device_node *np)
|
|
||||||
{
|
|
||||||
samsung_cmu_register_one(np, &gscl_cmu_info);
|
|
||||||
}
|
|
||||||
CLK_OF_DECLARE(exynos5433_cmu_gscl, "samsung,exynos5433-cmu-gscl",
|
|
||||||
exynos5433_cmu_gscl_init);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Register offset definitions for CMU_APOLLO
|
* Register offset definitions for CMU_APOLLO
|
||||||
*/
|
*/
|
||||||
@ -3970,6 +3985,11 @@ static const unsigned long mscl_clk_regs[] __initconst = {
|
|||||||
ENABLE_IP_MSCL_SECURE_SMMU_JPEG,
|
ENABLE_IP_MSCL_SECURE_SMMU_JPEG,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const struct samsung_clk_reg_dump mscl_suspend_regs[] = {
|
||||||
|
{ MUX_SEL_MSCL0, 0 },
|
||||||
|
{ MUX_SEL_MSCL1, 0 },
|
||||||
|
};
|
||||||
|
|
||||||
/* list of all parent clock list */
|
/* list of all parent clock list */
|
||||||
PNAME(mout_sclk_jpeg_user_p) = { "oscclk", "sclk_jpeg_mscl", };
|
PNAME(mout_sclk_jpeg_user_p) = { "oscclk", "sclk_jpeg_mscl", };
|
||||||
PNAME(mout_aclk_mscl_400_user_p) = { "oscclk", "aclk_mscl_400", };
|
PNAME(mout_aclk_mscl_400_user_p) = { "oscclk", "aclk_mscl_400", };
|
||||||
@ -4082,15 +4102,11 @@ static const struct samsung_cmu_info mscl_cmu_info __initconst = {
|
|||||||
.nr_clk_ids = MSCL_NR_CLK,
|
.nr_clk_ids = MSCL_NR_CLK,
|
||||||
.clk_regs = mscl_clk_regs,
|
.clk_regs = mscl_clk_regs,
|
||||||
.nr_clk_regs = ARRAY_SIZE(mscl_clk_regs),
|
.nr_clk_regs = ARRAY_SIZE(mscl_clk_regs),
|
||||||
|
.suspend_regs = mscl_suspend_regs,
|
||||||
|
.nr_suspend_regs = ARRAY_SIZE(mscl_suspend_regs),
|
||||||
|
.clk_name = "aclk_mscl_400",
|
||||||
};
|
};
|
||||||
|
|
||||||
static void __init exynos5433_cmu_mscl_init(struct device_node *np)
|
|
||||||
{
|
|
||||||
samsung_cmu_register_one(np, &mscl_cmu_info);
|
|
||||||
}
|
|
||||||
CLK_OF_DECLARE(exynos5433_cmu_mscl, "samsung,exynos5433-cmu-mscl",
|
|
||||||
exynos5433_cmu_mscl_init);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Register offset definitions for CMU_MFC
|
* Register offset definitions for CMU_MFC
|
||||||
*/
|
*/
|
||||||
@ -4120,6 +4136,10 @@ static const unsigned long mfc_clk_regs[] __initconst = {
|
|||||||
ENABLE_IP_MFC_SECURE_SMMU_MFC,
|
ENABLE_IP_MFC_SECURE_SMMU_MFC,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const struct samsung_clk_reg_dump mfc_suspend_regs[] = {
|
||||||
|
{ MUX_SEL_MFC, 0 },
|
||||||
|
};
|
||||||
|
|
||||||
PNAME(mout_aclk_mfc_400_user_p) = { "oscclk", "aclk_mfc_400", };
|
PNAME(mout_aclk_mfc_400_user_p) = { "oscclk", "aclk_mfc_400", };
|
||||||
|
|
||||||
static const struct samsung_mux_clock mfc_mux_clks[] __initconst = {
|
static const struct samsung_mux_clock mfc_mux_clks[] __initconst = {
|
||||||
@ -4190,15 +4210,11 @@ static const struct samsung_cmu_info mfc_cmu_info __initconst = {
|
|||||||
.nr_clk_ids = MFC_NR_CLK,
|
.nr_clk_ids = MFC_NR_CLK,
|
||||||
.clk_regs = mfc_clk_regs,
|
.clk_regs = mfc_clk_regs,
|
||||||
.nr_clk_regs = ARRAY_SIZE(mfc_clk_regs),
|
.nr_clk_regs = ARRAY_SIZE(mfc_clk_regs),
|
||||||
|
.suspend_regs = mfc_suspend_regs,
|
||||||
|
.nr_suspend_regs = ARRAY_SIZE(mfc_suspend_regs),
|
||||||
|
.clk_name = "aclk_mfc_400",
|
||||||
};
|
};
|
||||||
|
|
||||||
static void __init exynos5433_cmu_mfc_init(struct device_node *np)
|
|
||||||
{
|
|
||||||
samsung_cmu_register_one(np, &mfc_cmu_info);
|
|
||||||
}
|
|
||||||
CLK_OF_DECLARE(exynos5433_cmu_mfc, "samsung,exynos5433-cmu-mfc",
|
|
||||||
exynos5433_cmu_mfc_init);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Register offset definitions for CMU_HEVC
|
* Register offset definitions for CMU_HEVC
|
||||||
*/
|
*/
|
||||||
@ -4228,6 +4244,10 @@ static const unsigned long hevc_clk_regs[] __initconst = {
|
|||||||
ENABLE_IP_HEVC_SECURE_SMMU_HEVC,
|
ENABLE_IP_HEVC_SECURE_SMMU_HEVC,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const struct samsung_clk_reg_dump hevc_suspend_regs[] = {
|
||||||
|
{ MUX_SEL_HEVC, 0 },
|
||||||
|
};
|
||||||
|
|
||||||
PNAME(mout_aclk_hevc_400_user_p) = { "oscclk", "aclk_hevc_400", };
|
PNAME(mout_aclk_hevc_400_user_p) = { "oscclk", "aclk_hevc_400", };
|
||||||
|
|
||||||
static const struct samsung_mux_clock hevc_mux_clks[] __initconst = {
|
static const struct samsung_mux_clock hevc_mux_clks[] __initconst = {
|
||||||
@ -4300,15 +4320,11 @@ static const struct samsung_cmu_info hevc_cmu_info __initconst = {
|
|||||||
.nr_clk_ids = HEVC_NR_CLK,
|
.nr_clk_ids = HEVC_NR_CLK,
|
||||||
.clk_regs = hevc_clk_regs,
|
.clk_regs = hevc_clk_regs,
|
||||||
.nr_clk_regs = ARRAY_SIZE(hevc_clk_regs),
|
.nr_clk_regs = ARRAY_SIZE(hevc_clk_regs),
|
||||||
|
.suspend_regs = hevc_suspend_regs,
|
||||||
|
.nr_suspend_regs = ARRAY_SIZE(hevc_suspend_regs),
|
||||||
|
.clk_name = "aclk_hevc_400",
|
||||||
};
|
};
|
||||||
|
|
||||||
static void __init exynos5433_cmu_hevc_init(struct device_node *np)
|
|
||||||
{
|
|
||||||
samsung_cmu_register_one(np, &hevc_cmu_info);
|
|
||||||
}
|
|
||||||
CLK_OF_DECLARE(exynos5433_cmu_hevc, "samsung,exynos5433-cmu-hevc",
|
|
||||||
exynos5433_cmu_hevc_init);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Register offset definitions for CMU_ISP
|
* Register offset definitions for CMU_ISP
|
||||||
*/
|
*/
|
||||||
@ -4342,6 +4358,10 @@ static const unsigned long isp_clk_regs[] __initconst = {
|
|||||||
ENABLE_IP_ISP3,
|
ENABLE_IP_ISP3,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const struct samsung_clk_reg_dump isp_suspend_regs[] = {
|
||||||
|
{ MUX_SEL_ISP, 0 },
|
||||||
|
};
|
||||||
|
|
||||||
PNAME(mout_aclk_isp_dis_400_user_p) = { "oscclk", "aclk_isp_dis_400", };
|
PNAME(mout_aclk_isp_dis_400_user_p) = { "oscclk", "aclk_isp_dis_400", };
|
||||||
PNAME(mout_aclk_isp_400_user_p) = { "oscclk", "aclk_isp_400", };
|
PNAME(mout_aclk_isp_400_user_p) = { "oscclk", "aclk_isp_400", };
|
||||||
|
|
||||||
@ -4553,15 +4573,11 @@ static const struct samsung_cmu_info isp_cmu_info __initconst = {
|
|||||||
.nr_clk_ids = ISP_NR_CLK,
|
.nr_clk_ids = ISP_NR_CLK,
|
||||||
.clk_regs = isp_clk_regs,
|
.clk_regs = isp_clk_regs,
|
||||||
.nr_clk_regs = ARRAY_SIZE(isp_clk_regs),
|
.nr_clk_regs = ARRAY_SIZE(isp_clk_regs),
|
||||||
|
.suspend_regs = isp_suspend_regs,
|
||||||
|
.nr_suspend_regs = ARRAY_SIZE(isp_suspend_regs),
|
||||||
|
.clk_name = "aclk_isp_400",
|
||||||
};
|
};
|
||||||
|
|
||||||
static void __init exynos5433_cmu_isp_init(struct device_node *np)
|
|
||||||
{
|
|
||||||
samsung_cmu_register_one(np, &isp_cmu_info);
|
|
||||||
}
|
|
||||||
CLK_OF_DECLARE(exynos5433_cmu_isp, "samsung,exynos5433-cmu-isp",
|
|
||||||
exynos5433_cmu_isp_init);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Register offset definitions for CMU_CAM0
|
* Register offset definitions for CMU_CAM0
|
||||||
*/
|
*/
|
||||||
@ -4625,6 +4641,15 @@ static const unsigned long cam0_clk_regs[] __initconst = {
|
|||||||
ENABLE_IP_CAM02,
|
ENABLE_IP_CAM02,
|
||||||
ENABLE_IP_CAM03,
|
ENABLE_IP_CAM03,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const struct samsung_clk_reg_dump cam0_suspend_regs[] = {
|
||||||
|
{ MUX_SEL_CAM00, 0 },
|
||||||
|
{ MUX_SEL_CAM01, 0 },
|
||||||
|
{ MUX_SEL_CAM02, 0 },
|
||||||
|
{ MUX_SEL_CAM03, 0 },
|
||||||
|
{ MUX_SEL_CAM04, 0 },
|
||||||
|
};
|
||||||
|
|
||||||
PNAME(mout_aclk_cam0_333_user_p) = { "oscclk", "aclk_cam0_333", };
|
PNAME(mout_aclk_cam0_333_user_p) = { "oscclk", "aclk_cam0_333", };
|
||||||
PNAME(mout_aclk_cam0_400_user_p) = { "oscclk", "aclk_cam0_400", };
|
PNAME(mout_aclk_cam0_400_user_p) = { "oscclk", "aclk_cam0_400", };
|
||||||
PNAME(mout_aclk_cam0_552_user_p) = { "oscclk", "aclk_cam0_552", };
|
PNAME(mout_aclk_cam0_552_user_p) = { "oscclk", "aclk_cam0_552", };
|
||||||
@ -5030,15 +5055,11 @@ static const struct samsung_cmu_info cam0_cmu_info __initconst = {
|
|||||||
.nr_clk_ids = CAM0_NR_CLK,
|
.nr_clk_ids = CAM0_NR_CLK,
|
||||||
.clk_regs = cam0_clk_regs,
|
.clk_regs = cam0_clk_regs,
|
||||||
.nr_clk_regs = ARRAY_SIZE(cam0_clk_regs),
|
.nr_clk_regs = ARRAY_SIZE(cam0_clk_regs),
|
||||||
|
.suspend_regs = cam0_suspend_regs,
|
||||||
|
.nr_suspend_regs = ARRAY_SIZE(cam0_suspend_regs),
|
||||||
|
.clk_name = "aclk_cam0_400",
|
||||||
};
|
};
|
||||||
|
|
||||||
static void __init exynos5433_cmu_cam0_init(struct device_node *np)
|
|
||||||
{
|
|
||||||
samsung_cmu_register_one(np, &cam0_cmu_info);
|
|
||||||
}
|
|
||||||
CLK_OF_DECLARE(exynos5433_cmu_cam0, "samsung,exynos5433-cmu-cam0",
|
|
||||||
exynos5433_cmu_cam0_init);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Register offset definitions for CMU_CAM1
|
* Register offset definitions for CMU_CAM1
|
||||||
*/
|
*/
|
||||||
@ -5085,6 +5106,12 @@ static const unsigned long cam1_clk_regs[] __initconst = {
|
|||||||
ENABLE_IP_CAM12,
|
ENABLE_IP_CAM12,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const struct samsung_clk_reg_dump cam1_suspend_regs[] = {
|
||||||
|
{ MUX_SEL_CAM10, 0 },
|
||||||
|
{ MUX_SEL_CAM11, 0 },
|
||||||
|
{ MUX_SEL_CAM12, 0 },
|
||||||
|
};
|
||||||
|
|
||||||
PNAME(mout_sclk_isp_uart_user_p) = { "oscclk", "sclk_isp_uart_cam1", };
|
PNAME(mout_sclk_isp_uart_user_p) = { "oscclk", "sclk_isp_uart_cam1", };
|
||||||
PNAME(mout_sclk_isp_spi1_user_p) = { "oscclk", "sclk_isp_spi1_cam1", };
|
PNAME(mout_sclk_isp_spi1_user_p) = { "oscclk", "sclk_isp_spi1_cam1", };
|
||||||
PNAME(mout_sclk_isp_spi0_user_p) = { "oscclk", "sclk_isp_spi0_cam1", };
|
PNAME(mout_sclk_isp_spi0_user_p) = { "oscclk", "sclk_isp_spi0_cam1", };
|
||||||
@ -5403,11 +5430,223 @@ static const struct samsung_cmu_info cam1_cmu_info __initconst = {
|
|||||||
.nr_clk_ids = CAM1_NR_CLK,
|
.nr_clk_ids = CAM1_NR_CLK,
|
||||||
.clk_regs = cam1_clk_regs,
|
.clk_regs = cam1_clk_regs,
|
||||||
.nr_clk_regs = ARRAY_SIZE(cam1_clk_regs),
|
.nr_clk_regs = ARRAY_SIZE(cam1_clk_regs),
|
||||||
|
.suspend_regs = cam1_suspend_regs,
|
||||||
|
.nr_suspend_regs = ARRAY_SIZE(cam1_suspend_regs),
|
||||||
|
.clk_name = "aclk_cam1_400",
|
||||||
};
|
};
|
||||||
|
|
||||||
static void __init exynos5433_cmu_cam1_init(struct device_node *np)
|
|
||||||
|
struct exynos5433_cmu_data {
|
||||||
|
struct samsung_clk_reg_dump *clk_save;
|
||||||
|
unsigned int nr_clk_save;
|
||||||
|
const struct samsung_clk_reg_dump *clk_suspend;
|
||||||
|
unsigned int nr_clk_suspend;
|
||||||
|
|
||||||
|
struct clk *clk;
|
||||||
|
struct clk **pclks;
|
||||||
|
int nr_pclks;
|
||||||
|
|
||||||
|
/* must be the last entry */
|
||||||
|
struct samsung_clk_provider ctx;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int exynos5433_cmu_suspend(struct device *dev)
|
||||||
{
|
{
|
||||||
samsung_cmu_register_one(np, &cam1_cmu_info);
|
struct exynos5433_cmu_data *data = dev_get_drvdata(dev);
|
||||||
|
int i;
|
||||||
|
|
||||||
|
samsung_clk_save(data->ctx.reg_base, data->clk_save,
|
||||||
|
data->nr_clk_save);
|
||||||
|
|
||||||
|
for (i = 0; i < data->nr_pclks; i++)
|
||||||
|
clk_prepare_enable(data->pclks[i]);
|
||||||
|
|
||||||
|
/* for suspend some registers have to be set to certain values */
|
||||||
|
samsung_clk_restore(data->ctx.reg_base, data->clk_suspend,
|
||||||
|
data->nr_clk_suspend);
|
||||||
|
|
||||||
|
for (i = 0; i < data->nr_pclks; i++)
|
||||||
|
clk_disable_unprepare(data->pclks[i]);
|
||||||
|
|
||||||
|
clk_disable_unprepare(data->clk);
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
CLK_OF_DECLARE(exynos5433_cmu_cam1, "samsung,exynos5433-cmu-cam1",
|
|
||||||
exynos5433_cmu_cam1_init);
|
static int exynos5433_cmu_resume(struct device *dev)
|
||||||
|
{
|
||||||
|
struct exynos5433_cmu_data *data = dev_get_drvdata(dev);
|
||||||
|
int i;
|
||||||
|
|
||||||
|
clk_prepare_enable(data->clk);
|
||||||
|
|
||||||
|
for (i = 0; i < data->nr_pclks; i++)
|
||||||
|
clk_prepare_enable(data->pclks[i]);
|
||||||
|
|
||||||
|
samsung_clk_restore(data->ctx.reg_base, data->clk_save,
|
||||||
|
data->nr_clk_save);
|
||||||
|
|
||||||
|
for (i = 0; i < data->nr_pclks; i++)
|
||||||
|
clk_disable_unprepare(data->pclks[i]);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __init exynos5433_cmu_probe(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
const struct samsung_cmu_info *info;
|
||||||
|
struct exynos5433_cmu_data *data;
|
||||||
|
struct samsung_clk_provider *ctx;
|
||||||
|
struct device *dev = &pdev->dev;
|
||||||
|
struct resource *res;
|
||||||
|
void __iomem *reg_base;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
info = of_device_get_match_data(dev);
|
||||||
|
|
||||||
|
data = devm_kzalloc(dev, sizeof(*data) +
|
||||||
|
sizeof(*data->ctx.clk_data.hws) * info->nr_clk_ids,
|
||||||
|
GFP_KERNEL);
|
||||||
|
if (!data)
|
||||||
|
return -ENOMEM;
|
||||||
|
ctx = &data->ctx;
|
||||||
|
|
||||||
|
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||||
|
reg_base = devm_ioremap_resource(dev, res);
|
||||||
|
if (IS_ERR(reg_base)) {
|
||||||
|
dev_err(dev, "failed to map registers\n");
|
||||||
|
return PTR_ERR(reg_base);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < info->nr_clk_ids; ++i)
|
||||||
|
ctx->clk_data.hws[i] = ERR_PTR(-ENOENT);
|
||||||
|
|
||||||
|
ctx->clk_data.num = info->nr_clk_ids;
|
||||||
|
ctx->reg_base = reg_base;
|
||||||
|
ctx->dev = dev;
|
||||||
|
spin_lock_init(&ctx->lock);
|
||||||
|
|
||||||
|
data->clk_save = samsung_clk_alloc_reg_dump(info->clk_regs,
|
||||||
|
info->nr_clk_regs);
|
||||||
|
data->nr_clk_save = info->nr_clk_regs;
|
||||||
|
data->clk_suspend = info->suspend_regs;
|
||||||
|
data->nr_clk_suspend = info->nr_suspend_regs;
|
||||||
|
data->nr_pclks = of_count_phandle_with_args(dev->of_node, "clocks",
|
||||||
|
"#clock-cells");
|
||||||
|
if (data->nr_pclks > 0) {
|
||||||
|
data->pclks = devm_kcalloc(dev, sizeof(struct clk *),
|
||||||
|
data->nr_pclks, GFP_KERNEL);
|
||||||
|
|
||||||
|
for (i = 0; i < data->nr_pclks; i++) {
|
||||||
|
struct clk *clk = of_clk_get(dev->of_node, i);
|
||||||
|
|
||||||
|
if (IS_ERR(clk))
|
||||||
|
return PTR_ERR(clk);
|
||||||
|
data->pclks[i] = clk;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (info->clk_name)
|
||||||
|
data->clk = clk_get(dev, info->clk_name);
|
||||||
|
clk_prepare_enable(data->clk);
|
||||||
|
|
||||||
|
platform_set_drvdata(pdev, data);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Enable runtime PM here to allow the clock core using runtime PM
|
||||||
|
* for the registered clocks. Additionally, we increase the runtime
|
||||||
|
* PM usage count before registering the clocks, to prevent the
|
||||||
|
* clock core from runtime suspending the device.
|
||||||
|
*/
|
||||||
|
pm_runtime_get_noresume(dev);
|
||||||
|
pm_runtime_set_active(dev);
|
||||||
|
pm_runtime_enable(dev);
|
||||||
|
|
||||||
|
if (info->pll_clks)
|
||||||
|
samsung_clk_register_pll(ctx, info->pll_clks, info->nr_pll_clks,
|
||||||
|
reg_base);
|
||||||
|
if (info->mux_clks)
|
||||||
|
samsung_clk_register_mux(ctx, info->mux_clks,
|
||||||
|
info->nr_mux_clks);
|
||||||
|
if (info->div_clks)
|
||||||
|
samsung_clk_register_div(ctx, info->div_clks,
|
||||||
|
info->nr_div_clks);
|
||||||
|
if (info->gate_clks)
|
||||||
|
samsung_clk_register_gate(ctx, info->gate_clks,
|
||||||
|
info->nr_gate_clks);
|
||||||
|
if (info->fixed_clks)
|
||||||
|
samsung_clk_register_fixed_rate(ctx, info->fixed_clks,
|
||||||
|
info->nr_fixed_clks);
|
||||||
|
if (info->fixed_factor_clks)
|
||||||
|
samsung_clk_register_fixed_factor(ctx, info->fixed_factor_clks,
|
||||||
|
info->nr_fixed_factor_clks);
|
||||||
|
|
||||||
|
samsung_clk_of_add_provider(dev->of_node, ctx);
|
||||||
|
pm_runtime_put_sync(dev);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct of_device_id exynos5433_cmu_of_match[] = {
|
||||||
|
{
|
||||||
|
.compatible = "samsung,exynos5433-cmu-aud",
|
||||||
|
.data = &aud_cmu_info,
|
||||||
|
}, {
|
||||||
|
.compatible = "samsung,exynos5433-cmu-cam0",
|
||||||
|
.data = &cam0_cmu_info,
|
||||||
|
}, {
|
||||||
|
.compatible = "samsung,exynos5433-cmu-cam1",
|
||||||
|
.data = &cam1_cmu_info,
|
||||||
|
}, {
|
||||||
|
.compatible = "samsung,exynos5433-cmu-disp",
|
||||||
|
.data = &disp_cmu_info,
|
||||||
|
}, {
|
||||||
|
.compatible = "samsung,exynos5433-cmu-g2d",
|
||||||
|
.data = &g2d_cmu_info,
|
||||||
|
}, {
|
||||||
|
.compatible = "samsung,exynos5433-cmu-g3d",
|
||||||
|
.data = &g3d_cmu_info,
|
||||||
|
}, {
|
||||||
|
.compatible = "samsung,exynos5433-cmu-fsys",
|
||||||
|
.data = &fsys_cmu_info,
|
||||||
|
}, {
|
||||||
|
.compatible = "samsung,exynos5433-cmu-gscl",
|
||||||
|
.data = &gscl_cmu_info,
|
||||||
|
}, {
|
||||||
|
.compatible = "samsung,exynos5433-cmu-mfc",
|
||||||
|
.data = &mfc_cmu_info,
|
||||||
|
}, {
|
||||||
|
.compatible = "samsung,exynos5433-cmu-hevc",
|
||||||
|
.data = &hevc_cmu_info,
|
||||||
|
}, {
|
||||||
|
.compatible = "samsung,exynos5433-cmu-isp",
|
||||||
|
.data = &isp_cmu_info,
|
||||||
|
}, {
|
||||||
|
.compatible = "samsung,exynos5433-cmu-mscl",
|
||||||
|
.data = &mscl_cmu_info,
|
||||||
|
}, {
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct dev_pm_ops exynos5433_cmu_pm_ops = {
|
||||||
|
SET_RUNTIME_PM_OPS(exynos5433_cmu_suspend, exynos5433_cmu_resume,
|
||||||
|
NULL)
|
||||||
|
SET_LATE_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
|
||||||
|
pm_runtime_force_resume)
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct platform_driver exynos5433_cmu_driver __refdata = {
|
||||||
|
.driver = {
|
||||||
|
.name = "exynos5433-cmu",
|
||||||
|
.of_match_table = exynos5433_cmu_of_match,
|
||||||
|
.suppress_bind_attrs = true,
|
||||||
|
.pm = &exynos5433_cmu_pm_ops,
|
||||||
|
},
|
||||||
|
.probe = exynos5433_cmu_probe,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int __init exynos5433_cmu_init(void)
|
||||||
|
{
|
||||||
|
return platform_driver_register(&exynos5433_cmu_driver);
|
||||||
|
}
|
||||||
|
core_initcall(exynos5433_cmu_init);
|
||||||
|
@ -1388,7 +1388,7 @@ static void __init _samsung_clk_register_pll(struct samsung_clk_provider *ctx,
|
|||||||
pll->lock_reg = base + pll_clk->lock_offset;
|
pll->lock_reg = base + pll_clk->lock_offset;
|
||||||
pll->con_reg = base + pll_clk->con_offset;
|
pll->con_reg = base + pll_clk->con_offset;
|
||||||
|
|
||||||
ret = clk_hw_register(NULL, &pll->hw);
|
ret = clk_hw_register(ctx->dev, &pll->hw);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
pr_err("%s: failed to register pll clock %s : %d\n",
|
pr_err("%s: failed to register pll clock %s : %d\n",
|
||||||
__func__, pll_clk->name, ret);
|
__func__, pll_clk->name, ret);
|
||||||
|
@ -134,7 +134,7 @@ void __init samsung_clk_register_fixed_rate(struct samsung_clk_provider *ctx,
|
|||||||
unsigned int idx, ret;
|
unsigned int idx, ret;
|
||||||
|
|
||||||
for (idx = 0; idx < nr_clk; idx++, list++) {
|
for (idx = 0; idx < nr_clk; idx++, list++) {
|
||||||
clk_hw = clk_hw_register_fixed_rate(NULL, list->name,
|
clk_hw = clk_hw_register_fixed_rate(ctx->dev, list->name,
|
||||||
list->parent_name, list->flags, list->fixed_rate);
|
list->parent_name, list->flags, list->fixed_rate);
|
||||||
if (IS_ERR(clk_hw)) {
|
if (IS_ERR(clk_hw)) {
|
||||||
pr_err("%s: failed to register clock %s\n", __func__,
|
pr_err("%s: failed to register clock %s\n", __func__,
|
||||||
@ -163,7 +163,7 @@ void __init samsung_clk_register_fixed_factor(struct samsung_clk_provider *ctx,
|
|||||||
unsigned int idx;
|
unsigned int idx;
|
||||||
|
|
||||||
for (idx = 0; idx < nr_clk; idx++, list++) {
|
for (idx = 0; idx < nr_clk; idx++, list++) {
|
||||||
clk_hw = clk_hw_register_fixed_factor(NULL, list->name,
|
clk_hw = clk_hw_register_fixed_factor(ctx->dev, list->name,
|
||||||
list->parent_name, list->flags, list->mult, list->div);
|
list->parent_name, list->flags, list->mult, list->div);
|
||||||
if (IS_ERR(clk_hw)) {
|
if (IS_ERR(clk_hw)) {
|
||||||
pr_err("%s: failed to register clock %s\n", __func__,
|
pr_err("%s: failed to register clock %s\n", __func__,
|
||||||
@ -184,7 +184,7 @@ void __init samsung_clk_register_mux(struct samsung_clk_provider *ctx,
|
|||||||
unsigned int idx, ret;
|
unsigned int idx, ret;
|
||||||
|
|
||||||
for (idx = 0; idx < nr_clk; idx++, list++) {
|
for (idx = 0; idx < nr_clk; idx++, list++) {
|
||||||
clk_hw = clk_hw_register_mux(NULL, list->name,
|
clk_hw = clk_hw_register_mux(ctx->dev, list->name,
|
||||||
list->parent_names, list->num_parents, list->flags,
|
list->parent_names, list->num_parents, list->flags,
|
||||||
ctx->reg_base + list->offset,
|
ctx->reg_base + list->offset,
|
||||||
list->shift, list->width, list->mux_flags, &ctx->lock);
|
list->shift, list->width, list->mux_flags, &ctx->lock);
|
||||||
@ -217,13 +217,13 @@ void __init samsung_clk_register_div(struct samsung_clk_provider *ctx,
|
|||||||
|
|
||||||
for (idx = 0; idx < nr_clk; idx++, list++) {
|
for (idx = 0; idx < nr_clk; idx++, list++) {
|
||||||
if (list->table)
|
if (list->table)
|
||||||
clk_hw = clk_hw_register_divider_table(NULL,
|
clk_hw = clk_hw_register_divider_table(ctx->dev,
|
||||||
list->name, list->parent_name, list->flags,
|
list->name, list->parent_name, list->flags,
|
||||||
ctx->reg_base + list->offset,
|
ctx->reg_base + list->offset,
|
||||||
list->shift, list->width, list->div_flags,
|
list->shift, list->width, list->div_flags,
|
||||||
list->table, &ctx->lock);
|
list->table, &ctx->lock);
|
||||||
else
|
else
|
||||||
clk_hw = clk_hw_register_divider(NULL, list->name,
|
clk_hw = clk_hw_register_divider(ctx->dev, list->name,
|
||||||
list->parent_name, list->flags,
|
list->parent_name, list->flags,
|
||||||
ctx->reg_base + list->offset, list->shift,
|
ctx->reg_base + list->offset, list->shift,
|
||||||
list->width, list->div_flags, &ctx->lock);
|
list->width, list->div_flags, &ctx->lock);
|
||||||
@ -255,7 +255,7 @@ void __init samsung_clk_register_gate(struct samsung_clk_provider *ctx,
|
|||||||
unsigned int idx, ret;
|
unsigned int idx, ret;
|
||||||
|
|
||||||
for (idx = 0; idx < nr_clk; idx++, list++) {
|
for (idx = 0; idx < nr_clk; idx++, list++) {
|
||||||
clk_hw = clk_hw_register_gate(NULL, list->name, list->parent_name,
|
clk_hw = clk_hw_register_gate(ctx->dev, list->name, list->parent_name,
|
||||||
list->flags, ctx->reg_base + list->offset,
|
list->flags, ctx->reg_base + list->offset,
|
||||||
list->bit_idx, list->gate_flags, &ctx->lock);
|
list->bit_idx, list->gate_flags, &ctx->lock);
|
||||||
if (IS_ERR(clk_hw)) {
|
if (IS_ERR(clk_hw)) {
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
*/
|
*/
|
||||||
struct samsung_clk_provider {
|
struct samsung_clk_provider {
|
||||||
void __iomem *reg_base;
|
void __iomem *reg_base;
|
||||||
|
struct device *dev;
|
||||||
spinlock_t lock;
|
spinlock_t lock;
|
||||||
/* clk_data must be the last entry due to variable lenght 'hws' array */
|
/* clk_data must be the last entry due to variable lenght 'hws' array */
|
||||||
struct clk_hw_onecell_data clk_data;
|
struct clk_hw_onecell_data clk_data;
|
||||||
@ -352,6 +353,12 @@ struct samsung_cmu_info {
|
|||||||
/* list and number of clocks registers */
|
/* list and number of clocks registers */
|
||||||
const unsigned long *clk_regs;
|
const unsigned long *clk_regs;
|
||||||
unsigned int nr_clk_regs;
|
unsigned int nr_clk_regs;
|
||||||
|
|
||||||
|
/* list and number of clocks registers to set before suspend */
|
||||||
|
const struct samsung_clk_reg_dump *suspend_regs;
|
||||||
|
unsigned int nr_suspend_regs;
|
||||||
|
/* name of the parent clock needed for CMU register access */
|
||||||
|
const char *clk_name;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern struct samsung_clk_provider *__init samsung_clk_init(
|
extern struct samsung_clk_provider *__init samsung_clk_init(
|
||||||
|
Loading…
Reference in New Issue
Block a user