aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/clk
diff options
context:
space:
mode:
authorKukjin Kim <kgene.kim@samsung.com>2014-05-25 15:04:47 -0400
committerKukjin Kim <kgene.kim@samsung.com>2014-05-25 15:04:47 -0400
commitb5783dcaed065ae6622a9795a19a4eda748b64f8 (patch)
tree7a1dc27919e217182fc1a7d3105e10f426b993ec /drivers/clk
parent702b691e4a711e699cf3cccba879c1d945665c0d (diff)
parent34c453ce16633539a94a2e876faeb731ac1be899 (diff)
Merge branch 'v3.16-next/clk-s3c24xx-3' into v3.16-next/cleanup-samsung
Diffstat (limited to 'drivers/clk')
-rw-r--r--drivers/clk/samsung/Makefile4
-rw-r--r--drivers/clk/samsung/clk-pll.c266
-rw-r--r--drivers/clk/samsung/clk-pll.h6
-rw-r--r--drivers/clk/samsung/clk-s3c2410-dclk.c440
-rw-r--r--drivers/clk/samsung/clk-s3c2410.c477
-rw-r--r--drivers/clk/samsung/clk-s3c2412.c269
-rw-r--r--drivers/clk/samsung/clk-s3c2443.c462
7 files changed, 1922 insertions, 2 deletions
diff --git a/drivers/clk/samsung/Makefile b/drivers/clk/samsung/Makefile
index 8eb4799237f0..2cb62f87e068 100644
--- a/drivers/clk/samsung/Makefile
+++ b/drivers/clk/samsung/Makefile
@@ -8,4 +8,8 @@ obj-$(CONFIG_SOC_EXYNOS5250) += clk-exynos5250.o
8obj-$(CONFIG_SOC_EXYNOS5420) += clk-exynos5420.o 8obj-$(CONFIG_SOC_EXYNOS5420) += clk-exynos5420.o
9obj-$(CONFIG_SOC_EXYNOS5440) += clk-exynos5440.o 9obj-$(CONFIG_SOC_EXYNOS5440) += clk-exynos5440.o
10obj-$(CONFIG_ARCH_EXYNOS) += clk-exynos-audss.o 10obj-$(CONFIG_ARCH_EXYNOS) += clk-exynos-audss.o
11obj-$(CONFIG_S3C2410_COMMON_CLK)+= clk-s3c2410.o
12obj-$(CONFIG_S3C2410_COMMON_DCLK)+= clk-s3c2410-dclk.o
13obj-$(CONFIG_S3C2412_COMMON_CLK)+= clk-s3c2412.o
14obj-$(CONFIG_S3C2443_COMMON_CLK)+= clk-s3c2443.o
11obj-$(CONFIG_ARCH_S3C64XX) += clk-s3c64xx.o 15obj-$(CONFIG_ARCH_S3C64XX) += clk-s3c64xx.o
diff --git a/drivers/clk/samsung/clk-pll.c b/drivers/clk/samsung/clk-pll.c
index 81e6d2f49aa0..7fb0a28e65d5 100644
--- a/drivers/clk/samsung/clk-pll.c
+++ b/drivers/clk/samsung/clk-pll.c
@@ -11,6 +11,7 @@
11 11
12#include <linux/errno.h> 12#include <linux/errno.h>
13#include <linux/hrtimer.h> 13#include <linux/hrtimer.h>
14#include <linux/delay.h>
14#include "clk.h" 15#include "clk.h"
15#include "clk-pll.h" 16#include "clk-pll.h"
16 17
@@ -59,6 +60,72 @@ static long samsung_pll_round_rate(struct clk_hw *hw,
59} 60}
60 61
61/* 62/*
63 * PLL2126 Clock Type
64 */
65
66#define PLL2126_MDIV_MASK (0xff)
67#define PLL2126_PDIV_MASK (0x3f)
68#define PLL2126_SDIV_MASK (0x3)
69#define PLL2126_MDIV_SHIFT (16)
70#define PLL2126_PDIV_SHIFT (8)
71#define PLL2126_SDIV_SHIFT (0)
72
73static unsigned long samsung_pll2126_recalc_rate(struct clk_hw *hw,
74 unsigned long parent_rate)
75{
76 struct samsung_clk_pll *pll = to_clk_pll(hw);
77 u32 pll_con, mdiv, pdiv, sdiv;
78 u64 fvco = parent_rate;
79
80 pll_con = __raw_readl(pll->con_reg);
81 mdiv = (pll_con >> PLL2126_MDIV_SHIFT) & PLL2126_MDIV_MASK;
82 pdiv = (pll_con >> PLL2126_PDIV_SHIFT) & PLL2126_PDIV_MASK;
83 sdiv = (pll_con >> PLL2126_SDIV_SHIFT) & PLL2126_SDIV_MASK;
84
85 fvco *= (mdiv + 8);
86 do_div(fvco, (pdiv + 2) << sdiv);
87
88 return (unsigned long)fvco;
89}
90
91static const struct clk_ops samsung_pll2126_clk_ops = {
92 .recalc_rate = samsung_pll2126_recalc_rate,
93};
94
95/*
96 * PLL3000 Clock Type
97 */
98
99#define PLL3000_MDIV_MASK (0xff)
100#define PLL3000_PDIV_MASK (0x3)
101#define PLL3000_SDIV_MASK (0x3)
102#define PLL3000_MDIV_SHIFT (16)
103#define PLL3000_PDIV_SHIFT (8)
104#define PLL3000_SDIV_SHIFT (0)
105
106static unsigned long samsung_pll3000_recalc_rate(struct clk_hw *hw,
107 unsigned long parent_rate)
108{
109 struct samsung_clk_pll *pll = to_clk_pll(hw);
110 u32 pll_con, mdiv, pdiv, sdiv;
111 u64 fvco = parent_rate;
112
113 pll_con = __raw_readl(pll->con_reg);
114 mdiv = (pll_con >> PLL3000_MDIV_SHIFT) & PLL3000_MDIV_MASK;
115 pdiv = (pll_con >> PLL3000_PDIV_SHIFT) & PLL3000_PDIV_MASK;
116 sdiv = (pll_con >> PLL3000_SDIV_SHIFT) & PLL3000_SDIV_MASK;
117
118 fvco *= (2 * (mdiv + 8));
119 do_div(fvco, pdiv << sdiv);
120
121 return (unsigned long)fvco;
122}
123
124static const struct clk_ops samsung_pll3000_clk_ops = {
125 .recalc_rate = samsung_pll3000_recalc_rate,
126};
127
128/*
62 * PLL35xx Clock Type 129 * PLL35xx Clock Type
63 */ 130 */
64/* Maximum lock time can be 270 * PDIV cycles */ 131/* Maximum lock time can be 270 * PDIV cycles */
@@ -564,7 +631,9 @@ static const struct clk_ops samsung_pll46xx_clk_min_ops = {
564#define PLL6552_PDIV_MASK 0x3f 631#define PLL6552_PDIV_MASK 0x3f
565#define PLL6552_SDIV_MASK 0x7 632#define PLL6552_SDIV_MASK 0x7
566#define PLL6552_MDIV_SHIFT 16 633#define PLL6552_MDIV_SHIFT 16
634#define PLL6552_MDIV_SHIFT_2416 14
567#define PLL6552_PDIV_SHIFT 8 635#define PLL6552_PDIV_SHIFT 8
636#define PLL6552_PDIV_SHIFT_2416 5
568#define PLL6552_SDIV_SHIFT 0 637#define PLL6552_SDIV_SHIFT 0
569 638
570static unsigned long samsung_pll6552_recalc_rate(struct clk_hw *hw, 639static unsigned long samsung_pll6552_recalc_rate(struct clk_hw *hw,
@@ -575,8 +644,13 @@ static unsigned long samsung_pll6552_recalc_rate(struct clk_hw *hw,
575 u64 fvco = parent_rate; 644 u64 fvco = parent_rate;
576 645
577 pll_con = __raw_readl(pll->con_reg); 646 pll_con = __raw_readl(pll->con_reg);
578 mdiv = (pll_con >> PLL6552_MDIV_SHIFT) & PLL6552_MDIV_MASK; 647 if (pll->type == pll_6552_s3c2416) {
579 pdiv = (pll_con >> PLL6552_PDIV_SHIFT) & PLL6552_PDIV_MASK; 648 mdiv = (pll_con >> PLL6552_MDIV_SHIFT_2416) & PLL6552_MDIV_MASK;
649 pdiv = (pll_con >> PLL6552_PDIV_SHIFT_2416) & PLL6552_PDIV_MASK;
650 } else {
651 mdiv = (pll_con >> PLL6552_MDIV_SHIFT) & PLL6552_MDIV_MASK;
652 pdiv = (pll_con >> PLL6552_PDIV_SHIFT) & PLL6552_PDIV_MASK;
653 }
580 sdiv = (pll_con >> PLL6552_SDIV_SHIFT) & PLL6552_SDIV_MASK; 654 sdiv = (pll_con >> PLL6552_SDIV_SHIFT) & PLL6552_SDIV_MASK;
581 655
582 fvco *= mdiv; 656 fvco *= mdiv;
@@ -628,6 +702,169 @@ static const struct clk_ops samsung_pll6553_clk_ops = {
628}; 702};
629 703
630/* 704/*
705 * PLL Clock Type of S3C24XX before S3C2443
706 */
707
708#define PLLS3C2410_MDIV_MASK (0xff)
709#define PLLS3C2410_PDIV_MASK (0x1f)
710#define PLLS3C2410_SDIV_MASK (0x3)
711#define PLLS3C2410_MDIV_SHIFT (12)
712#define PLLS3C2410_PDIV_SHIFT (4)
713#define PLLS3C2410_SDIV_SHIFT (0)
714
715#define PLLS3C2410_ENABLE_REG_OFFSET 0x10
716
717static unsigned long samsung_s3c2410_pll_recalc_rate(struct clk_hw *hw,
718 unsigned long parent_rate)
719{
720 struct samsung_clk_pll *pll = to_clk_pll(hw);
721 u32 pll_con, mdiv, pdiv, sdiv;
722 u64 fvco = parent_rate;
723
724 pll_con = __raw_readl(pll->con_reg);
725 mdiv = (pll_con >> PLLS3C2410_MDIV_SHIFT) & PLLS3C2410_MDIV_MASK;
726 pdiv = (pll_con >> PLLS3C2410_PDIV_SHIFT) & PLLS3C2410_PDIV_MASK;
727 sdiv = (pll_con >> PLLS3C2410_SDIV_SHIFT) & PLLS3C2410_SDIV_MASK;
728
729 fvco *= (mdiv + 8);
730 do_div(fvco, (pdiv + 2) << sdiv);
731
732 return (unsigned int)fvco;
733}
734
735static unsigned long samsung_s3c2440_mpll_recalc_rate(struct clk_hw *hw,
736 unsigned long parent_rate)
737{
738 struct samsung_clk_pll *pll = to_clk_pll(hw);
739 u32 pll_con, mdiv, pdiv, sdiv;
740 u64 fvco = parent_rate;
741
742 pll_con = __raw_readl(pll->con_reg);
743 mdiv = (pll_con >> PLLS3C2410_MDIV_SHIFT) & PLLS3C2410_MDIV_MASK;
744 pdiv = (pll_con >> PLLS3C2410_PDIV_SHIFT) & PLLS3C2410_PDIV_MASK;
745 sdiv = (pll_con >> PLLS3C2410_SDIV_SHIFT) & PLLS3C2410_SDIV_MASK;
746
747 fvco *= (2 * (mdiv + 8));
748 do_div(fvco, (pdiv + 2) << sdiv);
749
750 return (unsigned int)fvco;
751}
752
753static int samsung_s3c2410_pll_set_rate(struct clk_hw *hw, unsigned long drate,
754 unsigned long prate)
755{
756 struct samsung_clk_pll *pll = to_clk_pll(hw);
757 const struct samsung_pll_rate_table *rate;
758 u32 tmp;
759
760 /* Get required rate settings from table */
761 rate = samsung_get_pll_settings(pll, drate);
762 if (!rate) {
763 pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__,
764 drate, __clk_get_name(hw->clk));
765 return -EINVAL;
766 }
767
768 tmp = __raw_readl(pll->con_reg);
769
770 /* Change PLL PMS values */
771 tmp &= ~((PLLS3C2410_MDIV_MASK << PLLS3C2410_MDIV_SHIFT) |
772 (PLLS3C2410_PDIV_MASK << PLLS3C2410_PDIV_SHIFT) |
773 (PLLS3C2410_SDIV_MASK << PLLS3C2410_SDIV_SHIFT));
774 tmp |= (rate->mdiv << PLLS3C2410_MDIV_SHIFT) |
775 (rate->pdiv << PLLS3C2410_PDIV_SHIFT) |
776 (rate->sdiv << PLLS3C2410_SDIV_SHIFT);
777 __raw_writel(tmp, pll->con_reg);
778
779 /* Time to settle according to the manual */
780 udelay(300);
781
782 return 0;
783}
784
785static int samsung_s3c2410_pll_enable(struct clk_hw *hw, int bit, bool enable)
786{
787 struct samsung_clk_pll *pll = to_clk_pll(hw);
788 u32 pll_en = __raw_readl(pll->lock_reg + PLLS3C2410_ENABLE_REG_OFFSET);
789 u32 pll_en_orig = pll_en;
790
791 if (enable)
792 pll_en &= ~BIT(bit);
793 else
794 pll_en |= BIT(bit);
795
796 __raw_writel(pll_en, pll->lock_reg + PLLS3C2410_ENABLE_REG_OFFSET);
797
798 /* if we started the UPLL, then allow to settle */
799 if (enable && (pll_en_orig & BIT(bit)))
800 udelay(300);
801
802 return 0;
803}
804
805static int samsung_s3c2410_mpll_enable(struct clk_hw *hw)
806{
807 return samsung_s3c2410_pll_enable(hw, 5, true);
808}
809
810static void samsung_s3c2410_mpll_disable(struct clk_hw *hw)
811{
812 samsung_s3c2410_pll_enable(hw, 5, false);
813}
814
815static int samsung_s3c2410_upll_enable(struct clk_hw *hw)
816{
817 return samsung_s3c2410_pll_enable(hw, 7, true);
818}
819
820static void samsung_s3c2410_upll_disable(struct clk_hw *hw)
821{
822 samsung_s3c2410_pll_enable(hw, 7, false);
823}
824
825static const struct clk_ops samsung_s3c2410_mpll_clk_min_ops = {
826 .recalc_rate = samsung_s3c2410_pll_recalc_rate,
827 .enable = samsung_s3c2410_mpll_enable,
828 .disable = samsung_s3c2410_mpll_disable,
829};
830
831static const struct clk_ops samsung_s3c2410_upll_clk_min_ops = {
832 .recalc_rate = samsung_s3c2410_pll_recalc_rate,
833 .enable = samsung_s3c2410_upll_enable,
834 .disable = samsung_s3c2410_upll_disable,
835};
836
837static const struct clk_ops samsung_s3c2440_mpll_clk_min_ops = {
838 .recalc_rate = samsung_s3c2440_mpll_recalc_rate,
839 .enable = samsung_s3c2410_mpll_enable,
840 .disable = samsung_s3c2410_mpll_disable,
841};
842
843static const struct clk_ops samsung_s3c2410_mpll_clk_ops = {
844 .recalc_rate = samsung_s3c2410_pll_recalc_rate,
845 .enable = samsung_s3c2410_mpll_enable,
846 .disable = samsung_s3c2410_mpll_disable,
847 .round_rate = samsung_pll_round_rate,
848 .set_rate = samsung_s3c2410_pll_set_rate,
849};
850
851static const struct clk_ops samsung_s3c2410_upll_clk_ops = {
852 .recalc_rate = samsung_s3c2410_pll_recalc_rate,
853 .enable = samsung_s3c2410_upll_enable,
854 .disable = samsung_s3c2410_upll_disable,
855 .round_rate = samsung_pll_round_rate,
856 .set_rate = samsung_s3c2410_pll_set_rate,
857};
858
859static const struct clk_ops samsung_s3c2440_mpll_clk_ops = {
860 .recalc_rate = samsung_s3c2440_mpll_recalc_rate,
861 .enable = samsung_s3c2410_mpll_enable,
862 .disable = samsung_s3c2410_mpll_disable,
863 .round_rate = samsung_pll_round_rate,
864 .set_rate = samsung_s3c2410_pll_set_rate,
865};
866
867/*
631 * PLL2550x Clock Type 868 * PLL2550x Clock Type
632 */ 869 */
633 870
@@ -746,6 +983,12 @@ static void __init _samsung_clk_register_pll(struct samsung_pll_clock *pll_clk,
746 } 983 }
747 984
748 switch (pll_clk->type) { 985 switch (pll_clk->type) {
986 case pll_2126:
987 init.ops = &samsung_pll2126_clk_ops;
988 break;
989 case pll_3000:
990 init.ops = &samsung_pll3000_clk_ops;
991 break;
749 /* clk_ops for 35xx and 2550 are similar */ 992 /* clk_ops for 35xx and 2550 are similar */
750 case pll_35xx: 993 case pll_35xx:
751 case pll_2550: 994 case pll_2550:
@@ -773,6 +1016,7 @@ static void __init _samsung_clk_register_pll(struct samsung_pll_clock *pll_clk,
773 init.ops = &samsung_pll36xx_clk_ops; 1016 init.ops = &samsung_pll36xx_clk_ops;
774 break; 1017 break;
775 case pll_6552: 1018 case pll_6552:
1019 case pll_6552_s3c2416:
776 init.ops = &samsung_pll6552_clk_ops; 1020 init.ops = &samsung_pll6552_clk_ops;
777 break; 1021 break;
778 case pll_6553: 1022 case pll_6553:
@@ -786,6 +1030,24 @@ static void __init _samsung_clk_register_pll(struct samsung_pll_clock *pll_clk,
786 else 1030 else
787 init.ops = &samsung_pll46xx_clk_ops; 1031 init.ops = &samsung_pll46xx_clk_ops;
788 break; 1032 break;
1033 case pll_s3c2410_mpll:
1034 if (!pll->rate_table)
1035 init.ops = &samsung_s3c2410_mpll_clk_min_ops;
1036 else
1037 init.ops = &samsung_s3c2410_mpll_clk_ops;
1038 break;
1039 case pll_s3c2410_upll:
1040 if (!pll->rate_table)
1041 init.ops = &samsung_s3c2410_upll_clk_min_ops;
1042 else
1043 init.ops = &samsung_s3c2410_upll_clk_ops;
1044 break;
1045 case pll_s3c2440_mpll:
1046 if (!pll->rate_table)
1047 init.ops = &samsung_s3c2440_mpll_clk_min_ops;
1048 else
1049 init.ops = &samsung_s3c2440_mpll_clk_ops;
1050 break;
789 default: 1051 default:
790 pr_warn("%s: Unknown pll type for pll clk %s\n", 1052 pr_warn("%s: Unknown pll type for pll clk %s\n",
791 __func__, pll_clk->name); 1053 __func__, pll_clk->name);
diff --git a/drivers/clk/samsung/clk-pll.h b/drivers/clk/samsung/clk-pll.h
index 6c39030080fb..6428bcc6df6f 100644
--- a/drivers/clk/samsung/clk-pll.h
+++ b/drivers/clk/samsung/clk-pll.h
@@ -13,6 +13,8 @@
13#define __SAMSUNG_CLK_PLL_H 13#define __SAMSUNG_CLK_PLL_H
14 14
15enum samsung_pll_type { 15enum samsung_pll_type {
16 pll_2126,
17 pll_3000,
16 pll_35xx, 18 pll_35xx,
17 pll_36xx, 19 pll_36xx,
18 pll_2550, 20 pll_2550,
@@ -24,7 +26,11 @@ enum samsung_pll_type {
24 pll_4650, 26 pll_4650,
25 pll_4650c, 27 pll_4650c,
26 pll_6552, 28 pll_6552,
29 pll_6552_s3c2416,
27 pll_6553, 30 pll_6553,
31 pll_s3c2410_mpll,
32 pll_s3c2410_upll,
33 pll_s3c2440_mpll,
28}; 34};
29 35
30#define PLL_35XX_RATE(_rate, _m, _p, _s) \ 36#define PLL_35XX_RATE(_rate, _m, _p, _s) \
diff --git a/drivers/clk/samsung/clk-s3c2410-dclk.c b/drivers/clk/samsung/clk-s3c2410-dclk.c
new file mode 100644
index 000000000000..8d8dff005c10
--- /dev/null
+++ b/drivers/clk/samsung/clk-s3c2410-dclk.c
@@ -0,0 +1,440 @@
1/*
2 * Copyright (c) 2013 Heiko Stuebner <heiko@sntech.de>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 * Common Clock Framework support for s3c24xx external clock output.
9 */
10
11#include <linux/platform_device.h>
12#include <linux/module.h>
13#include "clk.h"
14
15/* legacy access to misccr, until dt conversion is finished */
16#include <mach/hardware.h>
17#include <mach/regs-gpio.h>
18
19#define MUX_DCLK0 0
20#define MUX_DCLK1 1
21#define DIV_DCLK0 2
22#define DIV_DCLK1 3
23#define GATE_DCLK0 4
24#define GATE_DCLK1 5
25#define MUX_CLKOUT0 6
26#define MUX_CLKOUT1 7
27#define DCLK_MAX_CLKS (MUX_CLKOUT1 + 1)
28
29enum supported_socs {
30 S3C2410,
31 S3C2412,
32 S3C2440,
33 S3C2443,
34};
35
36struct s3c24xx_dclk_drv_data {
37 const char **clkout0_parent_names;
38 int clkout0_num_parents;
39 const char **clkout1_parent_names;
40 int clkout1_num_parents;
41 const char **mux_parent_names;
42 int mux_num_parents;
43};
44
45/*
46 * Clock for output-parent selection in misccr
47 */
48
49struct s3c24xx_clkout {
50 struct clk_hw hw;
51 u32 mask;
52 u8 shift;
53};
54
55#define to_s3c24xx_clkout(_hw) container_of(_hw, struct s3c24xx_clkout, hw)
56
57static u8 s3c24xx_clkout_get_parent(struct clk_hw *hw)
58{
59 struct s3c24xx_clkout *clkout = to_s3c24xx_clkout(hw);
60 int num_parents = __clk_get_num_parents(hw->clk);
61 u32 val;
62
63 val = readl_relaxed(S3C24XX_MISCCR) >> clkout->shift;
64 val >>= clkout->shift;
65 val &= clkout->mask;
66
67 if (val >= num_parents)
68 return -EINVAL;
69
70 return val;
71}
72
73static int s3c24xx_clkout_set_parent(struct clk_hw *hw, u8 index)
74{
75 struct s3c24xx_clkout *clkout = to_s3c24xx_clkout(hw);
76 int ret = 0;
77
78 s3c2410_modify_misccr((clkout->mask << clkout->shift),
79 (index << clkout->shift));
80
81 return ret;
82}
83
84const struct clk_ops s3c24xx_clkout_ops = {
85 .get_parent = s3c24xx_clkout_get_parent,
86 .set_parent = s3c24xx_clkout_set_parent,
87 .determine_rate = __clk_mux_determine_rate,
88};
89
90struct clk *s3c24xx_register_clkout(struct device *dev, const char *name,
91 const char **parent_names, u8 num_parents,
92 u8 shift, u32 mask)
93{
94 struct s3c24xx_clkout *clkout;
95 struct clk *clk;
96 struct clk_init_data init;
97
98 /* allocate the clkout */
99 clkout = kzalloc(sizeof(*clkout), GFP_KERNEL);
100 if (!clkout)
101 return ERR_PTR(-ENOMEM);
102
103 init.name = name;
104 init.ops = &s3c24xx_clkout_ops;
105 init.flags = CLK_IS_BASIC;
106 init.parent_names = parent_names;
107 init.num_parents = num_parents;
108
109 clkout->shift = shift;
110 clkout->mask = mask;
111 clkout->hw.init = &init;
112
113 clk = clk_register(dev, &clkout->hw);
114
115 return clk;
116}
117
118/*
119 * dclk and clkout init
120 */
121
122struct s3c24xx_dclk {
123 struct device *dev;
124 void __iomem *base;
125 struct clk_onecell_data clk_data;
126 struct notifier_block dclk0_div_change_nb;
127 struct notifier_block dclk1_div_change_nb;
128 spinlock_t dclk_lock;
129 unsigned long reg_save;
130};
131
132#define to_s3c24xx_dclk0(x) \
133 container_of(x, struct s3c24xx_dclk, dclk0_div_change_nb)
134
135#define to_s3c24xx_dclk1(x) \
136 container_of(x, struct s3c24xx_dclk, dclk1_div_change_nb)
137
138PNAME(dclk_s3c2410_p) = { "pclk", "uclk" };
139PNAME(clkout0_s3c2410_p) = { "mpll", "upll", "fclk", "hclk", "pclk",
140 "gate_dclk0" };
141PNAME(clkout1_s3c2410_p) = { "mpll", "upll", "fclk", "hclk", "pclk",
142 "gate_dclk1" };
143
144PNAME(clkout0_s3c2412_p) = { "mpll", "upll", "rtc_clkout",
145 "hclk", "pclk", "gate_dclk0" };
146PNAME(clkout1_s3c2412_p) = { "xti", "upll", "fclk", "hclk", "pclk",
147 "gate_dclk1" };
148
149PNAME(clkout0_s3c2440_p) = { "xti", "upll", "fclk", "hclk", "pclk",
150 "gate_dclk0" };
151PNAME(clkout1_s3c2440_p) = { "mpll", "upll", "rtc_clkout",
152 "hclk", "pclk", "gate_dclk1" };
153
154PNAME(dclk_s3c2443_p) = { "pclk", "epll" };
155PNAME(clkout0_s3c2443_p) = { "xti", "epll", "armclk", "hclk", "pclk",
156 "gate_dclk0" };
157PNAME(clkout1_s3c2443_p) = { "dummy", "epll", "rtc_clkout",
158 "hclk", "pclk", "gate_dclk1" };
159
160#define DCLKCON_DCLK_DIV_MASK 0xf
161#define DCLKCON_DCLK0_DIV_SHIFT 4
162#define DCLKCON_DCLK0_CMP_SHIFT 8
163#define DCLKCON_DCLK1_DIV_SHIFT 20
164#define DCLKCON_DCLK1_CMP_SHIFT 24
165
166static void s3c24xx_dclk_update_cmp(struct s3c24xx_dclk *s3c24xx_dclk,
167 int div_shift, int cmp_shift)
168{
169 unsigned long flags = 0;
170 u32 dclk_con, div, cmp;
171
172 spin_lock_irqsave(&s3c24xx_dclk->dclk_lock, flags);
173
174 dclk_con = readl_relaxed(s3c24xx_dclk->base);
175
176 div = ((dclk_con >> div_shift) & DCLKCON_DCLK_DIV_MASK) + 1;
177 cmp = ((div + 1) / 2) - 1;
178
179 dclk_con &= ~(DCLKCON_DCLK_DIV_MASK << cmp_shift);
180 dclk_con |= (cmp << cmp_shift);
181
182 writel_relaxed(dclk_con, s3c24xx_dclk->base);
183
184 spin_unlock_irqrestore(&s3c24xx_dclk->dclk_lock, flags);
185}
186
187static int s3c24xx_dclk0_div_notify(struct notifier_block *nb,
188 unsigned long event, void *data)
189{
190 struct s3c24xx_dclk *s3c24xx_dclk = to_s3c24xx_dclk0(nb);
191
192 if (event == POST_RATE_CHANGE) {
193 s3c24xx_dclk_update_cmp(s3c24xx_dclk,
194 DCLKCON_DCLK0_DIV_SHIFT, DCLKCON_DCLK0_CMP_SHIFT);
195 }
196
197 return NOTIFY_DONE;
198}
199
200static int s3c24xx_dclk1_div_notify(struct notifier_block *nb,
201 unsigned long event, void *data)
202{
203 struct s3c24xx_dclk *s3c24xx_dclk = to_s3c24xx_dclk1(nb);
204
205 if (event == POST_RATE_CHANGE) {
206 s3c24xx_dclk_update_cmp(s3c24xx_dclk,
207 DCLKCON_DCLK1_DIV_SHIFT, DCLKCON_DCLK1_CMP_SHIFT);
208 }
209
210 return NOTIFY_DONE;
211}
212
213#ifdef CONFIG_PM_SLEEP
214static int s3c24xx_dclk_suspend(struct device *dev)
215{
216 struct platform_device *pdev = to_platform_device(dev);
217 struct s3c24xx_dclk *s3c24xx_dclk = platform_get_drvdata(pdev);
218
219 s3c24xx_dclk->reg_save = readl_relaxed(s3c24xx_dclk->base);
220 return 0;
221}
222
223static int s3c24xx_dclk_resume(struct device *dev)
224{
225 struct platform_device *pdev = to_platform_device(dev);
226 struct s3c24xx_dclk *s3c24xx_dclk = platform_get_drvdata(pdev);
227
228 writel_relaxed(s3c24xx_dclk->reg_save, s3c24xx_dclk->base);
229 return 0;
230}
231#endif
232
233static SIMPLE_DEV_PM_OPS(s3c24xx_dclk_pm_ops,
234 s3c24xx_dclk_suspend, s3c24xx_dclk_resume);
235
236static int s3c24xx_dclk_probe(struct platform_device *pdev)
237{
238 struct s3c24xx_dclk *s3c24xx_dclk;
239 struct resource *mem;
240 struct clk **clk_table;
241 struct s3c24xx_dclk_drv_data *dclk_variant;
242 int ret, i;
243
244 s3c24xx_dclk = devm_kzalloc(&pdev->dev, sizeof(*s3c24xx_dclk),
245 GFP_KERNEL);
246 if (!s3c24xx_dclk)
247 return -ENOMEM;
248
249 s3c24xx_dclk->dev = &pdev->dev;
250 platform_set_drvdata(pdev, s3c24xx_dclk);
251 spin_lock_init(&s3c24xx_dclk->dclk_lock);
252
253 clk_table = devm_kzalloc(&pdev->dev,
254 sizeof(struct clk *) * DCLK_MAX_CLKS,
255 GFP_KERNEL);
256 if (!clk_table)
257 return -ENOMEM;
258
259 s3c24xx_dclk->clk_data.clks = clk_table;
260 s3c24xx_dclk->clk_data.clk_num = DCLK_MAX_CLKS;
261
262 mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
263 s3c24xx_dclk->base = devm_ioremap_resource(&pdev->dev, mem);
264 if (IS_ERR(s3c24xx_dclk->base))
265 return PTR_ERR(s3c24xx_dclk->base);
266
267 dclk_variant = (struct s3c24xx_dclk_drv_data *)
268 platform_get_device_id(pdev)->driver_data;
269
270
271 clk_table[MUX_DCLK0] = clk_register_mux(&pdev->dev, "mux_dclk0",
272 dclk_variant->mux_parent_names,
273 dclk_variant->mux_num_parents, 0,
274 s3c24xx_dclk->base, 1, 1, 0,
275 &s3c24xx_dclk->dclk_lock);
276 clk_table[MUX_DCLK1] = clk_register_mux(&pdev->dev, "mux_dclk1",
277 dclk_variant->mux_parent_names,
278 dclk_variant->mux_num_parents, 0,
279 s3c24xx_dclk->base, 17, 1, 0,
280 &s3c24xx_dclk->dclk_lock);
281
282 clk_table[DIV_DCLK0] = clk_register_divider(&pdev->dev, "div_dclk0",
283 "mux_dclk0", 0, s3c24xx_dclk->base,
284 4, 4, 0, &s3c24xx_dclk->dclk_lock);
285 clk_table[DIV_DCLK1] = clk_register_divider(&pdev->dev, "div_dclk1",
286 "mux_dclk1", 0, s3c24xx_dclk->base,
287 20, 4, 0, &s3c24xx_dclk->dclk_lock);
288
289 clk_table[GATE_DCLK0] = clk_register_gate(&pdev->dev, "gate_dclk0",
290 "div_dclk0", CLK_SET_RATE_PARENT,
291 s3c24xx_dclk->base, 0, 0,
292 &s3c24xx_dclk->dclk_lock);
293 clk_table[GATE_DCLK1] = clk_register_gate(&pdev->dev, "gate_dclk1",
294 "div_dclk1", CLK_SET_RATE_PARENT,
295 s3c24xx_dclk->base, 16, 0,
296 &s3c24xx_dclk->dclk_lock);
297
298 clk_table[MUX_CLKOUT0] = s3c24xx_register_clkout(&pdev->dev,
299 "clkout0", dclk_variant->clkout0_parent_names,
300 dclk_variant->clkout0_num_parents, 4, 7);
301 clk_table[MUX_CLKOUT1] = s3c24xx_register_clkout(&pdev->dev,
302 "clkout1", dclk_variant->clkout1_parent_names,
303 dclk_variant->clkout1_num_parents, 8, 7);
304
305 for (i = 0; i < DCLK_MAX_CLKS; i++)
306 if (IS_ERR(clk_table[i])) {
307 dev_err(&pdev->dev, "clock %d failed to register\n", i);
308 ret = PTR_ERR(clk_table[i]);
309 goto err_clk_register;
310 }
311
312 ret = clk_register_clkdev(clk_table[MUX_DCLK0], "dclk0", NULL);
313 if (!ret)
314 ret = clk_register_clkdev(clk_table[MUX_DCLK1], "dclk1", NULL);
315 if (!ret)
316 ret = clk_register_clkdev(clk_table[MUX_CLKOUT0],
317 "clkout0", NULL);
318 if (!ret)
319 ret = clk_register_clkdev(clk_table[MUX_CLKOUT1],
320 "clkout1", NULL);
321 if (ret) {
322 dev_err(&pdev->dev, "failed to register aliases, %d\n", ret);
323 goto err_clk_register;
324 }
325
326 s3c24xx_dclk->dclk0_div_change_nb.notifier_call =
327 s3c24xx_dclk0_div_notify;
328
329 s3c24xx_dclk->dclk1_div_change_nb.notifier_call =
330 s3c24xx_dclk1_div_notify;
331
332 ret = clk_notifier_register(clk_table[DIV_DCLK0],
333 &s3c24xx_dclk->dclk0_div_change_nb);
334 if (ret)
335 goto err_clk_register;
336
337 ret = clk_notifier_register(clk_table[DIV_DCLK1],
338 &s3c24xx_dclk->dclk1_div_change_nb);
339 if (ret)
340 goto err_dclk_notify;
341
342 return 0;
343
344err_dclk_notify:
345 clk_notifier_unregister(clk_table[DIV_DCLK0],
346 &s3c24xx_dclk->dclk0_div_change_nb);
347err_clk_register:
348 for (i = 0; i < DCLK_MAX_CLKS; i++)
349 if (clk_table[i] && !IS_ERR(clk_table[i]))
350 clk_unregister(clk_table[i]);
351
352 return ret;
353}
354
355static int s3c24xx_dclk_remove(struct platform_device *pdev)
356{
357 struct s3c24xx_dclk *s3c24xx_dclk = platform_get_drvdata(pdev);
358 struct clk **clk_table = s3c24xx_dclk->clk_data.clks;
359 int i;
360
361 clk_notifier_unregister(clk_table[DIV_DCLK1],
362 &s3c24xx_dclk->dclk1_div_change_nb);
363 clk_notifier_unregister(clk_table[DIV_DCLK0],
364 &s3c24xx_dclk->dclk0_div_change_nb);
365
366 for (i = 0; i < DCLK_MAX_CLKS; i++)
367 clk_unregister(clk_table[i]);
368
369 return 0;
370}
371
372static struct s3c24xx_dclk_drv_data dclk_variants[] = {
373 [S3C2410] = {
374 .clkout0_parent_names = clkout0_s3c2410_p,
375 .clkout0_num_parents = ARRAY_SIZE(clkout0_s3c2410_p),
376 .clkout1_parent_names = clkout1_s3c2410_p,
377 .clkout1_num_parents = ARRAY_SIZE(clkout1_s3c2410_p),
378 .mux_parent_names = dclk_s3c2410_p,
379 .mux_num_parents = ARRAY_SIZE(dclk_s3c2410_p),
380 },
381 [S3C2412] = {
382 .clkout0_parent_names = clkout0_s3c2412_p,
383 .clkout0_num_parents = ARRAY_SIZE(clkout0_s3c2412_p),
384 .clkout1_parent_names = clkout1_s3c2412_p,
385 .clkout1_num_parents = ARRAY_SIZE(clkout1_s3c2412_p),
386 .mux_parent_names = dclk_s3c2410_p,
387 .mux_num_parents = ARRAY_SIZE(dclk_s3c2410_p),
388 },
389 [S3C2440] = {
390 .clkout0_parent_names = clkout0_s3c2440_p,
391 .clkout0_num_parents = ARRAY_SIZE(clkout0_s3c2440_p),
392 .clkout1_parent_names = clkout1_s3c2440_p,
393 .clkout1_num_parents = ARRAY_SIZE(clkout1_s3c2440_p),
394 .mux_parent_names = dclk_s3c2410_p,
395 .mux_num_parents = ARRAY_SIZE(dclk_s3c2410_p),
396 },
397 [S3C2443] = {
398 .clkout0_parent_names = clkout0_s3c2443_p,
399 .clkout0_num_parents = ARRAY_SIZE(clkout0_s3c2443_p),
400 .clkout1_parent_names = clkout1_s3c2443_p,
401 .clkout1_num_parents = ARRAY_SIZE(clkout1_s3c2443_p),
402 .mux_parent_names = dclk_s3c2443_p,
403 .mux_num_parents = ARRAY_SIZE(dclk_s3c2443_p),
404 },
405};
406
407static struct platform_device_id s3c24xx_dclk_driver_ids[] = {
408 {
409 .name = "s3c2410-dclk",
410 .driver_data = (kernel_ulong_t)&dclk_variants[S3C2410],
411 }, {
412 .name = "s3c2412-dclk",
413 .driver_data = (kernel_ulong_t)&dclk_variants[S3C2412],
414 }, {
415 .name = "s3c2440-dclk",
416 .driver_data = (kernel_ulong_t)&dclk_variants[S3C2440],
417 }, {
418 .name = "s3c2443-dclk",
419 .driver_data = (kernel_ulong_t)&dclk_variants[S3C2443],
420 },
421 { }
422};
423
424MODULE_DEVICE_TABLE(platform, s3c24xx_dclk_driver_ids);
425
426static struct platform_driver s3c24xx_dclk_driver = {
427 .driver = {
428 .name = "s3c24xx-dclk",
429 .owner = THIS_MODULE,
430 .pm = &s3c24xx_dclk_pm_ops,
431 },
432 .probe = s3c24xx_dclk_probe,
433 .remove = s3c24xx_dclk_remove,
434 .id_table = s3c24xx_dclk_driver_ids,
435};
436module_platform_driver(s3c24xx_dclk_driver);
437
438MODULE_LICENSE("GPL v2");
439MODULE_AUTHOR("Heiko Stuebner <heiko@sntech.de>");
440MODULE_DESCRIPTION("Driver for the S3C24XX external clock outputs");
diff --git a/drivers/clk/samsung/clk-s3c2410.c b/drivers/clk/samsung/clk-s3c2410.c
new file mode 100644
index 000000000000..7b4182186a30
--- /dev/null
+++ b/drivers/clk/samsung/clk-s3c2410.c
@@ -0,0 +1,477 @@
1/*
2 * Copyright (c) 2013 Heiko Stuebner <heiko@sntech.de>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 * Common Clock Framework support for S3C2410 and following SoCs.
9 */
10
11#include <linux/clk.h>
12#include <linux/clkdev.h>
13#include <linux/clk-provider.h>
14#include <linux/of.h>
15#include <linux/of_address.h>
16#include <linux/syscore_ops.h>
17
18#include <dt-bindings/clock/s3c2410.h>
19
20#include "clk.h"
21#include "clk-pll.h"
22
23#define LOCKTIME 0x00
24#define MPLLCON 0x04
25#define UPLLCON 0x08
26#define CLKCON 0x0c
27#define CLKSLOW 0x10
28#define CLKDIVN 0x14
29#define CAMDIVN 0x18
30
31/* the soc types */
32enum supported_socs {
33 S3C2410,
34 S3C2440,
35 S3C2442,
36};
37
38/* list of PLLs to be registered */
39enum s3c2410_plls {
40 mpll, upll,
41};
42
43static void __iomem *reg_base;
44
45#ifdef CONFIG_PM_SLEEP
46static struct samsung_clk_reg_dump *s3c2410_save;
47
48/*
49 * list of controller registers to be saved and restored during a
50 * suspend/resume cycle.
51 */
52static unsigned long s3c2410_clk_regs[] __initdata = {
53 LOCKTIME,
54 MPLLCON,
55 UPLLCON,
56 CLKCON,
57 CLKSLOW,
58 CLKDIVN,
59 CAMDIVN,
60};
61
62static int s3c2410_clk_suspend(void)
63{
64 samsung_clk_save(reg_base, s3c2410_save,
65 ARRAY_SIZE(s3c2410_clk_regs));
66
67 return 0;
68}
69
70static void s3c2410_clk_resume(void)
71{
72 samsung_clk_restore(reg_base, s3c2410_save,
73 ARRAY_SIZE(s3c2410_clk_regs));
74}
75
76static struct syscore_ops s3c2410_clk_syscore_ops = {
77 .suspend = s3c2410_clk_suspend,
78 .resume = s3c2410_clk_resume,
79};
80
81static void s3c2410_clk_sleep_init(void)
82{
83 s3c2410_save = samsung_clk_alloc_reg_dump(s3c2410_clk_regs,
84 ARRAY_SIZE(s3c2410_clk_regs));
85 if (!s3c2410_save) {
86 pr_warn("%s: failed to allocate sleep save data, no sleep support!\n",
87 __func__);
88 return;
89 }
90
91 register_syscore_ops(&s3c2410_clk_syscore_ops);
92 return;
93}
94#else
95static void s3c2410_clk_sleep_init(void) {}
96#endif
97
98PNAME(fclk_p) = { "mpll", "div_slow" };
99
100struct samsung_mux_clock s3c2410_common_muxes[] __initdata = {
101 MUX(FCLK, "fclk", fclk_p, CLKSLOW, 4, 1),
102};
103
104static struct clk_div_table divslow_d[] = {
105 { .val = 0, .div = 1 },
106 { .val = 1, .div = 2 },
107 { .val = 2, .div = 4 },
108 { .val = 3, .div = 6 },
109 { .val = 4, .div = 8 },
110 { .val = 5, .div = 10 },
111 { .val = 6, .div = 12 },
112 { .val = 7, .div = 14 },
113 { /* sentinel */ },
114};
115
116struct samsung_div_clock s3c2410_common_dividers[] __initdata = {
117 DIV_T(0, "div_slow", "xti", CLKSLOW, 0, 3, divslow_d),
118 DIV(PCLK, "pclk", "hclk", CLKDIVN, 0, 1),
119};
120
121struct samsung_gate_clock s3c2410_common_gates[] __initdata = {
122 GATE(PCLK_SPI, "spi", "pclk", CLKCON, 18, 0, 0),
123 GATE(PCLK_I2S, "i2s", "pclk", CLKCON, 17, 0, 0),
124 GATE(PCLK_I2C, "i2c", "pclk", CLKCON, 16, 0, 0),
125 GATE(PCLK_ADC, "adc", "pclk", CLKCON, 15, 0, 0),
126 GATE(PCLK_RTC, "rtc", "pclk", CLKCON, 14, 0, 0),
127 GATE(PCLK_GPIO, "gpio", "pclk", CLKCON, 13, CLK_IGNORE_UNUSED, 0),
128 GATE(PCLK_UART2, "uart2", "pclk", CLKCON, 12, 0, 0),
129 GATE(PCLK_UART1, "uart1", "pclk", CLKCON, 11, 0, 0),
130 GATE(PCLK_UART0, "uart0", "pclk", CLKCON, 10, 0, 0),
131 GATE(PCLK_SDI, "sdi", "pclk", CLKCON, 9, 0, 0),
132 GATE(PCLK_PWM, "pwm", "pclk", CLKCON, 8, 0, 0),
133 GATE(HCLK_USBD, "usb-device", "hclk", CLKCON, 7, 0, 0),
134 GATE(HCLK_USBH, "usb-host", "hclk", CLKCON, 6, 0, 0),
135 GATE(HCLK_LCD, "lcd", "hclk", CLKCON, 5, 0, 0),
136 GATE(HCLK_NAND, "nand", "hclk", CLKCON, 4, 0, 0),
137};
138
139/* should be added _after_ the soc-specific clocks are created */
140struct samsung_clock_alias s3c2410_common_aliases[] __initdata = {
141 ALIAS(PCLK_I2C, "s3c2410-i2c.0", "i2c"),
142 ALIAS(PCLK_ADC, NULL, "adc"),
143 ALIAS(PCLK_RTC, NULL, "rtc"),
144 ALIAS(PCLK_PWM, NULL, "timers"),
145 ALIAS(HCLK_LCD, NULL, "lcd"),
146 ALIAS(HCLK_USBD, NULL, "usb-device"),
147 ALIAS(HCLK_USBH, NULL, "usb-host"),
148 ALIAS(UCLK, NULL, "usb-bus-host"),
149 ALIAS(UCLK, NULL, "usb-bus-gadget"),
150 ALIAS(ARMCLK, NULL, "armclk"),
151 ALIAS(UCLK, NULL, "uclk"),
152 ALIAS(HCLK, NULL, "hclk"),
153 ALIAS(MPLL, NULL, "mpll"),
154 ALIAS(FCLK, NULL, "fclk"),
155};
156
157/* S3C2410 specific clocks */
158
159static struct samsung_pll_rate_table pll_s3c2410_12mhz_tbl[] __initdata = {
160 /* sorted in descending order */
161 /* 2410A extras */
162 PLL_35XX_RATE(270000000, 127, 1, 1),
163 PLL_35XX_RATE(268000000, 126, 1, 1),
164 PLL_35XX_RATE(266000000, 125, 1, 1),
165 PLL_35XX_RATE(226000000, 105, 1, 1),
166 PLL_35XX_RATE(210000000, 132, 2, 1),
167 /* 2410 common */
168 PLL_35XX_RATE(203000000, 161, 3, 1),
169 PLL_35XX_RATE(192000000, 88, 1, 1),
170 PLL_35XX_RATE(186000000, 85, 1, 1),
171 PLL_35XX_RATE(180000000, 82, 1, 1),
172 PLL_35XX_RATE(170000000, 77, 1, 1),
173 PLL_35XX_RATE(158000000, 71, 1, 1),
174 PLL_35XX_RATE(152000000, 68, 1, 1),
175 PLL_35XX_RATE(147000000, 90, 2, 1),
176 PLL_35XX_RATE(135000000, 82, 2, 1),
177 PLL_35XX_RATE(124000000, 116, 1, 2),
178 PLL_35XX_RATE(118000000, 150, 2, 2),
179 PLL_35XX_RATE(113000000, 105, 1, 2),
180 PLL_35XX_RATE(101000000, 127, 2, 2),
181 PLL_35XX_RATE(90000000, 112, 2, 2),
182 PLL_35XX_RATE(85000000, 105, 2, 2),
183 PLL_35XX_RATE(79000000, 71, 1, 2),
184 PLL_35XX_RATE(68000000, 82, 2, 2),
185 PLL_35XX_RATE(56000000, 142, 2, 3),
186 PLL_35XX_RATE(48000000, 120, 2, 3),
187 PLL_35XX_RATE(51000000, 161, 3, 3),
188 PLL_35XX_RATE(45000000, 82, 1, 3),
189 PLL_35XX_RATE(34000000, 82, 2, 3),
190 { /* sentinel */ },
191};
192
193static struct samsung_pll_clock s3c2410_plls[] __initdata = {
194 [mpll] = PLL(pll_s3c2410_mpll, MPLL, "mpll", "xti",
195 LOCKTIME, MPLLCON, NULL),
196 [upll] = PLL(pll_s3c2410_upll, UPLL, "upll", "xti",
197 LOCKTIME, UPLLCON, NULL),
198};
199
200struct samsung_div_clock s3c2410_dividers[] __initdata = {
201 DIV(HCLK, "hclk", "mpll", CLKDIVN, 1, 1),
202};
203
204struct samsung_fixed_factor_clock s3c2410_ffactor[] __initdata = {
205 /*
206 * armclk is directly supplied by the fclk, without
207 * switching possibility like on the s3c244x below.
208 */
209 FFACTOR(ARMCLK, "armclk", "fclk", 1, 1, 0),
210
211 /* uclk is fed from the unmodified upll */
212 FFACTOR(UCLK, "uclk", "upll", 1, 1, 0),
213};
214
215struct samsung_clock_alias s3c2410_aliases[] __initdata = {
216 ALIAS(PCLK_UART0, "s3c2410-uart.0", "uart"),
217 ALIAS(PCLK_UART1, "s3c2410-uart.1", "uart"),
218 ALIAS(PCLK_UART2, "s3c2410-uart.2", "uart"),
219 ALIAS(PCLK_UART0, "s3c2410-uart.0", "clk_uart_baud0"),
220 ALIAS(PCLK_UART1, "s3c2410-uart.1", "clk_uart_baud0"),
221 ALIAS(PCLK_UART2, "s3c2410-uart.2", "clk_uart_baud0"),
222 ALIAS(UCLK, NULL, "clk_uart_baud1"),
223};
224
225/* S3C244x specific clocks */
226
227static struct samsung_pll_rate_table pll_s3c244x_12mhz_tbl[] __initdata = {
228 /* sorted in descending order */
229 PLL_35XX_RATE(400000000, 0x5c, 1, 1),
230 PLL_35XX_RATE(390000000, 0x7a, 2, 1),
231 PLL_35XX_RATE(380000000, 0x57, 1, 1),
232 PLL_35XX_RATE(370000000, 0xb1, 4, 1),
233 PLL_35XX_RATE(360000000, 0x70, 2, 1),
234 PLL_35XX_RATE(350000000, 0xa7, 4, 1),
235 PLL_35XX_RATE(340000000, 0x4d, 1, 1),
236 PLL_35XX_RATE(330000000, 0x66, 2, 1),
237 PLL_35XX_RATE(320000000, 0x98, 4, 1),
238 PLL_35XX_RATE(310000000, 0x93, 4, 1),
239 PLL_35XX_RATE(300000000, 0x75, 3, 1),
240 PLL_35XX_RATE(240000000, 0x70, 1, 2),
241 PLL_35XX_RATE(230000000, 0x6b, 1, 2),
242 PLL_35XX_RATE(220000000, 0x66, 1, 2),
243 PLL_35XX_RATE(210000000, 0x84, 2, 2),
244 PLL_35XX_RATE(200000000, 0x5c, 1, 2),
245 PLL_35XX_RATE(190000000, 0x57, 1, 2),
246 PLL_35XX_RATE(180000000, 0x70, 2, 2),
247 PLL_35XX_RATE(170000000, 0x4d, 1, 2),
248 PLL_35XX_RATE(160000000, 0x98, 4, 2),
249 PLL_35XX_RATE(150000000, 0x75, 3, 2),
250 PLL_35XX_RATE(120000000, 0x70, 1, 3),
251 PLL_35XX_RATE(110000000, 0x66, 1, 3),
252 PLL_35XX_RATE(100000000, 0x5c, 1, 3),
253 PLL_35XX_RATE(90000000, 0x70, 2, 3),
254 PLL_35XX_RATE(80000000, 0x98, 4, 3),
255 PLL_35XX_RATE(75000000, 0x75, 3, 3),
256 { /* sentinel */ },
257};
258
259static struct samsung_pll_clock s3c244x_common_plls[] __initdata = {
260 [mpll] = PLL(pll_s3c2440_mpll, MPLL, "mpll", "xti",
261 LOCKTIME, MPLLCON, NULL),
262 [upll] = PLL(pll_s3c2410_upll, UPLL, "upll", "xti",
263 LOCKTIME, UPLLCON, NULL),
264};
265
266PNAME(hclk_p) = { "fclk", "div_hclk_2", "div_hclk_4", "div_hclk_3" };
267PNAME(armclk_p) = { "fclk", "hclk" };
268
269struct samsung_mux_clock s3c244x_common_muxes[] __initdata = {
270 MUX(HCLK, "hclk", hclk_p, CLKDIVN, 1, 2),
271 MUX(ARMCLK, "armclk", armclk_p, CAMDIVN, 12, 1),
272};
273
274struct samsung_fixed_factor_clock s3c244x_common_ffactor[] __initdata = {
275 FFACTOR(0, "div_hclk_2", "fclk", 1, 2, 0),
276 FFACTOR(0, "ff_cam", "div_cam", 2, 1, CLK_SET_RATE_PARENT),
277};
278
279static struct clk_div_table div_hclk_4_d[] = {
280 { .val = 0, .div = 4 },
281 { .val = 1, .div = 8 },
282 { /* sentinel */ },
283};
284
285static struct clk_div_table div_hclk_3_d[] = {
286 { .val = 0, .div = 3 },
287 { .val = 1, .div = 6 },
288 { /* sentinel */ },
289};
290
291struct samsung_div_clock s3c244x_common_dividers[] __initdata = {
292 DIV(UCLK, "uclk", "upll", CLKDIVN, 3, 1),
293 DIV(0, "div_hclk", "fclk", CLKDIVN, 1, 1),
294 DIV_T(0, "div_hclk_4", "fclk", CAMDIVN, 9, 1, div_hclk_4_d),
295 DIV_T(0, "div_hclk_3", "fclk", CAMDIVN, 8, 1, div_hclk_3_d),
296 DIV(0, "div_cam", "upll", CAMDIVN, 0, 3),
297};
298
299struct samsung_gate_clock s3c244x_common_gates[] __initdata = {
300 GATE(HCLK_CAM, "cam", "hclk", CLKCON, 19, 0, 0),
301};
302
303struct samsung_clock_alias s3c244x_common_aliases[] __initdata = {
304 ALIAS(PCLK_UART0, "s3c2440-uart.0", "uart"),
305 ALIAS(PCLK_UART1, "s3c2440-uart.1", "uart"),
306 ALIAS(PCLK_UART2, "s3c2440-uart.2", "uart"),
307 ALIAS(PCLK_UART0, "s3c2440-uart.0", "clk_uart_baud2"),
308 ALIAS(PCLK_UART1, "s3c2440-uart.1", "clk_uart_baud2"),
309 ALIAS(PCLK_UART2, "s3c2440-uart.2", "clk_uart_baud2"),
310 ALIAS(HCLK_CAM, NULL, "camif"),
311 ALIAS(CAMIF, NULL, "camif-upll"),
312};
313
314/* S3C2440 specific clocks */
315
316PNAME(s3c2440_camif_p) = { "upll", "ff_cam" };
317
318struct samsung_mux_clock s3c2440_muxes[] __initdata = {
319 MUX(CAMIF, "camif", s3c2440_camif_p, CAMDIVN, 4, 1),
320};
321
322struct samsung_gate_clock s3c2440_gates[] __initdata = {
323 GATE(PCLK_AC97, "ac97", "pclk", CLKCON, 20, 0, 0),
324};
325
326/* S3C2442 specific clocks */
327
328struct samsung_fixed_factor_clock s3c2442_ffactor[] __initdata = {
329 FFACTOR(0, "upll_3", "upll", 1, 3, 0),
330};
331
332PNAME(s3c2442_camif_p) = { "upll", "ff_cam", "upll", "upll_3" };
333
334struct samsung_mux_clock s3c2442_muxes[] __initdata = {
335 MUX(CAMIF, "camif", s3c2442_camif_p, CAMDIVN, 4, 2),
336};
337
338/*
339 * fixed rate clocks generated outside the soc
340 * Only necessary until the devicetree-move is complete
341 */
342#define XTI 1
343struct samsung_fixed_rate_clock s3c2410_common_frate_clks[] __initdata = {
344 FRATE(XTI, "xti", NULL, CLK_IS_ROOT, 0),
345};
346
347static void __init s3c2410_common_clk_register_fixed_ext(unsigned long xti_f)
348{
349 struct samsung_clock_alias xti_alias = ALIAS(XTI, NULL, "xtal");
350
351 s3c2410_common_frate_clks[0].fixed_rate = xti_f;
352 samsung_clk_register_fixed_rate(s3c2410_common_frate_clks,
353 ARRAY_SIZE(s3c2410_common_frate_clks));
354
355 samsung_clk_register_alias(&xti_alias, 1);
356}
357
358void __init s3c2410_common_clk_init(struct device_node *np, unsigned long xti_f,
359 int current_soc,
360 void __iomem *base)
361{
362 reg_base = base;
363
364 if (np) {
365 reg_base = of_iomap(np, 0);
366 if (!reg_base)
367 panic("%s: failed to map registers\n", __func__);
368 }
369
370 samsung_clk_init(np, reg_base, NR_CLKS);
371
372 /* Register external clocks only in non-dt cases */
373 if (!np)
374 s3c2410_common_clk_register_fixed_ext(xti_f);
375
376 if (current_soc == 2410) {
377 if (_get_rate("xti") == 12 * MHZ) {
378 s3c2410_plls[mpll].rate_table = pll_s3c2410_12mhz_tbl;
379 s3c2410_plls[upll].rate_table = pll_s3c2410_12mhz_tbl;
380 }
381
382 /* Register PLLs. */
383 samsung_clk_register_pll(s3c2410_plls,
384 ARRAY_SIZE(s3c2410_plls), reg_base);
385
386 } else { /* S3C2440, S3C2442 */
387 if (_get_rate("xti") == 12 * MHZ) {
388 /*
389 * plls follow different calculation schemes, with the
390 * upll following the same scheme as the s3c2410 plls
391 */
392 s3c244x_common_plls[mpll].rate_table =
393 pll_s3c244x_12mhz_tbl;
394 s3c244x_common_plls[upll].rate_table =
395 pll_s3c2410_12mhz_tbl;
396 }
397
398 /* Register PLLs. */
399 samsung_clk_register_pll(s3c244x_common_plls,
400 ARRAY_SIZE(s3c244x_common_plls), reg_base);
401 }
402
403 /* Register common internal clocks. */
404 samsung_clk_register_mux(s3c2410_common_muxes,
405 ARRAY_SIZE(s3c2410_common_muxes));
406 samsung_clk_register_div(s3c2410_common_dividers,
407 ARRAY_SIZE(s3c2410_common_dividers));
408 samsung_clk_register_gate(s3c2410_common_gates,
409 ARRAY_SIZE(s3c2410_common_gates));
410
411 if (current_soc == S3C2440 || current_soc == S3C2442) {
412 samsung_clk_register_div(s3c244x_common_dividers,
413 ARRAY_SIZE(s3c244x_common_dividers));
414 samsung_clk_register_gate(s3c244x_common_gates,
415 ARRAY_SIZE(s3c244x_common_gates));
416 samsung_clk_register_mux(s3c244x_common_muxes,
417 ARRAY_SIZE(s3c244x_common_muxes));
418 samsung_clk_register_fixed_factor(s3c244x_common_ffactor,
419 ARRAY_SIZE(s3c244x_common_ffactor));
420 }
421
422 /* Register SoC-specific clocks. */
423 switch (current_soc) {
424 case S3C2410:
425 samsung_clk_register_div(s3c2410_dividers,
426 ARRAY_SIZE(s3c2410_dividers));
427 samsung_clk_register_fixed_factor(s3c2410_ffactor,
428 ARRAY_SIZE(s3c2410_ffactor));
429 samsung_clk_register_alias(s3c2410_aliases,
430 ARRAY_SIZE(s3c2410_common_aliases));
431 break;
432 case S3C2440:
433 samsung_clk_register_mux(s3c2440_muxes,
434 ARRAY_SIZE(s3c2440_muxes));
435 samsung_clk_register_gate(s3c2440_gates,
436 ARRAY_SIZE(s3c2440_gates));
437 break;
438 case S3C2442:
439 samsung_clk_register_mux(s3c2442_muxes,
440 ARRAY_SIZE(s3c2442_muxes));
441 samsung_clk_register_fixed_factor(s3c2442_ffactor,
442 ARRAY_SIZE(s3c2442_ffactor));
443 break;
444 }
445
446 /*
447 * Register common aliases at the end, as some of the aliased clocks
448 * are SoC specific.
449 */
450 samsung_clk_register_alias(s3c2410_common_aliases,
451 ARRAY_SIZE(s3c2410_common_aliases));
452
453 if (current_soc == S3C2440 || current_soc == S3C2442) {
454 samsung_clk_register_alias(s3c244x_common_aliases,
455 ARRAY_SIZE(s3c244x_common_aliases));
456 }
457
458 s3c2410_clk_sleep_init();
459}
460
461static void __init s3c2410_clk_init(struct device_node *np)
462{
463 s3c2410_common_clk_init(np, 0, S3C2410, 0);
464}
465CLK_OF_DECLARE(s3c2410_clk, "samsung,s3c2410-clock", s3c2410_clk_init);
466
467static void __init s3c2440_clk_init(struct device_node *np)
468{
469 s3c2410_common_clk_init(np, 0, S3C2440, 0);
470}
471CLK_OF_DECLARE(s3c2440_clk, "samsung,s3c2440-clock", s3c2440_clk_init);
472
473static void __init s3c2442_clk_init(struct device_node *np)
474{
475 s3c2410_common_clk_init(np, 0, S3C2442, 0);
476}
477CLK_OF_DECLARE(s3c2442_clk, "samsung,s3c2442-clock", s3c2442_clk_init);
diff --git a/drivers/clk/samsung/clk-s3c2412.c b/drivers/clk/samsung/clk-s3c2412.c
new file mode 100644
index 000000000000..0f11a07d5c01
--- /dev/null
+++ b/drivers/clk/samsung/clk-s3c2412.c
@@ -0,0 +1,269 @@
1/*
2 * Copyright (c) 2013 Heiko Stuebner <heiko@sntech.de>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 * Common Clock Framework support for S3C2412 and S3C2413.
9 */
10
11#include <linux/clk.h>
12#include <linux/clkdev.h>
13#include <linux/clk-provider.h>
14#include <linux/of.h>
15#include <linux/of_address.h>
16#include <linux/syscore_ops.h>
17
18#include <dt-bindings/clock/s3c2412.h>
19
20#include "clk.h"
21#include "clk-pll.h"
22
23#define LOCKTIME 0x00
24#define MPLLCON 0x04
25#define UPLLCON 0x08
26#define CLKCON 0x0c
27#define CLKDIVN 0x14
28#define CLKSRC 0x1c
29
30/* list of PLLs to be registered */
31enum s3c2412_plls {
32 mpll, upll,
33};
34
35static void __iomem *reg_base;
36
37#ifdef CONFIG_PM_SLEEP
38static struct samsung_clk_reg_dump *s3c2412_save;
39
40/*
41 * list of controller registers to be saved and restored during a
42 * suspend/resume cycle.
43 */
44static unsigned long s3c2412_clk_regs[] __initdata = {
45 LOCKTIME,
46 MPLLCON,
47 UPLLCON,
48 CLKCON,
49 CLKDIVN,
50 CLKSRC,
51};
52
53static int s3c2412_clk_suspend(void)
54{
55 samsung_clk_save(reg_base, s3c2412_save,
56 ARRAY_SIZE(s3c2412_clk_regs));
57
58 return 0;
59}
60
61static void s3c2412_clk_resume(void)
62{
63 samsung_clk_restore(reg_base, s3c2412_save,
64 ARRAY_SIZE(s3c2412_clk_regs));
65}
66
67static struct syscore_ops s3c2412_clk_syscore_ops = {
68 .suspend = s3c2412_clk_suspend,
69 .resume = s3c2412_clk_resume,
70};
71
72static void s3c2412_clk_sleep_init(void)
73{
74 s3c2412_save = samsung_clk_alloc_reg_dump(s3c2412_clk_regs,
75 ARRAY_SIZE(s3c2412_clk_regs));
76 if (!s3c2412_save) {
77 pr_warn("%s: failed to allocate sleep save data, no sleep support!\n",
78 __func__);
79 return;
80 }
81
82 register_syscore_ops(&s3c2412_clk_syscore_ops);
83 return;
84}
85#else
86static void s3c2412_clk_sleep_init(void) {}
87#endif
88
89static struct clk_div_table divxti_d[] = {
90 { .val = 0, .div = 1 },
91 { .val = 1, .div = 2 },
92 { .val = 2, .div = 4 },
93 { .val = 3, .div = 6 },
94 { .val = 4, .div = 8 },
95 { .val = 5, .div = 10 },
96 { .val = 6, .div = 12 },
97 { .val = 7, .div = 14 },
98 { /* sentinel */ },
99};
100
101struct samsung_div_clock s3c2412_dividers[] __initdata = {
102 DIV_T(0, "div_xti", "xti", CLKSRC, 0, 3, divxti_d),
103 DIV(0, "div_cam", "mux_cam", CLKDIVN, 16, 4),
104 DIV(0, "div_i2s", "mux_i2s", CLKDIVN, 12, 4),
105 DIV(0, "div_uart", "mux_uart", CLKDIVN, 8, 4),
106 DIV(0, "div_usb", "mux_usb", CLKDIVN, 6, 1),
107 DIV(0, "div_hclk_half", "hclk", CLKDIVN, 5, 1),
108 DIV(ARMDIV, "armdiv", "msysclk", CLKDIVN, 3, 1),
109 DIV(PCLK, "pclk", "hclk", CLKDIVN, 2, 1),
110 DIV(HCLK, "hclk", "armdiv", CLKDIVN, 0, 2),
111};
112
113struct samsung_fixed_factor_clock s3c2412_ffactor[] __initdata = {
114 FFACTOR(0, "ff_hclk", "hclk", 2, 1, CLK_SET_RATE_PARENT),
115};
116
117/*
118 * The first two use the OM[4] setting, which is not readable from
119 * software, so assume it is set to xti.
120 */
121PNAME(erefclk_p) = { "xti", "xti", "xti", "ext" };
122PNAME(urefclk_p) = { "xti", "xti", "xti", "ext" };
123
124PNAME(camclk_p) = { "usysclk", "hclk" };
125PNAME(usbclk_p) = { "usysclk", "hclk" };
126PNAME(i2sclk_p) = { "erefclk", "mpll" };
127PNAME(uartclk_p) = { "erefclk", "mpll" };
128PNAME(usysclk_p) = { "urefclk", "upll" };
129PNAME(msysclk_p) = { "mdivclk", "mpll" };
130PNAME(mdivclk_p) = { "xti", "div_xti" };
131PNAME(armclk_p) = { "armdiv", "hclk" };
132
133struct samsung_mux_clock s3c2412_muxes[] __initdata = {
134 MUX(0, "erefclk", erefclk_p, CLKSRC, 14, 2),
135 MUX(0, "urefclk", urefclk_p, CLKSRC, 12, 2),
136 MUX(0, "mux_cam", camclk_p, CLKSRC, 11, 1),
137 MUX(0, "mux_usb", usbclk_p, CLKSRC, 10, 1),
138 MUX(0, "mux_i2s", i2sclk_p, CLKSRC, 9, 1),
139 MUX(0, "mux_uart", uartclk_p, CLKSRC, 8, 1),
140 MUX(USYSCLK, "usysclk", usysclk_p, CLKSRC, 5, 1),
141 MUX(MSYSCLK, "msysclk", msysclk_p, CLKSRC, 4, 1),
142 MUX(MDIVCLK, "mdivclk", mdivclk_p, CLKSRC, 3, 1),
143 MUX(ARMCLK, "armclk", armclk_p, CLKDIVN, 4, 1),
144};
145
146static struct samsung_pll_clock s3c2412_plls[] __initdata = {
147 [mpll] = PLL(pll_s3c2440_mpll, MPLL, "mpll", "xti",
148 LOCKTIME, MPLLCON, NULL),
149 [upll] = PLL(pll_s3c2410_upll, UPLL, "upll", "urefclk",
150 LOCKTIME, UPLLCON, NULL),
151};
152
153struct samsung_gate_clock s3c2412_gates[] __initdata = {
154 GATE(PCLK_WDT, "wdt", "pclk", CLKCON, 28, 0, 0),
155 GATE(PCLK_SPI, "spi", "pclk", CLKCON, 27, 0, 0),
156 GATE(PCLK_I2S, "i2s", "pclk", CLKCON, 26, 0, 0),
157 GATE(PCLK_I2C, "i2c", "pclk", CLKCON, 25, 0, 0),
158 GATE(PCLK_ADC, "adc", "pclk", CLKCON, 24, 0, 0),
159 GATE(PCLK_RTC, "rtc", "pclk", CLKCON, 23, 0, 0),
160 GATE(PCLK_GPIO, "gpio", "pclk", CLKCON, 22, CLK_IGNORE_UNUSED, 0),
161 GATE(PCLK_UART2, "uart2", "pclk", CLKCON, 21, 0, 0),
162 GATE(PCLK_UART1, "uart1", "pclk", CLKCON, 20, 0, 0),
163 GATE(PCLK_UART0, "uart0", "pclk", CLKCON, 19, 0, 0),
164 GATE(PCLK_SDI, "sdi", "pclk", CLKCON, 18, 0, 0),
165 GATE(PCLK_PWM, "pwm", "pclk", CLKCON, 17, 0, 0),
166 GATE(PCLK_USBD, "usb-device", "pclk", CLKCON, 16, 0, 0),
167 GATE(SCLK_CAM, "sclk_cam", "div_cam", CLKCON, 15, 0, 0),
168 GATE(SCLK_UART, "sclk_uart", "div_uart", CLKCON, 14, 0, 0),
169 GATE(SCLK_I2S, "sclk_i2s", "div_i2s", CLKCON, 13, 0, 0),
170 GATE(SCLK_USBH, "sclk_usbh", "div_usb", CLKCON, 12, 0, 0),
171 GATE(SCLK_USBD, "sclk_usbd", "div_usb", CLKCON, 11, 0, 0),
172 GATE(HCLK_HALF, "hclk_half", "div_hclk_half", CLKCON, 10, CLK_IGNORE_UNUSED, 0),
173 GATE(HCLK_X2, "hclkx2", "ff_hclk", CLKCON, 9, CLK_IGNORE_UNUSED, 0),
174 GATE(HCLK_SDRAM, "sdram", "hclk", CLKCON, 8, CLK_IGNORE_UNUSED, 0),
175 GATE(HCLK_USBH, "usb-host", "hclk", CLKCON, 6, 0, 0),
176 GATE(HCLK_LCD, "lcd", "hclk", CLKCON, 5, 0, 0),
177 GATE(HCLK_NAND, "nand", "hclk", CLKCON, 4, 0, 0),
178 GATE(HCLK_DMA3, "dma3", "hclk", CLKCON, 3, CLK_IGNORE_UNUSED, 0),
179 GATE(HCLK_DMA2, "dma2", "hclk", CLKCON, 2, CLK_IGNORE_UNUSED, 0),
180 GATE(HCLK_DMA1, "dma1", "hclk", CLKCON, 1, CLK_IGNORE_UNUSED, 0),
181 GATE(HCLK_DMA0, "dma0", "hclk", CLKCON, 0, CLK_IGNORE_UNUSED, 0),
182};
183
184struct samsung_clock_alias s3c2412_aliases[] __initdata = {
185 ALIAS(PCLK_UART0, "s3c2412-uart.0", "uart"),
186 ALIAS(PCLK_UART1, "s3c2412-uart.1", "uart"),
187 ALIAS(PCLK_UART2, "s3c2412-uart.2", "uart"),
188 ALIAS(PCLK_UART0, "s3c2412-uart.0", "clk_uart_baud2"),
189 ALIAS(PCLK_UART1, "s3c2412-uart.1", "clk_uart_baud2"),
190 ALIAS(PCLK_UART2, "s3c2412-uart.2", "clk_uart_baud2"),
191 ALIAS(SCLK_UART, NULL, "clk_uart_baud3"),
192 ALIAS(PCLK_I2C, "s3c2410-i2c.0", "i2c"),
193 ALIAS(PCLK_ADC, NULL, "adc"),
194 ALIAS(PCLK_RTC, NULL, "rtc"),
195 ALIAS(PCLK_PWM, NULL, "timers"),
196 ALIAS(HCLK_LCD, NULL, "lcd"),
197 ALIAS(PCLK_USBD, NULL, "usb-device"),
198 ALIAS(SCLK_USBD, NULL, "usb-bus-gadget"),
199 ALIAS(HCLK_USBH, NULL, "usb-host"),
200 ALIAS(SCLK_USBH, NULL, "usb-bus-host"),
201 ALIAS(ARMCLK, NULL, "armclk"),
202 ALIAS(HCLK, NULL, "hclk"),
203 ALIAS(MPLL, NULL, "mpll"),
204 ALIAS(MSYSCLK, NULL, "fclk"),
205};
206
207/*
208 * fixed rate clocks generated outside the soc
209 * Only necessary until the devicetree-move is complete
210 */
211#define XTI 1
212struct samsung_fixed_rate_clock s3c2412_common_frate_clks[] __initdata = {
213 FRATE(XTI, "xti", NULL, CLK_IS_ROOT, 0),
214 FRATE(0, "ext", NULL, CLK_IS_ROOT, 0),
215};
216
217static void __init s3c2412_common_clk_register_fixed_ext(unsigned long xti_f,
218 unsigned long ext_f)
219{
220 /* xtal alias is necessary for the current cpufreq driver */
221 struct samsung_clock_alias xti_alias = ALIAS(XTI, NULL, "xtal");
222
223 s3c2412_common_frate_clks[0].fixed_rate = xti_f;
224 s3c2412_common_frate_clks[1].fixed_rate = ext_f;
225 samsung_clk_register_fixed_rate(s3c2412_common_frate_clks,
226 ARRAY_SIZE(s3c2412_common_frate_clks));
227
228 samsung_clk_register_alias(&xti_alias, 1);
229}
230
231void __init s3c2412_common_clk_init(struct device_node *np, unsigned long xti_f,
232 unsigned long ext_f, void __iomem *base)
233{
234 reg_base = base;
235
236 if (np) {
237 reg_base = of_iomap(np, 0);
238 if (!reg_base)
239 panic("%s: failed to map registers\n", __func__);
240 }
241
242 samsung_clk_init(np, reg_base, NR_CLKS);
243
244 /* Register external clocks only in non-dt cases */
245 if (!np)
246 s3c2412_common_clk_register_fixed_ext(xti_f, ext_f);
247
248 /* Register PLLs. */
249 samsung_clk_register_pll(s3c2412_plls, ARRAY_SIZE(s3c2412_plls),
250 reg_base);
251
252 /* Register common internal clocks. */
253 samsung_clk_register_mux(s3c2412_muxes, ARRAY_SIZE(s3c2412_muxes));
254 samsung_clk_register_div(s3c2412_dividers,
255 ARRAY_SIZE(s3c2412_dividers));
256 samsung_clk_register_gate(s3c2412_gates, ARRAY_SIZE(s3c2412_gates));
257 samsung_clk_register_fixed_factor(s3c2412_ffactor,
258 ARRAY_SIZE(s3c2412_ffactor));
259 samsung_clk_register_alias(s3c2412_aliases,
260 ARRAY_SIZE(s3c2412_aliases));
261
262 s3c2412_clk_sleep_init();
263}
264
265static void __init s3c2412_clk_init(struct device_node *np)
266{
267 s3c2412_common_clk_init(np, 0, 0, 0);
268}
269CLK_OF_DECLARE(s3c2412_clk, "samsung,s3c2412-clock", s3c2412_clk_init);
diff --git a/drivers/clk/samsung/clk-s3c2443.c b/drivers/clk/samsung/clk-s3c2443.c
new file mode 100644
index 000000000000..8e4f4517e95c
--- /dev/null
+++ b/drivers/clk/samsung/clk-s3c2443.c
@@ -0,0 +1,462 @@
1/*
2 * Copyright (c) 2013 Heiko Stuebner <heiko@sntech.de>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 * Common Clock Framework support for S3C2443 and following SoCs.
9 */
10
11#include <linux/clk.h>
12#include <linux/clkdev.h>
13#include <linux/clk-provider.h>
14#include <linux/of.h>
15#include <linux/of_address.h>
16#include <linux/syscore_ops.h>
17
18#include <dt-bindings/clock/s3c2443.h>
19
20#include "clk.h"
21#include "clk-pll.h"
22
23/* S3C2416 clock controller register offsets */
24#define LOCKCON0 0x00
25#define LOCKCON1 0x04
26#define MPLLCON 0x10
27#define EPLLCON 0x18
28#define EPLLCON_K 0x1C
29#define CLKSRC 0x20
30#define CLKDIV0 0x24
31#define CLKDIV1 0x28
32#define CLKDIV2 0x2C
33#define HCLKCON 0x30
34#define PCLKCON 0x34
35#define SCLKCON 0x38
36
37/* the soc types */
38enum supported_socs {
39 S3C2416,
40 S3C2443,
41 S3C2450,
42};
43
44/* list of PLLs to be registered */
45enum s3c2443_plls {
46 mpll, epll,
47};
48
49static void __iomem *reg_base;
50
51#ifdef CONFIG_PM_SLEEP
52static struct samsung_clk_reg_dump *s3c2443_save;
53
54/*
55 * list of controller registers to be saved and restored during a
56 * suspend/resume cycle.
57 */
58static unsigned long s3c2443_clk_regs[] __initdata = {
59 LOCKCON0,
60 LOCKCON1,
61 MPLLCON,
62 EPLLCON,
63 EPLLCON_K,
64 CLKSRC,
65 CLKDIV0,
66 CLKDIV1,
67 CLKDIV2,
68 PCLKCON,
69 HCLKCON,
70 SCLKCON,
71};
72
73static int s3c2443_clk_suspend(void)
74{
75 samsung_clk_save(reg_base, s3c2443_save,
76 ARRAY_SIZE(s3c2443_clk_regs));
77
78 return 0;
79}
80
81static void s3c2443_clk_resume(void)
82{
83 samsung_clk_restore(reg_base, s3c2443_save,
84 ARRAY_SIZE(s3c2443_clk_regs));
85}
86
87static struct syscore_ops s3c2443_clk_syscore_ops = {
88 .suspend = s3c2443_clk_suspend,
89 .resume = s3c2443_clk_resume,
90};
91
92static void s3c2443_clk_sleep_init(void)
93{
94 s3c2443_save = samsung_clk_alloc_reg_dump(s3c2443_clk_regs,
95 ARRAY_SIZE(s3c2443_clk_regs));
96 if (!s3c2443_save) {
97 pr_warn("%s: failed to allocate sleep save data, no sleep support!\n",
98 __func__);
99 return;
100 }
101
102 register_syscore_ops(&s3c2443_clk_syscore_ops);
103 return;
104}
105#else
106static void s3c2443_clk_sleep_init(void) {}
107#endif
108
109PNAME(epllref_p) = { "mpllref", "mpllref", "xti", "ext" };
110PNAME(esysclk_p) = { "epllref", "epll" };
111PNAME(mpllref_p) = { "xti", "mdivclk" };
112PNAME(msysclk_p) = { "mpllref", "mpll" };
113PNAME(armclk_p) = { "armdiv" , "hclk" };
114PNAME(i2s0_p) = { "div_i2s0", "ext_i2s", "epllref", "epllref" };
115
116struct samsung_mux_clock s3c2443_common_muxes[] __initdata = {
117 MUX(0, "epllref", epllref_p, CLKSRC, 7, 2),
118 MUX(ESYSCLK, "esysclk", esysclk_p, CLKSRC, 6, 1),
119 MUX(0, "mpllref", mpllref_p, CLKSRC, 3, 1),
120 MUX_A(MSYSCLK, "msysclk", msysclk_p, CLKSRC, 4, 1, "msysclk"),
121 MUX_A(ARMCLK, "armclk", armclk_p, CLKDIV0, 13, 1, "armclk"),
122 MUX(0, "mux_i2s0", i2s0_p, CLKSRC, 14, 2),
123};
124
125static struct clk_div_table hclk_d[] = {
126 { .val = 0, .div = 1 },
127 { .val = 1, .div = 2 },
128 { .val = 3, .div = 4 },
129 { /* sentinel */ },
130};
131
132static struct clk_div_table mdivclk_d[] = {
133 { .val = 0, .div = 1 },
134 { .val = 1, .div = 3 },
135 { .val = 2, .div = 5 },
136 { .val = 3, .div = 7 },
137 { .val = 4, .div = 9 },
138 { .val = 5, .div = 11 },
139 { .val = 6, .div = 13 },
140 { .val = 7, .div = 15 },
141 { /* sentinel */ },
142};
143
144struct samsung_div_clock s3c2443_common_dividers[] __initdata = {
145 DIV_T(0, "mdivclk", "xti", CLKDIV0, 6, 3, mdivclk_d),
146 DIV(0, "prediv", "msysclk", CLKDIV0, 4, 2),
147 DIV_T(HCLK, "hclk", "prediv", CLKDIV0, 0, 2, hclk_d),
148 DIV(PCLK, "pclk", "hclk", CLKDIV0, 2, 1),
149 DIV(0, "div_hsspi0_epll", "esysclk", CLKDIV1, 24, 2),
150 DIV(0, "div_fimd", "esysclk", CLKDIV1, 16, 8),
151 DIV(0, "div_i2s0", "esysclk", CLKDIV1, 12, 4),
152 DIV(0, "div_uart", "esysclk", CLKDIV1, 8, 4),
153 DIV(0, "div_hsmmc1", "esysclk", CLKDIV1, 6, 2),
154 DIV(0, "div_usbhost", "esysclk", CLKDIV1, 4, 2),
155};
156
157struct samsung_gate_clock s3c2443_common_gates[] __initdata = {
158 GATE(SCLK_HSMMC_EXT, "sclk_hsmmcext", "ext", SCLKCON, 13, 0, 0),
159 GATE(SCLK_HSMMC1, "sclk_hsmmc1", "div_hsmmc1", SCLKCON, 12, 0, 0),
160 GATE(SCLK_FIMD, "sclk_fimd", "div_fimd", SCLKCON, 10, 0, 0),
161 GATE(SCLK_I2S0, "sclk_i2s0", "mux_i2s0", SCLKCON, 9, 0, 0),
162 GATE(SCLK_UART, "sclk_uart", "div_uart", SCLKCON, 8, 0, 0),
163 GATE(SCLK_USBH, "sclk_usbhost", "div_usbhost", SCLKCON, 1, 0, 0),
164 GATE(HCLK_DRAM, "dram", "hclk", HCLKCON, 19, CLK_IGNORE_UNUSED, 0),
165 GATE(HCLK_SSMC, "ssmc", "hclk", HCLKCON, 18, CLK_IGNORE_UNUSED, 0),
166 GATE(HCLK_HSMMC1, "hsmmc1", "hclk", HCLKCON, 16, 0, 0),
167 GATE(HCLK_USBD, "usb-device", "hclk", HCLKCON, 12, 0, 0),
168 GATE(HCLK_USBH, "usb-host", "hclk", HCLKCON, 11, 0, 0),
169 GATE(HCLK_LCD, "lcd", "hclk", HCLKCON, 9, 0, 0),
170 GATE(HCLK_DMA5, "dma5", "hclk", HCLKCON, 5, CLK_IGNORE_UNUSED, 0),
171 GATE(HCLK_DMA4, "dma4", "hclk", HCLKCON, 4, CLK_IGNORE_UNUSED, 0),
172 GATE(HCLK_DMA3, "dma3", "hclk", HCLKCON, 3, CLK_IGNORE_UNUSED, 0),
173 GATE(HCLK_DMA2, "dma2", "hclk", HCLKCON, 2, CLK_IGNORE_UNUSED, 0),
174 GATE(HCLK_DMA1, "dma1", "hclk", HCLKCON, 1, CLK_IGNORE_UNUSED, 0),
175 GATE(HCLK_DMA0, "dma0", "hclk", HCLKCON, 0, CLK_IGNORE_UNUSED, 0),
176 GATE(PCLK_GPIO, "gpio", "pclk", PCLKCON, 13, CLK_IGNORE_UNUSED, 0),
177 GATE(PCLK_RTC, "rtc", "pclk", PCLKCON, 12, 0, 0),
178 GATE(PCLK_WDT, "wdt", "pclk", PCLKCON, 11, 0, 0),
179 GATE(PCLK_PWM, "pwm", "pclk", PCLKCON, 10, 0, 0),
180 GATE(PCLK_I2S0, "i2s0", "pclk", PCLKCON, 9, 0, 0),
181 GATE(PCLK_AC97, "ac97", "pclk", PCLKCON, 8, 0, 0),
182 GATE(PCLK_ADC, "adc", "pclk", PCLKCON, 7, 0, 0),
183 GATE(PCLK_SPI0, "spi0", "pclk", PCLKCON, 6, 0, 0),
184 GATE(PCLK_I2C0, "i2c0", "pclk", PCLKCON, 4, 0, 0),
185 GATE(PCLK_UART3, "uart3", "pclk", PCLKCON, 3, 0, 0),
186 GATE(PCLK_UART2, "uart2", "pclk", PCLKCON, 2, 0, 0),
187 GATE(PCLK_UART1, "uart1", "pclk", PCLKCON, 1, 0, 0),
188 GATE(PCLK_UART0, "uart0", "pclk", PCLKCON, 0, 0, 0),
189};
190
191struct samsung_clock_alias s3c2443_common_aliases[] __initdata = {
192 ALIAS(HCLK, NULL, "hclk"),
193 ALIAS(HCLK_SSMC, NULL, "nand"),
194 ALIAS(PCLK_UART0, "s3c2440-uart.0", "uart"),
195 ALIAS(PCLK_UART1, "s3c2440-uart.1", "uart"),
196 ALIAS(PCLK_UART2, "s3c2440-uart.2", "uart"),
197 ALIAS(PCLK_UART3, "s3c2440-uart.3", "uart"),
198 ALIAS(PCLK_UART0, "s3c2440-uart.0", "clk_uart_baud2"),
199 ALIAS(PCLK_UART1, "s3c2440-uart.1", "clk_uart_baud2"),
200 ALIAS(PCLK_UART2, "s3c2440-uart.2", "clk_uart_baud2"),
201 ALIAS(PCLK_UART3, "s3c2440-uart.3", "clk_uart_baud2"),
202 ALIAS(SCLK_UART, NULL, "clk_uart_baud3"),
203 ALIAS(PCLK_PWM, NULL, "timers"),
204 ALIAS(PCLK_RTC, NULL, "rtc"),
205 ALIAS(PCLK_WDT, NULL, "watchdog"),
206 ALIAS(PCLK_ADC, NULL, "adc"),
207 ALIAS(PCLK_I2C0, "s3c2410-i2c.0", "i2c"),
208 ALIAS(HCLK_USBD, NULL, "usb-device"),
209 ALIAS(HCLK_USBH, NULL, "usb-host"),
210 ALIAS(SCLK_USBH, NULL, "usb-bus-host"),
211 ALIAS(PCLK_SPI0, "s3c2443-spi.0", "spi"),
212 ALIAS(PCLK_SPI0, "s3c2443-spi.0", "spi_busclk0"),
213 ALIAS(HCLK_HSMMC1, "s3c-sdhci.1", "hsmmc"),
214 ALIAS(HCLK_HSMMC1, "s3c-sdhci.1", "mmc_busclk.0"),
215 ALIAS(PCLK_I2S0, "samsung-i2s.0", "iis"),
216 ALIAS(SCLK_I2S0, NULL, "i2s-if"),
217 ALIAS(HCLK_LCD, NULL, "lcd"),
218 ALIAS(SCLK_FIMD, NULL, "sclk_fimd"),
219};
220
221/* S3C2416 specific clocks */
222
223static struct samsung_pll_clock s3c2416_pll_clks[] __initdata = {
224 [mpll] = PLL(pll_6552_s3c2416, 0, "mpll", "mpllref",
225 LOCKCON0, MPLLCON, NULL),
226 [epll] = PLL(pll_6553, 0, "epll", "epllref",
227 LOCKCON1, EPLLCON, NULL),
228};
229
230PNAME(s3c2416_hsmmc0_p) = { "sclk_hsmmc0", "sclk_hsmmcext" };
231PNAME(s3c2416_hsmmc1_p) = { "sclk_hsmmc1", "sclk_hsmmcext" };
232PNAME(s3c2416_hsspi0_p) = { "hsspi0_epll", "hsspi0_mpll" };
233
234static struct clk_div_table armdiv_s3c2416_d[] = {
235 { .val = 0, .div = 1 },
236 { .val = 1, .div = 2 },
237 { .val = 2, .div = 3 },
238 { .val = 3, .div = 4 },
239 { .val = 5, .div = 6 },
240 { .val = 7, .div = 8 },
241 { /* sentinel */ },
242};
243
244struct samsung_div_clock s3c2416_dividers[] __initdata = {
245 DIV_T(ARMDIV, "armdiv", "msysclk", CLKDIV0, 9, 3, armdiv_s3c2416_d),
246 DIV(0, "div_hsspi0_mpll", "msysclk", CLKDIV2, 0, 4),
247 DIV(0, "div_hsmmc0", "esysclk", CLKDIV2, 6, 2),
248};
249
250struct samsung_mux_clock s3c2416_muxes[] __initdata = {
251 MUX(MUX_HSMMC0, "mux_hsmmc0", s3c2416_hsmmc0_p, CLKSRC, 16, 1),
252 MUX(MUX_HSMMC1, "mux_hsmmc1", s3c2416_hsmmc1_p, CLKSRC, 17, 1),
253 MUX(MUX_HSSPI0, "mux_hsspi0", s3c2416_hsspi0_p, CLKSRC, 18, 1),
254};
255
256struct samsung_gate_clock s3c2416_gates[] __initdata = {
257 GATE(0, "hsspi0_mpll", "div_hsspi0_mpll", SCLKCON, 19, 0, 0),
258 GATE(0, "hsspi0_epll", "div_hsspi0_epll", SCLKCON, 14, 0, 0),
259 GATE(0, "sclk_hsmmc0", "div_hsmmc0", SCLKCON, 6, 0, 0),
260 GATE(HCLK_2D, "2d", "hclk", HCLKCON, 20, 0, 0),
261 GATE(HCLK_HSMMC0, "hsmmc0", "hclk", HCLKCON, 15, 0, 0),
262 GATE(HCLK_IROM, "irom", "hclk", HCLKCON, 13, CLK_IGNORE_UNUSED, 0),
263 GATE(PCLK_PCM, "pcm", "pclk", PCLKCON, 19, 0, 0),
264};
265
266struct samsung_clock_alias s3c2416_aliases[] __initdata = {
267 ALIAS(HCLK_HSMMC0, "s3c-sdhci.0", "hsmmc"),
268 ALIAS(HCLK_HSMMC0, "s3c-sdhci.0", "mmc_busclk.0"),
269 ALIAS(MUX_HSMMC0, "s3c-sdhci.0", "mmc_busclk.2"),
270 ALIAS(MUX_HSMMC1, "s3c-sdhci.1", "mmc_busclk.2"),
271 ALIAS(MUX_HSSPI0, "s3c2443-spi.0", "spi_busclk2"),
272 ALIAS(ARMDIV, NULL, "armdiv"),
273};
274
275/* S3C2443 specific clocks */
276
277static struct samsung_pll_clock s3c2443_pll_clks[] __initdata = {
278 [mpll] = PLL(pll_3000, 0, "mpll", "mpllref",
279 LOCKCON0, MPLLCON, NULL),
280 [epll] = PLL(pll_2126, 0, "epll", "epllref",
281 LOCKCON1, EPLLCON, NULL),
282};
283
284static struct clk_div_table armdiv_s3c2443_d[] = {
285 { .val = 0, .div = 1 },
286 { .val = 8, .div = 2 },
287 { .val = 2, .div = 3 },
288 { .val = 9, .div = 4 },
289 { .val = 10, .div = 6 },
290 { .val = 11, .div = 8 },
291 { .val = 13, .div = 12 },
292 { .val = 15, .div = 16 },
293 { /* sentinel */ },
294};
295
296struct samsung_div_clock s3c2443_dividers[] __initdata = {
297 DIV_T(ARMDIV, "armdiv", "msysclk", CLKDIV0, 9, 4, armdiv_s3c2443_d),
298 DIV(0, "div_cam", "esysclk", CLKDIV1, 26, 4),
299};
300
301struct samsung_gate_clock s3c2443_gates[] __initdata = {
302 GATE(SCLK_HSSPI0, "sclk_hsspi0", "div_hsspi0_epll", SCLKCON, 14, 0, 0),
303 GATE(SCLK_CAM, "sclk_cam", "div_cam", SCLKCON, 11, 0, 0),
304 GATE(HCLK_CFC, "cfc", "hclk", HCLKCON, 17, CLK_IGNORE_UNUSED, 0),
305 GATE(HCLK_CAM, "cam", "hclk", HCLKCON, 8, 0, 0),
306 GATE(PCLK_SPI1, "spi1", "pclk", PCLKCON, 15, 0, 0),
307 GATE(PCLK_SDI, "sdi", "pclk", PCLKCON, 5, 0, 0),
308};
309
310struct samsung_clock_alias s3c2443_aliases[] __initdata = {
311 ALIAS(SCLK_HSSPI0, "s3c2443-spi.0", "spi_busclk2"),
312 ALIAS(SCLK_HSMMC1, "s3c-sdhci.1", "mmc_busclk.2"),
313 ALIAS(SCLK_CAM, NULL, "camif-upll"),
314 ALIAS(PCLK_SPI1, "s3c2410-spi.0", "spi"),
315 ALIAS(PCLK_SDI, NULL, "sdi"),
316 ALIAS(HCLK_CFC, NULL, "cfc"),
317 ALIAS(ARMDIV, NULL, "armdiv"),
318};
319
320/* S3C2450 specific clocks */
321
322PNAME(s3c2450_cam_p) = { "div_cam", "hclk" };
323PNAME(s3c2450_hsspi1_p) = { "hsspi1_epll", "hsspi1_mpll" };
324PNAME(i2s1_p) = { "div_i2s1", "ext_i2s", "epllref", "epllref" };
325
326struct samsung_div_clock s3c2450_dividers[] __initdata = {
327 DIV(0, "div_cam", "esysclk", CLKDIV1, 26, 4),
328 DIV(0, "div_hsspi1_epll", "esysclk", CLKDIV2, 24, 2),
329 DIV(0, "div_hsspi1_mpll", "msysclk", CLKDIV2, 16, 4),
330 DIV(0, "div_i2s1", "esysclk", CLKDIV2, 12, 4),
331};
332
333struct samsung_mux_clock s3c2450_muxes[] __initdata = {
334 MUX(0, "mux_cam", s3c2450_cam_p, CLKSRC, 20, 1),
335 MUX(MUX_HSSPI1, "mux_hsspi1", s3c2450_hsspi1_p, CLKSRC, 19, 1),
336 MUX(0, "mux_i2s1", i2s1_p, CLKSRC, 12, 2),
337};
338
339struct samsung_gate_clock s3c2450_gates[] __initdata = {
340 GATE(SCLK_I2S1, "sclk_i2s1", "div_i2s1", SCLKCON, 5, 0, 0),
341 GATE(HCLK_CFC, "cfc", "hclk", HCLKCON, 17, 0, 0),
342 GATE(HCLK_CAM, "cam", "hclk", HCLKCON, 8, 0, 0),
343 GATE(HCLK_DMA7, "dma7", "hclk", HCLKCON, 7, CLK_IGNORE_UNUSED, 0),
344 GATE(HCLK_DMA6, "dma6", "hclk", HCLKCON, 6, CLK_IGNORE_UNUSED, 0),
345 GATE(PCLK_I2S1, "i2s1", "pclk", PCLKCON, 17, 0, 0),
346 GATE(PCLK_I2C1, "i2c1", "pclk", PCLKCON, 16, 0, 0),
347 GATE(PCLK_SPI1, "spi1", "pclk", PCLKCON, 14, 0, 0),
348};
349
350struct samsung_clock_alias s3c2450_aliases[] __initdata = {
351 ALIAS(PCLK_SPI1, "s3c2443-spi.1", "spi"),
352 ALIAS(PCLK_SPI1, "s3c2443-spi.1", "spi_busclk0"),
353 ALIAS(MUX_HSSPI1, "s3c2443-spi.1", "spi_busclk2"),
354 ALIAS(PCLK_I2C1, "s3c2410-i2c.1", "i2c"),
355};
356
357/*
358 * fixed rate clocks generated outside the soc
359 * Only necessary until the devicetree-move is complete
360 */
361struct samsung_fixed_rate_clock s3c2443_common_frate_clks[] __initdata = {
362 FRATE(0, "xti", NULL, CLK_IS_ROOT, 0),
363 FRATE(0, "ext", NULL, CLK_IS_ROOT, 0),
364 FRATE(0, "ext_i2s", NULL, CLK_IS_ROOT, 0),
365 FRATE(0, "ext_uart", NULL, CLK_IS_ROOT, 0),
366};
367
368static void __init s3c2443_common_clk_register_fixed_ext(unsigned long xti_f)
369{
370 s3c2443_common_frate_clks[0].fixed_rate = xti_f;
371 samsung_clk_register_fixed_rate(s3c2443_common_frate_clks,
372 ARRAY_SIZE(s3c2443_common_frate_clks));
373}
374
375void __init s3c2443_common_clk_init(struct device_node *np, unsigned long xti_f,
376 int current_soc,
377 void __iomem *base)
378{
379 reg_base = base;
380
381 if (np) {
382 reg_base = of_iomap(np, 0);
383 if (!reg_base)
384 panic("%s: failed to map registers\n", __func__);
385 }
386
387 samsung_clk_init(np, reg_base, NR_CLKS);
388
389 /* Register external clocks only in non-dt cases */
390 if (!np)
391 s3c2443_common_clk_register_fixed_ext(xti_f);
392
393 /* Register PLLs. */
394 if (current_soc == S3C2416 || current_soc == S3C2450)
395 samsung_clk_register_pll(s3c2416_pll_clks,
396 ARRAY_SIZE(s3c2416_pll_clks), reg_base);
397 else
398 samsung_clk_register_pll(s3c2443_pll_clks,
399 ARRAY_SIZE(s3c2443_pll_clks), reg_base);
400
401 /* Register common internal clocks. */
402 samsung_clk_register_mux(s3c2443_common_muxes,
403 ARRAY_SIZE(s3c2443_common_muxes));
404 samsung_clk_register_div(s3c2443_common_dividers,
405 ARRAY_SIZE(s3c2443_common_dividers));
406 samsung_clk_register_gate(s3c2443_common_gates,
407 ARRAY_SIZE(s3c2443_common_gates));
408 samsung_clk_register_alias(s3c2443_common_aliases,
409 ARRAY_SIZE(s3c2443_common_aliases));
410
411 /* Register SoC-specific clocks. */
412 switch (current_soc) {
413 case S3C2450:
414 samsung_clk_register_div(s3c2450_dividers,
415 ARRAY_SIZE(s3c2450_dividers));
416 samsung_clk_register_mux(s3c2450_muxes,
417 ARRAY_SIZE(s3c2450_muxes));
418 samsung_clk_register_gate(s3c2450_gates,
419 ARRAY_SIZE(s3c2450_gates));
420 samsung_clk_register_alias(s3c2450_aliases,
421 ARRAY_SIZE(s3c2450_aliases));
422 /* fall through, as s3c2450 extends the s3c2416 clocks */
423 case S3C2416:
424 samsung_clk_register_div(s3c2416_dividers,
425 ARRAY_SIZE(s3c2416_dividers));
426 samsung_clk_register_mux(s3c2416_muxes,
427 ARRAY_SIZE(s3c2416_muxes));
428 samsung_clk_register_gate(s3c2416_gates,
429 ARRAY_SIZE(s3c2416_gates));
430 samsung_clk_register_alias(s3c2416_aliases,
431 ARRAY_SIZE(s3c2416_aliases));
432 break;
433 case S3C2443:
434 samsung_clk_register_div(s3c2443_dividers,
435 ARRAY_SIZE(s3c2443_dividers));
436 samsung_clk_register_gate(s3c2443_gates,
437 ARRAY_SIZE(s3c2443_gates));
438 samsung_clk_register_alias(s3c2443_aliases,
439 ARRAY_SIZE(s3c2443_aliases));
440 break;
441 }
442
443 s3c2443_clk_sleep_init();
444}
445
446static void __init s3c2416_clk_init(struct device_node *np)
447{
448 s3c2443_common_clk_init(np, 0, S3C2416, 0);
449}
450CLK_OF_DECLARE(s3c2416_clk, "samsung,s3c2416-clock", s3c2416_clk_init);
451
452static void __init s3c2443_clk_init(struct device_node *np)
453{
454 s3c2443_common_clk_init(np, 0, S3C2443, 0);
455}
456CLK_OF_DECLARE(s3c2443_clk, "samsung,s3c2443-clock", s3c2443_clk_init);
457
458static void __init s3c2450_clk_init(struct device_node *np)
459{
460 s3c2443_common_clk_init(np, 0, S3C2450, 0);
461}
462CLK_OF_DECLARE(s3c2450_clk, "samsung,s3c2450-clock", s3c2450_clk_init);