diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2016-07-30 21:20:02 +0300 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-07-30 21:20:02 +0300 |
commit | 1056c9bd2702ea1bb79abf9bd1e78c578589d247 (patch) | |
tree | faada7d658151c059a845cdb9d9d521817d1e611 /drivers/clk/hisilicon | |
parent | 797cee982eef9195736afc5e7f3b8f613c41d19a (diff) | |
parent | d22527fed2f094c2e4f9a66f35b68a090c3d906a (diff) | |
download | linux-1056c9bd2702ea1bb79abf9bd1e78c578589d247.tar.xz |
Merge tag 'clk-for-linus-4.8' of git://git.kernel.org/pub/scm/linux/kernel/git/clk/linux
Pull clk updates from Michael Turquette:
"The bulk of the changes are updates and fixes to existing clk provider
drivers, along with a pretty standard number of new drivers. The core
recieved a small number of updates as well.
Core changes of note:
- removed CLK_IS_ROOT flag
New clk provider drivers:
- Renesas r8a7796 clock pulse generator / module standby and
software reset
- Allwinner sun8i H3 clock controller unit
- AmLogic meson8b clock controller (rewritten)
- AmLogic gxbb clock controller
- support for some new ICs was added by simple changes to static
data tables for chips sharing the same family
Driver updates of note:
- the Allwinner sunxi clock driver infrastucture was rewritten to
comform to the state of the art at drivers/clk/sunxi-ng. The old
implementation is still supported for backwards compatibility with
the DT ABI"
* tag 'clk-for-linus-4.8' of git://git.kernel.org/pub/scm/linux/kernel/git/clk/linux: (162 commits)
clk: Makefile: re-sort and clean up
Revert "clk: gxbb: expose CLKID_MMC_PCLK"
clk: samsung: Allow modular build of the Audio Subsystem CLKCON driver
clk: samsung: make clk-s5pv210-audss explicitly non-modular
clk: exynos5433: remove CLK_IGNORE_UNUSED flag from SPI clocks
clk: oxnas: Add hardware dependencies
clk: imx7d: do not set parent of ethernet time/ref clocks
ARM: dt: sun8i: switch the H3 to the new CCU driver
clk: sunxi-ng: h3: Fix Kconfig symbol typo
clk: sunxi-ng: h3: Fix audio clock divider offset
clk: sunxi-ng: Add H3 clocks
clk: sunxi-ng: Add N-K-M-P factor clock
clk: sunxi-ng: Add N-K-M Factor clock
clk: sunxi-ng: Add N-M-factor clock support
clk: sunxi-ng: Add N-K-factor clock support
clk: sunxi-ng: Add M-P factor clock support
clk: sunxi-ng: Add divider
clk: sunxi-ng: Add phase clock support
clk: sunxi-ng: Add mux clock support
clk: sunxi-ng: Add gate clock support
...
Diffstat (limited to 'drivers/clk/hisilicon')
-rw-r--r-- | drivers/clk/hisilicon/clk-hi3519.c | 116 | ||||
-rw-r--r-- | drivers/clk/hisilicon/clk-hi6220.c | 6 | ||||
-rw-r--r-- | drivers/clk/hisilicon/clk.c | 89 | ||||
-rw-r--r-- | drivers/clk/hisilicon/clk.h | 34 | ||||
-rw-r--r-- | drivers/clk/hisilicon/clkdivider-hi6220.c | 2 | ||||
-rw-r--r-- | drivers/clk/hisilicon/reset.c | 19 | ||||
-rw-r--r-- | drivers/clk/hisilicon/reset.h | 5 |
7 files changed, 226 insertions, 45 deletions
diff --git a/drivers/clk/hisilicon/clk-hi3519.c b/drivers/clk/hisilicon/clk-hi3519.c index 715c7301a66a..51b173ef1dda 100644 --- a/drivers/clk/hisilicon/clk-hi3519.c +++ b/drivers/clk/hisilicon/clk-hi3519.c @@ -38,6 +38,11 @@ #define HI3519_NR_CLKS 128 +struct hi3519_crg_data { + struct hisi_clock_data *clk_data; + struct hisi_reset_controller *rstc; +}; + static const struct hisi_fixed_rate_clock hi3519_fixed_rate_clks[] = { { HI3519_FIXED_24M, "24m", NULL, 0, 24000000, }, { HI3519_FIXED_50M, "50m", NULL, 0, 50000000, }, @@ -80,33 +85,105 @@ static const struct hisi_gate_clock hi3519_gate_clks[] = { CLK_SET_RATE_PARENT, 0xe4, 18, 0, }, }; -static int hi3519_clk_probe(struct platform_device *pdev) +static struct hisi_clock_data *hi3519_clk_register(struct platform_device *pdev) { - struct device_node *np = pdev->dev.of_node; struct hisi_clock_data *clk_data; - struct hisi_reset_controller *rstc; + int ret; - rstc = hisi_reset_init(np); - if (!rstc) + clk_data = hisi_clk_alloc(pdev, HI3519_NR_CLKS); + if (!clk_data) + return ERR_PTR(-ENOMEM); + + ret = hisi_clk_register_fixed_rate(hi3519_fixed_rate_clks, + ARRAY_SIZE(hi3519_fixed_rate_clks), + clk_data); + if (ret) + return ERR_PTR(ret); + + ret = hisi_clk_register_mux(hi3519_mux_clks, + ARRAY_SIZE(hi3519_mux_clks), + clk_data); + if (ret) + goto unregister_fixed_rate; + + ret = hisi_clk_register_gate(hi3519_gate_clks, + ARRAY_SIZE(hi3519_gate_clks), + clk_data); + if (ret) + goto unregister_mux; + + ret = of_clk_add_provider(pdev->dev.of_node, + of_clk_src_onecell_get, &clk_data->clk_data); + if (ret) + goto unregister_gate; + + return clk_data; + +unregister_fixed_rate: + hisi_clk_unregister_fixed_rate(hi3519_fixed_rate_clks, + ARRAY_SIZE(hi3519_fixed_rate_clks), + clk_data); + +unregister_mux: + hisi_clk_unregister_mux(hi3519_mux_clks, + ARRAY_SIZE(hi3519_mux_clks), + clk_data); +unregister_gate: + hisi_clk_unregister_gate(hi3519_gate_clks, + ARRAY_SIZE(hi3519_gate_clks), + clk_data); + return ERR_PTR(ret); +} + +static void hi3519_clk_unregister(struct platform_device *pdev) +{ + struct hi3519_crg_data *crg = platform_get_drvdata(pdev); + + of_clk_del_provider(pdev->dev.of_node); + + hisi_clk_unregister_gate(hi3519_gate_clks, + ARRAY_SIZE(hi3519_mux_clks), + crg->clk_data); + hisi_clk_unregister_mux(hi3519_mux_clks, + ARRAY_SIZE(hi3519_mux_clks), + crg->clk_data); + hisi_clk_unregister_fixed_rate(hi3519_fixed_rate_clks, + ARRAY_SIZE(hi3519_fixed_rate_clks), + crg->clk_data); +} + +static int hi3519_clk_probe(struct platform_device *pdev) +{ + struct hi3519_crg_data *crg; + + crg = devm_kmalloc(&pdev->dev, sizeof(*crg), GFP_KERNEL); + if (!crg) + return -ENOMEM; + + crg->rstc = hisi_reset_init(pdev); + if (!crg->rstc) return -ENOMEM; - clk_data = hisi_clk_init(np, HI3519_NR_CLKS); - if (!clk_data) { - hisi_reset_exit(rstc); - return -ENODEV; + crg->clk_data = hi3519_clk_register(pdev); + if (IS_ERR(crg->clk_data)) { + hisi_reset_exit(crg->rstc); + return PTR_ERR(crg->clk_data); } - hisi_clk_register_fixed_rate(hi3519_fixed_rate_clks, - ARRAY_SIZE(hi3519_fixed_rate_clks), - clk_data); - hisi_clk_register_mux(hi3519_mux_clks, ARRAY_SIZE(hi3519_mux_clks), - clk_data); - hisi_clk_register_gate(hi3519_gate_clks, - ARRAY_SIZE(hi3519_gate_clks), clk_data); + platform_set_drvdata(pdev, crg); + return 0; +} + +static int hi3519_clk_remove(struct platform_device *pdev) +{ + struct hi3519_crg_data *crg = platform_get_drvdata(pdev); + hisi_reset_exit(crg->rstc); + hi3519_clk_unregister(pdev); return 0; } + static const struct of_device_id hi3519_clk_match_table[] = { { .compatible = "hisilicon,hi3519-crg" }, { } @@ -115,6 +192,7 @@ MODULE_DEVICE_TABLE(of, hi3519_clk_match_table); static struct platform_driver hi3519_clk_driver = { .probe = hi3519_clk_probe, + .remove = hi3519_clk_remove, .driver = { .name = "hi3519-clk", .of_match_table = hi3519_clk_match_table, @@ -127,5 +205,11 @@ static int __init hi3519_clk_init(void) } core_initcall(hi3519_clk_init); +static void __exit hi3519_clk_exit(void) +{ + platform_driver_unregister(&hi3519_clk_driver); +} +module_exit(hi3519_clk_exit); + MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("HiSilicon Hi3519 Clock Driver"); diff --git a/drivers/clk/hisilicon/clk-hi6220.c b/drivers/clk/hisilicon/clk-hi6220.c index f02cb41d40a4..fe364e63f8de 100644 --- a/drivers/clk/hisilicon/clk-hi6220.c +++ b/drivers/clk/hisilicon/clk-hi6220.c @@ -34,8 +34,8 @@ static struct hisi_fixed_rate_clock hi6220_fixed_rate_clks[] __initdata = { { HI6220_PLL_BBP, "bbppll0", NULL, 0, 245760000, }, { HI6220_PLL_GPU, "gpupll", NULL, 0, 1000000000,}, { HI6220_PLL1_DDR, "ddrpll1", NULL, 0, 1066000000,}, - { HI6220_PLL_SYS, "syspll", NULL, 0, 1200000000,}, - { HI6220_PLL_SYS_MEDIA, "media_syspll", NULL, 0, 1200000000,}, + { HI6220_PLL_SYS, "syspll", NULL, 0, 1190400000,}, + { HI6220_PLL_SYS_MEDIA, "media_syspll", NULL, 0, 1190400000,}, { HI6220_DDR_SRC, "ddr_sel_src", NULL, 0, 1200000000,}, { HI6220_PLL_MEDIA, "media_pll", NULL, 0, 1440000000,}, { HI6220_PLL_DDR, "ddrpll0", NULL, 0, 1600000000,}, @@ -68,6 +68,8 @@ static struct hisi_gate_clock hi6220_separated_gate_clks_ao[] __initdata = { { HI6220_TIMER7_PCLK, "timer7_pclk", "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 22, 0, }, { HI6220_TIMER8_PCLK, "timer8_pclk", "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 23, 0, }, { HI6220_UART0_PCLK, "uart0_pclk", "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 24, 0, }, + { HI6220_RTC0_PCLK, "rtc0_pclk", "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 25, 0, }, + { HI6220_RTC1_PCLK, "rtc1_pclk", "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 26, 0, }, }; static void __init hi6220_clk_ao_init(struct device_node *np) diff --git a/drivers/clk/hisilicon/clk.c b/drivers/clk/hisilicon/clk.c index 9b15adbfc30c..9ba2d91f4d3a 100644 --- a/drivers/clk/hisilicon/clk.c +++ b/drivers/clk/hisilicon/clk.c @@ -37,6 +37,35 @@ static DEFINE_SPINLOCK(hisi_clk_lock); +struct hisi_clock_data *hisi_clk_alloc(struct platform_device *pdev, + int nr_clks) +{ + struct hisi_clock_data *clk_data; + struct resource *res; + struct clk **clk_table; + + clk_data = devm_kmalloc(&pdev->dev, sizeof(*clk_data), GFP_KERNEL); + if (!clk_data) + return NULL; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + clk_data->base = devm_ioremap(&pdev->dev, + res->start, resource_size(res)); + if (!clk_data->base) + return NULL; + + clk_table = devm_kmalloc(&pdev->dev, sizeof(struct clk *) * nr_clks, + GFP_KERNEL); + if (!clk_table) + return NULL; + + clk_data->clk_data.clks = clk_table; + clk_data->clk_data.clk_num = nr_clks; + + return clk_data; +} +EXPORT_SYMBOL_GPL(hisi_clk_alloc); + struct hisi_clock_data *hisi_clk_init(struct device_node *np, int nr_clks) { @@ -73,7 +102,7 @@ err: } EXPORT_SYMBOL_GPL(hisi_clk_init); -void hisi_clk_register_fixed_rate(const struct hisi_fixed_rate_clock *clks, +int hisi_clk_register_fixed_rate(const struct hisi_fixed_rate_clock *clks, int nums, struct hisi_clock_data *data) { struct clk *clk; @@ -87,14 +116,22 @@ void hisi_clk_register_fixed_rate(const struct hisi_fixed_rate_clock *clks, if (IS_ERR(clk)) { pr_err("%s: failed to register clock %s\n", __func__, clks[i].name); - continue; + goto err; } data->clk_data.clks[clks[i].id] = clk; } + + return 0; + +err: + while (i--) + clk_unregister_fixed_rate(data->clk_data.clks[clks[i].id]); + + return PTR_ERR(clk); } EXPORT_SYMBOL_GPL(hisi_clk_register_fixed_rate); -void hisi_clk_register_fixed_factor(const struct hisi_fixed_factor_clock *clks, +int hisi_clk_register_fixed_factor(const struct hisi_fixed_factor_clock *clks, int nums, struct hisi_clock_data *data) { @@ -109,14 +146,22 @@ void hisi_clk_register_fixed_factor(const struct hisi_fixed_factor_clock *clks, if (IS_ERR(clk)) { pr_err("%s: failed to register clock %s\n", __func__, clks[i].name); - continue; + goto err; } data->clk_data.clks[clks[i].id] = clk; } + + return 0; + +err: + while (i--) + clk_unregister_fixed_factor(data->clk_data.clks[clks[i].id]); + + return PTR_ERR(clk); } EXPORT_SYMBOL_GPL(hisi_clk_register_fixed_factor); -void hisi_clk_register_mux(const struct hisi_mux_clock *clks, +int hisi_clk_register_mux(const struct hisi_mux_clock *clks, int nums, struct hisi_clock_data *data) { struct clk *clk; @@ -135,7 +180,7 @@ void hisi_clk_register_mux(const struct hisi_mux_clock *clks, if (IS_ERR(clk)) { pr_err("%s: failed to register clock %s\n", __func__, clks[i].name); - continue; + goto err; } if (clks[i].alias) @@ -143,10 +188,18 @@ void hisi_clk_register_mux(const struct hisi_mux_clock *clks, data->clk_data.clks[clks[i].id] = clk; } + + return 0; + +err: + while (i--) + clk_unregister_mux(data->clk_data.clks[clks[i].id]); + + return PTR_ERR(clk); } EXPORT_SYMBOL_GPL(hisi_clk_register_mux); -void hisi_clk_register_divider(const struct hisi_divider_clock *clks, +int hisi_clk_register_divider(const struct hisi_divider_clock *clks, int nums, struct hisi_clock_data *data) { struct clk *clk; @@ -165,7 +218,7 @@ void hisi_clk_register_divider(const struct hisi_divider_clock *clks, if (IS_ERR(clk)) { pr_err("%s: failed to register clock %s\n", __func__, clks[i].name); - continue; + goto err; } if (clks[i].alias) @@ -173,10 +226,18 @@ void hisi_clk_register_divider(const struct hisi_divider_clock *clks, data->clk_data.clks[clks[i].id] = clk; } + + return 0; + +err: + while (i--) + clk_unregister_divider(data->clk_data.clks[clks[i].id]); + + return PTR_ERR(clk); } EXPORT_SYMBOL_GPL(hisi_clk_register_divider); -void hisi_clk_register_gate(const struct hisi_gate_clock *clks, +int hisi_clk_register_gate(const struct hisi_gate_clock *clks, int nums, struct hisi_clock_data *data) { struct clk *clk; @@ -194,7 +255,7 @@ void hisi_clk_register_gate(const struct hisi_gate_clock *clks, if (IS_ERR(clk)) { pr_err("%s: failed to register clock %s\n", __func__, clks[i].name); - continue; + goto err; } if (clks[i].alias) @@ -202,6 +263,14 @@ void hisi_clk_register_gate(const struct hisi_gate_clock *clks, data->clk_data.clks[clks[i].id] = clk; } + + return 0; + +err: + while (i--) + clk_unregister_gate(data->clk_data.clks[clks[i].id]); + + return PTR_ERR(clk); } EXPORT_SYMBOL_GPL(hisi_clk_register_gate); diff --git a/drivers/clk/hisilicon/clk.h b/drivers/clk/hisilicon/clk.h index 20d64afe4ad8..4e1d1affc6f5 100644 --- a/drivers/clk/hisilicon/clk.h +++ b/drivers/clk/hisilicon/clk.h @@ -30,6 +30,8 @@ #include <linux/io.h> #include <linux/spinlock.h> +struct platform_device; + struct hisi_clock_data { struct clk_onecell_data clk_data; void __iomem *base; @@ -110,19 +112,41 @@ struct clk *hi6220_register_clkdiv(struct device *dev, const char *name, const char *parent_name, unsigned long flags, void __iomem *reg, u8 shift, u8 width, u32 mask_bit, spinlock_t *lock); +struct hisi_clock_data *hisi_clk_alloc(struct platform_device *, int); struct hisi_clock_data *hisi_clk_init(struct device_node *, int); -void hisi_clk_register_fixed_rate(const struct hisi_fixed_rate_clock *, +int hisi_clk_register_fixed_rate(const struct hisi_fixed_rate_clock *, int, struct hisi_clock_data *); -void hisi_clk_register_fixed_factor(const struct hisi_fixed_factor_clock *, +int hisi_clk_register_fixed_factor(const struct hisi_fixed_factor_clock *, int, struct hisi_clock_data *); -void hisi_clk_register_mux(const struct hisi_mux_clock *, int, +int hisi_clk_register_mux(const struct hisi_mux_clock *, int, struct hisi_clock_data *); -void hisi_clk_register_divider(const struct hisi_divider_clock *, +int hisi_clk_register_divider(const struct hisi_divider_clock *, int, struct hisi_clock_data *); -void hisi_clk_register_gate(const struct hisi_gate_clock *, +int hisi_clk_register_gate(const struct hisi_gate_clock *, int, struct hisi_clock_data *); void hisi_clk_register_gate_sep(const struct hisi_gate_clock *, int, struct hisi_clock_data *); void hi6220_clk_register_divider(const struct hi6220_divider_clock *, int, struct hisi_clock_data *); + +#define hisi_clk_unregister(type) \ +static inline \ +void hisi_clk_unregister_##type(const struct hisi_##type##_clock *clks, \ + int nums, struct hisi_clock_data *data) \ +{ \ + struct clk **clocks = data->clk_data.clks; \ + int i; \ + for (i = 0; i < nums; i++) { \ + int id = clks[i].id; \ + if (clocks[id]) \ + clk_unregister_##type(clocks[id]); \ + } \ +} + +hisi_clk_unregister(fixed_rate) +hisi_clk_unregister(fixed_factor) +hisi_clk_unregister(mux) +hisi_clk_unregister(divider) +hisi_clk_unregister(gate) + #endif /* __HISI_CLK_H */ diff --git a/drivers/clk/hisilicon/clkdivider-hi6220.c b/drivers/clk/hisilicon/clkdivider-hi6220.c index 113eee8ed23a..a1c1f684ad58 100644 --- a/drivers/clk/hisilicon/clkdivider-hi6220.c +++ b/drivers/clk/hisilicon/clkdivider-hi6220.c @@ -18,6 +18,8 @@ #include <linux/err.h> #include <linux/spinlock.h> +#include "clk.h" + #define div_mask(width) ((1 << (width)) - 1) /** diff --git a/drivers/clk/hisilicon/reset.c b/drivers/clk/hisilicon/reset.c index 6aa49c2204d0..2a5015c736ce 100644 --- a/drivers/clk/hisilicon/reset.c +++ b/drivers/clk/hisilicon/reset.c @@ -19,6 +19,7 @@ #include <linux/io.h> #include <linux/of_address.h> +#include <linux/platform_device.h> #include <linux/reset-controller.h> #include <linux/slab.h> #include <linux/spinlock.h> @@ -98,25 +99,25 @@ static const struct reset_control_ops hisi_reset_ops = { .deassert = hisi_reset_deassert, }; -struct hisi_reset_controller *hisi_reset_init(struct device_node *np) +struct hisi_reset_controller *hisi_reset_init(struct platform_device *pdev) { struct hisi_reset_controller *rstc; + struct resource *res; - rstc = kzalloc(sizeof(*rstc), GFP_KERNEL); + rstc = devm_kmalloc(&pdev->dev, sizeof(*rstc), GFP_KERNEL); if (!rstc) return NULL; - rstc->membase = of_iomap(np, 0); - if (!rstc->membase) { - kfree(rstc); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + rstc->membase = devm_ioremap(&pdev->dev, + res->start, resource_size(res)); + if (!rstc->membase) return NULL; - } spin_lock_init(&rstc->lock); - rstc->rcdev.owner = THIS_MODULE; rstc->rcdev.ops = &hisi_reset_ops; - rstc->rcdev.of_node = np; + rstc->rcdev.of_node = pdev->dev.of_node; rstc->rcdev.of_reset_n_cells = 2; rstc->rcdev.of_xlate = hisi_reset_of_xlate; reset_controller_register(&rstc->rcdev); @@ -128,7 +129,5 @@ EXPORT_SYMBOL_GPL(hisi_reset_init); void hisi_reset_exit(struct hisi_reset_controller *rstc) { reset_controller_unregister(&rstc->rcdev); - iounmap(rstc->membase); - kfree(rstc); } EXPORT_SYMBOL_GPL(hisi_reset_exit); diff --git a/drivers/clk/hisilicon/reset.h b/drivers/clk/hisilicon/reset.h index 677d773ed27c..9a69374a0b32 100644 --- a/drivers/clk/hisilicon/reset.h +++ b/drivers/clk/hisilicon/reset.h @@ -22,10 +22,11 @@ struct device_node; struct hisi_reset_controller; #ifdef CONFIG_RESET_CONTROLLER -struct hisi_reset_controller *hisi_reset_init(struct device_node *np); +struct hisi_reset_controller *hisi_reset_init(struct platform_device *pdev); void hisi_reset_exit(struct hisi_reset_controller *rstc); #else -static inline hisi_reset_controller *hisi_reset_init(struct device_node *np) +static inline +struct hisi_reset_controller *hisi_reset_init(struct platform_device *pdev) { return 0; } |