diff options
Diffstat (limited to 'drivers/gpu/drm/i915/dvo_ch7017.c')
-rw-r--r-- | drivers/gpu/drm/i915/dvo_ch7017.c | 454 |
1 files changed, 454 insertions, 0 deletions
diff --git a/drivers/gpu/drm/i915/dvo_ch7017.c b/drivers/gpu/drm/i915/dvo_ch7017.c new file mode 100644 index 000000000000..03d4b4973b02 --- /dev/null +++ b/drivers/gpu/drm/i915/dvo_ch7017.c | |||
@@ -0,0 +1,454 @@ | |||
1 | /* | ||
2 | * Copyright © 2006 Intel Corporation | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice (including the next | ||
12 | * paragraph) shall be included in all copies or substantial portions of the | ||
13 | * Software. | ||
14 | * | ||
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
18 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
20 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
21 | * DEALINGS IN THE SOFTWARE. | ||
22 | * | ||
23 | * Authors: | ||
24 | * Eric Anholt <eric@anholt.net> | ||
25 | * | ||
26 | */ | ||
27 | |||
28 | #include "dvo.h" | ||
29 | |||
30 | #define CH7017_TV_DISPLAY_MODE 0x00 | ||
31 | #define CH7017_FLICKER_FILTER 0x01 | ||
32 | #define CH7017_VIDEO_BANDWIDTH 0x02 | ||
33 | #define CH7017_TEXT_ENHANCEMENT 0x03 | ||
34 | #define CH7017_START_ACTIVE_VIDEO 0x04 | ||
35 | #define CH7017_HORIZONTAL_POSITION 0x05 | ||
36 | #define CH7017_VERTICAL_POSITION 0x06 | ||
37 | #define CH7017_BLACK_LEVEL 0x07 | ||
38 | #define CH7017_CONTRAST_ENHANCEMENT 0x08 | ||
39 | #define CH7017_TV_PLL 0x09 | ||
40 | #define CH7017_TV_PLL_M 0x0a | ||
41 | #define CH7017_TV_PLL_N 0x0b | ||
42 | #define CH7017_SUB_CARRIER_0 0x0c | ||
43 | #define CH7017_CIV_CONTROL 0x10 | ||
44 | #define CH7017_CIV_0 0x11 | ||
45 | #define CH7017_CHROMA_BOOST 0x14 | ||
46 | #define CH7017_CLOCK_MODE 0x1c | ||
47 | #define CH7017_INPUT_CLOCK 0x1d | ||
48 | #define CH7017_GPIO_CONTROL 0x1e | ||
49 | #define CH7017_INPUT_DATA_FORMAT 0x1f | ||
50 | #define CH7017_CONNECTION_DETECT 0x20 | ||
51 | #define CH7017_DAC_CONTROL 0x21 | ||
52 | #define CH7017_BUFFERED_CLOCK_OUTPUT 0x22 | ||
53 | #define CH7017_DEFEAT_VSYNC 0x47 | ||
54 | #define CH7017_TEST_PATTERN 0x48 | ||
55 | |||
56 | #define CH7017_POWER_MANAGEMENT 0x49 | ||
57 | /** Enables the TV output path. */ | ||
58 | #define CH7017_TV_EN (1 << 0) | ||
59 | #define CH7017_DAC0_POWER_DOWN (1 << 1) | ||
60 | #define CH7017_DAC1_POWER_DOWN (1 << 2) | ||
61 | #define CH7017_DAC2_POWER_DOWN (1 << 3) | ||
62 | #define CH7017_DAC3_POWER_DOWN (1 << 4) | ||
63 | /** Powers down the TV out block, and DAC0-3 */ | ||
64 | #define CH7017_TV_POWER_DOWN_EN (1 << 5) | ||
65 | |||
66 | #define CH7017_VERSION_ID 0x4a | ||
67 | |||
68 | #define CH7017_DEVICE_ID 0x4b | ||
69 | #define CH7017_DEVICE_ID_VALUE 0x1b | ||
70 | #define CH7018_DEVICE_ID_VALUE 0x1a | ||
71 | #define CH7019_DEVICE_ID_VALUE 0x19 | ||
72 | |||
73 | #define CH7017_XCLK_D2_ADJUST 0x53 | ||
74 | #define CH7017_UP_SCALER_COEFF_0 0x55 | ||
75 | #define CH7017_UP_SCALER_COEFF_1 0x56 | ||
76 | #define CH7017_UP_SCALER_COEFF_2 0x57 | ||
77 | #define CH7017_UP_SCALER_COEFF_3 0x58 | ||
78 | #define CH7017_UP_SCALER_COEFF_4 0x59 | ||
79 | #define CH7017_UP_SCALER_VERTICAL_INC_0 0x5a | ||
80 | #define CH7017_UP_SCALER_VERTICAL_INC_1 0x5b | ||
81 | #define CH7017_GPIO_INVERT 0x5c | ||
82 | #define CH7017_UP_SCALER_HORIZONTAL_INC_0 0x5d | ||
83 | #define CH7017_UP_SCALER_HORIZONTAL_INC_1 0x5e | ||
84 | |||
85 | #define CH7017_HORIZONTAL_ACTIVE_PIXEL_INPUT 0x5f | ||
86 | /**< Low bits of horizontal active pixel input */ | ||
87 | |||
88 | #define CH7017_ACTIVE_INPUT_LINE_OUTPUT 0x60 | ||
89 | /** High bits of horizontal active pixel input */ | ||
90 | #define CH7017_LVDS_HAP_INPUT_MASK (0x7 << 0) | ||
91 | /** High bits of vertical active line output */ | ||
92 | #define CH7017_LVDS_VAL_HIGH_MASK (0x7 << 3) | ||
93 | |||
94 | #define CH7017_VERTICAL_ACTIVE_LINE_OUTPUT 0x61 | ||
95 | /**< Low bits of vertical active line output */ | ||
96 | |||
97 | #define CH7017_HORIZONTAL_ACTIVE_PIXEL_OUTPUT 0x62 | ||
98 | /**< Low bits of horizontal active pixel output */ | ||
99 | |||
100 | #define CH7017_LVDS_POWER_DOWN 0x63 | ||
101 | /** High bits of horizontal active pixel output */ | ||
102 | #define CH7017_LVDS_HAP_HIGH_MASK (0x7 << 0) | ||
103 | /** Enables the LVDS power down state transition */ | ||
104 | #define CH7017_LVDS_POWER_DOWN_EN (1 << 6) | ||
105 | /** Enables the LVDS upscaler */ | ||
106 | #define CH7017_LVDS_UPSCALER_EN (1 << 7) | ||
107 | #define CH7017_LVDS_POWER_DOWN_DEFAULT_RESERVED 0x08 | ||
108 | |||
109 | #define CH7017_LVDS_ENCODING 0x64 | ||
110 | #define CH7017_LVDS_DITHER_2D (1 << 2) | ||
111 | #define CH7017_LVDS_DITHER_DIS (1 << 3) | ||
112 | #define CH7017_LVDS_DUAL_CHANNEL_EN (1 << 4) | ||
113 | #define CH7017_LVDS_24_BIT (1 << 5) | ||
114 | |||
115 | #define CH7017_LVDS_ENCODING_2 0x65 | ||
116 | |||
117 | #define CH7017_LVDS_PLL_CONTROL 0x66 | ||
118 | /** Enables the LVDS panel output path */ | ||
119 | #define CH7017_LVDS_PANEN (1 << 0) | ||
120 | /** Enables the LVDS panel backlight */ | ||
121 | #define CH7017_LVDS_BKLEN (1 << 3) | ||
122 | |||
123 | #define CH7017_POWER_SEQUENCING_T1 0x67 | ||
124 | #define CH7017_POWER_SEQUENCING_T2 0x68 | ||
125 | #define CH7017_POWER_SEQUENCING_T3 0x69 | ||
126 | #define CH7017_POWER_SEQUENCING_T4 0x6a | ||
127 | #define CH7017_POWER_SEQUENCING_T5 0x6b | ||
128 | #define CH7017_GPIO_DRIVER_TYPE 0x6c | ||
129 | #define CH7017_GPIO_DATA 0x6d | ||
130 | #define CH7017_GPIO_DIRECTION_CONTROL 0x6e | ||
131 | |||
132 | #define CH7017_LVDS_PLL_FEEDBACK_DIV 0x71 | ||
133 | # define CH7017_LVDS_PLL_FEED_BACK_DIVIDER_SHIFT 4 | ||
134 | # define CH7017_LVDS_PLL_FEED_FORWARD_DIVIDER_SHIFT 0 | ||
135 | # define CH7017_LVDS_PLL_FEEDBACK_DEFAULT_RESERVED 0x80 | ||
136 | |||
137 | #define CH7017_LVDS_PLL_VCO_CONTROL 0x72 | ||
138 | # define CH7017_LVDS_PLL_VCO_DEFAULT_RESERVED 0x80 | ||
139 | # define CH7017_LVDS_PLL_VCO_SHIFT 4 | ||
140 | # define CH7017_LVDS_PLL_POST_SCALE_DIV_SHIFT 0 | ||
141 | |||
142 | #define CH7017_OUTPUTS_ENABLE 0x73 | ||
143 | # define CH7017_CHARGE_PUMP_LOW 0x0 | ||
144 | # define CH7017_CHARGE_PUMP_HIGH 0x3 | ||
145 | # define CH7017_LVDS_CHANNEL_A (1 << 3) | ||
146 | # define CH7017_LVDS_CHANNEL_B (1 << 4) | ||
147 | # define CH7017_TV_DAC_A (1 << 5) | ||
148 | # define CH7017_TV_DAC_B (1 << 6) | ||
149 | # define CH7017_DDC_SELECT_DC2 (1 << 7) | ||
150 | |||
151 | #define CH7017_LVDS_OUTPUT_AMPLITUDE 0x74 | ||
152 | #define CH7017_LVDS_PLL_EMI_REDUCTION 0x75 | ||
153 | #define CH7017_LVDS_POWER_DOWN_FLICKER 0x76 | ||
154 | |||
155 | #define CH7017_LVDS_CONTROL_2 0x78 | ||
156 | # define CH7017_LOOP_FILTER_SHIFT 5 | ||
157 | # define CH7017_PHASE_DETECTOR_SHIFT 0 | ||
158 | |||
159 | #define CH7017_BANG_LIMIT_CONTROL 0x7f | ||
160 | |||
161 | struct ch7017_priv { | ||
162 | uint8_t save_hapi; | ||
163 | uint8_t save_vali; | ||
164 | uint8_t save_valo; | ||
165 | uint8_t save_ailo; | ||
166 | uint8_t save_lvds_pll_vco; | ||
167 | uint8_t save_feedback_div; | ||
168 | uint8_t save_lvds_control_2; | ||
169 | uint8_t save_outputs_enable; | ||
170 | uint8_t save_lvds_power_down; | ||
171 | uint8_t save_power_management; | ||
172 | }; | ||
173 | |||
174 | static void ch7017_dump_regs(struct intel_dvo_device *dvo); | ||
175 | static void ch7017_dpms(struct intel_dvo_device *dvo, int mode); | ||
176 | |||
177 | static bool ch7017_read(struct intel_dvo_device *dvo, int addr, uint8_t *val) | ||
178 | { | ||
179 | struct intel_i2c_chan *i2cbus = dvo->i2c_bus; | ||
180 | u8 out_buf[2]; | ||
181 | u8 in_buf[2]; | ||
182 | |||
183 | struct i2c_msg msgs[] = { | ||
184 | { | ||
185 | .addr = i2cbus->slave_addr, | ||
186 | .flags = 0, | ||
187 | .len = 1, | ||
188 | .buf = out_buf, | ||
189 | }, | ||
190 | { | ||
191 | .addr = i2cbus->slave_addr, | ||
192 | .flags = I2C_M_RD, | ||
193 | .len = 1, | ||
194 | .buf = in_buf, | ||
195 | } | ||
196 | }; | ||
197 | |||
198 | out_buf[0] = addr; | ||
199 | out_buf[1] = 0; | ||
200 | |||
201 | if (i2c_transfer(&i2cbus->adapter, msgs, 2) == 2) { | ||
202 | *val= in_buf[0]; | ||
203 | return true; | ||
204 | }; | ||
205 | |||
206 | return false; | ||
207 | } | ||
208 | |||
209 | static bool ch7017_write(struct intel_dvo_device *dvo, int addr, uint8_t val) | ||
210 | { | ||
211 | struct intel_i2c_chan *i2cbus = dvo->i2c_bus; | ||
212 | uint8_t out_buf[2]; | ||
213 | struct i2c_msg msg = { | ||
214 | .addr = i2cbus->slave_addr, | ||
215 | .flags = 0, | ||
216 | .len = 2, | ||
217 | .buf = out_buf, | ||
218 | }; | ||
219 | |||
220 | out_buf[0] = addr; | ||
221 | out_buf[1] = val; | ||
222 | |||
223 | if (i2c_transfer(&i2cbus->adapter, &msg, 1) == 1) | ||
224 | return true; | ||
225 | |||
226 | return false; | ||
227 | } | ||
228 | |||
229 | /** Probes for a CH7017 on the given bus and slave address. */ | ||
230 | static bool ch7017_init(struct intel_dvo_device *dvo, | ||
231 | struct intel_i2c_chan *i2cbus) | ||
232 | { | ||
233 | struct ch7017_priv *priv; | ||
234 | uint8_t val; | ||
235 | |||
236 | priv = kzalloc(sizeof(struct ch7017_priv), GFP_KERNEL); | ||
237 | if (priv == NULL) | ||
238 | return false; | ||
239 | |||
240 | dvo->i2c_bus = i2cbus; | ||
241 | dvo->i2c_bus->slave_addr = dvo->slave_addr; | ||
242 | dvo->dev_priv = priv; | ||
243 | |||
244 | if (!ch7017_read(dvo, CH7017_DEVICE_ID, &val)) | ||
245 | goto fail; | ||
246 | |||
247 | if (val != CH7017_DEVICE_ID_VALUE && | ||
248 | val != CH7018_DEVICE_ID_VALUE && | ||
249 | val != CH7019_DEVICE_ID_VALUE) { | ||
250 | DRM_DEBUG("ch701x not detected, got %d: from %s Slave %d.\n", | ||
251 | val, i2cbus->adapter.name,i2cbus->slave_addr); | ||
252 | goto fail; | ||
253 | } | ||
254 | |||
255 | return true; | ||
256 | fail: | ||
257 | kfree(priv); | ||
258 | return false; | ||
259 | } | ||
260 | |||
261 | static enum drm_connector_status ch7017_detect(struct intel_dvo_device *dvo) | ||
262 | { | ||
263 | return connector_status_unknown; | ||
264 | } | ||
265 | |||
266 | static enum drm_mode_status ch7017_mode_valid(struct intel_dvo_device *dvo, | ||
267 | struct drm_display_mode *mode) | ||
268 | { | ||
269 | if (mode->clock > 160000) | ||
270 | return MODE_CLOCK_HIGH; | ||
271 | |||
272 | return MODE_OK; | ||
273 | } | ||
274 | |||
275 | static void ch7017_mode_set(struct intel_dvo_device *dvo, | ||
276 | struct drm_display_mode *mode, | ||
277 | struct drm_display_mode *adjusted_mode) | ||
278 | { | ||
279 | uint8_t lvds_pll_feedback_div, lvds_pll_vco_control; | ||
280 | uint8_t outputs_enable, lvds_control_2, lvds_power_down; | ||
281 | uint8_t horizontal_active_pixel_input; | ||
282 | uint8_t horizontal_active_pixel_output, vertical_active_line_output; | ||
283 | uint8_t active_input_line_output; | ||
284 | |||
285 | DRM_DEBUG("Registers before mode setting\n"); | ||
286 | ch7017_dump_regs(dvo); | ||
287 | |||
288 | /* LVDS PLL settings from page 75 of 7017-7017ds.pdf*/ | ||
289 | if (mode->clock < 100000) { | ||
290 | outputs_enable = CH7017_LVDS_CHANNEL_A | CH7017_CHARGE_PUMP_LOW; | ||
291 | lvds_pll_feedback_div = CH7017_LVDS_PLL_FEEDBACK_DEFAULT_RESERVED | | ||
292 | (2 << CH7017_LVDS_PLL_FEED_BACK_DIVIDER_SHIFT) | | ||
293 | (13 << CH7017_LVDS_PLL_FEED_FORWARD_DIVIDER_SHIFT); | ||
294 | lvds_pll_vco_control = CH7017_LVDS_PLL_VCO_DEFAULT_RESERVED | | ||
295 | (2 << CH7017_LVDS_PLL_VCO_SHIFT) | | ||
296 | (3 << CH7017_LVDS_PLL_POST_SCALE_DIV_SHIFT); | ||
297 | lvds_control_2 = (1 << CH7017_LOOP_FILTER_SHIFT) | | ||
298 | (0 << CH7017_PHASE_DETECTOR_SHIFT); | ||
299 | } else { | ||
300 | outputs_enable = CH7017_LVDS_CHANNEL_A | CH7017_CHARGE_PUMP_HIGH; | ||
301 | lvds_pll_feedback_div = CH7017_LVDS_PLL_FEEDBACK_DEFAULT_RESERVED | | ||
302 | (2 << CH7017_LVDS_PLL_FEED_BACK_DIVIDER_SHIFT) | | ||
303 | (3 << CH7017_LVDS_PLL_FEED_FORWARD_DIVIDER_SHIFT); | ||
304 | lvds_pll_feedback_div = 35; | ||
305 | lvds_control_2 = (3 << CH7017_LOOP_FILTER_SHIFT) | | ||
306 | (0 << CH7017_PHASE_DETECTOR_SHIFT); | ||
307 | if (1) { /* XXX: dual channel panel detection. Assume yes for now. */ | ||
308 | outputs_enable |= CH7017_LVDS_CHANNEL_B; | ||
309 | lvds_pll_vco_control = CH7017_LVDS_PLL_VCO_DEFAULT_RESERVED | | ||
310 | (2 << CH7017_LVDS_PLL_VCO_SHIFT) | | ||
311 | (13 << CH7017_LVDS_PLL_POST_SCALE_DIV_SHIFT); | ||
312 | } else { | ||
313 | lvds_pll_vco_control = CH7017_LVDS_PLL_VCO_DEFAULT_RESERVED | | ||
314 | (1 << CH7017_LVDS_PLL_VCO_SHIFT) | | ||
315 | (13 << CH7017_LVDS_PLL_POST_SCALE_DIV_SHIFT); | ||
316 | } | ||
317 | } | ||
318 | |||
319 | horizontal_active_pixel_input = mode->hdisplay & 0x00ff; | ||
320 | |||
321 | vertical_active_line_output = mode->vdisplay & 0x00ff; | ||
322 | horizontal_active_pixel_output = mode->hdisplay & 0x00ff; | ||
323 | |||
324 | active_input_line_output = ((mode->hdisplay & 0x0700) >> 8) | | ||
325 | (((mode->vdisplay & 0x0700) >> 8) << 3); | ||
326 | |||
327 | lvds_power_down = CH7017_LVDS_POWER_DOWN_DEFAULT_RESERVED | | ||
328 | (mode->hdisplay & 0x0700) >> 8; | ||
329 | |||
330 | ch7017_dpms(dvo, DRM_MODE_DPMS_OFF); | ||
331 | ch7017_write(dvo, CH7017_HORIZONTAL_ACTIVE_PIXEL_INPUT, | ||
332 | horizontal_active_pixel_input); | ||
333 | ch7017_write(dvo, CH7017_HORIZONTAL_ACTIVE_PIXEL_OUTPUT, | ||
334 | horizontal_active_pixel_output); | ||
335 | ch7017_write(dvo, CH7017_VERTICAL_ACTIVE_LINE_OUTPUT, | ||
336 | vertical_active_line_output); | ||
337 | ch7017_write(dvo, CH7017_ACTIVE_INPUT_LINE_OUTPUT, | ||
338 | active_input_line_output); | ||
339 | ch7017_write(dvo, CH7017_LVDS_PLL_VCO_CONTROL, lvds_pll_vco_control); | ||
340 | ch7017_write(dvo, CH7017_LVDS_PLL_FEEDBACK_DIV, lvds_pll_feedback_div); | ||
341 | ch7017_write(dvo, CH7017_LVDS_CONTROL_2, lvds_control_2); | ||
342 | ch7017_write(dvo, CH7017_OUTPUTS_ENABLE, outputs_enable); | ||
343 | |||
344 | /* Turn the LVDS back on with new settings. */ | ||
345 | ch7017_write(dvo, CH7017_LVDS_POWER_DOWN, lvds_power_down); | ||
346 | |||
347 | DRM_DEBUG("Registers after mode setting\n"); | ||
348 | ch7017_dump_regs(dvo); | ||
349 | } | ||
350 | |||
351 | /* set the CH7017 power state */ | ||
352 | static void ch7017_dpms(struct intel_dvo_device *dvo, int mode) | ||
353 | { | ||
354 | uint8_t val; | ||
355 | |||
356 | ch7017_read(dvo, CH7017_LVDS_POWER_DOWN, &val); | ||
357 | |||
358 | /* Turn off TV/VGA, and never turn it on since we don't support it. */ | ||
359 | ch7017_write(dvo, CH7017_POWER_MANAGEMENT, | ||
360 | CH7017_DAC0_POWER_DOWN | | ||
361 | CH7017_DAC1_POWER_DOWN | | ||
362 | CH7017_DAC2_POWER_DOWN | | ||
363 | CH7017_DAC3_POWER_DOWN | | ||
364 | CH7017_TV_POWER_DOWN_EN); | ||
365 | |||
366 | if (mode == DRM_MODE_DPMS_ON) { | ||
367 | /* Turn on the LVDS */ | ||
368 | ch7017_write(dvo, CH7017_LVDS_POWER_DOWN, | ||
369 | val & ~CH7017_LVDS_POWER_DOWN_EN); | ||
370 | } else { | ||
371 | /* Turn off the LVDS */ | ||
372 | ch7017_write(dvo, CH7017_LVDS_POWER_DOWN, | ||
373 | val | CH7017_LVDS_POWER_DOWN_EN); | ||
374 | } | ||
375 | |||
376 | /* XXX: Should actually wait for update power status somehow */ | ||
377 | udelay(20000); | ||
378 | } | ||
379 | |||
380 | static void ch7017_dump_regs(struct intel_dvo_device *dvo) | ||
381 | { | ||
382 | uint8_t val; | ||
383 | |||
384 | #define DUMP(reg) \ | ||
385 | do { \ | ||
386 | ch7017_read(dvo, reg, &val); \ | ||
387 | DRM_DEBUG(#reg ": %02x\n", val); \ | ||
388 | } while (0) | ||
389 | |||
390 | DUMP(CH7017_HORIZONTAL_ACTIVE_PIXEL_INPUT); | ||
391 | DUMP(CH7017_HORIZONTAL_ACTIVE_PIXEL_OUTPUT); | ||
392 | DUMP(CH7017_VERTICAL_ACTIVE_LINE_OUTPUT); | ||
393 | DUMP(CH7017_ACTIVE_INPUT_LINE_OUTPUT); | ||
394 | DUMP(CH7017_LVDS_PLL_VCO_CONTROL); | ||
395 | DUMP(CH7017_LVDS_PLL_FEEDBACK_DIV); | ||
396 | DUMP(CH7017_LVDS_CONTROL_2); | ||
397 | DUMP(CH7017_OUTPUTS_ENABLE); | ||
398 | DUMP(CH7017_LVDS_POWER_DOWN); | ||
399 | } | ||
400 | |||
401 | static void ch7017_save(struct intel_dvo_device *dvo) | ||
402 | { | ||
403 | struct ch7017_priv *priv = dvo->dev_priv; | ||
404 | |||
405 | ch7017_read(dvo, CH7017_HORIZONTAL_ACTIVE_PIXEL_INPUT, &priv->save_hapi); | ||
406 | ch7017_read(dvo, CH7017_VERTICAL_ACTIVE_LINE_OUTPUT, &priv->save_valo); | ||
407 | ch7017_read(dvo, CH7017_ACTIVE_INPUT_LINE_OUTPUT, &priv->save_ailo); | ||
408 | ch7017_read(dvo, CH7017_LVDS_PLL_VCO_CONTROL, &priv->save_lvds_pll_vco); | ||
409 | ch7017_read(dvo, CH7017_LVDS_PLL_FEEDBACK_DIV, &priv->save_feedback_div); | ||
410 | ch7017_read(dvo, CH7017_LVDS_CONTROL_2, &priv->save_lvds_control_2); | ||
411 | ch7017_read(dvo, CH7017_OUTPUTS_ENABLE, &priv->save_outputs_enable); | ||
412 | ch7017_read(dvo, CH7017_LVDS_POWER_DOWN, &priv->save_lvds_power_down); | ||
413 | ch7017_read(dvo, CH7017_POWER_MANAGEMENT, &priv->save_power_management); | ||
414 | } | ||
415 | |||
416 | static void ch7017_restore(struct intel_dvo_device *dvo) | ||
417 | { | ||
418 | struct ch7017_priv *priv = dvo->dev_priv; | ||
419 | |||
420 | /* Power down before changing mode */ | ||
421 | ch7017_dpms(dvo, DRM_MODE_DPMS_OFF); | ||
422 | |||
423 | ch7017_write(dvo, CH7017_HORIZONTAL_ACTIVE_PIXEL_INPUT, priv->save_hapi); | ||
424 | ch7017_write(dvo, CH7017_VERTICAL_ACTIVE_LINE_OUTPUT, priv->save_valo); | ||
425 | ch7017_write(dvo, CH7017_ACTIVE_INPUT_LINE_OUTPUT, priv->save_ailo); | ||
426 | ch7017_write(dvo, CH7017_LVDS_PLL_VCO_CONTROL, priv->save_lvds_pll_vco); | ||
427 | ch7017_write(dvo, CH7017_LVDS_PLL_FEEDBACK_DIV, priv->save_feedback_div); | ||
428 | ch7017_write(dvo, CH7017_LVDS_CONTROL_2, priv->save_lvds_control_2); | ||
429 | ch7017_write(dvo, CH7017_OUTPUTS_ENABLE, priv->save_outputs_enable); | ||
430 | ch7017_write(dvo, CH7017_LVDS_POWER_DOWN, priv->save_lvds_power_down); | ||
431 | ch7017_write(dvo, CH7017_POWER_MANAGEMENT, priv->save_power_management); | ||
432 | } | ||
433 | |||
434 | static void ch7017_destroy(struct intel_dvo_device *dvo) | ||
435 | { | ||
436 | struct ch7017_priv *priv = dvo->dev_priv; | ||
437 | |||
438 | if (priv) { | ||
439 | kfree(priv); | ||
440 | dvo->dev_priv = NULL; | ||
441 | } | ||
442 | } | ||
443 | |||
444 | struct intel_dvo_dev_ops ch7017_ops = { | ||
445 | .init = ch7017_init, | ||
446 | .detect = ch7017_detect, | ||
447 | .mode_valid = ch7017_mode_valid, | ||
448 | .mode_set = ch7017_mode_set, | ||
449 | .dpms = ch7017_dpms, | ||
450 | .dump_regs = ch7017_dump_regs, | ||
451 | .save = ch7017_save, | ||
452 | .restore = ch7017_restore, | ||
453 | .destroy = ch7017_destroy, | ||
454 | }; | ||