|
|
@@ -9,9 +9,13 @@
|
|
|
* Common Clock Framework support for Exynos5433 SoC.
|
|
|
*/
|
|
|
|
|
|
+#include <linux/clk.h>
|
|
|
#include <linux/clk-provider.h>
|
|
|
#include <linux/of.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>
|
|
|
|
|
|
@@ -1991,6 +1995,14 @@ static const unsigned long fsys_clk_regs[] __initconst = {
|
|
|
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 = {
|
|
|
/* PHY clocks from USBDRD30_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,
|
|
|
.clk_regs = 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
|
|
|
*/
|
|
|
@@ -2335,6 +2342,10 @@ static const unsigned long g2d_clk_regs[] __initconst = {
|
|
|
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 */
|
|
|
PNAME(mout_aclk_g2d_266_user_p) = { "oscclk", "aclk_g2d_266", };
|
|
|
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,
|
|
|
.clk_regs = 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
|
|
|
*/
|
|
|
@@ -2494,6 +2500,18 @@ static const unsigned long disp_clk_regs[] __initconst = {
|
|
|
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 */
|
|
|
PNAME(mout_disp_pll_p) = { "oscclk", "fout_disp_pll", };
|
|
|
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,
|
|
|
.clk_regs = 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
|
|
|
*/
|
|
|
@@ -2885,6 +2898,11 @@ static const unsigned long aud_clk_regs[] __initconst = {
|
|
|
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 */
|
|
|
PNAME(mout_aud_pll_user_aud_p) = { "oscclk", "fout_aud_pll", };
|
|
|
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,
|
|
|
.clk_regs = 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}
|
|
|
*/
|
|
|
@@ -3222,6 +3235,10 @@ static const unsigned long g3d_clk_regs[] __initconst = {
|
|
|
CLK_STOPCTRL,
|
|
|
};
|
|
|
|
|
|
+static const struct samsung_clk_reg_dump g3d_suspend_regs[] = {
|
|
|
+ { MUX_SEL_G3D, 0 },
|
|
|
+};
|
|
|
+
|
|
|
/* list of all parent clock list */
|
|
|
PNAME(mout_aclk_g3d_400_p) = { "mout_g3d_pll", "aclk_g3d_400", };
|
|
|
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,
|
|
|
.clk_regs = 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
|
|
|
*/
|
|
|
@@ -3342,6 +3355,12 @@ static const unsigned long gscl_clk_regs[] __initconst = {
|
|
|
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 */
|
|
|
PNAME(aclk_gscl_111_user_p) = { "oscclk", "aclk_gscl_111", };
|
|
|
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,
|
|
|
.clk_regs = 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
|
|
|
*/
|
|
|
@@ -3970,6 +3985,11 @@ static const unsigned long mscl_clk_regs[] __initconst = {
|
|
|
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 */
|
|
|
PNAME(mout_sclk_jpeg_user_p) = { "oscclk", "sclk_jpeg_mscl", };
|
|
|
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,
|
|
|
.clk_regs = 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
|
|
|
*/
|
|
|
@@ -4120,6 +4136,10 @@ static const unsigned long mfc_clk_regs[] __initconst = {
|
|
|
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", };
|
|
|
|
|
|
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,
|
|
|
.clk_regs = 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
|
|
|
*/
|
|
|
@@ -4228,6 +4244,10 @@ static const unsigned long hevc_clk_regs[] __initconst = {
|
|
|
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", };
|
|
|
|
|
|
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,
|
|
|
.clk_regs = 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
|
|
|
*/
|
|
|
@@ -4342,6 +4358,10 @@ static const unsigned long isp_clk_regs[] __initconst = {
|
|
|
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_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,
|
|
|
.clk_regs = 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
|
|
|
*/
|
|
|
@@ -4625,6 +4641,15 @@ static const unsigned long cam0_clk_regs[] __initconst = {
|
|
|
ENABLE_IP_CAM02,
|
|
|
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_400_user_p) = { "oscclk", "aclk_cam0_400", };
|
|
|
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,
|
|
|
.clk_regs = 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
|
|
|
*/
|
|
|
@@ -5085,6 +5106,12 @@ static const unsigned long cam1_clk_regs[] __initconst = {
|
|
|
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_spi1_user_p) = { "oscclk", "sclk_isp_spi1_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,
|
|
|
.clk_regs = 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",
|
|
|
+};
|
|
|
+
|
|
|
+
|
|
|
+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)
|
|
|
+{
|
|
|
+ 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;
|
|
|
+}
|
|
|
+
|
|
|
+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 void __init exynos5433_cmu_cam1_init(struct device_node *np)
|
|
|
+static int __init exynos5433_cmu_init(void)
|
|
|
{
|
|
|
- samsung_cmu_register_one(np, &cam1_cmu_info);
|
|
|
+ return platform_driver_register(&exynos5433_cmu_driver);
|
|
|
}
|
|
|
-CLK_OF_DECLARE(exynos5433_cmu_cam1, "samsung,exynos5433-cmu-cam1",
|
|
|
- exynos5433_cmu_cam1_init);
|
|
|
+core_initcall(exynos5433_cmu_init);
|