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 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 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 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 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 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