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 <media/s5p_hdmi.h>
37 #include <media/v4l2-common.h>
38 #include <media/v4l2-dev.h>
39 #include <media/v4l2-device.h>
41 #include "regs-hdmi.h"
43 MODULE_AUTHOR("Tomasz Stanislawski, <t.stanislaws@samsung.com>");
44 MODULE_DESCRIPTION("Samsung HDMI");
45 MODULE_LICENSE("GPL");
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 */
92 /** current timings */
93 struct v4l2_dv_timings cur_timings
;
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 pr_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 pr_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
;
255 dev_dbg(dev
, "%s\n", __func__
);
257 /* skip if conf is already synchronized with HW */
258 if (!hdmi_dev
->cur_conf_dirty
)
262 hdmi_write_mask(hdmi_dev
, HDMI_PHY_RSTOUT
, ~0, HDMI_PHY_SW_RSTOUT
);
264 hdmi_write_mask(hdmi_dev
, HDMI_PHY_RSTOUT
, 0, HDMI_PHY_SW_RSTOUT
);
267 /* configure timings */
268 ret
= v4l2_subdev_call(hdmi_dev
->phy_sd
, video
, s_dv_timings
,
269 &hdmi_dev
->cur_timings
);
271 dev_err(dev
, "failed to set timings\n");
275 /* resetting HDMI core */
276 hdmi_write_mask(hdmi_dev
, HDMI_CORE_RSTOUT
, 0, HDMI_CORE_SW_RSTOUT
);
278 hdmi_write_mask(hdmi_dev
, HDMI_CORE_RSTOUT
, ~0, HDMI_CORE_SW_RSTOUT
);
281 hdmi_reg_init(hdmi_dev
);
283 /* setting core registers */
284 hdmi_timing_apply(hdmi_dev
, conf
);
286 hdmi_dev
->cur_conf_dirty
= 0;
291 static void hdmi_dumpregs(struct hdmi_device
*hdev
, char *prefix
)
293 #define DUMPREG(reg_id) \
294 dev_dbg(hdev->dev, "%s:" #reg_id " = %08x\n", prefix, \
295 readl(hdev->regs + reg_id))
297 dev_dbg(hdev
->dev
, "%s: ---- CONTROL REGISTERS ----\n", prefix
);
298 DUMPREG(HDMI_INTC_FLAG
);
299 DUMPREG(HDMI_INTC_CON
);
300 DUMPREG(HDMI_HPD_STATUS
);
301 DUMPREG(HDMI_PHY_RSTOUT
);
302 DUMPREG(HDMI_PHY_VPLL
);
303 DUMPREG(HDMI_PHY_CMU
);
304 DUMPREG(HDMI_CORE_RSTOUT
);
306 dev_dbg(hdev
->dev
, "%s: ---- CORE REGISTERS ----\n", prefix
);
310 DUMPREG(HDMI_SYS_STATUS
);
311 DUMPREG(HDMI_PHY_STATUS
);
312 DUMPREG(HDMI_STATUS_EN
);
314 DUMPREG(HDMI_MODE_SEL
);
315 DUMPREG(HDMI_HPD_GEN
);
316 DUMPREG(HDMI_DC_CONTROL
);
317 DUMPREG(HDMI_VIDEO_PATTERN_GEN
);
319 dev_dbg(hdev
->dev
, "%s: ---- CORE SYNC REGISTERS ----\n", prefix
);
320 DUMPREG(HDMI_H_BLANK_0
);
321 DUMPREG(HDMI_H_BLANK_1
);
322 DUMPREG(HDMI_V_BLANK_0
);
323 DUMPREG(HDMI_V_BLANK_1
);
324 DUMPREG(HDMI_V_BLANK_2
);
325 DUMPREG(HDMI_H_V_LINE_0
);
326 DUMPREG(HDMI_H_V_LINE_1
);
327 DUMPREG(HDMI_H_V_LINE_2
);
328 DUMPREG(HDMI_VSYNC_POL
);
329 DUMPREG(HDMI_INT_PRO_MODE
);
330 DUMPREG(HDMI_V_BLANK_F_0
);
331 DUMPREG(HDMI_V_BLANK_F_1
);
332 DUMPREG(HDMI_V_BLANK_F_2
);
333 DUMPREG(HDMI_H_SYNC_GEN_0
);
334 DUMPREG(HDMI_H_SYNC_GEN_1
);
335 DUMPREG(HDMI_H_SYNC_GEN_2
);
336 DUMPREG(HDMI_V_SYNC_GEN_1_0
);
337 DUMPREG(HDMI_V_SYNC_GEN_1_1
);
338 DUMPREG(HDMI_V_SYNC_GEN_1_2
);
339 DUMPREG(HDMI_V_SYNC_GEN_2_0
);
340 DUMPREG(HDMI_V_SYNC_GEN_2_1
);
341 DUMPREG(HDMI_V_SYNC_GEN_2_2
);
342 DUMPREG(HDMI_V_SYNC_GEN_3_0
);
343 DUMPREG(HDMI_V_SYNC_GEN_3_1
);
344 DUMPREG(HDMI_V_SYNC_GEN_3_2
);
346 dev_dbg(hdev
->dev
, "%s: ---- TG REGISTERS ----\n", prefix
);
347 DUMPREG(HDMI_TG_CMD
);
348 DUMPREG(HDMI_TG_H_FSZ_L
);
349 DUMPREG(HDMI_TG_H_FSZ_H
);
350 DUMPREG(HDMI_TG_HACT_ST_L
);
351 DUMPREG(HDMI_TG_HACT_ST_H
);
352 DUMPREG(HDMI_TG_HACT_SZ_L
);
353 DUMPREG(HDMI_TG_HACT_SZ_H
);
354 DUMPREG(HDMI_TG_V_FSZ_L
);
355 DUMPREG(HDMI_TG_V_FSZ_H
);
356 DUMPREG(HDMI_TG_VSYNC_L
);
357 DUMPREG(HDMI_TG_VSYNC_H
);
358 DUMPREG(HDMI_TG_VSYNC2_L
);
359 DUMPREG(HDMI_TG_VSYNC2_H
);
360 DUMPREG(HDMI_TG_VACT_ST_L
);
361 DUMPREG(HDMI_TG_VACT_ST_H
);
362 DUMPREG(HDMI_TG_VACT_SZ_L
);
363 DUMPREG(HDMI_TG_VACT_SZ_H
);
364 DUMPREG(HDMI_TG_FIELD_CHG_L
);
365 DUMPREG(HDMI_TG_FIELD_CHG_H
);
366 DUMPREG(HDMI_TG_VACT_ST2_L
);
367 DUMPREG(HDMI_TG_VACT_ST2_H
);
368 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_L
);
369 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_H
);
370 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_L
);
371 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_H
);
372 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_L
);
373 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_H
);
374 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_L
);
375 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_H
);
379 static const struct hdmi_timings hdmi_timings_480p
= {
380 .hact
= { .beg
= 138, .end
= 858 },
382 .hsyn
= { .beg
= 16, .end
= 16 + 62 },
384 .vact
[0] = { .beg
= 42 + 3, .end
= 522 + 3 },
386 .vsyn
[0] = { .beg
= 6 + 3, .end
= 12 + 3},
389 static const struct hdmi_timings hdmi_timings_576p50
= {
390 .hact
= { .beg
= 144, .end
= 864 },
392 .hsyn
= { .beg
= 12, .end
= 12 + 64 },
394 .vact
[0] = { .beg
= 44 + 5, .end
= 620 + 5 },
396 .vsyn
[0] = { .beg
= 0 + 5, .end
= 5 + 5},
399 static const struct hdmi_timings hdmi_timings_720p60
= {
400 .hact
= { .beg
= 370, .end
= 1650 },
402 .hsyn
= { .beg
= 110, .end
= 110 + 40 },
404 .vact
[0] = { .beg
= 25 + 5, .end
= 745 + 5 },
406 .vsyn
[0] = { .beg
= 0 + 5, .end
= 5 + 5},
409 static const struct hdmi_timings hdmi_timings_720p50
= {
410 .hact
= { .beg
= 700, .end
= 1980 },
412 .hsyn
= { .beg
= 440, .end
= 440 + 40 },
414 .vact
[0] = { .beg
= 25 + 5, .end
= 745 + 5 },
416 .vsyn
[0] = { .beg
= 0 + 5, .end
= 5 + 5},
419 static const struct hdmi_timings hdmi_timings_1080p24
= {
420 .hact
= { .beg
= 830, .end
= 2750 },
422 .hsyn
= { .beg
= 638, .end
= 638 + 44 },
424 .vact
[0] = { .beg
= 41 + 4, .end
= 1121 + 4 },
426 .vsyn
[0] = { .beg
= 0 + 4, .end
= 5 + 4},
429 static const struct hdmi_timings hdmi_timings_1080p60
= {
430 .hact
= { .beg
= 280, .end
= 2200 },
432 .hsyn
= { .beg
= 88, .end
= 88 + 44 },
434 .vact
[0] = { .beg
= 41 + 4, .end
= 1121 + 4 },
436 .vsyn
[0] = { .beg
= 0 + 4, .end
= 5 + 4},
439 static const struct hdmi_timings hdmi_timings_1080i60
= {
440 .hact
= { .beg
= 280, .end
= 2200 },
442 .hsyn
= { .beg
= 88, .end
= 88 + 44 },
444 .vact
[0] = { .beg
= 20 + 2, .end
= 560 + 2 },
445 .vact
[1] = { .beg
= 583 + 2, .end
= 1123 + 2 },
448 .vsyn
[0] = { .beg
= 0 + 2, .end
= 5 + 2},
449 .vsyn
[1] = { .beg
= 562 + 2, .end
= 567 + 2},
452 static const struct hdmi_timings hdmi_timings_1080i50
= {
453 .hact
= { .beg
= 720, .end
= 2640 },
455 .hsyn
= { .beg
= 528, .end
= 528 + 44 },
457 .vact
[0] = { .beg
= 20 + 2, .end
= 560 + 2 },
458 .vact
[1] = { .beg
= 583 + 2, .end
= 1123 + 2 },
461 .vsyn
[0] = { .beg
= 0 + 2, .end
= 5 + 2},
462 .vsyn
[1] = { .beg
= 562 + 2, .end
= 567 + 2},
465 static const struct hdmi_timings hdmi_timings_1080p50
= {
466 .hact
= { .beg
= 720, .end
= 2640 },
468 .hsyn
= { .beg
= 528, .end
= 528 + 44 },
470 .vact
[0] = { .beg
= 41 + 4, .end
= 1121 + 4 },
472 .vsyn
[0] = { .beg
= 0 + 4, .end
= 5 + 4},
475 /* default hdmi_timings index of the timings configured on probe */
476 #define HDMI_DEFAULT_TIMINGS_IDX (0)
478 static const struct {
480 const struct v4l2_dv_timings dv_timings
;
481 const struct hdmi_timings
*hdmi_timings
;
483 { false, V4L2_DV_BT_CEA_720X480P59_94
, &hdmi_timings_480p
},
484 { false, V4L2_DV_BT_CEA_720X576P50
, &hdmi_timings_576p50
},
485 { false, V4L2_DV_BT_CEA_1280X720P50
, &hdmi_timings_720p50
},
486 { true, V4L2_DV_BT_CEA_1280X720P60
, &hdmi_timings_720p60
},
487 { false, V4L2_DV_BT_CEA_1920X1080P24
, &hdmi_timings_1080p24
},
488 { false, V4L2_DV_BT_CEA_1920X1080P30
, &hdmi_timings_1080p60
},
489 { false, V4L2_DV_BT_CEA_1920X1080P50
, &hdmi_timings_1080p50
},
490 { false, V4L2_DV_BT_CEA_1920X1080I50
, &hdmi_timings_1080i50
},
491 { false, V4L2_DV_BT_CEA_1920X1080I60
, &hdmi_timings_1080i60
},
492 { false, V4L2_DV_BT_CEA_1920X1080P60
, &hdmi_timings_1080p60
},
495 static int hdmi_streamon(struct hdmi_device
*hdev
)
497 struct device
*dev
= hdev
->dev
;
498 struct hdmi_resources
*res
= &hdev
->res
;
501 dev_dbg(dev
, "%s\n", __func__
);
503 ret
= hdmi_conf_apply(hdev
);
507 ret
= v4l2_subdev_call(hdev
->phy_sd
, video
, s_stream
, 1);
511 /* waiting for HDMIPHY's PLL to get to steady state */
512 for (tries
= 100; tries
; --tries
) {
513 u32 val
= hdmi_read(hdev
, HDMI_PHY_STATUS
);
514 if (val
& HDMI_PHY_STATUS_READY
)
518 /* steady state not achieved */
520 dev_err(dev
, "hdmiphy's pll could not reach steady state.\n");
521 v4l2_subdev_call(hdev
->phy_sd
, video
, s_stream
, 0);
522 hdmi_dumpregs(hdev
, "hdmiphy - s_stream");
527 ret
= v4l2_subdev_call(hdev
->mhl_sd
, video
, s_stream
, 1);
528 if (hdev
->mhl_sd
&& ret
) {
529 v4l2_subdev_call(hdev
->phy_sd
, video
, s_stream
, 0);
530 hdmi_dumpregs(hdev
, "mhl - s_stream");
534 /* hdmiphy clock is used for HDMI in streaming mode */
535 clk_disable(res
->sclk_hdmi
);
536 clk_set_parent(res
->sclk_hdmi
, res
->sclk_hdmiphy
);
537 clk_enable(res
->sclk_hdmi
);
539 /* enable HDMI and timing generator */
540 hdmi_write_mask(hdev
, HDMI_CON_0
, ~0, HDMI_EN
);
541 hdmi_write_mask(hdev
, HDMI_TG_CMD
, ~0, HDMI_TG_EN
);
542 hdmi_dumpregs(hdev
, "streamon");
546 static int hdmi_streamoff(struct hdmi_device
*hdev
)
548 struct device
*dev
= hdev
->dev
;
549 struct hdmi_resources
*res
= &hdev
->res
;
551 dev_dbg(dev
, "%s\n", __func__
);
553 hdmi_write_mask(hdev
, HDMI_CON_0
, 0, HDMI_EN
);
554 hdmi_write_mask(hdev
, HDMI_TG_CMD
, 0, HDMI_TG_EN
);
556 /* pixel(vpll) clock is used for HDMI in config mode */
557 clk_disable(res
->sclk_hdmi
);
558 clk_set_parent(res
->sclk_hdmi
, res
->sclk_pixel
);
559 clk_enable(res
->sclk_hdmi
);
561 v4l2_subdev_call(hdev
->mhl_sd
, video
, s_stream
, 0);
562 v4l2_subdev_call(hdev
->phy_sd
, video
, s_stream
, 0);
564 hdmi_dumpregs(hdev
, "streamoff");
568 static int hdmi_s_stream(struct v4l2_subdev
*sd
, int enable
)
570 struct hdmi_device
*hdev
= sd_to_hdmi_dev(sd
);
571 struct device
*dev
= hdev
->dev
;
573 dev_dbg(dev
, "%s(%d)\n", __func__
, enable
);
575 return hdmi_streamon(hdev
);
576 return hdmi_streamoff(hdev
);
579 static void hdmi_resource_poweron(struct hdmi_resources
*res
)
581 /* turn HDMI power on */
582 regulator_bulk_enable(res
->regul_count
, res
->regul_bulk
);
583 /* power-on hdmi physical interface */
584 clk_enable(res
->hdmiphy
);
585 /* use VPP as parent clock; HDMIPHY is not working yet */
586 clk_set_parent(res
->sclk_hdmi
, res
->sclk_pixel
);
588 clk_enable(res
->sclk_hdmi
);
591 static void hdmi_resource_poweroff(struct hdmi_resources
*res
)
593 /* turn clocks off */
594 clk_disable(res
->sclk_hdmi
);
595 /* power-off hdmiphy */
596 clk_disable(res
->hdmiphy
);
597 /* turn HDMI power off */
598 regulator_bulk_disable(res
->regul_count
, res
->regul_bulk
);
601 static int hdmi_s_power(struct v4l2_subdev
*sd
, int on
)
603 struct hdmi_device
*hdev
= sd_to_hdmi_dev(sd
);
607 ret
= pm_runtime_get_sync(hdev
->dev
);
609 ret
= pm_runtime_put_sync(hdev
->dev
);
610 /* only values < 0 indicate errors */
611 return IS_ERR_VALUE(ret
) ? ret
: 0;
614 static int hdmi_s_dv_timings(struct v4l2_subdev
*sd
,
615 struct v4l2_dv_timings
*timings
)
617 struct hdmi_device
*hdev
= sd_to_hdmi_dev(sd
);
618 struct device
*dev
= hdev
->dev
;
621 for (i
= 0; i
< ARRAY_SIZE(hdmi_timings
); i
++)
622 if (v4l_match_dv_timings(&hdmi_timings
[i
].dv_timings
,
625 if (i
== ARRAY_SIZE(hdmi_timings
)) {
626 dev_err(dev
, "timings not supported\n");
629 hdev
->cur_conf
= hdmi_timings
[i
].hdmi_timings
;
630 hdev
->cur_conf_dirty
= 1;
631 hdev
->cur_timings
= *timings
;
632 if (!hdmi_timings
[i
].reduced_fps
)
633 hdev
->cur_timings
.bt
.flags
&= ~V4L2_DV_FL_CAN_REDUCE_FPS
;
637 static int hdmi_g_dv_timings(struct v4l2_subdev
*sd
,
638 struct v4l2_dv_timings
*timings
)
640 *timings
= sd_to_hdmi_dev(sd
)->cur_timings
;
644 static int hdmi_g_mbus_fmt(struct v4l2_subdev
*sd
,
645 struct v4l2_mbus_framefmt
*fmt
)
647 struct hdmi_device
*hdev
= sd_to_hdmi_dev(sd
);
648 const struct hdmi_timings
*t
= hdev
->cur_conf
;
650 dev_dbg(hdev
->dev
, "%s\n", __func__
);
653 memset(fmt
, 0, sizeof(*fmt
));
654 fmt
->width
= t
->hact
.end
- t
->hact
.beg
;
655 fmt
->height
= t
->vact
[0].end
- t
->vact
[0].beg
;
656 fmt
->code
= V4L2_MBUS_FMT_FIXED
; /* means RGB888 */
657 fmt
->colorspace
= V4L2_COLORSPACE_SRGB
;
659 fmt
->field
= V4L2_FIELD_INTERLACED
;
662 fmt
->field
= V4L2_FIELD_NONE
;
667 static int hdmi_enum_dv_timings(struct v4l2_subdev
*sd
,
668 struct v4l2_enum_dv_timings
*timings
)
670 if (timings
->index
>= ARRAY_SIZE(hdmi_timings
))
672 timings
->timings
= hdmi_timings
[timings
->index
].dv_timings
;
673 if (!hdmi_timings
[timings
->index
].reduced_fps
)
674 timings
->timings
.bt
.flags
&= ~V4L2_DV_FL_CAN_REDUCE_FPS
;
678 static int hdmi_dv_timings_cap(struct v4l2_subdev
*sd
,
679 struct v4l2_dv_timings_cap
*cap
)
681 struct hdmi_device
*hdev
= sd_to_hdmi_dev(sd
);
683 /* Let the phy fill in the pixelclock range */
684 v4l2_subdev_call(hdev
->phy_sd
, video
, dv_timings_cap
, cap
);
685 cap
->type
= V4L2_DV_BT_656_1120
;
686 cap
->bt
.min_width
= 720;
687 cap
->bt
.max_width
= 1920;
688 cap
->bt
.min_height
= 480;
689 cap
->bt
.max_height
= 1080;
690 cap
->bt
.standards
= V4L2_DV_BT_STD_CEA861
;
691 cap
->bt
.capabilities
= V4L2_DV_BT_CAP_INTERLACED
|
692 V4L2_DV_BT_CAP_PROGRESSIVE
;
696 static const struct v4l2_subdev_core_ops hdmi_sd_core_ops
= {
697 .s_power
= hdmi_s_power
,
700 static const struct v4l2_subdev_video_ops hdmi_sd_video_ops
= {
701 .s_dv_timings
= hdmi_s_dv_timings
,
702 .g_dv_timings
= hdmi_g_dv_timings
,
703 .enum_dv_timings
= hdmi_enum_dv_timings
,
704 .dv_timings_cap
= hdmi_dv_timings_cap
,
705 .g_mbus_fmt
= hdmi_g_mbus_fmt
,
706 .s_stream
= hdmi_s_stream
,
709 static const struct v4l2_subdev_ops hdmi_sd_ops
= {
710 .core
= &hdmi_sd_core_ops
,
711 .video
= &hdmi_sd_video_ops
,
714 static int hdmi_runtime_suspend(struct device
*dev
)
716 struct v4l2_subdev
*sd
= dev_get_drvdata(dev
);
717 struct hdmi_device
*hdev
= sd_to_hdmi_dev(sd
);
719 dev_dbg(dev
, "%s\n", __func__
);
720 v4l2_subdev_call(hdev
->mhl_sd
, core
, s_power
, 0);
721 hdmi_resource_poweroff(&hdev
->res
);
722 /* flag that device context is lost */
723 hdev
->cur_conf_dirty
= 1;
727 static int hdmi_runtime_resume(struct device
*dev
)
729 struct v4l2_subdev
*sd
= dev_get_drvdata(dev
);
730 struct hdmi_device
*hdev
= sd_to_hdmi_dev(sd
);
733 dev_dbg(dev
, "%s\n", __func__
);
735 hdmi_resource_poweron(&hdev
->res
);
738 ret
= v4l2_subdev_call(hdev
->mhl_sd
, core
, s_power
, 1);
739 if (hdev
->mhl_sd
&& ret
)
742 dev_dbg(dev
, "poweron succeed\n");
747 hdmi_resource_poweroff(&hdev
->res
);
748 dev_err(dev
, "poweron failed\n");
753 static const struct dev_pm_ops hdmi_pm_ops
= {
754 .runtime_suspend
= hdmi_runtime_suspend
,
755 .runtime_resume
= hdmi_runtime_resume
,
758 static void hdmi_resources_cleanup(struct hdmi_device
*hdev
)
760 struct hdmi_resources
*res
= &hdev
->res
;
762 dev_dbg(hdev
->dev
, "HDMI resource cleanup\n");
763 /* put clocks, power */
764 if (res
->regul_count
)
765 regulator_bulk_free(res
->regul_count
, res
->regul_bulk
);
766 /* kfree is NULL-safe */
767 kfree(res
->regul_bulk
);
768 if (!IS_ERR_OR_NULL(res
->hdmiphy
))
769 clk_put(res
->hdmiphy
);
770 if (!IS_ERR_OR_NULL(res
->sclk_hdmiphy
))
771 clk_put(res
->sclk_hdmiphy
);
772 if (!IS_ERR_OR_NULL(res
->sclk_pixel
))
773 clk_put(res
->sclk_pixel
);
774 if (!IS_ERR_OR_NULL(res
->sclk_hdmi
))
775 clk_put(res
->sclk_hdmi
);
776 if (!IS_ERR_OR_NULL(res
->hdmi
))
778 memset(res
, 0, sizeof(*res
));
781 static int hdmi_resources_init(struct hdmi_device
*hdev
)
783 struct device
*dev
= hdev
->dev
;
784 struct hdmi_resources
*res
= &hdev
->res
;
785 static char *supply
[] = {
793 dev_dbg(dev
, "HDMI resource init\n");
795 memset(res
, 0, sizeof(*res
));
796 /* get clocks, power */
798 res
->hdmi
= clk_get(dev
, "hdmi");
799 if (IS_ERR(res
->hdmi
)) {
800 dev_err(dev
, "failed to get clock 'hdmi'\n");
803 res
->sclk_hdmi
= clk_get(dev
, "sclk_hdmi");
804 if (IS_ERR(res
->sclk_hdmi
)) {
805 dev_err(dev
, "failed to get clock 'sclk_hdmi'\n");
808 res
->sclk_pixel
= clk_get(dev
, "sclk_pixel");
809 if (IS_ERR(res
->sclk_pixel
)) {
810 dev_err(dev
, "failed to get clock 'sclk_pixel'\n");
813 res
->sclk_hdmiphy
= clk_get(dev
, "sclk_hdmiphy");
814 if (IS_ERR(res
->sclk_hdmiphy
)) {
815 dev_err(dev
, "failed to get clock 'sclk_hdmiphy'\n");
818 res
->hdmiphy
= clk_get(dev
, "hdmiphy");
819 if (IS_ERR(res
->hdmiphy
)) {
820 dev_err(dev
, "failed to get clock 'hdmiphy'\n");
823 res
->regul_bulk
= kcalloc(ARRAY_SIZE(supply
),
824 sizeof(res
->regul_bulk
[0]), GFP_KERNEL
);
825 if (!res
->regul_bulk
) {
826 dev_err(dev
, "failed to get memory for regulators\n");
829 for (i
= 0; i
< ARRAY_SIZE(supply
); ++i
) {
830 res
->regul_bulk
[i
].supply
= supply
[i
];
831 res
->regul_bulk
[i
].consumer
= NULL
;
834 ret
= regulator_bulk_get(dev
, ARRAY_SIZE(supply
), res
->regul_bulk
);
836 dev_err(dev
, "failed to get regulators\n");
839 res
->regul_count
= ARRAY_SIZE(supply
);
843 dev_err(dev
, "HDMI resource init - failed\n");
844 hdmi_resources_cleanup(hdev
);
848 static int hdmi_probe(struct platform_device
*pdev
)
850 struct device
*dev
= &pdev
->dev
;
851 struct resource
*res
;
852 struct i2c_adapter
*adapter
;
853 struct v4l2_subdev
*sd
;
854 struct hdmi_device
*hdmi_dev
= NULL
;
855 struct s5p_hdmi_platform_data
*pdata
= dev
->platform_data
;
858 dev_dbg(dev
, "probe start\n");
861 dev_err(dev
, "platform data is missing\n");
866 hdmi_dev
= devm_kzalloc(&pdev
->dev
, sizeof(*hdmi_dev
), GFP_KERNEL
);
868 dev_err(dev
, "out of memory\n");
875 ret
= hdmi_resources_init(hdmi_dev
);
879 /* mapping HDMI registers */
880 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
882 dev_err(dev
, "get memory resource failed.\n");
887 hdmi_dev
->regs
= devm_ioremap(&pdev
->dev
, res
->start
,
889 if (hdmi_dev
->regs
== NULL
) {
890 dev_err(dev
, "register mapping failed.\n");
895 res
= platform_get_resource(pdev
, IORESOURCE_IRQ
, 0);
897 dev_err(dev
, "get interrupt resource failed.\n");
902 ret
= devm_request_irq(&pdev
->dev
, res
->start
, hdmi_irq_handler
, 0,
905 dev_err(dev
, "request interrupt failed.\n");
908 hdmi_dev
->irq
= res
->start
;
910 /* setting v4l2 name to prevent WARN_ON in v4l2_device_register */
911 strlcpy(hdmi_dev
->v4l2_dev
.name
, dev_name(dev
),
912 sizeof(hdmi_dev
->v4l2_dev
.name
));
913 /* passing NULL owner prevents driver from erasing drvdata */
914 ret
= v4l2_device_register(NULL
, &hdmi_dev
->v4l2_dev
);
916 dev_err(dev
, "could not register v4l2 device.\n");
920 /* testing if hdmiphy info is present */
921 if (!pdata
->hdmiphy_info
) {
922 dev_err(dev
, "hdmiphy info is missing in platform data\n");
927 adapter
= i2c_get_adapter(pdata
->hdmiphy_bus
);
928 if (adapter
== NULL
) {
929 dev_err(dev
, "hdmiphy adapter request failed\n");
934 hdmi_dev
->phy_sd
= v4l2_i2c_new_subdev_board(&hdmi_dev
->v4l2_dev
,
935 adapter
, pdata
->hdmiphy_info
, NULL
);
936 /* on failure or not adapter is no longer useful */
937 i2c_put_adapter(adapter
);
938 if (hdmi_dev
->phy_sd
== NULL
) {
939 dev_err(dev
, "missing subdev for hdmiphy\n");
944 /* initialization of MHL interface if present */
945 if (pdata
->mhl_info
) {
946 adapter
= i2c_get_adapter(pdata
->mhl_bus
);
947 if (adapter
== NULL
) {
948 dev_err(dev
, "MHL adapter request failed\n");
953 hdmi_dev
->mhl_sd
= v4l2_i2c_new_subdev_board(
954 &hdmi_dev
->v4l2_dev
, adapter
,
955 pdata
->mhl_info
, NULL
);
956 /* on failure or not adapter is no longer useful */
957 i2c_put_adapter(adapter
);
958 if (hdmi_dev
->mhl_sd
== NULL
) {
959 dev_err(dev
, "missing subdev for MHL\n");
965 clk_enable(hdmi_dev
->res
.hdmi
);
967 pm_runtime_enable(dev
);
970 v4l2_subdev_init(sd
, &hdmi_sd_ops
);
971 sd
->owner
= THIS_MODULE
;
973 strlcpy(sd
->name
, "s5p-hdmi", sizeof(sd
->name
));
974 hdmi_dev
->cur_timings
=
975 hdmi_timings
[HDMI_DEFAULT_TIMINGS_IDX
].dv_timings
;
976 /* FIXME: missing fail timings is not supported */
978 hdmi_timings
[HDMI_DEFAULT_TIMINGS_IDX
].hdmi_timings
;
979 hdmi_dev
->cur_conf_dirty
= 1;
981 /* storing subdev for call that have only access to struct device */
982 dev_set_drvdata(dev
, sd
);
984 dev_info(dev
, "probe successful\n");
989 v4l2_device_unregister(&hdmi_dev
->v4l2_dev
);
992 hdmi_resources_cleanup(hdmi_dev
);
995 dev_err(dev
, "probe failed\n");
999 static int hdmi_remove(struct platform_device
*pdev
)
1001 struct device
*dev
= &pdev
->dev
;
1002 struct v4l2_subdev
*sd
= dev_get_drvdata(dev
);
1003 struct hdmi_device
*hdmi_dev
= sd_to_hdmi_dev(sd
);
1005 pm_runtime_disable(dev
);
1006 clk_disable(hdmi_dev
->res
.hdmi
);
1007 v4l2_device_unregister(&hdmi_dev
->v4l2_dev
);
1008 disable_irq(hdmi_dev
->irq
);
1009 hdmi_resources_cleanup(hdmi_dev
);
1010 dev_info(dev
, "remove successful\n");
1015 static struct platform_driver hdmi_driver __refdata
= {
1016 .probe
= hdmi_probe
,
1017 .remove
= hdmi_remove
,
1018 .id_table
= hdmi_driver_types
,
1021 .owner
= THIS_MODULE
,
1026 module_platform_driver(hdmi_driver
);