Linux-libre 5.3.12-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  *      edge_select           - Edge Select:
73  *                               0 = Input data is falling edge latched (falling
74  *                                   edge latched first in dual edge mode)
75  *                               1 = Input data is rising edge latched (rising
76  *                                   edge latched first in dual edge mode)
77  *      bus_select            - Input Bus Select:
78  *                               0 = Input data bus is 12-bits wide
79  *                               1 = Input data bus is 24-bits wide
80  *      dual_edge_clk_select  - Dual Edge Clock Select
81  *                               0 = Input data is single edge latched
82  *                               1 = Input data is dual edge latched
83  *      hsync_enable          - Horizontal Sync Enable:
84  *                               0 = HSYNC input is transmitted as fixed LOW
85  *                               1 = HSYNC input is transmitted as is
86  *      vsync_enable          - Vertical Sync Enable:
87  *                               0 = VSYNC input is transmitted as fixed LOW
88  *                               1 = VSYNC input is transmitted as is
89  *      deskew_enable         - De-skewing Enable:
90  *                               0 = De-skew disabled
91  *                               1 = De-skew enabled
92  *      deskew_setting        - 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  *      continuous_sync_enable- SYNC Continuous:
102  *                               0 = Disable
103  *                               1 = Enable
104  *      pll_filter_enable     - PLL Filter Enable
105  *                               0 = Disable PLL Filter
106  *                               1 = Enable PLL Filter
107  *      pll_filter_value      - 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 edge_select,
115                     unsigned char bus_select,
116                     unsigned char dual_edge_clk_select,
117                     unsigned char hsync_enable,
118                     unsigned char vsync_enable,
119                     unsigned char deskew_enable,
120                     unsigned char deskew_setting,
121                     unsigned char continuous_sync_enable,
122                     unsigned char pll_filter_enable,
123                     unsigned char pll_filter_value)
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 (edge_select == 0)
143                         config = SII164_CONFIGURATION_LATCH_FALLING;
144                 else
145                         config = SII164_CONFIGURATION_LATCH_RISING;
146
147                 /* Select bus wide */
148                 if (bus_select == 0)
149                         config |= SII164_CONFIGURATION_BUS_12BITS;
150                 else
151                         config |= SII164_CONFIGURATION_BUS_24BITS;
152
153                 /* Select Dual/Single Edge Clock */
154                 if (dual_edge_clk_select == 0)
155                         config |= SII164_CONFIGURATION_CLOCK_SINGLE;
156                 else
157                         config |= SII164_CONFIGURATION_CLOCK_DUAL;
158
159                 /* Select HSync Enable */
160                 if (hsync_enable == 0)
161                         config |= SII164_CONFIGURATION_HSYNC_FORCE_LOW;
162                 else
163                         config |= SII164_CONFIGURATION_HSYNC_AS_IS;
164
165                 /* Select VSync Enable */
166                 if (vsync_enable == 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 (deskew_enable == 0)
179                         config = SII164_DESKEW_DISABLE;
180                 else
181                         config = SII164_DESKEW_ENABLE;
182
183                 switch (deskew_setting) {
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 (continuous_sync_enable == 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 (pll_filter_enable == 0)
219                         config |= SII164_PLL_FILTER_DISABLE;
220                 else
221                         config |= SII164_PLL_FILTER_ENABLE;
222
223                 /* Set the PLL Filter value */
224                 config |= ((pll_filter_value & 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