1 // SPDX-License-Identifier: GPL-2.0+
3 * Copyright 2012 Freescale Semiconductor, Inc.
7 #include "vsc3316_3308.h"
10 #define REVISION_ID_REG 0x7E
11 #define INTERFACE_MODE_REG 0x79
12 #define CURRENT_PAGE_REGISTER 0x7F
13 #define CONNECTION_CONFIG_PAGE 0x00
14 #define INPUT_STATE_REG 0x13
15 #define GLOBAL_INPUT_ISE1 0x51
16 #define GLOBAL_INPUT_ISE2 0x52
17 #define GLOBAL_INPUT_GAIN 0x53
18 #define GLOBAL_INPUT_LOS 0x55
19 #define GLOBAL_OUTPUT_PE1 0x56
20 #define GLOBAL_OUTPUT_PE2 0x57
21 #define GLOBAL_OUTPUT_LEVEL 0x58
22 #define GLOBAL_OUTPUT_TERMINATION 0x5A
23 #define GLOBAL_CORE_CNTRL 0x5D
24 #define OUTPUT_MODE_PAGE 0x23
25 #define CORE_CONTROL_PAGE 0x25
26 #define CORE_CONFIG_REG 0x75
28 int vsc_if_enable(unsigned int vsc_addr)
32 debug("VSC:Configuring VSC at I2C address 0x%2x"
33 " for 2-wire interface\n", vsc_addr);
35 /* enable 2-wire Serial InterFace (I2C) */
41 ret = i2c_get_chip_for_busnum(bus_num, vsc_addr,
44 printf("%s: Cannot find udev for a bus %d\n", __func__,
49 return dm_i2c_write(dev, INTERFACE_MODE_REG, &data, 1);
51 return i2c_write(vsc_addr, INTERFACE_MODE_REG, 1, &data, 1);
55 int vsc3316_config(unsigned int vsc_addr, int8_t con_arr[][2],
62 debug("VSC:Initializing VSC3316 at I2C address 0x%2x"
63 " for Tx\n", vsc_addr);
69 ret = i2c_get_chip_for_busnum(bus_num, vsc_addr,
72 printf("%s: Cannot find udev for a bus %d\n", __func__,
77 ret = dm_i2c_read(dev, REVISION_ID_REG, &rev_id, 1);
79 printf("VSC:0x%x could not read REV_ID from device.\n",
85 printf("VSC: device at address 0x%x is not VSC3316/3308.\n",
90 ret = vsc_if_enable(vsc_addr);
92 printf("VSC:0x%x could not configured for 2-wire I/F.\n",
97 /* config connections - page 0x00 */
98 dm_i2c_reg_write(dev, CURRENT_PAGE_REGISTER, CONNECTION_CONFIG_PAGE);
100 /* Making crosspoint connections, by connecting required
103 for (i = 0; i < num_con ; i++)
104 dm_i2c_reg_write(dev, con_arr[i][1], con_arr[i][0]);
106 /* input state - page 0x13 */
107 dm_i2c_reg_write(dev, CURRENT_PAGE_REGISTER, INPUT_STATE_REG);
108 /* Configuring the required input of the switch */
109 for (i = 0; i < num_con ; i++)
110 dm_i2c_reg_write(dev, con_arr[i][0], 0x80);
112 /* Setting Global Input LOS threshold value */
113 dm_i2c_reg_write(dev, GLOBAL_INPUT_LOS, 0x60);
115 /* config output mode - page 0x23 */
116 dm_i2c_reg_write(dev, CURRENT_PAGE_REGISTER, OUTPUT_MODE_PAGE);
117 /* Turn ON the Output driver correspond to required output*/
118 for (i = 0; i < num_con ; i++)
119 dm_i2c_reg_write(dev, con_arr[i][1], 0);
121 /* configure global core control register, Turn on Global core power */
122 dm_i2c_reg_write(dev, GLOBAL_CORE_CNTRL, 0);
125 ret = i2c_read(vsc_addr, REVISION_ID_REG, 1, &rev_id, 1);
127 printf("VSC:0x%x could not read REV_ID from device.\n",
132 if (rev_id != 0xab) {
133 printf("VSC: device at address 0x%x is not VSC3316/3308.\n",
138 ret = vsc_if_enable(vsc_addr);
140 printf("VSC:0x%x could not configured for 2-wire I/F.\n",
145 /* config connections - page 0x00 */
146 i2c_reg_write(vsc_addr, CURRENT_PAGE_REGISTER, CONNECTION_CONFIG_PAGE);
148 /* Making crosspoint connections, by connecting required
150 for (i = 0; i < num_con ; i++)
151 i2c_reg_write(vsc_addr, con_arr[i][1], con_arr[i][0]);
153 /* input state - page 0x13 */
154 i2c_reg_write(vsc_addr, CURRENT_PAGE_REGISTER, INPUT_STATE_REG);
155 /* Configuring the required input of the switch */
156 for (i = 0; i < num_con ; i++)
157 i2c_reg_write(vsc_addr, con_arr[i][0], 0x80);
159 /* Setting Global Input LOS threshold value */
160 i2c_reg_write(vsc_addr, GLOBAL_INPUT_LOS, 0x60);
162 /* config output mode - page 0x23 */
163 i2c_reg_write(vsc_addr, CURRENT_PAGE_REGISTER, OUTPUT_MODE_PAGE);
164 /* Turn ON the Output driver correspond to required output*/
165 for (i = 0; i < num_con ; i++)
166 i2c_reg_write(vsc_addr, con_arr[i][1], 0);
168 /* configure global core control register, Turn on Global core power */
169 i2c_reg_write(vsc_addr, GLOBAL_CORE_CNTRL, 0);
172 vsc_wp_config(vsc_addr);
177 #ifdef CONFIG_SYS_FSL_B4860QDS_XFI_ERR
178 int vsc3308_config_adjust(unsigned int vsc_addr, const int8_t con_arr[][2],
179 unsigned int num_con)
185 debug("VSC:Initializing VSC3308 at I2C address 0x%x for Tx\n",
192 ret = i2c_get_chip_for_busnum(bus_num, vsc_addr,
195 printf("%s: Cannot find udev for a bus %d\n", __func__,
200 ret = dm_i2c_read(dev, REVISION_ID_REG, &rev_id, 1);
202 printf("VSC:0x%x could not read REV_ID from device.\n",
207 if (rev_id != 0xab) {
208 printf("VSC: device at address 0x%x is not VSC3316/3308.\n",
213 ret = vsc_if_enable(vsc_addr);
215 printf("VSC:0x%x could not configured for 2-wire I/F.\n",
220 /* config connections - page 0x00 */
221 dm_i2c_reg_write(dev, CURRENT_PAGE_REGISTER, CONNECTION_CONFIG_PAGE);
223 /* Configure Global Input ISE */
224 dm_i2c_reg_write(dev, GLOBAL_INPUT_ISE1, 0);
225 dm_i2c_reg_write(dev, GLOBAL_INPUT_ISE2, 0);
227 /* Configure Tx/Rx Global Output PE1 */
228 dm_i2c_reg_write(dev, GLOBAL_OUTPUT_PE1, 0);
230 /* Configure Tx/Rx Global Output PE2 */
231 dm_i2c_reg_write(dev, GLOBAL_OUTPUT_PE2, 0);
233 /* Configure Tx/Rx Global Input GAIN */
234 dm_i2c_reg_write(dev, GLOBAL_INPUT_GAIN, 0x3F);
236 /* Setting Global Input LOS threshold value */
237 dm_i2c_reg_write(dev, GLOBAL_INPUT_LOS, 0xE0);
239 /* Setting Global output termination */
240 dm_i2c_reg_write(dev, GLOBAL_OUTPUT_TERMINATION, 0);
242 /* Configure Tx/Rx Global Output level */
243 if (vsc_addr == VSC3308_TX_ADDRESS)
244 dm_i2c_reg_write(dev, GLOBAL_OUTPUT_LEVEL, 4);
246 dm_i2c_reg_write(dev, GLOBAL_OUTPUT_LEVEL, 2);
248 /* Making crosspoint connections, by connecting required
251 for (i = 0; i < num_con ; i++)
252 dm_i2c_reg_write(dev, con_arr[i][1], con_arr[i][0]);
254 /* input state - page 0x13 */
255 dm_i2c_reg_write(dev, CURRENT_PAGE_REGISTER, INPUT_STATE_REG);
256 /* Turning off all the required input of the switch */
257 for (i = 0; i < num_con; i++)
258 dm_i2c_reg_write(dev, con_arr[i][0], 1);
260 /* only turn on specific Tx/Rx requested by the XFI erratum */
261 if (vsc_addr == VSC3308_TX_ADDRESS) {
262 dm_i2c_reg_write(dev, 2, 0);
263 dm_i2c_reg_write(dev, 3, 0);
265 dm_i2c_reg_write(dev, 0, 0);
266 dm_i2c_reg_write(dev, 1, 0);
269 /* config output mode - page 0x23 */
270 dm_i2c_reg_write(dev, CURRENT_PAGE_REGISTER, OUTPUT_MODE_PAGE);
271 /* Turn off the Output driver correspond to required output*/
272 for (i = 0; i < num_con ; i++)
273 dm_i2c_reg_write(dev, con_arr[i][1], 1);
275 /* only turn on specific Tx/Rx requested by the XFI erratum */
276 if (vsc_addr == VSC3308_TX_ADDRESS) {
277 dm_i2c_reg_write(dev, 0, 0);
278 dm_i2c_reg_write(dev, 1, 0);
280 dm_i2c_reg_write(dev, 3, 0);
281 dm_i2c_reg_write(dev, 4, 0);
284 /* configure global core control register, Turn on Global core power */
285 dm_i2c_reg_write(dev, GLOBAL_CORE_CNTRL, 0);
287 ret = i2c_read(vsc_addr, REVISION_ID_REG, 1, &rev_id, 1);
289 printf("VSC:0x%x could not read REV_ID from device.\n",
294 if (rev_id != 0xab) {
295 printf("VSC: device at address 0x%x is not VSC3316/3308.\n",
300 ret = vsc_if_enable(vsc_addr);
302 printf("VSC:0x%x could not configured for 2-wire I/F.\n",
307 /* config connections - page 0x00 */
308 i2c_reg_write(vsc_addr, CURRENT_PAGE_REGISTER, CONNECTION_CONFIG_PAGE);
310 /* Configure Global Input ISE */
311 i2c_reg_write(vsc_addr, GLOBAL_INPUT_ISE1, 0);
312 i2c_reg_write(vsc_addr, GLOBAL_INPUT_ISE2, 0);
314 /* Configure Tx/Rx Global Output PE1 */
315 i2c_reg_write(vsc_addr, GLOBAL_OUTPUT_PE1, 0);
317 /* Configure Tx/Rx Global Output PE2 */
318 i2c_reg_write(vsc_addr, GLOBAL_OUTPUT_PE2, 0);
320 /* Configure Tx/Rx Global Input GAIN */
321 i2c_reg_write(vsc_addr, GLOBAL_INPUT_GAIN, 0x3F);
323 /* Setting Global Input LOS threshold value */
324 i2c_reg_write(vsc_addr, GLOBAL_INPUT_LOS, 0xE0);
326 /* Setting Global output termination */
327 i2c_reg_write(vsc_addr, GLOBAL_OUTPUT_TERMINATION, 0);
329 /* Configure Tx/Rx Global Output level */
330 if (vsc_addr == VSC3308_TX_ADDRESS)
331 i2c_reg_write(vsc_addr, GLOBAL_OUTPUT_LEVEL, 4);
333 i2c_reg_write(vsc_addr, GLOBAL_OUTPUT_LEVEL, 2);
335 /* Making crosspoint connections, by connecting required
337 for (i = 0; i < num_con ; i++)
338 i2c_reg_write(vsc_addr, con_arr[i][1], con_arr[i][0]);
340 /* input state - page 0x13 */
341 i2c_reg_write(vsc_addr, CURRENT_PAGE_REGISTER, INPUT_STATE_REG);
342 /* Turning off all the required input of the switch */
343 for (i = 0; i < num_con; i++)
344 i2c_reg_write(vsc_addr, con_arr[i][0], 1);
346 /* only turn on specific Tx/Rx requested by the XFI erratum */
347 if (vsc_addr == VSC3308_TX_ADDRESS) {
348 i2c_reg_write(vsc_addr, 2, 0);
349 i2c_reg_write(vsc_addr, 3, 0);
351 i2c_reg_write(vsc_addr, 0, 0);
352 i2c_reg_write(vsc_addr, 1, 0);
355 /* config output mode - page 0x23 */
356 i2c_reg_write(vsc_addr, CURRENT_PAGE_REGISTER, OUTPUT_MODE_PAGE);
357 /* Turn off the Output driver correspond to required output*/
358 for (i = 0; i < num_con ; i++)
359 i2c_reg_write(vsc_addr, con_arr[i][1], 1);
361 /* only turn on specific Tx/Rx requested by the XFI erratum */
362 if (vsc_addr == VSC3308_TX_ADDRESS) {
363 i2c_reg_write(vsc_addr, 0, 0);
364 i2c_reg_write(vsc_addr, 1, 0);
366 i2c_reg_write(vsc_addr, 3, 0);
367 i2c_reg_write(vsc_addr, 4, 0);
370 /* configure global core control register, Turn on Global core power */
371 i2c_reg_write(vsc_addr, GLOBAL_CORE_CNTRL, 0);
373 vsc_wp_config(vsc_addr);
379 int vsc3308_config(unsigned int vsc_addr, const int8_t con_arr[][2],
380 unsigned int num_con)
386 debug("VSC:Initializing VSC3308 at I2C address 0x%x"
387 " for Tx\n", vsc_addr);
392 ret = i2c_get_chip_for_busnum(bus_num, vsc_addr,
395 printf("%s: Cannot find udev for a bus %d\n", __func__,
400 ret = dm_i2c_read(dev, REVISION_ID_REG, &rev_id, 1);
402 printf("VSC:0x%x could not read REV_ID from device.\n",
407 if (rev_id != 0xab) {
408 printf("VSC: device at address 0x%x is not VSC3316/3308.\n",
413 ret = vsc_if_enable(vsc_addr);
415 printf("VSC:0x%x could not configured for 2-wire I/F.\n",
420 /* config connections - page 0x00 */
421 dm_i2c_reg_write(dev, CURRENT_PAGE_REGISTER, CONNECTION_CONFIG_PAGE);
423 /* Making crosspoint connections, by connecting required
426 for (i = 0; i < num_con ; i++)
427 dm_i2c_reg_write(dev, con_arr[i][1], con_arr[i][0]);
429 /*Configure Global Input ISE and gain */
430 dm_i2c_reg_write(dev, GLOBAL_INPUT_ISE1, 0x12);
431 dm_i2c_reg_write(dev, GLOBAL_INPUT_ISE2, 0x12);
433 /* input state - page 0x13 */
434 dm_i2c_reg_write(dev, CURRENT_PAGE_REGISTER, INPUT_STATE_REG);
435 /* Turning ON the required input of the switch */
436 for (i = 0; i < num_con ; i++)
437 dm_i2c_reg_write(dev, con_arr[i][0], 0);
439 /* Setting Global Input LOS threshold value */
440 dm_i2c_reg_write(dev, GLOBAL_INPUT_LOS, 0x60);
442 /* config output mode - page 0x23 */
443 dm_i2c_reg_write(dev, CURRENT_PAGE_REGISTER, OUTPUT_MODE_PAGE);
444 /* Turn ON the Output driver correspond to required output*/
445 for (i = 0; i < num_con ; i++)
446 dm_i2c_reg_write(dev, con_arr[i][1], 0);
448 /* configure global core control register, Turn on Global core power */
449 dm_i2c_reg_write(dev, GLOBAL_CORE_CNTRL, 0);
451 ret = i2c_read(vsc_addr, REVISION_ID_REG, 1, &rev_id, 1);
453 printf("VSC:0x%x could not read REV_ID from device.\n",
458 if (rev_id != 0xab) {
459 printf("VSC: device at address 0x%x is not VSC3316/3308.\n",
464 ret = vsc_if_enable(vsc_addr);
466 printf("VSC:0x%x could not configured for 2-wire I/F.\n",
471 /* config connections - page 0x00 */
472 i2c_reg_write(vsc_addr, CURRENT_PAGE_REGISTER, CONNECTION_CONFIG_PAGE);
474 /* Making crosspoint connections, by connecting required
476 for (i = 0; i < num_con ; i++)
477 i2c_reg_write(vsc_addr, con_arr[i][1], con_arr[i][0]);
479 /*Configure Global Input ISE and gain */
480 i2c_reg_write(vsc_addr, GLOBAL_INPUT_ISE1, 0x12);
481 i2c_reg_write(vsc_addr, GLOBAL_INPUT_ISE2, 0x12);
483 /* input state - page 0x13 */
484 i2c_reg_write(vsc_addr, CURRENT_PAGE_REGISTER, INPUT_STATE_REG);
485 /* Turning ON the required input of the switch */
486 for (i = 0; i < num_con ; i++)
487 i2c_reg_write(vsc_addr, con_arr[i][0], 0);
489 /* Setting Global Input LOS threshold value */
490 i2c_reg_write(vsc_addr, GLOBAL_INPUT_LOS, 0x60);
492 /* config output mode - page 0x23 */
493 i2c_reg_write(vsc_addr, CURRENT_PAGE_REGISTER, OUTPUT_MODE_PAGE);
494 /* Turn ON the Output driver correspond to required output*/
495 for (i = 0; i < num_con ; i++)
496 i2c_reg_write(vsc_addr, con_arr[i][1], 0);
498 /* configure global core control register, Turn on Global core power */
499 i2c_reg_write(vsc_addr, GLOBAL_CORE_CNTRL, 0);
501 vsc_wp_config(vsc_addr);
506 void vsc_wp_config(unsigned int vsc_addr)
508 debug("VSC:Configuring VSC at address:0x%x for WP\n", vsc_addr);
510 /* For new crosspoint configuration to occur, WP bit of
511 * CORE_CONFIG_REG should be set 1 and then reset to 0 */
513 int ret, bus_num = 0;
516 ret = i2c_get_chip_for_busnum(bus_num, vsc_addr,
519 printf("%s: Cannot find udev for a bus %d\n", __func__,
524 dm_i2c_reg_write(dev, CORE_CONFIG_REG, 0x01);
525 dm_i2c_reg_write(dev, CORE_CONFIG_REG, 0x0);
527 i2c_reg_write(vsc_addr, CORE_CONFIG_REG, 0x01);
528 i2c_reg_write(vsc_addr, CORE_CONFIG_REG, 0x0);