blob: 5e1a7158005196572459dbf7bfbf561495210410 [file] [log] [blame]
Jingoo Hane9474be2012-02-03 18:01:55 +09001/*
2 * Samsung SoC DP (Display Port) interface driver.
3 *
4 * Copyright (C) 2012 Samsung Electronics Co., Ltd.
5 * Author: Jingoo Han <jg1.han@samsung.com>
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version.
11 */
12
13#include <linux/module.h>
14#include <linux/platform_device.h>
15#include <linux/slab.h>
16#include <linux/err.h>
17#include <linux/clk.h>
18#include <linux/io.h>
19#include <linux/interrupt.h>
20#include <linux/delay.h>
Ajay Kumarc4e235c2012-10-13 05:48:00 +090021#include <linux/of.h>
Jingoo Han8114fab2013-10-16 21:58:16 +053022#include <linux/phy/phy.h>
Jingoo Hane9474be2012-02-03 18:01:55 +090023
Jingoo Hane9474be2012-02-03 18:01:55 +090024#include "exynos_dp_core.h"
25
26static int exynos_dp_init_dp(struct exynos_dp_device *dp)
27{
28 exynos_dp_reset(dp);
29
Jingoo Han24db03a2012-05-25 16:21:08 +090030 exynos_dp_swreset(dp);
31
Jingoo Han75435c72012-08-23 19:55:13 +090032 exynos_dp_init_analog_param(dp);
33 exynos_dp_init_interrupt(dp);
34
Jingoo Hane9474be2012-02-03 18:01:55 +090035 /* SW defined function Normal operation */
36 exynos_dp_enable_sw_function(dp);
37
38 exynos_dp_config_interrupt(dp);
39 exynos_dp_init_analog_func(dp);
40
41 exynos_dp_init_hpd(dp);
42 exynos_dp_init_aux(dp);
43
44 return 0;
45}
46
47static int exynos_dp_detect_hpd(struct exynos_dp_device *dp)
48{
49 int timeout_loop = 0;
50
Jingoo Hane9474be2012-02-03 18:01:55 +090051 while (exynos_dp_get_plug_in_status(dp) != 0) {
52 timeout_loop++;
53 if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) {
54 dev_err(dp->dev, "failed to get hpd plug status\n");
55 return -ETIMEDOUT;
56 }
Jingoo Hana2c81bc2012-07-18 18:50:59 +090057 usleep_range(10, 11);
Jingoo Hane9474be2012-02-03 18:01:55 +090058 }
59
60 return 0;
61}
62
63static unsigned char exynos_dp_calc_edid_check_sum(unsigned char *edid_data)
64{
65 int i;
66 unsigned char sum = 0;
67
68 for (i = 0; i < EDID_BLOCK_LENGTH; i++)
69 sum = sum + edid_data[i];
70
71 return sum;
72}
73
74static int exynos_dp_read_edid(struct exynos_dp_device *dp)
75{
76 unsigned char edid[EDID_BLOCK_LENGTH * 2];
77 unsigned int extend_block = 0;
78 unsigned char sum;
79 unsigned char test_vector;
80 int retval;
81
82 /*
83 * EDID device address is 0x50.
84 * However, if necessary, you must have set upper address
85 * into E-EDID in I2C device, 0x30.
86 */
87
88 /* Read Extension Flag, Number of 128-byte EDID extension blocks */
Sean Paul99f54152012-11-01 02:13:00 +000089 retval = exynos_dp_read_byte_from_i2c(dp, I2C_EDID_DEVICE_ADDR,
Jingoo Hane9474be2012-02-03 18:01:55 +090090 EDID_EXTENSION_FLAG,
91 &extend_block);
Sean Paul99f54152012-11-01 02:13:00 +000092 if (retval)
93 return retval;
Jingoo Hane9474be2012-02-03 18:01:55 +090094
95 if (extend_block > 0) {
96 dev_dbg(dp->dev, "EDID data includes a single extension!\n");
97
98 /* Read EDID data */
99 retval = exynos_dp_read_bytes_from_i2c(dp, I2C_EDID_DEVICE_ADDR,
100 EDID_HEADER_PATTERN,
101 EDID_BLOCK_LENGTH,
102 &edid[EDID_HEADER_PATTERN]);
103 if (retval != 0) {
104 dev_err(dp->dev, "EDID Read failed!\n");
105 return -EIO;
106 }
107 sum = exynos_dp_calc_edid_check_sum(edid);
108 if (sum != 0) {
109 dev_err(dp->dev, "EDID bad checksum!\n");
110 return -EIO;
111 }
112
113 /* Read additional EDID data */
114 retval = exynos_dp_read_bytes_from_i2c(dp,
115 I2C_EDID_DEVICE_ADDR,
116 EDID_BLOCK_LENGTH,
117 EDID_BLOCK_LENGTH,
118 &edid[EDID_BLOCK_LENGTH]);
119 if (retval != 0) {
120 dev_err(dp->dev, "EDID Read failed!\n");
121 return -EIO;
122 }
123 sum = exynos_dp_calc_edid_check_sum(&edid[EDID_BLOCK_LENGTH]);
124 if (sum != 0) {
125 dev_err(dp->dev, "EDID bad checksum!\n");
126 return -EIO;
127 }
128
129 exynos_dp_read_byte_from_dpcd(dp, DPCD_ADDR_TEST_REQUEST,
130 &test_vector);
131 if (test_vector & DPCD_TEST_EDID_READ) {
132 exynos_dp_write_byte_to_dpcd(dp,
133 DPCD_ADDR_TEST_EDID_CHECKSUM,
134 edid[EDID_BLOCK_LENGTH + EDID_CHECKSUM]);
135 exynos_dp_write_byte_to_dpcd(dp,
136 DPCD_ADDR_TEST_RESPONSE,
137 DPCD_TEST_EDID_CHECKSUM_WRITE);
138 }
139 } else {
140 dev_info(dp->dev, "EDID data does not include any extensions.\n");
141
142 /* Read EDID data */
143 retval = exynos_dp_read_bytes_from_i2c(dp,
144 I2C_EDID_DEVICE_ADDR,
145 EDID_HEADER_PATTERN,
146 EDID_BLOCK_LENGTH,
147 &edid[EDID_HEADER_PATTERN]);
148 if (retval != 0) {
149 dev_err(dp->dev, "EDID Read failed!\n");
150 return -EIO;
151 }
152 sum = exynos_dp_calc_edid_check_sum(edid);
153 if (sum != 0) {
154 dev_err(dp->dev, "EDID bad checksum!\n");
155 return -EIO;
156 }
157
158 exynos_dp_read_byte_from_dpcd(dp,
159 DPCD_ADDR_TEST_REQUEST,
160 &test_vector);
161 if (test_vector & DPCD_TEST_EDID_READ) {
162 exynos_dp_write_byte_to_dpcd(dp,
163 DPCD_ADDR_TEST_EDID_CHECKSUM,
164 edid[EDID_CHECKSUM]);
165 exynos_dp_write_byte_to_dpcd(dp,
166 DPCD_ADDR_TEST_RESPONSE,
167 DPCD_TEST_EDID_CHECKSUM_WRITE);
168 }
169 }
170
171 dev_err(dp->dev, "EDID Read success!\n");
172 return 0;
173}
174
175static int exynos_dp_handle_edid(struct exynos_dp_device *dp)
176{
177 u8 buf[12];
178 int i;
179 int retval;
180
181 /* Read DPCD DPCD_ADDR_DPCD_REV~RECEIVE_PORT1_CAP_1 */
Sean Paul99f54152012-11-01 02:13:00 +0000182 retval = exynos_dp_read_bytes_from_dpcd(dp, DPCD_ADDR_DPCD_REV,
183 12, buf);
184 if (retval)
185 return retval;
Jingoo Hane9474be2012-02-03 18:01:55 +0900186
187 /* Read EDID */
188 for (i = 0; i < 3; i++) {
189 retval = exynos_dp_read_edid(dp);
Sean Paul99f54152012-11-01 02:13:00 +0000190 if (!retval)
Jingoo Hane9474be2012-02-03 18:01:55 +0900191 break;
192 }
193
194 return retval;
195}
196
197static void exynos_dp_enable_rx_to_enhanced_mode(struct exynos_dp_device *dp,
198 bool enable)
199{
200 u8 data;
201
202 exynos_dp_read_byte_from_dpcd(dp, DPCD_ADDR_LANE_COUNT_SET, &data);
203
204 if (enable)
205 exynos_dp_write_byte_to_dpcd(dp, DPCD_ADDR_LANE_COUNT_SET,
206 DPCD_ENHANCED_FRAME_EN |
207 DPCD_LANE_COUNT_SET(data));
208 else
209 exynos_dp_write_byte_to_dpcd(dp, DPCD_ADDR_LANE_COUNT_SET,
210 DPCD_LANE_COUNT_SET(data));
211}
212
213static int exynos_dp_is_enhanced_mode_available(struct exynos_dp_device *dp)
214{
215 u8 data;
216 int retval;
217
218 exynos_dp_read_byte_from_dpcd(dp, DPCD_ADDR_MAX_LANE_COUNT, &data);
219 retval = DPCD_ENHANCED_FRAME_CAP(data);
220
221 return retval;
222}
223
224static void exynos_dp_set_enhanced_mode(struct exynos_dp_device *dp)
225{
226 u8 data;
227
228 data = exynos_dp_is_enhanced_mode_available(dp);
229 exynos_dp_enable_rx_to_enhanced_mode(dp, data);
230 exynos_dp_enable_enhanced_mode(dp, data);
231}
232
233static void exynos_dp_training_pattern_dis(struct exynos_dp_device *dp)
234{
235 exynos_dp_set_training_pattern(dp, DP_NONE);
236
237 exynos_dp_write_byte_to_dpcd(dp,
238 DPCD_ADDR_TRAINING_PATTERN_SET,
239 DPCD_TRAINING_PATTERN_DISABLED);
240}
241
242static void exynos_dp_set_lane_lane_pre_emphasis(struct exynos_dp_device *dp,
243 int pre_emphasis, int lane)
244{
245 switch (lane) {
246 case 0:
247 exynos_dp_set_lane0_pre_emphasis(dp, pre_emphasis);
248 break;
249 case 1:
250 exynos_dp_set_lane1_pre_emphasis(dp, pre_emphasis);
251 break;
252
253 case 2:
254 exynos_dp_set_lane2_pre_emphasis(dp, pre_emphasis);
255 break;
256
257 case 3:
258 exynos_dp_set_lane3_pre_emphasis(dp, pre_emphasis);
259 break;
260 }
261}
262
Sean Paulace2d7f2012-10-31 23:21:00 +0000263static int exynos_dp_link_start(struct exynos_dp_device *dp)
Jingoo Hane9474be2012-02-03 18:01:55 +0900264{
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900265 u8 buf[4];
Sean Paul49ce41f2012-10-31 23:21:00 +0000266 int lane, lane_count, pll_tries, retval;
Jingoo Hane9474be2012-02-03 18:01:55 +0900267
268 lane_count = dp->link_train.lane_count;
269
270 dp->link_train.lt_state = CLOCK_RECOVERY;
271 dp->link_train.eq_loop = 0;
272
273 for (lane = 0; lane < lane_count; lane++)
274 dp->link_train.cr_loop[lane] = 0;
275
Jingoo Hane9474be2012-02-03 18:01:55 +0900276 /* Set link rate and count as you want to establish*/
277 exynos_dp_set_link_bandwidth(dp, dp->link_train.link_rate);
278 exynos_dp_set_lane_count(dp, dp->link_train.lane_count);
279
280 /* Setup RX configuration */
281 buf[0] = dp->link_train.link_rate;
282 buf[1] = dp->link_train.lane_count;
Sean Paulace2d7f2012-10-31 23:21:00 +0000283 retval = exynos_dp_write_bytes_to_dpcd(dp, DPCD_ADDR_LINK_BW_SET,
Jingoo Hane9474be2012-02-03 18:01:55 +0900284 2, buf);
Sean Paulace2d7f2012-10-31 23:21:00 +0000285 if (retval)
286 return retval;
Jingoo Hane9474be2012-02-03 18:01:55 +0900287
288 /* Set TX pre-emphasis to minimum */
289 for (lane = 0; lane < lane_count; lane++)
290 exynos_dp_set_lane_lane_pre_emphasis(dp,
291 PRE_EMPHASIS_LEVEL_0, lane);
292
Sean Paul49ce41f2012-10-31 23:21:00 +0000293 /* Wait for PLL lock */
294 pll_tries = 0;
295 while (exynos_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) {
296 if (pll_tries == DP_TIMEOUT_LOOP_COUNT) {
297 dev_err(dp->dev, "Wait for PLL lock timed out\n");
298 return -ETIMEDOUT;
299 }
300
301 pll_tries++;
302 usleep_range(90, 120);
303 }
304
Jingoo Hane9474be2012-02-03 18:01:55 +0900305 /* Set training pattern 1 */
306 exynos_dp_set_training_pattern(dp, TRAINING_PTN1);
307
308 /* Set RX training pattern */
Sean Paulfadec4b2012-10-31 23:21:00 +0000309 retval = exynos_dp_write_byte_to_dpcd(dp,
310 DPCD_ADDR_TRAINING_PATTERN_SET,
311 DPCD_SCRAMBLING_DISABLED | DPCD_TRAINING_PATTERN_1);
312 if (retval)
313 return retval;
Jingoo Hane9474be2012-02-03 18:01:55 +0900314
315 for (lane = 0; lane < lane_count; lane++)
316 buf[lane] = DPCD_PRE_EMPHASIS_PATTERN2_LEVEL0 |
317 DPCD_VOLTAGE_SWING_PATTERN1_LEVEL0;
Sean Paulfadec4b2012-10-31 23:21:00 +0000318
319 retval = exynos_dp_write_bytes_to_dpcd(dp, DPCD_ADDR_TRAINING_LANE0_SET,
320 lane_count, buf);
Sean Paulace2d7f2012-10-31 23:21:00 +0000321
322 return retval;
Jingoo Hane9474be2012-02-03 18:01:55 +0900323}
324
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900325static unsigned char exynos_dp_get_lane_status(u8 link_status[2], int lane)
Jingoo Hane9474be2012-02-03 18:01:55 +0900326{
327 int shift = (lane & 1) * 4;
328 u8 link_value = link_status[lane>>1];
329
330 return (link_value >> shift) & 0xf;
331}
332
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900333static int exynos_dp_clock_recovery_ok(u8 link_status[2], int lane_count)
Jingoo Hane9474be2012-02-03 18:01:55 +0900334{
335 int lane;
336 u8 lane_status;
337
338 for (lane = 0; lane < lane_count; lane++) {
339 lane_status = exynos_dp_get_lane_status(link_status, lane);
340 if ((lane_status & DPCD_LANE_CR_DONE) == 0)
341 return -EINVAL;
342 }
343 return 0;
344}
345
Sean Paulfadec4b2012-10-31 23:21:00 +0000346static int exynos_dp_channel_eq_ok(u8 link_status[2], u8 link_align,
347 int lane_count)
Jingoo Hane9474be2012-02-03 18:01:55 +0900348{
349 int lane;
Jingoo Hane9474be2012-02-03 18:01:55 +0900350 u8 lane_status;
351
Sean Paulfadec4b2012-10-31 23:21:00 +0000352 if ((link_align & DPCD_INTERLANE_ALIGN_DONE) == 0)
Jingoo Hane9474be2012-02-03 18:01:55 +0900353 return -EINVAL;
354
355 for (lane = 0; lane < lane_count; lane++) {
Sean Paulfadec4b2012-10-31 23:21:00 +0000356 lane_status = exynos_dp_get_lane_status(link_status, lane);
Jingoo Hane9474be2012-02-03 18:01:55 +0900357 lane_status &= DPCD_CHANNEL_EQ_BITS;
358 if (lane_status != DPCD_CHANNEL_EQ_BITS)
359 return -EINVAL;
360 }
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900361
Jingoo Hane9474be2012-02-03 18:01:55 +0900362 return 0;
363}
364
365static unsigned char exynos_dp_get_adjust_request_voltage(u8 adjust_request[2],
366 int lane)
367{
368 int shift = (lane & 1) * 4;
369 u8 link_value = adjust_request[lane>>1];
370
371 return (link_value >> shift) & 0x3;
372}
373
374static unsigned char exynos_dp_get_adjust_request_pre_emphasis(
375 u8 adjust_request[2],
376 int lane)
377{
378 int shift = (lane & 1) * 4;
379 u8 link_value = adjust_request[lane>>1];
380
381 return ((link_value >> shift) & 0xc) >> 2;
382}
383
384static void exynos_dp_set_lane_link_training(struct exynos_dp_device *dp,
385 u8 training_lane_set, int lane)
386{
387 switch (lane) {
388 case 0:
389 exynos_dp_set_lane0_link_training(dp, training_lane_set);
390 break;
391 case 1:
392 exynos_dp_set_lane1_link_training(dp, training_lane_set);
393 break;
394
395 case 2:
396 exynos_dp_set_lane2_link_training(dp, training_lane_set);
397 break;
398
399 case 3:
400 exynos_dp_set_lane3_link_training(dp, training_lane_set);
401 break;
402 }
403}
404
405static unsigned int exynos_dp_get_lane_link_training(
406 struct exynos_dp_device *dp,
407 int lane)
408{
409 u32 reg;
410
411 switch (lane) {
412 case 0:
413 reg = exynos_dp_get_lane0_link_training(dp);
414 break;
415 case 1:
416 reg = exynos_dp_get_lane1_link_training(dp);
417 break;
418 case 2:
419 reg = exynos_dp_get_lane2_link_training(dp);
420 break;
421 case 3:
422 reg = exynos_dp_get_lane3_link_training(dp);
423 break;
Jingoo Han64c43df2012-06-20 10:25:48 +0900424 default:
425 WARN_ON(1);
426 return 0;
Jingoo Hane9474be2012-02-03 18:01:55 +0900427 }
428
429 return reg;
430}
431
432static void exynos_dp_reduce_link_rate(struct exynos_dp_device *dp)
433{
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900434 exynos_dp_training_pattern_dis(dp);
435 exynos_dp_set_enhanced_mode(dp);
Jingoo Hane9474be2012-02-03 18:01:55 +0900436
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900437 dp->link_train.lt_state = FAILED;
Jingoo Hane9474be2012-02-03 18:01:55 +0900438}
439
Sean Paulfadec4b2012-10-31 23:21:00 +0000440static void exynos_dp_get_adjust_training_lane(struct exynos_dp_device *dp,
441 u8 adjust_request[2])
442{
443 int lane, lane_count;
444 u8 voltage_swing, pre_emphasis, training_lane;
445
446 lane_count = dp->link_train.lane_count;
447 for (lane = 0; lane < lane_count; lane++) {
448 voltage_swing = exynos_dp_get_adjust_request_voltage(
449 adjust_request, lane);
450 pre_emphasis = exynos_dp_get_adjust_request_pre_emphasis(
451 adjust_request, lane);
452 training_lane = DPCD_VOLTAGE_SWING_SET(voltage_swing) |
453 DPCD_PRE_EMPHASIS_SET(pre_emphasis);
454
455 if (voltage_swing == VOLTAGE_LEVEL_3)
456 training_lane |= DPCD_MAX_SWING_REACHED;
457 if (pre_emphasis == PRE_EMPHASIS_LEVEL_3)
458 training_lane |= DPCD_MAX_PRE_EMPHASIS_REACHED;
459
460 dp->link_train.training_lane[lane] = training_lane;
461 }
462}
463
Jingoo Hane9474be2012-02-03 18:01:55 +0900464static int exynos_dp_process_clock_recovery(struct exynos_dp_device *dp)
465{
Sean Paulace2d7f2012-10-31 23:21:00 +0000466 int lane, lane_count, retval;
Sean Paulfadec4b2012-10-31 23:21:00 +0000467 u8 voltage_swing, pre_emphasis, training_lane;
468 u8 link_status[2], adjust_request[2];
Jingoo Hane9474be2012-02-03 18:01:55 +0900469
Jingoo Hana2c81bc2012-07-18 18:50:59 +0900470 usleep_range(100, 101);
Jingoo Hane9474be2012-02-03 18:01:55 +0900471
Jingoo Hane9474be2012-02-03 18:01:55 +0900472 lane_count = dp->link_train.lane_count;
473
Sean Paulfadec4b2012-10-31 23:21:00 +0000474 retval = exynos_dp_read_bytes_from_dpcd(dp,
475 DPCD_ADDR_LANE0_1_STATUS, 2, link_status);
476 if (retval)
477 return retval;
478
479 retval = exynos_dp_read_bytes_from_dpcd(dp,
480 DPCD_ADDR_ADJUST_REQUEST_LANE0_1, 2, adjust_request);
Sean Paulace2d7f2012-10-31 23:21:00 +0000481 if (retval)
482 return retval;
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900483
Jingoo Hane9474be2012-02-03 18:01:55 +0900484 if (exynos_dp_clock_recovery_ok(link_status, lane_count) == 0) {
485 /* set training pattern 2 for EQ */
486 exynos_dp_set_training_pattern(dp, TRAINING_PTN2);
487
Sean Paulace2d7f2012-10-31 23:21:00 +0000488 retval = exynos_dp_write_byte_to_dpcd(dp,
Sean Paulfadec4b2012-10-31 23:21:00 +0000489 DPCD_ADDR_TRAINING_PATTERN_SET,
490 DPCD_SCRAMBLING_DISABLED |
491 DPCD_TRAINING_PATTERN_2);
Sean Paulace2d7f2012-10-31 23:21:00 +0000492 if (retval)
493 return retval;
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900494
495 dev_info(dp->dev, "Link Training Clock Recovery success\n");
496 dp->link_train.lt_state = EQUALIZER_TRAINING;
497 } else {
498 for (lane = 0; lane < lane_count; lane++) {
499 training_lane = exynos_dp_get_lane_link_training(
500 dp, lane);
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900501 voltage_swing = exynos_dp_get_adjust_request_voltage(
502 adjust_request, lane);
503 pre_emphasis = exynos_dp_get_adjust_request_pre_emphasis(
504 adjust_request, lane);
505
Sean Paulfadec4b2012-10-31 23:21:00 +0000506 if (DPCD_VOLTAGE_SWING_GET(training_lane) ==
507 voltage_swing &&
508 DPCD_PRE_EMPHASIS_GET(training_lane) ==
509 pre_emphasis)
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900510 dp->link_train.cr_loop[lane]++;
Sean Paulfadec4b2012-10-31 23:21:00 +0000511
512 if (dp->link_train.cr_loop[lane] == MAX_CR_LOOP ||
513 voltage_swing == VOLTAGE_LEVEL_3 ||
514 pre_emphasis == PRE_EMPHASIS_LEVEL_3) {
515 dev_err(dp->dev, "CR Max reached (%d,%d,%d)\n",
516 dp->link_train.cr_loop[lane],
517 voltage_swing, pre_emphasis);
518 exynos_dp_reduce_link_rate(dp);
519 return -EIO;
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900520 }
Jingoo Hane9474be2012-02-03 18:01:55 +0900521 }
522 }
523
Sean Paulfadec4b2012-10-31 23:21:00 +0000524 exynos_dp_get_adjust_training_lane(dp, adjust_request);
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900525
Sean Paulfadec4b2012-10-31 23:21:00 +0000526 for (lane = 0; lane < lane_count; lane++)
527 exynos_dp_set_lane_link_training(dp,
528 dp->link_train.training_lane[lane], lane);
529
530 retval = exynos_dp_write_bytes_to_dpcd(dp,
531 DPCD_ADDR_TRAINING_LANE0_SET, lane_count,
532 dp->link_train.training_lane);
533 if (retval)
534 return retval;
535
536 return retval;
Jingoo Hane9474be2012-02-03 18:01:55 +0900537}
538
539static int exynos_dp_process_equalizer_training(struct exynos_dp_device *dp)
540{
Sean Paulace2d7f2012-10-31 23:21:00 +0000541 int lane, lane_count, retval;
Jingoo Hane9474be2012-02-03 18:01:55 +0900542 u32 reg;
Sean Paulfadec4b2012-10-31 23:21:00 +0000543 u8 link_align, link_status[2], adjust_request[2];
Jingoo Hane9474be2012-02-03 18:01:55 +0900544
Jingoo Hana2c81bc2012-07-18 18:50:59 +0900545 usleep_range(400, 401);
Jingoo Hane9474be2012-02-03 18:01:55 +0900546
Jingoo Hane9474be2012-02-03 18:01:55 +0900547 lane_count = dp->link_train.lane_count;
548
Sean Paulfadec4b2012-10-31 23:21:00 +0000549 retval = exynos_dp_read_bytes_from_dpcd(dp,
550 DPCD_ADDR_LANE0_1_STATUS, 2, link_status);
Sean Paulace2d7f2012-10-31 23:21:00 +0000551 if (retval)
552 return retval;
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900553
Sean Paulfadec4b2012-10-31 23:21:00 +0000554 if (exynos_dp_clock_recovery_ok(link_status, lane_count)) {
555 exynos_dp_reduce_link_rate(dp);
556 return -EIO;
Jingoo Hane9474be2012-02-03 18:01:55 +0900557 }
558
Sean Paulfadec4b2012-10-31 23:21:00 +0000559 retval = exynos_dp_read_bytes_from_dpcd(dp,
560 DPCD_ADDR_ADJUST_REQUEST_LANE0_1, 2, adjust_request);
561 if (retval)
562 return retval;
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900563
Sean Paulfadec4b2012-10-31 23:21:00 +0000564 retval = exynos_dp_read_byte_from_dpcd(dp,
565 DPCD_ADDR_LANE_ALIGN_STATUS_UPDATED, &link_align);
566 if (retval)
567 return retval;
568
569 exynos_dp_get_adjust_training_lane(dp, adjust_request);
570
571 if (!exynos_dp_channel_eq_ok(link_status, link_align, lane_count)) {
572 /* traing pattern Set to Normal */
573 exynos_dp_training_pattern_dis(dp);
574
575 dev_info(dp->dev, "Link Training success!\n");
576
577 exynos_dp_get_link_bandwidth(dp, &reg);
578 dp->link_train.link_rate = reg;
579 dev_dbg(dp->dev, "final bandwidth = %.2x\n",
580 dp->link_train.link_rate);
581
582 exynos_dp_get_lane_count(dp, &reg);
583 dp->link_train.lane_count = reg;
584 dev_dbg(dp->dev, "final lane count = %.2x\n",
585 dp->link_train.lane_count);
586
587 /* set enhanced mode if available */
588 exynos_dp_set_enhanced_mode(dp);
589 dp->link_train.lt_state = FINISHED;
590
591 return 0;
592 }
593
594 /* not all locked */
595 dp->link_train.eq_loop++;
596
597 if (dp->link_train.eq_loop > MAX_EQ_LOOP) {
598 dev_err(dp->dev, "EQ Max loop\n");
599 exynos_dp_reduce_link_rate(dp);
600 return -EIO;
601 }
602
603 for (lane = 0; lane < lane_count; lane++)
604 exynos_dp_set_lane_link_training(dp,
605 dp->link_train.training_lane[lane], lane);
606
607 retval = exynos_dp_write_bytes_to_dpcd(dp, DPCD_ADDR_TRAINING_LANE0_SET,
608 lane_count, dp->link_train.training_lane);
609
610 return retval;
Jingoo Hane9474be2012-02-03 18:01:55 +0900611}
612
613static void exynos_dp_get_max_rx_bandwidth(struct exynos_dp_device *dp,
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900614 u8 *bandwidth)
Jingoo Hane9474be2012-02-03 18:01:55 +0900615{
616 u8 data;
617
618 /*
619 * For DP rev.1.1, Maximum link rate of Main Link lanes
620 * 0x06 = 1.62 Gbps, 0x0a = 2.7 Gbps
621 */
622 exynos_dp_read_byte_from_dpcd(dp, DPCD_ADDR_MAX_LINK_RATE, &data);
623 *bandwidth = data;
624}
625
626static void exynos_dp_get_max_rx_lane_count(struct exynos_dp_device *dp,
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900627 u8 *lane_count)
Jingoo Hane9474be2012-02-03 18:01:55 +0900628{
629 u8 data;
630
631 /*
632 * For DP rev.1.1, Maximum number of Main Link lanes
633 * 0x01 = 1 lane, 0x02 = 2 lanes, 0x04 = 4 lanes
634 */
635 exynos_dp_read_byte_from_dpcd(dp, DPCD_ADDR_MAX_LANE_COUNT, &data);
636 *lane_count = DPCD_MAX_LANE_COUNT(data);
637}
638
639static void exynos_dp_init_training(struct exynos_dp_device *dp,
640 enum link_lane_count_type max_lane,
641 enum link_rate_type max_rate)
642{
643 /*
644 * MACRO_RST must be applied after the PLL_LOCK to avoid
645 * the DP inter pair skew issue for at least 10 us
646 */
647 exynos_dp_reset_macro(dp);
648
649 /* Initialize by reading RX's DPCD */
650 exynos_dp_get_max_rx_bandwidth(dp, &dp->link_train.link_rate);
651 exynos_dp_get_max_rx_lane_count(dp, &dp->link_train.lane_count);
652
653 if ((dp->link_train.link_rate != LINK_RATE_1_62GBPS) &&
654 (dp->link_train.link_rate != LINK_RATE_2_70GBPS)) {
655 dev_err(dp->dev, "Rx Max Link Rate is abnormal :%x !\n",
656 dp->link_train.link_rate);
657 dp->link_train.link_rate = LINK_RATE_1_62GBPS;
658 }
659
660 if (dp->link_train.lane_count == 0) {
661 dev_err(dp->dev, "Rx Max Lane count is abnormal :%x !\n",
662 dp->link_train.lane_count);
663 dp->link_train.lane_count = (u8)LANE_COUNT1;
664 }
665
666 /* Setup TX lane count & rate */
667 if (dp->link_train.lane_count > max_lane)
668 dp->link_train.lane_count = max_lane;
669 if (dp->link_train.link_rate > max_rate)
670 dp->link_train.link_rate = max_rate;
671
672 /* All DP analog module power up */
673 exynos_dp_set_analog_power_down(dp, POWER_ALL, 0);
674}
675
676static int exynos_dp_sw_link_training(struct exynos_dp_device *dp)
677{
Sean Paulace2d7f2012-10-31 23:21:00 +0000678 int retval = 0, training_finished = 0;
Jingoo Hane9474be2012-02-03 18:01:55 +0900679
680 dp->link_train.lt_state = START;
681
682 /* Process here */
Sean Paulace2d7f2012-10-31 23:21:00 +0000683 while (!retval && !training_finished) {
Jingoo Hane9474be2012-02-03 18:01:55 +0900684 switch (dp->link_train.lt_state) {
685 case START:
Sean Paulace2d7f2012-10-31 23:21:00 +0000686 retval = exynos_dp_link_start(dp);
687 if (retval)
688 dev_err(dp->dev, "LT link start failed!\n");
Jingoo Hane9474be2012-02-03 18:01:55 +0900689 break;
690 case CLOCK_RECOVERY:
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900691 retval = exynos_dp_process_clock_recovery(dp);
692 if (retval)
693 dev_err(dp->dev, "LT CR failed!\n");
Jingoo Hane9474be2012-02-03 18:01:55 +0900694 break;
695 case EQUALIZER_TRAINING:
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900696 retval = exynos_dp_process_equalizer_training(dp);
697 if (retval)
698 dev_err(dp->dev, "LT EQ failed!\n");
Jingoo Hane9474be2012-02-03 18:01:55 +0900699 break;
700 case FINISHED:
701 training_finished = 1;
702 break;
703 case FAILED:
704 return -EREMOTEIO;
705 }
706 }
Sean Paulace2d7f2012-10-31 23:21:00 +0000707 if (retval)
708 dev_err(dp->dev, "eDP link training failed (%d)\n", retval);
Jingoo Hane9474be2012-02-03 18:01:55 +0900709
710 return retval;
711}
712
713static int exynos_dp_set_link_train(struct exynos_dp_device *dp,
714 u32 count,
715 u32 bwtype)
716{
717 int i;
718 int retval;
719
720 for (i = 0; i < DP_TIMEOUT_LOOP_COUNT; i++) {
721 exynos_dp_init_training(dp, count, bwtype);
722 retval = exynos_dp_sw_link_training(dp);
723 if (retval == 0)
724 break;
725
Jingoo Hana2c81bc2012-07-18 18:50:59 +0900726 usleep_range(100, 110);
Jingoo Hane9474be2012-02-03 18:01:55 +0900727 }
728
729 return retval;
730}
731
Ajay Kumar3fcb6eb2012-11-09 14:05:06 +0900732static int exynos_dp_config_video(struct exynos_dp_device *dp)
Jingoo Hane9474be2012-02-03 18:01:55 +0900733{
734 int retval = 0;
735 int timeout_loop = 0;
736 int done_count = 0;
737
Ajay Kumar3fcb6eb2012-11-09 14:05:06 +0900738 exynos_dp_config_video_slave_mode(dp);
Jingoo Hane9474be2012-02-03 18:01:55 +0900739
Ajay Kumar3fcb6eb2012-11-09 14:05:06 +0900740 exynos_dp_set_video_color_format(dp);
Jingoo Hane9474be2012-02-03 18:01:55 +0900741
742 if (exynos_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) {
743 dev_err(dp->dev, "PLL is not locked yet.\n");
744 return -EINVAL;
745 }
746
747 for (;;) {
748 timeout_loop++;
749 if (exynos_dp_is_slave_video_stream_clock_on(dp) == 0)
750 break;
751 if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) {
752 dev_err(dp->dev, "Timeout of video streamclk ok\n");
753 return -ETIMEDOUT;
754 }
755
Jingoo Hana2c81bc2012-07-18 18:50:59 +0900756 usleep_range(1, 2);
Jingoo Hane9474be2012-02-03 18:01:55 +0900757 }
758
759 /* Set to use the register calculated M/N video */
760 exynos_dp_set_video_cr_mn(dp, CALCULATED_M, 0, 0);
761
762 /* For video bist, Video timing must be generated by register */
763 exynos_dp_set_video_timing_mode(dp, VIDEO_TIMING_FROM_CAPTURE);
764
765 /* Disable video mute */
766 exynos_dp_enable_video_mute(dp, 0);
767
768 /* Configure video slave mode */
769 exynos_dp_enable_video_master(dp, 0);
770
771 /* Enable video */
772 exynos_dp_start_video(dp);
773
774 timeout_loop = 0;
775
776 for (;;) {
777 timeout_loop++;
778 if (exynos_dp_is_video_stream_on(dp) == 0) {
779 done_count++;
780 if (done_count > 10)
781 break;
782 } else if (done_count) {
783 done_count = 0;
784 }
785 if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) {
786 dev_err(dp->dev, "Timeout of video streamclk ok\n");
787 return -ETIMEDOUT;
788 }
789
Jingoo Hana2c81bc2012-07-18 18:50:59 +0900790 usleep_range(1000, 1001);
Jingoo Hane9474be2012-02-03 18:01:55 +0900791 }
792
793 if (retval != 0)
794 dev_err(dp->dev, "Video stream is not detected!\n");
795
796 return retval;
797}
798
799static void exynos_dp_enable_scramble(struct exynos_dp_device *dp, bool enable)
800{
801 u8 data;
802
803 if (enable) {
804 exynos_dp_enable_scrambling(dp);
805
806 exynos_dp_read_byte_from_dpcd(dp,
807 DPCD_ADDR_TRAINING_PATTERN_SET,
808 &data);
809 exynos_dp_write_byte_to_dpcd(dp,
810 DPCD_ADDR_TRAINING_PATTERN_SET,
811 (u8)(data & ~DPCD_SCRAMBLING_DISABLED));
812 } else {
813 exynos_dp_disable_scrambling(dp);
814
815 exynos_dp_read_byte_from_dpcd(dp,
816 DPCD_ADDR_TRAINING_PATTERN_SET,
817 &data);
818 exynos_dp_write_byte_to_dpcd(dp,
819 DPCD_ADDR_TRAINING_PATTERN_SET,
820 (u8)(data | DPCD_SCRAMBLING_DISABLED));
821 }
822}
823
824static irqreturn_t exynos_dp_irq_handler(int irq, void *arg)
825{
826 struct exynos_dp_device *dp = arg;
827
Sean Paulc30ffb92012-11-01 19:13:46 +0900828 enum dp_irq_type irq_type;
829
830 irq_type = exynos_dp_get_irq_type(dp);
831 switch (irq_type) {
832 case DP_IRQ_TYPE_HP_CABLE_IN:
833 dev_dbg(dp->dev, "Received irq - cable in\n");
834 schedule_work(&dp->hotplug_work);
835 exynos_dp_clear_hotplug_interrupts(dp);
836 break;
837 case DP_IRQ_TYPE_HP_CABLE_OUT:
838 dev_dbg(dp->dev, "Received irq - cable out\n");
839 exynos_dp_clear_hotplug_interrupts(dp);
840 break;
841 case DP_IRQ_TYPE_HP_CHANGE:
842 /*
843 * We get these change notifications once in a while, but there
844 * is nothing we can do with them. Just ignore it for now and
845 * only handle cable changes.
846 */
847 dev_dbg(dp->dev, "Received irq - hotplug change; ignoring.\n");
848 exynos_dp_clear_hotplug_interrupts(dp);
849 break;
850 default:
851 dev_err(dp->dev, "Received irq - unknown type!\n");
852 break;
853 }
Jingoo Hane9474be2012-02-03 18:01:55 +0900854 return IRQ_HANDLED;
855}
856
Sean Paul784fa9a2012-11-09 13:55:08 +0900857static void exynos_dp_hotplug(struct work_struct *work)
858{
859 struct exynos_dp_device *dp;
860 int ret;
861
862 dp = container_of(work, struct exynos_dp_device, hotplug_work);
863
864 ret = exynos_dp_detect_hpd(dp);
865 if (ret) {
Sean Paulc30ffb92012-11-01 19:13:46 +0900866 /* Cable has been disconnected, we're done */
Sean Paul784fa9a2012-11-09 13:55:08 +0900867 return;
868 }
869
870 ret = exynos_dp_handle_edid(dp);
871 if (ret) {
872 dev_err(dp->dev, "unable to handle edid\n");
873 return;
874 }
875
876 ret = exynos_dp_set_link_train(dp, dp->video_info->lane_count,
877 dp->video_info->link_rate);
878 if (ret) {
879 dev_err(dp->dev, "unable to do link train\n");
880 return;
881 }
882
883 exynos_dp_enable_scramble(dp, 1);
884 exynos_dp_enable_rx_to_enhanced_mode(dp, 1);
885 exynos_dp_enable_enhanced_mode(dp, 1);
886
887 exynos_dp_set_lane_count(dp, dp->video_info->lane_count);
888 exynos_dp_set_link_bandwidth(dp, dp->video_info->link_rate);
889
890 exynos_dp_init_video(dp);
Ajay Kumar3fcb6eb2012-11-09 14:05:06 +0900891 ret = exynos_dp_config_video(dp);
Sean Paul784fa9a2012-11-09 13:55:08 +0900892 if (ret)
893 dev_err(dp->dev, "unable to config video\n");
894}
895
Jingoo Hanf9b1e012013-10-16 21:58:15 +0530896static struct video_info *exynos_dp_dt_parse_pdata(struct device *dev)
Ajay Kumarc4e235c2012-10-13 05:48:00 +0900897{
898 struct device_node *dp_node = dev->of_node;
Ajay Kumarc4e235c2012-10-13 05:48:00 +0900899 struct video_info *dp_video_config;
900
Ajay Kumarc4e235c2012-10-13 05:48:00 +0900901 dp_video_config = devm_kzalloc(dev,
902 sizeof(*dp_video_config), GFP_KERNEL);
Ajay Kumarc4e235c2012-10-13 05:48:00 +0900903 if (!dp_video_config) {
904 dev_err(dev, "memory allocation for video config failed\n");
905 return ERR_PTR(-ENOMEM);
906 }
Ajay Kumarc4e235c2012-10-13 05:48:00 +0900907
908 dp_video_config->h_sync_polarity =
909 of_property_read_bool(dp_node, "hsync-active-high");
910
911 dp_video_config->v_sync_polarity =
912 of_property_read_bool(dp_node, "vsync-active-high");
913
914 dp_video_config->interlaced =
915 of_property_read_bool(dp_node, "interlaced");
916
917 if (of_property_read_u32(dp_node, "samsung,color-space",
918 &dp_video_config->color_space)) {
919 dev_err(dev, "failed to get color-space\n");
920 return ERR_PTR(-EINVAL);
921 }
922
923 if (of_property_read_u32(dp_node, "samsung,dynamic-range",
924 &dp_video_config->dynamic_range)) {
925 dev_err(dev, "failed to get dynamic-range\n");
926 return ERR_PTR(-EINVAL);
927 }
928
929 if (of_property_read_u32(dp_node, "samsung,ycbcr-coeff",
930 &dp_video_config->ycbcr_coeff)) {
931 dev_err(dev, "failed to get ycbcr-coeff\n");
932 return ERR_PTR(-EINVAL);
933 }
934
935 if (of_property_read_u32(dp_node, "samsung,color-depth",
936 &dp_video_config->color_depth)) {
937 dev_err(dev, "failed to get color-depth\n");
938 return ERR_PTR(-EINVAL);
939 }
940
941 if (of_property_read_u32(dp_node, "samsung,link-rate",
942 &dp_video_config->link_rate)) {
943 dev_err(dev, "failed to get link-rate\n");
944 return ERR_PTR(-EINVAL);
945 }
946
947 if (of_property_read_u32(dp_node, "samsung,lane-count",
948 &dp_video_config->lane_count)) {
949 dev_err(dev, "failed to get lane-count\n");
950 return ERR_PTR(-EINVAL);
951 }
952
Jingoo Hanf9b1e012013-10-16 21:58:15 +0530953 return dp_video_config;
Ajay Kumarc4e235c2012-10-13 05:48:00 +0900954}
955
956static int exynos_dp_dt_parse_phydata(struct exynos_dp_device *dp)
957{
Jingoo Hand3ed9702013-02-21 16:42:37 -0800958 struct device_node *dp_phy_node = of_node_get(dp->dev->of_node);
Ajay Kumarc4e235c2012-10-13 05:48:00 +0900959 u32 phy_base;
Jingoo Hand3ed9702013-02-21 16:42:37 -0800960 int ret = 0;
Ajay Kumarc4e235c2012-10-13 05:48:00 +0900961
Jingoo Hand3ed9702013-02-21 16:42:37 -0800962 dp_phy_node = of_find_node_by_name(dp_phy_node, "dptx-phy");
Ajay Kumarc4e235c2012-10-13 05:48:00 +0900963 if (!dp_phy_node) {
Jingoo Han8114fab2013-10-16 21:58:16 +0530964 dp->phy = devm_phy_get(dp->dev, "dp");
965 if (IS_ERR(dp->phy))
966 return PTR_ERR(dp->phy);
967 else
968 return 0;
Ajay Kumarc4e235c2012-10-13 05:48:00 +0900969 }
970
971 if (of_property_read_u32(dp_phy_node, "reg", &phy_base)) {
Masanari Iida1051e9b2013-03-31 01:23:50 +0900972 dev_err(dp->dev, "failed to get reg for dptx-phy\n");
Jingoo Hand3ed9702013-02-21 16:42:37 -0800973 ret = -EINVAL;
974 goto err;
Ajay Kumarc4e235c2012-10-13 05:48:00 +0900975 }
976
977 if (of_property_read_u32(dp_phy_node, "samsung,enable-mask",
978 &dp->enable_mask)) {
Masanari Iida1051e9b2013-03-31 01:23:50 +0900979 dev_err(dp->dev, "failed to get enable-mask for dptx-phy\n");
Jingoo Hand3ed9702013-02-21 16:42:37 -0800980 ret = -EINVAL;
981 goto err;
Ajay Kumarc4e235c2012-10-13 05:48:00 +0900982 }
983
984 dp->phy_addr = ioremap(phy_base, SZ_4);
985 if (!dp->phy_addr) {
986 dev_err(dp->dev, "failed to ioremap dp-phy\n");
Jingoo Hand3ed9702013-02-21 16:42:37 -0800987 ret = -ENOMEM;
988 goto err;
Ajay Kumarc4e235c2012-10-13 05:48:00 +0900989 }
990
Jingoo Hand3ed9702013-02-21 16:42:37 -0800991err:
992 of_node_put(dp_phy_node);
993
994 return ret;
Ajay Kumarc4e235c2012-10-13 05:48:00 +0900995}
996
997static void exynos_dp_phy_init(struct exynos_dp_device *dp)
998{
Jingoo Han8114fab2013-10-16 21:58:16 +0530999 if (dp->phy) {
1000 phy_power_on(dp->phy);
1001 } else if (dp->phy_addr) {
Jingoo Hanf9b1e012013-10-16 21:58:15 +05301002 u32 reg;
Ajay Kumarc4e235c2012-10-13 05:48:00 +09001003
Jingoo Hanf9b1e012013-10-16 21:58:15 +05301004 reg = __raw_readl(dp->phy_addr);
1005 reg |= dp->enable_mask;
1006 __raw_writel(reg, dp->phy_addr);
1007 }
Ajay Kumarc4e235c2012-10-13 05:48:00 +09001008}
1009
1010static void exynos_dp_phy_exit(struct exynos_dp_device *dp)
1011{
Jingoo Han8114fab2013-10-16 21:58:16 +05301012 if (dp->phy) {
1013 phy_power_off(dp->phy);
1014 } else if (dp->phy_addr) {
Jingoo Hanf9b1e012013-10-16 21:58:15 +05301015 u32 reg;
Ajay Kumarc4e235c2012-10-13 05:48:00 +09001016
Jingoo Hanf9b1e012013-10-16 21:58:15 +05301017 reg = __raw_readl(dp->phy_addr);
1018 reg &= ~(dp->enable_mask);
1019 __raw_writel(reg, dp->phy_addr);
1020 }
Ajay Kumarc4e235c2012-10-13 05:48:00 +09001021}
Ajay Kumarc4e235c2012-10-13 05:48:00 +09001022
Greg Kroah-Hartman48c68c42012-12-21 13:07:39 -08001023static int exynos_dp_probe(struct platform_device *pdev)
Jingoo Hane9474be2012-02-03 18:01:55 +09001024{
1025 struct resource *res;
1026 struct exynos_dp_device *dp;
Jingoo Hane9474be2012-02-03 18:01:55 +09001027
1028 int ret = 0;
1029
Jingoo Han4d10ecf82012-05-25 16:20:45 +09001030 dp = devm_kzalloc(&pdev->dev, sizeof(struct exynos_dp_device),
1031 GFP_KERNEL);
Jingoo Hane9474be2012-02-03 18:01:55 +09001032 if (!dp) {
1033 dev_err(&pdev->dev, "no memory for device data\n");
1034 return -ENOMEM;
1035 }
1036
1037 dp->dev = &pdev->dev;
1038
Jingoo Hanf9b1e012013-10-16 21:58:15 +05301039 dp->video_info = exynos_dp_dt_parse_pdata(&pdev->dev);
1040 if (IS_ERR(dp->video_info))
1041 return PTR_ERR(dp->video_info);
Ajay Kumarc4e235c2012-10-13 05:48:00 +09001042
Jingoo Hanf9b1e012013-10-16 21:58:15 +05301043 ret = exynos_dp_dt_parse_phydata(dp);
1044 if (ret)
1045 return ret;
Ajay Kumarc4e235c2012-10-13 05:48:00 +09001046
Damien Cassoud913f362012-08-01 18:20:39 +02001047 dp->clock = devm_clk_get(&pdev->dev, "dp");
Jingoo Hane9474be2012-02-03 18:01:55 +09001048 if (IS_ERR(dp->clock)) {
1049 dev_err(&pdev->dev, "failed to get clock\n");
Jingoo Han4d10ecf82012-05-25 16:20:45 +09001050 return PTR_ERR(dp->clock);
Jingoo Hane9474be2012-02-03 18:01:55 +09001051 }
1052
Jingoo Han37414fb2012-10-04 15:45:14 +09001053 clk_prepare_enable(dp->clock);
Jingoo Hane9474be2012-02-03 18:01:55 +09001054
1055 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
Jingoo Hane9474be2012-02-03 18:01:55 +09001056
Thierry Redingbc3bad12013-01-21 11:09:23 +01001057 dp->reg_base = devm_ioremap_resource(&pdev->dev, res);
1058 if (IS_ERR(dp->reg_base))
1059 return PTR_ERR(dp->reg_base);
Jingoo Hane9474be2012-02-03 18:01:55 +09001060
1061 dp->irq = platform_get_irq(pdev, 0);
Sean Paul1cefc1d2012-10-31 23:21:00 +00001062 if (dp->irq == -ENXIO) {
Jingoo Hane9474be2012-02-03 18:01:55 +09001063 dev_err(&pdev->dev, "failed to get irq\n");
Damien Cassoud913f362012-08-01 18:20:39 +02001064 return -ENODEV;
Jingoo Hane9474be2012-02-03 18:01:55 +09001065 }
1066
Sean Paul784fa9a2012-11-09 13:55:08 +09001067 INIT_WORK(&dp->hotplug_work, exynos_dp_hotplug);
1068
Jingoo Hanf9b1e012013-10-16 21:58:15 +05301069 exynos_dp_phy_init(dp);
Jingoo Hane9474be2012-02-03 18:01:55 +09001070
1071 exynos_dp_init_dp(dp);
1072
Ajay Kumar22ce19c2012-11-09 13:59:09 +09001073 ret = devm_request_irq(&pdev->dev, dp->irq, exynos_dp_irq_handler, 0,
1074 "exynos-dp", dp);
1075 if (ret) {
1076 dev_err(&pdev->dev, "failed to request irq\n");
1077 return ret;
1078 }
1079
Jingoo Hane9474be2012-02-03 18:01:55 +09001080 platform_set_drvdata(pdev, dp);
1081
1082 return 0;
Jingoo Hane9474be2012-02-03 18:01:55 +09001083}
1084
Greg Kroah-Hartman48c68c42012-12-21 13:07:39 -08001085static int exynos_dp_remove(struct platform_device *pdev)
Jingoo Hane9474be2012-02-03 18:01:55 +09001086{
Jingoo Hane9474be2012-02-03 18:01:55 +09001087 struct exynos_dp_device *dp = platform_get_drvdata(pdev);
1088
Tejun Heo7d0315a2012-12-21 17:57:13 -08001089 flush_work(&dp->hotplug_work);
Sean Paul784fa9a2012-11-09 13:55:08 +09001090
Jingoo Hanf9b1e012013-10-16 21:58:15 +05301091 exynos_dp_phy_exit(dp);
Jingoo Hane9474be2012-02-03 18:01:55 +09001092
Jingoo Han37414fb2012-10-04 15:45:14 +09001093 clk_disable_unprepare(dp->clock);
Jingoo Hane9474be2012-02-03 18:01:55 +09001094
Sean Paul784fa9a2012-11-09 13:55:08 +09001095
Jingoo Hane9474be2012-02-03 18:01:55 +09001096 return 0;
1097}
1098
1099#ifdef CONFIG_PM_SLEEP
1100static int exynos_dp_suspend(struct device *dev)
1101{
Ajay Kumarc4e235c2012-10-13 05:48:00 +09001102 struct exynos_dp_device *dp = dev_get_drvdata(dev);
Jingoo Hane9474be2012-02-03 18:01:55 +09001103
Ajay Kumar9ea8b9a2013-02-21 16:42:38 -08001104 disable_irq(dp->irq);
1105
Tejun Heo7d0315a2012-12-21 17:57:13 -08001106 flush_work(&dp->hotplug_work);
Sean Paul784fa9a2012-11-09 13:55:08 +09001107
Jingoo Hanf9b1e012013-10-16 21:58:15 +05301108 exynos_dp_phy_exit(dp);
Jingoo Hane9474be2012-02-03 18:01:55 +09001109
Jingoo Han37414fb2012-10-04 15:45:14 +09001110 clk_disable_unprepare(dp->clock);
Jingoo Hane9474be2012-02-03 18:01:55 +09001111
1112 return 0;
1113}
1114
1115static int exynos_dp_resume(struct device *dev)
1116{
Ajay Kumarc4e235c2012-10-13 05:48:00 +09001117 struct exynos_dp_device *dp = dev_get_drvdata(dev);
Jingoo Hane9474be2012-02-03 18:01:55 +09001118
Jingoo Hanf9b1e012013-10-16 21:58:15 +05301119 exynos_dp_phy_init(dp);
Jingoo Hane9474be2012-02-03 18:01:55 +09001120
Jingoo Han37414fb2012-10-04 15:45:14 +09001121 clk_prepare_enable(dp->clock);
Jingoo Hane9474be2012-02-03 18:01:55 +09001122
1123 exynos_dp_init_dp(dp);
1124
Sean Paulc30ffb92012-11-01 19:13:46 +09001125 enable_irq(dp->irq);
Jingoo Hane9474be2012-02-03 18:01:55 +09001126
1127 return 0;
1128}
1129#endif
1130
1131static const struct dev_pm_ops exynos_dp_pm_ops = {
1132 SET_SYSTEM_SLEEP_PM_OPS(exynos_dp_suspend, exynos_dp_resume)
1133};
1134
Ajay Kumarc4e235c2012-10-13 05:48:00 +09001135static const struct of_device_id exynos_dp_match[] = {
1136 { .compatible = "samsung,exynos5-dp" },
1137 {},
1138};
1139MODULE_DEVICE_TABLE(of, exynos_dp_match);
1140
Jingoo Hane9474be2012-02-03 18:01:55 +09001141static struct platform_driver exynos_dp_driver = {
1142 .probe = exynos_dp_probe,
Greg Kroah-Hartman48c68c42012-12-21 13:07:39 -08001143 .remove = exynos_dp_remove,
Jingoo Hane9474be2012-02-03 18:01:55 +09001144 .driver = {
1145 .name = "exynos-dp",
1146 .owner = THIS_MODULE,
1147 .pm = &exynos_dp_pm_ops,
Jingoo Hanf9b1e012013-10-16 21:58:15 +05301148 .of_match_table = exynos_dp_match,
Jingoo Hane9474be2012-02-03 18:01:55 +09001149 },
1150};
1151
1152module_platform_driver(exynos_dp_driver);
1153
1154MODULE_AUTHOR("Jingoo Han <jg1.han@samsung.com>");
1155MODULE_DESCRIPTION("Samsung SoC DP Driver");
1156MODULE_LICENSE("GPL");