Add the rt linux 4.1.3-rt3 as base
[kvmfornfv.git] / kernel / drivers / gpu / drm / i915 / dvo_ns2501.c
1 /*
2  *
3  * Copyright (c) 2012 Gilles Dartiguelongue, Thomas Richter
4  *
5  * All Rights Reserved.
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a
8  * copy of this software and associated documentation files (the
9  * "Software"), to deal in the Software without restriction, including
10  * without limitation the rights to use, copy, modify, merge, publish,
11  * distribute, sub license, and/or sell copies of the Software, and to
12  * permit persons to whom the Software is furnished to do so, subject to
13  * the following conditions:
14  *
15  * The above copyright notice and this permission notice (including the
16  * next paragraph) shall be included in all copies or substantial portions
17  * of the Software.
18  *
19  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
22  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
23  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26  *
27  */
28
29 #include "dvo.h"
30 #include "i915_reg.h"
31 #include "i915_drv.h"
32
33 #define NS2501_VID 0x1305
34 #define NS2501_DID 0x6726
35
36 #define NS2501_VID_LO 0x00
37 #define NS2501_VID_HI 0x01
38 #define NS2501_DID_LO 0x02
39 #define NS2501_DID_HI 0x03
40 #define NS2501_REV 0x04
41 #define NS2501_RSVD 0x05
42 #define NS2501_FREQ_LO 0x06
43 #define NS2501_FREQ_HI 0x07
44
45 #define NS2501_REG8 0x08
46 #define NS2501_8_VEN (1<<5)
47 #define NS2501_8_HEN (1<<4)
48 #define NS2501_8_DSEL (1<<3)
49 #define NS2501_8_BPAS (1<<2)
50 #define NS2501_8_RSVD (1<<1)
51 #define NS2501_8_PD (1<<0)
52
53 #define NS2501_REG9 0x09
54 #define NS2501_9_VLOW (1<<7)
55 #define NS2501_9_MSEL_MASK (0x7<<4)
56 #define NS2501_9_TSEL (1<<3)
57 #define NS2501_9_RSEN (1<<2)
58 #define NS2501_9_RSVD (1<<1)
59 #define NS2501_9_MDI (1<<0)
60
61 #define NS2501_REGC 0x0c
62
63 enum {
64         MODE_640x480,
65         MODE_800x600,
66         MODE_1024x768,
67 };
68
69 struct ns2501_reg {
70          uint8_t offset;
71          uint8_t value;
72 };
73
74 /*
75  * Magic values based on what the BIOS on
76  * Fujitsu-Siemens Lifebook S6010 programs (1024x768 panel).
77  */
78 static const struct ns2501_reg regs_1024x768[][86] = {
79         [MODE_640x480] = {
80                 [0] = { .offset = 0x0a, .value = 0x81, },
81                 [1] = { .offset = 0x18, .value = 0x07, },
82                 [2] = { .offset = 0x19, .value = 0x00, },
83                 [3] = { .offset = 0x1a, .value = 0x00, },
84                 [4] = { .offset = 0x1b, .value = 0x11, },
85                 [5] = { .offset = 0x1c, .value = 0x54, },
86                 [6] = { .offset = 0x1d, .value = 0x03, },
87                 [7] = { .offset = 0x1e, .value = 0x02, },
88                 [8] = { .offset = 0xf3, .value = 0x90, },
89                 [9] = { .offset = 0xf9, .value = 0x00, },
90                 [10] = { .offset = 0xc1, .value = 0x90, },
91                 [11] = { .offset = 0xc2, .value = 0x00, },
92                 [12] = { .offset = 0xc3, .value = 0x0f, },
93                 [13] = { .offset = 0xc4, .value = 0x03, },
94                 [14] = { .offset = 0xc5, .value = 0x16, },
95                 [15] = { .offset = 0xc6, .value = 0x00, },
96                 [16] = { .offset = 0xc7, .value = 0x02, },
97                 [17] = { .offset = 0xc8, .value = 0x02, },
98                 [18] = { .offset = 0xf4, .value = 0x00, },
99                 [19] = { .offset = 0x80, .value = 0xff, },
100                 [20] = { .offset = 0x81, .value = 0x07, },
101                 [21] = { .offset = 0x82, .value = 0x3d, },
102                 [22] = { .offset = 0x83, .value = 0x05, },
103                 [23] = { .offset = 0x94, .value = 0x00, },
104                 [24] = { .offset = 0x95, .value = 0x00, },
105                 [25] = { .offset = 0x96, .value = 0x05, },
106                 [26] = { .offset = 0x97, .value = 0x00, },
107                 [27] = { .offset = 0x9a, .value = 0x88, },
108                 [28] = { .offset = 0x9b, .value = 0x00, },
109                 [29] = { .offset = 0x98, .value = 0x00, },
110                 [30] = { .offset = 0x99, .value = 0x00, },
111                 [31] = { .offset = 0xf7, .value = 0x88, },
112                 [32] = { .offset = 0xf8, .value = 0x0a, },
113                 [33] = { .offset = 0x9c, .value = 0x24, },
114                 [34] = { .offset = 0x9d, .value = 0x00, },
115                 [35] = { .offset = 0x9e, .value = 0x25, },
116                 [36] = { .offset = 0x9f, .value = 0x03, },
117                 [37] = { .offset = 0xa0, .value = 0x28, },
118                 [38] = { .offset = 0xa1, .value = 0x01, },
119                 [39] = { .offset = 0xa2, .value = 0x28, },
120                 [40] = { .offset = 0xa3, .value = 0x05, },
121                 [41] = { .offset = 0xb6, .value = 0x09, },
122                 [42] = { .offset = 0xb8, .value = 0x00, },
123                 [43] = { .offset = 0xb9, .value = 0xa0, },
124                 [44] = { .offset = 0xba, .value = 0x00, },
125                 [45] = { .offset = 0xbb, .value = 0x20, },
126                 [46] = { .offset = 0x10, .value = 0x00, },
127                 [47] = { .offset = 0x11, .value = 0xa0, },
128                 [48] = { .offset = 0x12, .value = 0x02, },
129                 [49] = { .offset = 0x20, .value = 0x00, },
130                 [50] = { .offset = 0x22, .value = 0x00, },
131                 [51] = { .offset = 0x23, .value = 0x00, },
132                 [52] = { .offset = 0x24, .value = 0x00, },
133                 [53] = { .offset = 0x25, .value = 0x00, },
134                 [54] = { .offset = 0x8c, .value = 0x10, },
135                 [55] = { .offset = 0x8d, .value = 0x02, },
136                 [56] = { .offset = 0x8e, .value = 0x10, },
137                 [57] = { .offset = 0x8f, .value = 0x00, },
138                 [58] = { .offset = 0x90, .value = 0xff, },
139                 [59] = { .offset = 0x91, .value = 0x07, },
140                 [60] = { .offset = 0x92, .value = 0xa0, },
141                 [61] = { .offset = 0x93, .value = 0x02, },
142                 [62] = { .offset = 0xa5, .value = 0x00, },
143                 [63] = { .offset = 0xa6, .value = 0x00, },
144                 [64] = { .offset = 0xa7, .value = 0x00, },
145                 [65] = { .offset = 0xa8, .value = 0x00, },
146                 [66] = { .offset = 0xa9, .value = 0x04, },
147                 [67] = { .offset = 0xaa, .value = 0x70, },
148                 [68] = { .offset = 0xab, .value = 0x4f, },
149                 [69] = { .offset = 0xac, .value = 0x00, },
150                 [70] = { .offset = 0xa4, .value = 0x84, },
151                 [71] = { .offset = 0x7e, .value = 0x18, },
152                 [72] = { .offset = 0x84, .value = 0x00, },
153                 [73] = { .offset = 0x85, .value = 0x00, },
154                 [74] = { .offset = 0x86, .value = 0x00, },
155                 [75] = { .offset = 0x87, .value = 0x00, },
156                 [76] = { .offset = 0x88, .value = 0x00, },
157                 [77] = { .offset = 0x89, .value = 0x00, },
158                 [78] = { .offset = 0x8a, .value = 0x00, },
159                 [79] = { .offset = 0x8b, .value = 0x00, },
160                 [80] = { .offset = 0x26, .value = 0x00, },
161                 [81] = { .offset = 0x27, .value = 0x00, },
162                 [82] = { .offset = 0xad, .value = 0x00, },
163                 [83] = { .offset = 0x08, .value = 0x30, }, /* 0x31 */
164                 [84] = { .offset = 0x41, .value = 0x00, },
165                 [85] = { .offset = 0xc0, .value = 0x05, },
166         },
167         [MODE_800x600] = {
168                 [0] = { .offset = 0x0a, .value = 0x81, },
169                 [1] = { .offset = 0x18, .value = 0x07, },
170                 [2] = { .offset = 0x19, .value = 0x00, },
171                 [3] = { .offset = 0x1a, .value = 0x00, },
172                 [4] = { .offset = 0x1b, .value = 0x19, },
173                 [5] = { .offset = 0x1c, .value = 0x64, },
174                 [6] = { .offset = 0x1d, .value = 0x02, },
175                 [7] = { .offset = 0x1e, .value = 0x02, },
176                 [8] = { .offset = 0xf3, .value = 0x90, },
177                 [9] = { .offset = 0xf9, .value = 0x00, },
178                 [10] = { .offset = 0xc1, .value = 0xd7, },
179                 [11] = { .offset = 0xc2, .value = 0x00, },
180                 [12] = { .offset = 0xc3, .value = 0xf8, },
181                 [13] = { .offset = 0xc4, .value = 0x03, },
182                 [14] = { .offset = 0xc5, .value = 0x1a, },
183                 [15] = { .offset = 0xc6, .value = 0x00, },
184                 [16] = { .offset = 0xc7, .value = 0x73, },
185                 [17] = { .offset = 0xc8, .value = 0x02, },
186                 [18] = { .offset = 0xf4, .value = 0x00, },
187                 [19] = { .offset = 0x80, .value = 0x27, },
188                 [20] = { .offset = 0x81, .value = 0x03, },
189                 [21] = { .offset = 0x82, .value = 0x41, },
190                 [22] = { .offset = 0x83, .value = 0x05, },
191                 [23] = { .offset = 0x94, .value = 0x00, },
192                 [24] = { .offset = 0x95, .value = 0x00, },
193                 [25] = { .offset = 0x96, .value = 0x05, },
194                 [26] = { .offset = 0x97, .value = 0x00, },
195                 [27] = { .offset = 0x9a, .value = 0x88, },
196                 [28] = { .offset = 0x9b, .value = 0x00, },
197                 [29] = { .offset = 0x98, .value = 0x00, },
198                 [30] = { .offset = 0x99, .value = 0x00, },
199                 [31] = { .offset = 0xf7, .value = 0x88, },
200                 [32] = { .offset = 0xf8, .value = 0x06, },
201                 [33] = { .offset = 0x9c, .value = 0x23, },
202                 [34] = { .offset = 0x9d, .value = 0x00, },
203                 [35] = { .offset = 0x9e, .value = 0x25, },
204                 [36] = { .offset = 0x9f, .value = 0x03, },
205                 [37] = { .offset = 0xa0, .value = 0x28, },
206                 [38] = { .offset = 0xa1, .value = 0x01, },
207                 [39] = { .offset = 0xa2, .value = 0x28, },
208                 [40] = { .offset = 0xa3, .value = 0x05, },
209                 [41] = { .offset = 0xb6, .value = 0x09, },
210                 [42] = { .offset = 0xb8, .value = 0x30, },
211                 [43] = { .offset = 0xb9, .value = 0xc8, },
212                 [44] = { .offset = 0xba, .value = 0x00, },
213                 [45] = { .offset = 0xbb, .value = 0x20, },
214                 [46] = { .offset = 0x10, .value = 0x20, },
215                 [47] = { .offset = 0x11, .value = 0xc8, },
216                 [48] = { .offset = 0x12, .value = 0x02, },
217                 [49] = { .offset = 0x20, .value = 0x00, },
218                 [50] = { .offset = 0x22, .value = 0x00, },
219                 [51] = { .offset = 0x23, .value = 0x00, },
220                 [52] = { .offset = 0x24, .value = 0x00, },
221                 [53] = { .offset = 0x25, .value = 0x00, },
222                 [54] = { .offset = 0x8c, .value = 0x10, },
223                 [55] = { .offset = 0x8d, .value = 0x02, },
224                 [56] = { .offset = 0x8e, .value = 0x04, },
225                 [57] = { .offset = 0x8f, .value = 0x00, },
226                 [58] = { .offset = 0x90, .value = 0xff, },
227                 [59] = { .offset = 0x91, .value = 0x07, },
228                 [60] = { .offset = 0x92, .value = 0xa0, },
229                 [61] = { .offset = 0x93, .value = 0x02, },
230                 [62] = { .offset = 0xa5, .value = 0x00, },
231                 [63] = { .offset = 0xa6, .value = 0x00, },
232                 [64] = { .offset = 0xa7, .value = 0x00, },
233                 [65] = { .offset = 0xa8, .value = 0x00, },
234                 [66] = { .offset = 0xa9, .value = 0x83, },
235                 [67] = { .offset = 0xaa, .value = 0x40, },
236                 [68] = { .offset = 0xab, .value = 0x32, },
237                 [69] = { .offset = 0xac, .value = 0x00, },
238                 [70] = { .offset = 0xa4, .value = 0x80, },
239                 [71] = { .offset = 0x7e, .value = 0x18, },
240                 [72] = { .offset = 0x84, .value = 0x00, },
241                 [73] = { .offset = 0x85, .value = 0x00, },
242                 [74] = { .offset = 0x86, .value = 0x00, },
243                 [75] = { .offset = 0x87, .value = 0x00, },
244                 [76] = { .offset = 0x88, .value = 0x00, },
245                 [77] = { .offset = 0x89, .value = 0x00, },
246                 [78] = { .offset = 0x8a, .value = 0x00, },
247                 [79] = { .offset = 0x8b, .value = 0x00, },
248                 [80] = { .offset = 0x26, .value = 0x00, },
249                 [81] = { .offset = 0x27, .value = 0x00, },
250                 [82] = { .offset = 0xad, .value = 0x00, },
251                 [83] = { .offset = 0x08, .value = 0x30, }, /* 0x31 */
252                 [84] = { .offset = 0x41, .value = 0x00, },
253                 [85] = { .offset = 0xc0, .value = 0x07, },
254         },
255         [MODE_1024x768] = {
256                 [0] = { .offset = 0x0a, .value = 0x81, },
257                 [1] = { .offset = 0x18, .value = 0x07, },
258                 [2] = { .offset = 0x19, .value = 0x00, },
259                 [3] = { .offset = 0x1a, .value = 0x00, },
260                 [4] = { .offset = 0x1b, .value = 0x11, },
261                 [5] = { .offset = 0x1c, .value = 0x54, },
262                 [6] = { .offset = 0x1d, .value = 0x03, },
263                 [7] = { .offset = 0x1e, .value = 0x02, },
264                 [8] = { .offset = 0xf3, .value = 0x90, },
265                 [9] = { .offset = 0xf9, .value = 0x00, },
266                 [10] = { .offset = 0xc1, .value = 0x90, },
267                 [11] = { .offset = 0xc2, .value = 0x00, },
268                 [12] = { .offset = 0xc3, .value = 0x0f, },
269                 [13] = { .offset = 0xc4, .value = 0x03, },
270                 [14] = { .offset = 0xc5, .value = 0x16, },
271                 [15] = { .offset = 0xc6, .value = 0x00, },
272                 [16] = { .offset = 0xc7, .value = 0x02, },
273                 [17] = { .offset = 0xc8, .value = 0x02, },
274                 [18] = { .offset = 0xf4, .value = 0x00, },
275                 [19] = { .offset = 0x80, .value = 0xff, },
276                 [20] = { .offset = 0x81, .value = 0x07, },
277                 [21] = { .offset = 0x82, .value = 0x3d, },
278                 [22] = { .offset = 0x83, .value = 0x05, },
279                 [23] = { .offset = 0x94, .value = 0x00, },
280                 [24] = { .offset = 0x95, .value = 0x00, },
281                 [25] = { .offset = 0x96, .value = 0x05, },
282                 [26] = { .offset = 0x97, .value = 0x00, },
283                 [27] = { .offset = 0x9a, .value = 0x88, },
284                 [28] = { .offset = 0x9b, .value = 0x00, },
285                 [29] = { .offset = 0x98, .value = 0x00, },
286                 [30] = { .offset = 0x99, .value = 0x00, },
287                 [31] = { .offset = 0xf7, .value = 0x88, },
288                 [32] = { .offset = 0xf8, .value = 0x0a, },
289                 [33] = { .offset = 0x9c, .value = 0x24, },
290                 [34] = { .offset = 0x9d, .value = 0x00, },
291                 [35] = { .offset = 0x9e, .value = 0x25, },
292                 [36] = { .offset = 0x9f, .value = 0x03, },
293                 [37] = { .offset = 0xa0, .value = 0x28, },
294                 [38] = { .offset = 0xa1, .value = 0x01, },
295                 [39] = { .offset = 0xa2, .value = 0x28, },
296                 [40] = { .offset = 0xa3, .value = 0x05, },
297                 [41] = { .offset = 0xb6, .value = 0x09, },
298                 [42] = { .offset = 0xb8, .value = 0x00, },
299                 [43] = { .offset = 0xb9, .value = 0xa0, },
300                 [44] = { .offset = 0xba, .value = 0x00, },
301                 [45] = { .offset = 0xbb, .value = 0x20, },
302                 [46] = { .offset = 0x10, .value = 0x00, },
303                 [47] = { .offset = 0x11, .value = 0xa0, },
304                 [48] = { .offset = 0x12, .value = 0x02, },
305                 [49] = { .offset = 0x20, .value = 0x00, },
306                 [50] = { .offset = 0x22, .value = 0x00, },
307                 [51] = { .offset = 0x23, .value = 0x00, },
308                 [52] = { .offset = 0x24, .value = 0x00, },
309                 [53] = { .offset = 0x25, .value = 0x00, },
310                 [54] = { .offset = 0x8c, .value = 0x10, },
311                 [55] = { .offset = 0x8d, .value = 0x02, },
312                 [56] = { .offset = 0x8e, .value = 0x10, },
313                 [57] = { .offset = 0x8f, .value = 0x00, },
314                 [58] = { .offset = 0x90, .value = 0xff, },
315                 [59] = { .offset = 0x91, .value = 0x07, },
316                 [60] = { .offset = 0x92, .value = 0xa0, },
317                 [61] = { .offset = 0x93, .value = 0x02, },
318                 [62] = { .offset = 0xa5, .value = 0x00, },
319                 [63] = { .offset = 0xa6, .value = 0x00, },
320                 [64] = { .offset = 0xa7, .value = 0x00, },
321                 [65] = { .offset = 0xa8, .value = 0x00, },
322                 [66] = { .offset = 0xa9, .value = 0x04, },
323                 [67] = { .offset = 0xaa, .value = 0x70, },
324                 [68] = { .offset = 0xab, .value = 0x4f, },
325                 [69] = { .offset = 0xac, .value = 0x00, },
326                 [70] = { .offset = 0xa4, .value = 0x84, },
327                 [71] = { .offset = 0x7e, .value = 0x18, },
328                 [72] = { .offset = 0x84, .value = 0x00, },
329                 [73] = { .offset = 0x85, .value = 0x00, },
330                 [74] = { .offset = 0x86, .value = 0x00, },
331                 [75] = { .offset = 0x87, .value = 0x00, },
332                 [76] = { .offset = 0x88, .value = 0x00, },
333                 [77] = { .offset = 0x89, .value = 0x00, },
334                 [78] = { .offset = 0x8a, .value = 0x00, },
335                 [79] = { .offset = 0x8b, .value = 0x00, },
336                 [80] = { .offset = 0x26, .value = 0x00, },
337                 [81] = { .offset = 0x27, .value = 0x00, },
338                 [82] = { .offset = 0xad, .value = 0x00, },
339                 [83] = { .offset = 0x08, .value = 0x34, }, /* 0x35 */
340                 [84] = { .offset = 0x41, .value = 0x00, },
341                 [85] = { .offset = 0xc0, .value = 0x01, },
342         },
343 };
344
345 static const struct ns2501_reg regs_init[] = {
346         [0] = { .offset = 0x35, .value = 0xff, },
347         [1] = { .offset = 0x34, .value = 0x00, },
348         [2] = { .offset = 0x08, .value = 0x30, },
349 };
350
351 struct ns2501_priv {
352         bool quiet;
353         const struct ns2501_reg *regs;
354 };
355
356 #define NSPTR(d) ((NS2501Ptr)(d->DriverPrivate.ptr))
357
358 /*
359  * For reasons unclear to me, the ns2501 at least on the Fujitsu/Siemens
360  * laptops does not react on the i2c bus unless
361  * both the PLL is running and the display is configured in its native
362  * resolution.
363  * This function forces the DVO on, and stores the registers it touches.
364  * Afterwards, registers are restored to regular values.
365  *
366  * This is pretty much a hack, though it works.
367  * Without that, ns2501_readb and ns2501_writeb fail
368  * when switching the resolution.
369  */
370
371 /*
372 ** Read a register from the ns2501.
373 ** Returns true if successful, false otherwise.
374 ** If it returns false, it might be wise to enable the
375 ** DVO with the above function.
376 */
377 static bool ns2501_readb(struct intel_dvo_device *dvo, int addr, uint8_t * ch)
378 {
379         struct ns2501_priv *ns = dvo->dev_priv;
380         struct i2c_adapter *adapter = dvo->i2c_bus;
381         u8 out_buf[2];
382         u8 in_buf[2];
383
384         struct i2c_msg msgs[] = {
385                 {
386                  .addr = dvo->slave_addr,
387                  .flags = 0,
388                  .len = 1,
389                  .buf = out_buf,
390                  },
391                 {
392                  .addr = dvo->slave_addr,
393                  .flags = I2C_M_RD,
394                  .len = 1,
395                  .buf = in_buf,
396                  }
397         };
398
399         out_buf[0] = addr;
400         out_buf[1] = 0;
401
402         if (i2c_transfer(adapter, msgs, 2) == 2) {
403                 *ch = in_buf[0];
404                 return true;
405         }
406
407         if (!ns->quiet) {
408                 DRM_DEBUG_KMS
409                     ("Unable to read register 0x%02x from %s:0x%02x.\n", addr,
410                      adapter->name, dvo->slave_addr);
411         }
412
413         return false;
414 }
415
416 /*
417 ** Write a register to the ns2501.
418 ** Returns true if successful, false otherwise.
419 ** If it returns false, it might be wise to enable the
420 ** DVO with the above function.
421 */
422 static bool ns2501_writeb(struct intel_dvo_device *dvo, int addr, uint8_t ch)
423 {
424         struct ns2501_priv *ns = dvo->dev_priv;
425         struct i2c_adapter *adapter = dvo->i2c_bus;
426         uint8_t out_buf[2];
427
428         struct i2c_msg msg = {
429                 .addr = dvo->slave_addr,
430                 .flags = 0,
431                 .len = 2,
432                 .buf = out_buf,
433         };
434
435         out_buf[0] = addr;
436         out_buf[1] = ch;
437
438         if (i2c_transfer(adapter, &msg, 1) == 1) {
439                 return true;
440         }
441
442         if (!ns->quiet) {
443                 DRM_DEBUG_KMS("Unable to write register 0x%02x to %s:%d\n",
444                               addr, adapter->name, dvo->slave_addr);
445         }
446
447         return false;
448 }
449
450 /* National Semiconductor 2501 driver for chip on i2c bus
451  * scan for the chip on the bus.
452  * Hope the VBIOS initialized the PLL correctly so we can
453  * talk to it. If not, it will not be seen and not detected.
454  * Bummer!
455  */
456 static bool ns2501_init(struct intel_dvo_device *dvo,
457                         struct i2c_adapter *adapter)
458 {
459         /* this will detect the NS2501 chip on the specified i2c bus */
460         struct ns2501_priv *ns;
461         unsigned char ch;
462
463         ns = kzalloc(sizeof(struct ns2501_priv), GFP_KERNEL);
464         if (ns == NULL)
465                 return false;
466
467         dvo->i2c_bus = adapter;
468         dvo->dev_priv = ns;
469         ns->quiet = true;
470
471         if (!ns2501_readb(dvo, NS2501_VID_LO, &ch))
472                 goto out;
473
474         if (ch != (NS2501_VID & 0xff)) {
475                 DRM_DEBUG_KMS("ns2501 not detected got %d: from %s Slave %d.\n",
476                               ch, adapter->name, dvo->slave_addr);
477                 goto out;
478         }
479
480         if (!ns2501_readb(dvo, NS2501_DID_LO, &ch))
481                 goto out;
482
483         if (ch != (NS2501_DID & 0xff)) {
484                 DRM_DEBUG_KMS("ns2501 not detected got %d: from %s Slave %d.\n",
485                               ch, adapter->name, dvo->slave_addr);
486                 goto out;
487         }
488         ns->quiet = false;
489
490         DRM_DEBUG_KMS("init ns2501 dvo controller successfully!\n");
491
492         return true;
493
494 out:
495         kfree(ns);
496         return false;
497 }
498
499 static enum drm_connector_status ns2501_detect(struct intel_dvo_device *dvo)
500 {
501         /*
502          * This is a Laptop display, it doesn't have hotplugging.
503          * Even if not, the detection bit of the 2501 is unreliable as
504          * it only works for some display types.
505          * It is even more unreliable as the PLL must be active for
506          * allowing reading from the chiop.
507          */
508         return connector_status_connected;
509 }
510
511 static enum drm_mode_status ns2501_mode_valid(struct intel_dvo_device *dvo,
512                                               struct drm_display_mode *mode)
513 {
514         DRM_DEBUG_KMS
515             ("is mode valid (hdisplay=%d,htotal=%d,vdisplay=%d,vtotal=%d)\n",
516              mode->hdisplay, mode->htotal, mode->vdisplay, mode->vtotal);
517
518         /*
519          * Currently, these are all the modes I have data from.
520          * More might exist. Unclear how to find the native resolution
521          * of the panel in here so we could always accept it
522          * by disabling the scaler.
523          */
524         if ((mode->hdisplay == 640 && mode->vdisplay == 480 && mode->clock == 25175) ||
525             (mode->hdisplay == 800 && mode->vdisplay == 600 && mode->clock == 40000) ||
526             (mode->hdisplay == 1024 && mode->vdisplay == 768 && mode->clock == 65000)) {
527                 return MODE_OK;
528         } else {
529                 return MODE_ONE_SIZE;   /* Is this a reasonable error? */
530         }
531 }
532
533 static void ns2501_mode_set(struct intel_dvo_device *dvo,
534                             struct drm_display_mode *mode,
535                             struct drm_display_mode *adjusted_mode)
536 {
537         struct ns2501_priv *ns = (struct ns2501_priv *)(dvo->dev_priv);
538         int mode_idx, i;
539
540         DRM_DEBUG_KMS
541             ("set mode (hdisplay=%d,htotal=%d,vdisplay=%d,vtotal=%d).\n",
542              mode->hdisplay, mode->htotal, mode->vdisplay, mode->vtotal);
543
544         if (mode->hdisplay == 640 && mode->vdisplay == 480)
545                 mode_idx = MODE_640x480;
546         else if (mode->hdisplay == 800 && mode->vdisplay == 600)
547                 mode_idx = MODE_800x600;
548         else if (mode->hdisplay == 1024 && mode->vdisplay == 768)
549                 mode_idx = MODE_1024x768;
550         else
551                 return;
552
553         /* Hopefully doing it every time won't hurt... */
554         for (i = 0; i < ARRAY_SIZE(regs_init); i++)
555                 ns2501_writeb(dvo, regs_init[i].offset, regs_init[i].value);
556
557         ns->regs = regs_1024x768[mode_idx];
558
559         for (i = 0; i < 84; i++)
560                 ns2501_writeb(dvo, ns->regs[i].offset, ns->regs[i].value);
561 }
562
563 /* set the NS2501 power state */
564 static bool ns2501_get_hw_state(struct intel_dvo_device *dvo)
565 {
566         unsigned char ch;
567
568         if (!ns2501_readb(dvo, NS2501_REG8, &ch))
569                 return false;
570
571         return ch & NS2501_8_PD;
572 }
573
574 /* set the NS2501 power state */
575 static void ns2501_dpms(struct intel_dvo_device *dvo, bool enable)
576 {
577         struct ns2501_priv *ns = (struct ns2501_priv *)(dvo->dev_priv);
578
579         DRM_DEBUG_KMS("Trying set the dpms of the DVO to %i\n", enable);
580
581         if (enable) {
582                 if (WARN_ON(ns->regs[83].offset != 0x08 ||
583                             ns->regs[84].offset != 0x41 ||
584                             ns->regs[85].offset != 0xc0))
585                         return;
586
587                 ns2501_writeb(dvo, 0xc0, ns->regs[85].value | 0x08);
588
589                 ns2501_writeb(dvo, 0x41, ns->regs[84].value);
590
591                 ns2501_writeb(dvo, 0x34, 0x01);
592                 msleep(15);
593
594                 ns2501_writeb(dvo, 0x08, 0x35);
595                 if (!(ns->regs[83].value & NS2501_8_BPAS))
596                         ns2501_writeb(dvo, 0x08, 0x31);
597                 msleep(200);
598
599                 ns2501_writeb(dvo, 0x34, 0x03);
600
601                 ns2501_writeb(dvo, 0xc0, ns->regs[85].value);
602         } else {
603                 ns2501_writeb(dvo, 0x34, 0x01);
604                 msleep(200);
605
606                 ns2501_writeb(dvo, 0x08, 0x34);
607                 msleep(15);
608
609                 ns2501_writeb(dvo, 0x34, 0x00);
610         }
611 }
612
613 static void ns2501_destroy(struct intel_dvo_device *dvo)
614 {
615         struct ns2501_priv *ns = dvo->dev_priv;
616
617         if (ns) {
618                 kfree(ns);
619                 dvo->dev_priv = NULL;
620         }
621 }
622
623 struct intel_dvo_dev_ops ns2501_ops = {
624         .init = ns2501_init,
625         .detect = ns2501_detect,
626         .mode_valid = ns2501_mode_valid,
627         .mode_set = ns2501_mode_set,
628         .dpms = ns2501_dpms,
629         .get_hw_state = ns2501_get_hw_state,
630         .destroy = ns2501_destroy,
631 };