]>
Commit | Line | Data |
---|---|---|
92cc4e1c DB |
1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* | |
3 | * Texas Instruments sysc interconnect target driver | |
4 | * | |
5 | * Copyright (C) 2020 Dario Binacchi <[email protected]> | |
6 | */ | |
7 | ||
92cc4e1c DB |
8 | #include <clk.h> |
9 | #include <dm.h> | |
10 | #include <dm/device_compat.h> | |
11 | ||
12 | enum ti_sysc_clocks { | |
13 | TI_SYSC_FCK, | |
14 | TI_SYSC_ICK, | |
15 | TI_SYSC_MAX_CLOCKS, | |
16 | }; | |
17 | ||
18 | static const char *const clock_names[] = {"fck", "ick"}; | |
19 | ||
20 | struct ti_sysc_priv { | |
21 | int clocks_count; | |
22 | struct clk clocks[TI_SYSC_MAX_CLOCKS]; | |
23 | }; | |
24 | ||
25 | static const struct udevice_id ti_sysc_ids[] = { | |
26 | {.compatible = "ti,sysc-omap2"}, | |
27 | {.compatible = "ti,sysc-omap4"}, | |
28 | {.compatible = "ti,sysc-omap4-simple"}, | |
29 | {.compatible = "ti,sysc-omap3430-sr"}, | |
30 | {.compatible = "ti,sysc-omap3630-sr"}, | |
31 | {.compatible = "ti,sysc-omap4-sr"}, | |
32 | {.compatible = "ti,sysc-omap3-sham"}, | |
33 | {.compatible = "ti,sysc-omap-aes"}, | |
34 | {.compatible = "ti,sysc-mcasp"}, | |
35 | {.compatible = "ti,sysc-usb-host-fs"}, | |
36 | {} | |
37 | }; | |
38 | ||
39 | static int ti_sysc_get_one_clock(struct udevice *dev, enum ti_sysc_clocks index) | |
40 | { | |
41 | struct ti_sysc_priv *priv = dev_get_priv(dev); | |
42 | const char *name; | |
43 | int err; | |
44 | ||
45 | switch (index) { | |
46 | case TI_SYSC_FCK: | |
47 | break; | |
48 | case TI_SYSC_ICK: | |
49 | break; | |
50 | default: | |
51 | return -EINVAL; | |
52 | } | |
53 | ||
54 | name = clock_names[index]; | |
55 | ||
56 | err = clk_get_by_name(dev, name, &priv->clocks[index]); | |
57 | if (err) { | |
58 | if (err == -ENODATA) | |
59 | return 0; | |
60 | ||
61 | dev_err(dev, "failed to get %s clock\n", name); | |
62 | return err; | |
63 | } | |
64 | ||
65 | return 0; | |
66 | } | |
67 | ||
68 | static int ti_sysc_put_clocks(struct udevice *dev) | |
69 | { | |
70 | struct ti_sysc_priv *priv = dev_get_priv(dev); | |
71 | int err; | |
72 | ||
73 | err = clk_release_all(priv->clocks, priv->clocks_count); | |
74 | if (err) | |
75 | dev_err(dev, "failed to release all clocks\n"); | |
76 | ||
77 | return err; | |
78 | } | |
79 | ||
80 | static int ti_sysc_get_clocks(struct udevice *dev) | |
81 | { | |
82 | struct ti_sysc_priv *priv = dev_get_priv(dev); | |
83 | int i, err; | |
84 | ||
85 | for (i = 0; i < TI_SYSC_MAX_CLOCKS; i++) { | |
86 | err = ti_sysc_get_one_clock(dev, i); | |
87 | if (!err) | |
88 | priv->clocks_count++; | |
89 | else if (err != -ENOENT) | |
90 | return err; | |
91 | } | |
92 | ||
93 | return 0; | |
94 | } | |
95 | ||
96 | static int ti_sysc_child_post_remove(struct udevice *dev) | |
97 | { | |
98 | struct ti_sysc_priv *priv = dev_get_priv(dev->parent); | |
99 | int i, err; | |
100 | ||
101 | for (i = 0; i < priv->clocks_count; i++) { | |
102 | err = clk_disable(&priv->clocks[i]); | |
103 | if (err) { | |
104 | dev_err(dev->parent, "failed to disable %s clock\n", | |
105 | clock_names[i]); | |
106 | return err; | |
107 | } | |
108 | } | |
109 | ||
110 | return 0; | |
111 | } | |
112 | ||
113 | static int ti_sysc_child_pre_probe(struct udevice *dev) | |
114 | { | |
115 | struct ti_sysc_priv *priv = dev_get_priv(dev->parent); | |
116 | int i, err; | |
117 | ||
118 | for (i = 0; i < priv->clocks_count; i++) { | |
119 | err = clk_enable(&priv->clocks[i]); | |
120 | if (err) { | |
121 | dev_err(dev->parent, "failed to enable %s clock\n", | |
122 | clock_names[i]); | |
123 | return err; | |
124 | } | |
125 | } | |
126 | ||
127 | return 0; | |
128 | } | |
129 | ||
130 | static int ti_sysc_remove(struct udevice *dev) | |
131 | { | |
132 | return ti_sysc_put_clocks(dev); | |
133 | } | |
134 | ||
135 | static int ti_sysc_probe(struct udevice *dev) | |
136 | { | |
137 | int err; | |
138 | ||
139 | err = ti_sysc_get_clocks(dev); | |
140 | if (err) | |
141 | goto clocks_err; | |
142 | ||
143 | return 0; | |
144 | ||
145 | clocks_err: | |
146 | ti_sysc_put_clocks(dev); | |
147 | return err; | |
148 | } | |
149 | ||
92cc4e1c DB |
150 | U_BOOT_DRIVER(ti_sysc) = { |
151 | .name = "ti_sysc", | |
152 | .id = UCLASS_SIMPLE_BUS, | |
153 | .of_match = ti_sysc_ids, | |
154 | .probe = ti_sysc_probe, | |
155 | .remove = ti_sysc_remove, | |
156 | .child_pre_probe = ti_sysc_child_pre_probe, | |
157 | .child_post_remove = ti_sysc_child_post_remove, | |
158 | .priv_auto = sizeof(struct ti_sysc_priv) | |
159 | }; |