xref: /linux/drivers/staging/sm750fb/ddk750_sii164.c (revision a1c613ae4c322ddd58d5a8539dbfba2a0380a8c0)
1 // SPDX-License-Identifier: GPL-2.0
2 #define USE_DVICHIP
3 #ifdef USE_DVICHIP
4 
5 #include "ddk750_sii164.h"
6 #include "ddk750_hwi2c.h"
7 
8 /* I2C Address of each SII164 chip */
9 #define SII164_I2C_ADDRESS                  0x70
10 
11 /* Define this definition to use hardware i2c. */
12 #define USE_HW_I2C
13 
14 #ifdef USE_HW_I2C
15     #define i2cWriteReg sm750_hw_i2c_write_reg
16     #define i2cReadReg  sm750_hw_i2c_read_reg
17 #else
18     #define i2cWriteReg sm750_sw_i2c_write_reg
19     #define i2cReadReg  sm750_sw_i2c_read_reg
20 #endif
21 
22 /* SII164 Vendor and Device ID */
23 #define SII164_VENDOR_ID                    0x0001
24 #define SII164_DEVICE_ID                    0x0006
25 
26 #ifdef SII164_FULL_FUNCTIONS
27 /* Name of the DVI Controller chip */
28 static char *gDviCtrlChipName = "Silicon Image SiI 164";
29 #endif
30 
31 /*
32  *  sii164_get_vendor_id
33  *      This function gets the vendor ID of the DVI controller chip.
34  *
35  *  Output:
36  *      Vendor ID
37  */
sii164_get_vendor_id(void)38 unsigned short sii164_get_vendor_id(void)
39 {
40 	unsigned short vendorID;
41 
42 	vendorID = ((unsigned short)i2cReadReg(SII164_I2C_ADDRESS,
43 					       SII164_VENDOR_ID_HIGH) << 8) |
44 		   (unsigned short)i2cReadReg(SII164_I2C_ADDRESS,
45 					      SII164_VENDOR_ID_LOW);
46 
47 	return vendorID;
48 }
49 
50 /*
51  *  sii164GetDeviceID
52  *      This function gets the device ID of the DVI controller chip.
53  *
54  *  Output:
55  *      Device ID
56  */
sii164GetDeviceID(void)57 unsigned short sii164GetDeviceID(void)
58 {
59 	unsigned short deviceID;
60 
61 	deviceID = ((unsigned short)i2cReadReg(SII164_I2C_ADDRESS,
62 					       SII164_DEVICE_ID_HIGH) << 8) |
63 		   (unsigned short)i2cReadReg(SII164_I2C_ADDRESS,
64 					      SII164_DEVICE_ID_LOW);
65 
66 	return deviceID;
67 }
68 
69 /*
70  *  DVI.C will handle all SiI164 chip stuffs and try its best to make code
71  *  minimal and useful
72  */
73 
74 /*
75  *  sii164_init_chip
76  *      This function initialize and detect the DVI controller chip.
77  *
78  *  Input:
79  *      edge_select           - Edge Select:
80  *                               0 = Input data is falling edge latched (falling
81  *                                   edge latched first in dual edge mode)
82  *                               1 = Input data is rising edge latched (rising
83  *                                   edge latched first in dual edge mode)
84  *      bus_select            - Input Bus Select:
85  *                               0 = Input data bus is 12-bits wide
86  *                               1 = Input data bus is 24-bits wide
87  *      dual_edge_clk_select  - Dual Edge Clock Select
88  *                               0 = Input data is single edge latched
89  *                               1 = Input data is dual edge latched
90  *      hsync_enable          - Horizontal Sync Enable:
91  *                               0 = HSYNC input is transmitted as fixed LOW
92  *                               1 = HSYNC input is transmitted as is
93  *      vsync_enable          - Vertical Sync Enable:
94  *                               0 = VSYNC input is transmitted as fixed LOW
95  *                               1 = VSYNC input is transmitted as is
96  *      deskew_enable         - De-skewing Enable:
97  *                               0 = De-skew disabled
98  *                               1 = De-skew enabled
99  *      deskew_setting        - De-skewing Setting (increment of 260psec)
100  *                               0 = 1 step --> minimum setup / maximum hold
101  *                               1 = 2 step
102  *                               2 = 3 step
103  *                               3 = 4 step
104  *                               4 = 5 step
105  *                               5 = 6 step
106  *                               6 = 7 step
107  *                               7 = 8 step --> maximum setup / minimum hold
108  *      continuous_sync_enable- SYNC Continuous:
109  *                               0 = Disable
110  *                               1 = Enable
111  *      pll_filter_enable     - PLL Filter Enable
112  *                               0 = Disable PLL Filter
113  *                               1 = Enable PLL Filter
114  *      pll_filter_value      - PLL Filter characteristics:
115  *                               0~7 (recommended value is 4)
116  *
117  *  Output:
118  *      0   - Success
119  *     -1   - Fail.
120  */
sii164_init_chip(unsigned char edge_select,unsigned char bus_select,unsigned char dual_edge_clk_select,unsigned char hsync_enable,unsigned char vsync_enable,unsigned char deskew_enable,unsigned char deskew_setting,unsigned char continuous_sync_enable,unsigned char pll_filter_enable,unsigned char pll_filter_value)121 long sii164_init_chip(unsigned char edge_select,
122 		      unsigned char bus_select,
123 		      unsigned char dual_edge_clk_select,
124 		      unsigned char hsync_enable,
125 		      unsigned char vsync_enable,
126 		      unsigned char deskew_enable,
127 		      unsigned char deskew_setting,
128 		      unsigned char continuous_sync_enable,
129 		      unsigned char pll_filter_enable,
130 		      unsigned char pll_filter_value)
131 {
132 	unsigned char config;
133 
134 	/* Initialize the i2c bus */
135 #ifdef USE_HW_I2C
136 	/* Use fast mode. */
137 	sm750_hw_i2c_init(1);
138 #else
139 	sm750_sw_i2c_init(DEFAULT_I2C_SCL, DEFAULT_I2C_SDA);
140 #endif
141 
142 	/* Check if SII164 Chip exists */
143 	if ((sii164_get_vendor_id() == SII164_VENDOR_ID) &&
144 	    (sii164GetDeviceID() == SII164_DEVICE_ID)) {
145 		/*
146 		 *  Initialize SII164 controller chip.
147 		 */
148 
149 		/* Select the edge */
150 		if (edge_select == 0)
151 			config = SII164_CONFIGURATION_LATCH_FALLING;
152 		else
153 			config = SII164_CONFIGURATION_LATCH_RISING;
154 
155 		/* Select bus wide */
156 		if (bus_select == 0)
157 			config |= SII164_CONFIGURATION_BUS_12BITS;
158 		else
159 			config |= SII164_CONFIGURATION_BUS_24BITS;
160 
161 		/* Select Dual/Single Edge Clock */
162 		if (dual_edge_clk_select == 0)
163 			config |= SII164_CONFIGURATION_CLOCK_SINGLE;
164 		else
165 			config |= SII164_CONFIGURATION_CLOCK_DUAL;
166 
167 		/* Select HSync Enable */
168 		if (hsync_enable == 0)
169 			config |= SII164_CONFIGURATION_HSYNC_FORCE_LOW;
170 		else
171 			config |= SII164_CONFIGURATION_HSYNC_AS_IS;
172 
173 		/* Select VSync Enable */
174 		if (vsync_enable == 0)
175 			config |= SII164_CONFIGURATION_VSYNC_FORCE_LOW;
176 		else
177 			config |= SII164_CONFIGURATION_VSYNC_AS_IS;
178 
179 		i2cWriteReg(SII164_I2C_ADDRESS, SII164_CONFIGURATION, config);
180 
181 		/*
182 		 * De-skew enabled with default 111b value.
183 		 * This fixes some artifacts problem in some mode on board 2.2.
184 		 * Somehow this fix does not affect board 2.1.
185 		 */
186 		if (deskew_enable == 0)
187 			config = SII164_DESKEW_DISABLE;
188 		else
189 			config = SII164_DESKEW_ENABLE;
190 
191 		switch (deskew_setting) {
192 		case 0:
193 			config |= SII164_DESKEW_1_STEP;
194 			break;
195 		case 1:
196 			config |= SII164_DESKEW_2_STEP;
197 			break;
198 		case 2:
199 			config |= SII164_DESKEW_3_STEP;
200 			break;
201 		case 3:
202 			config |= SII164_DESKEW_4_STEP;
203 			break;
204 		case 4:
205 			config |= SII164_DESKEW_5_STEP;
206 			break;
207 		case 5:
208 			config |= SII164_DESKEW_6_STEP;
209 			break;
210 		case 6:
211 			config |= SII164_DESKEW_7_STEP;
212 			break;
213 		case 7:
214 			config |= SII164_DESKEW_8_STEP;
215 			break;
216 		}
217 		i2cWriteReg(SII164_I2C_ADDRESS, SII164_DESKEW, config);
218 
219 		/* Enable/Disable Continuous Sync. */
220 		if (continuous_sync_enable == 0)
221 			config = SII164_PLL_FILTER_SYNC_CONTINUOUS_DISABLE;
222 		else
223 			config = SII164_PLL_FILTER_SYNC_CONTINUOUS_ENABLE;
224 
225 		/* Enable/Disable PLL Filter */
226 		if (pll_filter_enable == 0)
227 			config |= SII164_PLL_FILTER_DISABLE;
228 		else
229 			config |= SII164_PLL_FILTER_ENABLE;
230 
231 		/* Set the PLL Filter value */
232 		config |= ((pll_filter_value & 0x07) << 1);
233 
234 		i2cWriteReg(SII164_I2C_ADDRESS, SII164_PLL, config);
235 
236 		/* Recover from Power Down and enable output. */
237 		config = i2cReadReg(SII164_I2C_ADDRESS, SII164_CONFIGURATION);
238 		config |= SII164_CONFIGURATION_POWER_NORMAL;
239 		i2cWriteReg(SII164_I2C_ADDRESS, SII164_CONFIGURATION, config);
240 
241 		return 0;
242 	}
243 
244 	/* Return -1 if initialization fails. */
245 	return -1;
246 }
247 
248 /* below sii164 function is not necessary */
249 
250 #ifdef SII164_FULL_FUNCTIONS
251 
252 /*
253  *  sii164ResetChip
254  *      This function resets the DVI Controller Chip.
255  */
sii164ResetChip(void)256 void sii164ResetChip(void)
257 {
258 	/* Power down */
259 	sii164SetPower(0);
260 	sii164SetPower(1);
261 }
262 
263 /*
264  * sii164GetChipString
265  *      This function returns a char string name of the current DVI Controller
266  *      chip.
267  *
268  *      It's convenient for application need to display the chip name.
269  */
sii164GetChipString(void)270 char *sii164GetChipString(void)
271 {
272 	return gDviCtrlChipName;
273 }
274 
275 /*
276  *  sii164SetPower
277  *      This function sets the power configuration of the DVI Controller Chip.
278  *
279  *  Input:
280  *      powerUp - Flag to set the power down or up
281  */
sii164SetPower(unsigned char powerUp)282 void sii164SetPower(unsigned char powerUp)
283 {
284 	unsigned char config;
285 
286 	config = i2cReadReg(SII164_I2C_ADDRESS, SII164_CONFIGURATION);
287 	if (powerUp == 1) {
288 		/* Power up the chip */
289 		config &= ~SII164_CONFIGURATION_POWER_MASK;
290 		config |= SII164_CONFIGURATION_POWER_NORMAL;
291 		i2cWriteReg(SII164_I2C_ADDRESS, SII164_CONFIGURATION, config);
292 	} else {
293 		/* Power down the chip */
294 		config &= ~SII164_CONFIGURATION_POWER_MASK;
295 		config |= SII164_CONFIGURATION_POWER_DOWN;
296 		i2cWriteReg(SII164_I2C_ADDRESS, SII164_CONFIGURATION, config);
297 	}
298 }
299 
300 /*
301  *  sii164SelectHotPlugDetectionMode
302  *      This function selects the mode of the hot plug detection.
303  */
304 static
sii164SelectHotPlugDetectionMode(enum sii164_hot_plug_mode hotPlugMode)305 void sii164SelectHotPlugDetectionMode(enum sii164_hot_plug_mode hotPlugMode)
306 {
307 	unsigned char detectReg;
308 
309 	detectReg = i2cReadReg(SII164_I2C_ADDRESS, SII164_DETECT) &
310 		    ~SII164_DETECT_MONITOR_SENSE_OUTPUT_FLAG;
311 	switch (hotPlugMode) {
312 	case SII164_HOTPLUG_DISABLE:
313 		detectReg |= SII164_DETECT_MONITOR_SENSE_OUTPUT_HIGH;
314 		break;
315 	case SII164_HOTPLUG_USE_MDI:
316 		detectReg &= ~SII164_DETECT_INTERRUPT_MASK;
317 		detectReg |= SII164_DETECT_INTERRUPT_BY_HTPLG_PIN;
318 		detectReg |= SII164_DETECT_MONITOR_SENSE_OUTPUT_MDI;
319 		break;
320 	case SII164_HOTPLUG_USE_RSEN:
321 		detectReg |= SII164_DETECT_MONITOR_SENSE_OUTPUT_RSEN;
322 		break;
323 	case SII164_HOTPLUG_USE_HTPLG:
324 		detectReg |= SII164_DETECT_MONITOR_SENSE_OUTPUT_HTPLG;
325 		break;
326 	}
327 
328 	i2cWriteReg(SII164_I2C_ADDRESS, SII164_DETECT, detectReg);
329 }
330 
331 /*
332  *  sii164EnableHotPlugDetection
333  *      This function enables the Hot Plug detection.
334  *
335  *  enableHotPlug   - Enable (=1) / disable (=0) Hot Plug detection
336  */
sii164EnableHotPlugDetection(unsigned char enableHotPlug)337 void sii164EnableHotPlugDetection(unsigned char enableHotPlug)
338 {
339 	unsigned char detectReg;
340 
341 	detectReg = i2cReadReg(SII164_I2C_ADDRESS, SII164_DETECT);
342 
343 	/* Depending on each DVI controller, need to enable the hot plug based
344 	 * on each individual chip design.
345 	 */
346 	if (enableHotPlug != 0)
347 		sii164SelectHotPlugDetectionMode(SII164_HOTPLUG_USE_MDI);
348 	else
349 		sii164SelectHotPlugDetectionMode(SII164_HOTPLUG_DISABLE);
350 }
351 
352 /*
353  *  sii164IsConnected
354  *      Check if the DVI Monitor is connected.
355  *
356  *  Output:
357  *      0   - Not Connected
358  *      1   - Connected
359  */
sii164IsConnected(void)360 unsigned char sii164IsConnected(void)
361 {
362 	unsigned char hotPlugValue;
363 
364 	hotPlugValue = i2cReadReg(SII164_I2C_ADDRESS, SII164_DETECT) &
365 		       SII164_DETECT_HOT_PLUG_STATUS_MASK;
366 	if (hotPlugValue == SII164_DETECT_HOT_PLUG_STATUS_ON)
367 		return 1;
368 	else
369 		return 0;
370 }
371 
372 /*
373  *  sii164CheckInterrupt
374  *      Checks if interrupt has occurred.
375  *
376  *  Output:
377  *      0   - No interrupt
378  *      1   - Interrupt occurs
379  */
sii164CheckInterrupt(void)380 unsigned char sii164CheckInterrupt(void)
381 {
382 	unsigned char detectReg;
383 
384 	detectReg = i2cReadReg(SII164_I2C_ADDRESS, SII164_DETECT) &
385 		    SII164_DETECT_MONITOR_STATE_MASK;
386 	if (detectReg == SII164_DETECT_MONITOR_STATE_CHANGE)
387 		return 1;
388 	else
389 		return 0;
390 }
391 
392 /*
393  *  sii164ClearInterrupt
394  *      Clear the hot plug interrupt.
395  */
sii164ClearInterrupt(void)396 void sii164ClearInterrupt(void)
397 {
398 	unsigned char detectReg;
399 
400 	/* Clear the MDI interrupt */
401 	detectReg = i2cReadReg(SII164_I2C_ADDRESS, SII164_DETECT);
402 	i2cWriteReg(SII164_I2C_ADDRESS, SII164_DETECT,
403 		    detectReg | SII164_DETECT_MONITOR_STATE_CLEAR);
404 }
405 
406 #endif
407 
408 #endif
409