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