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 - https://www.ti.com/
6 *	Tero Kristo <t-kristo@ti.com>
7 *
8 * Based on Linux kernel clk-cdce925.c.
9 */
10
11#include <dm.h>
12#include <errno.h>
13#include <clk-uclass.h>
14#include <i2c.h>
15#include <dm/device_compat.h>
16#include <linux/bitops.h>
17
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
88static int cdce9xx_clk_request(struct clk *clk)
89{
90	struct cdce9xx_clk_data *data = dev_get_priv(clk->dev);
91
92	if (clk->id > data->chip->num_outputs)
93		return -EINVAL;
94
95	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 = {
237	.request = cdce9xx_clk_request,
238	.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,
247	.priv_auto	= sizeof(struct cdce9xx_clk_data),
248	.ops = &cdce9xx_clk_ops,
249};
250