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