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_LOS		0x55
17 #define GLOBAL_CORE_CNTRL		0x5D
18 #define OUTPUT_MODE_PAGE		0x23
19 #define CORE_CONTROL_PAGE		0x25
20 #define CORE_CONFIG_REG		0x75
21 
22 int vsc_if_enable(unsigned int vsc_addr)
23 {
24 	u8 data;
25 
26 	debug("VSC:Configuring VSC at I2C address 0x%2x"
27 			" for 2-wire interface\n", vsc_addr);
28 
29 	/* enable 2-wire Serial InterFace (I2C) */
30 	data = 0x02;
31 	return i2c_write(vsc_addr, INTERFACE_MODE_REG, 1, &data, 1);
32 }
33 
34 int vsc3316_config(unsigned int vsc_addr, int8_t con_arr[][2],
35 		unsigned int num_con)
36 {
37 	unsigned int i;
38 	u8 rev_id = 0;
39 	int ret;
40 
41 	debug("VSC:Initializing VSC3316 at I2C address 0x%2x"
42 		" for Tx\n", vsc_addr);
43 
44 	ret = i2c_read(vsc_addr, REVISION_ID_REG, 1, &rev_id, 1);
45 	if (ret < 0) {
46 		printf("VSC:0x%x could not read REV_ID from device.\n",
47 			vsc_addr);
48 		return ret;
49 	}
50 
51 	if (rev_id != 0xab) {
52 		printf("VSC: device at address 0x%x is not VSC3316/3308.\n",
53 			vsc_addr);
54 		return -ENODEV;
55 	}
56 
57 	ret = vsc_if_enable(vsc_addr);
58 	if (ret) {
59 		printf("VSC:0x%x could not configured for 2-wire I/F.\n",
60 			vsc_addr);
61 		return ret;
62 	}
63 
64 	/* config connections - page 0x00 */
65 	i2c_reg_write(vsc_addr, CURRENT_PAGE_REGISTER, CONNECTION_CONFIG_PAGE);
66 
67 	/* Making crosspoint connections, by connecting required
68 	 * input to output */
69 	for (i = 0; i < num_con ; i++)
70 		i2c_reg_write(vsc_addr, con_arr[i][1], con_arr[i][0]);
71 
72 	/* input state - page 0x13 */
73 	i2c_reg_write(vsc_addr, CURRENT_PAGE_REGISTER, INPUT_STATE_REG);
74 	/* Configuring the required input of the switch */
75 	for (i = 0; i < num_con ; i++)
76 		i2c_reg_write(vsc_addr, con_arr[i][0], 0x80);
77 
78 	/* Setting Global Input LOS threshold value */
79 	i2c_reg_write(vsc_addr, GLOBAL_INPUT_LOS, 0x60);
80 
81 	/* config output mode - page 0x23 */
82 	i2c_reg_write(vsc_addr, CURRENT_PAGE_REGISTER, OUTPUT_MODE_PAGE);
83 	/* Turn ON the Output driver correspond to required output*/
84 	for (i = 0; i < num_con ; i++)
85 		i2c_reg_write(vsc_addr,  con_arr[i][1], 0);
86 
87 	/* configure global core control register, Turn on Global core power */
88 	i2c_reg_write(vsc_addr, GLOBAL_CORE_CNTRL, 0);
89 
90 	vsc_wp_config(vsc_addr);
91 
92 	return 0;
93 }
94 
95 int vsc3308_config(unsigned int vsc_addr, const int8_t con_arr[][2],
96 		unsigned int num_con)
97 {
98 	unsigned int i;
99 	u8 rev_id = 0;
100 	int ret;
101 
102 	debug("VSC:Initializing VSC3308 at I2C address 0x%x"
103 		" for Tx\n", vsc_addr);
104 
105 	ret = i2c_read(vsc_addr, REVISION_ID_REG, 1, &rev_id, 1);
106 	if (ret < 0) {
107 		printf("VSC:0x%x could not read REV_ID from device.\n",
108 			vsc_addr);
109 		return ret;
110 	}
111 
112 	if (rev_id != 0xab) {
113 		printf("VSC: device at address 0x%x is not VSC3316/3308.\n",
114 			vsc_addr);
115 		return -ENODEV;
116 	}
117 
118 	ret = vsc_if_enable(vsc_addr);
119 	if (ret) {
120 		printf("VSC:0x%x could not configured for 2-wire I/F.\n",
121 			vsc_addr);
122 		return ret;
123 	}
124 
125 	/* config connections - page 0x00 */
126 	i2c_reg_write(vsc_addr, CURRENT_PAGE_REGISTER, CONNECTION_CONFIG_PAGE);
127 
128 	/* Making crosspoint connections, by connecting required
129 	 * input to output */
130 	for (i = 0; i < num_con ; i++)
131 		i2c_reg_write(vsc_addr, con_arr[i][1], con_arr[i][0]);
132 
133 	/*Configure Global Input ISE and gain */
134 	i2c_reg_write(vsc_addr, GLOBAL_INPUT_ISE1, 0x12);
135 	i2c_reg_write(vsc_addr, GLOBAL_INPUT_ISE2, 0x12);
136 
137 	/* input state - page 0x13 */
138 	i2c_reg_write(vsc_addr, CURRENT_PAGE_REGISTER, INPUT_STATE_REG);
139 	/* Turning ON the required input of the switch */
140 	for (i = 0; i < num_con ; i++)
141 		i2c_reg_write(vsc_addr, con_arr[i][0], 0);
142 
143 	/* Setting Global Input LOS threshold value */
144 	i2c_reg_write(vsc_addr, GLOBAL_INPUT_LOS, 0x60);
145 
146 	/* config output mode - page 0x23 */
147 	i2c_reg_write(vsc_addr, CURRENT_PAGE_REGISTER, OUTPUT_MODE_PAGE);
148 	/* Turn ON the Output driver correspond to required output*/
149 	for (i = 0; i < num_con ; i++)
150 		i2c_reg_write(vsc_addr,  con_arr[i][1], 0);
151 
152 	/* configure global core control register, Turn on Global core power */
153 	i2c_reg_write(vsc_addr, GLOBAL_CORE_CNTRL, 0);
154 
155 	vsc_wp_config(vsc_addr);
156 
157 	return 0;
158 }
159 
160 void vsc_wp_config(unsigned int vsc_addr)
161 {
162 	debug("VSC:Configuring VSC at address:0x%x for WP\n", vsc_addr);
163 
164 	/* For new crosspoint configuration to occur, WP bit of
165 	 * CORE_CONFIG_REG should be set 1 and then reset to 0 */
166 	i2c_reg_write(vsc_addr, CORE_CONFIG_REG, 0x01);
167 	i2c_reg_write(vsc_addr, CORE_CONFIG_REG, 0x0);
168 }
169