Skip to content

Commit

Permalink
Merge branch 'clk-next-s3c64xx' into clk-next
Browse files Browse the repository at this point in the history
  • Loading branch information
Mike Turquette committed Aug 8, 2013
2 parents 6f9a489 + 06dda9d commit 5cfe961
Show file tree
Hide file tree
Showing 8 changed files with 906 additions and 1 deletion.
77 changes: 77 additions & 0 deletions Documentation/devicetree/bindings/clock/samsung,s3c64xx-clock.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
* 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";
};
10 changes: 9 additions & 1 deletion drivers/clk/clk-mux.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -133,7 +138,10 @@ struct clk *clk_register_mux_table(struct device *dev, const char *name,
}

init.name = name;
init.ops = &clk_mux_ops;
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;
init.num_parents = num_parents;
Expand Down
3 changes: 3 additions & 0 deletions drivers/clk/samsung/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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 changes: 160 additions & 0 deletions drivers/clk/samsung/clk-pll.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
*/
Expand Down
4 changes: 4 additions & 0 deletions drivers/clk/samsung/clk-pll.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Loading

0 comments on commit 5cfe961

Please sign in to comment.