xref: /dragonfly/sys/dev/drm/i915/dvo_ns2501.c (revision 820c5b08)
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 intel_iic_softc *sc;
380 	struct ns2501_priv *ns = dvo->dev_priv;
381 	struct i2c_adapter *adapter = dvo->i2c_bus;
382 	u8 out_buf[2];
383 	u8 in_buf[2];
384 
385 	struct i2c_msg msgs[] = {
386 		{
387 		 .slave = dvo->slave_addr << 1,
388 		 .flags = 0,
389 		 .len = 1,
390 		 .buf = out_buf,
391 		 },
392 		{
393 		 .slave = dvo->slave_addr << 1,
394 		 .flags = I2C_M_RD,
395 		 .len = 1,
396 		 .buf = in_buf,
397 		 }
398 	};
399 
400 	out_buf[0] = addr;
401 	out_buf[1] = 0;
402 
403 	sc = device_get_softc(adapter);
404 
405 	if (iicbus_transfer(adapter, msgs, 2) == 0) {
406 		*ch = in_buf[0];
407 		return true;
408 	}
409 
410 	if (!ns->quiet) {
411 		DRM_DEBUG_KMS
412 		    ("Unable to read register 0x%02x from %s:0x%02x.\n", addr,
413 		     sc->name, dvo->slave_addr);
414 	}
415 
416 	return false;
417 }
418 
419 /*
420 ** Write a register to the ns2501.
421 ** Returns true if successful, false otherwise.
422 ** If it returns false, it might be wise to enable the
423 ** DVO with the above function.
424 */
425 static bool ns2501_writeb(struct intel_dvo_device *dvo, int addr, uint8_t ch)
426 {
427 	struct intel_iic_softc *sc;
428 	struct ns2501_priv *ns = dvo->dev_priv;
429 	struct i2c_adapter *adapter = dvo->i2c_bus;
430 	uint8_t out_buf[2];
431 
432 	struct i2c_msg msg = {
433 		.slave = dvo->slave_addr << 1,
434 		.flags = 0,
435 		.len = 2,
436 		.buf = out_buf,
437 	};
438 
439 	out_buf[0] = addr;
440 	out_buf[1] = ch;
441 
442 	sc = device_get_softc(adapter);
443 
444 	if (iicbus_transfer(adapter, &msg, 1) == 0) {
445 		return true;
446 	}
447 
448 	if (!ns->quiet) {
449 		DRM_DEBUG_KMS("Unable to write register 0x%02x to %s:%d\n",
450 			      addr, sc->name, dvo->slave_addr);
451 	}
452 
453 	return false;
454 }
455 
456 /* National Semiconductor 2501 driver for chip on i2c bus
457  * scan for the chip on the bus.
458  * Hope the VBIOS initialized the PLL correctly so we can
459  * talk to it. If not, it will not be seen and not detected.
460  * Bummer!
461  */
462 static bool ns2501_init(struct intel_dvo_device *dvo,
463 			struct i2c_adapter *adapter)
464 {
465 	struct intel_iic_softc *sc;
466 	/* this will detect the NS2501 chip on the specified i2c bus */
467 	struct ns2501_priv *ns;
468 	unsigned char ch;
469 
470 	sc = device_get_softc(adapter);
471 
472 	ns = kzalloc(sizeof(struct ns2501_priv), GFP_KERNEL);
473 	if (ns == NULL)
474 		return false;
475 
476 	dvo->i2c_bus = adapter;
477 	dvo->dev_priv = ns;
478 	ns->quiet = true;
479 
480 	if (!ns2501_readb(dvo, NS2501_VID_LO, &ch))
481 		goto out;
482 
483 	if (ch != (NS2501_VID & 0xff)) {
484 		DRM_DEBUG_KMS("ns2501 not detected got %d: from %s Slave %d.\n",
485 			      ch, sc->name, dvo->slave_addr);
486 		goto out;
487 	}
488 
489 	if (!ns2501_readb(dvo, NS2501_DID_LO, &ch))
490 		goto out;
491 
492 	if (ch != (NS2501_DID & 0xff)) {
493 		DRM_DEBUG_KMS("ns2501 not detected got %d: from %s Slave %d.\n",
494 			      ch, sc->name, dvo->slave_addr);
495 		goto out;
496 	}
497 	ns->quiet = false;
498 
499 	DRM_DEBUG_KMS("init ns2501 dvo controller successfully!\n");
500 
501 	return true;
502 
503 out:
504 	kfree(ns);
505 	return false;
506 }
507 
508 static enum drm_connector_status ns2501_detect(struct intel_dvo_device *dvo)
509 {
510 	/*
511 	 * This is a Laptop display, it doesn't have hotplugging.
512 	 * Even if not, the detection bit of the 2501 is unreliable as
513 	 * it only works for some display types.
514 	 * It is even more unreliable as the PLL must be active for
515 	 * allowing reading from the chiop.
516 	 */
517 	return connector_status_connected;
518 }
519 
520 static enum drm_mode_status ns2501_mode_valid(struct intel_dvo_device *dvo,
521 					      struct drm_display_mode *mode)
522 {
523 	DRM_DEBUG_KMS
524 	    ("is mode valid (hdisplay=%d,htotal=%d,vdisplay=%d,vtotal=%d)\n",
525 	     mode->hdisplay, mode->htotal, mode->vdisplay, mode->vtotal);
526 
527 	/*
528 	 * Currently, these are all the modes I have data from.
529 	 * More might exist. Unclear how to find the native resolution
530 	 * of the panel in here so we could always accept it
531 	 * by disabling the scaler.
532 	 */
533 	if ((mode->hdisplay == 640 && mode->vdisplay == 480 && mode->clock == 25175) ||
534 	    (mode->hdisplay == 800 && mode->vdisplay == 600 && mode->clock == 40000) ||
535 	    (mode->hdisplay == 1024 && mode->vdisplay == 768 && mode->clock == 65000)) {
536 		return MODE_OK;
537 	} else {
538 		return MODE_ONE_SIZE;	/* Is this a reasonable error? */
539 	}
540 }
541 
542 static void ns2501_mode_set(struct intel_dvo_device *dvo,
543 			    struct drm_display_mode *mode,
544 			    struct drm_display_mode *adjusted_mode)
545 {
546 	struct ns2501_priv *ns = (struct ns2501_priv *)(dvo->dev_priv);
547 	int mode_idx, i;
548 
549 	DRM_DEBUG_KMS
550 	    ("set mode (hdisplay=%d,htotal=%d,vdisplay=%d,vtotal=%d).\n",
551 	     mode->hdisplay, mode->htotal, mode->vdisplay, mode->vtotal);
552 
553 	if (mode->hdisplay == 640 && mode->vdisplay == 480)
554 		mode_idx = MODE_640x480;
555 	else if (mode->hdisplay == 800 && mode->vdisplay == 600)
556 		mode_idx = MODE_800x600;
557 	else if (mode->hdisplay == 1024 && mode->vdisplay == 768)
558 		mode_idx = MODE_1024x768;
559 	else
560 		return;
561 
562 	/* Hopefully doing it every time won't hurt... */
563 	for (i = 0; i < ARRAY_SIZE(regs_init); i++)
564 		ns2501_writeb(dvo, regs_init[i].offset, regs_init[i].value);
565 
566 	ns->regs = regs_1024x768[mode_idx];
567 
568 	for (i = 0; i < 84; i++)
569 		ns2501_writeb(dvo, ns->regs[i].offset, ns->regs[i].value);
570 }
571 
572 /* set the NS2501 power state */
573 static bool ns2501_get_hw_state(struct intel_dvo_device *dvo)
574 {
575 	unsigned char ch;
576 
577 	if (!ns2501_readb(dvo, NS2501_REG8, &ch))
578 		return false;
579 
580 	return ch & NS2501_8_PD;
581 }
582 
583 /* set the NS2501 power state */
584 static void ns2501_dpms(struct intel_dvo_device *dvo, bool enable)
585 {
586 	struct ns2501_priv *ns = (struct ns2501_priv *)(dvo->dev_priv);
587 
588 	DRM_DEBUG_KMS("Trying set the dpms of the DVO to %i\n", enable);
589 
590 	if (enable) {
591 		if (WARN_ON(ns->regs[83].offset != 0x08 ||
592 			    ns->regs[84].offset != 0x41 ||
593 			    ns->regs[85].offset != 0xc0))
594 			return;
595 
596 		ns2501_writeb(dvo, 0xc0, ns->regs[85].value | 0x08);
597 
598 		ns2501_writeb(dvo, 0x41, ns->regs[84].value);
599 
600 		ns2501_writeb(dvo, 0x34, 0x01);
601 		msleep(15);
602 
603 		ns2501_writeb(dvo, 0x08, 0x35);
604 		if (!(ns->regs[83].value & NS2501_8_BPAS))
605 			ns2501_writeb(dvo, 0x08, 0x31);
606 		msleep(200);
607 
608 		ns2501_writeb(dvo, 0x34, 0x03);
609 
610 		ns2501_writeb(dvo, 0xc0, ns->regs[85].value);
611 	} else {
612 		ns2501_writeb(dvo, 0x34, 0x01);
613 		msleep(200);
614 
615 		ns2501_writeb(dvo, 0x08, 0x34);
616 		msleep(15);
617 
618 		ns2501_writeb(dvo, 0x34, 0x00);
619 	}
620 }
621 
622 static void ns2501_destroy(struct intel_dvo_device *dvo)
623 {
624 	struct ns2501_priv *ns = dvo->dev_priv;
625 
626 	if (ns) {
627 		kfree(ns);
628 		dvo->dev_priv = NULL;
629 	}
630 }
631 
632 struct intel_dvo_dev_ops ns2501_ops = {
633 	.init = ns2501_init,
634 	.detect = ns2501_detect,
635 	.mode_valid = ns2501_mode_valid,
636 	.mode_set = ns2501_mode_set,
637 	.dpms = ns2501_dpms,
638 	.get_hw_state = ns2501_get_hw_state,
639 	.destroy = ns2501_destroy,
640 };
641