1*3bb16560SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2c7bb4fc1SJonas Jensen /*
3c7bb4fc1SJonas Jensen * MOXA ART SoCs clock driver.
4c7bb4fc1SJonas Jensen *
5c7bb4fc1SJonas Jensen * Copyright (C) 2013 Jonas Jensen
6c7bb4fc1SJonas Jensen *
7c7bb4fc1SJonas Jensen * Jonas Jensen <jonas.jensen@gmail.com>
8c7bb4fc1SJonas Jensen */
9c7bb4fc1SJonas Jensen
1067bb5408SStephen Boyd #include <linux/clk.h>
11c7bb4fc1SJonas Jensen #include <linux/clk-provider.h>
12c7bb4fc1SJonas Jensen #include <linux/io.h>
13c7bb4fc1SJonas Jensen #include <linux/of_address.h>
14c7bb4fc1SJonas Jensen #include <linux/clkdev.h>
15c7bb4fc1SJonas Jensen
moxart_of_pll_clk_init(struct device_node * node)1661ad23a1SStephen Boyd static void __init moxart_of_pll_clk_init(struct device_node *node)
17c7bb4fc1SJonas Jensen {
18c8108cf2SGustavo A. R. Silva void __iomem *base;
195a962d2eSStephen Boyd struct clk_hw *hw;
205a962d2eSStephen Boyd struct clk *ref_clk;
21c7bb4fc1SJonas Jensen unsigned int mul;
22c7bb4fc1SJonas Jensen const char *name = node->name;
23c7bb4fc1SJonas Jensen const char *parent_name;
24c7bb4fc1SJonas Jensen
25c7bb4fc1SJonas Jensen of_property_read_string(node, "clock-output-names", &name);
26c7bb4fc1SJonas Jensen parent_name = of_clk_get_parent_name(node, 0);
27c7bb4fc1SJonas Jensen
28c7bb4fc1SJonas Jensen base = of_iomap(node, 0);
29c7bb4fc1SJonas Jensen if (!base) {
3016673931SRob Herring pr_err("%pOF: of_iomap failed\n", node);
31c7bb4fc1SJonas Jensen return;
32c7bb4fc1SJonas Jensen }
33c7bb4fc1SJonas Jensen
34c7bb4fc1SJonas Jensen mul = readl(base + 0x30) >> 3 & 0x3f;
35c7bb4fc1SJonas Jensen iounmap(base);
36c7bb4fc1SJonas Jensen
37c7bb4fc1SJonas Jensen ref_clk = of_clk_get(node, 0);
38c7bb4fc1SJonas Jensen if (IS_ERR(ref_clk)) {
3916673931SRob Herring pr_err("%pOF: of_clk_get failed\n", node);
40c7bb4fc1SJonas Jensen return;
41c7bb4fc1SJonas Jensen }
42c7bb4fc1SJonas Jensen
435a962d2eSStephen Boyd hw = clk_hw_register_fixed_factor(NULL, name, parent_name, 0, mul, 1);
445a962d2eSStephen Boyd if (IS_ERR(hw)) {
4516673931SRob Herring pr_err("%pOF: failed to register clock\n", node);
46c7bb4fc1SJonas Jensen return;
47c7bb4fc1SJonas Jensen }
48c7bb4fc1SJonas Jensen
495a962d2eSStephen Boyd clk_hw_register_clkdev(hw, NULL, name);
505a962d2eSStephen Boyd of_clk_add_hw_provider(node, of_clk_hw_simple_get, hw);
51c7bb4fc1SJonas Jensen }
52c7bb4fc1SJonas Jensen CLK_OF_DECLARE(moxart_pll_clock, "moxa,moxart-pll-clock",
53c7bb4fc1SJonas Jensen moxart_of_pll_clk_init);
54c7bb4fc1SJonas Jensen
moxart_of_apb_clk_init(struct device_node * node)5561ad23a1SStephen Boyd static void __init moxart_of_apb_clk_init(struct device_node *node)
56c7bb4fc1SJonas Jensen {
57c8108cf2SGustavo A. R. Silva void __iomem *base;
585a962d2eSStephen Boyd struct clk_hw *hw;
595a962d2eSStephen Boyd struct clk *pll_clk;
60c7bb4fc1SJonas Jensen unsigned int div, val;
61c7bb4fc1SJonas Jensen unsigned int div_idx[] = { 2, 3, 4, 6, 8};
62c7bb4fc1SJonas Jensen const char *name = node->name;
63c7bb4fc1SJonas Jensen const char *parent_name;
64c7bb4fc1SJonas Jensen
65c7bb4fc1SJonas Jensen of_property_read_string(node, "clock-output-names", &name);
66c7bb4fc1SJonas Jensen parent_name = of_clk_get_parent_name(node, 0);
67c7bb4fc1SJonas Jensen
68c7bb4fc1SJonas Jensen base = of_iomap(node, 0);
69c7bb4fc1SJonas Jensen if (!base) {
7016673931SRob Herring pr_err("%pOF: of_iomap failed\n", node);
71c7bb4fc1SJonas Jensen return;
72c7bb4fc1SJonas Jensen }
73c7bb4fc1SJonas Jensen
74c7bb4fc1SJonas Jensen val = readl(base + 0xc) >> 4 & 0x7;
75c7bb4fc1SJonas Jensen iounmap(base);
76c7bb4fc1SJonas Jensen
77c7bb4fc1SJonas Jensen if (val > 4)
78c7bb4fc1SJonas Jensen val = 0;
79c7bb4fc1SJonas Jensen div = div_idx[val] * 2;
80c7bb4fc1SJonas Jensen
81c7bb4fc1SJonas Jensen pll_clk = of_clk_get(node, 0);
82c7bb4fc1SJonas Jensen if (IS_ERR(pll_clk)) {
8316673931SRob Herring pr_err("%pOF: of_clk_get failed\n", node);
84c7bb4fc1SJonas Jensen return;
85c7bb4fc1SJonas Jensen }
86c7bb4fc1SJonas Jensen
875a962d2eSStephen Boyd hw = clk_hw_register_fixed_factor(NULL, name, parent_name, 0, 1, div);
885a962d2eSStephen Boyd if (IS_ERR(hw)) {
8916673931SRob Herring pr_err("%pOF: failed to register clock\n", node);
90c7bb4fc1SJonas Jensen return;
91c7bb4fc1SJonas Jensen }
92c7bb4fc1SJonas Jensen
935a962d2eSStephen Boyd clk_hw_register_clkdev(hw, NULL, name);
945a962d2eSStephen Boyd of_clk_add_hw_provider(node, of_clk_hw_simple_get, hw);
95c7bb4fc1SJonas Jensen }
96c7bb4fc1SJonas Jensen CLK_OF_DECLARE(moxart_apb_clock, "moxa,moxart-apb-clock",
97c7bb4fc1SJonas Jensen moxart_of_apb_clk_init);
98