2 * Samsung HDMI interface driver
4 * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
6 * Tomasz Stanislawski, <t.stanislaws@samsung.com>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published
10 * by the Free Software Foundiation. either version 2 of the License,
11 * or (at your option) any later version
14 #ifdef CONFIG_VIDEO_SAMSUNG_S5P_HDMI_DEBUG
18 #include <linux/kernel.h>
19 #include <linux/slab.h>
21 #include <linux/i2c.h>
22 #include <linux/platform_device.h>
23 #include <media/v4l2-subdev.h>
24 #include <linux/module.h>
25 #include <linux/interrupt.h>
26 #include <linux/irq.h>
27 #include <linux/delay.h>
28 #include <linux/bug.h>
29 #include <linux/pm_runtime.h>
30 #include <linux/clk.h>
31 #include <linux/regulator/consumer.h>
33 #include <media/s5p_hdmi.h>
34 #include <media/v4l2-common.h>
35 #include <media/v4l2-dev.h>
36 #include <media/v4l2-device.h>
38 #include "regs-hdmi.h"
40 MODULE_AUTHOR("Tomasz Stanislawski, <t.stanislaws@samsung.com>");
41 MODULE_DESCRIPTION("Samsung HDMI");
42 MODULE_LICENSE("GPL");
44 /* default preset configured on probe */
45 #define HDMI_DEFAULT_PRESET V4L2_DV_480P59_94
53 struct hdmi_pulse hact
;
54 u32 hsyn_pol
; /* 0 - high, 1 - low */
55 struct hdmi_pulse hsyn
;
57 struct hdmi_pulse vact
[2];
58 u32 vsyn_pol
; /* 0 - high, 1 - low */
60 struct hdmi_pulse vsyn
[2];
63 struct hdmi_resources
{
65 struct clk
*sclk_hdmi
;
66 struct clk
*sclk_pixel
;
67 struct clk
*sclk_hdmiphy
;
69 struct regulator_bulk_data
*regul_bulk
;
74 /** base address of HDMI registers */
78 /** pointer to device parent */
80 /** subdev generated by HDMI device */
81 struct v4l2_subdev sd
;
82 /** V4L2 device structure */
83 struct v4l2_device v4l2_dev
;
84 /** subdev of HDMIPHY interface */
85 struct v4l2_subdev
*phy_sd
;
86 /** subdev of MHL interface */
87 struct v4l2_subdev
*mhl_sd
;
88 /** configuration of current graphic mode */
89 const struct hdmi_timings
*cur_conf
;
90 /** flag indicating that timings are dirty */
94 /** other resources */
95 struct hdmi_resources res
;
98 static struct platform_device_id hdmi_driver_types
[] = {
100 .name
= "s5pv210-hdmi",
102 .name
= "exynos4-hdmi",
108 static const struct v4l2_subdev_ops hdmi_sd_ops
;
110 static struct hdmi_device
*sd_to_hdmi_dev(struct v4l2_subdev
*sd
)
112 return container_of(sd
, struct hdmi_device
, sd
);
116 void hdmi_write(struct hdmi_device
*hdev
, u32 reg_id
, u32 value
)
118 writel(value
, hdev
->regs
+ reg_id
);
122 void hdmi_write_mask(struct hdmi_device
*hdev
, u32 reg_id
, u32 value
, u32 mask
)
124 u32 old
= readl(hdev
->regs
+ reg_id
);
125 value
= (value
& mask
) | (old
& ~mask
);
126 writel(value
, hdev
->regs
+ reg_id
);
130 void hdmi_writeb(struct hdmi_device
*hdev
, u32 reg_id
, u8 value
)
132 writeb(value
, hdev
->regs
+ reg_id
);
136 void hdmi_writebn(struct hdmi_device
*hdev
, u32 reg_id
, int n
, u32 value
)
140 writeb(value
>> 24, hdev
->regs
+ reg_id
+ 12);
142 writeb(value
>> 16, hdev
->regs
+ reg_id
+ 8);
144 writeb(value
>> 8, hdev
->regs
+ reg_id
+ 4);
146 writeb(value
>> 0, hdev
->regs
+ reg_id
+ 0);
150 static inline u32
hdmi_read(struct hdmi_device
*hdev
, u32 reg_id
)
152 return readl(hdev
->regs
+ reg_id
);
155 static irqreturn_t
hdmi_irq_handler(int irq
, void *dev_data
)
157 struct hdmi_device
*hdev
= dev_data
;
161 intc_flag
= hdmi_read(hdev
, HDMI_INTC_FLAG
);
162 /* clearing flags for HPD plug/unplug */
163 if (intc_flag
& HDMI_INTC_FLAG_HPD_UNPLUG
) {
164 printk(KERN_INFO
"unplugged\n");
165 hdmi_write_mask(hdev
, HDMI_INTC_FLAG
, ~0,
166 HDMI_INTC_FLAG_HPD_UNPLUG
);
168 if (intc_flag
& HDMI_INTC_FLAG_HPD_PLUG
) {
169 printk(KERN_INFO
"plugged\n");
170 hdmi_write_mask(hdev
, HDMI_INTC_FLAG
, ~0,
171 HDMI_INTC_FLAG_HPD_PLUG
);
177 static void hdmi_reg_init(struct hdmi_device
*hdev
)
179 /* enable HPD interrupts */
180 hdmi_write_mask(hdev
, HDMI_INTC_CON
, ~0, HDMI_INTC_EN_GLOBAL
|
181 HDMI_INTC_EN_HPD_PLUG
| HDMI_INTC_EN_HPD_UNPLUG
);
182 /* choose DVI mode */
183 hdmi_write_mask(hdev
, HDMI_MODE_SEL
,
184 HDMI_MODE_DVI_EN
, HDMI_MODE_MASK
);
185 hdmi_write_mask(hdev
, HDMI_CON_2
, ~0,
186 HDMI_DVI_PERAMBLE_EN
| HDMI_DVI_BAND_EN
);
187 /* disable bluescreen */
188 hdmi_write_mask(hdev
, HDMI_CON_0
, 0, HDMI_BLUE_SCR_EN
);
189 /* choose bluescreen (fecal) color */
190 hdmi_writeb(hdev
, HDMI_BLUE_SCREEN_0
, 0x12);
191 hdmi_writeb(hdev
, HDMI_BLUE_SCREEN_1
, 0x34);
192 hdmi_writeb(hdev
, HDMI_BLUE_SCREEN_2
, 0x56);
195 static void hdmi_timing_apply(struct hdmi_device
*hdev
,
196 const struct hdmi_timings
*t
)
198 /* setting core registers */
199 hdmi_writebn(hdev
, HDMI_H_BLANK_0
, 2, t
->hact
.beg
);
200 hdmi_writebn(hdev
, HDMI_H_SYNC_GEN_0
, 3,
201 (t
->hsyn_pol
<< 20) | (t
->hsyn
.end
<< 10) | t
->hsyn
.beg
);
202 hdmi_writeb(hdev
, HDMI_VSYNC_POL
, t
->vsyn_pol
);
203 hdmi_writebn(hdev
, HDMI_V_BLANK_0
, 3,
204 (t
->vact
[0].beg
<< 11) | t
->vact
[0].end
);
205 hdmi_writebn(hdev
, HDMI_V_SYNC_GEN_1_0
, 3,
206 (t
->vsyn
[0].beg
<< 12) | t
->vsyn
[0].end
);
208 u32 vsyn_trans
= t
->hsyn
.beg
+ t
->vsyn_off
;
210 hdmi_writeb(hdev
, HDMI_INT_PRO_MODE
, 1);
211 hdmi_writebn(hdev
, HDMI_H_V_LINE_0
, 3,
212 (t
->hact
.end
<< 12) | t
->vact
[1].end
);
213 hdmi_writebn(hdev
, HDMI_V_BLANK_F_0
, 3,
214 (t
->vact
[1].end
<< 11) | t
->vact
[1].beg
);
215 hdmi_writebn(hdev
, HDMI_V_SYNC_GEN_2_0
, 3,
216 (t
->vsyn
[1].beg
<< 12) | t
->vsyn
[1].end
);
217 hdmi_writebn(hdev
, HDMI_V_SYNC_GEN_3_0
, 3,
218 (vsyn_trans
<< 12) | vsyn_trans
);
220 hdmi_writeb(hdev
, HDMI_INT_PRO_MODE
, 0);
221 hdmi_writebn(hdev
, HDMI_H_V_LINE_0
, 3,
222 (t
->hact
.end
<< 12) | t
->vact
[0].end
);
225 /* Timing generator registers */
226 hdmi_writebn(hdev
, HDMI_TG_H_FSZ_L
, 2, t
->hact
.end
);
227 hdmi_writebn(hdev
, HDMI_TG_HACT_ST_L
, 2, t
->hact
.beg
);
228 hdmi_writebn(hdev
, HDMI_TG_HACT_SZ_L
, 2, t
->hact
.end
- t
->hact
.beg
);
229 hdmi_writebn(hdev
, HDMI_TG_VSYNC_L
, 2, t
->vsyn
[0].beg
);
230 hdmi_writebn(hdev
, HDMI_TG_VACT_ST_L
, 2, t
->vact
[0].beg
);
231 hdmi_writebn(hdev
, HDMI_TG_VACT_SZ_L
, 2,
232 t
->vact
[0].end
- t
->vact
[0].beg
);
233 hdmi_writebn(hdev
, HDMI_TG_VSYNC_TOP_HDMI_L
, 2, t
->vsyn
[0].beg
);
234 hdmi_writebn(hdev
, HDMI_TG_FIELD_TOP_HDMI_L
, 2, t
->vsyn
[0].beg
);
236 hdmi_write_mask(hdev
, HDMI_TG_CMD
, ~0, HDMI_TG_FIELD_EN
);
237 hdmi_writebn(hdev
, HDMI_TG_V_FSZ_L
, 2, t
->vact
[1].end
);
238 hdmi_writebn(hdev
, HDMI_TG_VSYNC2_L
, 2, t
->vsyn
[1].beg
);
239 hdmi_writebn(hdev
, HDMI_TG_FIELD_CHG_L
, 2, t
->vact
[0].end
);
240 hdmi_writebn(hdev
, HDMI_TG_VACT_ST2_L
, 2, t
->vact
[1].beg
);
241 hdmi_writebn(hdev
, HDMI_TG_VSYNC_BOT_HDMI_L
, 2, t
->vsyn
[1].beg
);
242 hdmi_writebn(hdev
, HDMI_TG_FIELD_BOT_HDMI_L
, 2, t
->vsyn
[1].beg
);
244 hdmi_write_mask(hdev
, HDMI_TG_CMD
, 0, HDMI_TG_FIELD_EN
);
245 hdmi_writebn(hdev
, HDMI_TG_V_FSZ_L
, 2, t
->vact
[0].end
);
249 static int hdmi_conf_apply(struct hdmi_device
*hdmi_dev
)
251 struct device
*dev
= hdmi_dev
->dev
;
252 const struct hdmi_timings
*conf
= hdmi_dev
->cur_conf
;
253 struct v4l2_dv_preset preset
;
256 dev_dbg(dev
, "%s\n", __func__
);
258 /* skip if conf is already synchronized with HW */
259 if (!hdmi_dev
->cur_conf_dirty
)
263 hdmi_write_mask(hdmi_dev
, HDMI_PHY_RSTOUT
, ~0, HDMI_PHY_SW_RSTOUT
);
265 hdmi_write_mask(hdmi_dev
, HDMI_PHY_RSTOUT
, 0, HDMI_PHY_SW_RSTOUT
);
268 /* configure presets */
269 preset
.preset
= hdmi_dev
->cur_preset
;
270 ret
= v4l2_subdev_call(hdmi_dev
->phy_sd
, video
, s_dv_preset
, &preset
);
272 dev_err(dev
, "failed to set preset (%u)\n", preset
.preset
);
276 /* resetting HDMI core */
277 hdmi_write_mask(hdmi_dev
, HDMI_CORE_RSTOUT
, 0, HDMI_CORE_SW_RSTOUT
);
279 hdmi_write_mask(hdmi_dev
, HDMI_CORE_RSTOUT
, ~0, HDMI_CORE_SW_RSTOUT
);
282 hdmi_reg_init(hdmi_dev
);
284 /* setting core registers */
285 hdmi_timing_apply(hdmi_dev
, conf
);
287 hdmi_dev
->cur_conf_dirty
= 0;
292 static void hdmi_dumpregs(struct hdmi_device
*hdev
, char *prefix
)
294 #define DUMPREG(reg_id) \
295 dev_dbg(hdev->dev, "%s:" #reg_id " = %08x\n", prefix, \
296 readl(hdev->regs + reg_id))
298 dev_dbg(hdev
->dev
, "%s: ---- CONTROL REGISTERS ----\n", prefix
);
299 DUMPREG(HDMI_INTC_FLAG
);
300 DUMPREG(HDMI_INTC_CON
);
301 DUMPREG(HDMI_HPD_STATUS
);
302 DUMPREG(HDMI_PHY_RSTOUT
);
303 DUMPREG(HDMI_PHY_VPLL
);
304 DUMPREG(HDMI_PHY_CMU
);
305 DUMPREG(HDMI_CORE_RSTOUT
);
307 dev_dbg(hdev
->dev
, "%s: ---- CORE REGISTERS ----\n", prefix
);
311 DUMPREG(HDMI_SYS_STATUS
);
312 DUMPREG(HDMI_PHY_STATUS
);
313 DUMPREG(HDMI_STATUS_EN
);
315 DUMPREG(HDMI_MODE_SEL
);
316 DUMPREG(HDMI_HPD_GEN
);
317 DUMPREG(HDMI_DC_CONTROL
);
318 DUMPREG(HDMI_VIDEO_PATTERN_GEN
);
320 dev_dbg(hdev
->dev
, "%s: ---- CORE SYNC REGISTERS ----\n", prefix
);
321 DUMPREG(HDMI_H_BLANK_0
);
322 DUMPREG(HDMI_H_BLANK_1
);
323 DUMPREG(HDMI_V_BLANK_0
);
324 DUMPREG(HDMI_V_BLANK_1
);
325 DUMPREG(HDMI_V_BLANK_2
);
326 DUMPREG(HDMI_H_V_LINE_0
);
327 DUMPREG(HDMI_H_V_LINE_1
);
328 DUMPREG(HDMI_H_V_LINE_2
);
329 DUMPREG(HDMI_VSYNC_POL
);
330 DUMPREG(HDMI_INT_PRO_MODE
);
331 DUMPREG(HDMI_V_BLANK_F_0
);
332 DUMPREG(HDMI_V_BLANK_F_1
);
333 DUMPREG(HDMI_V_BLANK_F_2
);
334 DUMPREG(HDMI_H_SYNC_GEN_0
);
335 DUMPREG(HDMI_H_SYNC_GEN_1
);
336 DUMPREG(HDMI_H_SYNC_GEN_2
);
337 DUMPREG(HDMI_V_SYNC_GEN_1_0
);
338 DUMPREG(HDMI_V_SYNC_GEN_1_1
);
339 DUMPREG(HDMI_V_SYNC_GEN_1_2
);
340 DUMPREG(HDMI_V_SYNC_GEN_2_0
);
341 DUMPREG(HDMI_V_SYNC_GEN_2_1
);
342 DUMPREG(HDMI_V_SYNC_GEN_2_2
);
343 DUMPREG(HDMI_V_SYNC_GEN_3_0
);
344 DUMPREG(HDMI_V_SYNC_GEN_3_1
);
345 DUMPREG(HDMI_V_SYNC_GEN_3_2
);
347 dev_dbg(hdev
->dev
, "%s: ---- TG REGISTERS ----\n", prefix
);
348 DUMPREG(HDMI_TG_CMD
);
349 DUMPREG(HDMI_TG_H_FSZ_L
);
350 DUMPREG(HDMI_TG_H_FSZ_H
);
351 DUMPREG(HDMI_TG_HACT_ST_L
);
352 DUMPREG(HDMI_TG_HACT_ST_H
);
353 DUMPREG(HDMI_TG_HACT_SZ_L
);
354 DUMPREG(HDMI_TG_HACT_SZ_H
);
355 DUMPREG(HDMI_TG_V_FSZ_L
);
356 DUMPREG(HDMI_TG_V_FSZ_H
);
357 DUMPREG(HDMI_TG_VSYNC_L
);
358 DUMPREG(HDMI_TG_VSYNC_H
);
359 DUMPREG(HDMI_TG_VSYNC2_L
);
360 DUMPREG(HDMI_TG_VSYNC2_H
);
361 DUMPREG(HDMI_TG_VACT_ST_L
);
362 DUMPREG(HDMI_TG_VACT_ST_H
);
363 DUMPREG(HDMI_TG_VACT_SZ_L
);
364 DUMPREG(HDMI_TG_VACT_SZ_H
);
365 DUMPREG(HDMI_TG_FIELD_CHG_L
);
366 DUMPREG(HDMI_TG_FIELD_CHG_H
);
367 DUMPREG(HDMI_TG_VACT_ST2_L
);
368 DUMPREG(HDMI_TG_VACT_ST2_H
);
369 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_L
);
370 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_H
);
371 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_L
);
372 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_H
);
373 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_L
);
374 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_H
);
375 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_L
);
376 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_H
);
380 static const struct hdmi_timings hdmi_timings_480p
= {
381 .hact
= { .beg
= 138, .end
= 858 },
383 .hsyn
= { .beg
= 16, .end
= 16 + 62 },
385 .vact
[0] = { .beg
= 42 + 3, .end
= 522 + 3 },
387 .vsyn
[0] = { .beg
= 6 + 3, .end
= 12 + 3},
390 static const struct hdmi_timings hdmi_timings_576p50
= {
391 .hact
= { .beg
= 144, .end
= 864 },
393 .hsyn
= { .beg
= 12, .end
= 12 + 64 },
395 .vact
[0] = { .beg
= 44 + 5, .end
= 620 + 5 },
397 .vsyn
[0] = { .beg
= 0 + 5, .end
= 5 + 5},
400 static const struct hdmi_timings hdmi_timings_720p60
= {
401 .hact
= { .beg
= 370, .end
= 1650 },
403 .hsyn
= { .beg
= 110, .end
= 110 + 40 },
405 .vact
[0] = { .beg
= 25 + 5, .end
= 745 + 5 },
407 .vsyn
[0] = { .beg
= 0 + 5, .end
= 5 + 5},
410 static const struct hdmi_timings hdmi_timings_720p50
= {
411 .hact
= { .beg
= 700, .end
= 1980 },
413 .hsyn
= { .beg
= 440, .end
= 440 + 40 },
415 .vact
[0] = { .beg
= 25 + 5, .end
= 745 + 5 },
417 .vsyn
[0] = { .beg
= 0 + 5, .end
= 5 + 5},
420 static const struct hdmi_timings hdmi_timings_1080p24
= {
421 .hact
= { .beg
= 830, .end
= 2750 },
423 .hsyn
= { .beg
= 638, .end
= 638 + 44 },
425 .vact
[0] = { .beg
= 41 + 4, .end
= 1121 + 4 },
427 .vsyn
[0] = { .beg
= 0 + 4, .end
= 5 + 4},
430 static const struct hdmi_timings hdmi_timings_1080p60
= {
431 .hact
= { .beg
= 280, .end
= 2200 },
433 .hsyn
= { .beg
= 88, .end
= 88 + 44 },
435 .vact
[0] = { .beg
= 41 + 4, .end
= 1121 + 4 },
437 .vsyn
[0] = { .beg
= 0 + 4, .end
= 5 + 4},
440 static const struct hdmi_timings hdmi_timings_1080i60
= {
441 .hact
= { .beg
= 280, .end
= 2200 },
443 .hsyn
= { .beg
= 88, .end
= 88 + 44 },
445 .vact
[0] = { .beg
= 20 + 2, .end
= 560 + 2 },
446 .vact
[1] = { .beg
= 583 + 2, .end
= 1123 + 2 },
449 .vsyn
[0] = { .beg
= 0 + 2, .end
= 5 + 2},
450 .vsyn
[1] = { .beg
= 562 + 2, .end
= 567 + 2},
453 static const struct hdmi_timings hdmi_timings_1080i50
= {
454 .hact
= { .beg
= 720, .end
= 2640 },
456 .hsyn
= { .beg
= 528, .end
= 528 + 44 },
458 .vact
[0] = { .beg
= 20 + 2, .end
= 560 + 2 },
459 .vact
[1] = { .beg
= 583 + 2, .end
= 1123 + 2 },
462 .vsyn
[0] = { .beg
= 0 + 2, .end
= 5 + 2},
463 .vsyn
[1] = { .beg
= 562 + 2, .end
= 567 + 2},
466 static const struct hdmi_timings hdmi_timings_1080p50
= {
467 .hact
= { .beg
= 720, .end
= 2640 },
469 .hsyn
= { .beg
= 528, .end
= 528 + 44 },
471 .vact
[0] = { .beg
= 41 + 4, .end
= 1121 + 4 },
473 .vsyn
[0] = { .beg
= 0 + 4, .end
= 5 + 4},
476 static const struct {
478 const struct hdmi_timings
*timings
;
480 { V4L2_DV_480P59_94
, &hdmi_timings_480p
},
481 { V4L2_DV_576P50
, &hdmi_timings_576p50
},
482 { V4L2_DV_720P50
, &hdmi_timings_720p50
},
483 { V4L2_DV_720P59_94
, &hdmi_timings_720p60
},
484 { V4L2_DV_720P60
, &hdmi_timings_720p60
},
485 { V4L2_DV_1080P24
, &hdmi_timings_1080p24
},
486 { V4L2_DV_1080P30
, &hdmi_timings_1080p60
},
487 { V4L2_DV_1080P50
, &hdmi_timings_1080p50
},
488 { V4L2_DV_1080I50
, &hdmi_timings_1080i50
},
489 { V4L2_DV_1080I60
, &hdmi_timings_1080i60
},
490 { V4L2_DV_1080P60
, &hdmi_timings_1080p60
},
493 static const struct hdmi_timings
*hdmi_preset2timings(u32 preset
)
497 for (i
= 0; i
< ARRAY_SIZE(hdmi_timings
); ++i
)
498 if (hdmi_timings
[i
].preset
== preset
)
499 return hdmi_timings
[i
].timings
;
503 static int hdmi_streamon(struct hdmi_device
*hdev
)
505 struct device
*dev
= hdev
->dev
;
506 struct hdmi_resources
*res
= &hdev
->res
;
509 dev_dbg(dev
, "%s\n", __func__
);
511 ret
= hdmi_conf_apply(hdev
);
515 ret
= v4l2_subdev_call(hdev
->phy_sd
, video
, s_stream
, 1);
519 /* waiting for HDMIPHY's PLL to get to steady state */
520 for (tries
= 100; tries
; --tries
) {
521 u32 val
= hdmi_read(hdev
, HDMI_PHY_STATUS
);
522 if (val
& HDMI_PHY_STATUS_READY
)
526 /* steady state not achieved */
528 dev_err(dev
, "hdmiphy's pll could not reach steady state.\n");
529 v4l2_subdev_call(hdev
->phy_sd
, video
, s_stream
, 0);
530 hdmi_dumpregs(hdev
, "hdmiphy - s_stream");
535 ret
= v4l2_subdev_call(hdev
->mhl_sd
, video
, s_stream
, 1);
536 if (hdev
->mhl_sd
&& ret
) {
537 v4l2_subdev_call(hdev
->phy_sd
, video
, s_stream
, 0);
538 hdmi_dumpregs(hdev
, "mhl - s_stream");
542 /* hdmiphy clock is used for HDMI in streaming mode */
543 clk_disable(res
->sclk_hdmi
);
544 clk_set_parent(res
->sclk_hdmi
, res
->sclk_hdmiphy
);
545 clk_enable(res
->sclk_hdmi
);
547 /* enable HDMI and timing generator */
548 hdmi_write_mask(hdev
, HDMI_CON_0
, ~0, HDMI_EN
);
549 hdmi_write_mask(hdev
, HDMI_TG_CMD
, ~0, HDMI_TG_EN
);
550 hdmi_dumpregs(hdev
, "streamon");
554 static int hdmi_streamoff(struct hdmi_device
*hdev
)
556 struct device
*dev
= hdev
->dev
;
557 struct hdmi_resources
*res
= &hdev
->res
;
559 dev_dbg(dev
, "%s\n", __func__
);
561 hdmi_write_mask(hdev
, HDMI_CON_0
, 0, HDMI_EN
);
562 hdmi_write_mask(hdev
, HDMI_TG_CMD
, 0, HDMI_TG_EN
);
564 /* pixel(vpll) clock is used for HDMI in config mode */
565 clk_disable(res
->sclk_hdmi
);
566 clk_set_parent(res
->sclk_hdmi
, res
->sclk_pixel
);
567 clk_enable(res
->sclk_hdmi
);
569 v4l2_subdev_call(hdev
->mhl_sd
, video
, s_stream
, 0);
570 v4l2_subdev_call(hdev
->phy_sd
, video
, s_stream
, 0);
572 hdmi_dumpregs(hdev
, "streamoff");
576 static int hdmi_s_stream(struct v4l2_subdev
*sd
, int enable
)
578 struct hdmi_device
*hdev
= sd_to_hdmi_dev(sd
);
579 struct device
*dev
= hdev
->dev
;
581 dev_dbg(dev
, "%s(%d)\n", __func__
, enable
);
583 return hdmi_streamon(hdev
);
584 return hdmi_streamoff(hdev
);
587 static void hdmi_resource_poweron(struct hdmi_resources
*res
)
589 /* turn HDMI power on */
590 regulator_bulk_enable(res
->regul_count
, res
->regul_bulk
);
591 /* power-on hdmi physical interface */
592 clk_enable(res
->hdmiphy
);
593 /* use VPP as parent clock; HDMIPHY is not working yet */
594 clk_set_parent(res
->sclk_hdmi
, res
->sclk_pixel
);
596 clk_enable(res
->sclk_hdmi
);
599 static void hdmi_resource_poweroff(struct hdmi_resources
*res
)
601 /* turn clocks off */
602 clk_disable(res
->sclk_hdmi
);
603 /* power-off hdmiphy */
604 clk_disable(res
->hdmiphy
);
605 /* turn HDMI power off */
606 regulator_bulk_disable(res
->regul_count
, res
->regul_bulk
);
609 static int hdmi_s_power(struct v4l2_subdev
*sd
, int on
)
611 struct hdmi_device
*hdev
= sd_to_hdmi_dev(sd
);
615 ret
= pm_runtime_get_sync(hdev
->dev
);
617 ret
= pm_runtime_put_sync(hdev
->dev
);
618 /* only values < 0 indicate errors */
619 return IS_ERR_VALUE(ret
) ? ret
: 0;
622 static int hdmi_s_dv_preset(struct v4l2_subdev
*sd
,
623 struct v4l2_dv_preset
*preset
)
625 struct hdmi_device
*hdev
= sd_to_hdmi_dev(sd
);
626 struct device
*dev
= hdev
->dev
;
627 const struct hdmi_timings
*conf
;
629 conf
= hdmi_preset2timings(preset
->preset
);
631 dev_err(dev
, "preset (%u) not supported\n", preset
->preset
);
634 hdev
->cur_conf
= conf
;
635 hdev
->cur_conf_dirty
= 1;
636 hdev
->cur_preset
= preset
->preset
;
640 static int hdmi_g_dv_preset(struct v4l2_subdev
*sd
,
641 struct v4l2_dv_preset
*preset
)
643 memset(preset
, 0, sizeof(*preset
));
644 preset
->preset
= sd_to_hdmi_dev(sd
)->cur_preset
;
648 static int hdmi_g_mbus_fmt(struct v4l2_subdev
*sd
,
649 struct v4l2_mbus_framefmt
*fmt
)
651 struct hdmi_device
*hdev
= sd_to_hdmi_dev(sd
);
652 const struct hdmi_timings
*t
= hdev
->cur_conf
;
654 dev_dbg(hdev
->dev
, "%s\n", __func__
);
657 memset(fmt
, 0, sizeof *fmt
);
658 fmt
->width
= t
->hact
.end
- t
->hact
.beg
;
659 fmt
->height
= t
->vact
[0].end
- t
->vact
[0].beg
;
660 fmt
->code
= V4L2_MBUS_FMT_FIXED
; /* means RGB888 */
661 fmt
->colorspace
= V4L2_COLORSPACE_SRGB
;
663 fmt
->field
= V4L2_FIELD_INTERLACED
;
666 fmt
->field
= V4L2_FIELD_NONE
;
671 static int hdmi_enum_dv_presets(struct v4l2_subdev
*sd
,
672 struct v4l2_dv_enum_preset
*preset
)
674 if (preset
->index
>= ARRAY_SIZE(hdmi_timings
))
676 return v4l_fill_dv_preset_info(hdmi_timings
[preset
->index
].preset
,
680 static const struct v4l2_subdev_core_ops hdmi_sd_core_ops
= {
681 .s_power
= hdmi_s_power
,
684 static const struct v4l2_subdev_video_ops hdmi_sd_video_ops
= {
685 .s_dv_preset
= hdmi_s_dv_preset
,
686 .g_dv_preset
= hdmi_g_dv_preset
,
687 .enum_dv_presets
= hdmi_enum_dv_presets
,
688 .g_mbus_fmt
= hdmi_g_mbus_fmt
,
689 .s_stream
= hdmi_s_stream
,
692 static const struct v4l2_subdev_ops hdmi_sd_ops
= {
693 .core
= &hdmi_sd_core_ops
,
694 .video
= &hdmi_sd_video_ops
,
697 static int hdmi_runtime_suspend(struct device
*dev
)
699 struct v4l2_subdev
*sd
= dev_get_drvdata(dev
);
700 struct hdmi_device
*hdev
= sd_to_hdmi_dev(sd
);
702 dev_dbg(dev
, "%s\n", __func__
);
703 v4l2_subdev_call(hdev
->mhl_sd
, core
, s_power
, 0);
704 hdmi_resource_poweroff(&hdev
->res
);
705 /* flag that device context is lost */
706 hdev
->cur_conf_dirty
= 1;
710 static int hdmi_runtime_resume(struct device
*dev
)
712 struct v4l2_subdev
*sd
= dev_get_drvdata(dev
);
713 struct hdmi_device
*hdev
= sd_to_hdmi_dev(sd
);
716 dev_dbg(dev
, "%s\n", __func__
);
718 hdmi_resource_poweron(&hdev
->res
);
721 ret
= v4l2_subdev_call(hdev
->mhl_sd
, core
, s_power
, 1);
722 if (hdev
->mhl_sd
&& ret
)
725 dev_dbg(dev
, "poweron succeed\n");
730 hdmi_resource_poweroff(&hdev
->res
);
731 dev_err(dev
, "poweron failed\n");
736 static const struct dev_pm_ops hdmi_pm_ops
= {
737 .runtime_suspend
= hdmi_runtime_suspend
,
738 .runtime_resume
= hdmi_runtime_resume
,
741 static void hdmi_resources_cleanup(struct hdmi_device
*hdev
)
743 struct hdmi_resources
*res
= &hdev
->res
;
745 dev_dbg(hdev
->dev
, "HDMI resource cleanup\n");
746 /* put clocks, power */
747 if (res
->regul_count
)
748 regulator_bulk_free(res
->regul_count
, res
->regul_bulk
);
749 /* kfree is NULL-safe */
750 kfree(res
->regul_bulk
);
751 if (!IS_ERR_OR_NULL(res
->hdmiphy
))
752 clk_put(res
->hdmiphy
);
753 if (!IS_ERR_OR_NULL(res
->sclk_hdmiphy
))
754 clk_put(res
->sclk_hdmiphy
);
755 if (!IS_ERR_OR_NULL(res
->sclk_pixel
))
756 clk_put(res
->sclk_pixel
);
757 if (!IS_ERR_OR_NULL(res
->sclk_hdmi
))
758 clk_put(res
->sclk_hdmi
);
759 if (!IS_ERR_OR_NULL(res
->hdmi
))
761 memset(res
, 0, sizeof *res
);
764 static int hdmi_resources_init(struct hdmi_device
*hdev
)
766 struct device
*dev
= hdev
->dev
;
767 struct hdmi_resources
*res
= &hdev
->res
;
768 static char *supply
[] = {
776 dev_dbg(dev
, "HDMI resource init\n");
778 memset(res
, 0, sizeof *res
);
779 /* get clocks, power */
781 res
->hdmi
= clk_get(dev
, "hdmi");
782 if (IS_ERR_OR_NULL(res
->hdmi
)) {
783 dev_err(dev
, "failed to get clock 'hdmi'\n");
786 res
->sclk_hdmi
= clk_get(dev
, "sclk_hdmi");
787 if (IS_ERR_OR_NULL(res
->sclk_hdmi
)) {
788 dev_err(dev
, "failed to get clock 'sclk_hdmi'\n");
791 res
->sclk_pixel
= clk_get(dev
, "sclk_pixel");
792 if (IS_ERR_OR_NULL(res
->sclk_pixel
)) {
793 dev_err(dev
, "failed to get clock 'sclk_pixel'\n");
796 res
->sclk_hdmiphy
= clk_get(dev
, "sclk_hdmiphy");
797 if (IS_ERR_OR_NULL(res
->sclk_hdmiphy
)) {
798 dev_err(dev
, "failed to get clock 'sclk_hdmiphy'\n");
801 res
->hdmiphy
= clk_get(dev
, "hdmiphy");
802 if (IS_ERR_OR_NULL(res
->hdmiphy
)) {
803 dev_err(dev
, "failed to get clock 'hdmiphy'\n");
806 res
->regul_bulk
= kcalloc(ARRAY_SIZE(supply
),
807 sizeof(res
->regul_bulk
[0]), GFP_KERNEL
);
808 if (!res
->regul_bulk
) {
809 dev_err(dev
, "failed to get memory for regulators\n");
812 for (i
= 0; i
< ARRAY_SIZE(supply
); ++i
) {
813 res
->regul_bulk
[i
].supply
= supply
[i
];
814 res
->regul_bulk
[i
].consumer
= NULL
;
817 ret
= regulator_bulk_get(dev
, ARRAY_SIZE(supply
), res
->regul_bulk
);
819 dev_err(dev
, "failed to get regulators\n");
822 res
->regul_count
= ARRAY_SIZE(supply
);
826 dev_err(dev
, "HDMI resource init - failed\n");
827 hdmi_resources_cleanup(hdev
);
831 static int __devinit
hdmi_probe(struct platform_device
*pdev
)
833 struct device
*dev
= &pdev
->dev
;
834 struct resource
*res
;
835 struct i2c_adapter
*adapter
;
836 struct v4l2_subdev
*sd
;
837 struct hdmi_device
*hdmi_dev
= NULL
;
838 struct s5p_hdmi_platform_data
*pdata
= dev
->platform_data
;
841 dev_dbg(dev
, "probe start\n");
844 dev_err(dev
, "platform data is missing\n");
849 hdmi_dev
= devm_kzalloc(&pdev
->dev
, sizeof(*hdmi_dev
), GFP_KERNEL
);
851 dev_err(dev
, "out of memory\n");
858 ret
= hdmi_resources_init(hdmi_dev
);
862 /* mapping HDMI registers */
863 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
865 dev_err(dev
, "get memory resource failed.\n");
870 hdmi_dev
->regs
= devm_ioremap(&pdev
->dev
, res
->start
,
872 if (hdmi_dev
->regs
== NULL
) {
873 dev_err(dev
, "register mapping failed.\n");
878 res
= platform_get_resource(pdev
, IORESOURCE_IRQ
, 0);
880 dev_err(dev
, "get interrupt resource failed.\n");
885 ret
= devm_request_irq(&pdev
->dev
, res
->start
, hdmi_irq_handler
, 0,
888 dev_err(dev
, "request interrupt failed.\n");
891 hdmi_dev
->irq
= res
->start
;
893 /* setting v4l2 name to prevent WARN_ON in v4l2_device_register */
894 strlcpy(hdmi_dev
->v4l2_dev
.name
, dev_name(dev
),
895 sizeof(hdmi_dev
->v4l2_dev
.name
));
896 /* passing NULL owner prevents driver from erasing drvdata */
897 ret
= v4l2_device_register(NULL
, &hdmi_dev
->v4l2_dev
);
899 dev_err(dev
, "could not register v4l2 device.\n");
903 /* testing if hdmiphy info is present */
904 if (!pdata
->hdmiphy_info
) {
905 dev_err(dev
, "hdmiphy info is missing in platform data\n");
910 adapter
= i2c_get_adapter(pdata
->hdmiphy_bus
);
911 if (adapter
== NULL
) {
912 dev_err(dev
, "hdmiphy adapter request failed\n");
917 hdmi_dev
->phy_sd
= v4l2_i2c_new_subdev_board(&hdmi_dev
->v4l2_dev
,
918 adapter
, pdata
->hdmiphy_info
, NULL
);
919 /* on failure or not adapter is no longer useful */
920 i2c_put_adapter(adapter
);
921 if (hdmi_dev
->phy_sd
== NULL
) {
922 dev_err(dev
, "missing subdev for hdmiphy\n");
927 /* initialization of MHL interface if present */
928 if (pdata
->mhl_info
) {
929 adapter
= i2c_get_adapter(pdata
->mhl_bus
);
930 if (adapter
== NULL
) {
931 dev_err(dev
, "MHL adapter request failed\n");
936 hdmi_dev
->mhl_sd
= v4l2_i2c_new_subdev_board(
937 &hdmi_dev
->v4l2_dev
, adapter
,
938 pdata
->mhl_info
, NULL
);
939 /* on failure or not adapter is no longer useful */
940 i2c_put_adapter(adapter
);
941 if (hdmi_dev
->mhl_sd
== NULL
) {
942 dev_err(dev
, "missing subdev for MHL\n");
948 clk_enable(hdmi_dev
->res
.hdmi
);
950 pm_runtime_enable(dev
);
953 v4l2_subdev_init(sd
, &hdmi_sd_ops
);
954 sd
->owner
= THIS_MODULE
;
956 strlcpy(sd
->name
, "s5p-hdmi", sizeof sd
->name
);
957 hdmi_dev
->cur_preset
= HDMI_DEFAULT_PRESET
;
958 /* FIXME: missing fail preset is not supported */
959 hdmi_dev
->cur_conf
= hdmi_preset2timings(hdmi_dev
->cur_preset
);
960 hdmi_dev
->cur_conf_dirty
= 1;
962 /* storing subdev for call that have only access to struct device */
963 dev_set_drvdata(dev
, sd
);
965 dev_info(dev
, "probe successful\n");
970 v4l2_device_unregister(&hdmi_dev
->v4l2_dev
);
973 hdmi_resources_cleanup(hdmi_dev
);
976 dev_err(dev
, "probe failed\n");
980 static int __devexit
hdmi_remove(struct platform_device
*pdev
)
982 struct device
*dev
= &pdev
->dev
;
983 struct v4l2_subdev
*sd
= dev_get_drvdata(dev
);
984 struct hdmi_device
*hdmi_dev
= sd_to_hdmi_dev(sd
);
986 pm_runtime_disable(dev
);
987 clk_disable(hdmi_dev
->res
.hdmi
);
988 v4l2_device_unregister(&hdmi_dev
->v4l2_dev
);
989 disable_irq(hdmi_dev
->irq
);
990 hdmi_resources_cleanup(hdmi_dev
);
991 dev_info(dev
, "remove successful\n");
996 static struct platform_driver hdmi_driver __refdata
= {
998 .remove
= __devexit_p(hdmi_remove
),
999 .id_table
= hdmi_driver_types
,
1002 .owner
= THIS_MODULE
,
1007 module_platform_driver(hdmi_driver
);