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