1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3 * Copyright 2012 Freescale Semiconductor, Inc.
4 */
5
6 #include "vsc3316_3308.h"
7
8 #define REVISION_ID_REG 0x7E
9 #define INTERFACE_MODE_REG 0x79
10 #define CURRENT_PAGE_REGISTER 0x7F
11 #define CONNECTION_CONFIG_PAGE 0x00
12 #define INPUT_STATE_REG 0x13
13 #define GLOBAL_INPUT_ISE1 0x51
14 #define GLOBAL_INPUT_ISE2 0x52
15 #define GLOBAL_INPUT_GAIN 0x53
16 #define GLOBAL_INPUT_LOS 0x55
17 #define GLOBAL_OUTPUT_PE1 0x56
18 #define GLOBAL_OUTPUT_PE2 0x57
19 #define GLOBAL_OUTPUT_LEVEL 0x58
20 #define GLOBAL_OUTPUT_TERMINATION 0x5A
21 #define GLOBAL_CORE_CNTRL 0x5D
22 #define OUTPUT_MODE_PAGE 0x23
23 #define CORE_CONTROL_PAGE 0x25
24 #define CORE_CONFIG_REG 0x75
25
vsc_if_enable(unsigned int vsc_addr)26 int vsc_if_enable(unsigned int vsc_addr)
27 {
28 u8 data;
29
30 debug("VSC:Configuring VSC at I2C address 0x%2x"
31 " for 2-wire interface\n", vsc_addr);
32
33 /* enable 2-wire Serial InterFace (I2C) */
34 data = 0x02;
35 return i2c_write(vsc_addr, INTERFACE_MODE_REG, 1, &data, 1);
36 }
37
vsc3316_config(unsigned int vsc_addr,int8_t con_arr[][2],unsigned int num_con)38 int vsc3316_config(unsigned int vsc_addr, int8_t con_arr[][2],
39 unsigned int num_con)
40 {
41 unsigned int i;
42 u8 rev_id = 0;
43 int ret;
44
45 debug("VSC:Initializing VSC3316 at I2C address 0x%2x"
46 " for Tx\n", vsc_addr);
47
48 ret = i2c_read(vsc_addr, REVISION_ID_REG, 1, &rev_id, 1);
49 if (ret < 0) {
50 printf("VSC:0x%x could not read REV_ID from device.\n",
51 vsc_addr);
52 return ret;
53 }
54
55 if (rev_id != 0xab) {
56 printf("VSC: device at address 0x%x is not VSC3316/3308.\n",
57 vsc_addr);
58 return -ENODEV;
59 }
60
61 ret = vsc_if_enable(vsc_addr);
62 if (ret) {
63 printf("VSC:0x%x could not configured for 2-wire I/F.\n",
64 vsc_addr);
65 return ret;
66 }
67
68 /* config connections - page 0x00 */
69 i2c_reg_write(vsc_addr, CURRENT_PAGE_REGISTER, CONNECTION_CONFIG_PAGE);
70
71 /* Making crosspoint connections, by connecting required
72 * input to output */
73 for (i = 0; i < num_con ; i++)
74 i2c_reg_write(vsc_addr, con_arr[i][1], con_arr[i][0]);
75
76 /* input state - page 0x13 */
77 i2c_reg_write(vsc_addr, CURRENT_PAGE_REGISTER, INPUT_STATE_REG);
78 /* Configuring the required input of the switch */
79 for (i = 0; i < num_con ; i++)
80 i2c_reg_write(vsc_addr, con_arr[i][0], 0x80);
81
82 /* Setting Global Input LOS threshold value */
83 i2c_reg_write(vsc_addr, GLOBAL_INPUT_LOS, 0x60);
84
85 /* config output mode - page 0x23 */
86 i2c_reg_write(vsc_addr, CURRENT_PAGE_REGISTER, OUTPUT_MODE_PAGE);
87 /* Turn ON the Output driver correspond to required output*/
88 for (i = 0; i < num_con ; i++)
89 i2c_reg_write(vsc_addr, con_arr[i][1], 0);
90
91 /* configure global core control register, Turn on Global core power */
92 i2c_reg_write(vsc_addr, GLOBAL_CORE_CNTRL, 0);
93
94 vsc_wp_config(vsc_addr);
95
96 return 0;
97 }
98
99 #ifdef CONFIG_SYS_FSL_B4860QDS_XFI_ERR
vsc3308_config_adjust(unsigned int vsc_addr,const int8_t con_arr[][2],unsigned int num_con)100 int vsc3308_config_adjust(unsigned int vsc_addr, const int8_t con_arr[][2],
101 unsigned int num_con)
102 {
103 unsigned int i;
104 u8 rev_id = 0;
105 int ret;
106
107 debug("VSC:Initializing VSC3308 at I2C address 0x%x for Tx\n",
108 vsc_addr);
109
110 ret = i2c_read(vsc_addr, REVISION_ID_REG, 1, &rev_id, 1);
111 if (ret < 0) {
112 printf("VSC:0x%x could not read REV_ID from device.\n",
113 vsc_addr);
114 return ret;
115 }
116
117 if (rev_id != 0xab) {
118 printf("VSC: device at address 0x%x is not VSC3316/3308.\n",
119 vsc_addr);
120 return -ENODEV;
121 }
122
123 ret = vsc_if_enable(vsc_addr);
124 if (ret) {
125 printf("VSC:0x%x could not configured for 2-wire I/F.\n",
126 vsc_addr);
127 return ret;
128 }
129
130 /* config connections - page 0x00 */
131 i2c_reg_write(vsc_addr, CURRENT_PAGE_REGISTER, CONNECTION_CONFIG_PAGE);
132
133 /* Configure Global Input ISE */
134 i2c_reg_write(vsc_addr, GLOBAL_INPUT_ISE1, 0);
135 i2c_reg_write(vsc_addr, GLOBAL_INPUT_ISE2, 0);
136
137 /* Configure Tx/Rx Global Output PE1 */
138 i2c_reg_write(vsc_addr, GLOBAL_OUTPUT_PE1, 0);
139
140 /* Configure Tx/Rx Global Output PE2 */
141 i2c_reg_write(vsc_addr, GLOBAL_OUTPUT_PE2, 0);
142
143 /* Configure Tx/Rx Global Input GAIN */
144 i2c_reg_write(vsc_addr, GLOBAL_INPUT_GAIN, 0x3F);
145
146 /* Setting Global Input LOS threshold value */
147 i2c_reg_write(vsc_addr, GLOBAL_INPUT_LOS, 0xE0);
148
149 /* Setting Global output termination */
150 i2c_reg_write(vsc_addr, GLOBAL_OUTPUT_TERMINATION, 0);
151
152 /* Configure Tx/Rx Global Output level */
153 if (vsc_addr == VSC3308_TX_ADDRESS)
154 i2c_reg_write(vsc_addr, GLOBAL_OUTPUT_LEVEL, 4);
155 else
156 i2c_reg_write(vsc_addr, GLOBAL_OUTPUT_LEVEL, 2);
157
158 /* Making crosspoint connections, by connecting required
159 * input to output */
160 for (i = 0; i < num_con ; i++)
161 i2c_reg_write(vsc_addr, con_arr[i][1], con_arr[i][0]);
162
163 /* input state - page 0x13 */
164 i2c_reg_write(vsc_addr, CURRENT_PAGE_REGISTER, INPUT_STATE_REG);
165 /* Turning off all the required input of the switch */
166 for (i = 0; i < num_con; i++)
167 i2c_reg_write(vsc_addr, con_arr[i][0], 1);
168
169 /* only turn on specific Tx/Rx requested by the XFI erratum */
170 if (vsc_addr == VSC3308_TX_ADDRESS) {
171 i2c_reg_write(vsc_addr, 2, 0);
172 i2c_reg_write(vsc_addr, 3, 0);
173 } else {
174 i2c_reg_write(vsc_addr, 0, 0);
175 i2c_reg_write(vsc_addr, 1, 0);
176 }
177
178 /* config output mode - page 0x23 */
179 i2c_reg_write(vsc_addr, CURRENT_PAGE_REGISTER, OUTPUT_MODE_PAGE);
180 /* Turn off the Output driver correspond to required output*/
181 for (i = 0; i < num_con ; i++)
182 i2c_reg_write(vsc_addr, con_arr[i][1], 1);
183
184 /* only turn on specific Tx/Rx requested by the XFI erratum */
185 if (vsc_addr == VSC3308_TX_ADDRESS) {
186 i2c_reg_write(vsc_addr, 0, 0);
187 i2c_reg_write(vsc_addr, 1, 0);
188 } else {
189 i2c_reg_write(vsc_addr, 3, 0);
190 i2c_reg_write(vsc_addr, 4, 0);
191 }
192
193 /* configure global core control register, Turn on Global core power */
194 i2c_reg_write(vsc_addr, GLOBAL_CORE_CNTRL, 0);
195
196 vsc_wp_config(vsc_addr);
197
198 return 0;
199 }
200 #endif
201
vsc3308_config(unsigned int vsc_addr,const int8_t con_arr[][2],unsigned int num_con)202 int vsc3308_config(unsigned int vsc_addr, const int8_t con_arr[][2],
203 unsigned int num_con)
204 {
205 unsigned int i;
206 u8 rev_id = 0;
207 int ret;
208
209 debug("VSC:Initializing VSC3308 at I2C address 0x%x"
210 " for Tx\n", vsc_addr);
211
212 ret = i2c_read(vsc_addr, REVISION_ID_REG, 1, &rev_id, 1);
213 if (ret < 0) {
214 printf("VSC:0x%x could not read REV_ID from device.\n",
215 vsc_addr);
216 return ret;
217 }
218
219 if (rev_id != 0xab) {
220 printf("VSC: device at address 0x%x is not VSC3316/3308.\n",
221 vsc_addr);
222 return -ENODEV;
223 }
224
225 ret = vsc_if_enable(vsc_addr);
226 if (ret) {
227 printf("VSC:0x%x could not configured for 2-wire I/F.\n",
228 vsc_addr);
229 return ret;
230 }
231
232 /* config connections - page 0x00 */
233 i2c_reg_write(vsc_addr, CURRENT_PAGE_REGISTER, CONNECTION_CONFIG_PAGE);
234
235 /* Making crosspoint connections, by connecting required
236 * input to output */
237 for (i = 0; i < num_con ; i++)
238 i2c_reg_write(vsc_addr, con_arr[i][1], con_arr[i][0]);
239
240 /*Configure Global Input ISE and gain */
241 i2c_reg_write(vsc_addr, GLOBAL_INPUT_ISE1, 0x12);
242 i2c_reg_write(vsc_addr, GLOBAL_INPUT_ISE2, 0x12);
243
244 /* input state - page 0x13 */
245 i2c_reg_write(vsc_addr, CURRENT_PAGE_REGISTER, INPUT_STATE_REG);
246 /* Turning ON the required input of the switch */
247 for (i = 0; i < num_con ; i++)
248 i2c_reg_write(vsc_addr, con_arr[i][0], 0);
249
250 /* Setting Global Input LOS threshold value */
251 i2c_reg_write(vsc_addr, GLOBAL_INPUT_LOS, 0x60);
252
253 /* config output mode - page 0x23 */
254 i2c_reg_write(vsc_addr, CURRENT_PAGE_REGISTER, OUTPUT_MODE_PAGE);
255 /* Turn ON the Output driver correspond to required output*/
256 for (i = 0; i < num_con ; i++)
257 i2c_reg_write(vsc_addr, con_arr[i][1], 0);
258
259 /* configure global core control register, Turn on Global core power */
260 i2c_reg_write(vsc_addr, GLOBAL_CORE_CNTRL, 0);
261
262 vsc_wp_config(vsc_addr);
263
264 return 0;
265 }
266
vsc_wp_config(unsigned int vsc_addr)267 void vsc_wp_config(unsigned int vsc_addr)
268 {
269 debug("VSC:Configuring VSC at address:0x%x for WP\n", vsc_addr);
270
271 /* For new crosspoint configuration to occur, WP bit of
272 * CORE_CONFIG_REG should be set 1 and then reset to 0 */
273 i2c_reg_write(vsc_addr, CORE_CONFIG_REG, 0x01);
274 i2c_reg_write(vsc_addr, CORE_CONFIG_REG, 0x0);
275 }
276