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