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 #define pr_fmt(fmt) "s5p-tv (hdmi_drv): " fmt
16 #ifdef CONFIG_VIDEO_SAMSUNG_S5P_HDMI_DEBUG
20 #include <linux/kernel.h>
21 #include <linux/slab.h>
23 #include <linux/i2c.h>
24 #include <linux/platform_device.h>
25 #include <media/v4l2-subdev.h>
26 #include <linux/module.h>
27 #include <linux/interrupt.h>
28 #include <linux/irq.h>
29 #include <linux/delay.h>
30 #include <linux/bug.h>
31 #include <linux/pm_runtime.h>
32 #include <linux/clk.h>
33 #include <linux/regulator/consumer.h>
34 #include <linux/v4l2-dv-timings.h>
36 #include <linux/platform_data/media/s5p_hdmi.h>
37 #include <media/v4l2-common.h>
38 #include <media/v4l2-dev.h>
39 #include <media/v4l2-device.h>
40 #include <media/v4l2-dv-timings.h>
42 #include "regs-hdmi.h"
44 MODULE_AUTHOR("Tomasz Stanislawski, <t.stanislaws@samsung.com>");
45 MODULE_DESCRIPTION("Samsung HDMI");
46 MODULE_LICENSE("GPL");
54 struct hdmi_pulse hact
;
55 u32 hsyn_pol
; /* 0 - high, 1 - low */
56 struct hdmi_pulse hsyn
;
58 struct hdmi_pulse vact
[2];
59 u32 vsyn_pol
; /* 0 - high, 1 - low */
61 struct hdmi_pulse vsyn
[2];
64 struct hdmi_resources
{
66 struct clk
*sclk_hdmi
;
67 struct clk
*sclk_pixel
;
68 struct clk
*sclk_hdmiphy
;
70 struct regulator_bulk_data
*regul_bulk
;
75 /** base address of HDMI registers */
79 /** pointer to device parent */
81 /** subdev generated by HDMI device */
82 struct v4l2_subdev sd
;
83 /** V4L2 device structure */
84 struct v4l2_device v4l2_dev
;
85 /** subdev of HDMIPHY interface */
86 struct v4l2_subdev
*phy_sd
;
87 /** subdev of MHL interface */
88 struct v4l2_subdev
*mhl_sd
;
89 /** configuration of current graphic mode */
90 const struct hdmi_timings
*cur_conf
;
91 /** flag indicating that timings are dirty */
93 /** current timings */
94 struct v4l2_dv_timings cur_timings
;
95 /** other resources */
96 struct hdmi_resources res
;
99 static const struct platform_device_id hdmi_driver_types
[] = {
101 .name
= "s5pv210-hdmi",
103 .name
= "exynos4-hdmi",
109 static const struct v4l2_subdev_ops hdmi_sd_ops
;
111 static struct hdmi_device
*sd_to_hdmi_dev(struct v4l2_subdev
*sd
)
113 return container_of(sd
, struct hdmi_device
, sd
);
117 void hdmi_write(struct hdmi_device
*hdev
, u32 reg_id
, u32 value
)
119 writel(value
, hdev
->regs
+ reg_id
);
123 void hdmi_write_mask(struct hdmi_device
*hdev
, u32 reg_id
, u32 value
, u32 mask
)
125 u32 old
= readl(hdev
->regs
+ reg_id
);
126 value
= (value
& mask
) | (old
& ~mask
);
127 writel(value
, hdev
->regs
+ reg_id
);
131 void hdmi_writeb(struct hdmi_device
*hdev
, u32 reg_id
, u8 value
)
133 writeb(value
, hdev
->regs
+ reg_id
);
137 void hdmi_writebn(struct hdmi_device
*hdev
, u32 reg_id
, int n
, u32 value
)
141 writeb(value
>> 24, hdev
->regs
+ reg_id
+ 12);
143 writeb(value
>> 16, hdev
->regs
+ reg_id
+ 8);
145 writeb(value
>> 8, hdev
->regs
+ reg_id
+ 4);
147 writeb(value
>> 0, hdev
->regs
+ reg_id
+ 0);
151 static inline u32
hdmi_read(struct hdmi_device
*hdev
, u32 reg_id
)
153 return readl(hdev
->regs
+ reg_id
);
156 static irqreturn_t
hdmi_irq_handler(int irq
, void *dev_data
)
158 struct hdmi_device
*hdev
= dev_data
;
162 intc_flag
= hdmi_read(hdev
, HDMI_INTC_FLAG
);
163 /* clearing flags for HPD plug/unplug */
164 if (intc_flag
& HDMI_INTC_FLAG_HPD_UNPLUG
) {
165 pr_info("unplugged\n");
166 hdmi_write_mask(hdev
, HDMI_INTC_FLAG
, ~0,
167 HDMI_INTC_FLAG_HPD_UNPLUG
);
169 if (intc_flag
& HDMI_INTC_FLAG_HPD_PLUG
) {
170 pr_info("plugged\n");
171 hdmi_write_mask(hdev
, HDMI_INTC_FLAG
, ~0,
172 HDMI_INTC_FLAG_HPD_PLUG
);
178 static void hdmi_reg_init(struct hdmi_device
*hdev
)
180 /* enable HPD interrupts */
181 hdmi_write_mask(hdev
, HDMI_INTC_CON
, ~0, HDMI_INTC_EN_GLOBAL
|
182 HDMI_INTC_EN_HPD_PLUG
| HDMI_INTC_EN_HPD_UNPLUG
);
183 /* choose DVI mode */
184 hdmi_write_mask(hdev
, HDMI_MODE_SEL
,
185 HDMI_MODE_DVI_EN
, HDMI_MODE_MASK
);
186 hdmi_write_mask(hdev
, HDMI_CON_2
, ~0,
187 HDMI_DVI_PERAMBLE_EN
| HDMI_DVI_BAND_EN
);
188 /* disable bluescreen */
189 hdmi_write_mask(hdev
, HDMI_CON_0
, 0, HDMI_BLUE_SCR_EN
);
190 /* choose bluescreen (fecal) color */
191 hdmi_writeb(hdev
, HDMI_BLUE_SCREEN_0
, 0x12);
192 hdmi_writeb(hdev
, HDMI_BLUE_SCREEN_1
, 0x34);
193 hdmi_writeb(hdev
, HDMI_BLUE_SCREEN_2
, 0x56);
196 static void hdmi_timing_apply(struct hdmi_device
*hdev
,
197 const struct hdmi_timings
*t
)
199 /* setting core registers */
200 hdmi_writebn(hdev
, HDMI_H_BLANK_0
, 2, t
->hact
.beg
);
201 hdmi_writebn(hdev
, HDMI_H_SYNC_GEN_0
, 3,
202 (t
->hsyn_pol
<< 20) | (t
->hsyn
.end
<< 10) | t
->hsyn
.beg
);
203 hdmi_writeb(hdev
, HDMI_VSYNC_POL
, t
->vsyn_pol
);
204 hdmi_writebn(hdev
, HDMI_V_BLANK_0
, 3,
205 (t
->vact
[0].beg
<< 11) | t
->vact
[0].end
);
206 hdmi_writebn(hdev
, HDMI_V_SYNC_GEN_1_0
, 3,
207 (t
->vsyn
[0].beg
<< 12) | t
->vsyn
[0].end
);
209 u32 vsyn_trans
= t
->hsyn
.beg
+ t
->vsyn_off
;
211 hdmi_writeb(hdev
, HDMI_INT_PRO_MODE
, 1);
212 hdmi_writebn(hdev
, HDMI_H_V_LINE_0
, 3,
213 (t
->hact
.end
<< 12) | t
->vact
[1].end
);
214 hdmi_writebn(hdev
, HDMI_V_BLANK_F_0
, 3,
215 (t
->vact
[1].end
<< 11) | t
->vact
[1].beg
);
216 hdmi_writebn(hdev
, HDMI_V_SYNC_GEN_2_0
, 3,
217 (t
->vsyn
[1].beg
<< 12) | t
->vsyn
[1].end
);
218 hdmi_writebn(hdev
, HDMI_V_SYNC_GEN_3_0
, 3,
219 (vsyn_trans
<< 12) | vsyn_trans
);
221 hdmi_writeb(hdev
, HDMI_INT_PRO_MODE
, 0);
222 hdmi_writebn(hdev
, HDMI_H_V_LINE_0
, 3,
223 (t
->hact
.end
<< 12) | t
->vact
[0].end
);
226 /* Timing generator registers */
227 hdmi_writebn(hdev
, HDMI_TG_H_FSZ_L
, 2, t
->hact
.end
);
228 hdmi_writebn(hdev
, HDMI_TG_HACT_ST_L
, 2, t
->hact
.beg
);
229 hdmi_writebn(hdev
, HDMI_TG_HACT_SZ_L
, 2, t
->hact
.end
- t
->hact
.beg
);
230 hdmi_writebn(hdev
, HDMI_TG_VSYNC_L
, 2, t
->vsyn
[0].beg
);
231 hdmi_writebn(hdev
, HDMI_TG_VACT_ST_L
, 2, t
->vact
[0].beg
);
232 hdmi_writebn(hdev
, HDMI_TG_VACT_SZ_L
, 2,
233 t
->vact
[0].end
- t
->vact
[0].beg
);
234 hdmi_writebn(hdev
, HDMI_TG_VSYNC_TOP_HDMI_L
, 2, t
->vsyn
[0].beg
);
235 hdmi_writebn(hdev
, HDMI_TG_FIELD_TOP_HDMI_L
, 2, t
->vsyn
[0].beg
);
237 hdmi_write_mask(hdev
, HDMI_TG_CMD
, ~0, HDMI_TG_FIELD_EN
);
238 hdmi_writebn(hdev
, HDMI_TG_V_FSZ_L
, 2, t
->vact
[1].end
);
239 hdmi_writebn(hdev
, HDMI_TG_VSYNC2_L
, 2, t
->vsyn
[1].beg
);
240 hdmi_writebn(hdev
, HDMI_TG_FIELD_CHG_L
, 2, t
->vact
[0].end
);
241 hdmi_writebn(hdev
, HDMI_TG_VACT_ST2_L
, 2, t
->vact
[1].beg
);
242 hdmi_writebn(hdev
, HDMI_TG_VSYNC_BOT_HDMI_L
, 2, t
->vsyn
[1].beg
);
243 hdmi_writebn(hdev
, HDMI_TG_FIELD_BOT_HDMI_L
, 2, t
->vsyn
[1].beg
);
245 hdmi_write_mask(hdev
, HDMI_TG_CMD
, 0, HDMI_TG_FIELD_EN
);
246 hdmi_writebn(hdev
, HDMI_TG_V_FSZ_L
, 2, t
->vact
[0].end
);
250 static int hdmi_conf_apply(struct hdmi_device
*hdmi_dev
)
252 struct device
*dev
= hdmi_dev
->dev
;
253 const struct hdmi_timings
*conf
= hdmi_dev
->cur_conf
;
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 timings */
269 ret
= v4l2_subdev_call(hdmi_dev
->phy_sd
, video
, s_dv_timings
,
270 &hdmi_dev
->cur_timings
);
272 dev_err(dev
, "failed to set timings\n");
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 /* default hdmi_timings index of the timings configured on probe */
477 #define HDMI_DEFAULT_TIMINGS_IDX (0)
479 static const struct {
481 const struct v4l2_dv_timings dv_timings
;
482 const struct hdmi_timings
*hdmi_timings
;
484 { false, V4L2_DV_BT_CEA_720X480P59_94
, &hdmi_timings_480p
},
485 { false, V4L2_DV_BT_CEA_720X576P50
, &hdmi_timings_576p50
},
486 { false, V4L2_DV_BT_CEA_1280X720P50
, &hdmi_timings_720p50
},
487 { true, V4L2_DV_BT_CEA_1280X720P60
, &hdmi_timings_720p60
},
488 { false, V4L2_DV_BT_CEA_1920X1080P24
, &hdmi_timings_1080p24
},
489 { false, V4L2_DV_BT_CEA_1920X1080P30
, &hdmi_timings_1080p60
},
490 { false, V4L2_DV_BT_CEA_1920X1080P50
, &hdmi_timings_1080p50
},
491 { false, V4L2_DV_BT_CEA_1920X1080I50
, &hdmi_timings_1080i50
},
492 { false, V4L2_DV_BT_CEA_1920X1080I60
, &hdmi_timings_1080i60
},
493 { false, V4L2_DV_BT_CEA_1920X1080P60
, &hdmi_timings_1080p60
},
496 static int hdmi_streamon(struct hdmi_device
*hdev
)
498 struct device
*dev
= hdev
->dev
;
499 struct hdmi_resources
*res
= &hdev
->res
;
502 dev_dbg(dev
, "%s\n", __func__
);
504 ret
= hdmi_conf_apply(hdev
);
508 ret
= v4l2_subdev_call(hdev
->phy_sd
, video
, s_stream
, 1);
512 /* waiting for HDMIPHY's PLL to get to steady state */
513 for (tries
= 100; tries
; --tries
) {
514 u32 val
= hdmi_read(hdev
, HDMI_PHY_STATUS
);
515 if (val
& HDMI_PHY_STATUS_READY
)
519 /* steady state not achieved */
521 dev_err(dev
, "hdmiphy's pll could not reach steady state.\n");
522 v4l2_subdev_call(hdev
->phy_sd
, video
, s_stream
, 0);
523 hdmi_dumpregs(hdev
, "hdmiphy - s_stream");
528 ret
= v4l2_subdev_call(hdev
->mhl_sd
, video
, s_stream
, 1);
529 if (hdev
->mhl_sd
&& ret
) {
530 v4l2_subdev_call(hdev
->phy_sd
, video
, s_stream
, 0);
531 hdmi_dumpregs(hdev
, "mhl - s_stream");
535 /* hdmiphy clock is used for HDMI in streaming mode */
536 clk_disable(res
->sclk_hdmi
);
537 clk_set_parent(res
->sclk_hdmi
, res
->sclk_hdmiphy
);
538 clk_enable(res
->sclk_hdmi
);
540 /* enable HDMI and timing generator */
541 hdmi_write_mask(hdev
, HDMI_CON_0
, ~0, HDMI_EN
);
542 hdmi_write_mask(hdev
, HDMI_TG_CMD
, ~0, HDMI_TG_EN
);
543 hdmi_dumpregs(hdev
, "streamon");
547 static int hdmi_streamoff(struct hdmi_device
*hdev
)
549 struct device
*dev
= hdev
->dev
;
550 struct hdmi_resources
*res
= &hdev
->res
;
552 dev_dbg(dev
, "%s\n", __func__
);
554 hdmi_write_mask(hdev
, HDMI_CON_0
, 0, HDMI_EN
);
555 hdmi_write_mask(hdev
, HDMI_TG_CMD
, 0, HDMI_TG_EN
);
557 /* pixel(vpll) clock is used for HDMI in config mode */
558 clk_disable(res
->sclk_hdmi
);
559 clk_set_parent(res
->sclk_hdmi
, res
->sclk_pixel
);
560 clk_enable(res
->sclk_hdmi
);
562 v4l2_subdev_call(hdev
->mhl_sd
, video
, s_stream
, 0);
563 v4l2_subdev_call(hdev
->phy_sd
, video
, s_stream
, 0);
565 hdmi_dumpregs(hdev
, "streamoff");
569 static int hdmi_s_stream(struct v4l2_subdev
*sd
, int enable
)
571 struct hdmi_device
*hdev
= sd_to_hdmi_dev(sd
);
572 struct device
*dev
= hdev
->dev
;
574 dev_dbg(dev
, "%s(%d)\n", __func__
, enable
);
576 return hdmi_streamon(hdev
);
577 return hdmi_streamoff(hdev
);
580 static int hdmi_resource_poweron(struct hdmi_resources
*res
)
584 /* turn HDMI power on */
585 ret
= regulator_bulk_enable(res
->regul_count
, res
->regul_bulk
);
588 /* power-on hdmi physical interface */
589 clk_enable(res
->hdmiphy
);
590 /* use VPP as parent clock; HDMIPHY is not working yet */
591 clk_set_parent(res
->sclk_hdmi
, res
->sclk_pixel
);
593 clk_enable(res
->sclk_hdmi
);
598 static void hdmi_resource_poweroff(struct hdmi_resources
*res
)
600 /* turn clocks off */
601 clk_disable(res
->sclk_hdmi
);
602 /* power-off hdmiphy */
603 clk_disable(res
->hdmiphy
);
604 /* turn HDMI power off */
605 regulator_bulk_disable(res
->regul_count
, res
->regul_bulk
);
608 static int hdmi_s_power(struct v4l2_subdev
*sd
, int on
)
610 struct hdmi_device
*hdev
= sd_to_hdmi_dev(sd
);
614 ret
= pm_runtime_get_sync(hdev
->dev
);
616 ret
= pm_runtime_put_sync(hdev
->dev
);
617 /* only values < 0 indicate errors */
618 return ret
< 0 ? ret
: 0;
621 static int hdmi_s_dv_timings(struct v4l2_subdev
*sd
,
622 struct v4l2_dv_timings
*timings
)
624 struct hdmi_device
*hdev
= sd_to_hdmi_dev(sd
);
625 struct device
*dev
= hdev
->dev
;
628 for (i
= 0; i
< ARRAY_SIZE(hdmi_timings
); i
++)
629 if (v4l2_match_dv_timings(&hdmi_timings
[i
].dv_timings
,
632 if (i
== ARRAY_SIZE(hdmi_timings
)) {
633 dev_err(dev
, "timings not supported\n");
636 hdev
->cur_conf
= hdmi_timings
[i
].hdmi_timings
;
637 hdev
->cur_conf_dirty
= 1;
638 hdev
->cur_timings
= *timings
;
639 if (!hdmi_timings
[i
].reduced_fps
)
640 hdev
->cur_timings
.bt
.flags
&= ~V4L2_DV_FL_CAN_REDUCE_FPS
;
644 static int hdmi_g_dv_timings(struct v4l2_subdev
*sd
,
645 struct v4l2_dv_timings
*timings
)
647 *timings
= sd_to_hdmi_dev(sd
)->cur_timings
;
651 static int hdmi_get_fmt(struct v4l2_subdev
*sd
,
652 struct v4l2_subdev_pad_config
*cfg
,
653 struct v4l2_subdev_format
*format
)
655 struct v4l2_mbus_framefmt
*fmt
= &format
->format
;
656 struct hdmi_device
*hdev
= sd_to_hdmi_dev(sd
);
657 const struct hdmi_timings
*t
= hdev
->cur_conf
;
659 dev_dbg(hdev
->dev
, "%s\n", __func__
);
665 memset(fmt
, 0, sizeof(*fmt
));
666 fmt
->width
= t
->hact
.end
- t
->hact
.beg
;
667 fmt
->height
= t
->vact
[0].end
- t
->vact
[0].beg
;
668 fmt
->code
= MEDIA_BUS_FMT_FIXED
; /* means RGB888 */
669 fmt
->colorspace
= V4L2_COLORSPACE_SRGB
;
671 fmt
->field
= V4L2_FIELD_INTERLACED
;
674 fmt
->field
= V4L2_FIELD_NONE
;
679 static int hdmi_enum_dv_timings(struct v4l2_subdev
*sd
,
680 struct v4l2_enum_dv_timings
*timings
)
682 if (timings
->pad
!= 0)
684 if (timings
->index
>= ARRAY_SIZE(hdmi_timings
))
686 timings
->timings
= hdmi_timings
[timings
->index
].dv_timings
;
687 if (!hdmi_timings
[timings
->index
].reduced_fps
)
688 timings
->timings
.bt
.flags
&= ~V4L2_DV_FL_CAN_REDUCE_FPS
;
692 static int hdmi_dv_timings_cap(struct v4l2_subdev
*sd
,
693 struct v4l2_dv_timings_cap
*cap
)
695 struct hdmi_device
*hdev
= sd_to_hdmi_dev(sd
);
700 /* Let the phy fill in the pixelclock range */
701 v4l2_subdev_call(hdev
->phy_sd
, pad
, dv_timings_cap
, cap
);
702 cap
->type
= V4L2_DV_BT_656_1120
;
703 cap
->bt
.min_width
= 720;
704 cap
->bt
.max_width
= 1920;
705 cap
->bt
.min_height
= 480;
706 cap
->bt
.max_height
= 1080;
707 cap
->bt
.standards
= V4L2_DV_BT_STD_CEA861
;
708 cap
->bt
.capabilities
= V4L2_DV_BT_CAP_INTERLACED
|
709 V4L2_DV_BT_CAP_PROGRESSIVE
;
713 static const struct v4l2_subdev_core_ops hdmi_sd_core_ops
= {
714 .s_power
= hdmi_s_power
,
717 static const struct v4l2_subdev_video_ops hdmi_sd_video_ops
= {
718 .s_dv_timings
= hdmi_s_dv_timings
,
719 .g_dv_timings
= hdmi_g_dv_timings
,
720 .s_stream
= hdmi_s_stream
,
723 static const struct v4l2_subdev_pad_ops hdmi_sd_pad_ops
= {
724 .enum_dv_timings
= hdmi_enum_dv_timings
,
725 .dv_timings_cap
= hdmi_dv_timings_cap
,
726 .get_fmt
= hdmi_get_fmt
,
729 static const struct v4l2_subdev_ops hdmi_sd_ops
= {
730 .core
= &hdmi_sd_core_ops
,
731 .video
= &hdmi_sd_video_ops
,
732 .pad
= &hdmi_sd_pad_ops
,
735 static int hdmi_runtime_suspend(struct device
*dev
)
737 struct v4l2_subdev
*sd
= dev_get_drvdata(dev
);
738 struct hdmi_device
*hdev
= sd_to_hdmi_dev(sd
);
740 dev_dbg(dev
, "%s\n", __func__
);
741 v4l2_subdev_call(hdev
->mhl_sd
, core
, s_power
, 0);
742 hdmi_resource_poweroff(&hdev
->res
);
743 /* flag that device context is lost */
744 hdev
->cur_conf_dirty
= 1;
748 static int hdmi_runtime_resume(struct device
*dev
)
750 struct v4l2_subdev
*sd
= dev_get_drvdata(dev
);
751 struct hdmi_device
*hdev
= sd_to_hdmi_dev(sd
);
754 dev_dbg(dev
, "%s\n", __func__
);
756 ret
= hdmi_resource_poweron(&hdev
->res
);
761 ret
= v4l2_subdev_call(hdev
->mhl_sd
, core
, s_power
, 1);
762 if (hdev
->mhl_sd
&& ret
)
765 dev_dbg(dev
, "poweron succeed\n");
770 hdmi_resource_poweroff(&hdev
->res
);
771 dev_err(dev
, "poweron failed\n");
776 static const struct dev_pm_ops hdmi_pm_ops
= {
777 .runtime_suspend
= hdmi_runtime_suspend
,
778 .runtime_resume
= hdmi_runtime_resume
,
781 static void hdmi_resource_clear_clocks(struct hdmi_resources
*res
)
783 res
->hdmi
= ERR_PTR(-EINVAL
);
784 res
->sclk_hdmi
= ERR_PTR(-EINVAL
);
785 res
->sclk_pixel
= ERR_PTR(-EINVAL
);
786 res
->sclk_hdmiphy
= ERR_PTR(-EINVAL
);
787 res
->hdmiphy
= ERR_PTR(-EINVAL
);
790 static void hdmi_resources_cleanup(struct hdmi_device
*hdev
)
792 struct hdmi_resources
*res
= &hdev
->res
;
794 dev_dbg(hdev
->dev
, "HDMI resource cleanup\n");
795 /* put clocks, power */
796 if (res
->regul_count
)
797 regulator_bulk_free(res
->regul_count
, res
->regul_bulk
);
798 /* kfree is NULL-safe */
799 kfree(res
->regul_bulk
);
800 if (!IS_ERR(res
->hdmiphy
))
801 clk_put(res
->hdmiphy
);
802 if (!IS_ERR(res
->sclk_hdmiphy
))
803 clk_put(res
->sclk_hdmiphy
);
804 if (!IS_ERR(res
->sclk_pixel
))
805 clk_put(res
->sclk_pixel
);
806 if (!IS_ERR(res
->sclk_hdmi
))
807 clk_put(res
->sclk_hdmi
);
808 if (!IS_ERR(res
->hdmi
))
810 memset(res
, 0, sizeof(*res
));
811 hdmi_resource_clear_clocks(res
);
814 static int hdmi_resources_init(struct hdmi_device
*hdev
)
816 struct device
*dev
= hdev
->dev
;
817 struct hdmi_resources
*res
= &hdev
->res
;
818 static char *supply
[] = {
826 dev_dbg(dev
, "HDMI resource init\n");
828 memset(res
, 0, sizeof(*res
));
829 hdmi_resource_clear_clocks(res
);
831 /* get clocks, power */
832 res
->hdmi
= clk_get(dev
, "hdmi");
833 if (IS_ERR(res
->hdmi
)) {
834 dev_err(dev
, "failed to get clock 'hdmi'\n");
837 res
->sclk_hdmi
= clk_get(dev
, "sclk_hdmi");
838 if (IS_ERR(res
->sclk_hdmi
)) {
839 dev_err(dev
, "failed to get clock 'sclk_hdmi'\n");
842 res
->sclk_pixel
= clk_get(dev
, "sclk_pixel");
843 if (IS_ERR(res
->sclk_pixel
)) {
844 dev_err(dev
, "failed to get clock 'sclk_pixel'\n");
847 res
->sclk_hdmiphy
= clk_get(dev
, "sclk_hdmiphy");
848 if (IS_ERR(res
->sclk_hdmiphy
)) {
849 dev_err(dev
, "failed to get clock 'sclk_hdmiphy'\n");
852 res
->hdmiphy
= clk_get(dev
, "hdmiphy");
853 if (IS_ERR(res
->hdmiphy
)) {
854 dev_err(dev
, "failed to get clock 'hdmiphy'\n");
857 res
->regul_bulk
= kcalloc(ARRAY_SIZE(supply
),
858 sizeof(res
->regul_bulk
[0]), GFP_KERNEL
);
859 if (!res
->regul_bulk
) {
860 dev_err(dev
, "failed to get memory for regulators\n");
863 for (i
= 0; i
< ARRAY_SIZE(supply
); ++i
) {
864 res
->regul_bulk
[i
].supply
= supply
[i
];
865 res
->regul_bulk
[i
].consumer
= NULL
;
868 ret
= regulator_bulk_get(dev
, ARRAY_SIZE(supply
), res
->regul_bulk
);
870 dev_err(dev
, "failed to get regulators\n");
873 res
->regul_count
= ARRAY_SIZE(supply
);
877 dev_err(dev
, "HDMI resource init - failed\n");
878 hdmi_resources_cleanup(hdev
);
882 static int hdmi_probe(struct platform_device
*pdev
)
884 struct device
*dev
= &pdev
->dev
;
885 struct resource
*res
;
886 struct i2c_adapter
*adapter
;
887 struct v4l2_subdev
*sd
;
888 struct hdmi_device
*hdmi_dev
= NULL
;
889 struct s5p_hdmi_platform_data
*pdata
= dev
->platform_data
;
892 dev_dbg(dev
, "probe start\n");
895 dev_err(dev
, "platform data is missing\n");
900 hdmi_dev
= devm_kzalloc(&pdev
->dev
, sizeof(*hdmi_dev
), GFP_KERNEL
);
902 dev_err(dev
, "out of memory\n");
909 ret
= hdmi_resources_init(hdmi_dev
);
913 /* mapping HDMI registers */
914 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
916 dev_err(dev
, "get memory resource failed.\n");
921 hdmi_dev
->regs
= devm_ioremap(&pdev
->dev
, res
->start
,
923 if (hdmi_dev
->regs
== NULL
) {
924 dev_err(dev
, "register mapping failed.\n");
929 res
= platform_get_resource(pdev
, IORESOURCE_IRQ
, 0);
931 dev_err(dev
, "get interrupt resource failed.\n");
936 ret
= devm_request_irq(&pdev
->dev
, res
->start
, hdmi_irq_handler
, 0,
939 dev_err(dev
, "request interrupt failed.\n");
942 hdmi_dev
->irq
= res
->start
;
944 /* setting v4l2 name to prevent WARN_ON in v4l2_device_register */
945 strlcpy(hdmi_dev
->v4l2_dev
.name
, dev_name(dev
),
946 sizeof(hdmi_dev
->v4l2_dev
.name
));
947 /* passing NULL owner prevents driver from erasing drvdata */
948 ret
= v4l2_device_register(NULL
, &hdmi_dev
->v4l2_dev
);
950 dev_err(dev
, "could not register v4l2 device.\n");
954 /* testing if hdmiphy info is present */
955 if (!pdata
->hdmiphy_info
) {
956 dev_err(dev
, "hdmiphy info is missing in platform data\n");
961 adapter
= i2c_get_adapter(pdata
->hdmiphy_bus
);
962 if (adapter
== NULL
) {
963 dev_err(dev
, "hdmiphy adapter request failed\n");
968 hdmi_dev
->phy_sd
= v4l2_i2c_new_subdev_board(&hdmi_dev
->v4l2_dev
,
969 adapter
, pdata
->hdmiphy_info
, NULL
);
970 /* on failure or not adapter is no longer useful */
971 i2c_put_adapter(adapter
);
972 if (hdmi_dev
->phy_sd
== NULL
) {
973 dev_err(dev
, "missing subdev for hdmiphy\n");
978 /* initialization of MHL interface if present */
979 if (pdata
->mhl_info
) {
980 adapter
= i2c_get_adapter(pdata
->mhl_bus
);
981 if (adapter
== NULL
) {
982 dev_err(dev
, "MHL adapter request failed\n");
987 hdmi_dev
->mhl_sd
= v4l2_i2c_new_subdev_board(
988 &hdmi_dev
->v4l2_dev
, adapter
,
989 pdata
->mhl_info
, NULL
);
990 /* on failure or not adapter is no longer useful */
991 i2c_put_adapter(adapter
);
992 if (hdmi_dev
->mhl_sd
== NULL
) {
993 dev_err(dev
, "missing subdev for MHL\n");
999 clk_enable(hdmi_dev
->res
.hdmi
);
1001 pm_runtime_enable(dev
);
1004 v4l2_subdev_init(sd
, &hdmi_sd_ops
);
1005 sd
->owner
= THIS_MODULE
;
1007 strlcpy(sd
->name
, "s5p-hdmi", sizeof(sd
->name
));
1008 hdmi_dev
->cur_timings
=
1009 hdmi_timings
[HDMI_DEFAULT_TIMINGS_IDX
].dv_timings
;
1010 /* FIXME: missing fail timings is not supported */
1011 hdmi_dev
->cur_conf
=
1012 hdmi_timings
[HDMI_DEFAULT_TIMINGS_IDX
].hdmi_timings
;
1013 hdmi_dev
->cur_conf_dirty
= 1;
1015 /* storing subdev for call that have only access to struct device */
1016 dev_set_drvdata(dev
, sd
);
1018 dev_info(dev
, "probe successful\n");
1023 v4l2_device_unregister(&hdmi_dev
->v4l2_dev
);
1026 hdmi_resources_cleanup(hdmi_dev
);
1029 dev_err(dev
, "probe failed\n");
1033 static int hdmi_remove(struct platform_device
*pdev
)
1035 struct device
*dev
= &pdev
->dev
;
1036 struct v4l2_subdev
*sd
= dev_get_drvdata(dev
);
1037 struct hdmi_device
*hdmi_dev
= sd_to_hdmi_dev(sd
);
1039 pm_runtime_disable(dev
);
1040 clk_disable(hdmi_dev
->res
.hdmi
);
1041 v4l2_device_unregister(&hdmi_dev
->v4l2_dev
);
1042 disable_irq(hdmi_dev
->irq
);
1043 hdmi_resources_cleanup(hdmi_dev
);
1044 dev_info(dev
, "remove successful\n");
1049 static struct platform_driver hdmi_driver __refdata
= {
1050 .probe
= hdmi_probe
,
1051 .remove
= hdmi_remove
,
1052 .id_table
= hdmi_driver_types
,
1059 module_platform_driver(hdmi_driver
);