[PATCH v5 11/15] h8300: clock driver
Signed-off-by: Yoshinori Sato --- drivers/clk/Makefile| 1 + drivers/clk/h8300/Makefile | 2 + drivers/clk/h8300/clk-h83069.c | 74 ++ drivers/clk/h8300/clk-h8s2678.c | 165 include/linux/clk-provider.h| 12 +++ 5 files changed, 254 insertions(+) create mode 100644 drivers/clk/h8300/Makefile create mode 100644 drivers/clk/h8300/clk-h83069.c create mode 100644 drivers/clk/h8300/clk-h8s2678.c diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index d5fba5b..37b6e87 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -68,3 +68,4 @@ obj-$(CONFIG_ARCH_U8500) += ux500/ obj-$(CONFIG_COMMON_CLK_VERSATILE) += versatile/ obj-$(CONFIG_X86) += x86/ obj-$(CONFIG_ARCH_ZYNQ)+= zynq/ +obj-$(CONFIG_H8300)+= h8300/ diff --git a/drivers/clk/h8300/Makefile b/drivers/clk/h8300/Makefile new file mode 100644 index 000..82eab42 --- /dev/null +++ b/drivers/clk/h8300/Makefile @@ -0,0 +1,2 @@ +obj-$(CONFIG_H83069) += clk-h83069.o +obj-$(CONFIG_H8S2678) += clk-h8s2678.o diff --git a/drivers/clk/h8300/clk-h83069.c b/drivers/clk/h8300/clk-h83069.c new file mode 100644 index 000..8d1b915 --- /dev/null +++ b/drivers/clk/h8300/clk-h83069.c @@ -0,0 +1,74 @@ +/* + * H8/3069 clock driver + * + * Copyright 2015 Yoshinori Sato + */ + +#include +#include +#include +#include +#include +#include + +static DEFINE_SPINLOCK(clklock); + +#define DIVCR ((unsigned char *)0xfee01b) +#define DEVNAME "h83069-cpg" + +static int clk_probe(struct platform_device *pdev) +{ + struct clk *clk; + int *hz = dev_get_platdata(>dev); + + clk = clk_register_fixed_rate(>dev, "master_clk", NULL, + CLK_IS_ROOT, *hz); + if (IS_ERR(clk)) { + dev_err(>dev, "failed to register clock"); + return PTR_ERR(clk); + } + clk_register_clkdev(clk, "master_clk", DEVNAME ".%d", 0); + + clk = clk_register_divider(>dev, "core_clk", "master_clk", + CLK_SET_RATE_GATE, DIVCR, 0, 2, + CLK_DIVIDER_POWER_OF_TWO, ); + if (IS_ERR(clk)) { + dev_err(>dev, "failed to register clock"); + return PTR_ERR(clk); + } + clk_register_clkdev(clk, "core_clk", DEVNAME ".%d", 0); + + clk_add_alias("peripheral_clk", NULL, "core_clk", >dev); + return 0; +} + +static struct platform_driver cpg_driver = { + .driver = { + .name = DEVNAME, + }, + .probe = clk_probe, +}; + +early_platform_init(DEVNAME, _driver); + +static struct platform_device clk_device = { + .name = DEVNAME, + .id = 0, +}; + +static struct platform_device *devices[] __initdata = { + _device, +}; + +int __init h8300_clk_init(int hz) +{ + static int master_hz; + + master_hz = hz; + clk_device.dev.platform_data = _hz; + early_platform_add_devices(devices, + ARRAY_SIZE(devices)); + early_platform_driver_register_all(DEVNAME); + early_platform_driver_probe(DEVNAME, 1, 0); + return 0; +} diff --git a/drivers/clk/h8300/clk-h8s2678.c b/drivers/clk/h8300/clk-h8s2678.c new file mode 100644 index 000..e110cff --- /dev/null +++ b/drivers/clk/h8300/clk-h8s2678.c @@ -0,0 +1,165 @@ +/* + * H8S2678 clock driver + * + * Copyright 2015 Yoshinori Sato + */ + +#include +#include +#include +#include +#include +#include + +static DEFINE_SPINLOCK(clklock); + +#define SCKCR 0x3b +#define PLLCR 0x45 +#define DEVNAME "h8s2679-cpg" +#define MAX_FREQ +#define MIN_FREQ 800 + +static unsigned long pll_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + int mul = 1 << (ctrl_inb(PLLCR) & 3); + + return parent_rate * mul; +} + +static long pll_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + int i, m = -1; + long offset[3]; + + if (rate > MAX_FREQ) + rate = MAX_FREQ; + if (rate < MIN_FREQ) + rate = MIN_FREQ; + + for (i = 0; i < 3; i++) + offset[i] = abs(rate - (*prate * (1 << i))); + for (i = 0; i < 3; i++) + if (m < 0) + m = i; + else + m = (offset[i] < offset[m])?i:m; + + return *prate * (1 << m); +} + +static int pll_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + int pll; + unsigned char val; + unsigned long flags; + + pll = ((rate / parent_rate) / 2) & 0x03; + spin_lock_irqsave(, flags); + val = ctrl_inb(SCKCR); + val |= 0x08; + ctrl_outb(val, SCKCR); + val = ctrl_inb(PLLCR); + val &= ~0x03; + val |=
[PATCH v5 11/15] h8300: clock driver
Signed-off-by: Yoshinori Sato ys...@users.sourceforge.jp --- drivers/clk/Makefile| 1 + drivers/clk/h8300/Makefile | 2 + drivers/clk/h8300/clk-h83069.c | 74 ++ drivers/clk/h8300/clk-h8s2678.c | 165 include/linux/clk-provider.h| 12 +++ 5 files changed, 254 insertions(+) create mode 100644 drivers/clk/h8300/Makefile create mode 100644 drivers/clk/h8300/clk-h83069.c create mode 100644 drivers/clk/h8300/clk-h8s2678.c diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index d5fba5b..37b6e87 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -68,3 +68,4 @@ obj-$(CONFIG_ARCH_U8500) += ux500/ obj-$(CONFIG_COMMON_CLK_VERSATILE) += versatile/ obj-$(CONFIG_X86) += x86/ obj-$(CONFIG_ARCH_ZYNQ)+= zynq/ +obj-$(CONFIG_H8300)+= h8300/ diff --git a/drivers/clk/h8300/Makefile b/drivers/clk/h8300/Makefile new file mode 100644 index 000..82eab42 --- /dev/null +++ b/drivers/clk/h8300/Makefile @@ -0,0 +1,2 @@ +obj-$(CONFIG_H83069) += clk-h83069.o +obj-$(CONFIG_H8S2678) += clk-h8s2678.o diff --git a/drivers/clk/h8300/clk-h83069.c b/drivers/clk/h8300/clk-h83069.c new file mode 100644 index 000..8d1b915 --- /dev/null +++ b/drivers/clk/h8300/clk-h83069.c @@ -0,0 +1,74 @@ +/* + * H8/3069 clock driver + * + * Copyright 2015 Yoshinori Sato ys...@users.sourceforge.jp + */ + +#include linux/clk.h +#include linux/clkdev.h +#include linux/clk-provider.h +#include linux/err.h +#include linux/device.h +#include linux/platform_device.h + +static DEFINE_SPINLOCK(clklock); + +#define DIVCR ((unsigned char *)0xfee01b) +#define DEVNAME h83069-cpg + +static int clk_probe(struct platform_device *pdev) +{ + struct clk *clk; + int *hz = dev_get_platdata(pdev-dev); + + clk = clk_register_fixed_rate(pdev-dev, master_clk, NULL, + CLK_IS_ROOT, *hz); + if (IS_ERR(clk)) { + dev_err(pdev-dev, failed to register clock); + return PTR_ERR(clk); + } + clk_register_clkdev(clk, master_clk, DEVNAME .%d, 0); + + clk = clk_register_divider(pdev-dev, core_clk, master_clk, + CLK_SET_RATE_GATE, DIVCR, 0, 2, + CLK_DIVIDER_POWER_OF_TWO, clklock); + if (IS_ERR(clk)) { + dev_err(pdev-dev, failed to register clock); + return PTR_ERR(clk); + } + clk_register_clkdev(clk, core_clk, DEVNAME .%d, 0); + + clk_add_alias(peripheral_clk, NULL, core_clk, pdev-dev); + return 0; +} + +static struct platform_driver cpg_driver = { + .driver = { + .name = DEVNAME, + }, + .probe = clk_probe, +}; + +early_platform_init(DEVNAME, cpg_driver); + +static struct platform_device clk_device = { + .name = DEVNAME, + .id = 0, +}; + +static struct platform_device *devices[] __initdata = { + clk_device, +}; + +int __init h8300_clk_init(int hz) +{ + static int master_hz; + + master_hz = hz; + clk_device.dev.platform_data = master_hz; + early_platform_add_devices(devices, + ARRAY_SIZE(devices)); + early_platform_driver_register_all(DEVNAME); + early_platform_driver_probe(DEVNAME, 1, 0); + return 0; +} diff --git a/drivers/clk/h8300/clk-h8s2678.c b/drivers/clk/h8300/clk-h8s2678.c new file mode 100644 index 000..e110cff --- /dev/null +++ b/drivers/clk/h8300/clk-h8s2678.c @@ -0,0 +1,165 @@ +/* + * H8S2678 clock driver + * + * Copyright 2015 Yoshinori Sato ys...@users.sourceforge.jp + */ + +#include linux/clk.h +#include linux/clkdev.h +#include linux/clk-provider.h +#include linux/err.h +#include linux/device.h +#include linux/platform_device.h + +static DEFINE_SPINLOCK(clklock); + +#define SCKCR 0x3b +#define PLLCR 0x45 +#define DEVNAME h8s2679-cpg +#define MAX_FREQ +#define MIN_FREQ 800 + +static unsigned long pll_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + int mul = 1 (ctrl_inb(PLLCR) 3); + + return parent_rate * mul; +} + +static long pll_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + int i, m = -1; + long offset[3]; + + if (rate MAX_FREQ) + rate = MAX_FREQ; + if (rate MIN_FREQ) + rate = MIN_FREQ; + + for (i = 0; i 3; i++) + offset[i] = abs(rate - (*prate * (1 i))); + for (i = 0; i 3; i++) + if (m 0) + m = i; + else + m = (offset[i] offset[m])?i:m; + + return *prate * (1 m); +} + +static int pll_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + int pll; + unsigned char val; +