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