1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3 * Texas Instruments CDCE913/925/937/949 clock synthesizer driver
4 *
5 * Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com/
6 * Tero Kristo <t-kristo@ti.com>
7 *
8 * Based on Linux kernel clk-cdce925.c.
9 */
10
11 #include <common.h>
12 #include <dm.h>
13 #include <errno.h>
14 #include <clk-uclass.h>
15 #include <i2c.h>
16 #include <dm/device_compat.h>
17 #include <linux/bitops.h>
18
19 #define MAX_NUMBER_OF_PLLS 4
20 #define MAX_NUMER_OF_OUTPUTS 9
21
22 #define CDCE9XX_REG_GLOBAL1 0x01
23 #define CDCE9XX_REG_Y1SPIPDIVH 0x02
24 #define CDCE9XX_REG_PDIV1L 0x03
25 #define CDCE9XX_REG_XCSEL 0x05
26
27 #define CDCE9XX_PDIV1_H_MASK 0x3
28
29 #define CDCE9XX_REG_PDIV(clk) (0x16 + (((clk) - 1) & 1) + \
30 ((clk) - 1) / 2 * 0x10)
31
32 #define CDCE9XX_PDIV_MASK 0x7f
33
34 #define CDCE9XX_BYTE_TRANSFER BIT(7)
35
36 struct cdce9xx_chip_info {
37 int num_plls;
38 int num_outputs;
39 };
40
41 struct cdce9xx_clk_data {
42 struct udevice *i2c;
43 struct cdce9xx_chip_info *chip;
44 u32 xtal_rate;
45 };
46
47 static const struct cdce9xx_chip_info cdce913_chip_info = {
48 .num_plls = 1, .num_outputs = 3,
49 };
50
51 static const struct cdce9xx_chip_info cdce925_chip_info = {
52 .num_plls = 2, .num_outputs = 5,
53 };
54
55 static const struct cdce9xx_chip_info cdce937_chip_info = {
56 .num_plls = 3, .num_outputs = 7,
57 };
58
59 static const struct cdce9xx_chip_info cdce949_chip_info = {
60 .num_plls = 4, .num_outputs = 9,
61 };
62
cdce9xx_reg_read(struct udevice * dev,u8 addr,u8 * buf)63 static int cdce9xx_reg_read(struct udevice *dev, u8 addr, u8 *buf)
64 {
65 struct cdce9xx_clk_data *data = dev_get_priv(dev);
66 int ret;
67
68 ret = dm_i2c_read(data->i2c, addr | CDCE9XX_BYTE_TRANSFER, buf, 1);
69 if (ret)
70 dev_err(dev, "%s: failed for addr:%x, ret:%d\n", __func__,
71 addr, ret);
72
73 return ret;
74 }
75
cdce9xx_reg_write(struct udevice * dev,u8 addr,u8 val)76 static int cdce9xx_reg_write(struct udevice *dev, u8 addr, u8 val)
77 {
78 struct cdce9xx_clk_data *data = dev_get_priv(dev);
79 int ret;
80
81 ret = dm_i2c_write(data->i2c, addr | CDCE9XX_BYTE_TRANSFER, &val, 1);
82 if (ret)
83 dev_err(dev, "%s: failed for addr:%x, ret:%d\n", __func__,
84 addr, ret);
85
86 return ret;
87 }
88
cdce9xx_clk_of_xlate(struct clk * clk,struct ofnode_phandle_args * args)89 static int cdce9xx_clk_of_xlate(struct clk *clk,
90 struct ofnode_phandle_args *args)
91 {
92 struct cdce9xx_clk_data *data = dev_get_priv(clk->dev);
93
94 if (args->args_count != 1)
95 return -EINVAL;
96
97 if (args->args[0] > data->chip->num_outputs)
98 return -EINVAL;
99
100 clk->id = args->args[0];
101
102 return 0;
103 }
104
cdce9xx_clk_probe(struct udevice * dev)105 static int cdce9xx_clk_probe(struct udevice *dev)
106 {
107 struct cdce9xx_clk_data *data = dev_get_priv(dev);
108 struct cdce9xx_chip_info *chip = (void *)dev_get_driver_data(dev);
109 int ret;
110 u32 val;
111 struct clk clk;
112
113 val = (u32)dev_read_addr_ptr(dev);
114
115 ret = i2c_get_chip(dev->parent, val, 1, &data->i2c);
116 if (ret) {
117 dev_err(dev, "I2C probe failed.\n");
118 return ret;
119 }
120
121 data->chip = chip;
122
123 ret = clk_get_by_index(dev, 0, &clk);
124 data->xtal_rate = clk_get_rate(&clk);
125
126 val = dev_read_u32_default(dev, "xtal-load-pf", -1);
127 if (val >= 0)
128 cdce9xx_reg_write(dev, CDCE9XX_REG_XCSEL, val << 3);
129
130 return 0;
131 }
132
cdce9xx_clk_get_pdiv(struct clk * clk)133 static u16 cdce9xx_clk_get_pdiv(struct clk *clk)
134 {
135 u8 val;
136 u16 pdiv;
137 int ret;
138
139 if (clk->id == 0) {
140 ret = cdce9xx_reg_read(clk->dev, CDCE9XX_REG_Y1SPIPDIVH, &val);
141 if (ret)
142 return 0;
143
144 pdiv = (val & CDCE9XX_PDIV1_H_MASK) << 8;
145
146 ret = cdce9xx_reg_read(clk->dev, CDCE9XX_REG_PDIV1L, &val);
147 if (ret)
148 return 0;
149
150 pdiv |= val;
151 } else {
152 ret = cdce9xx_reg_read(clk->dev, CDCE9XX_REG_PDIV(clk->id),
153 &val);
154 if (ret)
155 return 0;
156
157 pdiv = val & CDCE9XX_PDIV_MASK;
158 }
159
160 return pdiv;
161 }
162
cdce9xx_clk_get_parent_rate(struct clk * clk)163 static u32 cdce9xx_clk_get_parent_rate(struct clk *clk)
164 {
165 struct cdce9xx_clk_data *data = dev_get_priv(clk->dev);
166
167 return data->xtal_rate;
168 }
169
cdce9xx_clk_get_rate(struct clk * clk)170 static ulong cdce9xx_clk_get_rate(struct clk *clk)
171 {
172 u32 parent_rate;
173 u16 pdiv;
174
175 parent_rate = cdce9xx_clk_get_parent_rate(clk);
176
177 pdiv = cdce9xx_clk_get_pdiv(clk);
178
179 return parent_rate / pdiv;
180 }
181
cdce9xx_clk_set_rate(struct clk * clk,ulong rate)182 static ulong cdce9xx_clk_set_rate(struct clk *clk, ulong rate)
183 {
184 u32 parent_rate;
185 int pdiv;
186 u32 diff;
187 u8 val;
188 int ret;
189
190 parent_rate = cdce9xx_clk_get_parent_rate(clk);
191
192 pdiv = parent_rate / rate;
193
194 diff = rate - parent_rate / pdiv;
195
196 if (rate - parent_rate / (pdiv + 1) < diff)
197 pdiv++;
198
199 if (clk->id == 0) {
200 ret = cdce9xx_reg_read(clk->dev, CDCE9XX_REG_Y1SPIPDIVH, &val);
201 if (ret)
202 return ret;
203
204 val &= ~CDCE9XX_PDIV1_H_MASK;
205
206 val |= (pdiv >> 8);
207
208 ret = cdce9xx_reg_write(clk->dev, CDCE9XX_REG_Y1SPIPDIVH, val);
209 if (ret)
210 return ret;
211
212 ret = cdce9xx_reg_write(clk->dev, CDCE9XX_REG_PDIV1L,
213 (pdiv & 0xff));
214 if (ret)
215 return ret;
216 } else {
217 ret = cdce9xx_reg_read(clk->dev, CDCE9XX_REG_PDIV(clk->id),
218 &val);
219 if (ret)
220 return ret;
221
222 val &= ~CDCE9XX_PDIV_MASK;
223
224 val |= pdiv;
225
226 ret = cdce9xx_reg_write(clk->dev, CDCE9XX_REG_PDIV(clk->id),
227 val);
228 if (ret)
229 return ret;
230 }
231
232 return 0;
233 }
234
235 static const struct udevice_id cdce9xx_clk_of_match[] = {
236 { .compatible = "ti,cdce913", .data = (u32)&cdce913_chip_info },
237 { .compatible = "ti,cdce925", .data = (u32)&cdce925_chip_info },
238 { .compatible = "ti,cdce937", .data = (u32)&cdce937_chip_info },
239 { .compatible = "ti,cdce949", .data = (u32)&cdce949_chip_info },
240 { /* sentinel */ },
241 };
242
243 static const struct clk_ops cdce9xx_clk_ops = {
244 .of_xlate = cdce9xx_clk_of_xlate,
245 .get_rate = cdce9xx_clk_get_rate,
246 .set_rate = cdce9xx_clk_set_rate,
247 };
248
249 U_BOOT_DRIVER(cdce9xx_clk) = {
250 .name = "cdce9xx-clk",
251 .id = UCLASS_CLK,
252 .of_match = cdce9xx_clk_of_match,
253 .probe = cdce9xx_clk_probe,
254 .priv_auto = sizeof(struct cdce9xx_clk_data),
255 .ops = &cdce9xx_clk_ops,
256 };
257