1 // SPDX-License-Identifier: GPL-2.0+
3 * Copyright 2012 Freescale Semiconductor, Inc.
7 #include "vsc3316_3308.h"
9 #define REVISION_ID_REG 0x7E
10 #define INTERFACE_MODE_REG 0x79
11 #define CURRENT_PAGE_REGISTER 0x7F
12 #define CONNECTION_CONFIG_PAGE 0x00
13 #define INPUT_STATE_REG 0x13
14 #define GLOBAL_INPUT_ISE1 0x51
15 #define GLOBAL_INPUT_ISE2 0x52
16 #define GLOBAL_INPUT_GAIN 0x53
17 #define GLOBAL_INPUT_LOS 0x55
18 #define GLOBAL_OUTPUT_PE1 0x56
19 #define GLOBAL_OUTPUT_PE2 0x57
20 #define GLOBAL_OUTPUT_LEVEL 0x58
21 #define GLOBAL_OUTPUT_TERMINATION 0x5A
22 #define GLOBAL_CORE_CNTRL 0x5D
23 #define OUTPUT_MODE_PAGE 0x23
24 #define CORE_CONTROL_PAGE 0x25
25 #define CORE_CONFIG_REG 0x75
27 int vsc_if_enable(unsigned int vsc_addr)
31 debug("VSC:Configuring VSC at I2C address 0x%2x"
32 " for 2-wire interface\n", vsc_addr);
34 /* enable 2-wire Serial InterFace (I2C) */
40 ret = i2c_get_chip_for_busnum(bus_num, vsc_addr,
43 printf("%s: Cannot find udev for a bus %d\n", __func__,
48 return dm_i2c_write(dev, INTERFACE_MODE_REG, &data, 1);
50 return i2c_write(vsc_addr, INTERFACE_MODE_REG, 1, &data, 1);
54 int vsc3316_config(unsigned int vsc_addr, int8_t con_arr[][2],
61 debug("VSC:Initializing VSC3316 at I2C address 0x%2x"
62 " for Tx\n", vsc_addr);
68 ret = i2c_get_chip_for_busnum(bus_num, vsc_addr,
71 printf("%s: Cannot find udev for a bus %d\n", __func__,
76 ret = dm_i2c_read(dev, REVISION_ID_REG, &rev_id, 1);
78 printf("VSC:0x%x could not read REV_ID from device.\n",
84 printf("VSC: device at address 0x%x is not VSC3316/3308.\n",
89 ret = vsc_if_enable(vsc_addr);
91 printf("VSC:0x%x could not configured for 2-wire I/F.\n",
96 /* config connections - page 0x00 */
97 dm_i2c_reg_write(dev, CURRENT_PAGE_REGISTER, CONNECTION_CONFIG_PAGE);
99 /* Making crosspoint connections, by connecting required
102 for (i = 0; i < num_con ; i++)
103 dm_i2c_reg_write(dev, con_arr[i][1], con_arr[i][0]);
105 /* input state - page 0x13 */
106 dm_i2c_reg_write(dev, CURRENT_PAGE_REGISTER, INPUT_STATE_REG);
107 /* Configuring the required input of the switch */
108 for (i = 0; i < num_con ; i++)
109 dm_i2c_reg_write(dev, con_arr[i][0], 0x80);
111 /* Setting Global Input LOS threshold value */
112 dm_i2c_reg_write(dev, GLOBAL_INPUT_LOS, 0x60);
114 /* config output mode - page 0x23 */
115 dm_i2c_reg_write(dev, CURRENT_PAGE_REGISTER, OUTPUT_MODE_PAGE);
116 /* Turn ON the Output driver correspond to required output*/
117 for (i = 0; i < num_con ; i++)
118 dm_i2c_reg_write(dev, con_arr[i][1], 0);
120 /* configure global core control register, Turn on Global core power */
121 dm_i2c_reg_write(dev, GLOBAL_CORE_CNTRL, 0);
124 ret = i2c_read(vsc_addr, REVISION_ID_REG, 1, &rev_id, 1);
126 printf("VSC:0x%x could not read REV_ID from device.\n",
131 if (rev_id != 0xab) {
132 printf("VSC: device at address 0x%x is not VSC3316/3308.\n",
137 ret = vsc_if_enable(vsc_addr);
139 printf("VSC:0x%x could not configured for 2-wire I/F.\n",
144 /* config connections - page 0x00 */
145 i2c_reg_write(vsc_addr, CURRENT_PAGE_REGISTER, CONNECTION_CONFIG_PAGE);
147 /* Making crosspoint connections, by connecting required
149 for (i = 0; i < num_con ; i++)
150 i2c_reg_write(vsc_addr, con_arr[i][1], con_arr[i][0]);
152 /* input state - page 0x13 */
153 i2c_reg_write(vsc_addr, CURRENT_PAGE_REGISTER, INPUT_STATE_REG);
154 /* Configuring the required input of the switch */
155 for (i = 0; i < num_con ; i++)
156 i2c_reg_write(vsc_addr, con_arr[i][0], 0x80);
158 /* Setting Global Input LOS threshold value */
159 i2c_reg_write(vsc_addr, GLOBAL_INPUT_LOS, 0x60);
161 /* config output mode - page 0x23 */
162 i2c_reg_write(vsc_addr, CURRENT_PAGE_REGISTER, OUTPUT_MODE_PAGE);
163 /* Turn ON the Output driver correspond to required output*/
164 for (i = 0; i < num_con ; i++)
165 i2c_reg_write(vsc_addr, con_arr[i][1], 0);
167 /* configure global core control register, Turn on Global core power */
168 i2c_reg_write(vsc_addr, GLOBAL_CORE_CNTRL, 0);
171 vsc_wp_config(vsc_addr);
176 #ifdef CONFIG_SYS_FSL_B4860QDS_XFI_ERR
177 int vsc3308_config_adjust(unsigned int vsc_addr, const int8_t con_arr[][2],
178 unsigned int num_con)
184 debug("VSC:Initializing VSC3308 at I2C address 0x%x for Tx\n",
191 ret = i2c_get_chip_for_busnum(bus_num, vsc_addr,
194 printf("%s: Cannot find udev for a bus %d\n", __func__,
199 ret = dm_i2c_read(dev, REVISION_ID_REG, &rev_id, 1);
201 printf("VSC:0x%x could not read REV_ID from device.\n",
206 if (rev_id != 0xab) {
207 printf("VSC: device at address 0x%x is not VSC3316/3308.\n",
212 ret = vsc_if_enable(vsc_addr);
214 printf("VSC:0x%x could not configured for 2-wire I/F.\n",
219 /* config connections - page 0x00 */
220 dm_i2c_reg_write(dev, CURRENT_PAGE_REGISTER, CONNECTION_CONFIG_PAGE);
222 /* Configure Global Input ISE */
223 dm_i2c_reg_write(dev, GLOBAL_INPUT_ISE1, 0);
224 dm_i2c_reg_write(dev, GLOBAL_INPUT_ISE2, 0);
226 /* Configure Tx/Rx Global Output PE1 */
227 dm_i2c_reg_write(dev, GLOBAL_OUTPUT_PE1, 0);
229 /* Configure Tx/Rx Global Output PE2 */
230 dm_i2c_reg_write(dev, GLOBAL_OUTPUT_PE2, 0);
232 /* Configure Tx/Rx Global Input GAIN */
233 dm_i2c_reg_write(dev, GLOBAL_INPUT_GAIN, 0x3F);
235 /* Setting Global Input LOS threshold value */
236 dm_i2c_reg_write(dev, GLOBAL_INPUT_LOS, 0xE0);
238 /* Setting Global output termination */
239 dm_i2c_reg_write(dev, GLOBAL_OUTPUT_TERMINATION, 0);
241 /* Configure Tx/Rx Global Output level */
242 if (vsc_addr == VSC3308_TX_ADDRESS)
243 dm_i2c_reg_write(dev, GLOBAL_OUTPUT_LEVEL, 4);
245 dm_i2c_reg_write(dev, GLOBAL_OUTPUT_LEVEL, 2);
247 /* Making crosspoint connections, by connecting required
250 for (i = 0; i < num_con ; i++)
251 dm_i2c_reg_write(dev, con_arr[i][1], con_arr[i][0]);
253 /* input state - page 0x13 */
254 dm_i2c_reg_write(dev, CURRENT_PAGE_REGISTER, INPUT_STATE_REG);
255 /* Turning off all the required input of the switch */
256 for (i = 0; i < num_con; i++)
257 dm_i2c_reg_write(dev, con_arr[i][0], 1);
259 /* only turn on specific Tx/Rx requested by the XFI erratum */
260 if (vsc_addr == VSC3308_TX_ADDRESS) {
261 dm_i2c_reg_write(dev, 2, 0);
262 dm_i2c_reg_write(dev, 3, 0);
264 dm_i2c_reg_write(dev, 0, 0);
265 dm_i2c_reg_write(dev, 1, 0);
268 /* config output mode - page 0x23 */
269 dm_i2c_reg_write(dev, CURRENT_PAGE_REGISTER, OUTPUT_MODE_PAGE);
270 /* Turn off the Output driver correspond to required output*/
271 for (i = 0; i < num_con ; i++)
272 dm_i2c_reg_write(dev, con_arr[i][1], 1);
274 /* only turn on specific Tx/Rx requested by the XFI erratum */
275 if (vsc_addr == VSC3308_TX_ADDRESS) {
276 dm_i2c_reg_write(dev, 0, 0);
277 dm_i2c_reg_write(dev, 1, 0);
279 dm_i2c_reg_write(dev, 3, 0);
280 dm_i2c_reg_write(dev, 4, 0);
283 /* configure global core control register, Turn on Global core power */
284 dm_i2c_reg_write(dev, GLOBAL_CORE_CNTRL, 0);
286 ret = i2c_read(vsc_addr, REVISION_ID_REG, 1, &rev_id, 1);
288 printf("VSC:0x%x could not read REV_ID from device.\n",
293 if (rev_id != 0xab) {
294 printf("VSC: device at address 0x%x is not VSC3316/3308.\n",
299 ret = vsc_if_enable(vsc_addr);
301 printf("VSC:0x%x could not configured for 2-wire I/F.\n",
306 /* config connections - page 0x00 */
307 i2c_reg_write(vsc_addr, CURRENT_PAGE_REGISTER, CONNECTION_CONFIG_PAGE);
309 /* Configure Global Input ISE */
310 i2c_reg_write(vsc_addr, GLOBAL_INPUT_ISE1, 0);
311 i2c_reg_write(vsc_addr, GLOBAL_INPUT_ISE2, 0);
313 /* Configure Tx/Rx Global Output PE1 */
314 i2c_reg_write(vsc_addr, GLOBAL_OUTPUT_PE1, 0);
316 /* Configure Tx/Rx Global Output PE2 */
317 i2c_reg_write(vsc_addr, GLOBAL_OUTPUT_PE2, 0);
319 /* Configure Tx/Rx Global Input GAIN */
320 i2c_reg_write(vsc_addr, GLOBAL_INPUT_GAIN, 0x3F);
322 /* Setting Global Input LOS threshold value */
323 i2c_reg_write(vsc_addr, GLOBAL_INPUT_LOS, 0xE0);
325 /* Setting Global output termination */
326 i2c_reg_write(vsc_addr, GLOBAL_OUTPUT_TERMINATION, 0);
328 /* Configure Tx/Rx Global Output level */
329 if (vsc_addr == VSC3308_TX_ADDRESS)
330 i2c_reg_write(vsc_addr, GLOBAL_OUTPUT_LEVEL, 4);
332 i2c_reg_write(vsc_addr, GLOBAL_OUTPUT_LEVEL, 2);
334 /* Making crosspoint connections, by connecting required
336 for (i = 0; i < num_con ; i++)
337 i2c_reg_write(vsc_addr, con_arr[i][1], con_arr[i][0]);
339 /* input state - page 0x13 */
340 i2c_reg_write(vsc_addr, CURRENT_PAGE_REGISTER, INPUT_STATE_REG);
341 /* Turning off all the required input of the switch */
342 for (i = 0; i < num_con; i++)
343 i2c_reg_write(vsc_addr, con_arr[i][0], 1);
345 /* only turn on specific Tx/Rx requested by the XFI erratum */
346 if (vsc_addr == VSC3308_TX_ADDRESS) {
347 i2c_reg_write(vsc_addr, 2, 0);
348 i2c_reg_write(vsc_addr, 3, 0);
350 i2c_reg_write(vsc_addr, 0, 0);
351 i2c_reg_write(vsc_addr, 1, 0);
354 /* config output mode - page 0x23 */
355 i2c_reg_write(vsc_addr, CURRENT_PAGE_REGISTER, OUTPUT_MODE_PAGE);
356 /* Turn off the Output driver correspond to required output*/
357 for (i = 0; i < num_con ; i++)
358 i2c_reg_write(vsc_addr, con_arr[i][1], 1);
360 /* only turn on specific Tx/Rx requested by the XFI erratum */
361 if (vsc_addr == VSC3308_TX_ADDRESS) {
362 i2c_reg_write(vsc_addr, 0, 0);
363 i2c_reg_write(vsc_addr, 1, 0);
365 i2c_reg_write(vsc_addr, 3, 0);
366 i2c_reg_write(vsc_addr, 4, 0);
369 /* configure global core control register, Turn on Global core power */
370 i2c_reg_write(vsc_addr, GLOBAL_CORE_CNTRL, 0);
372 vsc_wp_config(vsc_addr);
378 int vsc3308_config(unsigned int vsc_addr, const int8_t con_arr[][2],
379 unsigned int num_con)
385 debug("VSC:Initializing VSC3308 at I2C address 0x%x"
386 " for Tx\n", vsc_addr);
391 ret = i2c_get_chip_for_busnum(bus_num, vsc_addr,
394 printf("%s: Cannot find udev for a bus %d\n", __func__,
399 ret = dm_i2c_read(dev, REVISION_ID_REG, &rev_id, 1);
401 printf("VSC:0x%x could not read REV_ID from device.\n",
406 if (rev_id != 0xab) {
407 printf("VSC: device at address 0x%x is not VSC3316/3308.\n",
412 ret = vsc_if_enable(vsc_addr);
414 printf("VSC:0x%x could not configured for 2-wire I/F.\n",
419 /* config connections - page 0x00 */
420 dm_i2c_reg_write(dev, CURRENT_PAGE_REGISTER, CONNECTION_CONFIG_PAGE);
422 /* Making crosspoint connections, by connecting required
425 for (i = 0; i < num_con ; i++)
426 dm_i2c_reg_write(dev, con_arr[i][1], con_arr[i][0]);
428 /*Configure Global Input ISE and gain */
429 dm_i2c_reg_write(dev, GLOBAL_INPUT_ISE1, 0x12);
430 dm_i2c_reg_write(dev, GLOBAL_INPUT_ISE2, 0x12);
432 /* input state - page 0x13 */
433 dm_i2c_reg_write(dev, CURRENT_PAGE_REGISTER, INPUT_STATE_REG);
434 /* Turning ON the required input of the switch */
435 for (i = 0; i < num_con ; i++)
436 dm_i2c_reg_write(dev, con_arr[i][0], 0);
438 /* Setting Global Input LOS threshold value */
439 dm_i2c_reg_write(dev, GLOBAL_INPUT_LOS, 0x60);
441 /* config output mode - page 0x23 */
442 dm_i2c_reg_write(dev, CURRENT_PAGE_REGISTER, OUTPUT_MODE_PAGE);
443 /* Turn ON the Output driver correspond to required output*/
444 for (i = 0; i < num_con ; i++)
445 dm_i2c_reg_write(dev, con_arr[i][1], 0);
447 /* configure global core control register, Turn on Global core power */
448 dm_i2c_reg_write(dev, GLOBAL_CORE_CNTRL, 0);
450 ret = i2c_read(vsc_addr, REVISION_ID_REG, 1, &rev_id, 1);
452 printf("VSC:0x%x could not read REV_ID from device.\n",
457 if (rev_id != 0xab) {
458 printf("VSC: device at address 0x%x is not VSC3316/3308.\n",
463 ret = vsc_if_enable(vsc_addr);
465 printf("VSC:0x%x could not configured for 2-wire I/F.\n",
470 /* config connections - page 0x00 */
471 i2c_reg_write(vsc_addr, CURRENT_PAGE_REGISTER, CONNECTION_CONFIG_PAGE);
473 /* Making crosspoint connections, by connecting required
475 for (i = 0; i < num_con ; i++)
476 i2c_reg_write(vsc_addr, con_arr[i][1], con_arr[i][0]);
478 /*Configure Global Input ISE and gain */
479 i2c_reg_write(vsc_addr, GLOBAL_INPUT_ISE1, 0x12);
480 i2c_reg_write(vsc_addr, GLOBAL_INPUT_ISE2, 0x12);
482 /* input state - page 0x13 */
483 i2c_reg_write(vsc_addr, CURRENT_PAGE_REGISTER, INPUT_STATE_REG);
484 /* Turning ON the required input of the switch */
485 for (i = 0; i < num_con ; i++)
486 i2c_reg_write(vsc_addr, con_arr[i][0], 0);
488 /* Setting Global Input LOS threshold value */
489 i2c_reg_write(vsc_addr, GLOBAL_INPUT_LOS, 0x60);
491 /* config output mode - page 0x23 */
492 i2c_reg_write(vsc_addr, CURRENT_PAGE_REGISTER, OUTPUT_MODE_PAGE);
493 /* Turn ON the Output driver correspond to required output*/
494 for (i = 0; i < num_con ; i++)
495 i2c_reg_write(vsc_addr, con_arr[i][1], 0);
497 /* configure global core control register, Turn on Global core power */
498 i2c_reg_write(vsc_addr, GLOBAL_CORE_CNTRL, 0);
500 vsc_wp_config(vsc_addr);
505 void vsc_wp_config(unsigned int vsc_addr)
507 debug("VSC:Configuring VSC at address:0x%x for WP\n", vsc_addr);
509 /* For new crosspoint configuration to occur, WP bit of
510 * CORE_CONFIG_REG should be set 1 and then reset to 0 */
512 int ret, bus_num = 0;
515 ret = i2c_get_chip_for_busnum(bus_num, vsc_addr,
518 printf("%s: Cannot find udev for a bus %d\n", __func__,
523 dm_i2c_reg_write(dev, CORE_CONFIG_REG, 0x01);
524 dm_i2c_reg_write(dev, CORE_CONFIG_REG, 0x0);
526 i2c_reg_write(vsc_addr, CORE_CONFIG_REG, 0x01);
527 i2c_reg_write(vsc_addr, CORE_CONFIG_REG, 0x0);