dm: ppc: T4240: add i2c DM support
[oweals/u-boot.git] / board / freescale / common / vsc3316_3308.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright 2012 Freescale Semiconductor, Inc.
4  * Copyright 2020 NXP
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 #ifdef CONFIG_DM_I2C
37         int ret, bus_num = 0;
38         struct udevice *dev;
39
40         ret = i2c_get_chip_for_busnum(bus_num, vsc_addr,
41                                       1, &dev);
42         if (ret) {
43                 printf("%s: Cannot find udev for a bus %d\n", __func__,
44                        bus_num);
45                 return ret;
46         }
47
48         return dm_i2c_write(dev, INTERFACE_MODE_REG, &data, 1);
49 #else
50         return i2c_write(vsc_addr, INTERFACE_MODE_REG, 1, &data, 1);
51 #endif
52 }
53
54 int vsc3316_config(unsigned int vsc_addr, int8_t con_arr[][2],
55                 unsigned int num_con)
56 {
57         unsigned int i;
58         u8 rev_id = 0;
59         int ret;
60
61         debug("VSC:Initializing VSC3316 at I2C address 0x%2x"
62                 " for Tx\n", vsc_addr);
63
64 #ifdef CONFIG_DM_I2C
65         int bus_num = 0;
66         struct udevice *dev;
67
68         ret = i2c_get_chip_for_busnum(bus_num, vsc_addr,
69                                       1, &dev);
70         if (ret) {
71                 printf("%s: Cannot find udev for a bus %d\n", __func__,
72                        bus_num);
73                 return ret;
74         }
75
76         ret = dm_i2c_read(dev, REVISION_ID_REG, &rev_id, 1);
77         if (ret < 0) {
78                 printf("VSC:0x%x could not read REV_ID from device.\n",
79                        vsc_addr);
80                 return ret;
81         }
82
83         if (rev_id != 0xab) {
84                 printf("VSC: device at address 0x%x is not VSC3316/3308.\n",
85                        vsc_addr);
86                 return -ENODEV;
87         }
88
89         ret = vsc_if_enable(vsc_addr);
90         if (ret) {
91                 printf("VSC:0x%x could not configured for 2-wire I/F.\n",
92                        vsc_addr);
93                 return ret;
94         }
95
96         /* config connections - page 0x00 */
97         dm_i2c_reg_write(dev, CURRENT_PAGE_REGISTER, CONNECTION_CONFIG_PAGE);
98
99         /* Making crosspoint connections, by connecting required
100          * input to output
101          */
102         for (i = 0; i < num_con ; i++)
103                 dm_i2c_reg_write(dev, con_arr[i][1], con_arr[i][0]);
104
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);
110
111         /* Setting Global Input LOS threshold value */
112         dm_i2c_reg_write(dev, GLOBAL_INPUT_LOS, 0x60);
113
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);
119
120         /* configure global core control register, Turn on Global core power */
121         dm_i2c_reg_write(dev, GLOBAL_CORE_CNTRL, 0);
122
123 #else
124         ret = i2c_read(vsc_addr, REVISION_ID_REG, 1, &rev_id, 1);
125         if (ret < 0) {
126                 printf("VSC:0x%x could not read REV_ID from device.\n",
127                         vsc_addr);
128                 return ret;
129         }
130
131         if (rev_id != 0xab) {
132                 printf("VSC: device at address 0x%x is not VSC3316/3308.\n",
133                         vsc_addr);
134                 return -ENODEV;
135         }
136
137         ret = vsc_if_enable(vsc_addr);
138         if (ret) {
139                 printf("VSC:0x%x could not configured for 2-wire I/F.\n",
140                         vsc_addr);
141                 return ret;
142         }
143
144         /* config connections - page 0x00 */
145         i2c_reg_write(vsc_addr, CURRENT_PAGE_REGISTER, CONNECTION_CONFIG_PAGE);
146
147         /* Making crosspoint connections, by connecting required
148          * input to output */
149         for (i = 0; i < num_con ; i++)
150                 i2c_reg_write(vsc_addr, con_arr[i][1], con_arr[i][0]);
151
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);
157
158         /* Setting Global Input LOS threshold value */
159         i2c_reg_write(vsc_addr, GLOBAL_INPUT_LOS, 0x60);
160
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);
166
167         /* configure global core control register, Turn on Global core power */
168         i2c_reg_write(vsc_addr, GLOBAL_CORE_CNTRL, 0);
169 #endif
170
171         vsc_wp_config(vsc_addr);
172
173         return 0;
174 }
175
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)
179 {
180         unsigned int i;
181         u8 rev_id = 0;
182         int ret;
183
184         debug("VSC:Initializing VSC3308 at I2C address 0x%x for Tx\n",
185               vsc_addr);
186
187 #ifdef CONFIG_DM_I2C
188         int bus_num = 0;
189         struct udevice *dev;
190
191         ret = i2c_get_chip_for_busnum(bus_num, vsc_addr,
192                                       1, &dev);
193         if (ret) {
194                 printf("%s: Cannot find udev for a bus %d\n", __func__,
195                        bus_num);
196                 return ret;
197         }
198
199         ret = dm_i2c_read(dev, REVISION_ID_REG, &rev_id, 1);
200         if (ret < 0) {
201                 printf("VSC:0x%x could not read REV_ID from device.\n",
202                        vsc_addr);
203                 return ret;
204         }
205
206         if (rev_id != 0xab) {
207                 printf("VSC: device at address 0x%x is not VSC3316/3308.\n",
208                        vsc_addr);
209                 return -ENODEV;
210         }
211
212         ret = vsc_if_enable(vsc_addr);
213         if (ret) {
214                 printf("VSC:0x%x could not configured for 2-wire I/F.\n",
215                        vsc_addr);
216                 return ret;
217         }
218
219         /* config connections - page 0x00 */
220         dm_i2c_reg_write(dev, CURRENT_PAGE_REGISTER, CONNECTION_CONFIG_PAGE);
221
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);
225
226         /* Configure Tx/Rx Global Output PE1 */
227         dm_i2c_reg_write(dev, GLOBAL_OUTPUT_PE1, 0);
228
229         /* Configure Tx/Rx Global Output PE2 */
230         dm_i2c_reg_write(dev, GLOBAL_OUTPUT_PE2, 0);
231
232         /* Configure Tx/Rx Global Input GAIN */
233         dm_i2c_reg_write(dev, GLOBAL_INPUT_GAIN, 0x3F);
234
235         /* Setting Global Input LOS threshold value */
236         dm_i2c_reg_write(dev, GLOBAL_INPUT_LOS, 0xE0);
237
238         /* Setting Global output termination */
239         dm_i2c_reg_write(dev, GLOBAL_OUTPUT_TERMINATION, 0);
240
241         /* Configure Tx/Rx Global Output level */
242         if (vsc_addr == VSC3308_TX_ADDRESS)
243                 dm_i2c_reg_write(dev, GLOBAL_OUTPUT_LEVEL, 4);
244         else
245                 dm_i2c_reg_write(dev, GLOBAL_OUTPUT_LEVEL, 2);
246
247         /* Making crosspoint connections, by connecting required
248          * input to output
249          */
250         for (i = 0; i < num_con ; i++)
251                 dm_i2c_reg_write(dev, con_arr[i][1], con_arr[i][0]);
252
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);
258
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);
263         } else {
264                 dm_i2c_reg_write(dev, 0, 0);
265                 dm_i2c_reg_write(dev, 1, 0);
266         }
267
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);
273
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);
278         } else {
279                 dm_i2c_reg_write(dev, 3, 0);
280                 dm_i2c_reg_write(dev, 4, 0);
281         }
282
283         /* configure global core control register, Turn on Global core power */
284         dm_i2c_reg_write(dev, GLOBAL_CORE_CNTRL, 0);
285 #else
286         ret = i2c_read(vsc_addr, REVISION_ID_REG, 1, &rev_id, 1);
287         if (ret < 0) {
288                 printf("VSC:0x%x could not read REV_ID from device.\n",
289                        vsc_addr);
290                 return ret;
291         }
292
293         if (rev_id != 0xab) {
294                 printf("VSC: device at address 0x%x is not VSC3316/3308.\n",
295                        vsc_addr);
296                 return -ENODEV;
297         }
298
299         ret = vsc_if_enable(vsc_addr);
300         if (ret) {
301                 printf("VSC:0x%x could not configured for 2-wire I/F.\n",
302                        vsc_addr);
303                 return ret;
304         }
305
306         /* config connections - page 0x00 */
307         i2c_reg_write(vsc_addr, CURRENT_PAGE_REGISTER, CONNECTION_CONFIG_PAGE);
308
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);
312
313         /* Configure Tx/Rx Global Output PE1 */
314         i2c_reg_write(vsc_addr, GLOBAL_OUTPUT_PE1, 0);
315
316         /* Configure Tx/Rx Global Output PE2 */
317         i2c_reg_write(vsc_addr, GLOBAL_OUTPUT_PE2, 0);
318
319         /* Configure Tx/Rx Global Input GAIN */
320         i2c_reg_write(vsc_addr, GLOBAL_INPUT_GAIN, 0x3F);
321
322         /* Setting Global Input LOS threshold value */
323         i2c_reg_write(vsc_addr, GLOBAL_INPUT_LOS, 0xE0);
324
325         /* Setting Global output termination */
326         i2c_reg_write(vsc_addr, GLOBAL_OUTPUT_TERMINATION, 0);
327
328         /* Configure Tx/Rx Global Output level */
329         if (vsc_addr == VSC3308_TX_ADDRESS)
330                 i2c_reg_write(vsc_addr, GLOBAL_OUTPUT_LEVEL, 4);
331         else
332                 i2c_reg_write(vsc_addr, GLOBAL_OUTPUT_LEVEL, 2);
333
334         /* Making crosspoint connections, by connecting required
335          * input to output */
336         for (i = 0; i < num_con ; i++)
337                 i2c_reg_write(vsc_addr, con_arr[i][1], con_arr[i][0]);
338
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);
344
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);
349         } else {
350                 i2c_reg_write(vsc_addr, 0, 0);
351                 i2c_reg_write(vsc_addr, 1, 0);
352         }
353
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);
359
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);
364         } else {
365                 i2c_reg_write(vsc_addr, 3, 0);
366                 i2c_reg_write(vsc_addr, 4, 0);
367         }
368
369         /* configure global core control register, Turn on Global core power */
370         i2c_reg_write(vsc_addr, GLOBAL_CORE_CNTRL, 0);
371 #endif
372         vsc_wp_config(vsc_addr);
373
374         return 0;
375 }
376 #endif
377
378 int vsc3308_config(unsigned int vsc_addr, const int8_t con_arr[][2],
379                 unsigned int num_con)
380 {
381         unsigned int i;
382         u8 rev_id = 0;
383         int ret;
384
385         debug("VSC:Initializing VSC3308 at I2C address 0x%x"
386                 " for Tx\n", vsc_addr);
387 #ifdef CONFIG_DM_I2C
388         int bus_num = 0;
389         struct udevice *dev;
390
391         ret = i2c_get_chip_for_busnum(bus_num, vsc_addr,
392                                       1, &dev);
393         if (ret) {
394                 printf("%s: Cannot find udev for a bus %d\n", __func__,
395                        bus_num);
396                 return ret;
397         }
398
399         ret = dm_i2c_read(dev, REVISION_ID_REG, &rev_id, 1);
400         if (ret < 0) {
401                 printf("VSC:0x%x could not read REV_ID from device.\n",
402                        vsc_addr);
403                 return ret;
404         }
405
406         if (rev_id != 0xab) {
407                 printf("VSC: device at address 0x%x is not VSC3316/3308.\n",
408                        vsc_addr);
409                 return -ENODEV;
410         }
411
412         ret = vsc_if_enable(vsc_addr);
413         if (ret) {
414                 printf("VSC:0x%x could not configured for 2-wire I/F.\n",
415                        vsc_addr);
416                 return ret;
417         }
418
419         /* config connections - page 0x00 */
420         dm_i2c_reg_write(dev, CURRENT_PAGE_REGISTER, CONNECTION_CONFIG_PAGE);
421
422         /* Making crosspoint connections, by connecting required
423          * input to output
424          */
425         for (i = 0; i < num_con ; i++)
426                 dm_i2c_reg_write(dev, con_arr[i][1], con_arr[i][0]);
427
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);
431
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);
437
438         /* Setting Global Input LOS threshold value */
439         dm_i2c_reg_write(dev, GLOBAL_INPUT_LOS, 0x60);
440
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);
446
447         /* configure global core control register, Turn on Global core power */
448         dm_i2c_reg_write(dev, GLOBAL_CORE_CNTRL, 0);
449 #else
450         ret = i2c_read(vsc_addr, REVISION_ID_REG, 1, &rev_id, 1);
451         if (ret < 0) {
452                 printf("VSC:0x%x could not read REV_ID from device.\n",
453                         vsc_addr);
454                 return ret;
455         }
456
457         if (rev_id != 0xab) {
458                 printf("VSC: device at address 0x%x is not VSC3316/3308.\n",
459                         vsc_addr);
460                 return -ENODEV;
461         }
462
463         ret = vsc_if_enable(vsc_addr);
464         if (ret) {
465                 printf("VSC:0x%x could not configured for 2-wire I/F.\n",
466                         vsc_addr);
467                 return ret;
468         }
469
470         /* config connections - page 0x00 */
471         i2c_reg_write(vsc_addr, CURRENT_PAGE_REGISTER, CONNECTION_CONFIG_PAGE);
472
473         /* Making crosspoint connections, by connecting required
474          * input to output */
475         for (i = 0; i < num_con ; i++)
476                 i2c_reg_write(vsc_addr, con_arr[i][1], con_arr[i][0]);
477
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);
481
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);
487
488         /* Setting Global Input LOS threshold value */
489         i2c_reg_write(vsc_addr, GLOBAL_INPUT_LOS, 0x60);
490
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);
496
497         /* configure global core control register, Turn on Global core power */
498         i2c_reg_write(vsc_addr, GLOBAL_CORE_CNTRL, 0);
499 #endif
500         vsc_wp_config(vsc_addr);
501
502         return 0;
503 }
504
505 void vsc_wp_config(unsigned int vsc_addr)
506 {
507         debug("VSC:Configuring VSC at address:0x%x for WP\n", vsc_addr);
508
509         /* For new crosspoint configuration to occur, WP bit of
510          * CORE_CONFIG_REG should be set 1 and then reset to 0 */
511 #ifdef CONFIG_DM_I2C
512         int ret, bus_num = 0;
513         struct udevice *dev;
514
515         ret = i2c_get_chip_for_busnum(bus_num, vsc_addr,
516                                       1, &dev);
517         if (ret) {
518                 printf("%s: Cannot find udev for a bus %d\n", __func__,
519                        bus_num);
520                 return;
521         }
522
523         dm_i2c_reg_write(dev, CORE_CONFIG_REG, 0x01);
524         dm_i2c_reg_write(dev, CORE_CONFIG_REG, 0x0);
525 #else
526         i2c_reg_write(vsc_addr, CORE_CONFIG_REG, 0x01);
527         i2c_reg_write(vsc_addr, CORE_CONFIG_REG, 0x0);
528 #endif
529 }