1/*
2 * Samsung HDMI interface driver
3 *
4 * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
5 *
6 * Tomasz Stanislawski, <t.stanislaws@samsung.com>
7 *
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
12 */
13
14#ifdef CONFIG_VIDEO_SAMSUNG_S5P_HDMI_DEBUG
15#define DEBUG
16#endif
17
18#include <linux/kernel.h>
19#include <linux/slab.h>
20#include <linux/io.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>
32
33#include <media/s5p_hdmi.h>
34#include <media/v4l2-common.h>
35#include <media/v4l2-dev.h>
36#include <media/v4l2-device.h>
37
38#include "regs-hdmi.h"
39
40MODULE_AUTHOR("Tomasz Stanislawski, <t.stanislaws@samsung.com>");
41MODULE_DESCRIPTION("Samsung HDMI");
42MODULE_LICENSE("GPL");
43
44/* default preset configured on probe */
45#define HDMI_DEFAULT_PRESET V4L2_DV_1080P60
46
47struct hdmi_resources {
48	struct clk *hdmi;
49	struct clk *sclk_hdmi;
50	struct clk *sclk_pixel;
51	struct clk *sclk_hdmiphy;
52	struct clk *hdmiphy;
53	struct regulator_bulk_data *regul_bulk;
54	int regul_count;
55};
56
57struct hdmi_device {
58	/** base address of HDMI registers */
59	void __iomem *regs;
60	/** HDMI interrupt */
61	unsigned int irq;
62	/** pointer to device parent */
63	struct device *dev;
64	/** subdev generated by HDMI device */
65	struct v4l2_subdev sd;
66	/** V4L2 device structure */
67	struct v4l2_device v4l2_dev;
68	/** subdev of HDMIPHY interface */
69	struct v4l2_subdev *phy_sd;
70	/** subdev of MHL interface */
71	struct v4l2_subdev *mhl_sd;
72	/** configuration of current graphic mode */
73	const struct hdmi_preset_conf *cur_conf;
74	/** current preset */
75	u32 cur_preset;
76	/** other resources */
77	struct hdmi_resources res;
78};
79
80struct hdmi_tg_regs {
81	u8 cmd;
82	u8 h_fsz_l;
83	u8 h_fsz_h;
84	u8 hact_st_l;
85	u8 hact_st_h;
86	u8 hact_sz_l;
87	u8 hact_sz_h;
88	u8 v_fsz_l;
89	u8 v_fsz_h;
90	u8 vsync_l;
91	u8 vsync_h;
92	u8 vsync2_l;
93	u8 vsync2_h;
94	u8 vact_st_l;
95	u8 vact_st_h;
96	u8 vact_sz_l;
97	u8 vact_sz_h;
98	u8 field_chg_l;
99	u8 field_chg_h;
100	u8 vact_st2_l;
101	u8 vact_st2_h;
102	u8 vsync_top_hdmi_l;
103	u8 vsync_top_hdmi_h;
104	u8 vsync_bot_hdmi_l;
105	u8 vsync_bot_hdmi_h;
106	u8 field_top_hdmi_l;
107	u8 field_top_hdmi_h;
108	u8 field_bot_hdmi_l;
109	u8 field_bot_hdmi_h;
110};
111
112struct hdmi_core_regs {
113	u8 h_blank[2];
114	u8 v_blank[3];
115	u8 h_v_line[3];
116	u8 vsync_pol[1];
117	u8 int_pro_mode[1];
118	u8 v_blank_f[3];
119	u8 h_sync_gen[3];
120	u8 v_sync_gen1[3];
121	u8 v_sync_gen2[3];
122	u8 v_sync_gen3[3];
123};
124
125struct hdmi_preset_conf {
126	struct hdmi_core_regs core;
127	struct hdmi_tg_regs tg;
128	struct v4l2_mbus_framefmt mbus_fmt;
129};
130
131static struct platform_device_id hdmi_driver_types[] = {
132	{
133		.name		= "s5pv210-hdmi",
134	}, {
135		.name		= "exynos4-hdmi",
136	}, {
137		/* end node */
138	}
139};
140
141static const struct v4l2_subdev_ops hdmi_sd_ops;
142
143static struct hdmi_device *sd_to_hdmi_dev(struct v4l2_subdev *sd)
144{
145	return container_of(sd, struct hdmi_device, sd);
146}
147
148static inline
149void hdmi_write(struct hdmi_device *hdev, u32 reg_id, u32 value)
150{
151	writel(value, hdev->regs + reg_id);
152}
153
154static inline
155void hdmi_write_mask(struct hdmi_device *hdev, u32 reg_id, u32 value, u32 mask)
156{
157	u32 old = readl(hdev->regs + reg_id);
158	value = (value & mask) | (old & ~mask);
159	writel(value, hdev->regs + reg_id);
160}
161
162static inline
163void hdmi_writeb(struct hdmi_device *hdev, u32 reg_id, u8 value)
164{
165	writeb(value, hdev->regs + reg_id);
166}
167
168static inline u32 hdmi_read(struct hdmi_device *hdev, u32 reg_id)
169{
170	return readl(hdev->regs + reg_id);
171}
172
173static irqreturn_t hdmi_irq_handler(int irq, void *dev_data)
174{
175	struct hdmi_device *hdev = dev_data;
176	u32 intc_flag;
177
178	(void)irq;
179	intc_flag = hdmi_read(hdev, HDMI_INTC_FLAG);
180	/* clearing flags for HPD plug/unplug */
181	if (intc_flag & HDMI_INTC_FLAG_HPD_UNPLUG) {
182		printk(KERN_INFO "unplugged\n");
183		hdmi_write_mask(hdev, HDMI_INTC_FLAG, ~0,
184			HDMI_INTC_FLAG_HPD_UNPLUG);
185	}
186	if (intc_flag & HDMI_INTC_FLAG_HPD_PLUG) {
187		printk(KERN_INFO "plugged\n");
188		hdmi_write_mask(hdev, HDMI_INTC_FLAG, ~0,
189			HDMI_INTC_FLAG_HPD_PLUG);
190	}
191
192	return IRQ_HANDLED;
193}
194
195static void hdmi_reg_init(struct hdmi_device *hdev)
196{
197	/* enable HPD interrupts */
198	hdmi_write_mask(hdev, HDMI_INTC_CON, ~0, HDMI_INTC_EN_GLOBAL |
199		HDMI_INTC_EN_HPD_PLUG | HDMI_INTC_EN_HPD_UNPLUG);
200	/* choose DVI mode */
201	hdmi_write_mask(hdev, HDMI_MODE_SEL,
202		HDMI_MODE_DVI_EN, HDMI_MODE_MASK);
203	hdmi_write_mask(hdev, HDMI_CON_2, ~0,
204		HDMI_DVI_PERAMBLE_EN | HDMI_DVI_BAND_EN);
205	/* disable bluescreen */
206	hdmi_write_mask(hdev, HDMI_CON_0, 0, HDMI_BLUE_SCR_EN);
207	/* choose bluescreen (fecal) color */
208	hdmi_writeb(hdev, HDMI_BLUE_SCREEN_0, 0x12);
209	hdmi_writeb(hdev, HDMI_BLUE_SCREEN_1, 0x34);
210	hdmi_writeb(hdev, HDMI_BLUE_SCREEN_2, 0x56);
211}
212
213static void hdmi_timing_apply(struct hdmi_device *hdev,
214	const struct hdmi_preset_conf *conf)
215{
216	const struct hdmi_core_regs *core = &conf->core;
217	const struct hdmi_tg_regs *tg = &conf->tg;
218
219	/* setting core registers */
220	hdmi_writeb(hdev, HDMI_H_BLANK_0, core->h_blank[0]);
221	hdmi_writeb(hdev, HDMI_H_BLANK_1, core->h_blank[1]);
222	hdmi_writeb(hdev, HDMI_V_BLANK_0, core->v_blank[0]);
223	hdmi_writeb(hdev, HDMI_V_BLANK_1, core->v_blank[1]);
224	hdmi_writeb(hdev, HDMI_V_BLANK_2, core->v_blank[2]);
225	hdmi_writeb(hdev, HDMI_H_V_LINE_0, core->h_v_line[0]);
226	hdmi_writeb(hdev, HDMI_H_V_LINE_1, core->h_v_line[1]);
227	hdmi_writeb(hdev, HDMI_H_V_LINE_2, core->h_v_line[2]);
228	hdmi_writeb(hdev, HDMI_VSYNC_POL, core->vsync_pol[0]);
229	hdmi_writeb(hdev, HDMI_INT_PRO_MODE, core->int_pro_mode[0]);
230	hdmi_writeb(hdev, HDMI_V_BLANK_F_0, core->v_blank_f[0]);
231	hdmi_writeb(hdev, HDMI_V_BLANK_F_1, core->v_blank_f[1]);
232	hdmi_writeb(hdev, HDMI_V_BLANK_F_2, core->v_blank_f[2]);
233	hdmi_writeb(hdev, HDMI_H_SYNC_GEN_0, core->h_sync_gen[0]);
234	hdmi_writeb(hdev, HDMI_H_SYNC_GEN_1, core->h_sync_gen[1]);
235	hdmi_writeb(hdev, HDMI_H_SYNC_GEN_2, core->h_sync_gen[2]);
236	hdmi_writeb(hdev, HDMI_V_SYNC_GEN_1_0, core->v_sync_gen1[0]);
237	hdmi_writeb(hdev, HDMI_V_SYNC_GEN_1_1, core->v_sync_gen1[1]);
238	hdmi_writeb(hdev, HDMI_V_SYNC_GEN_1_2, core->v_sync_gen1[2]);
239	hdmi_writeb(hdev, HDMI_V_SYNC_GEN_2_0, core->v_sync_gen2[0]);
240	hdmi_writeb(hdev, HDMI_V_SYNC_GEN_2_1, core->v_sync_gen2[1]);
241	hdmi_writeb(hdev, HDMI_V_SYNC_GEN_2_2, core->v_sync_gen2[2]);
242	hdmi_writeb(hdev, HDMI_V_SYNC_GEN_3_0, core->v_sync_gen3[0]);
243	hdmi_writeb(hdev, HDMI_V_SYNC_GEN_3_1, core->v_sync_gen3[1]);
244	hdmi_writeb(hdev, HDMI_V_SYNC_GEN_3_2, core->v_sync_gen3[2]);
245	/* Timing generator registers */
246	hdmi_writeb(hdev, HDMI_TG_H_FSZ_L, tg->h_fsz_l);
247	hdmi_writeb(hdev, HDMI_TG_H_FSZ_H, tg->h_fsz_h);
248	hdmi_writeb(hdev, HDMI_TG_HACT_ST_L, tg->hact_st_l);
249	hdmi_writeb(hdev, HDMI_TG_HACT_ST_H, tg->hact_st_h);
250	hdmi_writeb(hdev, HDMI_TG_HACT_SZ_L, tg->hact_sz_l);
251	hdmi_writeb(hdev, HDMI_TG_HACT_SZ_H, tg->hact_sz_h);
252	hdmi_writeb(hdev, HDMI_TG_V_FSZ_L, tg->v_fsz_l);
253	hdmi_writeb(hdev, HDMI_TG_V_FSZ_H, tg->v_fsz_h);
254	hdmi_writeb(hdev, HDMI_TG_VSYNC_L, tg->vsync_l);
255	hdmi_writeb(hdev, HDMI_TG_VSYNC_H, tg->vsync_h);
256	hdmi_writeb(hdev, HDMI_TG_VSYNC2_L, tg->vsync2_l);
257	hdmi_writeb(hdev, HDMI_TG_VSYNC2_H, tg->vsync2_h);
258	hdmi_writeb(hdev, HDMI_TG_VACT_ST_L, tg->vact_st_l);
259	hdmi_writeb(hdev, HDMI_TG_VACT_ST_H, tg->vact_st_h);
260	hdmi_writeb(hdev, HDMI_TG_VACT_SZ_L, tg->vact_sz_l);
261	hdmi_writeb(hdev, HDMI_TG_VACT_SZ_H, tg->vact_sz_h);
262	hdmi_writeb(hdev, HDMI_TG_FIELD_CHG_L, tg->field_chg_l);
263	hdmi_writeb(hdev, HDMI_TG_FIELD_CHG_H, tg->field_chg_h);
264	hdmi_writeb(hdev, HDMI_TG_VACT_ST2_L, tg->vact_st2_l);
265	hdmi_writeb(hdev, HDMI_TG_VACT_ST2_H, tg->vact_st2_h);
266	hdmi_writeb(hdev, HDMI_TG_VSYNC_TOP_HDMI_L, tg->vsync_top_hdmi_l);
267	hdmi_writeb(hdev, HDMI_TG_VSYNC_TOP_HDMI_H, tg->vsync_top_hdmi_h);
268	hdmi_writeb(hdev, HDMI_TG_VSYNC_BOT_HDMI_L, tg->vsync_bot_hdmi_l);
269	hdmi_writeb(hdev, HDMI_TG_VSYNC_BOT_HDMI_H, tg->vsync_bot_hdmi_h);
270	hdmi_writeb(hdev, HDMI_TG_FIELD_TOP_HDMI_L, tg->field_top_hdmi_l);
271	hdmi_writeb(hdev, HDMI_TG_FIELD_TOP_HDMI_H, tg->field_top_hdmi_h);
272	hdmi_writeb(hdev, HDMI_TG_FIELD_BOT_HDMI_L, tg->field_bot_hdmi_l);
273	hdmi_writeb(hdev, HDMI_TG_FIELD_BOT_HDMI_H, tg->field_bot_hdmi_h);
274}
275
276static int hdmi_conf_apply(struct hdmi_device *hdmi_dev)
277{
278	struct device *dev = hdmi_dev->dev;
279	const struct hdmi_preset_conf *conf = hdmi_dev->cur_conf;
280	struct v4l2_dv_preset preset;
281	int ret;
282
283	dev_dbg(dev, "%s\n", __func__);
284
285	/* reset hdmiphy */
286	hdmi_write_mask(hdmi_dev, HDMI_PHY_RSTOUT, ~0, HDMI_PHY_SW_RSTOUT);
287	mdelay(10);
288	hdmi_write_mask(hdmi_dev, HDMI_PHY_RSTOUT,  0, HDMI_PHY_SW_RSTOUT);
289	mdelay(10);
290
291	/* configure presets */
292	preset.preset = hdmi_dev->cur_preset;
293	ret = v4l2_subdev_call(hdmi_dev->phy_sd, video, s_dv_preset, &preset);
294	if (ret) {
295		dev_err(dev, "failed to set preset (%u)\n", preset.preset);
296		return ret;
297	}
298
299	/* resetting HDMI core */
300	hdmi_write_mask(hdmi_dev, HDMI_CORE_RSTOUT,  0, HDMI_CORE_SW_RSTOUT);
301	mdelay(10);
302	hdmi_write_mask(hdmi_dev, HDMI_CORE_RSTOUT, ~0, HDMI_CORE_SW_RSTOUT);
303	mdelay(10);
304
305	hdmi_reg_init(hdmi_dev);
306
307	/* setting core registers */
308	hdmi_timing_apply(hdmi_dev, conf);
309
310	return 0;
311}
312
313static void hdmi_dumpregs(struct hdmi_device *hdev, char *prefix)
314{
315#define DUMPREG(reg_id) \
316	dev_dbg(hdev->dev, "%s:" #reg_id " = %08x\n", prefix, \
317		readl(hdev->regs + reg_id))
318
319	dev_dbg(hdev->dev, "%s: ---- CONTROL REGISTERS ----\n", prefix);
320	DUMPREG(HDMI_INTC_FLAG);
321	DUMPREG(HDMI_INTC_CON);
322	DUMPREG(HDMI_HPD_STATUS);
323	DUMPREG(HDMI_PHY_RSTOUT);
324	DUMPREG(HDMI_PHY_VPLL);
325	DUMPREG(HDMI_PHY_CMU);
326	DUMPREG(HDMI_CORE_RSTOUT);
327
328	dev_dbg(hdev->dev, "%s: ---- CORE REGISTERS ----\n", prefix);
329	DUMPREG(HDMI_CON_0);
330	DUMPREG(HDMI_CON_1);
331	DUMPREG(HDMI_CON_2);
332	DUMPREG(HDMI_SYS_STATUS);
333	DUMPREG(HDMI_PHY_STATUS);
334	DUMPREG(HDMI_STATUS_EN);
335	DUMPREG(HDMI_HPD);
336	DUMPREG(HDMI_MODE_SEL);
337	DUMPREG(HDMI_HPD_GEN);
338	DUMPREG(HDMI_DC_CONTROL);
339	DUMPREG(HDMI_VIDEO_PATTERN_GEN);
340
341	dev_dbg(hdev->dev, "%s: ---- CORE SYNC REGISTERS ----\n", prefix);
342	DUMPREG(HDMI_H_BLANK_0);
343	DUMPREG(HDMI_H_BLANK_1);
344	DUMPREG(HDMI_V_BLANK_0);
345	DUMPREG(HDMI_V_BLANK_1);
346	DUMPREG(HDMI_V_BLANK_2);
347	DUMPREG(HDMI_H_V_LINE_0);
348	DUMPREG(HDMI_H_V_LINE_1);
349	DUMPREG(HDMI_H_V_LINE_2);
350	DUMPREG(HDMI_VSYNC_POL);
351	DUMPREG(HDMI_INT_PRO_MODE);
352	DUMPREG(HDMI_V_BLANK_F_0);
353	DUMPREG(HDMI_V_BLANK_F_1);
354	DUMPREG(HDMI_V_BLANK_F_2);
355	DUMPREG(HDMI_H_SYNC_GEN_0);
356	DUMPREG(HDMI_H_SYNC_GEN_1);
357	DUMPREG(HDMI_H_SYNC_GEN_2);
358	DUMPREG(HDMI_V_SYNC_GEN_1_0);
359	DUMPREG(HDMI_V_SYNC_GEN_1_1);
360	DUMPREG(HDMI_V_SYNC_GEN_1_2);
361	DUMPREG(HDMI_V_SYNC_GEN_2_0);
362	DUMPREG(HDMI_V_SYNC_GEN_2_1);
363	DUMPREG(HDMI_V_SYNC_GEN_2_2);
364	DUMPREG(HDMI_V_SYNC_GEN_3_0);
365	DUMPREG(HDMI_V_SYNC_GEN_3_1);
366	DUMPREG(HDMI_V_SYNC_GEN_3_2);
367
368	dev_dbg(hdev->dev, "%s: ---- TG REGISTERS ----\n", prefix);
369	DUMPREG(HDMI_TG_CMD);
370	DUMPREG(HDMI_TG_H_FSZ_L);
371	DUMPREG(HDMI_TG_H_FSZ_H);
372	DUMPREG(HDMI_TG_HACT_ST_L);
373	DUMPREG(HDMI_TG_HACT_ST_H);
374	DUMPREG(HDMI_TG_HACT_SZ_L);
375	DUMPREG(HDMI_TG_HACT_SZ_H);
376	DUMPREG(HDMI_TG_V_FSZ_L);
377	DUMPREG(HDMI_TG_V_FSZ_H);
378	DUMPREG(HDMI_TG_VSYNC_L);
379	DUMPREG(HDMI_TG_VSYNC_H);
380	DUMPREG(HDMI_TG_VSYNC2_L);
381	DUMPREG(HDMI_TG_VSYNC2_H);
382	DUMPREG(HDMI_TG_VACT_ST_L);
383	DUMPREG(HDMI_TG_VACT_ST_H);
384	DUMPREG(HDMI_TG_VACT_SZ_L);
385	DUMPREG(HDMI_TG_VACT_SZ_H);
386	DUMPREG(HDMI_TG_FIELD_CHG_L);
387	DUMPREG(HDMI_TG_FIELD_CHG_H);
388	DUMPREG(HDMI_TG_VACT_ST2_L);
389	DUMPREG(HDMI_TG_VACT_ST2_H);
390	DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_L);
391	DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_H);
392	DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_L);
393	DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_H);
394	DUMPREG(HDMI_TG_FIELD_TOP_HDMI_L);
395	DUMPREG(HDMI_TG_FIELD_TOP_HDMI_H);
396	DUMPREG(HDMI_TG_FIELD_BOT_HDMI_L);
397	DUMPREG(HDMI_TG_FIELD_BOT_HDMI_H);
398#undef DUMPREG
399}
400
401static const struct hdmi_preset_conf hdmi_conf_480p = {
402	.core = {
403		.h_blank = {0x8a, 0x00},
404		.v_blank = {0x0d, 0x6a, 0x01},
405		.h_v_line = {0x0d, 0xa2, 0x35},
406		.vsync_pol = {0x01},
407		.int_pro_mode = {0x00},
408		.v_blank_f = {0x00, 0x00, 0x00},
409		.h_sync_gen = {0x0e, 0x30, 0x11},
410		.v_sync_gen1 = {0x0f, 0x90, 0x00},
411		/* other don't care */
412	},
413	.tg = {
414		0x00, /* cmd */
415		0x5a, 0x03, /* h_fsz */
416		0x8a, 0x00, 0xd0, 0x02, /* hact */
417		0x0d, 0x02, /* v_fsz */
418		0x01, 0x00, 0x33, 0x02, /* vsync */
419		0x2d, 0x00, 0xe0, 0x01, /* vact */
420		0x33, 0x02, /* field_chg */
421		0x49, 0x02, /* vact_st2 */
422		0x01, 0x00, 0x33, 0x02, /* vsync top/bot */
423		0x01, 0x00, 0x33, 0x02, /* field top/bot */
424	},
425	.mbus_fmt = {
426		.width = 720,
427		.height = 480,
428		.code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
429		.field = V4L2_FIELD_NONE,
430		.colorspace = V4L2_COLORSPACE_SRGB,
431	},
432};
433
434static const struct hdmi_preset_conf hdmi_conf_720p60 = {
435	.core = {
436		.h_blank = {0x72, 0x01},
437		.v_blank = {0xee, 0xf2, 0x00},
438		.h_v_line = {0xee, 0x22, 0x67},
439		.vsync_pol = {0x00},
440		.int_pro_mode = {0x00},
441		.v_blank_f = {0x00, 0x00, 0x00}, /* don't care */
442		.h_sync_gen = {0x6c, 0x50, 0x02},
443		.v_sync_gen1 = {0x0a, 0x50, 0x00},
444		/* other don't care */
445	},
446	.tg = {
447		0x00, /* cmd */
448		0x72, 0x06, /* h_fsz */
449		0x72, 0x01, 0x00, 0x05, /* hact */
450		0xee, 0x02, /* v_fsz */
451		0x01, 0x00, 0x33, 0x02, /* vsync */
452		0x1e, 0x00, 0xd0, 0x02, /* vact */
453		0x33, 0x02, /* field_chg */
454		0x49, 0x02, /* vact_st2 */
455		0x01, 0x00, 0x33, 0x02, /* vsync top/bot */
456		0x01, 0x00, 0x33, 0x02, /* field top/bot */
457	},
458	.mbus_fmt = {
459		.width = 1280,
460		.height = 720,
461		.code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
462		.field = V4L2_FIELD_NONE,
463		.colorspace = V4L2_COLORSPACE_SRGB,
464	},
465};
466
467static const struct hdmi_preset_conf hdmi_conf_1080p50 = {
468	.core = {
469		.h_blank = {0xd0, 0x02},
470		.v_blank = {0x65, 0x6c, 0x01},
471		.h_v_line = {0x65, 0x04, 0xa5},
472		.vsync_pol = {0x00},
473		.int_pro_mode = {0x00},
474		.v_blank_f = {0x00, 0x00, 0x00}, /* don't care */
475		.h_sync_gen = {0x0e, 0xea, 0x08},
476		.v_sync_gen1 = {0x09, 0x40, 0x00},
477		/* other don't care */
478	},
479	.tg = {
480		0x00, /* cmd */
481		0x98, 0x08, /* h_fsz */
482		0x18, 0x01, 0x80, 0x07, /* hact */
483		0x65, 0x04, /* v_fsz */
484		0x01, 0x00, 0x33, 0x02, /* vsync */
485		0x2d, 0x00, 0x38, 0x04, /* vact */
486		0x33, 0x02, /* field_chg */
487		0x49, 0x02, /* vact_st2 */
488		0x01, 0x00, 0x33, 0x02, /* vsync top/bot */
489		0x01, 0x00, 0x33, 0x02, /* field top/bot */
490	},
491	.mbus_fmt = {
492		.width = 1920,
493		.height = 1080,
494		.code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
495		.field = V4L2_FIELD_NONE,
496		.colorspace = V4L2_COLORSPACE_SRGB,
497	},
498};
499
500static const struct hdmi_preset_conf hdmi_conf_1080p60 = {
501	.core = {
502		.h_blank = {0x18, 0x01},
503		.v_blank = {0x65, 0x6c, 0x01},
504		.h_v_line = {0x65, 0x84, 0x89},
505		.vsync_pol = {0x00},
506		.int_pro_mode = {0x00},
507		.v_blank_f = {0x00, 0x00, 0x00}, /* don't care */
508		.h_sync_gen = {0x56, 0x08, 0x02},
509		.v_sync_gen1 = {0x09, 0x40, 0x00},
510		/* other don't care */
511	},
512	.tg = {
513		0x00, /* cmd */
514		0x98, 0x08, /* h_fsz */
515		0x18, 0x01, 0x80, 0x07, /* hact */
516		0x65, 0x04, /* v_fsz */
517		0x01, 0x00, 0x33, 0x02, /* vsync */
518		0x2d, 0x00, 0x38, 0x04, /* vact */
519		0x33, 0x02, /* field_chg */
520		0x48, 0x02, /* vact_st2 */
521		0x01, 0x00, 0x01, 0x00, /* vsync top/bot */
522		0x01, 0x00, 0x33, 0x02, /* field top/bot */
523	},
524	.mbus_fmt = {
525		.width = 1920,
526		.height = 1080,
527		.code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
528		.field = V4L2_FIELD_NONE,
529		.colorspace = V4L2_COLORSPACE_SRGB,
530	},
531};
532
533static const struct {
534	u32 preset;
535	const struct hdmi_preset_conf *conf;
536} hdmi_conf[] = {
537	{ V4L2_DV_480P59_94, &hdmi_conf_480p },
538	{ V4L2_DV_720P59_94, &hdmi_conf_720p60 },
539	{ V4L2_DV_1080P50, &hdmi_conf_1080p50 },
540	{ V4L2_DV_1080P30, &hdmi_conf_1080p60 },
541	{ V4L2_DV_1080P60, &hdmi_conf_1080p60 },
542};
543
544static const struct hdmi_preset_conf *hdmi_preset2conf(u32 preset)
545{
546	int i;
547
548	for (i = 0; i < ARRAY_SIZE(hdmi_conf); ++i)
549		if (hdmi_conf[i].preset == preset)
550			return  hdmi_conf[i].conf;
551	return NULL;
552}
553
554static int hdmi_streamon(struct hdmi_device *hdev)
555{
556	struct device *dev = hdev->dev;
557	struct hdmi_resources *res = &hdev->res;
558	int ret, tries;
559
560	dev_dbg(dev, "%s\n", __func__);
561
562	ret = v4l2_subdev_call(hdev->phy_sd, video, s_stream, 1);
563	if (ret)
564		return ret;
565
566	/* waiting for HDMIPHY's PLL to get to steady state */
567	for (tries = 100; tries; --tries) {
568		u32 val = hdmi_read(hdev, HDMI_PHY_STATUS);
569		if (val & HDMI_PHY_STATUS_READY)
570			break;
571		mdelay(1);
572	}
573	/* steady state not achieved */
574	if (tries == 0) {
575		dev_err(dev, "hdmiphy's pll could not reach steady state.\n");
576		v4l2_subdev_call(hdev->phy_sd, video, s_stream, 0);
577		hdmi_dumpregs(hdev, "hdmiphy - s_stream");
578		return -EIO;
579	}
580
581	/* starting MHL */
582	ret = v4l2_subdev_call(hdev->mhl_sd, video, s_stream, 1);
583	if (hdev->mhl_sd && ret) {
584		v4l2_subdev_call(hdev->phy_sd, video, s_stream, 0);
585		hdmi_dumpregs(hdev, "mhl - s_stream");
586		return -EIO;
587	}
588
589	/* hdmiphy clock is used for HDMI in streaming mode */
590	clk_disable(res->sclk_hdmi);
591	clk_set_parent(res->sclk_hdmi, res->sclk_hdmiphy);
592	clk_enable(res->sclk_hdmi);
593
594	/* enable HDMI and timing generator */
595	hdmi_write_mask(hdev, HDMI_CON_0, ~0, HDMI_EN);
596	hdmi_write_mask(hdev, HDMI_TG_CMD, ~0, HDMI_TG_EN);
597	hdmi_dumpregs(hdev, "streamon");
598	return 0;
599}
600
601static int hdmi_streamoff(struct hdmi_device *hdev)
602{
603	struct device *dev = hdev->dev;
604	struct hdmi_resources *res = &hdev->res;
605
606	dev_dbg(dev, "%s\n", __func__);
607
608	hdmi_write_mask(hdev, HDMI_CON_0, 0, HDMI_EN);
609	hdmi_write_mask(hdev, HDMI_TG_CMD, 0, HDMI_TG_EN);
610
611	/* pixel(vpll) clock is used for HDMI in config mode */
612	clk_disable(res->sclk_hdmi);
613	clk_set_parent(res->sclk_hdmi, res->sclk_pixel);
614	clk_enable(res->sclk_hdmi);
615
616	v4l2_subdev_call(hdev->mhl_sd, video, s_stream, 0);
617	v4l2_subdev_call(hdev->phy_sd, video, s_stream, 0);
618
619	hdmi_dumpregs(hdev, "streamoff");
620	return 0;
621}
622
623static int hdmi_s_stream(struct v4l2_subdev *sd, int enable)
624{
625	struct hdmi_device *hdev = sd_to_hdmi_dev(sd);
626	struct device *dev = hdev->dev;
627
628	dev_dbg(dev, "%s(%d)\n", __func__, enable);
629	if (enable)
630		return hdmi_streamon(hdev);
631	return hdmi_streamoff(hdev);
632}
633
634static void hdmi_resource_poweron(struct hdmi_resources *res)
635{
636	/* turn HDMI power on */
637	regulator_bulk_enable(res->regul_count, res->regul_bulk);
638	/* power-on hdmi physical interface */
639	clk_enable(res->hdmiphy);
640	/* use VPP as parent clock; HDMIPHY is not working yet */
641	clk_set_parent(res->sclk_hdmi, res->sclk_pixel);
642	/* turn clocks on */
643	clk_enable(res->sclk_hdmi);
644}
645
646static void hdmi_resource_poweroff(struct hdmi_resources *res)
647{
648	/* turn clocks off */
649	clk_disable(res->sclk_hdmi);
650	/* power-off hdmiphy */
651	clk_disable(res->hdmiphy);
652	/* turn HDMI power off */
653	regulator_bulk_disable(res->regul_count, res->regul_bulk);
654}
655
656static int hdmi_s_power(struct v4l2_subdev *sd, int on)
657{
658	struct hdmi_device *hdev = sd_to_hdmi_dev(sd);
659	int ret;
660
661	if (on)
662		ret = pm_runtime_get_sync(hdev->dev);
663	else
664		ret = pm_runtime_put_sync(hdev->dev);
665	/* only values < 0 indicate errors */
666	return IS_ERR_VALUE(ret) ? ret : 0;
667}
668
669static int hdmi_s_dv_preset(struct v4l2_subdev *sd,
670	struct v4l2_dv_preset *preset)
671{
672	struct hdmi_device *hdev = sd_to_hdmi_dev(sd);
673	struct device *dev = hdev->dev;
674	const struct hdmi_preset_conf *conf;
675
676	conf = hdmi_preset2conf(preset->preset);
677	if (conf == NULL) {
678		dev_err(dev, "preset (%u) not supported\n", preset->preset);
679		return -EINVAL;
680	}
681	hdev->cur_conf = conf;
682	hdev->cur_preset = preset->preset;
683	return 0;
684}
685
686static int hdmi_g_dv_preset(struct v4l2_subdev *sd,
687	struct v4l2_dv_preset *preset)
688{
689	memset(preset, 0, sizeof(*preset));
690	preset->preset = sd_to_hdmi_dev(sd)->cur_preset;
691	return 0;
692}
693
694static int hdmi_g_mbus_fmt(struct v4l2_subdev *sd,
695	  struct v4l2_mbus_framefmt *fmt)
696{
697	struct hdmi_device *hdev = sd_to_hdmi_dev(sd);
698	struct device *dev = hdev->dev;
699
700	dev_dbg(dev, "%s\n", __func__);
701	if (!hdev->cur_conf)
702		return -EINVAL;
703	*fmt = hdev->cur_conf->mbus_fmt;
704	return 0;
705}
706
707static int hdmi_enum_dv_presets(struct v4l2_subdev *sd,
708	struct v4l2_dv_enum_preset *preset)
709{
710	if (preset->index >= ARRAY_SIZE(hdmi_conf))
711		return -EINVAL;
712	return v4l_fill_dv_preset_info(hdmi_conf[preset->index].preset, preset);
713}
714
715static const struct v4l2_subdev_core_ops hdmi_sd_core_ops = {
716	.s_power = hdmi_s_power,
717};
718
719static const struct v4l2_subdev_video_ops hdmi_sd_video_ops = {
720	.s_dv_preset = hdmi_s_dv_preset,
721	.g_dv_preset = hdmi_g_dv_preset,
722	.enum_dv_presets = hdmi_enum_dv_presets,
723	.g_mbus_fmt = hdmi_g_mbus_fmt,
724	.s_stream = hdmi_s_stream,
725};
726
727static const struct v4l2_subdev_ops hdmi_sd_ops = {
728	.core = &hdmi_sd_core_ops,
729	.video = &hdmi_sd_video_ops,
730};
731
732static int hdmi_runtime_suspend(struct device *dev)
733{
734	struct v4l2_subdev *sd = dev_get_drvdata(dev);
735	struct hdmi_device *hdev = sd_to_hdmi_dev(sd);
736
737	dev_dbg(dev, "%s\n", __func__);
738	v4l2_subdev_call(hdev->mhl_sd, core, s_power, 0);
739	hdmi_resource_poweroff(&hdev->res);
740	return 0;
741}
742
743static int hdmi_runtime_resume(struct device *dev)
744{
745	struct v4l2_subdev *sd = dev_get_drvdata(dev);
746	struct hdmi_device *hdev = sd_to_hdmi_dev(sd);
747	int ret = 0;
748
749	dev_dbg(dev, "%s\n", __func__);
750
751	hdmi_resource_poweron(&hdev->res);
752
753	ret = hdmi_conf_apply(hdev);
754	if (ret)
755		goto fail;
756
757	/* starting MHL */
758	ret = v4l2_subdev_call(hdev->mhl_sd, core, s_power, 1);
759	if (hdev->mhl_sd && ret)
760		goto fail;
761
762	dev_dbg(dev, "poweron succeed\n");
763
764	return 0;
765
766fail:
767	hdmi_resource_poweroff(&hdev->res);
768	dev_err(dev, "poweron failed\n");
769
770	return ret;
771}
772
773static const struct dev_pm_ops hdmi_pm_ops = {
774	.runtime_suspend = hdmi_runtime_suspend,
775	.runtime_resume	 = hdmi_runtime_resume,
776};
777
778static void hdmi_resources_cleanup(struct hdmi_device *hdev)
779{
780	struct hdmi_resources *res = &hdev->res;
781
782	dev_dbg(hdev->dev, "HDMI resource cleanup\n");
783	/* put clocks, power */
784	if (res->regul_count)
785		regulator_bulk_free(res->regul_count, res->regul_bulk);
786	/* kfree is NULL-safe */
787	kfree(res->regul_bulk);
788	if (!IS_ERR_OR_NULL(res->hdmiphy))
789		clk_put(res->hdmiphy);
790	if (!IS_ERR_OR_NULL(res->sclk_hdmiphy))
791		clk_put(res->sclk_hdmiphy);
792	if (!IS_ERR_OR_NULL(res->sclk_pixel))
793		clk_put(res->sclk_pixel);
794	if (!IS_ERR_OR_NULL(res->sclk_hdmi))
795		clk_put(res->sclk_hdmi);
796	if (!IS_ERR_OR_NULL(res->hdmi))
797		clk_put(res->hdmi);
798	memset(res, 0, sizeof *res);
799}
800
801static int hdmi_resources_init(struct hdmi_device *hdev)
802{
803	struct device *dev = hdev->dev;
804	struct hdmi_resources *res = &hdev->res;
805	static char *supply[] = {
806		"hdmi-en",
807		"vdd",
808		"vdd_osc",
809		"vdd_pll",
810	};
811	int i, ret;
812
813	dev_dbg(dev, "HDMI resource init\n");
814
815	memset(res, 0, sizeof *res);
816	/* get clocks, power */
817
818	res->hdmi = clk_get(dev, "hdmi");
819	if (IS_ERR_OR_NULL(res->hdmi)) {
820		dev_err(dev, "failed to get clock 'hdmi'\n");
821		goto fail;
822	}
823	res->sclk_hdmi = clk_get(dev, "sclk_hdmi");
824	if (IS_ERR_OR_NULL(res->sclk_hdmi)) {
825		dev_err(dev, "failed to get clock 'sclk_hdmi'\n");
826		goto fail;
827	}
828	res->sclk_pixel = clk_get(dev, "sclk_pixel");
829	if (IS_ERR_OR_NULL(res->sclk_pixel)) {
830		dev_err(dev, "failed to get clock 'sclk_pixel'\n");
831		goto fail;
832	}
833	res->sclk_hdmiphy = clk_get(dev, "sclk_hdmiphy");
834	if (IS_ERR_OR_NULL(res->sclk_hdmiphy)) {
835		dev_err(dev, "failed to get clock 'sclk_hdmiphy'\n");
836		goto fail;
837	}
838	res->hdmiphy = clk_get(dev, "hdmiphy");
839	if (IS_ERR_OR_NULL(res->hdmiphy)) {
840		dev_err(dev, "failed to get clock 'hdmiphy'\n");
841		goto fail;
842	}
843	res->regul_bulk = kcalloc(ARRAY_SIZE(supply),
844				  sizeof(res->regul_bulk[0]), GFP_KERNEL);
845	if (!res->regul_bulk) {
846		dev_err(dev, "failed to get memory for regulators\n");
847		goto fail;
848	}
849	for (i = 0; i < ARRAY_SIZE(supply); ++i) {
850		res->regul_bulk[i].supply = supply[i];
851		res->regul_bulk[i].consumer = NULL;
852	}
853
854	ret = regulator_bulk_get(dev, ARRAY_SIZE(supply), res->regul_bulk);
855	if (ret) {
856		dev_err(dev, "failed to get regulators\n");
857		goto fail;
858	}
859	res->regul_count = ARRAY_SIZE(supply);
860
861	return 0;
862fail:
863	dev_err(dev, "HDMI resource init - failed\n");
864	hdmi_resources_cleanup(hdev);
865	return -ENODEV;
866}
867
868static int __devinit hdmi_probe(struct platform_device *pdev)
869{
870	struct device *dev = &pdev->dev;
871	struct resource *res;
872	struct i2c_adapter *adapter;
873	struct v4l2_subdev *sd;
874	struct hdmi_device *hdmi_dev = NULL;
875	struct s5p_hdmi_platform_data *pdata = dev->platform_data;
876	int ret;
877
878	dev_dbg(dev, "probe start\n");
879
880	if (!pdata) {
881		dev_err(dev, "platform data is missing\n");
882		ret = -ENODEV;
883		goto fail;
884	}
885
886	hdmi_dev = devm_kzalloc(&pdev->dev, sizeof(*hdmi_dev), GFP_KERNEL);
887	if (!hdmi_dev) {
888		dev_err(dev, "out of memory\n");
889		ret = -ENOMEM;
890		goto fail;
891	}
892
893	hdmi_dev->dev = dev;
894
895	ret = hdmi_resources_init(hdmi_dev);
896	if (ret)
897		goto fail;
898
899	/* mapping HDMI registers */
900	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
901	if (res == NULL) {
902		dev_err(dev, "get memory resource failed.\n");
903		ret = -ENXIO;
904		goto fail_init;
905	}
906
907	hdmi_dev->regs = devm_ioremap(&pdev->dev, res->start,
908				      resource_size(res));
909	if (hdmi_dev->regs == NULL) {
910		dev_err(dev, "register mapping failed.\n");
911		ret = -ENXIO;
912		goto fail_init;
913	}
914
915	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
916	if (res == NULL) {
917		dev_err(dev, "get interrupt resource failed.\n");
918		ret = -ENXIO;
919		goto fail_init;
920	}
921
922	ret = devm_request_irq(&pdev->dev, res->start, hdmi_irq_handler, 0,
923			       "hdmi", hdmi_dev);
924	if (ret) {
925		dev_err(dev, "request interrupt failed.\n");
926		goto fail_init;
927	}
928	hdmi_dev->irq = res->start;
929
930	/* setting v4l2 name to prevent WARN_ON in v4l2_device_register */
931	strlcpy(hdmi_dev->v4l2_dev.name, dev_name(dev),
932		sizeof(hdmi_dev->v4l2_dev.name));
933	/* passing NULL owner prevents driver from erasing drvdata */
934	ret = v4l2_device_register(NULL, &hdmi_dev->v4l2_dev);
935	if (ret) {
936		dev_err(dev, "could not register v4l2 device.\n");
937		goto fail_init;
938	}
939
940	/* testing if hdmiphy info is present */
941	if (!pdata->hdmiphy_info) {
942		dev_err(dev, "hdmiphy info is missing in platform data\n");
943		ret = -ENXIO;
944		goto fail_vdev;
945	}
946
947	adapter = i2c_get_adapter(pdata->hdmiphy_bus);
948	if (adapter == NULL) {
949		dev_err(dev, "hdmiphy adapter request failed\n");
950		ret = -ENXIO;
951		goto fail_vdev;
952	}
953
954	hdmi_dev->phy_sd = v4l2_i2c_new_subdev_board(&hdmi_dev->v4l2_dev,
955		adapter, pdata->hdmiphy_info, NULL);
956	/* on failure or not adapter is no longer useful */
957	i2c_put_adapter(adapter);
958	if (hdmi_dev->phy_sd == NULL) {
959		dev_err(dev, "missing subdev for hdmiphy\n");
960		ret = -ENODEV;
961		goto fail_vdev;
962	}
963
964	/* initialization of MHL interface if present */
965	if (pdata->mhl_info) {
966		adapter = i2c_get_adapter(pdata->mhl_bus);
967		if (adapter == NULL) {
968			dev_err(dev, "MHL adapter request failed\n");
969			ret = -ENXIO;
970			goto fail_vdev;
971		}
972
973		hdmi_dev->mhl_sd = v4l2_i2c_new_subdev_board(
974			&hdmi_dev->v4l2_dev, adapter,
975			pdata->mhl_info, NULL);
976		/* on failure or not adapter is no longer useful */
977		i2c_put_adapter(adapter);
978		if (hdmi_dev->mhl_sd == NULL) {
979			dev_err(dev, "missing subdev for MHL\n");
980			ret = -ENODEV;
981			goto fail_vdev;
982		}
983	}
984
985	clk_enable(hdmi_dev->res.hdmi);
986
987	pm_runtime_enable(dev);
988
989	sd = &hdmi_dev->sd;
990	v4l2_subdev_init(sd, &hdmi_sd_ops);
991	sd->owner = THIS_MODULE;
992
993	strlcpy(sd->name, "s5p-hdmi", sizeof sd->name);
994	hdmi_dev->cur_preset = HDMI_DEFAULT_PRESET;
995	/* FIXME: missing fail preset is not supported */
996	hdmi_dev->cur_conf = hdmi_preset2conf(hdmi_dev->cur_preset);
997
998	/* storing subdev for call that have only access to struct device */
999	dev_set_drvdata(dev, sd);
1000
1001	dev_info(dev, "probe successful\n");
1002
1003	return 0;
1004
1005fail_vdev:
1006	v4l2_device_unregister(&hdmi_dev->v4l2_dev);
1007
1008fail_init:
1009	hdmi_resources_cleanup(hdmi_dev);
1010
1011fail:
1012	dev_err(dev, "probe failed\n");
1013	return ret;
1014}
1015
1016static int __devexit hdmi_remove(struct platform_device *pdev)
1017{
1018	struct device *dev = &pdev->dev;
1019	struct v4l2_subdev *sd = dev_get_drvdata(dev);
1020	struct hdmi_device *hdmi_dev = sd_to_hdmi_dev(sd);
1021
1022	pm_runtime_disable(dev);
1023	clk_disable(hdmi_dev->res.hdmi);
1024	v4l2_device_unregister(&hdmi_dev->v4l2_dev);
1025	disable_irq(hdmi_dev->irq);
1026	hdmi_resources_cleanup(hdmi_dev);
1027	dev_info(dev, "remove successful\n");
1028
1029	return 0;
1030}
1031
1032static struct platform_driver hdmi_driver __refdata = {
1033	.probe = hdmi_probe,
1034	.remove = __devexit_p(hdmi_remove),
1035	.id_table = hdmi_driver_types,
1036	.driver = {
1037		.name = "s5p-hdmi",
1038		.owner = THIS_MODULE,
1039		.pm = &hdmi_pm_ops,
1040	}
1041};
1042
1043module_platform_driver(hdmi_driver);
1044