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