Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5cfe9614 authored by Mike Turquette's avatar Mike Turquette
Browse files

Merge branch 'clk-next-s3c64xx' into clk-next

parents 6f9a4894 06dda9d7
Loading
Loading
Loading
Loading
+77 −0
Original line number Diff line number Diff line
* Samsung S3C64xx Clock Controller

The S3C64xx clock controller generates and supplies clock to various controllers
within the SoC. The clock binding described here is applicable to all SoCs in
the S3C64xx family.

Required Properties:

- compatible: should be one of the following.
  - "samsung,s3c6400-clock" - controller compatible with S3C6400 SoC.
  - "samsung,s3c6410-clock" - controller compatible with S3C6410 SoC.

- reg: physical base address of the controller and length of memory mapped
  region.

- #clock-cells: should be 1.

Each clock is assigned an identifier and client nodes can use this identifier
to specify the clock which they consume. Some of the clocks are available only
on a particular S3C64xx SoC and this is specified where applicable.

All available clocks are defined as preprocessor macros in
dt-bindings/clock/samsung,s3c64xx-clock.h header and can be used in device
tree sources.

External clocks:

There are several clocks that are generated outside the SoC. It is expected
that they are defined using standard clock bindings with following
clock-output-names:
 - "fin_pll" - PLL input clock (xtal/extclk) - required,
 - "xusbxti" - USB xtal - required,
 - "iiscdclk0" - I2S0 codec clock - optional,
 - "iiscdclk1" - I2S1 codec clock - optional,
 - "iiscdclk2" - I2S2 codec clock - optional,
 - "pcmcdclk0" - PCM0 codec clock - optional,
 - "pcmcdclk1" - PCM1 codec clock - optional, only S3C6410.

Example: Clock controller node:

	clock: clock-controller@7e00f000 {
		compatible = "samsung,s3c6410-clock";
		reg = <0x7e00f000 0x1000>;
		#clock-cells = <1>;
	};

Example: Required external clocks:

	fin_pll: clock-fin-pll {
		compatible = "fixed-clock";
		clock-output-names = "fin_pll";
		clock-frequency = <12000000>;
		#clock-cells = <0>;
	};

	xusbxti: clock-xusbxti {
		compatible = "fixed-clock";
		clock-output-names = "xusbxti";
		clock-frequency = <48000000>;
		#clock-cells = <0>;
	};

Example: UART controller node that consumes the clock generated by the clock
  controller (refer to the standard clock bindings for information about
  "clocks" and "clock-names" properties):

		uart0: serial@7f005000 {
			compatible = "samsung,s3c6400-uart";
			reg = <0x7f005000 0x100>;
			interrupt-parent = <&vic1>;
			interrupts = <5>;
			clock-names = "uart", "clk_uart_baud2",
					"clk_uart_baud3";
			clocks = <&clock PCLK_UART0>, <&clocks PCLK_UART0>,
					<&clock SCLK_UART>;
			status = "disabled";
		};
+9 −1
Original line number Diff line number Diff line
@@ -107,6 +107,11 @@ const struct clk_ops clk_mux_ops = {
};
EXPORT_SYMBOL_GPL(clk_mux_ops);

const struct clk_ops clk_mux_ro_ops = {
	.get_parent = clk_mux_get_parent,
};
EXPORT_SYMBOL_GPL(clk_mux_ro_ops);

struct clk *clk_register_mux_table(struct device *dev, const char *name,
		const char **parent_names, u8 num_parents, unsigned long flags,
		void __iomem *reg, u8 shift, u32 mask,
@@ -133,6 +138,9 @@ struct clk *clk_register_mux_table(struct device *dev, const char *name,
	}

	init.name = name;
	if (clk_mux_flags & CLK_MUX_READ_ONLY)
		init.ops = &clk_mux_ro_ops;
	else
		init.ops = &clk_mux_ops;
	init.flags = flags | CLK_IS_BASIC;
	init.parent_names = parent_names;
+3 −0
Original line number Diff line number Diff line
@@ -8,3 +8,6 @@ obj-$(CONFIG_SOC_EXYNOS5250) += clk-exynos5250.o
obj-$(CONFIG_SOC_EXYNOS5420)	+= clk-exynos5420.o
obj-$(CONFIG_SOC_EXYNOS5440)	+= clk-exynos5440.o
obj-$(CONFIG_ARCH_EXYNOS)	+= clk-exynos-audss.o
ifdef CONFIG_COMMON_CLK
obj-$(CONFIG_ARCH_S3C64XX)	+= clk-s3c64xx.o
endif
+160 −0
Original line number Diff line number Diff line
@@ -437,6 +437,166 @@ struct clk * __init samsung_clk_register_pll46xx(const char *name,
	return clk;
}

/*
 * PLL6552 Clock Type
 */

#define PLL6552_LOCK_REG	0x00
#define PLL6552_CON_REG		0x0c

#define PLL6552_MDIV_MASK	0x3ff
#define PLL6552_PDIV_MASK	0x3f
#define PLL6552_SDIV_MASK	0x7
#define PLL6552_MDIV_SHIFT	16
#define PLL6552_PDIV_SHIFT	8
#define PLL6552_SDIV_SHIFT	0

struct samsung_clk_pll6552 {
	struct clk_hw hw;
	void __iomem *reg_base;
};

#define to_clk_pll6552(_hw) container_of(_hw, struct samsung_clk_pll6552, hw)

static unsigned long samsung_pll6552_recalc_rate(struct clk_hw *hw,
						unsigned long parent_rate)
{
	struct samsung_clk_pll6552 *pll = to_clk_pll6552(hw);
	u32 mdiv, pdiv, sdiv, pll_con;
	u64 fvco = parent_rate;

	pll_con = __raw_readl(pll->reg_base + PLL6552_CON_REG);
	mdiv = (pll_con >> PLL6552_MDIV_SHIFT) & PLL6552_MDIV_MASK;
	pdiv = (pll_con >> PLL6552_PDIV_SHIFT) & PLL6552_PDIV_MASK;
	sdiv = (pll_con >> PLL6552_SDIV_SHIFT) & PLL6552_SDIV_MASK;

	fvco *= mdiv;
	do_div(fvco, (pdiv << sdiv));

	return (unsigned long)fvco;
}

static const struct clk_ops samsung_pll6552_clk_ops = {
	.recalc_rate = samsung_pll6552_recalc_rate,
};

struct clk * __init samsung_clk_register_pll6552(const char *name,
					const char *pname, void __iomem *base)
{
	struct samsung_clk_pll6552 *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_pll6552_clk_ops;
	init.parent_names = &pname;
	init.num_parents = 1;

	pll->hw.init = &init;
	pll->reg_base = base;

	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;
}

/*
 * PLL6553 Clock Type
 */

#define PLL6553_LOCK_REG	0x00
#define PLL6553_CON0_REG	0x0c
#define PLL6553_CON1_REG	0x10

#define PLL6553_MDIV_MASK	0xff
#define PLL6553_PDIV_MASK	0x3f
#define PLL6553_SDIV_MASK	0x7
#define PLL6553_KDIV_MASK	0xffff
#define PLL6553_MDIV_SHIFT	16
#define PLL6553_PDIV_SHIFT	8
#define PLL6553_SDIV_SHIFT	0
#define PLL6553_KDIV_SHIFT	0

struct samsung_clk_pll6553 {
	struct clk_hw hw;
	void __iomem *reg_base;
};

#define to_clk_pll6553(_hw) container_of(_hw, struct samsung_clk_pll6553, hw)

static unsigned long samsung_pll6553_recalc_rate(struct clk_hw *hw,
						unsigned long parent_rate)
{
	struct samsung_clk_pll6553 *pll = to_clk_pll6553(hw);
	u32 mdiv, pdiv, sdiv, kdiv, pll_con0, pll_con1;
	u64 fvco = parent_rate;

	pll_con0 = __raw_readl(pll->reg_base + PLL6553_CON0_REG);
	pll_con1 = __raw_readl(pll->reg_base + PLL6553_CON1_REG);
	mdiv = (pll_con0 >> PLL6553_MDIV_SHIFT) & PLL6553_MDIV_MASK;
	pdiv = (pll_con0 >> PLL6553_PDIV_SHIFT) & PLL6553_PDIV_MASK;
	sdiv = (pll_con0 >> PLL6553_SDIV_SHIFT) & PLL6553_SDIV_MASK;
	kdiv = (pll_con1 >> PLL6553_KDIV_SHIFT) & PLL6553_KDIV_MASK;

	fvco *= (mdiv << 16) + kdiv;
	do_div(fvco, (pdiv << sdiv));
	fvco >>= 16;

	return (unsigned long)fvco;
}

static const struct clk_ops samsung_pll6553_clk_ops = {
	.recalc_rate = samsung_pll6553_recalc_rate,
};

struct clk * __init samsung_clk_register_pll6553(const char *name,
					const char *pname, void __iomem *base)
{
	struct samsung_clk_pll6553 *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_pll6553_clk_ops;
	init.parent_names = &pname;
	init.num_parents = 1;

	pll->hw.init = &init;
	pll->reg_base = base;

	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
 */
+4 −0
Original line number Diff line number Diff line
@@ -64,6 +64,10 @@ 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 *samsung_clk_register_pll6552(const char *name,
			const char *pname, void __iomem *base);
extern struct clk *samsung_clk_register_pll6553(const char *name,
			const char *pname, void __iomem *base);
extern struct clk * __init samsung_clk_register_pll2550x(const char *name,
			const char *pname, const void __iomem *reg_base,
			const unsigned long offset);
Loading