1 // 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 
13 enum ti_sysc_clocks {
14 	TI_SYSC_FCK,
15 	TI_SYSC_ICK,
16 	TI_SYSC_MAX_CLOCKS,
17 };
18 
19 static const char *const clock_names[] = {"fck", "ick"};
20 
21 struct ti_sysc_priv {
22 	int clocks_count;
23 	struct clk clocks[TI_SYSC_MAX_CLOCKS];
24 };
25 
26 static 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 
ti_sysc_get_one_clock(struct udevice * dev,enum ti_sysc_clocks index)40 static 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 
ti_sysc_put_clocks(struct udevice * dev)69 static 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 
ti_sysc_get_clocks(struct udevice * dev)81 static 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 
ti_sysc_child_post_remove(struct udevice * dev)97 static 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 
ti_sysc_child_pre_probe(struct udevice * dev)114 static 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 
ti_sysc_remove(struct udevice * dev)131 static int ti_sysc_remove(struct udevice *dev)
132 {
133 	return ti_sysc_put_clocks(dev);
134 }
135 
ti_sysc_probe(struct udevice * dev)136 static 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 
146 clocks_err:
147 	ti_sysc_put_clocks(dev);
148 	return err;
149 }
150 
151 U_BOOT_DRIVER(ti_sysc) = {
152 	.name = "ti_sysc",
153 	.id = UCLASS_SIMPLE_BUS,
154 	.of_match = ti_sysc_ids,
155 	.probe = ti_sysc_probe,
156 	.remove = ti_sysc_remove,
157 	.child_pre_probe = ti_sysc_child_pre_probe,
158 	.child_post_remove = ti_sysc_child_post_remove,
159 	.priv_auto = sizeof(struct ti_sysc_priv)
160 };
161