1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3 * Copyright (C) 2019 DENX Software Engineering
4 * Lukasz Majewski, DENX Software Engineering, lukma@denx.de
5 */
6
7 #define LOG_CATEGORY UCLASS_CLK
8
9 #include <clk.h>
10 #include <clk-uclass.h>
11 #include <log.h>
12 #include <dm/device.h>
13 #include <dm/uclass.h>
14 #include <dm/lists.h>
15 #include <dm/device-internal.h>
16
clk_register(struct clk * clk,const char * drv_name,const char * name,const char * parent_name)17 int clk_register(struct clk *clk, const char *drv_name,
18 const char *name, const char *parent_name)
19 {
20 struct udevice *parent = NULL;
21 struct driver *drv;
22 int ret;
23
24 if (parent_name) {
25 ret = uclass_get_device_by_name(UCLASS_CLK, parent_name, &parent);
26 if (ret) {
27 log_err("%s: failed to get %s device (parent of %s)\n",
28 __func__, parent_name, name);
29 } else {
30 log_debug("%s: name: %s parent: %s [0x%p]\n", __func__, name,
31 parent->name, parent);
32 }
33 }
34
35 drv = lists_driver_lookup_name(drv_name);
36 if (!drv) {
37 log_err("%s: %s is not a valid driver name\n",
38 __func__, drv_name);
39 return -ENOENT;
40 }
41
42 ret = device_bind(parent, drv, name, NULL, ofnode_null(), &clk->dev);
43 if (ret) {
44 log_err("%s: CLK: %s driver bind error [%d]!\n", __func__, name,
45 ret);
46 return ret;
47 }
48
49 clk->enable_count = 0;
50
51 /* Store back pointer to clk from udevice */
52 /* FIXME: This is not allowed...should be allocated by driver model */
53 dev_set_uclass_priv(clk->dev, clk);
54
55 return 0;
56 }
57
clk_generic_get_rate(struct clk * clk)58 ulong clk_generic_get_rate(struct clk *clk)
59 {
60 return clk_get_parent_rate(clk);
61 }
62
clk_hw_get_name(const struct clk * hw)63 const char *clk_hw_get_name(const struct clk *hw)
64 {
65 assert(hw);
66 assert(hw->dev);
67
68 return hw->dev->name;
69 }
70
clk_dev_binded(struct clk * clk)71 bool clk_dev_binded(struct clk *clk)
72 {
73 if (clk->dev && (dev_get_flags(clk->dev) & DM_FLAG_BOUND))
74 return true;
75
76 return false;
77 }
78
79 /* Helper functions for clock ops */
80
ccf_clk_get_rate(struct clk * clk)81 ulong ccf_clk_get_rate(struct clk *clk)
82 {
83 struct clk *c;
84 int err = clk_get_by_id(clk->id, &c);
85
86 if (err)
87 return err;
88 return clk_get_rate(c);
89 }
90
ccf_clk_set_rate(struct clk * clk,unsigned long rate)91 ulong ccf_clk_set_rate(struct clk *clk, unsigned long rate)
92 {
93 struct clk *c;
94 int err = clk_get_by_id(clk->id, &c);
95
96 if (err)
97 return err;
98 return clk_set_rate(c, rate);
99 }
100
ccf_clk_set_parent(struct clk * clk,struct clk * parent)101 int ccf_clk_set_parent(struct clk *clk, struct clk *parent)
102 {
103 struct clk *c, *p;
104 int err = clk_get_by_id(clk->id, &c);
105
106 if (err)
107 return err;
108
109 err = clk_get_by_id(parent->id, &p);
110 if (err)
111 return err;
112
113 return clk_set_parent(c, p);
114 }
115
ccf_clk_endisable(struct clk * clk,bool enable)116 static int ccf_clk_endisable(struct clk *clk, bool enable)
117 {
118 struct clk *c;
119 int err = clk_get_by_id(clk->id, &c);
120
121 if (err)
122 return err;
123 return enable ? clk_enable(c) : clk_disable(c);
124 }
125
ccf_clk_enable(struct clk * clk)126 int ccf_clk_enable(struct clk *clk)
127 {
128 return ccf_clk_endisable(clk, true);
129 }
130
ccf_clk_disable(struct clk * clk)131 int ccf_clk_disable(struct clk *clk)
132 {
133 return ccf_clk_endisable(clk, false);
134 }
135
136 const struct clk_ops ccf_clk_ops = {
137 .set_rate = ccf_clk_set_rate,
138 .get_rate = ccf_clk_get_rate,
139 .set_parent = ccf_clk_set_parent,
140 .enable = ccf_clk_enable,
141 .disable = ccf_clk_disable,
142 };
143