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>
35 #include <media/s5p_hdmi.h>
36 #include <media/v4l2-common.h>
37 #include <media/v4l2-dev.h>
38 #include <media/v4l2-device.h>
40 #include "regs-hdmi.h"
42 MODULE_AUTHOR("Tomasz Stanislawski, <t.stanislaws@samsung.com>");
43 MODULE_DESCRIPTION("Samsung HDMI");
44 MODULE_LICENSE("GPL");
46 /* default preset configured on probe */
47 #define HDMI_DEFAULT_PRESET V4L2_DV_480P59_94
55 struct hdmi_pulse hact
;
56 u32 hsyn_pol
; /* 0 - high, 1 - low */
57 struct hdmi_pulse hsyn
;
59 struct hdmi_pulse vact
[2];
60 u32 vsyn_pol
; /* 0 - high, 1 - low */
62 struct hdmi_pulse vsyn
[2];
65 struct hdmi_resources
{
67 struct clk
*sclk_hdmi
;
68 struct clk
*sclk_pixel
;
69 struct clk
*sclk_hdmiphy
;
71 struct regulator_bulk_data
*regul_bulk
;
76 /** base address of HDMI registers */
80 /** pointer to device parent */
82 /** subdev generated by HDMI device */
83 struct v4l2_subdev sd
;
84 /** V4L2 device structure */
85 struct v4l2_device v4l2_dev
;
86 /** subdev of HDMIPHY interface */
87 struct v4l2_subdev
*phy_sd
;
88 /** subdev of MHL interface */
89 struct v4l2_subdev
*mhl_sd
;
90 /** configuration of current graphic mode */
91 const struct hdmi_timings
*cur_conf
;
92 /** flag indicating that timings are dirty */
96 /** other resources */
97 struct hdmi_resources res
;
100 static struct platform_device_id hdmi_driver_types
[] = {
102 .name
= "s5pv210-hdmi",
104 .name
= "exynos4-hdmi",
110 static const struct v4l2_subdev_ops hdmi_sd_ops
;
112 static struct hdmi_device
*sd_to_hdmi_dev(struct v4l2_subdev
*sd
)
114 return container_of(sd
, struct hdmi_device
, sd
);
118 void hdmi_write(struct hdmi_device
*hdev
, u32 reg_id
, u32 value
)
120 writel(value
, hdev
->regs
+ reg_id
);
124 void hdmi_write_mask(struct hdmi_device
*hdev
, u32 reg_id
, u32 value
, u32 mask
)
126 u32 old
= readl(hdev
->regs
+ reg_id
);
127 value
= (value
& mask
) | (old
& ~mask
);
128 writel(value
, hdev
->regs
+ reg_id
);
132 void hdmi_writeb(struct hdmi_device
*hdev
, u32 reg_id
, u8 value
)
134 writeb(value
, hdev
->regs
+ reg_id
);
138 void hdmi_writebn(struct hdmi_device
*hdev
, u32 reg_id
, int n
, u32 value
)
142 writeb(value
>> 24, hdev
->regs
+ reg_id
+ 12);
144 writeb(value
>> 16, hdev
->regs
+ reg_id
+ 8);
146 writeb(value
>> 8, hdev
->regs
+ reg_id
+ 4);
148 writeb(value
>> 0, hdev
->regs
+ reg_id
+ 0);
152 static inline u32
hdmi_read(struct hdmi_device
*hdev
, u32 reg_id
)
154 return readl(hdev
->regs
+ reg_id
);
157 static irqreturn_t
hdmi_irq_handler(int irq
, void *dev_data
)
159 struct hdmi_device
*hdev
= dev_data
;
163 intc_flag
= hdmi_read(hdev
, HDMI_INTC_FLAG
);
164 /* clearing flags for HPD plug/unplug */
165 if (intc_flag
& HDMI_INTC_FLAG_HPD_UNPLUG
) {
166 pr_info("unplugged\n");
167 hdmi_write_mask(hdev
, HDMI_INTC_FLAG
, ~0,
168 HDMI_INTC_FLAG_HPD_UNPLUG
);
170 if (intc_flag
& HDMI_INTC_FLAG_HPD_PLUG
) {
171 pr_info("plugged\n");
172 hdmi_write_mask(hdev
, HDMI_INTC_FLAG
, ~0,
173 HDMI_INTC_FLAG_HPD_PLUG
);
179 static void hdmi_reg_init(struct hdmi_device
*hdev
)
181 /* enable HPD interrupts */
182 hdmi_write_mask(hdev
, HDMI_INTC_CON
, ~0, HDMI_INTC_EN_GLOBAL
|
183 HDMI_INTC_EN_HPD_PLUG
| HDMI_INTC_EN_HPD_UNPLUG
);
184 /* choose DVI mode */
185 hdmi_write_mask(hdev
, HDMI_MODE_SEL
,
186 HDMI_MODE_DVI_EN
, HDMI_MODE_MASK
);
187 hdmi_write_mask(hdev
, HDMI_CON_2
, ~0,
188 HDMI_DVI_PERAMBLE_EN
| HDMI_DVI_BAND_EN
);
189 /* disable bluescreen */
190 hdmi_write_mask(hdev
, HDMI_CON_0
, 0, HDMI_BLUE_SCR_EN
);
191 /* choose bluescreen (fecal) color */
192 hdmi_writeb(hdev
, HDMI_BLUE_SCREEN_0
, 0x12);
193 hdmi_writeb(hdev
, HDMI_BLUE_SCREEN_1
, 0x34);
194 hdmi_writeb(hdev
, HDMI_BLUE_SCREEN_2
, 0x56);
197 static void hdmi_timing_apply(struct hdmi_device
*hdev
,
198 const struct hdmi_timings
*t
)
200 /* setting core registers */
201 hdmi_writebn(hdev
, HDMI_H_BLANK_0
, 2, t
->hact
.beg
);
202 hdmi_writebn(hdev
, HDMI_H_SYNC_GEN_0
, 3,
203 (t
->hsyn_pol
<< 20) | (t
->hsyn
.end
<< 10) | t
->hsyn
.beg
);
204 hdmi_writeb(hdev
, HDMI_VSYNC_POL
, t
->vsyn_pol
);
205 hdmi_writebn(hdev
, HDMI_V_BLANK_0
, 3,
206 (t
->vact
[0].beg
<< 11) | t
->vact
[0].end
);
207 hdmi_writebn(hdev
, HDMI_V_SYNC_GEN_1_0
, 3,
208 (t
->vsyn
[0].beg
<< 12) | t
->vsyn
[0].end
);
210 u32 vsyn_trans
= t
->hsyn
.beg
+ t
->vsyn_off
;
212 hdmi_writeb(hdev
, HDMI_INT_PRO_MODE
, 1);
213 hdmi_writebn(hdev
, HDMI_H_V_LINE_0
, 3,
214 (t
->hact
.end
<< 12) | t
->vact
[1].end
);
215 hdmi_writebn(hdev
, HDMI_V_BLANK_F_0
, 3,
216 (t
->vact
[1].end
<< 11) | t
->vact
[1].beg
);
217 hdmi_writebn(hdev
, HDMI_V_SYNC_GEN_2_0
, 3,
218 (t
->vsyn
[1].beg
<< 12) | t
->vsyn
[1].end
);
219 hdmi_writebn(hdev
, HDMI_V_SYNC_GEN_3_0
, 3,
220 (vsyn_trans
<< 12) | vsyn_trans
);
222 hdmi_writeb(hdev
, HDMI_INT_PRO_MODE
, 0);
223 hdmi_writebn(hdev
, HDMI_H_V_LINE_0
, 3,
224 (t
->hact
.end
<< 12) | t
->vact
[0].end
);
227 /* Timing generator registers */
228 hdmi_writebn(hdev
, HDMI_TG_H_FSZ_L
, 2, t
->hact
.end
);
229 hdmi_writebn(hdev
, HDMI_TG_HACT_ST_L
, 2, t
->hact
.beg
);
230 hdmi_writebn(hdev
, HDMI_TG_HACT_SZ_L
, 2, t
->hact
.end
- t
->hact
.beg
);
231 hdmi_writebn(hdev
, HDMI_TG_VSYNC_L
, 2, t
->vsyn
[0].beg
);
232 hdmi_writebn(hdev
, HDMI_TG_VACT_ST_L
, 2, t
->vact
[0].beg
);
233 hdmi_writebn(hdev
, HDMI_TG_VACT_SZ_L
, 2,
234 t
->vact
[0].end
- t
->vact
[0].beg
);
235 hdmi_writebn(hdev
, HDMI_TG_VSYNC_TOP_HDMI_L
, 2, t
->vsyn
[0].beg
);
236 hdmi_writebn(hdev
, HDMI_TG_FIELD_TOP_HDMI_L
, 2, t
->vsyn
[0].beg
);
238 hdmi_write_mask(hdev
, HDMI_TG_CMD
, ~0, HDMI_TG_FIELD_EN
);
239 hdmi_writebn(hdev
, HDMI_TG_V_FSZ_L
, 2, t
->vact
[1].end
);
240 hdmi_writebn(hdev
, HDMI_TG_VSYNC2_L
, 2, t
->vsyn
[1].beg
);
241 hdmi_writebn(hdev
, HDMI_TG_FIELD_CHG_L
, 2, t
->vact
[0].end
);
242 hdmi_writebn(hdev
, HDMI_TG_VACT_ST2_L
, 2, t
->vact
[1].beg
);
243 hdmi_writebn(hdev
, HDMI_TG_VSYNC_BOT_HDMI_L
, 2, t
->vsyn
[1].beg
);
244 hdmi_writebn(hdev
, HDMI_TG_FIELD_BOT_HDMI_L
, 2, t
->vsyn
[1].beg
);
246 hdmi_write_mask(hdev
, HDMI_TG_CMD
, 0, HDMI_TG_FIELD_EN
);
247 hdmi_writebn(hdev
, HDMI_TG_V_FSZ_L
, 2, t
->vact
[0].end
);
251 static int hdmi_conf_apply(struct hdmi_device
*hdmi_dev
)
253 struct device
*dev
= hdmi_dev
->dev
;
254 const struct hdmi_timings
*conf
= hdmi_dev
->cur_conf
;
255 struct v4l2_dv_preset preset
;
258 dev_dbg(dev
, "%s\n", __func__
);
260 /* skip if conf is already synchronized with HW */
261 if (!hdmi_dev
->cur_conf_dirty
)
265 hdmi_write_mask(hdmi_dev
, HDMI_PHY_RSTOUT
, ~0, HDMI_PHY_SW_RSTOUT
);
267 hdmi_write_mask(hdmi_dev
, HDMI_PHY_RSTOUT
, 0, HDMI_PHY_SW_RSTOUT
);
270 /* configure presets */
271 preset
.preset
= hdmi_dev
->cur_preset
;
272 ret
= v4l2_subdev_call(hdmi_dev
->phy_sd
, video
, s_dv_preset
, &preset
);
274 dev_err(dev
, "failed to set preset (%u)\n", preset
.preset
);
278 /* resetting HDMI core */
279 hdmi_write_mask(hdmi_dev
, HDMI_CORE_RSTOUT
, 0, HDMI_CORE_SW_RSTOUT
);
281 hdmi_write_mask(hdmi_dev
, HDMI_CORE_RSTOUT
, ~0, HDMI_CORE_SW_RSTOUT
);
284 hdmi_reg_init(hdmi_dev
);
286 /* setting core registers */
287 hdmi_timing_apply(hdmi_dev
, conf
);
289 hdmi_dev
->cur_conf_dirty
= 0;
294 static void hdmi_dumpregs(struct hdmi_device
*hdev
, char *prefix
)
296 #define DUMPREG(reg_id) \
297 dev_dbg(hdev->dev, "%s:" #reg_id " = %08x\n", prefix, \
298 readl(hdev->regs + reg_id))
300 dev_dbg(hdev
->dev
, "%s: ---- CONTROL REGISTERS ----\n", prefix
);
301 DUMPREG(HDMI_INTC_FLAG
);
302 DUMPREG(HDMI_INTC_CON
);
303 DUMPREG(HDMI_HPD_STATUS
);
304 DUMPREG(HDMI_PHY_RSTOUT
);
305 DUMPREG(HDMI_PHY_VPLL
);
306 DUMPREG(HDMI_PHY_CMU
);
307 DUMPREG(HDMI_CORE_RSTOUT
);
309 dev_dbg(hdev
->dev
, "%s: ---- CORE REGISTERS ----\n", prefix
);
313 DUMPREG(HDMI_SYS_STATUS
);
314 DUMPREG(HDMI_PHY_STATUS
);
315 DUMPREG(HDMI_STATUS_EN
);
317 DUMPREG(HDMI_MODE_SEL
);
318 DUMPREG(HDMI_HPD_GEN
);
319 DUMPREG(HDMI_DC_CONTROL
);
320 DUMPREG(HDMI_VIDEO_PATTERN_GEN
);
322 dev_dbg(hdev
->dev
, "%s: ---- CORE SYNC REGISTERS ----\n", prefix
);
323 DUMPREG(HDMI_H_BLANK_0
);
324 DUMPREG(HDMI_H_BLANK_1
);
325 DUMPREG(HDMI_V_BLANK_0
);
326 DUMPREG(HDMI_V_BLANK_1
);
327 DUMPREG(HDMI_V_BLANK_2
);
328 DUMPREG(HDMI_H_V_LINE_0
);
329 DUMPREG(HDMI_H_V_LINE_1
);
330 DUMPREG(HDMI_H_V_LINE_2
);
331 DUMPREG(HDMI_VSYNC_POL
);
332 DUMPREG(HDMI_INT_PRO_MODE
);
333 DUMPREG(HDMI_V_BLANK_F_0
);
334 DUMPREG(HDMI_V_BLANK_F_1
);
335 DUMPREG(HDMI_V_BLANK_F_2
);
336 DUMPREG(HDMI_H_SYNC_GEN_0
);
337 DUMPREG(HDMI_H_SYNC_GEN_1
);
338 DUMPREG(HDMI_H_SYNC_GEN_2
);
339 DUMPREG(HDMI_V_SYNC_GEN_1_0
);
340 DUMPREG(HDMI_V_SYNC_GEN_1_1
);
341 DUMPREG(HDMI_V_SYNC_GEN_1_2
);
342 DUMPREG(HDMI_V_SYNC_GEN_2_0
);
343 DUMPREG(HDMI_V_SYNC_GEN_2_1
);
344 DUMPREG(HDMI_V_SYNC_GEN_2_2
);
345 DUMPREG(HDMI_V_SYNC_GEN_3_0
);
346 DUMPREG(HDMI_V_SYNC_GEN_3_1
);
347 DUMPREG(HDMI_V_SYNC_GEN_3_2
);
349 dev_dbg(hdev
->dev
, "%s: ---- TG REGISTERS ----\n", prefix
);
350 DUMPREG(HDMI_TG_CMD
);
351 DUMPREG(HDMI_TG_H_FSZ_L
);
352 DUMPREG(HDMI_TG_H_FSZ_H
);
353 DUMPREG(HDMI_TG_HACT_ST_L
);
354 DUMPREG(HDMI_TG_HACT_ST_H
);
355 DUMPREG(HDMI_TG_HACT_SZ_L
);
356 DUMPREG(HDMI_TG_HACT_SZ_H
);
357 DUMPREG(HDMI_TG_V_FSZ_L
);
358 DUMPREG(HDMI_TG_V_FSZ_H
);
359 DUMPREG(HDMI_TG_VSYNC_L
);
360 DUMPREG(HDMI_TG_VSYNC_H
);
361 DUMPREG(HDMI_TG_VSYNC2_L
);
362 DUMPREG(HDMI_TG_VSYNC2_H
);
363 DUMPREG(HDMI_TG_VACT_ST_L
);
364 DUMPREG(HDMI_TG_VACT_ST_H
);
365 DUMPREG(HDMI_TG_VACT_SZ_L
);
366 DUMPREG(HDMI_TG_VACT_SZ_H
);
367 DUMPREG(HDMI_TG_FIELD_CHG_L
);
368 DUMPREG(HDMI_TG_FIELD_CHG_H
);
369 DUMPREG(HDMI_TG_VACT_ST2_L
);
370 DUMPREG(HDMI_TG_VACT_ST2_H
);
371 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_L
);
372 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_H
);
373 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_L
);
374 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_H
);
375 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_L
);
376 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_H
);
377 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_L
);
378 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_H
);
382 static const struct hdmi_timings hdmi_timings_480p
= {
383 .hact
= { .beg
= 138, .end
= 858 },
385 .hsyn
= { .beg
= 16, .end
= 16 + 62 },
387 .vact
[0] = { .beg
= 42 + 3, .end
= 522 + 3 },
389 .vsyn
[0] = { .beg
= 6 + 3, .end
= 12 + 3},
392 static const struct hdmi_timings hdmi_timings_576p50
= {
393 .hact
= { .beg
= 144, .end
= 864 },
395 .hsyn
= { .beg
= 12, .end
= 12 + 64 },
397 .vact
[0] = { .beg
= 44 + 5, .end
= 620 + 5 },
399 .vsyn
[0] = { .beg
= 0 + 5, .end
= 5 + 5},
402 static const struct hdmi_timings hdmi_timings_720p60
= {
403 .hact
= { .beg
= 370, .end
= 1650 },
405 .hsyn
= { .beg
= 110, .end
= 110 + 40 },
407 .vact
[0] = { .beg
= 25 + 5, .end
= 745 + 5 },
409 .vsyn
[0] = { .beg
= 0 + 5, .end
= 5 + 5},
412 static const struct hdmi_timings hdmi_timings_720p50
= {
413 .hact
= { .beg
= 700, .end
= 1980 },
415 .hsyn
= { .beg
= 440, .end
= 440 + 40 },
417 .vact
[0] = { .beg
= 25 + 5, .end
= 745 + 5 },
419 .vsyn
[0] = { .beg
= 0 + 5, .end
= 5 + 5},
422 static const struct hdmi_timings hdmi_timings_1080p24
= {
423 .hact
= { .beg
= 830, .end
= 2750 },
425 .hsyn
= { .beg
= 638, .end
= 638 + 44 },
427 .vact
[0] = { .beg
= 41 + 4, .end
= 1121 + 4 },
429 .vsyn
[0] = { .beg
= 0 + 4, .end
= 5 + 4},
432 static const struct hdmi_timings hdmi_timings_1080p60
= {
433 .hact
= { .beg
= 280, .end
= 2200 },
435 .hsyn
= { .beg
= 88, .end
= 88 + 44 },
437 .vact
[0] = { .beg
= 41 + 4, .end
= 1121 + 4 },
439 .vsyn
[0] = { .beg
= 0 + 4, .end
= 5 + 4},
442 static const struct hdmi_timings hdmi_timings_1080i60
= {
443 .hact
= { .beg
= 280, .end
= 2200 },
445 .hsyn
= { .beg
= 88, .end
= 88 + 44 },
447 .vact
[0] = { .beg
= 20 + 2, .end
= 560 + 2 },
448 .vact
[1] = { .beg
= 583 + 2, .end
= 1123 + 2 },
451 .vsyn
[0] = { .beg
= 0 + 2, .end
= 5 + 2},
452 .vsyn
[1] = { .beg
= 562 + 2, .end
= 567 + 2},
455 static const struct hdmi_timings hdmi_timings_1080i50
= {
456 .hact
= { .beg
= 720, .end
= 2640 },
458 .hsyn
= { .beg
= 528, .end
= 528 + 44 },
460 .vact
[0] = { .beg
= 20 + 2, .end
= 560 + 2 },
461 .vact
[1] = { .beg
= 583 + 2, .end
= 1123 + 2 },
464 .vsyn
[0] = { .beg
= 0 + 2, .end
= 5 + 2},
465 .vsyn
[1] = { .beg
= 562 + 2, .end
= 567 + 2},
468 static const struct hdmi_timings hdmi_timings_1080p50
= {
469 .hact
= { .beg
= 720, .end
= 2640 },
471 .hsyn
= { .beg
= 528, .end
= 528 + 44 },
473 .vact
[0] = { .beg
= 41 + 4, .end
= 1121 + 4 },
475 .vsyn
[0] = { .beg
= 0 + 4, .end
= 5 + 4},
478 static const struct {
480 const struct hdmi_timings
*timings
;
482 { V4L2_DV_480P59_94
, &hdmi_timings_480p
},
483 { V4L2_DV_576P50
, &hdmi_timings_576p50
},
484 { V4L2_DV_720P50
, &hdmi_timings_720p50
},
485 { V4L2_DV_720P59_94
, &hdmi_timings_720p60
},
486 { V4L2_DV_720P60
, &hdmi_timings_720p60
},
487 { V4L2_DV_1080P24
, &hdmi_timings_1080p24
},
488 { V4L2_DV_1080P30
, &hdmi_timings_1080p60
},
489 { V4L2_DV_1080P50
, &hdmi_timings_1080p50
},
490 { V4L2_DV_1080I50
, &hdmi_timings_1080i50
},
491 { V4L2_DV_1080I60
, &hdmi_timings_1080i60
},
492 { V4L2_DV_1080P60
, &hdmi_timings_1080p60
},
495 static const struct hdmi_timings
*hdmi_preset2timings(u32 preset
)
499 for (i
= 0; i
< ARRAY_SIZE(hdmi_timings
); ++i
)
500 if (hdmi_timings
[i
].preset
== preset
)
501 return hdmi_timings
[i
].timings
;
505 static int hdmi_streamon(struct hdmi_device
*hdev
)
507 struct device
*dev
= hdev
->dev
;
508 struct hdmi_resources
*res
= &hdev
->res
;
511 dev_dbg(dev
, "%s\n", __func__
);
513 ret
= hdmi_conf_apply(hdev
);
517 ret
= v4l2_subdev_call(hdev
->phy_sd
, video
, s_stream
, 1);
521 /* waiting for HDMIPHY's PLL to get to steady state */
522 for (tries
= 100; tries
; --tries
) {
523 u32 val
= hdmi_read(hdev
, HDMI_PHY_STATUS
);
524 if (val
& HDMI_PHY_STATUS_READY
)
528 /* steady state not achieved */
530 dev_err(dev
, "hdmiphy's pll could not reach steady state.\n");
531 v4l2_subdev_call(hdev
->phy_sd
, video
, s_stream
, 0);
532 hdmi_dumpregs(hdev
, "hdmiphy - s_stream");
537 ret
= v4l2_subdev_call(hdev
->mhl_sd
, video
, s_stream
, 1);
538 if (hdev
->mhl_sd
&& ret
) {
539 v4l2_subdev_call(hdev
->phy_sd
, video
, s_stream
, 0);
540 hdmi_dumpregs(hdev
, "mhl - s_stream");
544 /* hdmiphy clock is used for HDMI in streaming mode */
545 clk_disable(res
->sclk_hdmi
);
546 clk_set_parent(res
->sclk_hdmi
, res
->sclk_hdmiphy
);
547 clk_enable(res
->sclk_hdmi
);
549 /* enable HDMI and timing generator */
550 hdmi_write_mask(hdev
, HDMI_CON_0
, ~0, HDMI_EN
);
551 hdmi_write_mask(hdev
, HDMI_TG_CMD
, ~0, HDMI_TG_EN
);
552 hdmi_dumpregs(hdev
, "streamon");
556 static int hdmi_streamoff(struct hdmi_device
*hdev
)
558 struct device
*dev
= hdev
->dev
;
559 struct hdmi_resources
*res
= &hdev
->res
;
561 dev_dbg(dev
, "%s\n", __func__
);
563 hdmi_write_mask(hdev
, HDMI_CON_0
, 0, HDMI_EN
);
564 hdmi_write_mask(hdev
, HDMI_TG_CMD
, 0, HDMI_TG_EN
);
566 /* pixel(vpll) clock is used for HDMI in config mode */
567 clk_disable(res
->sclk_hdmi
);
568 clk_set_parent(res
->sclk_hdmi
, res
->sclk_pixel
);
569 clk_enable(res
->sclk_hdmi
);
571 v4l2_subdev_call(hdev
->mhl_sd
, video
, s_stream
, 0);
572 v4l2_subdev_call(hdev
->phy_sd
, video
, s_stream
, 0);
574 hdmi_dumpregs(hdev
, "streamoff");
578 static int hdmi_s_stream(struct v4l2_subdev
*sd
, int enable
)
580 struct hdmi_device
*hdev
= sd_to_hdmi_dev(sd
);
581 struct device
*dev
= hdev
->dev
;
583 dev_dbg(dev
, "%s(%d)\n", __func__
, enable
);
585 return hdmi_streamon(hdev
);
586 return hdmi_streamoff(hdev
);
589 static void hdmi_resource_poweron(struct hdmi_resources
*res
)
591 /* turn HDMI power on */
592 regulator_bulk_enable(res
->regul_count
, res
->regul_bulk
);
593 /* power-on hdmi physical interface */
594 clk_enable(res
->hdmiphy
);
595 /* use VPP as parent clock; HDMIPHY is not working yet */
596 clk_set_parent(res
->sclk_hdmi
, res
->sclk_pixel
);
598 clk_enable(res
->sclk_hdmi
);
601 static void hdmi_resource_poweroff(struct hdmi_resources
*res
)
603 /* turn clocks off */
604 clk_disable(res
->sclk_hdmi
);
605 /* power-off hdmiphy */
606 clk_disable(res
->hdmiphy
);
607 /* turn HDMI power off */
608 regulator_bulk_disable(res
->regul_count
, res
->regul_bulk
);
611 static int hdmi_s_power(struct v4l2_subdev
*sd
, int on
)
613 struct hdmi_device
*hdev
= sd_to_hdmi_dev(sd
);
617 ret
= pm_runtime_get_sync(hdev
->dev
);
619 ret
= pm_runtime_put_sync(hdev
->dev
);
620 /* only values < 0 indicate errors */
621 return IS_ERR_VALUE(ret
) ? ret
: 0;
624 static int hdmi_s_dv_preset(struct v4l2_subdev
*sd
,
625 struct v4l2_dv_preset
*preset
)
627 struct hdmi_device
*hdev
= sd_to_hdmi_dev(sd
);
628 struct device
*dev
= hdev
->dev
;
629 const struct hdmi_timings
*conf
;
631 conf
= hdmi_preset2timings(preset
->preset
);
633 dev_err(dev
, "preset (%u) not supported\n", preset
->preset
);
636 hdev
->cur_conf
= conf
;
637 hdev
->cur_conf_dirty
= 1;
638 hdev
->cur_preset
= preset
->preset
;
642 static int hdmi_g_dv_preset(struct v4l2_subdev
*sd
,
643 struct v4l2_dv_preset
*preset
)
645 memset(preset
, 0, sizeof(*preset
));
646 preset
->preset
= sd_to_hdmi_dev(sd
)->cur_preset
;
650 static int hdmi_g_mbus_fmt(struct v4l2_subdev
*sd
,
651 struct v4l2_mbus_framefmt
*fmt
)
653 struct hdmi_device
*hdev
= sd_to_hdmi_dev(sd
);
654 const struct hdmi_timings
*t
= hdev
->cur_conf
;
656 dev_dbg(hdev
->dev
, "%s\n", __func__
);
659 memset(fmt
, 0, sizeof *fmt
);
660 fmt
->width
= t
->hact
.end
- t
->hact
.beg
;
661 fmt
->height
= t
->vact
[0].end
- t
->vact
[0].beg
;
662 fmt
->code
= V4L2_MBUS_FMT_FIXED
; /* means RGB888 */
663 fmt
->colorspace
= V4L2_COLORSPACE_SRGB
;
665 fmt
->field
= V4L2_FIELD_INTERLACED
;
668 fmt
->field
= V4L2_FIELD_NONE
;
673 static int hdmi_enum_dv_presets(struct v4l2_subdev
*sd
,
674 struct v4l2_dv_enum_preset
*preset
)
676 if (preset
->index
>= ARRAY_SIZE(hdmi_timings
))
678 return v4l_fill_dv_preset_info(hdmi_timings
[preset
->index
].preset
,
682 static const struct v4l2_subdev_core_ops hdmi_sd_core_ops
= {
683 .s_power
= hdmi_s_power
,
686 static const struct v4l2_subdev_video_ops hdmi_sd_video_ops
= {
687 .s_dv_preset
= hdmi_s_dv_preset
,
688 .g_dv_preset
= hdmi_g_dv_preset
,
689 .enum_dv_presets
= hdmi_enum_dv_presets
,
690 .g_mbus_fmt
= hdmi_g_mbus_fmt
,
691 .s_stream
= hdmi_s_stream
,
694 static const struct v4l2_subdev_ops hdmi_sd_ops
= {
695 .core
= &hdmi_sd_core_ops
,
696 .video
= &hdmi_sd_video_ops
,
699 static int hdmi_runtime_suspend(struct device
*dev
)
701 struct v4l2_subdev
*sd
= dev_get_drvdata(dev
);
702 struct hdmi_device
*hdev
= sd_to_hdmi_dev(sd
);
704 dev_dbg(dev
, "%s\n", __func__
);
705 v4l2_subdev_call(hdev
->mhl_sd
, core
, s_power
, 0);
706 hdmi_resource_poweroff(&hdev
->res
);
707 /* flag that device context is lost */
708 hdev
->cur_conf_dirty
= 1;
712 static int hdmi_runtime_resume(struct device
*dev
)
714 struct v4l2_subdev
*sd
= dev_get_drvdata(dev
);
715 struct hdmi_device
*hdev
= sd_to_hdmi_dev(sd
);
718 dev_dbg(dev
, "%s\n", __func__
);
720 hdmi_resource_poweron(&hdev
->res
);
723 ret
= v4l2_subdev_call(hdev
->mhl_sd
, core
, s_power
, 1);
724 if (hdev
->mhl_sd
&& ret
)
727 dev_dbg(dev
, "poweron succeed\n");
732 hdmi_resource_poweroff(&hdev
->res
);
733 dev_err(dev
, "poweron failed\n");
738 static const struct dev_pm_ops hdmi_pm_ops
= {
739 .runtime_suspend
= hdmi_runtime_suspend
,
740 .runtime_resume
= hdmi_runtime_resume
,
743 static void hdmi_resources_cleanup(struct hdmi_device
*hdev
)
745 struct hdmi_resources
*res
= &hdev
->res
;
747 dev_dbg(hdev
->dev
, "HDMI resource cleanup\n");
748 /* put clocks, power */
749 if (res
->regul_count
)
750 regulator_bulk_free(res
->regul_count
, res
->regul_bulk
);
751 /* kfree is NULL-safe */
752 kfree(res
->regul_bulk
);
753 if (!IS_ERR_OR_NULL(res
->hdmiphy
))
754 clk_put(res
->hdmiphy
);
755 if (!IS_ERR_OR_NULL(res
->sclk_hdmiphy
))
756 clk_put(res
->sclk_hdmiphy
);
757 if (!IS_ERR_OR_NULL(res
->sclk_pixel
))
758 clk_put(res
->sclk_pixel
);
759 if (!IS_ERR_OR_NULL(res
->sclk_hdmi
))
760 clk_put(res
->sclk_hdmi
);
761 if (!IS_ERR_OR_NULL(res
->hdmi
))
763 memset(res
, 0, sizeof *res
);
766 static int hdmi_resources_init(struct hdmi_device
*hdev
)
768 struct device
*dev
= hdev
->dev
;
769 struct hdmi_resources
*res
= &hdev
->res
;
770 static char *supply
[] = {
778 dev_dbg(dev
, "HDMI resource init\n");
780 memset(res
, 0, sizeof *res
);
781 /* get clocks, power */
783 res
->hdmi
= clk_get(dev
, "hdmi");
784 if (IS_ERR_OR_NULL(res
->hdmi
)) {
785 dev_err(dev
, "failed to get clock 'hdmi'\n");
788 res
->sclk_hdmi
= clk_get(dev
, "sclk_hdmi");
789 if (IS_ERR_OR_NULL(res
->sclk_hdmi
)) {
790 dev_err(dev
, "failed to get clock 'sclk_hdmi'\n");
793 res
->sclk_pixel
= clk_get(dev
, "sclk_pixel");
794 if (IS_ERR_OR_NULL(res
->sclk_pixel
)) {
795 dev_err(dev
, "failed to get clock 'sclk_pixel'\n");
798 res
->sclk_hdmiphy
= clk_get(dev
, "sclk_hdmiphy");
799 if (IS_ERR_OR_NULL(res
->sclk_hdmiphy
)) {
800 dev_err(dev
, "failed to get clock 'sclk_hdmiphy'\n");
803 res
->hdmiphy
= clk_get(dev
, "hdmiphy");
804 if (IS_ERR_OR_NULL(res
->hdmiphy
)) {
805 dev_err(dev
, "failed to get clock 'hdmiphy'\n");
808 res
->regul_bulk
= kcalloc(ARRAY_SIZE(supply
),
809 sizeof(res
->regul_bulk
[0]), GFP_KERNEL
);
810 if (!res
->regul_bulk
) {
811 dev_err(dev
, "failed to get memory for regulators\n");
814 for (i
= 0; i
< ARRAY_SIZE(supply
); ++i
) {
815 res
->regul_bulk
[i
].supply
= supply
[i
];
816 res
->regul_bulk
[i
].consumer
= NULL
;
819 ret
= regulator_bulk_get(dev
, ARRAY_SIZE(supply
), res
->regul_bulk
);
821 dev_err(dev
, "failed to get regulators\n");
824 res
->regul_count
= ARRAY_SIZE(supply
);
828 dev_err(dev
, "HDMI resource init - failed\n");
829 hdmi_resources_cleanup(hdev
);
833 static int hdmi_probe(struct platform_device
*pdev
)
835 struct device
*dev
= &pdev
->dev
;
836 struct resource
*res
;
837 struct i2c_adapter
*adapter
;
838 struct v4l2_subdev
*sd
;
839 struct hdmi_device
*hdmi_dev
= NULL
;
840 struct s5p_hdmi_platform_data
*pdata
= dev
->platform_data
;
843 dev_dbg(dev
, "probe start\n");
846 dev_err(dev
, "platform data is missing\n");
851 hdmi_dev
= devm_kzalloc(&pdev
->dev
, sizeof(*hdmi_dev
), GFP_KERNEL
);
853 dev_err(dev
, "out of memory\n");
860 ret
= hdmi_resources_init(hdmi_dev
);
864 /* mapping HDMI registers */
865 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
867 dev_err(dev
, "get memory resource failed.\n");
872 hdmi_dev
->regs
= devm_ioremap(&pdev
->dev
, res
->start
,
874 if (hdmi_dev
->regs
== NULL
) {
875 dev_err(dev
, "register mapping failed.\n");
880 res
= platform_get_resource(pdev
, IORESOURCE_IRQ
, 0);
882 dev_err(dev
, "get interrupt resource failed.\n");
887 ret
= devm_request_irq(&pdev
->dev
, res
->start
, hdmi_irq_handler
, 0,
890 dev_err(dev
, "request interrupt failed.\n");
893 hdmi_dev
->irq
= res
->start
;
895 /* setting v4l2 name to prevent WARN_ON in v4l2_device_register */
896 strlcpy(hdmi_dev
->v4l2_dev
.name
, dev_name(dev
),
897 sizeof(hdmi_dev
->v4l2_dev
.name
));
898 /* passing NULL owner prevents driver from erasing drvdata */
899 ret
= v4l2_device_register(NULL
, &hdmi_dev
->v4l2_dev
);
901 dev_err(dev
, "could not register v4l2 device.\n");
905 /* testing if hdmiphy info is present */
906 if (!pdata
->hdmiphy_info
) {
907 dev_err(dev
, "hdmiphy info is missing in platform data\n");
912 adapter
= i2c_get_adapter(pdata
->hdmiphy_bus
);
913 if (adapter
== NULL
) {
914 dev_err(dev
, "hdmiphy adapter request failed\n");
919 hdmi_dev
->phy_sd
= v4l2_i2c_new_subdev_board(&hdmi_dev
->v4l2_dev
,
920 adapter
, pdata
->hdmiphy_info
, NULL
);
921 /* on failure or not adapter is no longer useful */
922 i2c_put_adapter(adapter
);
923 if (hdmi_dev
->phy_sd
== NULL
) {
924 dev_err(dev
, "missing subdev for hdmiphy\n");
929 /* initialization of MHL interface if present */
930 if (pdata
->mhl_info
) {
931 adapter
= i2c_get_adapter(pdata
->mhl_bus
);
932 if (adapter
== NULL
) {
933 dev_err(dev
, "MHL adapter request failed\n");
938 hdmi_dev
->mhl_sd
= v4l2_i2c_new_subdev_board(
939 &hdmi_dev
->v4l2_dev
, adapter
,
940 pdata
->mhl_info
, NULL
);
941 /* on failure or not adapter is no longer useful */
942 i2c_put_adapter(adapter
);
943 if (hdmi_dev
->mhl_sd
== NULL
) {
944 dev_err(dev
, "missing subdev for MHL\n");
950 clk_enable(hdmi_dev
->res
.hdmi
);
952 pm_runtime_enable(dev
);
955 v4l2_subdev_init(sd
, &hdmi_sd_ops
);
956 sd
->owner
= THIS_MODULE
;
958 strlcpy(sd
->name
, "s5p-hdmi", sizeof sd
->name
);
959 hdmi_dev
->cur_preset
= HDMI_DEFAULT_PRESET
;
960 /* FIXME: missing fail preset is not supported */
961 hdmi_dev
->cur_conf
= hdmi_preset2timings(hdmi_dev
->cur_preset
);
962 hdmi_dev
->cur_conf_dirty
= 1;
964 /* storing subdev for call that have only access to struct device */
965 dev_set_drvdata(dev
, sd
);
967 dev_info(dev
, "probe successful\n");
972 v4l2_device_unregister(&hdmi_dev
->v4l2_dev
);
975 hdmi_resources_cleanup(hdmi_dev
);
978 dev_err(dev
, "probe failed\n");
982 static int hdmi_remove(struct platform_device
*pdev
)
984 struct device
*dev
= &pdev
->dev
;
985 struct v4l2_subdev
*sd
= dev_get_drvdata(dev
);
986 struct hdmi_device
*hdmi_dev
= sd_to_hdmi_dev(sd
);
988 pm_runtime_disable(dev
);
989 clk_disable(hdmi_dev
->res
.hdmi
);
990 v4l2_device_unregister(&hdmi_dev
->v4l2_dev
);
991 disable_irq(hdmi_dev
->irq
);
992 hdmi_resources_cleanup(hdmi_dev
);
993 dev_info(dev
, "remove successful\n");
998 static struct platform_driver hdmi_driver __refdata
= {
1000 .remove
= hdmi_remove
,
1001 .id_table
= hdmi_driver_types
,
1004 .owner
= THIS_MODULE
,
1009 module_platform_driver(hdmi_driver
);