Merge branch '2019-10-11-ti-imports'
[oweals/u-boot.git] / drivers / clk / clk-cdce9xx.c
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
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
34 struct cdce9xx_chip_info {
35         int num_plls;
36         int num_outputs;
37 };
38
39 struct cdce9xx_clk_data {
40         struct udevice *i2c;
41         struct cdce9xx_chip_info *chip;
42         u32 xtal_rate;
43 };
44
45 static const struct cdce9xx_chip_info cdce913_chip_info = {
46         .num_plls = 1, .num_outputs = 3,
47 };
48
49 static const struct cdce9xx_chip_info cdce925_chip_info = {
50         .num_plls = 2, .num_outputs = 5,
51 };
52
53 static const struct cdce9xx_chip_info cdce937_chip_info = {
54         .num_plls = 3, .num_outputs = 7,
55 };
56
57 static const struct cdce9xx_chip_info cdce949_chip_info = {
58         .num_plls = 4, .num_outputs = 9,
59 };
60
61 static 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
74 static 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
87 static 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
103 static 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
131 static 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
161 static 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
168 static 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
180 static 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
233 static 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
241 static 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
247 U_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 };