blob: 6e4d67220a1685ccf8ce3dca91cd83300783203c [file] [log] [blame]
Simon Glassf26c8a82015-06-23 15:39:15 -06001/*
2 * Copyright (C) 2015 Google, Inc
3 * Written by Simon Glass <sjg@chromium.org>
Stephen Warren135aa952016-06-17 09:44:00 -06004 * Copyright (c) 2016, NVIDIA CORPORATION.
Simon Glassf26c8a82015-06-23 15:39:15 -06005 *
6 * SPDX-License-Identifier: GPL-2.0+
7 */
8
9#include <common.h>
10#include <clk.h>
Stephen Warren135aa952016-06-17 09:44:00 -060011#include <clk-uclass.h>
Simon Glassf26c8a82015-06-23 15:39:15 -060012#include <dm.h>
13#include <errno.h>
Simon Glassf26c8a82015-06-23 15:39:15 -060014
Simon Glasse70cc432016-01-20 19:43:02 -070015DECLARE_GLOBAL_DATA_PTR;
16
Stephen Warren135aa952016-06-17 09:44:00 -060017static inline struct clk_ops *clk_dev_ops(struct udevice *dev)
Simon Glassf26c8a82015-06-23 15:39:15 -060018{
Stephen Warren135aa952016-06-17 09:44:00 -060019 return (struct clk_ops *)dev->driver->ops;
Simon Glassf26c8a82015-06-23 15:39:15 -060020}
21
Simon Glasse70cc432016-01-20 19:43:02 -070022#if CONFIG_IS_ENABLED(OF_CONTROL)
Stephen Warren135aa952016-06-17 09:44:00 -060023#ifdef CONFIG_SPL_BUILD
24int clk_get_by_index(struct udevice *dev, int index, struct clk *clk)
Simon Glasse70cc432016-01-20 19:43:02 -070025{
Simon Glasse70cc432016-01-20 19:43:02 -070026 int ret;
Simon Glassa4b10c02016-01-21 19:44:00 -070027 u32 cell[2];
28
29 if (index != 0)
30 return -ENOSYS;
Stephen Warren135aa952016-06-17 09:44:00 -060031 assert(clk);
32 ret = uclass_get_device(UCLASS_CLK, 0, &clk->dev);
Simon Glassa4b10c02016-01-21 19:44:00 -070033 if (ret)
34 return ret;
35 ret = fdtdec_get_int_array(gd->fdt_blob, dev->of_offset, "clocks",
36 cell, 2);
37 if (ret)
38 return ret;
Stephen Warren135aa952016-06-17 09:44:00 -060039 clk->id = cell[1];
40 return 0;
41}
Simon Glasse70cc432016-01-20 19:43:02 -070042
Stephen Warren135aa952016-06-17 09:44:00 -060043int clk_get_by_name(struct udevice *dev, const char *name, struct clk *clk)
44{
45 return -ENOSYS;
46}
47#else
48static int clk_of_xlate_default(struct clk *clk,
49 struct fdtdec_phandle_args *args)
50{
51 debug("%s(clk=%p)\n", __func__, clk);
52
53 if (args->args_count > 1) {
54 debug("Invaild args_count: %d\n", args->args_count);
55 return -EINVAL;
56 }
57
58 if (args->args_count)
59 clk->id = args->args[0];
60 else
61 clk->id = 0;
62
63 return 0;
64}
65
66int clk_get_by_index(struct udevice *dev, int index, struct clk *clk)
67{
68 int ret;
69 struct fdtdec_phandle_args args;
70 struct udevice *dev_clk;
71 struct clk_ops *ops;
72
73 debug("%s(dev=%p, index=%d, clk=%p)\n", __func__, dev, index, clk);
74
75 assert(clk);
Simon Glasse70cc432016-01-20 19:43:02 -070076 ret = fdtdec_parse_phandle_with_args(gd->fdt_blob, dev->of_offset,
77 "clocks", "#clock-cells", 0, index,
78 &args);
79 if (ret) {
80 debug("%s: fdtdec_parse_phandle_with_args failed: err=%d\n",
81 __func__, ret);
82 return ret;
83 }
84
Stephen Warren135aa952016-06-17 09:44:00 -060085 ret = uclass_get_device_by_of_offset(UCLASS_CLK, args.node, &dev_clk);
Simon Glasse70cc432016-01-20 19:43:02 -070086 if (ret) {
87 debug("%s: uclass_get_device_by_of_offset failed: err=%d\n",
88 __func__, ret);
89 return ret;
90 }
Stephen Warren135aa952016-06-17 09:44:00 -060091 ops = clk_dev_ops(dev_clk);
92
93 if (ops->of_xlate)
94 ret = ops->of_xlate(clk, &args);
95 else
96 ret = clk_of_xlate_default(clk, &args);
97 if (ret) {
98 debug("of_xlate() failed: %d\n", ret);
99 return ret;
100 }
101
102 return clk_request(dev_clk, clk);
103}
104
105int clk_get_by_name(struct udevice *dev, const char *name, struct clk *clk)
106{
107 int index;
108
109 debug("%s(dev=%p, name=%s, clk=%p)\n", __func__, dev, name, clk);
110
111 index = fdt_find_string(gd->fdt_blob, dev->of_offset, "clock-names",
112 name);
113 if (index < 0) {
114 debug("fdt_find_string() failed: %d\n", index);
115 return index;
116 }
117
118 return clk_get_by_index(dev, index, clk);
Simon Glasse70cc432016-01-20 19:43:02 -0700119}
120#endif
Stephen Warren135aa952016-06-17 09:44:00 -0600121#endif
122
123int clk_request(struct udevice *dev, struct clk *clk)
124{
125 struct clk_ops *ops = clk_dev_ops(dev);
126
127 debug("%s(dev=%p, clk=%p)\n", __func__, dev, clk);
128
129 clk->dev = dev;
130
131 if (!ops->request)
132 return 0;
133
134 return ops->request(clk);
135}
136
137int clk_free(struct clk *clk)
138{
139 struct clk_ops *ops = clk_dev_ops(clk->dev);
140
141 debug("%s(clk=%p)\n", __func__, clk);
142
143 if (!ops->free)
144 return 0;
145
146 return ops->free(clk);
147}
148
149ulong clk_get_rate(struct clk *clk)
150{
151 struct clk_ops *ops = clk_dev_ops(clk->dev);
152
153 debug("%s(clk=%p)\n", __func__, clk);
154
155 if (!ops->get_rate)
156 return -ENOSYS;
157
158 return ops->get_rate(clk);
159}
160
161ulong clk_set_rate(struct clk *clk, ulong rate)
162{
163 struct clk_ops *ops = clk_dev_ops(clk->dev);
164
165 debug("%s(clk=%p, rate=%lu)\n", __func__, clk, rate);
166
167 if (!ops->set_rate)
168 return -ENOSYS;
169
170 return ops->set_rate(clk, rate);
171}
172
173int clk_enable(struct clk *clk)
174{
175 struct clk_ops *ops = clk_dev_ops(clk->dev);
176
177 debug("%s(clk=%p)\n", __func__, clk);
178
179 if (!ops->enable)
180 return -ENOSYS;
181
182 return ops->enable(clk);
183}
184
185int clk_disable(struct clk *clk)
186{
187 struct clk_ops *ops = clk_dev_ops(clk->dev);
188
189 debug("%s(clk=%p)\n", __func__, clk);
190
191 if (!ops->disable)
192 return -ENOSYS;
193
194 return ops->disable(clk);
195}
Simon Glasse70cc432016-01-20 19:43:02 -0700196
Simon Glassf26c8a82015-06-23 15:39:15 -0600197UCLASS_DRIVER(clk) = {
198 .id = UCLASS_CLK,
199 .name = "clk",
200};