blob: dd9c37ebe8faf938b3a8244cb1fe7a1ac3b0ecc6 [file] [log] [blame]
Shaveta Leekhafa0123c2012-10-08 07:44:17 +00001/*
2 * Copyright 2012 Freescale Semiconductor, Inc.
3 *
Wolfgang Denkd79de1d2013-07-08 09:37:19 +02004 * SPDX-License-Identifier: GPL-2.0+
Shaveta Leekhafa0123c2012-10-08 07:44:17 +00005 */
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
Shaohui Xie60c3b092014-11-13 11:27:49 +080016#define GLOBAL_INPUT_GAIN 0x53
Shaveta Leekhafa0123c2012-10-08 07:44:17 +000017#define GLOBAL_INPUT_LOS 0x55
Shaohui Xie60c3b092014-11-13 11:27:49 +080018#define GLOBAL_OUTPUT_PE1 0x56
19#define GLOBAL_OUTPUT_PE2 0x57
20#define GLOBAL_OUTPUT_LEVEL 0x58
21#define GLOBAL_OUTPUT_TERMINATION 0x5A
Shaveta Leekhafa0123c2012-10-08 07:44:17 +000022#define GLOBAL_CORE_CNTRL 0x5D
23#define OUTPUT_MODE_PAGE 0x23
24#define CORE_CONTROL_PAGE 0x25
25#define CORE_CONFIG_REG 0x75
26
27int 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
Shaohui Xie3d8095e2013-08-19 18:43:07 +080039int vsc3316_config(unsigned int vsc_addr, int8_t con_arr[][2],
Shaveta Leekhafa0123c2012-10-08 07:44:17 +000040 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
Shaohui Xie60c3b092014-11-13 11:27:49 +0800100#ifdef CONFIG_SYS_FSL_B4860QDS_XFI_ERR
101int 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
Shaveta Leekhafa0123c2012-10-08 07:44:17 +0000203int 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
268void 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}