Commit | Line | Data |
---|---|---|
7b5bb891 YS |
1 | /* |
2 | * H8/300 divide clock driver | |
3 | * | |
4 | * Copyright 2015 Yoshinori Sato <ysato@users.sourceforge.jp> | |
5 | */ | |
6 | ||
7b5bb891 YS |
7 | #include <linux/clk-provider.h> |
8 | #include <linux/err.h> | |
9 | #include <linux/of.h> | |
10 | #include <linux/of_address.h> | |
11 | ||
12 | static DEFINE_SPINLOCK(clklock); | |
13 | ||
14 | static void __init h8300_div_clk_setup(struct device_node *node) | |
15 | { | |
e306479a | 16 | int num_parents; |
7b5bb891 YS |
17 | struct clk *clk; |
18 | const char *clk_name = node->name; | |
19 | const char *parent_name; | |
20 | void __iomem *divcr = NULL; | |
21 | int width; | |
aca25180 | 22 | int offset; |
7b5bb891 YS |
23 | |
24 | num_parents = of_clk_get_parent_count(node); | |
25 | if (num_parents < 1) { | |
26 | pr_err("%s: no parent found", clk_name); | |
27 | return; | |
28 | } | |
29 | ||
30 | divcr = of_iomap(node, 0); | |
31 | if (divcr == NULL) { | |
32 | pr_err("%s: failed to map divide register", clk_name); | |
33 | goto error; | |
34 | } | |
aca25180 YS |
35 | offset = (unsigned long)divcr & 3; |
36 | offset = (3 - offset) * 8; | |
37 | divcr = (void *)((unsigned long)divcr & ~3); | |
7b5bb891 YS |
38 | |
39 | parent_name = of_clk_get_parent_name(node, 0); | |
40 | of_property_read_u32(node, "renesas,width", &width); | |
41 | clk = clk_register_divider(NULL, clk_name, parent_name, | |
aca25180 | 42 | CLK_SET_RATE_GATE, divcr, offset, width, |
7b5bb891 YS |
43 | CLK_DIVIDER_POWER_OF_TWO, &clklock); |
44 | if (!IS_ERR(clk)) { | |
45 | of_clk_add_provider(node, of_clk_src_simple_get, clk); | |
46 | return; | |
47 | } | |
48 | pr_err("%s: failed to register %s div clock (%ld)\n", | |
49 | __func__, clk_name, PTR_ERR(clk)); | |
50 | error: | |
51 | if (divcr) | |
52 | iounmap(divcr); | |
53 | } | |
54 | ||
55 | CLK_OF_DECLARE(h8300_div_clk, "renesas,h8300-div-clock", h8300_div_clk_setup); |