]>
Commit | Line | Data |
---|---|---|
215bd541 DB |
1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* | |
3 | * OMAP clock controller support | |
4 | * | |
5 | * Copyright (C) 2020 Dario Binacchi <[email protected]> | |
6 | */ | |
7 | ||
8 | #include <common.h> | |
9 | #include <dm.h> | |
10 | #include <dm/device_compat.h> | |
11 | #include <clk-uclass.h> | |
12 | #include <asm/arch-am33xx/clock.h> | |
13 | ||
14 | struct clk_ti_ctrl_offs { | |
15 | fdt_addr_t start; | |
16 | fdt_size_t end; | |
17 | }; | |
18 | ||
19 | struct clk_ti_ctrl_priv { | |
20 | int offs_num; | |
21 | struct clk_ti_ctrl_offs *offs; | |
22 | }; | |
23 | ||
24 | static int clk_ti_ctrl_check_offs(struct clk *clk, fdt_addr_t offs) | |
25 | { | |
26 | struct clk_ti_ctrl_priv *priv = dev_get_priv(clk->dev); | |
27 | int i; | |
28 | ||
29 | for (i = 0; i < priv->offs_num; i++) { | |
30 | if (offs >= priv->offs[i].start && offs <= priv->offs[i].end) | |
31 | return 0; | |
32 | } | |
33 | ||
34 | return -EFAULT; | |
35 | } | |
36 | ||
37 | static int clk_ti_ctrl_disable(struct clk *clk) | |
38 | { | |
39 | struct clk_ti_ctrl_priv *priv = dev_get_priv(clk->dev); | |
40 | u32 *clk_modules[2] = { }; | |
41 | fdt_addr_t offs; | |
42 | int err; | |
43 | ||
44 | offs = priv->offs[0].start + clk->id; | |
45 | err = clk_ti_ctrl_check_offs(clk, offs); | |
46 | if (err) { | |
47 | dev_err(clk->dev, "invalid offset: 0x%lx\n", offs); | |
48 | return err; | |
49 | } | |
50 | ||
51 | clk_modules[0] = (u32 *)(offs); | |
d242a145 | 52 | dev_dbg(clk->dev, "disable module @ %p\n", clk_modules[0]); |
215bd541 DB |
53 | do_disable_clocks(NULL, clk_modules, 1); |
54 | return 0; | |
55 | } | |
56 | ||
57 | static int clk_ti_ctrl_enable(struct clk *clk) | |
58 | { | |
59 | struct clk_ti_ctrl_priv *priv = dev_get_priv(clk->dev); | |
60 | u32 *clk_modules[2] = { }; | |
61 | fdt_addr_t offs; | |
62 | int err; | |
63 | ||
64 | offs = priv->offs[0].start + clk->id; | |
65 | err = clk_ti_ctrl_check_offs(clk, offs); | |
66 | if (err) { | |
67 | dev_err(clk->dev, "invalid offset: 0x%lx\n", offs); | |
68 | return err; | |
69 | } | |
70 | ||
71 | clk_modules[0] = (u32 *)(offs); | |
d242a145 | 72 | dev_dbg(clk->dev, "enable module @ %p\n", clk_modules[0]); |
215bd541 DB |
73 | do_enable_clocks(NULL, clk_modules, 1); |
74 | return 0; | |
75 | } | |
76 | ||
77 | static ulong clk_ti_ctrl_get_rate(struct clk *clk) | |
78 | { | |
79 | return 0; | |
80 | } | |
81 | ||
82 | static int clk_ti_ctrl_of_xlate(struct clk *clk, | |
83 | struct ofnode_phandle_args *args) | |
84 | { | |
85 | if (args->args_count != 2) { | |
86 | dev_err(clk->dev, "invaild args_count: %d\n", args->args_count); | |
87 | return -EINVAL; | |
88 | } | |
89 | ||
90 | if (args->args_count) | |
91 | clk->id = args->args[0]; | |
92 | else | |
93 | clk->id = 0; | |
94 | ||
95 | dev_dbg(clk->dev, "name=%s, id=%ld\n", clk->dev->name, clk->id); | |
96 | return 0; | |
97 | } | |
98 | ||
99 | static int clk_ti_ctrl_of_to_plat(struct udevice *dev) | |
100 | { | |
101 | struct clk_ti_ctrl_priv *priv = dev_get_priv(dev); | |
102 | fdt_size_t fdt_size; | |
103 | int i, size; | |
104 | ||
105 | size = dev_read_size(dev, "reg"); | |
106 | if (size < 0) { | |
107 | dev_err(dev, "failed to get 'reg' size\n"); | |
108 | return size; | |
109 | } | |
110 | ||
111 | priv->offs_num = size / 2 / sizeof(u32); | |
112 | dev_dbg(dev, "size=%d, regs_num=%d\n", size, priv->offs_num); | |
113 | ||
114 | priv->offs = kmalloc_array(priv->offs_num, sizeof(*priv->offs), | |
115 | GFP_KERNEL); | |
116 | if (!priv->offs) | |
117 | return -ENOMEM; | |
118 | ||
119 | for (i = 0; i < priv->offs_num; i++) { | |
120 | priv->offs[i].start = | |
121 | dev_read_addr_size_index(dev, i, &fdt_size); | |
122 | if (priv->offs[i].start == FDT_ADDR_T_NONE) { | |
123 | dev_err(dev, "failed to get offset %d\n", i); | |
124 | return -EINVAL; | |
125 | } | |
126 | ||
127 | priv->offs[i].end = priv->offs[i].start + fdt_size; | |
128 | dev_dbg(dev, "start=0x%08lx, end=0x%08lx\n", | |
129 | priv->offs[i].start, priv->offs[i].end); | |
130 | } | |
131 | ||
132 | return 0; | |
133 | } | |
134 | ||
135 | static struct clk_ops clk_ti_ctrl_ops = { | |
136 | .of_xlate = clk_ti_ctrl_of_xlate, | |
137 | .enable = clk_ti_ctrl_enable, | |
138 | .disable = clk_ti_ctrl_disable, | |
139 | .get_rate = clk_ti_ctrl_get_rate, | |
140 | }; | |
141 | ||
142 | static const struct udevice_id clk_ti_ctrl_ids[] = { | |
143 | {.compatible = "ti,clkctrl"}, | |
144 | {}, | |
145 | }; | |
146 | ||
147 | U_BOOT_DRIVER(clk_ti_ctrl) = { | |
148 | .name = "ti_ctrl_clk", | |
149 | .id = UCLASS_CLK, | |
150 | .of_match = clk_ti_ctrl_ids, | |
b0db69b4 | 151 | .of_to_plat = clk_ti_ctrl_of_to_plat, |
215bd541 DB |
152 | .ops = &clk_ti_ctrl_ops, |
153 | .priv_auto = sizeof(struct clk_ti_ctrl_priv), | |
154 | }; |