summaryrefslogtreecommitdiff
path: root/drivers/clk/hisilicon
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2016-07-30 21:20:02 +0300
committerLinus Torvalds <torvalds@linux-foundation.org>2016-07-30 21:20:02 +0300
commit1056c9bd2702ea1bb79abf9bd1e78c578589d247 (patch)
treefaada7d658151c059a845cdb9d9d521817d1e611 /drivers/clk/hisilicon
parent797cee982eef9195736afc5e7f3b8f613c41d19a (diff)
parentd22527fed2f094c2e4f9a66f35b68a090c3d906a (diff)
downloadlinux-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.c116
-rw-r--r--drivers/clk/hisilicon/clk-hi6220.c6
-rw-r--r--drivers/clk/hisilicon/clk.c89
-rw-r--r--drivers/clk/hisilicon/clk.h34
-rw-r--r--drivers/clk/hisilicon/clkdivider-hi6220.c2
-rw-r--r--drivers/clk/hisilicon/reset.c19
-rw-r--r--drivers/clk/hisilicon/reset.h5
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;
}