]>
Commit | Line | Data |
---|---|---|
a5b22518 SL |
1 | /* |
2 | * Copyright 2013 Freescale Semiconductor, Inc. | |
3 | * Author: Shaveta Leekha <shaveta@freescale.com> | |
4 | * | |
3aab0cd8 | 5 | * SPDX-License-Identifier: GPL-2.0+ |
a5b22518 SL |
6 | */ |
7 | ||
8 | #include "idt8t49n222a_serdes_clk.h" | |
9 | ||
10 | #define DEVICE_ID_REG 0x00 | |
11 | ||
12 | static int check_pll_status(u8 idt_addr) | |
13 | { | |
14 | u8 val = 0; | |
15 | int ret; | |
16 | ||
17 | ret = i2c_read(idt_addr, 0x17, 1, &val, 1); | |
18 | if (ret < 0) { | |
19 | printf("IDT:0x%x could not read status register from device.\n", | |
20 | idt_addr); | |
21 | return ret; | |
22 | } | |
23 | ||
24 | if (val & 0x04) { | |
25 | debug("idt8t49n222a PLL is LOCKED: %x\n", val); | |
26 | } else { | |
27 | printf("idt8t49n222a PLL is not LOCKED: %x\n", val); | |
28 | return -1; | |
29 | } | |
30 | ||
31 | return 0; | |
32 | } | |
33 | ||
34 | int set_serdes_refclk(u8 idt_addr, u8 serdes_num, | |
35 | enum serdes_refclk refclk1, | |
36 | enum serdes_refclk refclk2, u8 feedback) | |
37 | { | |
38 | u8 dev_id = 0; | |
39 | int i, ret; | |
40 | ||
41 | debug("IDT:Configuring idt8t49n222a device at I2C address: 0x%2x\n", | |
42 | idt_addr); | |
43 | ||
44 | ret = i2c_read(idt_addr, DEVICE_ID_REG, 1, &dev_id, 1); | |
45 | if (ret < 0) { | |
46 | debug("IDT:0x%x could not read DEV_ID from device.\n", | |
47 | idt_addr); | |
48 | return ret; | |
49 | } | |
50 | ||
51 | if ((dev_id != 0x00) && (dev_id != 0x24) && (dev_id != 0x2a)) { | |
52 | debug("IDT: device at address 0x%x is not idt8t49n222a.\n", | |
53 | idt_addr); | |
54 | } | |
55 | ||
56 | if (serdes_num != 1 && serdes_num != 2) { | |
57 | debug("serdes_num should be 1 for SerDes1 and" | |
58 | " 2 for SerDes2.\n"); | |
59 | return -1; | |
60 | } | |
61 | ||
62 | if ((refclk1 == SERDES_REFCLK_122_88 && refclk2 != SERDES_REFCLK_122_88) | |
63 | || (refclk1 != SERDES_REFCLK_122_88 | |
64 | && refclk2 == SERDES_REFCLK_122_88)) { | |
65 | debug("Only one refclk at 122.88MHz is not supported." | |
66 | " Please set both refclk1 & refclk2 to 122.88MHz" | |
67 | " or both not to 122.88MHz.\n"); | |
68 | return -1; | |
69 | } | |
70 | ||
71 | if (refclk1 != SERDES_REFCLK_100 && refclk1 != SERDES_REFCLK_122_88 | |
72 | && refclk1 != SERDES_REFCLK_125 | |
73 | && refclk1 != SERDES_REFCLK_156_25) { | |
74 | debug("refclk1 should be 100MHZ, 122.88MHz, 125MHz" | |
75 | " or 156.25MHz.\n"); | |
76 | return -1; | |
77 | } | |
78 | ||
79 | if (refclk2 != SERDES_REFCLK_100 && refclk2 != SERDES_REFCLK_122_88 | |
80 | && refclk2 != SERDES_REFCLK_125 | |
81 | && refclk2 != SERDES_REFCLK_156_25) { | |
82 | debug("refclk2 should be 100MHZ, 122.88MHz, 125MHz" | |
83 | " or 156.25MHz.\n"); | |
84 | return -1; | |
85 | } | |
86 | ||
87 | if (feedback != 0 && feedback != 1) { | |
88 | debug("valid values for feedback are 0(default) or 1.\n"); | |
89 | return -1; | |
90 | } | |
91 | ||
92 | /* Configuring IDT for output refclks as | |
93 | * Refclk1 = 122.88MHz Refclk2 = 122.88MHz | |
94 | */ | |
95 | if (refclk1 == SERDES_REFCLK_122_88 && | |
96 | refclk2 == SERDES_REFCLK_122_88) { | |
97 | printf("Setting refclk1:122.88 and refclk2:122.88\n"); | |
98 | for (i = 0; i < NUM_IDT_REGS; i++) | |
99 | i2c_reg_write(idt_addr, idt_conf_122_88[i][0], | |
100 | idt_conf_122_88[i][1]); | |
101 | ||
102 | if (feedback) { | |
103 | for (i = 0; i < NUM_IDT_REGS_FEEDBACK; i++) | |
104 | i2c_reg_write(idt_addr, | |
105 | idt_conf_122_88_feedback[i][0], | |
106 | idt_conf_122_88_feedback[i][1]); | |
107 | } | |
108 | } | |
109 | ||
110 | if (refclk1 != SERDES_REFCLK_122_88 && | |
111 | refclk2 != SERDES_REFCLK_122_88) { | |
112 | for (i = 0; i < NUM_IDT_REGS; i++) | |
113 | i2c_reg_write(idt_addr, idt_conf_not_122_88[i][0], | |
114 | idt_conf_not_122_88[i][1]); | |
115 | } | |
116 | ||
117 | /* Configuring IDT for output refclks as | |
118 | * Refclk1 = 100MHz Refclk2 = 125MHz | |
119 | */ | |
120 | if (refclk1 == SERDES_REFCLK_100 && refclk2 == SERDES_REFCLK_125) { | |
121 | printf("Setting refclk1:100 and refclk2:125\n"); | |
122 | i2c_reg_write(idt_addr, 0x11, 0x10); | |
123 | } | |
124 | ||
125 | /* Configuring IDT for output refclks as | |
126 | * Refclk1 = 125MHz Refclk2 = 125MHz | |
127 | */ | |
128 | if (refclk1 == SERDES_REFCLK_125 && refclk2 == SERDES_REFCLK_125) { | |
129 | printf("Setting refclk1:125 and refclk2:125\n"); | |
130 | i2c_reg_write(idt_addr, 0x10, 0x10); | |
131 | i2c_reg_write(idt_addr, 0x11, 0x10); | |
132 | } | |
133 | ||
134 | /* Configuring IDT for output refclks as | |
135 | * Refclk1 = 125MHz Refclk2 = 100MHz | |
136 | */ | |
137 | if (refclk1 == SERDES_REFCLK_125 && refclk2 == SERDES_REFCLK_100) { | |
138 | printf("Setting refclk1:125 and refclk2:100\n"); | |
139 | i2c_reg_write(idt_addr, 0x10, 0x10); | |
140 | } | |
141 | ||
142 | /* Configuring IDT for output refclks as | |
143 | * Refclk1 = 156.25MHz Refclk2 = 156.25MHz | |
144 | */ | |
145 | if (refclk1 == SERDES_REFCLK_156_25 && | |
146 | refclk2 == SERDES_REFCLK_156_25) { | |
147 | printf("Setting refclk1:156.25 and refclk2:156.25\n"); | |
148 | for (i = 0; i < NUM_IDT_REGS_156_25; i++) | |
149 | i2c_reg_write(idt_addr, idt_conf_156_25[i][0], | |
150 | idt_conf_156_25[i][1]); | |
151 | } | |
152 | ||
153 | /* Configuring IDT for output refclks as | |
154 | * Refclk1 = 100MHz Refclk2 = 156.25MHz | |
155 | */ | |
156 | if (refclk1 == SERDES_REFCLK_100 && | |
157 | refclk2 == SERDES_REFCLK_156_25) { | |
158 | printf("Setting refclk1:100 and refclk2:156.25\n"); | |
159 | for (i = 0; i < NUM_IDT_REGS_156_25; i++) | |
160 | i2c_reg_write(idt_addr, idt_conf_100_156_25[i][0], | |
161 | idt_conf_100_156_25[i][1]); | |
162 | } | |
163 | ||
164 | /* Configuring IDT for output refclks as | |
165 | * Refclk1 = 125MHz Refclk2 = 156.25MHz | |
166 | */ | |
167 | if (refclk1 == SERDES_REFCLK_125 && | |
168 | refclk2 == SERDES_REFCLK_156_25) { | |
169 | printf("Setting refclk1:125 and refclk2:156.25\n"); | |
170 | for (i = 0; i < NUM_IDT_REGS_156_25; i++) | |
171 | i2c_reg_write(idt_addr, idt_conf_125_156_25[i][0], | |
172 | idt_conf_125_156_25[i][1]); | |
173 | } | |
174 | ||
175 | /* Configuring IDT for output refclks as | |
176 | * Refclk1 = 156.25MHz Refclk2 = 100MHz | |
177 | */ | |
178 | if (refclk1 == SERDES_REFCLK_156_25 && | |
179 | refclk2 == SERDES_REFCLK_100) { | |
180 | printf("Setting refclk1:156.25 and refclk2:100\n"); | |
181 | for (i = 0; i < NUM_IDT_REGS_156_25; i++) | |
182 | i2c_reg_write(idt_addr, idt_conf_156_25_100[i][0], | |
183 | idt_conf_156_25_100[i][1]); | |
184 | } | |
185 | ||
186 | /* Configuring IDT for output refclks as | |
187 | * Refclk1 = 156.25MHz Refclk2 = 125MHz | |
188 | */ | |
189 | if (refclk1 == SERDES_REFCLK_156_25 && | |
190 | refclk2 == SERDES_REFCLK_125) { | |
191 | printf("Setting refclk1:156.25 and refclk2:125\n"); | |
192 | for (i = 0; i < NUM_IDT_REGS_156_25; i++) | |
193 | i2c_reg_write(idt_addr, idt_conf_156_25_125[i][0], | |
194 | idt_conf_156_25_125[i][1]); | |
195 | } | |
196 | ||
197 | /* waiting for maximum of 1 second if PLL doesn'r get locked | |
198 | * initially. then check the status again. | |
199 | */ | |
200 | if (check_pll_status(idt_addr)) { | |
201 | mdelay(1000); | |
202 | if (check_pll_status(idt_addr)) | |
203 | return -1; | |
204 | } | |
205 | ||
206 | return 0; | |
207 | } |