1/*
2 * MOXA ART SoCs clock driver.
3 *
4 * Copyright (C) 2013 Jonas Jensen
5 *
6 * Jonas Jensen <jonas.jensen@gmail.com>
7 *
8 * This file is licensed under the terms of the GNU General Public
9 * License version 2.  This program is licensed "as is" without any
10 * warranty of any kind, whether express or implied.
11 */
12
13#include <linux/clk.h>
14#include <linux/clk-provider.h>
15#include <linux/io.h>
16#include <linux/of_address.h>
17#include <linux/clkdev.h>
18
19static void __init moxart_of_pll_clk_init(struct device_node *node)
20{
21	void __iomem *base;
22	struct clk_hw *hw;
23	struct clk *ref_clk;
24	unsigned int mul;
25	const char *name = node->name;
26	const char *parent_name;
27
28	of_property_read_string(node, "clock-output-names", &name);
29	parent_name = of_clk_get_parent_name(node, 0);
30
31	base = of_iomap(node, 0);
32	if (!base) {
33		pr_err("%pOF: of_iomap failed\n", node);
34		return;
35	}
36
37	mul = readl(base + 0x30) >> 3 & 0x3f;
38	iounmap(base);
39
40	ref_clk = of_clk_get(node, 0);
41	if (IS_ERR(ref_clk)) {
42		pr_err("%pOF: of_clk_get failed\n", node);
43		return;
44	}
45
46	hw = clk_hw_register_fixed_factor(NULL, name, parent_name, 0, mul, 1);
47	if (IS_ERR(hw)) {
48		pr_err("%pOF: failed to register clock\n", node);
49		return;
50	}
51
52	clk_hw_register_clkdev(hw, NULL, name);
53	of_clk_add_hw_provider(node, of_clk_hw_simple_get, hw);
54}
55CLK_OF_DECLARE(moxart_pll_clock, "moxa,moxart-pll-clock",
56	       moxart_of_pll_clk_init);
57
58static void __init moxart_of_apb_clk_init(struct device_node *node)
59{
60	void __iomem *base;
61	struct clk_hw *hw;
62	struct clk *pll_clk;
63	unsigned int div, val;
64	unsigned int div_idx[] = { 2, 3, 4, 6, 8};
65	const char *name = node->name;
66	const char *parent_name;
67
68	of_property_read_string(node, "clock-output-names", &name);
69	parent_name = of_clk_get_parent_name(node, 0);
70
71	base = of_iomap(node, 0);
72	if (!base) {
73		pr_err("%pOF: of_iomap failed\n", node);
74		return;
75	}
76
77	val = readl(base + 0xc) >> 4 & 0x7;
78	iounmap(base);
79
80	if (val > 4)
81		val = 0;
82	div = div_idx[val] * 2;
83
84	pll_clk = of_clk_get(node, 0);
85	if (IS_ERR(pll_clk)) {
86		pr_err("%pOF: of_clk_get failed\n", node);
87		return;
88	}
89
90	hw = clk_hw_register_fixed_factor(NULL, name, parent_name, 0, 1, div);
91	if (IS_ERR(hw)) {
92		pr_err("%pOF: failed to register clock\n", node);
93		return;
94	}
95
96	clk_hw_register_clkdev(hw, NULL, name);
97	of_clk_add_hw_provider(node, of_clk_hw_simple_get, hw);
98}
99CLK_OF_DECLARE(moxart_apb_clock, "moxa,moxart-apb-clock",
100	       moxart_of_apb_clk_init);
101