clk: samsung: exynos5433: Fix error paths
[platform/kernel/linux-exynos.git] / drivers / clk / samsung / clk-exynos5433.c
index 11343a5..01ead7e 100644 (file)
@@ -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>
 
@@ -173,6 +177,17 @@ static const unsigned long top_clk_regs[] __initconst = {
        ENABLE_CMU_TOP_DIV_STAT,
 };
 
+static const struct samsung_clk_reg_dump top_suspend_regs[] = {
+       /* force all aclk clocks enabled */
+       { ENABLE_ACLK_TOP, 0x67ecffed },
+       /* force all sclk_uart clocks enabled */
+       { ENABLE_SCLK_TOP_PERIC, 0x38 },
+       /* ISP PLL has to be enabled for suspend: reset value + ENABLE bit */
+       { ISP_PLL_CON0, 0x85cc0502 },
+       /* ISP PLL has to be enabled for suspend: reset value + ENABLE bit */
+       { AUD_PLL_CON0, 0x84830202 },
+};
+
 /* list of all parent clock list */
 PNAME(mout_aud_pll_p)          = { "oscclk", "fout_aud_pll", };
 PNAME(mout_isp_pll_p)          = { "oscclk", "fout_isp_pll", };
@@ -579,16 +594,16 @@ static const struct samsung_gate_clock top_gate_clks[] __initconst = {
                        CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0),
        GATE(CLK_ACLK_CAM1_333, "aclk_cam1_333", "div_aclk_cam1_333",
                        ENABLE_ACLK_TOP, 13,
-                       CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0),
+                       CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, 0),
        GATE(CLK_ACLK_CAM1_400, "aclk_cam1_400", "div_aclk_cam1_400",
                        ENABLE_ACLK_TOP, 12,
                        CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, 0),
        GATE(CLK_ACLK_CAM1_552, "aclk_cam1_552", "div_aclk_cam1_552",
                        ENABLE_ACLK_TOP, 11,
-                       CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0),
+                       CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, 0),
        GATE(CLK_ACLK_CAM0_333, "aclk_cam0_333", "div_aclk_cam0_333",
                        ENABLE_ACLK_TOP, 10,
-                       CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0),
+                       CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, 0),
        GATE(CLK_ACLK_CAM0_400, "aclk_cam0_400", "div_aclk_cam0_400",
                        ENABLE_ACLK_TOP, 9,
                        CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, 0),
@@ -597,7 +612,7 @@ static const struct samsung_gate_clock top_gate_clks[] __initconst = {
                        CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0),
        GATE(CLK_ACLK_ISP_DIS_400, "aclk_isp_dis_400", "div_aclk_isp_dis_400",
                        ENABLE_ACLK_TOP, 7,
-                       CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0),
+                       CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, 0),
        GATE(CLK_ACLK_ISP_400, "aclk_isp_400", "div_aclk_isp_400",
                        ENABLE_ACLK_TOP, 6,
                        CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, 0),
@@ -620,11 +635,11 @@ static const struct samsung_gate_clock top_gate_clks[] __initconst = {
 
        /* ENABLE_SCLK_TOP_CAM1 */
        GATE(CLK_SCLK_ISP_SENSOR2, "sclk_isp_sensor2", "div_sclk_isp_sensor2_b",
-                       ENABLE_SCLK_TOP_CAM1, 7, 0, 0),
+                       ENABLE_SCLK_TOP_CAM1, 7, CLK_IS_CRITICAL, 0),
        GATE(CLK_SCLK_ISP_SENSOR1, "sclk_isp_sensor1", "div_sclk_isp_sensor1_b",
                        ENABLE_SCLK_TOP_CAM1, 6, 0, 0),
        GATE(CLK_SCLK_ISP_SENSOR0, "sclk_isp_sensor0", "div_sclk_isp_sensor0_b",
-                       ENABLE_SCLK_TOP_CAM1, 5, 0, 0),
+                       ENABLE_SCLK_TOP_CAM1, 5, CLK_IS_CRITICAL, 0),
        GATE(CLK_SCLK_ISP_MCTADC_CAM1, "sclk_isp_mctadc_cam1", "oscclk",
                        ENABLE_SCLK_TOP_CAM1, 4, 0, 0),
        GATE(CLK_SCLK_ISP_UART_CAM1, "sclk_isp_uart_cam1", "div_sclk_isp_uart",
@@ -632,7 +647,7 @@ static const struct samsung_gate_clock top_gate_clks[] __initconst = {
        GATE(CLK_SCLK_ISP_SPI1_CAM1, "sclk_isp_spi1_cam1", "div_sclk_isp_spi1_b",
                        ENABLE_SCLK_TOP_CAM1, 1, 0, 0),
        GATE(CLK_SCLK_ISP_SPI0_CAM1, "sclk_isp_spi0_cam1", "div_sclk_isp_spi0_b",
-                       ENABLE_SCLK_TOP_CAM1, 0, 0, 0),
+                       ENABLE_SCLK_TOP_CAM1, 0, CLK_IS_CRITICAL, 0),
 
        /* ENABLE_SCLK_TOP_DISP */
        GATE(CLK_SCLK_HDMI_SPDIF_DISP, "sclk_hdmi_spdif_disp",
@@ -725,7 +740,7 @@ static const struct samsung_pll_rate_table exynos5433_pll_rates[] __initconst =
        PLL_35XX_RATE(800000000U,  400, 6,  1),
        PLL_35XX_RATE(733000000U,  733, 12, 1),
        PLL_35XX_RATE(700000000U,  175, 3,  1),
-       PLL_35XX_RATE(667000000U,  222, 4,  1),
+       PLL_35XX_RATE(666000000U,  222, 4,  1),
        PLL_35XX_RATE(633000000U,  211, 4,  1),
        PLL_35XX_RATE(600000000U,  500, 5,  2),
        PLL_35XX_RATE(552000000U,  460, 5,  2),
@@ -753,14 +768,15 @@ static const struct samsung_pll_rate_table exynos5433_pll_rates[] __initconst =
 /* AUD_PLL */
 static const struct samsung_pll_rate_table exynos5433_aud_pll_rates[] __initconst = {
        PLL_36XX_RATE(400000000U, 200, 3, 2,      0),
-       PLL_36XX_RATE(393216000U, 197, 3, 2, -25690),
+       PLL_36XX_RATE(393216003U, 197, 3, 2, -25690),
        PLL_36XX_RATE(384000000U, 128, 2, 2,      0),
-       PLL_36XX_RATE(368640000U, 246, 4, 2, -15729),
-       PLL_36XX_RATE(361507200U, 181, 3, 2, -16148),
-       PLL_36XX_RATE(338688000U, 113, 2, 2,  -6816),
-       PLL_36XX_RATE(294912000U,  98, 1, 3,  19923),
+       PLL_36XX_RATE(368639991U, 246, 4, 2, -15729),
+       PLL_36XX_RATE(361507202U, 181, 3, 2, -16148),
+       PLL_36XX_RATE(338687988U, 113, 2, 2,  -6816),
+       PLL_36XX_RATE(294912002U,  98, 1, 3,  19923),
        PLL_36XX_RATE(288000000U,  96, 1, 3,      0),
        PLL_36XX_RATE(252000000U,  84, 1, 3,      0),
+       PLL_36XX_RATE(196608001U, 197, 3, 3, -25690),
        { /* sentinel */ }
 };
 
@@ -787,6 +803,8 @@ static const struct samsung_cmu_info top_cmu_info __initconst = {
        .nr_clk_ids             = TOP_NR_CLK,
        .clk_regs               = top_clk_regs,
        .nr_clk_regs            = ARRAY_SIZE(top_clk_regs),
+       .suspend_regs           = top_suspend_regs,
+       .nr_suspend_regs        = ARRAY_SIZE(top_suspend_regs),
 };
 
 static void __init exynos5433_cmu_top_init(struct device_node *np)
@@ -817,6 +835,13 @@ static const unsigned long cpif_clk_regs[] __initconst = {
        ENABLE_SCLK_CPIF,
 };
 
+static const struct samsung_clk_reg_dump cpif_suspend_regs[] = {
+       /* force all sclk clocks enabled */
+       { ENABLE_SCLK_CPIF, 0x3ff },
+       /* MPHY PLL has to be enabled for suspend: reset value + ENABLE bit */
+       { MPHY_PLL_CON0, 0x81c70601 },
+};
+
 /* list of all parent clock list */
 PNAME(mout_mphy_pll_p)         = { "oscclk", "fout_mphy_pll", };
 
@@ -857,6 +882,8 @@ static const struct samsung_cmu_info cpif_cmu_info __initconst = {
        .nr_clk_ids             = CPIF_NR_CLK,
        .clk_regs               = cpif_clk_regs,
        .nr_clk_regs            = ARRAY_SIZE(cpif_clk_regs),
+       .suspend_regs           = cpif_suspend_regs,
+       .nr_suspend_regs        = ARRAY_SIZE(cpif_suspend_regs),
 };
 
 static void __init exynos5433_cmu_cpif_init(struct device_node *np)
@@ -1433,7 +1460,7 @@ static const struct samsung_gate_clock mif_gate_clks[] __initconst = {
        GATE(CLK_PCLK_GPIO_ALIVE, "pclk_gpio_alive", "div_aclk_mif_133",
                        ENABLE_PCLK_MIF, 8, CLK_IGNORE_UNUSED, 0),
        GATE(CLK_PCLK_ABB, "pclk_abb", "div_aclk_mif_133",
-                       ENABLE_PCLK_MIF, 7, 0, 0),
+                       ENABLE_PCLK_MIF, 7, CLK_IGNORE_UNUSED, 0),
        GATE(CLK_PCLK_PMU_APBIF, "pclk_pmu_apbif", "div_aclk_mif_133",
                        ENABLE_PCLK_MIF, 6, CLK_IGNORE_UNUSED, 0),
        GATE(CLK_PCLK_DDR_PHY1, "pclk_ddr_phy1", "div_aclk_mif_133",
@@ -1542,6 +1569,13 @@ static const unsigned long peric_clk_regs[] __initconst = {
        ENABLE_IP_PERIC2,
 };
 
+static const struct samsung_clk_reg_dump peric_suspend_regs[] = {
+       /* pclk: sci, pmu, sysreg, gpio_{finger, ese, touch, nfc}, uart2-0 */
+       { ENABLE_PCLK_PERIC0, 0xe00ff000 },
+       /* sclk: uart2-0 */
+       { ENABLE_SCLK_PERIC, 0x7 },
+};
+
 static const struct samsung_div_clock peric_div_clks[] __initconst = {
        /* DIV_PERIC */
        DIV(CLK_DIV_SCLK_SCI, "div_sclk_sci", "oscclk", DIV_PERIC, 4, 4),
@@ -1650,11 +1684,12 @@ static const struct samsung_gate_clock peric_gate_clks[] __initconst = {
        GATE(CLK_SCLK_IOCLK_SPI4, "sclk_ioclk_spi4", "ioclk_spi4_clk_in",
                        ENABLE_SCLK_PERIC, 21, CLK_SET_RATE_PARENT, 0),
        GATE(CLK_SCLK_IOCLK_SPI3, "sclk_ioclk_spi3", "ioclk_spi3_clk_in",
-                       ENABLE_SCLK_PERIC, 20, CLK_SET_RATE_PARENT, 0),
+                       ENABLE_SCLK_PERIC, 20,
+                       CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0),
        GATE(CLK_SCLK_SPI4, "sclk_spi4", "sclk_spi4_peric", ENABLE_SCLK_PERIC,
                        19, CLK_SET_RATE_PARENT, 0),
        GATE(CLK_SCLK_SPI3, "sclk_spi3", "sclk_spi3_peric", ENABLE_SCLK_PERIC,
-                       18, CLK_SET_RATE_PARENT, 0),
+                       18, CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0),
        GATE(CLK_SCLK_SCI, "sclk_sci", "div_sclk_sci", ENABLE_SCLK_PERIC,
                        17, 0, 0),
        GATE(CLK_SCLK_SC_IN, "sclk_sc_in", "div_sclk_sc_in", ENABLE_SCLK_PERIC,
@@ -1663,12 +1698,14 @@ static const struct samsung_gate_clock peric_gate_clks[] __initconst = {
        GATE(CLK_SCLK_IOCLK_SPI2, "sclk_ioclk_spi2", "ioclk_spi2_clk_in",
                        ENABLE_SCLK_PERIC, 13, CLK_SET_RATE_PARENT, 0),
        GATE(CLK_SCLK_IOCLK_SPI1, "sclk_ioclk_spi1", "ioclk_spi1_clk_in",
-                       ENABLE_SCLK_PERIC, 12, CLK_SET_RATE_PARENT, 0),
+                       ENABLE_SCLK_PERIC, 12,
+                       CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT, 0),
        GATE(CLK_SCLK_IOCLK_SPI0, "sclk_ioclk_spi0", "ioclk_spi0_clk_in",
-                       ENABLE_SCLK_PERIC, 11, CLK_SET_RATE_PARENT, 0),
+                       ENABLE_SCLK_PERIC, 11,
+                       CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0),
        GATE(CLK_SCLK_IOCLK_I2S1_BCLK, "sclk_ioclk_i2s1_bclk",
                        "ioclk_i2s1_bclk_in", ENABLE_SCLK_PERIC, 10,
-                       CLK_SET_RATE_PARENT, 0),
+                       CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0),
        GATE(CLK_SCLK_SPDIF, "sclk_spdif", "sclk_spdif_peric",
                        ENABLE_SCLK_PERIC, 8, CLK_SET_RATE_PARENT, 0),
        GATE(CLK_SCLK_PCM1, "sclk_pcm1", "sclk_pcm1_peric",
@@ -1678,9 +1715,9 @@ static const struct samsung_gate_clock peric_gate_clks[] __initconst = {
        GATE(CLK_SCLK_SPI2, "sclk_spi2", "sclk_spi2_peric", ENABLE_SCLK_PERIC,
                        5, CLK_SET_RATE_PARENT, 0),
        GATE(CLK_SCLK_SPI1, "sclk_spi1", "sclk_spi1_peric", ENABLE_SCLK_PERIC,
-                       4, CLK_SET_RATE_PARENT, 0),
+                       4, CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT, 0),
        GATE(CLK_SCLK_SPI0, "sclk_spi0", "sclk_spi0_peric", ENABLE_SCLK_PERIC,
-                       3, CLK_SET_RATE_PARENT, 0),
+                       3, CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0),
        GATE(CLK_SCLK_UART2, "sclk_uart2", "sclk_uart2_peric",
                        ENABLE_SCLK_PERIC, 2,
                        CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0),
@@ -1700,6 +1737,8 @@ static const struct samsung_cmu_info peric_cmu_info __initconst = {
        .nr_clk_ids             = PERIC_NR_CLK,
        .clk_regs               = peric_clk_regs,
        .nr_clk_regs            = ARRAY_SIZE(peric_clk_regs),
+       .suspend_regs           = peric_suspend_regs,
+       .nr_suspend_regs        = ARRAY_SIZE(peric_suspend_regs),
 };
 
 static void __init exynos5433_cmu_peric_init(struct device_node *np)
@@ -1855,7 +1894,7 @@ static const struct samsung_gate_clock peris_gate_clks[] __initconst = {
 
        /* ENABLE_SCLK_PERIS */
        GATE(CLK_SCLK_ASV_TB, "sclk_asv_tb", "oscclk_efuse_common",
-                       ENABLE_SCLK_PERIS, 10, 0, 0),
+                       ENABLE_SCLK_PERIS, 10, CLK_IGNORE_UNUSED, 0),
        GATE(CLK_SCLK_TMU1, "sclk_tmu1", "oscclk_efuse_common",
                        ENABLE_SCLK_PERIS, 4, 0, 0),
        GATE(CLK_SCLK_TMU0, "sclk_tmu0", "oscclk_efuse_common",
@@ -1991,6 +2030,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 +2343,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 +2377,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 +2466,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 +2535,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 +2894,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 +2933,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 +3064,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 +3270,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 +3347,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 +3390,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 +3490,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 +4020,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 +4137,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 +4171,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 +4245,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 +4279,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 +4355,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 +4393,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", };
 
@@ -4370,17 +4425,17 @@ static const struct samsung_gate_clock isp_gate_clks[] __initconst = {
        GATE(CLK_ACLK_ISP_D_GLUE, "aclk_isp_d_glue", "mout_aclk_isp_400_user",
                        ENABLE_ACLK_ISP0, 6, CLK_IGNORE_UNUSED, 0),
        GATE(CLK_ACLK_SCALERP, "aclk_scalerp", "mout_aclk_isp_400_user",
-                       ENABLE_ACLK_ISP0, 5, 0, 0),
+                       ENABLE_ACLK_ISP0, 5, CLK_IGNORE_UNUSED, 0),
        GATE(CLK_ACLK_3DNR, "aclk_3dnr", "mout_aclk_isp_400_user",
-                       ENABLE_ACLK_ISP0, 4, 0, 0),
+                       ENABLE_ACLK_ISP0, 4, CLK_IGNORE_UNUSED, 0),
        GATE(CLK_ACLK_DIS, "aclk_dis", "mout_aclk_isp_dis_400_user",
-                       ENABLE_ACLK_ISP0, 3, 0, 0),
+                       ENABLE_ACLK_ISP0, 3, CLK_IGNORE_UNUSED, 0),
        GATE(CLK_ACLK_SCALERC, "aclk_scalerc", "mout_aclk_isp_400_user",
-                       ENABLE_ACLK_ISP0, 2, 0, 0),
+                       ENABLE_ACLK_ISP0, 2, CLK_IGNORE_UNUSED, 0),
        GATE(CLK_ACLK_DRC, "aclk_drc", "mout_aclk_isp_400_user",
-                       ENABLE_ACLK_ISP0, 1, 0, 0),
+                       ENABLE_ACLK_ISP0, 1, CLK_IGNORE_UNUSED, 0),
        GATE(CLK_ACLK_ISP, "aclk_isp", "mout_aclk_isp_400_user",
-                       ENABLE_ACLK_ISP0, 0, 0, 0),
+                       ENABLE_ACLK_ISP0, 0, CLK_IGNORE_UNUSED, 0),
 
        /* ENABLE_ACLK_ISP1 */
        GATE(CLK_ACLK_AXIUS_SCALERP, "aclk_axius_scalerp",
@@ -4541,6 +4596,20 @@ static const struct samsung_gate_clock isp_gate_clks[] __initconst = {
        GATE(CLK_SCLK_PIXELASYNCM_ISPC, "sclk_pixelasyncm_ispc",
                        "mout_aclk_isp_400_user", ENABLE_SCLK_ISP,
                        0, CLK_IGNORE_UNUSED, 0),
+
+       /* ENABLE_IP_ISP2 */
+       GATE(CLK_BTS_3DNR, "clk_bts_3dnr", "",
+                       ENABLE_IP_ISP2, 5, CLK_IGNORE_UNUSED, 0),
+       GATE(CLK_BTS_DIS1, "clk_bts_dis1", "",
+                       ENABLE_IP_ISP2, 4, CLK_IGNORE_UNUSED, 0),
+       GATE(CLK_BTS_DIS0, "clk_bts_dis0", "",
+                       ENABLE_IP_ISP2, 3, CLK_IGNORE_UNUSED, 0),
+       GATE(CLK_BTS_SCALERC, "clk_bts_scalerc", "",
+                       ENABLE_IP_ISP2, 2, CLK_IGNORE_UNUSED, 0),
+       GATE(CLK_BTS_DRC, "clk_bts_drc", "",
+                       ENABLE_IP_ISP2, 1, CLK_IGNORE_UNUSED, 0),
+       GATE(CLK_BTS_ISP, "clk_bts_isp", "",
+                       ENABLE_IP_ISP2, 0, CLK_IGNORE_UNUSED, 0),
 };
 
 static const struct samsung_cmu_info isp_cmu_info __initconst = {
@@ -4553,15 +4622,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 +4690,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", };
@@ -4814,19 +4888,19 @@ static const struct samsung_div_clock cam0_div_clks[] __initconst = {
 static const struct samsung_gate_clock cam0_gate_clks[] __initconst = {
        /* ENABLE_ACLK_CAM00 */
        GATE(CLK_ACLK_CSIS1, "aclk_csis1", "div_aclk_csis1", ENABLE_ACLK_CAM00,
-                       6, 0, 0),
+                       6, CLK_IGNORE_UNUSED, 0),
        GATE(CLK_ACLK_CSIS0, "aclk_csis0", "div_aclk_csis0", ENABLE_ACLK_CAM00,
-                       5, 0, 0),
+                       5, CLK_IGNORE_UNUSED, 0),
        GATE(CLK_ACLK_3AA1, "aclk_3aa1", "div_aclk_3aa1", ENABLE_ACLK_CAM00,
-                       4, 0, 0),
+                       4, CLK_IGNORE_UNUSED, 0),
        GATE(CLK_ACLK_3AA0, "aclk_3aa0", "div_aclk_3aa0", ENABLE_ACLK_CAM00,
-                       3, 0, 0),
+                       3, CLK_IGNORE_UNUSED, 0),
        GATE(CLK_ACLK_LITE_D, "aclk_lite_d", "div_aclk_lite_d",
-                       ENABLE_ACLK_CAM00, 2, 0, 0),
+                       ENABLE_ACLK_CAM00, 2, CLK_IGNORE_UNUSED, 0),
        GATE(CLK_ACLK_LITE_B, "aclk_lite_b", "div_aclk_lite_b",
-                       ENABLE_ACLK_CAM00, 1, 0, 0),
+                       ENABLE_ACLK_CAM00, 1, CLK_IGNORE_UNUSED, 0),
        GATE(CLK_ACLK_LITE_A, "aclk_lite_a", "div_aclk_lite_a",
-                       ENABLE_ACLK_CAM00, 0, 0, 0),
+                       ENABLE_ACLK_CAM00, 0, CLK_IGNORE_UNUSED, 0),
 
        /* ENABLE_ACLK_CAM01 */
        GATE(CLK_ACLK_AHBSYNCDN, "aclk_ahbsyncdn", "div_aclk_cam0_200",
@@ -4995,27 +5069,89 @@ static const struct samsung_gate_clock cam0_gate_clks[] __initconst = {
        /* ENABLE_SCLK_CAM0 */
        GATE(CLK_PHYCLK_RXBYTECLKHS0_S4, "phyclk_rxbyteclkhs0_s4",
                        "mout_phyclk_rxbyteclkhs0_s4_user",
-                       ENABLE_SCLK_CAM0, 8, 0, 0),
+                       ENABLE_SCLK_CAM0, 8, CLK_IGNORE_UNUSED, 0),
        GATE(CLK_PHYCLK_RXBYTECLKHS0_S2A, "phyclk_rxbyteclkhs0_s2a",
                        "mout_phyclk_rxbyteclkhs0_s2a_user",
-                       ENABLE_SCLK_CAM0, 7, 0, 0),
+                       ENABLE_SCLK_CAM0, 7, CLK_IGNORE_UNUSED, 0),
        GATE(CLK_SCLK_LITE_FREECNT, "sclk_lite_freecnt",
-                       "mout_sclk_lite_freecnt_c", ENABLE_SCLK_CAM0, 6, 0, 0),
+                       "mout_sclk_lite_freecnt_c", ENABLE_SCLK_CAM0, 6,
+                       CLK_IGNORE_UNUSED, 0),
        GATE(CLK_SCLK_PIXELASYNCM_3AA1, "sclk_pixelasycm_3aa1",
-                       "div_aclk_3aa1", ENABLE_SCLK_CAM0, 5, 0, 0),
+                       "div_aclk_3aa1", ENABLE_SCLK_CAM0, 5,
+                       CLK_IGNORE_UNUSED, 0),
        GATE(CLK_SCLK_PIXELASYNCM_3AA0, "sclk_pixelasycm_3aa0",
-                       "div_aclk_3aa0", ENABLE_SCLK_CAM0, 4, 0, 0),
+                       "div_aclk_3aa0", ENABLE_SCLK_CAM0, 4,
+                       CLK_IGNORE_UNUSED, 0),
        GATE(CLK_SCLK_PIXELASYNCS_3AA0, "sclk_pixelasycs_3aa0",
-                       "div_aclk_3aa0", ENABLE_SCLK_CAM0, 3, 0, 0),
+                       "div_aclk_3aa0", ENABLE_SCLK_CAM0, 3,
+                       CLK_IGNORE_UNUSED, 0),
        GATE(CLK_SCLK_PIXELASYNCM_LITE_C, "sclk_pixelasyncm_lite_c",
                        "div_sclk_pixelasync_lite_c",
-                       ENABLE_SCLK_CAM0, 2, 0, 0),
+                       ENABLE_SCLK_CAM0, 2, CLK_IGNORE_UNUSED, 0),
        GATE(CLK_SCLK_PIXELASYNCM_LITE_C_INIT, "sclk_pixelasyncm_lite_c_init",
                        "div_sclk_pixelasync_lite_c_init",
-                       ENABLE_SCLK_CAM0, 1, 0, 0),
+                       ENABLE_SCLK_CAM0, 1, CLK_IGNORE_UNUSED, 0),
        GATE(CLK_SCLK_PIXELASYNCS_LITE_C_INIT, "sclk_pixelasyncs_lite_c_init",
                        "div_sclk_pixelasync_lite_c",
-                       ENABLE_SCLK_CAM0, 0, 0, 0),
+                       ENABLE_SCLK_CAM0, 0, CLK_IGNORE_UNUSED, 0),
+
+       /* ENABLE_IP_CAM03 */
+       GATE(CLK_LITE_FREECNT, "clk_lite_freecnt", "",
+                       ENABLE_IP_CAM03, 4, CLK_IGNORE_UNUSED, 0),
+       GATE(CLK_PIXELASYNC_3AA1, "clk_pixelasync_3aa1", "",
+                       ENABLE_IP_CAM03, 3, CLK_IGNORE_UNUSED, 0),
+       GATE(CLK_PIXELASYNC_3AA0, "clk_pixelasync_3aa0", "",
+                       ENABLE_IP_CAM03, 2, CLK_IGNORE_UNUSED, 0),
+       GATE(CLK_PIXELASYNC_LITE_C, "clk_pixelasync_lite_c", "",
+                       ENABLE_IP_CAM03, 1, CLK_IGNORE_UNUSED, 0),
+       GATE(CLK_PIXELASYNC_LITE_C_INIT, "clk_pixelasync_lite_c_init", "",
+                       ENABLE_IP_CAM03, 0, CLK_IGNORE_UNUSED, 0),
+       /* ENABLE_IP_CAM02 */
+       GATE(CLK_BTS_3AA1, "clk_bts_3aa1", "",
+                       ENABLE_IP_CAM02, 4, CLK_IGNORE_UNUSED, 0),
+       GATE(CLK_BTS_3AA0, "clk_bts_3aa0", "",
+                       ENABLE_IP_CAM02, 3, CLK_IGNORE_UNUSED, 0),
+
+       /* ENABLE_IP_CAM01 */
+       GATE(CLK_AXIUS_LITE_D, "clk_axius_lite_d", "",
+                       ENABLE_IP_CAM01, 21, CLK_IGNORE_UNUSED, 0),
+       GATE(CLK_AXIUS_LITE_B, "clk_axius_lite_b", "",
+                       ENABLE_IP_CAM01, 20, CLK_IGNORE_UNUSED, 0),
+       GATE(CLK_AXIUS_LITE_A, "clk_axius_lite_a", "",
+                       ENABLE_IP_CAM01, 19, CLK_IGNORE_UNUSED, 0),
+
+       GATE(CLK_ASYNCAXI_3AA1, "clk_asyncaxi_3aa1", "",
+                       ENABLE_IP_CAM01, 11, CLK_IGNORE_UNUSED, 0),
+       GATE(CLK_ASYNCAXI_3AA0, "clk_asyncaxi_3aa0", "",
+                       ENABLE_IP_CAM01, 10, CLK_IGNORE_UNUSED, 0),
+       GATE(CLK_ASYNCAXI_LITE_D, "clk_asyncaxi_lite_d", "",
+                       ENABLE_IP_CAM01, 9, CLK_IGNORE_UNUSED, 0),
+       GATE(CLK_ASYNCAXI_LITE_B, "clk_asyncaxi_lite_b", "",
+                       ENABLE_IP_CAM01, 8, CLK_IGNORE_UNUSED, 0),
+       GATE(CLK_ASYNCAXI_LITE_A, "clk_asyncaxi_lite_a", "",
+                       ENABLE_IP_CAM01, 7, CLK_IGNORE_UNUSED, 0),
+
+       /* ENABLE_IP_CAM00 */
+       GATE(CLK_PMU_CAM0, "clk_pmu_cam0", "",
+                       ENABLE_IP_CAM00, 9, CLK_IGNORE_UNUSED, 0),
+       GATE(CLK_SYSREG_CAM0, "clk_sysreg_cam0", "",
+                       ENABLE_IP_CAM00, 8, CLK_IGNORE_UNUSED, 0),
+       GATE(CLK_CMU_CAM0_LOCAL, "clk_cmu_cam0_local", "",
+                       ENABLE_IP_CAM00, 7, CLK_IGNORE_UNUSED, 0),
+       GATE(CLK_CSIS1, "clk_csis1", "",
+                       ENABLE_IP_CAM00, 6, CLK_IGNORE_UNUSED, 0),
+       GATE(CLK_CSIS0, "clk_csis0", "",
+                       ENABLE_IP_CAM00, 5, CLK_IGNORE_UNUSED, 0),
+       GATE(CLK_3AA1, "clk_3aa1", "",
+                       ENABLE_IP_CAM00, 4, CLK_IGNORE_UNUSED, 0),
+       GATE(CLK_3AA0, "clk_3aa0", "",
+                       ENABLE_IP_CAM00, 3, CLK_IGNORE_UNUSED, 0),
+       GATE(CLK_LITE_D, "clk_lite_d", "",
+                       ENABLE_IP_CAM00, 2, CLK_IGNORE_UNUSED, 0),
+       GATE(CLK_LITE_B, "clk_lite_b", "",
+                       ENABLE_IP_CAM00, 1, CLK_IGNORE_UNUSED, 0),
+       GATE(CLK_LITE_A, "clk_lite_a", "",
+                       ENABLE_IP_CAM00, 0, CLK_IGNORE_UNUSED, 0),
 };
 
 static const struct samsung_cmu_info cam0_cmu_info __initconst = {
@@ -5030,15 +5166,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 +5217,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", };
@@ -5179,13 +5317,13 @@ static const struct samsung_div_clock cam1_div_clks[] __initconst = {
 static const struct samsung_gate_clock cam1_gate_clks[] __initconst = {
        /* ENABLE_ACLK_CAM10 */
        GATE(CLK_ACLK_ISP_GIC, "aclk_isp_gic", "mout_aclk_cam1_333_user",
-                       ENABLE_ACLK_CAM10, 4, 0, 0),
+                       ENABLE_ACLK_CAM10, 4, CLK_IGNORE_UNUSED, 0),
        GATE(CLK_ACLK_FD, "aclk_fd", "div_aclk_fd",
-                       ENABLE_ACLK_CAM10, 3, 0, 0),
+                       ENABLE_ACLK_CAM10, 3, CLK_IGNORE_UNUSED, 0),
        GATE(CLK_ACLK_LITE_C, "aclk_lite_c", "div_aclk_lite_c",
-                       ENABLE_ACLK_CAM10, 1, 0, 0),
+                       ENABLE_ACLK_CAM10, 1, CLK_IGNORE_UNUSED, 0),
        GATE(CLK_ACLK_CSIS2, "aclk_csis2", "div_aclk_csis2",
-                       ENABLE_ACLK_CAM10, 0, 0, 0),
+                       ENABLE_ACLK_CAM10, 0, CLK_IGNORE_UNUSED, 0),
 
        /* ENABLE_ACLK_CAM11 */
        GATE(CLK_ACLK_ASYNCAPBM_FD, "aclk_asyncapbm_fd", "div_pclk_fd",
@@ -5359,36 +5497,56 @@ static const struct samsung_gate_clock cam1_gate_clks[] __initconst = {
 
        /* ENABLE_SCLK_CAM1 */
        GATE(CLK_SCLK_ISP_I2C2, "sclk_isp_i2c2", "oscclk", ENABLE_SCLK_CAM1,
-                       15, 0, 0),
+                       15, CLK_IGNORE_UNUSED, 0),
        GATE(CLK_SCLK_ISP_I2C1, "sclk_isp_i2c1", "oscclk", ENABLE_SCLK_CAM1,
-                       14, 0, 0),
+                       14, CLK_IGNORE_UNUSED, 0),
        GATE(CLK_SCLK_ISP_I2C0, "sclk_isp_i2c0", "oscclk", ENABLE_SCLK_CAM1,
-                       13, 0, 0),
+                       13, CLK_IGNORE_UNUSED, 0),
        GATE(CLK_SCLK_ISP_PWM, "sclk_isp_pwm", "oscclk", ENABLE_SCLK_CAM1,
-                       12, 0, 0),
+                       12, CLK_IGNORE_UNUSED, 0),
        GATE(CLK_PHYCLK_RXBYTECLKHS0_S2B, "phyclk_rxbyteclkhs0_s2b",
                        "mout_phyclk_rxbyteclkhs0_s2b_user",
-                       ENABLE_SCLK_CAM1, 11, 0, 0),
+                       ENABLE_SCLK_CAM1, 11, CLK_IGNORE_UNUSED, 0),
        GATE(CLK_SCLK_LITE_C_FREECNT, "sclk_lite_c_freecnt", "div_pclk_lite_c",
-                       ENABLE_SCLK_CAM1, 10, 0, 0),
+                       ENABLE_SCLK_CAM1, 10, CLK_IGNORE_UNUSED, 0),
        GATE(CLK_SCLK_PIXELASYNCM_FD, "sclk_pixelasyncm_fd", "div_aclk_fd",
-                       ENABLE_SCLK_CAM1, 9, 0, 0),
+                       ENABLE_SCLK_CAM1, 9, CLK_IGNORE_UNUSED, 0),
        GATE(CLK_SCLK_ISP_MCTADC, "sclk_isp_mctadc", "sclk_isp_mctadc_cam1",
-                       ENABLE_SCLK_CAM1, 7, 0, 0),
+                       ENABLE_SCLK_CAM1, 7, CLK_IGNORE_UNUSED, 0),
        GATE(CLK_SCLK_ISP_UART, "sclk_isp_uart", "mout_sclk_isp_uart_user",
-                       ENABLE_SCLK_CAM1, 6, 0, 0),
+                       ENABLE_SCLK_CAM1, 6, CLK_IGNORE_UNUSED, 0),
        GATE(CLK_SCLK_ISP_SPI1, "sclk_isp_spi1", "mout_sclk_isp_spi1_user",
-                       ENABLE_SCLK_CAM1, 5, 0, 0),
+                       ENABLE_SCLK_CAM1, 5, CLK_IGNORE_UNUSED, 0),
        GATE(CLK_SCLK_ISP_SPI0, "sclk_isp_spi0", "mout_sclk_isp_spi0_user",
-                       ENABLE_SCLK_CAM1, 4, 0, 0),
+                       ENABLE_SCLK_CAM1, 4, CLK_IGNORE_UNUSED, 0),
        GATE(CLK_SCLK_ISP_MPWM, "sclk_isp_mpwm", "div_sclk_isp_mpwm",
-                       ENABLE_SCLK_CAM1, 3, 0, 0),
+                       ENABLE_SCLK_CAM1, 3, CLK_IGNORE_UNUSED, 0),
        GATE(CLK_PCLK_DBG_ISP, "sclk_dbg_isp", "div_pclk_dbg_cam1",
-                       ENABLE_SCLK_CAM1, 2, 0, 0),
+                       ENABLE_SCLK_CAM1, 2, CLK_IGNORE_UNUSED, 0),
        GATE(CLK_ATCLK_ISP, "atclk_isp", "div_atclk_cam1",
-                       ENABLE_SCLK_CAM1, 1, 0, 0),
+                       ENABLE_SCLK_CAM1, 1, CLK_IGNORE_UNUSED, 0),
        GATE(CLK_SCLK_ISP_CA5, "sclk_isp_ca5", "mout_aclk_cam1_552_user",
-                       ENABLE_SCLK_CAM1, 0, 0, 0),
+                       ENABLE_SCLK_CAM1, 0, CLK_IGNORE_UNUSED, 0),
+
+       /* IP_CAM12 */
+       GATE(CLK_BTS_FD, "clk_bts_fd", "",
+                       ENABLE_IP_CAM12, 6, CLK_IGNORE_UNUSED, 0),
+
+       /* IP_CAM10 */
+       GATE(CLK_RXBYTECLKHS0_S2B, "clk_rxbyteclkhs0_s2b", "",
+                       ENABLE_IP_CAM10, 23, CLK_IGNORE_UNUSED, 0),
+       GATE(CLK_LITE_C_FREECNT, "clk_lite_c_freecnt", "",
+                       ENABLE_IP_CAM10, 22, CLK_IGNORE_UNUSED, 0),
+       GATE(CLK_PIXELASYNCS_LITE_C, "clk_pixelasyncs_lite_c", "",
+                       ENABLE_IP_CAM10, 20, CLK_IGNORE_UNUSED, 0),
+       GATE(CLK_ISP_SPI1, "clk_isp_spi1", "",
+                       ENABLE_IP_CAM10, 10, CLK_IGNORE_UNUSED, 0),
+       GATE(CLK_ISP_SPI0, "clk_isp_spi0", "",
+                       ENABLE_IP_CAM10, 9, CLK_IGNORE_UNUSED, 0),
+       GATE(CLK_LITE_C, "clk_lite_c", "",
+                       ENABLE_IP_CAM10, 2, CLK_IGNORE_UNUSED, 0),
+       GATE(CLK_CSIS2, "clk_csis2", "",
+                       ENABLE_IP_CAM10, 1, CLK_IGNORE_UNUSED, 0),
 };
 
 static const struct samsung_cmu_info cam1_cmu_info __initconst = {
@@ -5403,11 +5561,250 @@ 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 __maybe_unused 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 __maybe_unused 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;
+}
+
+/*
+ * late_suspend and early_resume callbacks are required to balance
+ * pm_runtime_disable and pm_runtime_enable calls in device_suspend_late
+ * and device_resume_early core functions to keep runtime enabled for
+ * CMU device during noirq sleep phase.
+ */
+static int __maybe_unused exynos5433_late_suspend(struct device *dev)
+{
+       pm_runtime_enable(dev);
+       return 0;
+}
+
+static int __maybe_unused exynos5433_early_resume(struct device *dev)
+{
+       pm_runtime_disable(dev);
+       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))
+               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);
+       if (!data->clk_save)
+               return -ENOMEM;
+       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);
+               if (!data->pclks) {
+                       kfree(data->clk_save);
+                       return -ENOMEM;
+               }
+               for (i = 0; i < data->nr_pclks; i++) {
+                       struct clk *clk = of_clk_get(dev->of_node, i);
+
+                       if (IS_ERR(clk)) {
+                               kfree(data->clk_save);
+                               while (--i >= 0)
+                                       clk_put(data->pclks[i]);
+                               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(exynos5433_late_suspend,
+                                    exynos5433_early_resume)
+       SET_NOIRQ_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);