linux-samsung-soc.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/7] ARM: S3C24XX: Convert S3C2416 to common clock framework
@ 2013-03-12  0:41 Heiko Stübner
  2013-03-12  0:42 ` [PATCH 1/7] clk: samsung: add plls used in s3c2416 and s3c2443 Heiko Stübner
                   ` (6 more replies)
  0 siblings, 7 replies; 14+ messages in thread
From: Heiko Stübner @ 2013-03-12  0:41 UTC (permalink / raw)
  To: Kukjin Kim
  Cc: mturquette, linux-arm-kernel, linux-samsung-soc, Thomas Abraham,
	Sylwester Nawrocki, t.figa

Due to the upcoming change in pwm/samsung-time handling, this series is meant
as mere discussion source. Nevertheless applied to the current linux-samsung
for-next it sucessfully enables the s3c2416 to use the common clock framework.

This series is dependant on the previous samsung-clock fixes and obviously
tested on a s3c2416.

Heiko Stuebner (7):
  clk: samsung: add plls used in s3c2416 and s3c2443
  ARM: S3C24XX: add soc_is_s3c2416 and soc_is_s3c2443
  ARM: S3C24XX: enable legacy clock code only when SAMSUNG_CLOCK selected
  clk: samsung: add clock-driver for s3c2416, s3c2443 and s3c2450
  DO_NOT_APPLY: add clock driver for Samsung pwm clocks
  ARM: SAMSUNG: use clk_prepare_enable in samsung-time
  DO_NOT_APPLY: convert s3c2416 to use the common clock framework

 arch/arm/mach-s3c24xx/Kconfig            |    2 +-
 arch/arm/mach-s3c24xx/Makefile           |    2 +-
 arch/arm/mach-s3c24xx/clock-s3c2416.c    |  173 ----------
 arch/arm/mach-s3c24xx/common-s3c2443.c   |   12 +
 arch/arm/mach-s3c24xx/common.c           |    2 +
 arch/arm/mach-s3c24xx/common.h           |    9 +
 arch/arm/mach-s3c24xx/mach-smdk2416.c    |    9 +-
 arch/arm/plat-samsung/include/plat/cpu.h |   20 +
 arch/arm/plat-samsung/samsung-time.c     |    6 +-
 drivers/clk/samsung/Makefile             |    1 +
 drivers/clk/samsung/clk-pll.c            |  376 ++++++++++++++++++++
 drivers/clk/samsung/clk-pll.h            |    8 +
 drivers/clk/samsung/clk-pwm.c            |  554 ++++++++++++++++++++++++++++++
 drivers/clk/samsung/clk-s3c2443.c        |  463 +++++++++++++++++++++++++
 14 files changed, 1457 insertions(+), 180 deletions(-)
 delete mode 100644 arch/arm/mach-s3c24xx/clock-s3c2416.c
 create mode 100644 drivers/clk/samsung/clk-pwm.c
 create mode 100644 drivers/clk/samsung/clk-s3c2443.c

-- 
1.7.2.3

^ permalink raw reply	[flat|nested] 14+ messages in thread

* [PATCH 1/7] clk: samsung: add plls used in s3c2416 and s3c2443
  2013-03-12  0:41 [PATCH 0/7] ARM: S3C24XX: Convert S3C2416 to common clock framework Heiko Stübner
@ 2013-03-12  0:42 ` Heiko Stübner
  2013-03-12 11:27   ` Russell King - ARM Linux
  2013-03-12 12:10   ` Sylwester Nawrocki
  2013-03-12  0:42 ` [PATCH 2/7] ARM: S3C24XX: add soc_is_s3c2416 and soc_is_s3c2443 Heiko Stübner
                   ` (5 subsequent siblings)
  6 siblings, 2 replies; 14+ messages in thread
From: Heiko Stübner @ 2013-03-12  0:42 UTC (permalink / raw)
  To: Kukjin Kim
  Cc: mturquette, linux-arm-kernel, linux-samsung-soc, Thomas Abraham,
	Sylwester Nawrocki, t.figa

This adds support for pll2126x, pll3000x, pll6552x and pll6553x.

Signed-off-by: Heiko Stuebner <heiko@sntech.de>
---
 drivers/clk/samsung/clk-pll.c |  376 +++++++++++++++++++++++++++++++++++++++++
 drivers/clk/samsung/clk-pll.h |    8 +
 2 files changed, 384 insertions(+), 0 deletions(-)

diff --git a/drivers/clk/samsung/clk-pll.c b/drivers/clk/samsung/clk-pll.c
index 4b24511..b772f9e 100644
--- a/drivers/clk/samsung/clk-pll.c
+++ b/drivers/clk/samsung/clk-pll.c
@@ -400,6 +400,97 @@ struct clk * __init samsung_clk_register_pll46xx(const char *name,
 }
 
 /*
+ * PLL2126x Clock Type
+ */
+
+#define PLL2126X_MDIV_MASK	(0xFF)
+#define PLL2126X_PDIV_MASK	(0x3)
+#define PLL2126X_SDIV_MASK	(0x3)
+#define PLL2126X_MDIV_SHIFT	(16)
+#define PLL2126X_PDIV_SHIFT	(8)
+#define PLL2126X_SDIV_SHIFT	(0)
+
+struct samsung_clk_pll2126x {
+	struct clk_hw		hw;
+	const void __iomem	*con_reg;
+};
+
+#define to_clk_pll2126x(_hw) container_of(_hw, struct samsung_clk_pll2126x, hw)
+
+static unsigned long samsung_pll2126x_recalc_rate(struct clk_hw *hw,
+				unsigned long parent_rate)
+{
+	struct samsung_clk_pll2126x *pll = to_clk_pll2126x(hw);
+	u32 pll_con, mdiv, pdiv, sdiv;
+	u64 fvco = parent_rate;
+
+	pll_con = __raw_readl(pll->con_reg);
+	mdiv = (pll_con >> PLL2126X_MDIV_SHIFT) & PLL2126X_MDIV_MASK;
+	pdiv = (pll_con >> PLL2126X_PDIV_SHIFT) & PLL2126X_PDIV_MASK;
+	sdiv = (pll_con >> PLL2126X_SDIV_SHIFT) & PLL2126X_SDIV_MASK;
+
+	fvco *= (mdiv + 8);
+	do_div(fvco, (pdiv + 2) << sdiv);
+
+	return (unsigned long)fvco;
+}
+
+/* todo: implement pll2126x clock round rate operation */
+static long samsung_pll2126x_round_rate(struct clk_hw *hw,
+				unsigned long drate, unsigned long *prate)
+{
+	return -ENOTSUPP;
+}
+
+/* todo: implement pll2126x clock set rate */
+static int samsung_pll2126x_set_rate(struct clk_hw *hw, unsigned long drate,
+				unsigned long prate)
+{
+	return -ENOTSUPP;
+}
+
+static const struct clk_ops samsung_pll2126x_clk_ops = {
+	.recalc_rate = samsung_pll2126x_recalc_rate,
+	.round_rate = samsung_pll2126x_round_rate,
+	.set_rate = samsung_pll2126x_set_rate,
+};
+
+struct clk * __init samsung_clk_register_pll2126x(const char *name,
+			const char *pname, const void __iomem *con_reg)
+{
+	struct samsung_clk_pll2126x *pll;
+	struct clk *clk;
+	struct clk_init_data init;
+
+	pll = kzalloc(sizeof(*pll), GFP_KERNEL);
+	if (!pll) {
+		pr_err("%s: could not allocate pll clk %s\n", __func__, name);
+		return NULL;
+	}
+
+	init.name = name;
+	init.ops = &samsung_pll2126x_clk_ops;
+	init.flags = CLK_GET_RATE_NOCACHE;
+	init.parent_names = &pname;
+	init.num_parents = 1;
+
+	pll->hw.init = &init;
+	pll->con_reg = con_reg;
+
+	clk = clk_register(NULL, &pll->hw);
+	if (IS_ERR(clk)) {
+		pr_err("%s: failed to register pll clock %s\n", __func__,
+				name);
+		kfree(pll);
+	}
+
+	if (clk_register_clkdev(clk, name, NULL))
+		pr_err("%s: failed to register lookup for %s", __func__, name);
+
+	return clk;
+}
+
+/*
  * PLL2550x Clock Type
  */
 
@@ -497,3 +588,288 @@ struct clk * __init samsung_clk_register_pll2550x(const char *name,
 
 	return clk;
 }
+
+/*
+ * PLL3000x Clock Type
+ */
+
+#define PLL3000X_MDIV_MASK	(0xFF)
+#define PLL3000X_PDIV_MASK	(0x3)
+#define PLL3000X_SDIV_MASK	(0x3)
+#define PLL3000X_MDIV_SHIFT	(16)
+#define PLL3000X_PDIV_SHIFT	(8)
+#define PLL3000X_SDIV_SHIFT	(0)
+
+struct samsung_clk_pll3000x {
+	struct clk_hw		hw;
+	const void __iomem	*con_reg;
+};
+
+#define to_clk_pll3000x(_hw) container_of(_hw, struct samsung_clk_pll3000x, hw)
+
+static unsigned long samsung_pll3000x_recalc_rate(struct clk_hw *hw,
+				unsigned long parent_rate)
+{
+	struct samsung_clk_pll3000x *pll = to_clk_pll3000x(hw);
+	u32 pll_con, mdiv, pdiv, sdiv;
+	u64 fvco = parent_rate;
+
+	pll_con = __raw_readl(pll->con_reg);
+	mdiv = (pll_con >> PLL3000X_MDIV_SHIFT) & PLL3000X_MDIV_MASK;
+	pdiv = (pll_con >> PLL3000X_PDIV_SHIFT) & PLL3000X_PDIV_MASK;
+	sdiv = (pll_con >> PLL3000X_SDIV_SHIFT) & PLL3000X_SDIV_MASK;
+
+	fvco *= (2 * (mdiv + 8));
+	do_div(fvco, pdiv << sdiv);
+
+	return (unsigned long)fvco;
+}
+
+/* todo: implement pll3000x clock round rate operation */
+static long samsung_pll3000x_round_rate(struct clk_hw *hw,
+				unsigned long drate, unsigned long *prate)
+{
+	return -ENOTSUPP;
+}
+
+/* todo: implement pll3000x clock set rate */
+static int samsung_pll3000x_set_rate(struct clk_hw *hw, unsigned long drate,
+				unsigned long prate)
+{
+	return -ENOTSUPP;
+}
+
+static const struct clk_ops samsung_pll3000x_clk_ops = {
+	.recalc_rate = samsung_pll3000x_recalc_rate,
+	.round_rate = samsung_pll3000x_round_rate,
+	.set_rate = samsung_pll3000x_set_rate,
+};
+
+struct clk * __init samsung_clk_register_pll3000x(const char *name,
+			const char *pname, const void __iomem *con_reg)
+{
+	struct samsung_clk_pll3000x *pll;
+	struct clk *clk;
+	struct clk_init_data init;
+
+	pll = kzalloc(sizeof(*pll), GFP_KERNEL);
+	if (!pll) {
+		pr_err("%s: could not allocate pll clk %s\n", __func__, name);
+		return NULL;
+	}
+
+	init.name = name;
+	init.ops = &samsung_pll3000x_clk_ops;
+	init.flags = CLK_GET_RATE_NOCACHE;
+	init.parent_names = &pname;
+	init.num_parents = 1;
+
+	pll->hw.init = &init;
+	pll->con_reg = con_reg;
+
+	clk = clk_register(NULL, &pll->hw);
+	if (IS_ERR(clk)) {
+		pr_err("%s: failed to register pll clock %s\n", __func__,
+				name);
+		kfree(pll);
+	}
+
+	if (clk_register_clkdev(clk, name, NULL))
+		pr_err("%s: failed to register lookup for %s", __func__, name);
+
+	return clk;
+}
+
+/*
+ * PLL6552x Clock Type
+ */
+
+#define PLL6552X_MDIV_MASK	(0x3FF)
+#define PLL6552X_PDIV_MASK	(0x3F)
+#define PLL6552X_SDIV_MASK	(0x7)
+#define PLL6552X_MDIV_SHIFT	(14)
+#define PLL6552X_PDIV_SHIFT	(5)
+#define PLL6552X_SDIV_SHIFT	(0)
+
+struct samsung_clk_pll6552x {
+	struct clk_hw		hw;
+	const void __iomem	*con_reg;
+};
+
+#define to_clk_pll6552x(_hw) container_of(_hw, struct samsung_clk_pll6552x, hw)
+
+static unsigned long samsung_pll6552x_recalc_rate(struct clk_hw *hw,
+				unsigned long parent_rate)
+{
+	struct samsung_clk_pll6552x *pll = to_clk_pll6552x(hw);
+	u32 pll_con, mdiv, pdiv, sdiv;
+	u64 fvco = parent_rate;
+
+	pll_con = __raw_readl(pll->con_reg);
+	mdiv = (pll_con >> PLL6552X_MDIV_SHIFT) & PLL6552X_MDIV_MASK;
+	pdiv = (pll_con >> PLL6552X_PDIV_SHIFT) & PLL6552X_PDIV_MASK;
+	sdiv = (pll_con >> PLL6552X_SDIV_SHIFT) & PLL6552X_SDIV_MASK;
+
+	fvco *= mdiv;
+	do_div(fvco, (pdiv << sdiv));
+
+	return (unsigned long)fvco;
+}
+
+/* todo: implement pll6552x clock round rate operation */
+static long samsung_pll6552x_round_rate(struct clk_hw *hw,
+				unsigned long drate, unsigned long *prate)
+{
+	return -ENOTSUPP;
+}
+
+/* todo: implement pll6552x clock set rate */
+static int samsung_pll6552x_set_rate(struct clk_hw *hw, unsigned long drate,
+				unsigned long prate)
+{
+	return -ENOTSUPP;
+}
+
+static const struct clk_ops samsung_pll6552x_clk_ops = {
+	.recalc_rate = samsung_pll6552x_recalc_rate,
+	.round_rate = samsung_pll6552x_round_rate,
+	.set_rate = samsung_pll6552x_set_rate,
+};
+
+struct clk * __init samsung_clk_register_pll6552x(const char *name,
+			const char *pname, const void __iomem *con_reg)
+{
+	struct samsung_clk_pll6552x *pll;
+	struct clk *clk;
+	struct clk_init_data init;
+
+	pll = kzalloc(sizeof(*pll), GFP_KERNEL);
+	if (!pll) {
+		pr_err("%s: could not allocate pll clk %s\n", __func__, name);
+		return NULL;
+	}
+
+	init.name = name;
+	init.ops = &samsung_pll6552x_clk_ops;
+	init.flags = CLK_GET_RATE_NOCACHE;
+	init.parent_names = &pname;
+	init.num_parents = 1;
+
+	pll->hw.init = &init;
+	pll->con_reg = con_reg;
+
+	clk = clk_register(NULL, &pll->hw);
+	if (IS_ERR(clk)) {
+		pr_err("%s: failed to register pll clock %s\n", __func__,
+				name);
+		kfree(pll);
+	}
+
+	if (clk_register_clkdev(clk, name, NULL))
+		pr_err("%s: failed to register lookup for %s", __func__, name);
+
+	return clk;
+}
+
+/*
+ * PLL6553x Clock Type
+ */
+
+#define PLL6553X_MDIV_MASK	(0x7F)
+#define PLL6553X_PDIV_MASK	(0x1F)
+#define PLL6553X_SDIV_MASK	(0x3)
+#define PLL6553X_KDIV_MASK	(0xFFFF)
+#define PLL6553X_MDIV_SHIFT	(16)
+#define PLL6553X_PDIV_SHIFT	(8)
+#define PLL6553X_SDIV_SHIFT	(0)
+
+struct samsung_clk_pll6553x {
+	struct clk_hw		hw;
+	const void __iomem	*con_reg;
+};
+
+#define to_clk_pll6553x(_hw) container_of(_hw, struct samsung_clk_pll6553x, hw)
+
+static unsigned long samsung_pll6553x_recalc_rate(struct clk_hw *hw,
+				unsigned long parent_rate)
+{
+	struct samsung_clk_pll6553x *pll = to_clk_pll6553x(hw);
+	u32 pll_con0, pll_con1, mdiv, pdiv, sdiv, kdiv;
+	u64 fvco = parent_rate;
+
+	pll_con0 = __raw_readl(pll->con_reg);
+	pll_con1 = __raw_readl(pll->con_reg + 4);
+	mdiv = (pll_con0 >> PLL6553X_MDIV_SHIFT) & PLL6553X_MDIV_MASK;
+	pdiv = (pll_con0 >> PLL6553X_PDIV_SHIFT) & PLL6553X_PDIV_MASK;
+	sdiv = (pll_con0 >> PLL6553X_SDIV_SHIFT) & PLL6553X_SDIV_MASK;
+	kdiv = pll_con1 & PLL6553X_KDIV_MASK;
+
+	/*
+	 * We need to multiple parent_rate by mdiv (the integer part) and kdiv
+	 * which is in 2^16ths, so shift mdiv up (does not overflow) and
+	 * add kdiv before multiplying. The use of tmp is to avoid any
+	 * overflows before shifting bac down into result when multipling
+	 * by the mdiv and kdiv pair.
+	 */
+
+	fvco *= (mdiv << 16) + kdiv;
+	do_div(fvco, (pdiv << sdiv));
+	fvco >>= 16;
+
+	return (unsigned long)fvco;
+}
+
+/* todo: implement pll6553x clock round rate operation */
+static long samsung_pll6553x_round_rate(struct clk_hw *hw,
+				unsigned long drate, unsigned long *prate)
+{
+	return -ENOTSUPP;
+}
+
+/* todo: implement pll6553x clock set rate */
+static int samsung_pll6553x_set_rate(struct clk_hw *hw, unsigned long drate,
+				unsigned long prate)
+{
+	return -ENOTSUPP;
+}
+
+static const struct clk_ops samsung_pll6553x_clk_ops = {
+	.recalc_rate = samsung_pll6553x_recalc_rate,
+	.round_rate = samsung_pll6553x_round_rate,
+	.set_rate = samsung_pll6553x_set_rate,
+};
+
+struct clk * __init samsung_clk_register_pll6553x(const char *name,
+			const char *pname, const void __iomem *con_reg)
+{
+	struct samsung_clk_pll6553x *pll;
+	struct clk *clk;
+	struct clk_init_data init;
+
+	pll = kzalloc(sizeof(*pll), GFP_KERNEL);
+	if (!pll) {
+		pr_err("%s: could not allocate pll clk %s\n", __func__, name);
+		return NULL;
+	}
+
+	init.name = name;
+	init.ops = &samsung_pll6553x_clk_ops;
+	init.flags = CLK_GET_RATE_NOCACHE;
+	init.parent_names = &pname;
+	init.num_parents = 1;
+
+	pll->hw.init = &init;
+	pll->con_reg = con_reg;
+
+	clk = clk_register(NULL, &pll->hw);
+	if (IS_ERR(clk)) {
+		pr_err("%s: failed to register pll clock %s\n", __func__,
+				name);
+		kfree(pll);
+	}
+
+	if (clk_register_clkdev(clk, name, NULL))
+		pr_err("%s: failed to register lookup for %s", __func__, name);
+
+	return clk;
+}
diff --git a/drivers/clk/samsung/clk-pll.h b/drivers/clk/samsung/clk-pll.h
index f33786e..465ee6f 100644
--- a/drivers/clk/samsung/clk-pll.h
+++ b/drivers/clk/samsung/clk-pll.h
@@ -34,8 +34,16 @@ extern struct clk * __init samsung_clk_register_pll45xx(const char *name,
 extern struct clk * __init samsung_clk_register_pll46xx(const char *name,
 			const char *pname, const void __iomem *con_reg,
 			enum pll46xx_type type);
+extern struct clk * __init samsung_clk_register_pll2126x(const char *name,
+			const char *pname, const void __iomem *con_reg);
 extern struct clk * __init samsung_clk_register_pll2550x(const char *name,
 			const char *pname, const void __iomem *reg_base,
 			const unsigned long offset);
+extern struct clk * __init samsung_clk_register_pll3000x(const char *name,
+			const char *pname, const void __iomem *con_reg);
+extern struct clk * __init samsung_clk_register_pll6552x(const char *name,
+			const char *pname, const void __iomem *con_reg);
+extern struct clk * __init samsung_clk_register_pll6553x(const char *name,
+			const char *pname, const void __iomem *con_reg);
 
 #endif /* __SAMSUNG_CLK_PLL_H */
-- 
1.7.2.3

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 2/7] ARM: S3C24XX: add soc_is_s3c2416 and soc_is_s3c2443
  2013-03-12  0:41 [PATCH 0/7] ARM: S3C24XX: Convert S3C2416 to common clock framework Heiko Stübner
  2013-03-12  0:42 ` [PATCH 1/7] clk: samsung: add plls used in s3c2416 and s3c2443 Heiko Stübner
@ 2013-03-12  0:42 ` Heiko Stübner
  2013-03-12  0:43 ` [PATCH 3/7] ARM: S3C24XX: enable legacy clock code only when SAMSUNG_CLOCK selected Heiko Stübner
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 14+ messages in thread
From: Heiko Stübner @ 2013-03-12  0:42 UTC (permalink / raw)
  To: Kukjin Kim
  Cc: mturquette, linux-arm-kernel, linux-samsung-soc, Thomas Abraham,
	Sylwester Nawrocki, t.figa

This is needed to distinguish between them during at least the clock init.

Signed-off-by: Heiko Stuebner <heiko@sntech.de>
---
 arch/arm/plat-samsung/include/plat/cpu.h |   20 ++++++++++++++++++++
 1 files changed, 20 insertions(+), 0 deletions(-)

diff --git a/arch/arm/plat-samsung/include/plat/cpu.h b/arch/arm/plat-samsung/include/plat/cpu.h
index 989fefe..33dad1c 100644
--- a/arch/arm/plat-samsung/include/plat/cpu.h
+++ b/arch/arm/plat-samsung/include/plat/cpu.h
@@ -26,6 +26,12 @@ extern unsigned long samsung_cpu_id;
 #define S3C2412_CPU_ID		0x32412000
 #define S3C2412_CPU_MASK	0xFFFFF000
 
+#define S3C2416_CPU_ID		0x32450000
+#define S3C2416_CPU_MASK	0xFFFFF000
+
+#define S3C2443_CPU_ID		0x32443000
+#define S3C2443_CPU_MASK	0xFFFFF000
+
 #define S3C6400_CPU_ID		0x36400000
 #define S3C6410_CPU_ID		0x36410000
 #define S3C64XX_CPU_MASK	0xFFFFF000
@@ -57,6 +63,8 @@ static inline int is_samsung_##name(void)	\
 
 IS_SAMSUNG_CPU(s3c24xx, S3C24XX_CPU_ID, S3C24XX_CPU_MASK)
 IS_SAMSUNG_CPU(s3c2412, S3C2412_CPU_ID, S3C2412_CPU_MASK)
+IS_SAMSUNG_CPU(s3c2416, S3C2416_CPU_ID, S3C2416_CPU_MASK)
+IS_SAMSUNG_CPU(s3c2443, S3C2443_CPU_ID, S3C2443_CPU_MASK)
 IS_SAMSUNG_CPU(s3c6400, S3C6400_CPU_ID, S3C64XX_CPU_MASK)
 IS_SAMSUNG_CPU(s3c6410, S3C6410_CPU_ID, S3C64XX_CPU_MASK)
 IS_SAMSUNG_CPU(s5p6440, S5P6440_CPU_ID, S5P64XX_CPU_MASK)
@@ -84,6 +92,18 @@ IS_SAMSUNG_CPU(exynos5440, EXYNOS5440_SOC_ID, EXYNOS5_SOC_MASK)
 # define soc_is_s3c2412()	0
 #endif
 
+#if defined(CONFIG_CPU_S3C2416)
+# define soc_is_s3c2416()	is_samsung_s3c2416()
+#else
+# define soc_is_s3c2416()	0
+#endif
+
+#if defined(CONFIG_CPU_S3C2443)
+# define soc_is_s3c2443()	is_samsung_s3c2443()
+#else
+# define soc_is_s3c2443()	0
+#endif
+
 #if defined(CONFIG_CPU_S3C6400) || defined(CONFIG_CPU_S3C6410)
 # define soc_is_s3c64xx()	(is_samsung_s3c6400() || is_samsung_s3c6410())
 #else
-- 
1.7.2.3

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 3/7] ARM: S3C24XX: enable legacy clock code only when SAMSUNG_CLOCK selected
  2013-03-12  0:41 [PATCH 0/7] ARM: S3C24XX: Convert S3C2416 to common clock framework Heiko Stübner
  2013-03-12  0:42 ` [PATCH 1/7] clk: samsung: add plls used in s3c2416 and s3c2443 Heiko Stübner
  2013-03-12  0:42 ` [PATCH 2/7] ARM: S3C24XX: add soc_is_s3c2416 and soc_is_s3c2443 Heiko Stübner
@ 2013-03-12  0:43 ` Heiko Stübner
  2013-03-12  0:43 ` [PATCH 4/7] clk: samsung: add clock-driver for s3c2416, s3c2443 and s3c2450 Heiko Stübner
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 14+ messages in thread
From: Heiko Stübner @ 2013-03-12  0:43 UTC (permalink / raw)
  To: Kukjin Kim
  Cc: mturquette, linux-arm-kernel, linux-samsung-soc, Thomas Abraham,
	Sylwester Nawrocki, t.figa

This enables a smooth transition, as not all S3C24XX SoCs need to be
converted at the same time and can instead simply exchange their
select SAMSUNG_CLOCK with a select COMMON_CLK after the conversion.

Signed-off-by: Heiko Stuebner <heiko@sntech.de>
---
 arch/arm/mach-s3c24xx/common-s3c2443.c |    2 ++
 arch/arm/mach-s3c24xx/common.c         |    2 ++
 2 files changed, 4 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-s3c24xx/common-s3c2443.c b/arch/arm/mach-s3c24xx/common-s3c2443.c
index f6b9f2e..b5bbeb7 100644
--- a/arch/arm/mach-s3c24xx/common-s3c2443.c
+++ b/arch/arm/mach-s3c24xx/common-s3c2443.c
@@ -28,6 +28,7 @@
 #include <plat/cpu-freq.h>
 
 
+#ifdef CONFIG_SAMSUNG_CLOCK
 static int s3c2443_gate(void __iomem *reg, struct clk *clk, int enable)
 {
 	u32 ctrlbit = clk->ctrlbit;
@@ -673,3 +674,4 @@ void __init s3c2443_common_init_clocks(int xtal, pll_fn get_mpll,
 
 	s3c2443_common_setup_clocks(get_mpll);
 }
+#endif
diff --git a/arch/arm/mach-s3c24xx/common.c b/arch/arm/mach-s3c24xx/common.c
index d97533d..9131eb2 100644
--- a/arch/arm/mach-s3c24xx/common.c
+++ b/arch/arm/mach-s3c24xx/common.c
@@ -285,6 +285,7 @@ struct s3c24xx_uart_resources s3c2410_uart_resources[] __initdata = {
 
 /* initialise all the clocks */
 
+#ifdef CONFIG_SAMSUNG_CLOCK
 void __init_or_cpufreq s3c24xx_setup_clocks(unsigned long fclk,
 					   unsigned long hclk,
 					   unsigned long pclk)
@@ -297,3 +298,4 @@ void __init_or_cpufreq s3c24xx_setup_clocks(unsigned long fclk,
 	clk_p.rate = pclk;
 	clk_f.rate = fclk;
 }
+#endif
-- 
1.7.2.3

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 4/7] clk: samsung: add clock-driver for s3c2416, s3c2443 and s3c2450
  2013-03-12  0:41 [PATCH 0/7] ARM: S3C24XX: Convert S3C2416 to common clock framework Heiko Stübner
                   ` (2 preceding siblings ...)
  2013-03-12  0:43 ` [PATCH 3/7] ARM: S3C24XX: enable legacy clock code only when SAMSUNG_CLOCK selected Heiko Stübner
@ 2013-03-12  0:43 ` Heiko Stübner
  2013-03-12  0:44 ` [PATCH 5/7] DO_NOT_APPLY: add clock driver for Samsung pwm clocks Heiko Stübner
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 14+ messages in thread
From: Heiko Stübner @ 2013-03-12  0:43 UTC (permalink / raw)
  To: Kukjin Kim
  Cc: mturquette, linux-arm-kernel, linux-samsung-soc, Thomas Abraham,
	Sylwester Nawrocki, t.figa

The three SoCs share a common clock tree which only differs in the
existence of some special clocks. The s3c2450 specific clocks will
only be reachable via DT in the near future, as there is no generic
way to distinguish between the similar s3c2416 and s3c2450 SoCs.

As with all parts common to these three SoCs the driver is named
after the s3c2443, as it was the first SoC introducing this structure
and there exists no other label to describe this s3c24xx epoch.

The clock structure is built according to the manuals of the included
SoCs and might include changes in comparison to the previous clock
structure. As an example the sclk_uart was never handled previously and
the div_uart was made the clock used by the serial driver.

Signed-off-by: Heiko Stuebner <heiko@sntech.de>
---
 drivers/clk/samsung/Makefile      |    1 +
 drivers/clk/samsung/clk-s3c2443.c |  463 +++++++++++++++++++++++++++++++++++++
 2 files changed, 464 insertions(+), 0 deletions(-)
 create mode 100644 drivers/clk/samsung/clk-s3c2443.c

diff --git a/drivers/clk/samsung/Makefile b/drivers/clk/samsung/Makefile
index b7c232e..7462ec5 100644
--- a/drivers/clk/samsung/Makefile
+++ b/drivers/clk/samsung/Makefile
@@ -6,3 +6,4 @@ obj-$(CONFIG_COMMON_CLK)	+= clk.o clk-pll.o
 obj-$(CONFIG_ARCH_EXYNOS4)	+= clk-exynos4.o
 obj-$(CONFIG_SOC_EXYNOS5250)	+= clk-exynos5250.o
 obj-$(CONFIG_SOC_EXYNOS5440)	+= clk-exynos5440.o
+obj-$(CONFIG_S3C2443_COMMON)	+= clk-s3c2443.o
diff --git a/drivers/clk/samsung/clk-s3c2443.c b/drivers/clk/samsung/clk-s3c2443.c
new file mode 100644
index 0000000..45681f1
--- /dev/null
+++ b/drivers/clk/samsung/clk-s3c2443.c
@@ -0,0 +1,463 @@
+/*
+ * Copyright (c) 2013 Heiko Stuebner <heiko@sntech.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Common Clock Framework support for S3C2416 SoCs.
+ */
+
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+#include <linux/clk-provider.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+
+#include <plat/cpu.h>
+#include "clk.h"
+#include "clk-pll.h"
+
+/* S3C2416 clock controller register offsets */
+#define MPLLCON		0x10
+#define EPLLCON		0x18
+#define EPLLCON_K	0x1C
+#define CLKSRC		0x20
+#define CLKDIV0		0x24
+#define CLKDIV1		0x28
+#define CLKDIV2		0x2C
+#define HCLKCON		0x30
+#define PCLKCON		0x34
+#define SCLKCON		0x38
+
+/* the soc types */
+enum supported_socs {
+	S3C2416,
+	S3C2443,
+	S3C2450,
+};
+
+/*
+ * Let each supported clock get a unique id. This id is used to lookup the clock
+ * for device tree based platforms. The clocks are categorized into four
+ * sections: core, sclk gate, bus interface gate and mux clocks.
+ *
+ * When adding a new clock to this list, it is advised to choose a clock
+ * category and add it to the end of that category. That is because the the
+ * device tree source file is referring to these ids and any change in the
+ * sequence number of existing clocks will require corresponding change in the
+ * device tree files. This limitation would go away when pre-processor support
+ * for dtc would be available.
+ */
+enum s3c2443_clks {
+	none,
+
+	/* core clocks */
+	xti, ext, ext_i2s, ext_uart, msysclk, esysclk, armdiv, armclk, hclk,
+
+	/* gate for special clocks (sclk) */
+	sclk_hsspi0 = 128, sclk_fimd, sclk_i2s0, sclk_i2s1, sclk_hsmmc1,
+	sclk_hsmmcext, sclk_cam, sclk_uart, sclk_usbh,
+
+	/* gate clocks */
+	hsmmc0 = 256, hsmmc1, nand, ssmc, usbh, usbd, lcd, dma0, dma1, dma2,
+	dma3, dma4, dma5, dma6, dma7, gpio, rtc, wdt, pwm, i2s0, i2s1, ac97,
+	pcm, adc, spi0, spi1, i2c0, i2c1, uart0, uart1, uart2, uart3, cfc,
+	sdi, cam, chipid,
+
+	/* mux clocks */
+	mux_hsspi0 = 384, mux_hsspi1, mux_hsmmc0, mux_hsmmc1,
+
+	nr_clks,
+};
+/*
+ * list of controller registers to be saved and restored during a
+ * suspend/resume cycle.
+ */
+static __initdata unsigned long s3c2443_clk_regs[] = {
+	MPLLCON,
+	EPLLCON,
+	EPLLCON_K,
+	CLKSRC,
+	CLKDIV0,
+	CLKDIV1,
+	CLKDIV2,
+	PCLKCON,
+	HCLKCON,
+	SCLKCON,
+};
+
+PNAME(epllref_p) = { "mpllref", "mpllref", "xti", "ext" };
+PNAME(esysclk_p) = { "epllref", "epll" };
+PNAME(msysclk_p) = { "mpllref, mdivclk", "mpll", "mpll" };
+PNAME(armclk_p) = { "armdiv" , "hclk" };
+PNAME(i2s0_p) = { "div_i2s0", "ext_i2s", "epllref", "epllref" };
+
+/* fixed rate clocks generated outside the soc */
+struct samsung_fixed_rate_clock s3c2443_common_frate_clks[] __initdata = {
+	FRATE(xti, "xti", NULL, CLK_IS_ROOT, 0),
+	FRATE(ext, "ext", NULL, CLK_IS_ROOT, 0),
+	FRATE(ext_i2s, "ext_i2s", NULL, CLK_IS_ROOT, 0),
+	FRATE(ext_uart, "ext_uart", NULL, CLK_IS_ROOT, 0),
+};
+
+/* mpllref is a direct descendant of clk_xtal by default, but it is not
+ * elided as the EPLL can be either sourced by the XTAL or EXTCLK and as
+ * such directly equating the two source clocks is impossible.
+ */
+struct samsung_fixed_factor_clock s3c2443_common_ffactor[] __initdata = {
+	FFACTOR(none, "mpllref", "xti", 1, 1, 0),
+};
+
+struct samsung_mux_clock s3c2443_common_muxes[] __initdata = {
+	MUX(none, "epllref", epllref_p, CLKSRC, 7, 2),
+	MUX(esysclk, "esysclk", esysclk_p, CLKSRC, 6, 1),
+	MUX_A(msysclk, "msysclk", msysclk_p, CLKSRC, 3, 2, "msysclk"),
+	MUX_A(armclk, "armclk", armclk_p, CLKDIV0, 13, 1, "armclk"),
+	MUX(none, "mux_i2s0", i2s0_p, CLKSRC, 14, 2),
+};
+
+static struct clk_div_table hclk_d[] = {
+	{ .val = 0, .div = 1 },
+	{ .val = 1, .div = 2 },
+	{ .val = 3, .div = 4 },
+	{ .div = 0 },
+};
+
+static struct clk_div_table mdivclk_d[] = {
+	{ .val = 0, .div = 1 },
+	{ .val = 1, .div = 3 },
+	{ .val = 2, .div = 5 },
+	{ .val = 3, .div = 7 },
+	{ .val = 4, .div = 9 },
+	{ .val = 5, .div = 11 },
+	{ .val = 6, .div = 13 },
+	{ .val = 7, .div = 15 },
+	{ .div = 0 },
+};
+
+struct samsung_div_clock s3c2443_common_dividers[] __initdata = {
+	DIV_T(none, "mdivclk", "mpllref", CLKDIV0, 6, 3, mdivclk_d),
+	DIV(none, "prediv", "msysclk", CLKDIV0, 4, 2),
+	DIV_T(hclk, "hclk", "prediv", CLKDIV0, 0, 2, hclk_d),
+	DIV(none, "pclk", "hclk", CLKDIV0, 2, 1),
+	DIV(none, "div_hsspi0_epll", "esysclk", CLKDIV1, 24, 2),
+	DIV(none, "div_fimd", "esysclk", CLKDIV1, 16, 8),
+	DIV(none, "div_i2s0", "esysclk", CLKDIV1, 12, 4),
+	DIV(none, "div_uart", "esysclk", CLKDIV1, 8, 4),
+	DIV(none, "div_hsmmc1", "esysclk", CLKDIV1, 6, 2),
+	DIV(none, "div_usbhost", "esysclk", CLKDIV1, 4, 2),
+};
+
+struct samsung_gate_clock s3c2443_common_gates[] __initdata = {
+	GATE(sclk_hsmmcext, "sclk_hsmmcext", "ext", SCLKCON, 13, 0, 0),
+	GATE(sclk_hsmmc1, "sclk_hsmmc1", "div_hsmmc1", SCLKCON, 12, 0, 0),
+	GATE(sclk_fimd, "sclk_fimd", "div_fimd", SCLKCON, 10, 0, 0),
+	GATE(sclk_i2s0, "sclk_i2s0", "mux_i2s0", SCLKCON, 9, 0, 0),
+	GATE(sclk_uart, "sclk_uart", "div_uart", SCLKCON, 8, 0, 0),
+	GATE(sclk_usbh, "sclk_usbhost", "div_usbhost", SCLKCON, 1, 0, 0),
+	GATE(ssmc, "ssmc", "hclk", HCLKCON, 18, CLK_IGNORE_UNUSED, 0),
+	GATE(hsmmc1, "hsmmc1", "hclk", HCLKCON, 16, 0, 0),
+	GATE(usbd, "usb-device", "hclk", HCLKCON, 12, 0, 0),
+	GATE(usbh, "usb-host", "hclk", HCLKCON, 11, 0, 0),
+	GATE(lcd, "lcd", "hclk", HCLKCON, 9, 0, 0),
+	GATE(dma5, "dma5", "hclk", HCLKCON, 5, CLK_IGNORE_UNUSED, 0),
+	GATE(dma4, "dma4", "hclk", HCLKCON, 4, CLK_IGNORE_UNUSED, 0),
+	GATE(dma3, "dma3", "hclk", HCLKCON, 3, CLK_IGNORE_UNUSED, 0),
+	GATE(dma2, "dma2", "hclk", HCLKCON, 2, CLK_IGNORE_UNUSED, 0),
+	GATE(dma1, "dma1", "hclk", HCLKCON, 1, CLK_IGNORE_UNUSED, 0),
+	GATE(dma0, "dma0", "hclk", HCLKCON, 0, CLK_IGNORE_UNUSED, 0),
+	GATE(gpio, "gpio", "pclk", PCLKCON, 13, CLK_IGNORE_UNUSED, 0),
+	GATE(rtc, "rtc", "pclk", PCLKCON, 12, 0, 0),
+	GATE(wdt, "wdt", "pclk", PCLKCON, 11, 0, 0),
+	GATE(pwm, "pwm", "pclk", PCLKCON, 10, 0, 0),
+	GATE(i2s0, "i2s0", "pclk", PCLKCON, 9, 0, 0),
+	GATE(ac97, "ac97", "pclk", PCLKCON, 8, 0, 0),
+	GATE(adc, "adc", "pclk", PCLKCON, 7, 0, 0),
+	GATE(spi0, "spi0", "pclk", PCLKCON, 6, 0, 0),
+	GATE(i2c0, "i2c0", "pclk", PCLKCON, 4, 0, 0),
+	GATE(uart3, "uart3", "pclk", PCLKCON, 3, 0, 0),
+	GATE(uart2, "uart2", "pclk", PCLKCON, 2, 0, 0),
+	GATE(uart1, "uart1", "pclk", PCLKCON, 1, 0, 0),
+	GATE(uart0, "uart0", "pclk", PCLKCON, 0, 0, 0),
+};
+
+struct samsung_clock_alias s3c2443_common_aliases[] __initdata = {
+	ALIAS(hclk, NULL, "hclk"),
+	/* the nand is supplied by the hclk without gating possibility */
+	ALIAS(hclk, NULL, "nand"),
+	ALIAS(uart0, "s3c2440-uart.0", "uart"),
+	ALIAS(uart1, "s3c2440-uart.1", "uart"),
+	ALIAS(uart2, "s3c2440-uart.2", "uart"),
+	ALIAS(uart3, "s3c2440-uart.3", "uart"),
+	ALIAS(ext_uart, NULL, "clk_uart_baud1"),
+	ALIAS(uart0, "s3c2440-uart.0", "clk_uart_baud2"),
+	ALIAS(uart1, "s3c2440-uart.1", "clk_uart_baud2"),
+	ALIAS(uart2, "s3c2440-uart.2", "clk_uart_baud2"),
+	ALIAS(uart3, "s3c2440-uart.3", "clk_uart_baud2"),
+	ALIAS(sclk_uart, NULL, "clk_uart_baud3"),
+	ALIAS(pwm, NULL, "timers"),
+	ALIAS(rtc, NULL, "rtc"),
+	ALIAS(wdt, NULL, "watchdog"),
+	ALIAS(adc, NULL, "adc"),
+	ALIAS(i2c0, "s3c2410-i2c.0", "i2c"),
+	ALIAS(usbd, NULL, "usb-device"),
+	ALIAS(usbh, NULL, "usb-host"),
+	ALIAS(sclk_usbh, NULL, "usb-bus-host"),
+	ALIAS(spi0, "s3c2443-spi.0", "spi"),
+	ALIAS(spi0, "s3c2443-spi.0", "spi_busclk0"),
+	ALIAS(hsmmc1, "s3c-sdhci.1", "hsmmc"),
+	ALIAS(hsmmc1, "s3c-sdhci.1", "mmc_busclk.0"),
+	ALIAS(i2s0, "samsung-i2s.0", "iis"),
+	ALIAS(sclk_i2s0, NULL, "i2s-if"),
+	ALIAS(lcd, NULL, "lcd"),
+	ALIAS(sclk_fimd, NULL, "sclk_fimd"),
+};
+
+/* S3C2416 specific clocks */
+
+PNAME(s3c2416_hsmmc0_p) = { "sclk_hsmmc0", "sclk_hsmmcext" };
+PNAME(s3c2416_hsmmc1_p) = { "sclk_hsmmc1", "sclk_hsmmcext" };
+PNAME(s3c2416_hsspi0_p) = { "hsspi0_epll", "hsspi0_mpll" };
+
+static struct clk_div_table armdiv_s3c2416_d[] = {
+	{ .val = 0, .div = 1 },
+	{ .val = 1, .div = 2 },
+	{ .val = 2, .div = 3 },
+	{ .val = 3, .div = 4 },
+	{ .val = 5, .div = 6 },
+	{ .val = 7, .div = 8 },
+	{ .div = 0 },
+};
+
+struct samsung_div_clock s3c2416_dividers[] __initdata = {
+	DIV_T(armdiv, "armdiv", "msysclk", CLKDIV0, 9, 3, armdiv_s3c2416_d),
+	DIV(none, "div_hsspi0_mpll", "msysclk", CLKDIV2, 0, 4),
+	DIV(none, "div_hsmmc0", "esysclk", CLKDIV2, 6, 2),
+};
+
+struct samsung_mux_clock s3c2416_muxes[] __initdata = {
+	MUX(mux_hsmmc0, "mux_hsmmc0", s3c2416_hsmmc0_p, CLKSRC, 16, 1),
+	MUX(mux_hsmmc1, "mux_hsmmc1", s3c2416_hsmmc1_p, CLKSRC, 17, 1),
+	MUX(mux_hsspi0, "mux_hsspi0", s3c2416_hsspi0_p, CLKSRC, 18, 1),
+};
+
+struct samsung_gate_clock s3c2416_gates[] __initdata = {
+	GATE(none, "hsspi0_mpll", "div_hsspi0_mpll", SCLKCON, 19, 0, 0),
+	GATE(none, "hsspi0_epll", "div_hsspi0_epll", SCLKCON, 14, 0, 0),
+	GATE(none, "sclk_hsmmc0", "div_hsmmc0", SCLKCON, 6, 0, 0),
+	GATE(hsmmc0, "hsmmc0", "hclk", HCLKCON, 15, 0, 0),
+	GATE(pcm, "pcm", "pclk", PCLKCON, 19, 0, 0),
+};
+
+struct samsung_clock_alias s3c2416_aliases[] __initdata = {
+	ALIAS(hsmmc0, "s3c-sdhci.0", "hsmmc"),
+	ALIAS(hsmmc0, "s3c-sdhci.0", "mmc_busclk.0"),
+	ALIAS(mux_hsmmc0, "s3c-sdhci.0", "mmc_busclk.2"),
+	ALIAS(mux_hsmmc1, "s3c-sdhci.1", "mmc_busclk.2"),
+	ALIAS(mux_hsspi0, "s3c2443-spi.0", "spi_busclk2"),
+	ALIAS(armdiv, NULL, "armdiv"),
+};
+
+/* S3C2443 specific clocks */
+
+static struct clk_div_table armdiv_s3c2443_d[] = {
+	{ .val = 0, .div = 1 },
+	{ .val = 8, .div = 2 },
+	{ .val = 2, .div = 3 },
+	{ .val = 9, .div = 4 },
+	{ .val = 10, .div = 6 },
+	{ .val = 11, .div = 8 },
+	{ .val = 13, .div = 12 },
+	{ .val = 15, .div = 16 },
+	{ .div = 0 },
+};
+
+struct samsung_div_clock s3c2443_dividers[] __initdata = {
+	DIV_T(armdiv, "armdiv", "msysclk", CLKDIV0, 9, 4, armdiv_s3c2443_d),
+	DIV(none, "div_cam", "esysclk", CLKDIV1, 26, 4),
+};
+
+struct samsung_gate_clock s3c2443_gates[] __initdata = {
+	GATE(sclk_hsspi0, "sclk_hsspi0", "div_hsspi0_epll", SCLKCON, 14, 0, 0),
+	GATE(sclk_cam, "sclk_cam", "div_cam", SCLKCON, 11, 0, 0),
+	GATE(cfc, "cfc", "hclk", HCLKCON, 17, CLK_IGNORE_UNUSED, 0),
+	GATE(cam, "cam", "hclk", HCLKCON, 8, 0, 0),
+	GATE(spi1, "spi1", "pclk", PCLKCON, 15, 0, 0),
+	GATE(sdi, "sdi", "pclk", PCLKCON, 5, 0, 0),
+};
+
+struct samsung_clock_alias s3c2443_aliases[] __initdata = {
+	ALIAS(spi1, "s3c2410-spi.0", "spi"),
+	ALIAS(sclk_hsspi0, "s3c2443-spi.0", "spi_busclk2"),
+	ALIAS(sclk_hsmmc1, "s3c-sdhci.1", "mmc_busclk.2"),
+	ALIAS(sclk_cam, NULL, "camif-upll"),
+	ALIAS(sdi, NULL, "sdi"),
+	ALIAS(cfc, NULL, "cfc"),
+	ALIAS(armdiv, NULL, "armdiv"),
+};
+
+/* S3C2450 specific clocks */
+
+PNAME(s3c2450_cam_p) = { "div_cam", "hclk" };
+PNAME(s3c2450_hsspi1_p) = { "hsspi1_epll", "hsspi1_mpll" };
+PNAME(i2s1_p) = { "div_i2s1", "ext_i2s", "epllref", "epllref" };
+
+struct samsung_div_clock s3c2450_dividers[] __initdata = {
+	DIV(none, "div_cam", "esysclk", CLKDIV1, 26, 4),
+	DIV(none, "div_hsspi1_epll", "esysclk", CLKDIV2, 24, 2),
+	DIV(none, "div_hsspi1_mpll", "msysclk", CLKDIV2, 16, 4),
+	DIV(none, "div_i2s1", "esysclk", CLKDIV2, 12, 4),
+};
+
+struct samsung_mux_clock s3c2450_muxes[] __initdata = {
+	MUX(none, "mux_cam", s3c2450_cam_p, CLKSRC, 20, 1),
+	MUX(mux_hsspi1, "mux_hsspi1", s3c2450_hsspi1_p, CLKSRC, 19, 1),
+	MUX(none, "mux_i2s1", i2s1_p, CLKSRC, 12, 2),
+};
+
+struct samsung_gate_clock s3c2450_gates[] __initdata = {
+	GATE(sclk_i2s1, "sclk_i2s1", "div_i2s1", SCLKCON, 5, 0, 0),
+	GATE(cfc, "cfc", "hclk", HCLKCON, 17, 0, 0),
+	GATE(cam, "cam", "hclk", HCLKCON, 8, 0, 0),
+	GATE(dma7, "dma7", "hclk", HCLKCON, 7, CLK_IGNORE_UNUSED, 0),
+	GATE(dma6, "dma6", "hclk", HCLKCON, 6, CLK_IGNORE_UNUSED, 0),
+	GATE(i2s1, "i2s1", "pclk", PCLKCON, 17, 0, 0),
+	GATE(i2c1, "i2c1", "pclk", PCLKCON, 16, 0, 0),
+	GATE(spi1, "spi1", "pclk", PCLKCON, 14, 0, 0),
+};
+
+struct samsung_clock_alias s3c2450_aliases[] __initdata = {
+	ALIAS(spi1, "s3c2443-spi.1", "spi"),
+	ALIAS(spi1, "s3c2443-spi.1", "spi_busclk0"),
+	ALIAS(mux_hsspi1, "s3c2443-spi.1", "spi_busclk2"),
+	ALIAS(i2c1, "s3c2410-i2c.1", "i2c"),
+};
+
+/*
+ * This function allows non-dt platforms to specify the clock speed of the
+ * xti and ext clocks.
+ */
+void __init s3c2443_clk_register_fixed_ext(unsigned long xti_f,
+				unsigned long ext_f, unsigned long i2s_f,
+				unsigned long uart_f)
+{
+	s3c2443_common_frate_clks[0].fixed_rate = xti_f;
+	s3c2443_common_frate_clks[1].fixed_rate = ext_f;
+	s3c2443_common_frate_clks[2].fixed_rate = i2s_f;
+	s3c2443_common_frate_clks[3].fixed_rate = uart_f;
+
+	samsung_clk_register_fixed_rate(s3c2443_common_frate_clks,
+			ARRAY_SIZE(s3c2443_common_frate_clks));
+}
+
+#ifdef CONFIG_OF
+static struct of_device_id s3c2443_clk_ids[] __initdata = {
+	{ .compatible = "samsung,s3c2416-clock",
+			.data = (void *)S3C2416, },
+	{ .compatible = "samsung,s3c2443-clock",
+			.data = (void *)S3C2443, },
+	{ .compatible = "samsung,s3c2450-clock",
+			.data = (void *)S3C2450, },
+	{ },
+};
+
+static __initdata struct of_device_id ext_clk_match[] = {
+	{ .compatible = "samsung,clock-xti", .data = (void *)0, },
+	{ .compatible = "samsung,clock-ext", .data = (void *)1, },
+	{ .compatible = "samsung,clock-ext-i2s", .data = (void *)2, },
+	{ .compatible = "samsung,clock-ext-uart", .data = (void *)3, },
+	{},
+};
+#endif
+
+void __init s3c2443_clk_init(struct device_node *np)
+{
+	void __iomem *reg_base;
+	struct clk *mpll, *epll;
+	u32 current_soc;
+
+	if (np) {
+		const struct of_device_id *match;
+		match = of_match_node(s3c2443_clk_ids, np);
+		current_soc = (u32)match->data;
+
+		reg_base = of_iomap(np, 0);
+		if (!reg_base)
+			panic("%s: failed to map registers\n", __func__);
+	} else {
+		reg_base = S3C24XX_VA_CLKPWR;
+
+		/* It's not possible to distinguish a s3c2450 from a s3c2416
+		 * programatically.
+		 */
+		if (soc_is_s3c2416())
+			current_soc = S3C2416;
+		else if (soc_is_s3c2443())
+			current_soc = S3C2443;
+		else
+			panic("%s: unable to determine soc\n", __func__);
+	}
+
+	samsung_clk_init(np, reg_base, nr_clks,
+		s3c2443_clk_regs, ARRAY_SIZE(s3c2443_clk_regs));
+
+	if (np)
+		samsung_clk_of_register_fixed_ext(s3c2443_common_frate_clks,
+			ARRAY_SIZE(s3c2443_common_frate_clks),
+			ext_clk_match);
+
+	samsung_clk_register_fixed_factor(s3c2443_common_ffactor,
+			ARRAY_SIZE(s3c2443_common_ffactor));
+
+	if (current_soc == S3C2416 || current_soc == S3C2450) {
+		mpll = samsung_clk_register_pll6552x("mpll", "mpllref",
+					reg_base + MPLLCON);
+		epll = samsung_clk_register_pll6553x("epll", "epllref",
+					reg_base + EPLLCON);
+	} else {
+		mpll = samsung_clk_register_pll3000x("mpll", "mpllref",
+					reg_base + MPLLCON);
+		epll = samsung_clk_register_pll2126x("epll", "epllref",
+					reg_base + EPLLCON);
+	}
+
+	samsung_clk_register_mux(s3c2443_common_muxes,
+			ARRAY_SIZE(s3c2443_common_muxes));
+	samsung_clk_register_div(s3c2443_common_dividers,
+			ARRAY_SIZE(s3c2443_common_dividers));
+	samsung_clk_register_gate(s3c2443_common_gates,
+		ARRAY_SIZE(s3c2443_common_gates));
+	samsung_clk_register_alias(s3c2443_common_aliases,
+		ARRAY_SIZE(s3c2443_common_aliases));
+
+	if (current_soc == S3C2416 || current_soc == S3C2450) {
+		samsung_clk_register_div(s3c2416_dividers,
+				ARRAY_SIZE(s3c2416_dividers));
+		samsung_clk_register_mux(s3c2416_muxes,
+				ARRAY_SIZE(s3c2416_muxes));
+		samsung_clk_register_gate(s3c2416_gates,
+				ARRAY_SIZE(s3c2416_gates));
+		samsung_clk_register_alias(s3c2416_aliases,
+				ARRAY_SIZE(s3c2416_aliases));
+	} else {
+		samsung_clk_register_div(s3c2443_dividers,
+				ARRAY_SIZE(s3c2443_dividers));
+		samsung_clk_register_gate(s3c2443_gates,
+				ARRAY_SIZE(s3c2443_gates));
+		samsung_clk_register_alias(s3c2443_aliases,
+				ARRAY_SIZE(s3c2443_aliases));
+	}
+
+	/* s3c2450 extends the s3c2416 clocks */
+	if (current_soc == S3C2450) {
+		samsung_clk_register_div(s3c2450_dividers,
+				ARRAY_SIZE(s3c2450_dividers));
+		samsung_clk_register_mux(s3c2450_muxes,
+				ARRAY_SIZE(s3c2450_muxes));
+		samsung_clk_register_gate(s3c2450_gates,
+				ARRAY_SIZE(s3c2450_gates));
+		samsung_clk_register_alias(s3c2450_aliases,
+				ARRAY_SIZE(s3c2450_aliases));
+	}
+}
-- 
1.7.2.3

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 5/7] DO_NOT_APPLY: add clock driver for Samsung pwm clocks
  2013-03-12  0:41 [PATCH 0/7] ARM: S3C24XX: Convert S3C2416 to common clock framework Heiko Stübner
                   ` (3 preceding siblings ...)
  2013-03-12  0:43 ` [PATCH 4/7] clk: samsung: add clock-driver for s3c2416, s3c2443 and s3c2450 Heiko Stübner
@ 2013-03-12  0:44 ` Heiko Stübner
  2013-03-12  0:45 ` [PATCH 6/7] ARM: SAMSUNG: use clk_prepare_enable in samsung-time Heiko Stübner
  2013-03-12  0:46 ` [PATCH 7/7] DO_NOT_APPLY: convert s3c2416 to use the common clock framework Heiko Stübner
  6 siblings, 0 replies; 14+ messages in thread
From: Heiko Stübner @ 2013-03-12  0:44 UTC (permalink / raw)
  To: Kukjin Kim
  Cc: mturquette, linux-arm-kernel, linux-samsung-soc, Thomas Abraham,
	Sylwester Nawrocki, t.figa

This ports the pwm-clock code from plat-samsung to the common clock
framework to make available the pwm clocks used by samsung-time and
the samsung pwm driver.

This is needed to enable the usage of the samsung-time clocksource
when using the common clock framework on s3c arches but the correct
solution will be in the upcoming time/pwm driver which will handle
the pwm clocks itself.

Signed-off-by: Heiko Stuebner <heiko@sntech.de>
---
 drivers/clk/samsung/Makefile  |    2 +-
 drivers/clk/samsung/clk-pwm.c |  554 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 555 insertions(+), 1 deletions(-)
 create mode 100644 drivers/clk/samsung/clk-pwm.c

diff --git a/drivers/clk/samsung/Makefile b/drivers/clk/samsung/Makefile
index 7462ec5..0f227c3 100644
--- a/drivers/clk/samsung/Makefile
+++ b/drivers/clk/samsung/Makefile
@@ -6,4 +6,4 @@ obj-$(CONFIG_COMMON_CLK)	+= clk.o clk-pll.o
 obj-$(CONFIG_ARCH_EXYNOS4)	+= clk-exynos4.o
 obj-$(CONFIG_SOC_EXYNOS5250)	+= clk-exynos5250.o
 obj-$(CONFIG_SOC_EXYNOS5440)	+= clk-exynos5440.o
-obj-$(CONFIG_S3C2443_COMMON)	+= clk-s3c2443.o
+obj-$(CONFIG_S3C2443_COMMON)	+= clk-s3c2443.o clk-pwm.o
diff --git a/drivers/clk/samsung/clk-pwm.c b/drivers/clk/samsung/clk-pwm.c
new file mode 100644
index 0000000..19142e8
--- /dev/null
+++ b/drivers/clk/samsung/clk-pwm.c
@@ -0,0 +1,554 @@
+/*
+ * Copyright (c) 2007 Simtec Electronics
+ * Copyright (c) 2007, 2008 Ben Dooks
+ *	Ben Dooks <ben-linux@fluff.org>
+ * Copyright (c) 2013 Heiko Stuebner <heiko@sntech.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License.
+ *
+ * Common Clock Framework support for Samsung pwm clocks
+*/
+
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+#include <linux/clk-provider.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/syscore_ops.h>
+#include <linux/io.h>
+
+#include <plat/cpu.h>
+#include <mach/map.h>
+
+#include "clk.h"
+
+/* Each of the timers 0 through 5 go through the following
+ * clock tree, with the inputs depending on the timers.
+ *
+ * pclk ---- [ prescaler 0 ] -+---> timer 0
+ *			      +---> timer 1
+ *
+ * pclk ---- [ prescaler 1 ] -+---> timer 2
+ *			      +---> timer 3
+ *			      \---> timer 4
+ *
+ * Which are fed into the timers as so:
+ *
+ * prescaled 0 ---- [ div 2,4,8,16 ] ---\
+ *				       [mux] -> timer 0
+ * tclk 0 ------------------------------/
+ *
+ * prescaled 0 ---- [ div 2,4,8,16 ] ---\
+ *				       [mux] -> timer 1
+ * tclk 0 ------------------------------/
+ *
+ *
+ * prescaled 1 ---- [ div 2,4,8,16 ] ---\
+ *				       [mux] -> timer 2
+ * tclk 1 ------------------------------/
+ *
+ * prescaled 1 ---- [ div 2,4,8,16 ] ---\
+ *				       [mux] -> timer 3
+ * tclk 1 ------------------------------/
+ *
+ * prescaled 1 ---- [ div 2,4,8, 16 ] --\
+ *				       [mux] -> timer 4
+ * tclk 1 ------------------------------/
+ *
+ * Since the mux and the divider are tied together in the
+ * same register space, it is impossible to set the parent
+ * and the rate at the same time. To avoid this, we add an
+ * intermediate 'prescaled-and-divided' clock to select
+ * as the parent for the timer input clock called tdiv.
+ *
+ * prescaled clk --> pwm-tdiv ---\
+ *                             [ mux ] --> timer X
+ * tclk -------------------------/
+*/
+
+enum pwm_clks {
+	none,
+
+	tclk0, tclk1, tdiv0, tdiv1, tdiv2, tdiv3, tdiv4,
+	tin0, tin1, tin2, tin3, tin4,
+
+	nr_clks,
+};
+
+/* the soc types */
+enum supported_socs {
+	S3C24XX,
+	S3C64XX, /* also S5PC100 */
+	S5P64XX,
+};
+
+/* clock controller register offsets */
+#define TCFG0	0
+#define TCFG1	0x4
+
+static DEFINE_SPINLOCK(lock);
+static int current_soc;
+static void __iomem *reg_base;
+static struct clk **clk_table;
+#ifdef CONFIG_OF
+static struct clk_onecell_data clk_data;
+#endif
+
+#ifdef CONFIG_PM_SLEEP
+static struct samsung_clk_reg_dump reg_dump[2] = {
+	{ .offset = TCFG0 },
+	{ .offset = TCFG1 },
+};
+
+static int samsung_clk_pwm_suspend(void)
+{
+	reg_dump[0].value = readl_relaxed(reg_base + reg_dump[0].offset);
+	reg_dump[1].value = readl_relaxed(reg_base + reg_dump[1].offset);
+	return 0;
+}
+
+static void samsung_clk_pwm_resume(void)
+{
+	writel_relaxed(reg_dump[0].value, reg_base + reg_dump[0].offset);
+	writel_relaxed(reg_dump[1].value, reg_base + reg_dump[1].offset);
+}
+
+static struct syscore_ops samsung_clk_pwm_syscore_ops = {
+	.suspend	= samsung_clk_pwm_suspend,
+	.resume		= samsung_clk_pwm_resume,
+};
+#endif /* CONFIG_PM_SLEEP */
+
+#define S3C2410_TCFG1_MUX_TCLK    (4 << 0)
+#define S3C64XX_TCFG1_MUX_TCLK    (5 << 0)
+
+/**
+ * pwm_cfg_src_is_tclk() - return whether the given mux config is a tclk
+ * @tcfg: The timer TCFG1 register bits shifted down to 0.
+ *
+ * Return true if the given configuration from TCFG1 is a TCLK instead
+ * any of the TDIV clocks.
+ */
+static inline int pwm_cfg_src_is_tclk(unsigned long tcfg)
+{
+	if (current_soc == S3C24XX)
+		return tcfg == S3C2410_TCFG1_MUX_TCLK;
+	else if (current_soc == S3C64XX)
+		return tcfg >= S3C64XX_TCFG1_MUX_TCLK;
+	else if (current_soc == S5P64XX)
+		return 0;
+	else
+		return tcfg == S3C64XX_TCFG1_MUX_TCLK;
+}
+
+struct clk_tdiv {
+	struct clk_divider	divider;
+	const struct clk_ops	*ops;
+	void __iomem		*reg;
+	unsigned int		divisor;
+};
+
+static inline struct clk_tdiv *to_clk_tdiv(struct clk_hw *hw)
+{
+	struct clk_divider *divider = container_of(hw, struct clk_divider, hw);
+
+	return container_of(divider, struct clk_tdiv, divider);
+}
+
+static unsigned long clk_tdiv_recalc_rate(struct clk_hw *hw,
+					 unsigned long parent_rate)
+{
+	struct clk_tdiv *tdiv = to_clk_tdiv(hw);
+	unsigned long tcfg1 = readl_relaxed(tdiv->reg);
+
+	tcfg1 >>= tdiv->divider.shift;
+	tcfg1 &= ((1 << (tdiv->divider.width)) - 1);
+
+	if (pwm_cfg_src_is_tclk(tcfg1))
+		return parent_rate / tdiv->divisor;
+	else
+		return tdiv->ops->recalc_rate(&tdiv->divider.hw, parent_rate);
+
+}
+
+static long clk_tdiv_round_rate(struct clk_hw *hw, unsigned long rate,
+			       unsigned long *parent_rate)
+{
+	struct clk_tdiv *tdiv = to_clk_tdiv(hw);
+
+	return tdiv->ops->round_rate(&tdiv->divider.hw, rate, parent_rate);
+}
+
+static int clk_tdiv_set_rate(struct clk_hw *hw, unsigned long rate,
+			    unsigned long parent_rate)
+{
+	struct clk_tdiv *tdiv = to_clk_tdiv(hw);
+	unsigned long tcfg1 = readl_relaxed(tdiv->reg);
+	unsigned long divisor;
+	int ret = 0;
+
+	tcfg1 >>= tdiv->divider.shift;
+	tcfg1 &= ((1 << (tdiv->divider.width)) - 1);
+
+	rate = tdiv->ops->round_rate(&tdiv->divider.hw, rate, &parent_rate);
+	divisor = parent_rate / rate;
+
+	if (divisor > 16)
+		return -EINVAL;
+
+	tdiv->divisor = divisor;
+
+	/* Update the current MUX settings if we are currently
+	 * selected as the clock source for this clock. */
+
+	if (!pwm_cfg_src_is_tclk(tcfg1))
+		ret = tdiv->ops->set_rate(&tdiv->divider.hw, rate, parent_rate);
+
+	return ret;
+}
+
+static struct clk_ops clk_tdiv_ops = {
+	.recalc_rate = clk_tdiv_recalc_rate,
+	.round_rate = clk_tdiv_round_rate,
+	.set_rate = clk_tdiv_set_rate,
+};
+
+static struct clk *samsung_clk_register_tdiv(const char *name,
+		const char *parent_name, unsigned long flags,
+		void __iomem *reg, u8 shift,
+		u8 clk_divider_flags, const struct clk_div_table *table)
+{
+	unsigned long tcfg1;
+	const struct clk_div_table *clkt;
+	struct clk_tdiv *tdiv;
+	struct clk *clk;
+	struct clk_init_data init;
+
+	tdiv = kzalloc(sizeof(struct clk_tdiv), GFP_KERNEL);
+	if (!tdiv)
+		return ERR_PTR(-ENOMEM);
+
+	init.name = name;
+	init.ops = &clk_tdiv_ops;
+	init.flags = flags;
+	init.parent_names = (parent_name ? &parent_name : NULL);
+	init.num_parents = (parent_name ? 1 : 0);
+
+	/* struct clk_divider assignments */
+	tdiv->divider.reg = reg;
+	tdiv->divider.shift = shift;
+	tdiv->divider.width = 4;
+	tdiv->divider.flags = clk_divider_flags;
+	tdiv->divider.lock = &lock;
+	tdiv->divider.hw.init = &init;
+	tdiv->divider.table = table;
+	tdiv->ops = &clk_divider_ops;
+
+	tcfg1 = readl_relaxed(reg);
+	tcfg1 >>= tdiv->divider.shift;
+	tcfg1 &= ((1 << (tdiv->divider.width)) - 1);
+
+	tdiv->reg = reg;
+
+	tdiv->divisor = 1;
+	for (clkt = table; clkt->div; clkt++)
+		if (clkt->val == tcfg1)
+			tdiv->divisor = clkt->div;
+
+	clk = clk_register(NULL, &tdiv->divider.hw);
+	if (IS_ERR(clk))
+		kfree(tdiv);
+
+	return clk;
+}
+
+struct clk_tin {
+	struct clk_hw	hw;
+	void __iomem	*reg;
+	u8		shift;
+	u8		width;
+	spinlock_t	*lock;
+};
+
+#define to_clk_tin(_hw) container_of(_hw, struct clk_tin, hw)
+
+static u8 clk_tin_get_parent(struct clk_hw *hw)
+{
+	struct clk_tin *tin = to_clk_tin(hw);
+	unsigned long tcfg1 = readl_relaxed(tin->reg);
+
+	tcfg1 >>= tin->shift;
+	tcfg1 &= ((1 << (tin->width)) - 1);
+
+	/* assume tclk is parent 0 and tdiv is parent 1 */
+	return pwm_cfg_src_is_tclk(tcfg1) ? 0 : 1;
+}
+
+static int clk_tin_set_parent(struct clk_hw *hw, u8 index)
+{
+	struct clk_tin *tin = to_clk_tin(hw);
+	struct clk *tdiv;
+	struct clk *prescaler;
+	unsigned long tcfg1;
+	unsigned long flags = 0;
+	unsigned long div;
+	int bits;
+
+	switch (index) {
+	case 0:
+		if (current_soc == S3C24XX)
+			bits = S3C2410_TCFG1_MUX_TCLK << tin->shift;
+		else if (current_soc == S5P64XX)
+			bits = 0;
+		else
+			bits = S3C64XX_TCFG1_MUX_TCLK << tin->shift;
+		break;
+	case 1:
+		tdiv = clk_get(NULL, hw->init->parent_names[0]);
+
+		prescaler = clk_get_parent(tdiv);
+		div = clk_get_rate(prescaler) / clk_get_rate(tdiv);
+
+		bits = (current_soc == S3C24XX) ? (ilog2(div) - 1) : ilog2(div);
+		bits &= ((1 << (tin->width)) - 1);
+		bits <<= tin->shift;
+
+		clk_put(tdiv);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	spin_lock_irqsave(tin->lock, flags);
+
+	tcfg1 = readl_relaxed(tin->reg);
+	tcfg1 &= ~(((1 << tin->width) - 1) << tin->shift);
+	tcfg1 |= bits;
+	writel_relaxed(tcfg1, tin->reg);
+
+	spin_unlock_irqrestore(tin->lock, flags);
+
+	return 0;
+}
+
+static const struct clk_ops clk_tin_ops = {
+	.get_parent = clk_tin_get_parent,
+	.set_parent = clk_tin_set_parent,
+};
+
+static struct clk *samsung_clk_register_tin(const char *name,
+		const char **parent_names, u8 num_parents,
+		void __iomem *reg, u8 shift, u8 width)
+{
+	struct clk_tin *tin;
+	struct clk *clk;
+	struct clk_init_data init;
+
+	/* allocate the mux */
+	tin = kzalloc(sizeof(struct clk_tin), GFP_KERNEL);
+	if (!tin) {
+		pr_err("%s: could not allocate tin clk\n", __func__);
+		return ERR_PTR(-ENOMEM);
+	}
+
+	init.name = name;
+	init.ops = &clk_tin_ops;
+	init.parent_names = parent_names;
+	init.num_parents = num_parents;
+
+	/* struct clk_mux assignments */
+	tin->reg = reg;
+	tin->shift = shift;
+	tin->width = width;
+	tin->lock = &lock;
+	tin->hw.init = &init;
+
+	clk = clk_register(NULL, &tin->hw);
+
+	if (IS_ERR(clk))
+		kfree(tin);
+
+	return clk;
+}
+
+
+PNAME(tin0_p) = { "pwm-tclk0", "pwm-tdiv0" };
+PNAME(tin1_p) = { "pwm-tclk0", "pwm-tdiv1" };
+PNAME(tin2_p) = { "pwm-tclk1", "pwm-tdiv2" };
+PNAME(tin3_p) = { "pwm-tclk1", "pwm-tdiv3" };
+PNAME(tin4_p) = { "pwm-tclk1", "pwm-tdiv4" };
+
+static struct clk_div_table tdiv_s3c24xx_d[] = {
+	{ .val = 0, .div = 2 },
+	{ .val = 1, .div = 4 },
+	{ .val = 2, .div = 8 },
+	{ .val = 3, .div = 16 },
+	{ .div = 0 },
+};
+struct samsung_div_clock pwm_s3c24xx_tdiv_dividers[] __initdata = {
+	DIV_T(tdiv0, "pwm-tdiv0", "pwm-scaler0", TCFG1, 0, 4, tdiv_s3c24xx_d),
+	DIV_T(tdiv1, "pwm-tdiv1", "pwm-scaler0", TCFG1, 4, 4, tdiv_s3c24xx_d),
+	DIV_T(tdiv2, "pwm-tdiv2", "pwm-scaler1", TCFG1, 8, 4, tdiv_s3c24xx_d),
+	DIV_T(tdiv3, "pwm-tdiv3", "pwm-scaler1", TCFG1, 12, 4, tdiv_s3c24xx_d),
+	DIV_T(tdiv4, "pwm-tdiv4", "pwm-scaler1", TCFG1, 16, 4, tdiv_s3c24xx_d),
+};
+
+static struct clk_div_table tdiv_s3c64xx_d[] = {
+	{ .val = 0, .div = 1 },
+	{ .val = 1, .div = 2 },
+	{ .val = 2, .div = 4 },
+	{ .val = 3, .div = 8 },
+	{ .val = 4, .div = 16 },
+	{ .div = 0 },
+};
+struct samsung_div_clock pwm_s3c64xx_tdiv_dividers[] __initdata = {
+	DIV_T(tdiv0, "pwm-tdiv0", "pwm-scaler0", TCFG1, 0, 4, tdiv_s3c64xx_d),
+	DIV_T(tdiv1, "pwm-tdiv1", "pwm-scaler0", TCFG1, 4, 4, tdiv_s3c64xx_d),
+	DIV_T(tdiv2, "pwm-tdiv2", "pwm-scaler1", TCFG1, 8, 4, tdiv_s3c64xx_d),
+	DIV_T(tdiv3, "pwm-tdiv3", "pwm-scaler1", TCFG1, 12, 4, tdiv_s3c64xx_d),
+	DIV_T(tdiv4, "pwm-tdiv4", "pwm-scaler1", TCFG1, 16, 4, tdiv_s3c64xx_d),
+};
+
+struct samsung_mux_clock pwm_tin[] __initdata = {
+	MUX(tin0, "pwm-tin0", tin0_p, TCFG1, 0, 4),
+	MUX(tin1, "pwm-tin1", tin1_p, TCFG1, 4, 4),
+	MUX(tin2, "pwm-tin2", tin2_p, TCFG1, 8, 4),
+	MUX(tin3, "pwm-tin3", tin3_p, TCFG1, 12, 4),
+	MUX(tin4, "pwm-tin4", tin4_p, TCFG1, 16, 4),
+};
+
+struct samsung_clock_alias pwm_aliases[] __initdata = {
+	ALIAS(tdiv0, "s3c24xx-pwm.0", "pwm-tdiv"),
+	ALIAS(tdiv1, "s3c24xx-pwm.1", "pwm-tdiv"),
+	ALIAS(tdiv2, "s3c24xx-pwm.2", "pwm-tdiv"),
+	ALIAS(tdiv3, "s3c24xx-pwm.3", "pwm-tdiv"),
+	ALIAS(tdiv4, "s3c24xx-pwm.4", "pwm-tdiv"),
+	ALIAS(tin0, "s3c24xx-pwm.0", "pwm-tin"),
+	ALIAS(tin1, "s3c24xx-pwm.1", "pwm-tin"),
+	ALIAS(tin2, "s3c24xx-pwm.2", "pwm-tin"),
+	ALIAS(tin3, "s3c24xx-pwm.3", "pwm-tin"),
+	ALIAS(tin4, "s3c24xx-pwm.4", "pwm-tin"),
+};
+
+
+#ifdef CONFIG_OF
+static struct of_device_id pwm_clk_ids[] __initdata = {
+	{ .compatible = "samsung,s3c24xx-clock-pwm",
+			.data = (void *)S3C24XX, },
+	{ .compatible = "samsung,s3c64xx-clock-pwm",
+			.data = (void *)S3C64XX, },
+	{ .compatible = "samsung,s5p64xx-clock-pwm",
+			.data = (void *)S5P64XX, },
+	{ },
+};
+#endif
+
+
+void __init samsung_pwm_clk_init(struct device_node *np)
+{
+	struct clk *clk;
+	struct samsung_div_clock *tdiv_list;
+	struct samsung_mux_clock *tin_list;
+	struct samsung_clock_alias *alias_list;
+	unsigned int idx;
+	int ret;
+
+	if (np) {
+		const struct of_device_id *match;
+		match = of_match_node(pwm_clk_ids, np);
+		current_soc = (u32)match->data;
+
+		reg_base = of_iomap(np, 0);
+		if (!reg_base)
+			panic("%s: failed to map registers\n", __func__);
+	} else {
+		reg_base = S3C_VA_TIMER;
+		if (soc_is_s3c24xx())
+			current_soc = S3C24XX;
+		else if (soc_is_s3c64xx() || soc_is_s5pc100())
+			current_soc = S3C64XX;
+		else if (soc_is_s5p6440() || soc_is_s5p6450())
+			current_soc = S5P64XX;
+		else
+			panic("%s: unable to determine soc\n", __func__);
+	}
+
+	clk_table = kzalloc(sizeof(struct clk *) * nr_clks, GFP_KERNEL);
+	if (!clk_table)
+		panic("could not allocate clock lookup table\n");
+
+#ifdef CONFIG_OF
+	clk_data.clks = clk_table;
+	clk_data.clk_num = nr_clks;
+	of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
+#endif
+
+#ifdef CONFIG_PM_SLEEP
+	register_syscore_ops(&samsung_clk_pwm_syscore_ops);
+#endif
+
+
+	clk = clk_register_fixed_rate(NULL, "pwm-tclk0", NULL, CLK_IS_ROOT, 0);
+	clk = clk_register_fixed_rate(NULL, "pwm-tclk1", NULL, CLK_IS_ROOT, 0);
+
+	clk = clk_register_divider(NULL, "pwm-scaler0", "pwm", 0, reg_base + TCFG0, 0, 8, 0, &lock);
+	clk = clk_register_divider(NULL, "pwm-scaler1", "pwm", 0, reg_base + TCFG0, 8, 8, 0, &lock);
+
+	tdiv_list = (current_soc == S3C24XX) ? pwm_s3c24xx_tdiv_dividers
+					      : pwm_s3c64xx_tdiv_dividers;
+
+	for (idx = 0; idx < 5; idx++, tdiv_list++) {
+		clk = samsung_clk_register_tdiv(tdiv_list->name, tdiv_list->parent_name,
+				tdiv_list->flags, reg_base + tdiv_list->offset,
+				tdiv_list->shift, tdiv_list->div_flags, tdiv_list->table);
+		if (IS_ERR(clk)) {
+			pr_err("%s: failed to register clock %s\n", __func__,
+				tdiv_list->name);
+			continue;
+		}
+
+		if (clk_table && tdiv_list->id)
+			clk_table[tdiv_list->id] = clk;
+	}
+
+	tin_list = pwm_tin;
+	for (idx = 0; idx < 5; idx++, tin_list++) {
+		clk = samsung_clk_register_tin(tin_list->name,
+				tin_list->parent_names, tin_list->num_parents,
+				reg_base + tin_list->offset, tin_list->shift,
+				tin_list->width);
+
+		if (IS_ERR(clk)) {
+			pr_err("%s: failed to register clock %s\n", __func__,
+				tin_list->name);
+			continue;
+		}
+
+		if (clk_table && tin_list->id)
+			clk_table[tin_list->id] = clk;
+	}
+
+	alias_list = pwm_aliases;
+	for (idx = 0; idx < ARRAY_SIZE(pwm_aliases); idx++, alias_list++) {
+		if (!alias_list->id) {
+			pr_err("%s: clock id missing for index %d\n", __func__,
+				idx);
+			continue;
+		}
+
+		clk = clk_table[alias_list->id];
+		if (!clk) {
+			pr_err("%s: failed to find clock %d\n", __func__,
+				alias_list->id);
+			continue;
+		}
+
+		ret = clk_register_clkdev(clk, alias_list->alias,
+					  alias_list->dev_name);
+		if (ret)
+			pr_err("%s: failed to register lookup %s\n",
+						__func__, alias_list->alias);
+	}
+}
-- 
1.7.2.3

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 6/7] ARM: SAMSUNG: use clk_prepare_enable in samsung-time
  2013-03-12  0:41 [PATCH 0/7] ARM: S3C24XX: Convert S3C2416 to common clock framework Heiko Stübner
                   ` (4 preceding siblings ...)
  2013-03-12  0:44 ` [PATCH 5/7] DO_NOT_APPLY: add clock driver for Samsung pwm clocks Heiko Stübner
@ 2013-03-12  0:45 ` Heiko Stübner
  2013-03-13 16:59   ` Pankaj Jangra
  2013-03-12  0:46 ` [PATCH 7/7] DO_NOT_APPLY: convert s3c2416 to use the common clock framework Heiko Stübner
  6 siblings, 1 reply; 14+ messages in thread
From: Heiko Stübner @ 2013-03-12  0:45 UTC (permalink / raw)
  To: Kukjin Kim
  Cc: mturquette, linux-arm-kernel, linux-samsung-soc, Thomas Abraham,
	Sylwester Nawrocki, t.figa

The common clock framework expects clocks to be prepared
before they are enabled.

Signed-off-by: Heiko Stuebner <heiko@sntech.de>
---
 arch/arm/plat-samsung/samsung-time.c |    6 +++---
 1 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/arch/arm/plat-samsung/samsung-time.c b/arch/arm/plat-samsung/samsung-time.c
index f899cbc..6ebb851 100644
--- a/arch/arm/plat-samsung/samsung-time.c
+++ b/arch/arm/plat-samsung/samsung-time.c
@@ -355,7 +355,7 @@ static void __init samsung_timer_resources(void)
 	if (IS_ERR(timerclk))
 		panic("failed to get timers clock for timer");
 
-	clk_enable(timerclk);
+	clk_prepare_enable(timerclk);
 
 	sprintf(devname, "s3c24xx-pwm.%lu", event_id);
 	s3c_device_timer[event_id].id = event_id;
@@ -369,7 +369,7 @@ static void __init samsung_timer_resources(void)
 	if (IS_ERR(tdiv_event))
 		panic("failed to get pwm-tdiv clock for event timer");
 
-	clk_enable(tin_event);
+	clk_prepare_enable(tin_event);
 
 	sprintf(devname, "s3c24xx-pwm.%lu", source_id);
 	s3c_device_timer[source_id].id = source_id;
@@ -383,7 +383,7 @@ static void __init samsung_timer_resources(void)
 	if (IS_ERR(tdiv_source))
 		panic("failed to get pwm-tdiv clock for source timer");
 
-	clk_enable(tin_source);
+	clk_prepare_enable(tin_source);
 }
 
 void __init samsung_timer_init(void)
-- 
1.7.2.3

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 7/7] DO_NOT_APPLY: convert s3c2416 to use the common clock framework
  2013-03-12  0:41 [PATCH 0/7] ARM: S3C24XX: Convert S3C2416 to common clock framework Heiko Stübner
                   ` (5 preceding siblings ...)
  2013-03-12  0:45 ` [PATCH 6/7] ARM: SAMSUNG: use clk_prepare_enable in samsung-time Heiko Stübner
@ 2013-03-12  0:46 ` Heiko Stübner
  6 siblings, 0 replies; 14+ messages in thread
From: Heiko Stübner @ 2013-03-12  0:46 UTC (permalink / raw)
  To: Kukjin Kim
  Cc: mturquette, linux-arm-kernel, linux-samsung-soc, Thomas Abraham,
	Sylwester Nawrocki, t.figa

Switch the s3c2416 and smdk2416 from using the Samsung clocks to
the common clock framework. This is not meant to be the final result,
as it uses the temporary pwm clocks and the clock init itself also
needs changes, especially as the _init_time function stolen from exynos
is currently board specific due to the xtal frequency which needs
to be set.

Signed-off-by: Heiko Stuebner <heiko@sntech.de>
---
 arch/arm/mach-s3c24xx/Kconfig          |    2 +-
 arch/arm/mach-s3c24xx/Makefile         |    2 +-
 arch/arm/mach-s3c24xx/clock-s3c2416.c  |  173 --------------------------------
 arch/arm/mach-s3c24xx/common-s3c2443.c |   10 ++
 arch/arm/mach-s3c24xx/common.h         |    9 ++
 arch/arm/mach-s3c24xx/mach-smdk2416.c  |    9 ++-
 6 files changed, 28 insertions(+), 177 deletions(-)
 delete mode 100644 arch/arm/mach-s3c24xx/clock-s3c2416.c

diff --git a/arch/arm/mach-s3c24xx/Kconfig b/arch/arm/mach-s3c24xx/Kconfig
index 0a8663c..351c198 100644
--- a/arch/arm/mach-s3c24xx/Kconfig
+++ b/arch/arm/mach-s3c24xx/Kconfig
@@ -54,7 +54,7 @@ config CPU_S3C2416
 	select S3C2416_PM if PM
 	select S3C2443_COMMON
 	select S3C2443_DMA if S3C24XX_DMA
-	select SAMSUNG_CLKSRC
+	select COMMON_CLK
 	select SAMSUNG_HRT
 	help
 	  Support for the S3C2416 SoC from the S3C24XX line
diff --git a/arch/arm/mach-s3c24xx/Makefile b/arch/arm/mach-s3c24xx/Makefile
index be6e4d0..820524e 100644
--- a/arch/arm/mach-s3c24xx/Makefile
+++ b/arch/arm/mach-s3c24xx/Makefile
@@ -28,7 +28,7 @@ obj-$(CONFIG_S3C2412_DMA)	+= dma-s3c2412.o
 obj-$(CONFIG_S3C2412_PM)	+= pm-s3c2412.o
 obj-$(CONFIG_S3C2412_PM_SLEEP)	+= sleep-s3c2412.o
 
-obj-$(CONFIG_CPU_S3C2416)	+= s3c2416.o clock-s3c2416.o
+obj-$(CONFIG_CPU_S3C2416)	+= s3c2416.o
 obj-$(CONFIG_S3C2416_PM)	+= pm-s3c2416.o
 
 obj-$(CONFIG_CPU_S3C2440)	+= s3c2440.o clock-s3c2440.o
diff --git a/arch/arm/mach-s3c24xx/clock-s3c2416.c b/arch/arm/mach-s3c24xx/clock-s3c2416.c
deleted file mode 100644
index 036056ce..0000000
--- a/arch/arm/mach-s3c24xx/clock-s3c2416.c
+++ /dev/null
@@ -1,173 +0,0 @@
-/* linux/arch/arm/mach-s3c2416/clock.c
- *
- * Copyright (c) 2010 Simtec Electronics
- * Copyright (c) 2010 Ben Dooks <ben-linux@fluff.org>
- *
- * S3C2416 Clock control support
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#include <linux/init.h>
-#include <linux/clk.h>
-
-#include <plat/clock.h>
-#include <plat/clock-clksrc.h>
-#include <plat/cpu.h>
-
-#include <plat/cpu-freq.h>
-#include <plat/pll.h>
-
-#include <asm/mach/map.h>
-
-#include <mach/regs-clock.h>
-#include <mach/regs-s3c2443-clock.h>
-
-/* armdiv
- *
- * this clock is sourced from msysclk and can have a number of
- * divider values applied to it to then be fed into armclk.
- * The real clock definition is done in s3c2443-clock.c,
- * only the armdiv divisor table must be defined here.
-*/
-
-static unsigned int armdiv[8] = {
-	[0] = 1,
-	[1] = 2,
-	[2] = 3,
-	[3] = 4,
-	[5] = 6,
-	[7] = 8,
-};
-
-static struct clksrc_clk hsspi_eplldiv = {
-	.clk = {
-		.name	= "hsspi-eplldiv",
-		.parent	= &clk_esysclk.clk,
-		.ctrlbit = (1 << 14),
-		.enable = s3c2443_clkcon_enable_s,
-	},
-	.reg_div = { .reg = S3C2443_CLKDIV1, .size = 2, .shift = 24 },
-};
-
-static struct clk *hsspi_sources[] = {
-	[0] = &hsspi_eplldiv.clk,
-	[1] = NULL, /* to fix */
-};
-
-static struct clksrc_clk hsspi_mux = {
-	.clk	= {
-		.name	= "hsspi-if",
-	},
-	.sources = &(struct clksrc_sources) {
-		.sources = hsspi_sources,
-		.nr_sources = ARRAY_SIZE(hsspi_sources),
-	},
-	.reg_src = { .reg = S3C2443_CLKSRC, .size = 1, .shift = 18 },
-};
-
-static struct clksrc_clk hsmmc_div[] = {
-	[0] = {
-		.clk = {
-			.name	= "hsmmc-div",
-			.devname	= "s3c-sdhci.0",
-			.parent	= &clk_esysclk.clk,
-		},
-		.reg_div = { .reg = S3C2416_CLKDIV2, .size = 2, .shift = 6 },
-	},
-	[1] = {
-		.clk = {
-			.name	= "hsmmc-div",
-			.devname	= "s3c-sdhci.1",
-			.parent	= &clk_esysclk.clk,
-		},
-		.reg_div = { .reg = S3C2443_CLKDIV1, .size = 2, .shift = 6 },
-	},
-};
-
-static struct clksrc_clk hsmmc_mux0 = {
-	.clk	= {
-		.name		= "hsmmc-if",
-		.devname	= "s3c-sdhci.0",
-		.ctrlbit	= (1 << 6),
-		.enable		= s3c2443_clkcon_enable_s,
-	},
-	.sources	= &(struct clksrc_sources) {
-		.nr_sources	= 2,
-		.sources	= (struct clk * []) {
-			[0]	= &hsmmc_div[0].clk,
-			[1]	= NULL, /* to fix */
-		},
-	},
-	.reg_src = { .reg = S3C2443_CLKSRC, .size = 1, .shift = 16 },
-};
-
-static struct clksrc_clk hsmmc_mux1 = {
-	.clk	= {
-		.name		= "hsmmc-if",
-		.devname	= "s3c-sdhci.1",
-		.ctrlbit	= (1 << 12),
-		.enable		= s3c2443_clkcon_enable_s,
-	},
-	.sources	= &(struct clksrc_sources) {
-		.nr_sources	= 2,
-		.sources	= (struct clk * []) {
-			[0]	= &hsmmc_div[1].clk,
-			[1]	= NULL, /* to fix */
-		},
-	},
-	.reg_src = { .reg = S3C2443_CLKSRC, .size = 1, .shift = 17 },
-};
-
-static struct clk hsmmc0_clk = {
-	.name		= "hsmmc",
-	.devname	= "s3c-sdhci.0",
-	.parent		= &clk_h,
-	.enable		= s3c2443_clkcon_enable_h,
-	.ctrlbit	= S3C2416_HCLKCON_HSMMC0,
-};
-
-static struct clksrc_clk *clksrcs[] __initdata = {
-	&hsspi_eplldiv,
-	&hsspi_mux,
-	&hsmmc_div[0],
-	&hsmmc_div[1],
-	&hsmmc_mux0,
-	&hsmmc_mux1,
-};
-
-static struct clk_lookup s3c2416_clk_lookup[] = {
-	CLKDEV_INIT("s3c-sdhci.0", "mmc_busclk.0", &hsmmc0_clk),
-	CLKDEV_INIT("s3c-sdhci.0", "mmc_busclk.2", &hsmmc_mux0.clk),
-	CLKDEV_INIT("s3c-sdhci.1", "mmc_busclk.2", &hsmmc_mux1.clk),
-	/* s3c2443-spi.0 is used on s3c2416 and s3c2450 as well */
-	CLKDEV_INIT("s3c2443-spi.0", "spi_busclk2", &hsspi_mux.clk),
-};
-
-void __init s3c2416_init_clocks(int xtal)
-{
-	u32 epllcon = __raw_readl(S3C2443_EPLLCON);
-	u32 epllcon1 = __raw_readl(S3C2443_EPLLCON+4);
-	int ptr;
-
-	/* s3c2416 EPLL compatible with s3c64xx */
-	clk_epll.rate = s3c_get_pll6553x(xtal, epllcon, epllcon1);
-
-	clk_epll.parent = &clk_epllref.clk;
-
-	s3c2443_common_init_clocks(xtal, s3c2416_get_pll,
-				   armdiv, ARRAY_SIZE(armdiv),
-				   S3C2416_CLKDIV0_ARMDIV_MASK);
-
-	for (ptr = 0; ptr < ARRAY_SIZE(clksrcs); ptr++)
-		s3c_register_clksrc(clksrcs[ptr], 1);
-
-	s3c24xx_register_clock(&hsmmc0_clk);
-	clkdev_add_table(s3c2416_clk_lookup, ARRAY_SIZE(s3c2416_clk_lookup));
-
-	s3c_pwmclk_init();
-
-}
diff --git a/arch/arm/mach-s3c24xx/common-s3c2443.c b/arch/arm/mach-s3c24xx/common-s3c2443.c
index b5bbeb7..d34b7ea 100644
--- a/arch/arm/mach-s3c24xx/common-s3c2443.c
+++ b/arch/arm/mach-s3c24xx/common-s3c2443.c
@@ -27,6 +27,7 @@
 
 #include <plat/cpu-freq.h>
 
+#include "common.h"
 
 #ifdef CONFIG_SAMSUNG_CLOCK
 static int s3c2443_gate(void __iomem *reg, struct clk *clk, int enable)
@@ -675,3 +676,12 @@ void __init s3c2443_common_init_clocks(int xtal, pll_fn get_mpll,
 	s3c2443_common_setup_clocks(get_mpll);
 }
 #endif
+
+#ifdef CONFIG_COMMON_CLK
+void __init s3c2416_init_clocks(int xtal)
+{
+	s3c2443_clk_init(NULL);
+	s3c2443_clk_register_fixed_ext(xtal, 0, 0, 0);
+	samsung_pwm_clk_init(NULL);
+}
+#endif
diff --git a/arch/arm/mach-s3c24xx/common.h b/arch/arm/mach-s3c24xx/common.h
index 307c371..9e59a3e 100644
--- a/arch/arm/mach-s3c24xx/common.h
+++ b/arch/arm/mach-s3c24xx/common.h
@@ -107,4 +107,13 @@ extern void s3c2443_init_irq(void);
 
 extern struct syscore_ops s3c24xx_irq_syscore_ops;
 
+#ifdef CONFIG_S3C2443_COMMON
+extern void s3c2443_clk_register_fixed_ext(unsigned long xti_f,
+				unsigned long ext_f, unsigned long i2s_f,
+				unsigned long uart_f);
+extern void __init s3c2443_clk_init(struct device_node *np);
+#endif
+
+extern void __init samsung_pwm_clk_init(struct device_node *np);
+
 #endif /* __ARCH_ARM_MACH_S3C24XX_COMMON_H */
diff --git a/arch/arm/mach-s3c24xx/mach-smdk2416.c b/arch/arm/mach-s3c24xx/mach-smdk2416.c
index cb46847..a0035f2 100644
--- a/arch/arm/mach-s3c24xx/mach-smdk2416.c
+++ b/arch/arm/mach-s3c24xx/mach-smdk2416.c
@@ -217,10 +217,15 @@ static struct platform_device *smdk2416_devices[] __initdata = {
 	&s3c_device_usb_hsudc,
 };
 
+static void __init smdk2416_init_time(void)
+{
+	s3c24xx_init_clocks(12000000);
+	samsung_timer_init();
+}
+
 static void __init smdk2416_map_io(void)
 {
 	s3c24xx_init_io(smdk2416_iodesc, ARRAY_SIZE(smdk2416_iodesc));
-	s3c24xx_init_clocks(12000000);
 	s3c24xx_init_uarts(smdk2416_uartcfgs, ARRAY_SIZE(smdk2416_uartcfgs));
 	samsung_set_timer_source(SAMSUNG_PWM3, SAMSUNG_PWM4);
 }
@@ -255,6 +260,6 @@ MACHINE_START(SMDK2416, "SMDK2416")
 	.init_irq	= s3c2416_init_irq,
 	.map_io		= smdk2416_map_io,
 	.init_machine	= smdk2416_machine_init,
-	.init_time	= samsung_timer_init,
+	.init_time	= smdk2416_init_time,
 	.restart	= s3c2416_restart,
 MACHINE_END
-- 
1.7.2.3

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* Re: [PATCH 1/7] clk: samsung: add plls used in s3c2416 and s3c2443
  2013-03-12  0:42 ` [PATCH 1/7] clk: samsung: add plls used in s3c2416 and s3c2443 Heiko Stübner
@ 2013-03-12 11:27   ` Russell King - ARM Linux
  2013-03-12 12:10   ` Sylwester Nawrocki
  1 sibling, 0 replies; 14+ messages in thread
From: Russell King - ARM Linux @ 2013-03-12 11:27 UTC (permalink / raw)
  To: Heiko Stübner
  Cc: Kukjin Kim, linux-samsung-soc, mturquette, t.figa,
	Thomas Abraham, Sylwester Nawrocki, linux-arm-kernel

On Tue, Mar 12, 2013 at 01:42:19AM +0100, Heiko Stübner wrote:
> +	clk = clk_register(NULL, &pll->hw);
> +	if (IS_ERR(clk)) {
> +		pr_err("%s: failed to register pll clock %s\n", __func__,
> +				name);
> +		kfree(pll);
> +	}
> +
> +	if (clk_register_clkdev(clk, name, NULL))
> +		pr_err("%s: failed to register lookup for %s", __func__, name);

The above looks wrong to me.

> +	clk = clk_register(NULL, &pll->hw);
> +	if (IS_ERR(clk)) {
> +		pr_err("%s: failed to register pll clock %s\n", __func__,
> +				name);
> +		kfree(pll);
> +	}
> +
> +	if (clk_register_clkdev(clk, name, NULL))
> +		pr_err("%s: failed to register lookup for %s", __func__, name);

Same pattern here.

> +	clk = clk_register(NULL, &pll->hw);
> +	if (IS_ERR(clk)) {
> +		pr_err("%s: failed to register pll clock %s\n", __func__,
> +				name);
> +		kfree(pll);
> +	}
> +
> +	if (clk_register_clkdev(clk, name, NULL))
> +		pr_err("%s: failed to register lookup for %s", __func__, name);

And again here.

> +	clk = clk_register(NULL, &pll->hw);
> +	if (IS_ERR(clk)) {
> +		pr_err("%s: failed to register pll clock %s\n", __func__,
> +				name);
> +		kfree(pll);
> +	}
> +
> +	if (clk_register_clkdev(clk, name, NULL))
> +		pr_err("%s: failed to register lookup for %s", __func__, name);

And again here... do you notice something about these?  They're all the
same.  Do you know what we do when we have the same thing repeated and
only the data is different?

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 1/7] clk: samsung: add plls used in s3c2416 and s3c2443
  2013-03-12  0:42 ` [PATCH 1/7] clk: samsung: add plls used in s3c2416 and s3c2443 Heiko Stübner
  2013-03-12 11:27   ` Russell King - ARM Linux
@ 2013-03-12 12:10   ` Sylwester Nawrocki
  2013-03-12 12:21     ` Heiko Stübner
  1 sibling, 1 reply; 14+ messages in thread
From: Sylwester Nawrocki @ 2013-03-12 12:10 UTC (permalink / raw)
  To: Heiko Stübner
  Cc: Kukjin Kim, mturquette, linux-arm-kernel, linux-samsung-soc,
	Thomas Abraham, Sylwester Nawrocki, t.figa

Hi,

On 03/12/2013 01:42 AM, Heiko Stübner wrote:
> This adds support for pll2126x, pll3000x, pll6552x and pll6553x.
> 
> Signed-off-by: Heiko Stuebner <heiko@sntech.de>
> ---
>  drivers/clk/samsung/clk-pll.c |  376 +++++++++++++++++++++++++++++++++++++++++
>  drivers/clk/samsung/clk-pll.h |    8 +
>  2 files changed, 384 insertions(+), 0 deletions(-)
> 
> diff --git a/drivers/clk/samsung/clk-pll.c b/drivers/clk/samsung/clk-pll.c
> index 4b24511..b772f9e 100644
> --- a/drivers/clk/samsung/clk-pll.c
> +++ b/drivers/clk/samsung/clk-pll.c
> @@ -400,6 +400,97 @@ struct clk * __init samsung_clk_register_pll46xx(const char *name,
...
> +struct samsung_clk_pll2126x {
> +	struct clk_hw		hw;
> +	const void __iomem	*con_reg;
> +};
> +
> +#define to_clk_pll2126x(_hw) container_of(_hw, struct samsung_clk_pll2126x, hw)
> +
> +static unsigned long samsung_pll2126x_recalc_rate(struct clk_hw *hw,
> +				unsigned long parent_rate)
> +{
> +	struct samsung_clk_pll2126x *pll = to_clk_pll2126x(hw);
> +	u32 pll_con, mdiv, pdiv, sdiv;
> +	u64 fvco = parent_rate;
> +
> +	pll_con = __raw_readl(pll->con_reg);
> +	mdiv = (pll_con >> PLL2126X_MDIV_SHIFT) & PLL2126X_MDIV_MASK;
> +	pdiv = (pll_con >> PLL2126X_PDIV_SHIFT) & PLL2126X_PDIV_MASK;
> +	sdiv = (pll_con >> PLL2126X_SDIV_SHIFT) & PLL2126X_SDIV_MASK;
> +
> +	fvco *= (mdiv + 8);
> +	do_div(fvco, (pdiv + 2) << sdiv);
> +
> +	return (unsigned long)fvco;
> +}
> +
> +/* todo: implement pll2126x clock round rate operation */
> +static long samsung_pll2126x_round_rate(struct clk_hw *hw,
> +				unsigned long drate, unsigned long *prate)
> +{
> +	return -ENOTSUPP;
> +}

If you look at __clk_round_rate() in drivers/clk/clk.c it calls
clk->ops->round_rate() recursively on the parent clock if
CLK_SET_RATE_PARENT flag is set. But if the clock provides round_rate
operation __clk_round_rate() will use it and will cast -ENOTSUPP
you return above to unsigned long. Unless you want to loose some hair
later and waste time on debugging I suggest to either remove all these
callbacks that return -ENOSUPP or implement them properly right away.

I'm just wondering why __clk_round_rate() return value type is unsigned long
despite the struct clk_ops round_rate return long, which might indicate
the negative values round_rate might callback are properly handled by the
clk core code.

Somewhat similar situation is with clk_mux_get_parent() in clk-mux.c
which can return -EINVAL which is then casted to u8.

I still have sending a patch for clk_mux_get_parent() on my todo list.
I guess we could just put a WARN_ON() there and return 0.

> +/* todo: implement pll2126x clock set rate */
> +static int samsung_pll2126x_set_rate(struct clk_hw *hw, unsigned long drate,
> +				unsigned long prate)
> +{
> +	return -ENOTSUPP;
> +}
> +
> +static const struct clk_ops samsung_pll2126x_clk_ops = {
> +	.recalc_rate = samsung_pll2126x_recalc_rate,
> +	.round_rate = samsung_pll2126x_round_rate,
> +	.set_rate = samsung_pll2126x_set_rate,
> +};

--

Thanks,
Sylwester

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 1/7] clk: samsung: add plls used in s3c2416 and s3c2443
  2013-03-12 12:10   ` Sylwester Nawrocki
@ 2013-03-12 12:21     ` Heiko Stübner
  2013-03-12 13:17       ` Sylwester Nawrocki
  0 siblings, 1 reply; 14+ messages in thread
From: Heiko Stübner @ 2013-03-12 12:21 UTC (permalink / raw)
  To: Sylwester Nawrocki
  Cc: Kukjin Kim, mturquette, linux-arm-kernel, linux-samsung-soc,
	Thomas Abraham, Sylwester Nawrocki, t.figa

Am Dienstag, 12. März 2013, 13:10:42 schrieb Sylwester Nawrocki:
> Hi,
> 
> On 03/12/2013 01:42 AM, Heiko Stübner wrote:
> > This adds support for pll2126x, pll3000x, pll6552x and pll6553x.
> > 
> > Signed-off-by: Heiko Stuebner <heiko@sntech.de>
> > ---
> > 
> >  drivers/clk/samsung/clk-pll.c |  376
> >  +++++++++++++++++++++++++++++++++++++++++ drivers/clk/samsung/clk-pll.h
> >  |    8 +
> >  2 files changed, 384 insertions(+), 0 deletions(-)
> > 
> > diff --git a/drivers/clk/samsung/clk-pll.c
> > b/drivers/clk/samsung/clk-pll.c index 4b24511..b772f9e 100644
> > --- a/drivers/clk/samsung/clk-pll.c
> > +++ b/drivers/clk/samsung/clk-pll.c
> > @@ -400,6 +400,97 @@ struct clk * __init
> > samsung_clk_register_pll46xx(const char *name,
> 
> ...
> 
> > +struct samsung_clk_pll2126x {
> > +	struct clk_hw		hw;
> > +	const void __iomem	*con_reg;
> > +};
> > +
> > +#define to_clk_pll2126x(_hw) container_of(_hw, struct
> > samsung_clk_pll2126x, hw) +
> > +static unsigned long samsung_pll2126x_recalc_rate(struct clk_hw *hw,
> > +				unsigned long parent_rate)
> > +{
> > +	struct samsung_clk_pll2126x *pll = to_clk_pll2126x(hw);
> > +	u32 pll_con, mdiv, pdiv, sdiv;
> > +	u64 fvco = parent_rate;
> > +
> > +	pll_con = __raw_readl(pll->con_reg);
> > +	mdiv = (pll_con >> PLL2126X_MDIV_SHIFT) & PLL2126X_MDIV_MASK;
> > +	pdiv = (pll_con >> PLL2126X_PDIV_SHIFT) & PLL2126X_PDIV_MASK;
> > +	sdiv = (pll_con >> PLL2126X_SDIV_SHIFT) & PLL2126X_SDIV_MASK;
> > +
> > +	fvco *= (mdiv + 8);
> > +	do_div(fvco, (pdiv + 2) << sdiv);
> > +
> > +	return (unsigned long)fvco;
> > +}
> > +
> > +/* todo: implement pll2126x clock round rate operation */
> > +static long samsung_pll2126x_round_rate(struct clk_hw *hw,
> > +				unsigned long drate, unsigned long *prate)
> > +{
> > +	return -ENOTSUPP;
> > +}
> 
> If you look at __clk_round_rate() in drivers/clk/clk.c it calls
> clk->ops->round_rate() recursively on the parent clock if
> CLK_SET_RATE_PARENT flag is set. But if the clock provides round_rate
> operation __clk_round_rate() will use it and will cast -ENOTSUPP
> you return above to unsigned long. Unless you want to loose some hair
> later and waste time on debugging I suggest to either remove all these
> callbacks that return -ENOSUPP or implement them properly right away.

Thanks for the hint ... this is what I rightfully get for mindlessly copying 
from the other plls in the file;-) .

What about the other plls in the pll-file, they should be affected in the same 
way, right?


> I'm just wondering why __clk_round_rate() return value type is unsigned
> long despite the struct clk_ops round_rate return long, which might
> indicate the negative values round_rate might callback are properly
> handled by the clk core code.
> 
> Somewhat similar situation is with clk_mux_get_parent() in clk-mux.c
> which can return -EINVAL which is then casted to u8.
> 
> I still have sending a patch for clk_mux_get_parent() on my todo list.
> I guess we could just put a WARN_ON() there and return 0.
> 
> > +/* todo: implement pll2126x clock set rate */
> > +static int samsung_pll2126x_set_rate(struct clk_hw *hw, unsigned long
> > drate, +				unsigned long prate)
> > +{
> > +	return -ENOTSUPP;
> > +}
> > +
> > +static const struct clk_ops samsung_pll2126x_clk_ops = {
> > +	.recalc_rate = samsung_pll2126x_recalc_rate,
> > +	.round_rate = samsung_pll2126x_round_rate,
> > +	.set_rate = samsung_pll2126x_set_rate,
> > +};
> 
> --
> 
> Thanks,
> Sylwester

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 1/7] clk: samsung: add plls used in s3c2416 and s3c2443
  2013-03-12 12:21     ` Heiko Stübner
@ 2013-03-12 13:17       ` Sylwester Nawrocki
  0 siblings, 0 replies; 14+ messages in thread
From: Sylwester Nawrocki @ 2013-03-12 13:17 UTC (permalink / raw)
  To: Heiko Stübner
  Cc: Kukjin Kim, mturquette, linux-arm-kernel, linux-samsung-soc,
	Thomas Abraham, Sylwester Nawrocki, t.figa

On 03/12/2013 01:21 PM, Heiko Stübner wrote:
> Thanks for the hint ... this is what I rightfully get for mindlessly copying 
> from the other plls in the file;-) .

:)

> What about the other plls in the pll-file, they should be affected in the same 
> way, right?

Yes, they're of course also affected. Otherwise we wouldn't know about
the problem;) We are going to submit all fixes we have for the clk driver
shortly. But those are mostly for the Exynos clocks definitions.

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 6/7] ARM: SAMSUNG: use clk_prepare_enable in samsung-time
  2013-03-12  0:45 ` [PATCH 6/7] ARM: SAMSUNG: use clk_prepare_enable in samsung-time Heiko Stübner
@ 2013-03-13 16:59   ` Pankaj Jangra
  2013-03-13 23:16     ` Heiko Stübner
  0 siblings, 1 reply; 14+ messages in thread
From: Pankaj Jangra @ 2013-03-13 16:59 UTC (permalink / raw)
  To: Heiko Stübner
  Cc: linux-samsung-soc, mturquette, t.figa, Kukjin Kim,
	Thomas Abraham, Sylwester Nawrocki, linux-arm-kernel

Hi,

On Tue, Mar 12, 2013 at 6:15 AM, Heiko Stübner <heiko@sntech.de> wrote:
> The common clock framework expects clocks to be prepared
> before they are enabled.
>
> Signed-off-by: Heiko Stuebner <heiko@sntech.de>
> ---
>  arch/arm/plat-samsung/samsung-time.c |    6 +++---
>  1 files changed, 3 insertions(+), 3 deletions(-)
>
> diff --git a/arch/arm/plat-samsung/samsung-time.c b/arch/arm/plat-samsung/samsung-time.c
> index f899cbc..6ebb851 100644
> --- a/arch/arm/plat-samsung/samsung-time.c
> +++ b/arch/arm/plat-samsung/samsung-time.c
> @@ -355,7 +355,7 @@ static void __init samsung_timer_resources(void)
>         if (IS_ERR(timerclk))
>                 panic("failed to get timers clock for timer");
>
Also how about calling the clk_prepare_enable() only if the clk_get()
call is a sucess? Though clk framework will take care of it. Just
thinking even to avoid that call if clk_get() fails since you are
modifying the code.

> -       clk_enable(timerclk);
> +       clk_prepare_enable(timerclk);
>
>         sprintf(devname, "s3c24xx-pwm.%lu", event_id);
>         s3c_device_timer[event_id].id = event_id;
> @@ -369,7 +369,7 @@ static void __init samsung_timer_resources(void)
>         if (IS_ERR(tdiv_event))
>                 panic("failed to get pwm-tdiv clock for event timer");
>
Same here...
> -       clk_enable(tin_event);
> +       clk_prepare_enable(tin_event);
>
>         sprintf(devname, "s3c24xx-pwm.%lu", source_id);

Regards,
Pankaj Jangra

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 6/7] ARM: SAMSUNG: use clk_prepare_enable in samsung-time
  2013-03-13 16:59   ` Pankaj Jangra
@ 2013-03-13 23:16     ` Heiko Stübner
  0 siblings, 0 replies; 14+ messages in thread
From: Heiko Stübner @ 2013-03-13 23:16 UTC (permalink / raw)
  To: Pankaj Jangra
  Cc: Kukjin Kim, mturquette, linux-arm-kernel, linux-samsung-soc,
	Thomas Abraham, Sylwester Nawrocki, t.figa

Hi,

Am Mittwoch, 13. März 2013, 17:59:04 schrieb Pankaj Jangra:
> Hi,
> 
> On Tue, Mar 12, 2013 at 6:15 AM, Heiko Stübner <heiko@sntech.de> wrote:
> > The common clock framework expects clocks to be prepared
> > before they are enabled.
> > 
> > Signed-off-by: Heiko Stuebner <heiko@sntech.de>
> > ---
> > 
> >  arch/arm/plat-samsung/samsung-time.c |    6 +++---
> >  1 files changed, 3 insertions(+), 3 deletions(-)
> > 
> > diff --git a/arch/arm/plat-samsung/samsung-time.c
> > b/arch/arm/plat-samsung/samsung-time.c index f899cbc..6ebb851 100644
> > --- a/arch/arm/plat-samsung/samsung-time.c
> > +++ b/arch/arm/plat-samsung/samsung-time.c
> > @@ -355,7 +355,7 @@ static void __init samsung_timer_resources(void)
> > 
> >         if (IS_ERR(timerclk))
> >         
> >                 panic("failed to get timers clock for timer");
> 
> Also how about calling the clk_prepare_enable() only if the clk_get()
> call is a sucess? Though clk framework will take care of it. Just
> thinking even to avoid that call if clk_get() fails since you are
> modifying the code.

I remember there was a discussion about panic vc error handling when this was 
introduced but I don't remember the specifics, but it seems they agreed to do 
it this way with letting the kernel panic when the clock is missing.


Also the current plan seems to replace the clocksource and pwm drivers that 
occupy the same register space with a driver handling both, making the pwm 
specific clocks obsolete and only the timers clock will remain. So this was 
merely meant as a fixup when using the clock changes with the current 
clocksource code.


> > -       clk_enable(timerclk);
> > +       clk_prepare_enable(timerclk);
> > 
> >         sprintf(devname, "s3c24xx-pwm.%lu", event_id);
> >         s3c_device_timer[event_id].id = event_id;
> > 
> > @@ -369,7 +369,7 @@ static void __init samsung_timer_resources(void)
> > 
> >         if (IS_ERR(tdiv_event))
> >         
> >                 panic("failed to get pwm-tdiv clock for event timer");
> 
> Same here...
> 
> > -       clk_enable(tin_event);
> > +       clk_prepare_enable(tin_event);
> > 
> >         sprintf(devname, "s3c24xx-pwm.%lu", source_id);
> 
> Regards,
> Pankaj Jangra

^ permalink raw reply	[flat|nested] 14+ messages in thread

end of thread, other threads:[~2013-03-13 23:16 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-03-12  0:41 [PATCH 0/7] ARM: S3C24XX: Convert S3C2416 to common clock framework Heiko Stübner
2013-03-12  0:42 ` [PATCH 1/7] clk: samsung: add plls used in s3c2416 and s3c2443 Heiko Stübner
2013-03-12 11:27   ` Russell King - ARM Linux
2013-03-12 12:10   ` Sylwester Nawrocki
2013-03-12 12:21     ` Heiko Stübner
2013-03-12 13:17       ` Sylwester Nawrocki
2013-03-12  0:42 ` [PATCH 2/7] ARM: S3C24XX: add soc_is_s3c2416 and soc_is_s3c2443 Heiko Stübner
2013-03-12  0:43 ` [PATCH 3/7] ARM: S3C24XX: enable legacy clock code only when SAMSUNG_CLOCK selected Heiko Stübner
2013-03-12  0:43 ` [PATCH 4/7] clk: samsung: add clock-driver for s3c2416, s3c2443 and s3c2450 Heiko Stübner
2013-03-12  0:44 ` [PATCH 5/7] DO_NOT_APPLY: add clock driver for Samsung pwm clocks Heiko Stübner
2013-03-12  0:45 ` [PATCH 6/7] ARM: SAMSUNG: use clk_prepare_enable in samsung-time Heiko Stübner
2013-03-13 16:59   ` Pankaj Jangra
2013-03-13 23:16     ` Heiko Stübner
2013-03-12  0:46 ` [PATCH 7/7] DO_NOT_APPLY: convert s3c2416 to use the common clock framework Heiko Stübner

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).