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