aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/s5p-tv
diff options
context:
space:
mode:
authorJonathan Herman <hermanjl@cs.unc.edu>2013-01-22 10:38:37 -0500
committerJonathan Herman <hermanjl@cs.unc.edu>2013-01-22 10:38:37 -0500
commitfcc9d2e5a6c89d22b8b773a64fb4ad21ac318446 (patch)
treea57612d1888735a2ec7972891b68c1ac5ec8faea /drivers/media/video/s5p-tv
parent8dea78da5cee153b8af9c07a2745f6c55057fe12 (diff)
Added missing tegra files.HEADmaster
Diffstat (limited to 'drivers/media/video/s5p-tv')
-rw-r--r--drivers/media/video/s5p-tv/Kconfig76
-rw-r--r--drivers/media/video/s5p-tv/Makefile17
-rw-r--r--drivers/media/video/s5p-tv/hdmi_drv.c1042
-rw-r--r--drivers/media/video/s5p-tv/hdmiphy_drv.c188
-rw-r--r--drivers/media/video/s5p-tv/mixer.h354
-rw-r--r--drivers/media/video/s5p-tv/mixer_drv.c487
-rw-r--r--drivers/media/video/s5p-tv/mixer_grp_layer.c185
-rw-r--r--drivers/media/video/s5p-tv/mixer_reg.c541
-rw-r--r--drivers/media/video/s5p-tv/mixer_video.c1006
-rw-r--r--drivers/media/video/s5p-tv/mixer_vp_layer.c211
-rw-r--r--drivers/media/video/s5p-tv/regs-hdmi.h141
-rw-r--r--drivers/media/video/s5p-tv/regs-mixer.h121
-rw-r--r--drivers/media/video/s5p-tv/regs-sdo.h63
-rw-r--r--drivers/media/video/s5p-tv/regs-vp.h88
-rw-r--r--drivers/media/video/s5p-tv/sdo_drv.c479
15 files changed, 4999 insertions, 0 deletions
diff --git a/drivers/media/video/s5p-tv/Kconfig b/drivers/media/video/s5p-tv/Kconfig
new file mode 100644
index 00000000000..9c37dee7bc5
--- /dev/null
+++ b/drivers/media/video/s5p-tv/Kconfig
@@ -0,0 +1,76 @@
1# drivers/media/video/s5p-tv/Kconfig
2#
3# Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
4# http://www.samsung.com/
5# Tomasz Stanislawski <t.stanislaws@samsung.com>
6#
7# Licensed under GPL
8
9config VIDEO_SAMSUNG_S5P_TV
10 bool "Samsung TV driver for S5P platform (experimental)"
11 depends on PLAT_S5P
12 depends on EXPERIMENTAL
13 default n
14 ---help---
15 Say Y here to enable selecting the TV output devices for
16 Samsung S5P platform.
17
18if VIDEO_SAMSUNG_S5P_TV
19
20config VIDEO_SAMSUNG_S5P_HDMI
21 tristate "Samsung HDMI Driver"
22 depends on VIDEO_V4L2
23 depends on VIDEO_SAMSUNG_S5P_TV
24 select VIDEO_SAMSUNG_S5P_HDMIPHY
25 help
26 Say Y here if you want support for the HDMI output
27 interface in S5P Samsung SoC. The driver can be compiled
28 as module. It is an auxiliary driver, that exposes a V4L2
29 subdev for use by other drivers. This driver requires
30 hdmiphy driver to work correctly.
31
32config VIDEO_SAMSUNG_S5P_HDMI_DEBUG
33 bool "Enable debug for HDMI Driver"
34 depends on VIDEO_SAMSUNG_S5P_HDMI
35 default n
36 help
37 Enables debugging for HDMI driver.
38
39config VIDEO_SAMSUNG_S5P_HDMIPHY
40 tristate "Samsung HDMIPHY Driver"
41 depends on VIDEO_DEV && VIDEO_V4L2 && I2C
42 depends on VIDEO_SAMSUNG_S5P_TV
43 help
44 Say Y here if you want support for the physical HDMI
45 interface in S5P Samsung SoC. The driver can be compiled
46 as module. It is an I2C driver, that exposes a V4L2
47 subdev for use by other drivers.
48
49config VIDEO_SAMSUNG_S5P_SDO
50 tristate "Samsung Analog TV Driver"
51 depends on VIDEO_DEV && VIDEO_V4L2
52 depends on VIDEO_SAMSUNG_S5P_TV
53 help
54 Say Y here if you want support for the analog TV output
55 interface in S5P Samsung SoC. The driver can be compiled
56 as module. It is an auxiliary driver, that exposes a V4L2
57 subdev for use by other drivers. This driver requires
58 hdmiphy driver to work correctly.
59
60config VIDEO_SAMSUNG_S5P_MIXER
61 tristate "Samsung Mixer and Video Processor Driver"
62 depends on VIDEO_DEV && VIDEO_V4L2
63 depends on VIDEO_SAMSUNG_S5P_TV
64 select VIDEOBUF2_DMA_CONTIG
65 help
66 Say Y here if you want support for the Mixer in Samsung S5P SoCs.
67 This device produce image data to one of output interfaces.
68
69config VIDEO_SAMSUNG_S5P_MIXER_DEBUG
70 bool "Enable debug for Mixer Driver"
71 depends on VIDEO_SAMSUNG_S5P_MIXER
72 default n
73 help
74 Enables debugging for Mixer driver.
75
76endif # VIDEO_SAMSUNG_S5P_TV
diff --git a/drivers/media/video/s5p-tv/Makefile b/drivers/media/video/s5p-tv/Makefile
new file mode 100644
index 00000000000..37e4c17663b
--- /dev/null
+++ b/drivers/media/video/s5p-tv/Makefile
@@ -0,0 +1,17 @@
1# drivers/media/video/samsung/tvout/Makefile
2#
3# Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
4# http://www.samsung.com/
5# Tomasz Stanislawski <t.stanislaws@samsung.com>
6#
7# Licensed under GPL
8
9obj-$(CONFIG_VIDEO_SAMSUNG_S5P_HDMIPHY) += s5p-hdmiphy.o
10s5p-hdmiphy-y += hdmiphy_drv.o
11obj-$(CONFIG_VIDEO_SAMSUNG_S5P_HDMI) += s5p-hdmi.o
12s5p-hdmi-y += hdmi_drv.o
13obj-$(CONFIG_VIDEO_SAMSUNG_S5P_SDO) += s5p-sdo.o
14s5p-sdo-y += sdo_drv.o
15obj-$(CONFIG_VIDEO_SAMSUNG_S5P_MIXER) += s5p-mixer.o
16s5p-mixer-y += mixer_drv.o mixer_video.o mixer_reg.o mixer_grp_layer.o mixer_vp_layer.o
17
diff --git a/drivers/media/video/s5p-tv/hdmi_drv.c b/drivers/media/video/s5p-tv/hdmi_drv.c
new file mode 100644
index 00000000000..06d6663f459
--- /dev/null
+++ b/drivers/media/video/s5p-tv/hdmi_drv.c
@@ -0,0 +1,1042 @@
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/v4l2-common.h>
34#include <media/v4l2-dev.h>
35#include <media/v4l2-device.h>
36
37#include "regs-hdmi.h"
38
39MODULE_AUTHOR("Tomasz Stanislawski, <t.stanislaws@samsung.com>");
40MODULE_DESCRIPTION("Samsung HDMI");
41MODULE_LICENSE("GPL");
42
43/* default preset configured on probe */
44#define HDMI_DEFAULT_PRESET V4L2_DV_1080P60
45
46struct hdmi_resources {
47 struct clk *hdmi;
48 struct clk *sclk_hdmi;
49 struct clk *sclk_pixel;
50 struct clk *sclk_hdmiphy;
51 struct clk *hdmiphy;
52 struct regulator_bulk_data *regul_bulk;
53 int regul_count;
54};
55
56struct hdmi_device {
57 /** base address of HDMI registers */
58 void __iomem *regs;
59 /** HDMI interrupt */
60 unsigned int irq;
61 /** pointer to device parent */
62 struct device *dev;
63 /** subdev generated by HDMI device */
64 struct v4l2_subdev sd;
65 /** V4L2 device structure */
66 struct v4l2_device v4l2_dev;
67 /** subdev of HDMIPHY interface */
68 struct v4l2_subdev *phy_sd;
69 /** configuration of current graphic mode */
70 const struct hdmi_preset_conf *cur_conf;
71 /** current preset */
72 u32 cur_preset;
73 /** other resources */
74 struct hdmi_resources res;
75};
76
77struct hdmi_driver_data {
78 int hdmiphy_bus;
79};
80
81struct hdmi_tg_regs {
82 u8 cmd;
83 u8 h_fsz_l;
84 u8 h_fsz_h;
85 u8 hact_st_l;
86 u8 hact_st_h;
87 u8 hact_sz_l;
88 u8 hact_sz_h;
89 u8 v_fsz_l;
90 u8 v_fsz_h;
91 u8 vsync_l;
92 u8 vsync_h;
93 u8 vsync2_l;
94 u8 vsync2_h;
95 u8 vact_st_l;
96 u8 vact_st_h;
97 u8 vact_sz_l;
98 u8 vact_sz_h;
99 u8 field_chg_l;
100 u8 field_chg_h;
101 u8 vact_st2_l;
102 u8 vact_st2_h;
103 u8 vsync_top_hdmi_l;
104 u8 vsync_top_hdmi_h;
105 u8 vsync_bot_hdmi_l;
106 u8 vsync_bot_hdmi_h;
107 u8 field_top_hdmi_l;
108 u8 field_top_hdmi_h;
109 u8 field_bot_hdmi_l;
110 u8 field_bot_hdmi_h;
111};
112
113struct hdmi_core_regs {
114 u8 h_blank[2];
115 u8 v_blank[3];
116 u8 h_v_line[3];
117 u8 vsync_pol[1];
118 u8 int_pro_mode[1];
119 u8 v_blank_f[3];
120 u8 h_sync_gen[3];
121 u8 v_sync_gen1[3];
122 u8 v_sync_gen2[3];
123 u8 v_sync_gen3[3];
124};
125
126struct hdmi_preset_conf {
127 struct hdmi_core_regs core;
128 struct hdmi_tg_regs tg;
129 struct v4l2_mbus_framefmt mbus_fmt;
130};
131
132/* I2C module and id for HDMIPHY */
133static struct i2c_board_info hdmiphy_info = {
134 I2C_BOARD_INFO("hdmiphy", 0x38),
135};
136
137static struct hdmi_driver_data hdmi_driver_data[] = {
138 { .hdmiphy_bus = 3 },
139 { .hdmiphy_bus = 8 },
140};
141
142static struct platform_device_id hdmi_driver_types[] = {
143 {
144 .name = "s5pv210-hdmi",
145 .driver_data = (unsigned long)&hdmi_driver_data[0],
146 }, {
147 .name = "exynos4-hdmi",
148 .driver_data = (unsigned long)&hdmi_driver_data[1],
149 }, {
150 /* end node */
151 }
152};
153
154static const struct v4l2_subdev_ops hdmi_sd_ops;
155
156static struct hdmi_device *sd_to_hdmi_dev(struct v4l2_subdev *sd)
157{
158 return container_of(sd, struct hdmi_device, sd);
159}
160
161static inline
162void hdmi_write(struct hdmi_device *hdev, u32 reg_id, u32 value)
163{
164 writel(value, hdev->regs + reg_id);
165}
166
167static inline
168void hdmi_write_mask(struct hdmi_device *hdev, u32 reg_id, u32 value, u32 mask)
169{
170 u32 old = readl(hdev->regs + reg_id);
171 value = (value & mask) | (old & ~mask);
172 writel(value, hdev->regs + reg_id);
173}
174
175static inline
176void hdmi_writeb(struct hdmi_device *hdev, u32 reg_id, u8 value)
177{
178 writeb(value, hdev->regs + reg_id);
179}
180
181static inline u32 hdmi_read(struct hdmi_device *hdev, u32 reg_id)
182{
183 return readl(hdev->regs + reg_id);
184}
185
186static irqreturn_t hdmi_irq_handler(int irq, void *dev_data)
187{
188 struct hdmi_device *hdev = dev_data;
189 u32 intc_flag;
190
191 (void)irq;
192 intc_flag = hdmi_read(hdev, HDMI_INTC_FLAG);
193 /* clearing flags for HPD plug/unplug */
194 if (intc_flag & HDMI_INTC_FLAG_HPD_UNPLUG) {
195 printk(KERN_INFO "unplugged\n");
196 hdmi_write_mask(hdev, HDMI_INTC_FLAG, ~0,
197 HDMI_INTC_FLAG_HPD_UNPLUG);
198 }
199 if (intc_flag & HDMI_INTC_FLAG_HPD_PLUG) {
200 printk(KERN_INFO "plugged\n");
201 hdmi_write_mask(hdev, HDMI_INTC_FLAG, ~0,
202 HDMI_INTC_FLAG_HPD_PLUG);
203 }
204
205 return IRQ_HANDLED;
206}
207
208static void hdmi_reg_init(struct hdmi_device *hdev)
209{
210 /* enable HPD interrupts */
211 hdmi_write_mask(hdev, HDMI_INTC_CON, ~0, HDMI_INTC_EN_GLOBAL |
212 HDMI_INTC_EN_HPD_PLUG | HDMI_INTC_EN_HPD_UNPLUG);
213 /* choose HDMI mode */
214 hdmi_write_mask(hdev, HDMI_MODE_SEL,
215 HDMI_MODE_HDMI_EN, HDMI_MODE_MASK);
216 /* disable bluescreen */
217 hdmi_write_mask(hdev, HDMI_CON_0, 0, HDMI_BLUE_SCR_EN);
218 /* choose bluescreen (fecal) color */
219 hdmi_writeb(hdev, HDMI_BLUE_SCREEN_0, 0x12);
220 hdmi_writeb(hdev, HDMI_BLUE_SCREEN_1, 0x34);
221 hdmi_writeb(hdev, HDMI_BLUE_SCREEN_2, 0x56);
222 /* enable AVI packet every vsync, fixes purple line problem */
223 hdmi_writeb(hdev, HDMI_AVI_CON, 0x02);
224 /* force YUV444, look to CEA-861-D, table 7 for more detail */
225 hdmi_writeb(hdev, HDMI_AVI_BYTE(0), 2 << 5);
226 hdmi_write_mask(hdev, HDMI_CON_1, 2, 3 << 5);
227}
228
229static void hdmi_timing_apply(struct hdmi_device *hdev,
230 const struct hdmi_preset_conf *conf)
231{
232 const struct hdmi_core_regs *core = &conf->core;
233 const struct hdmi_tg_regs *tg = &conf->tg;
234
235 /* setting core registers */
236 hdmi_writeb(hdev, HDMI_H_BLANK_0, core->h_blank[0]);
237 hdmi_writeb(hdev, HDMI_H_BLANK_1, core->h_blank[1]);
238 hdmi_writeb(hdev, HDMI_V_BLANK_0, core->v_blank[0]);
239 hdmi_writeb(hdev, HDMI_V_BLANK_1, core->v_blank[1]);
240 hdmi_writeb(hdev, HDMI_V_BLANK_2, core->v_blank[2]);
241 hdmi_writeb(hdev, HDMI_H_V_LINE_0, core->h_v_line[0]);
242 hdmi_writeb(hdev, HDMI_H_V_LINE_1, core->h_v_line[1]);
243 hdmi_writeb(hdev, HDMI_H_V_LINE_2, core->h_v_line[2]);
244 hdmi_writeb(hdev, HDMI_VSYNC_POL, core->vsync_pol[0]);
245 hdmi_writeb(hdev, HDMI_INT_PRO_MODE, core->int_pro_mode[0]);
246 hdmi_writeb(hdev, HDMI_V_BLANK_F_0, core->v_blank_f[0]);
247 hdmi_writeb(hdev, HDMI_V_BLANK_F_1, core->v_blank_f[1]);
248 hdmi_writeb(hdev, HDMI_V_BLANK_F_2, core->v_blank_f[2]);
249 hdmi_writeb(hdev, HDMI_H_SYNC_GEN_0, core->h_sync_gen[0]);
250 hdmi_writeb(hdev, HDMI_H_SYNC_GEN_1, core->h_sync_gen[1]);
251 hdmi_writeb(hdev, HDMI_H_SYNC_GEN_2, core->h_sync_gen[2]);
252 hdmi_writeb(hdev, HDMI_V_SYNC_GEN_1_0, core->v_sync_gen1[0]);
253 hdmi_writeb(hdev, HDMI_V_SYNC_GEN_1_1, core->v_sync_gen1[1]);
254 hdmi_writeb(hdev, HDMI_V_SYNC_GEN_1_2, core->v_sync_gen1[2]);
255 hdmi_writeb(hdev, HDMI_V_SYNC_GEN_2_0, core->v_sync_gen2[0]);
256 hdmi_writeb(hdev, HDMI_V_SYNC_GEN_2_1, core->v_sync_gen2[1]);
257 hdmi_writeb(hdev, HDMI_V_SYNC_GEN_2_2, core->v_sync_gen2[2]);
258 hdmi_writeb(hdev, HDMI_V_SYNC_GEN_3_0, core->v_sync_gen3[0]);
259 hdmi_writeb(hdev, HDMI_V_SYNC_GEN_3_1, core->v_sync_gen3[1]);
260 hdmi_writeb(hdev, HDMI_V_SYNC_GEN_3_2, core->v_sync_gen3[2]);
261 /* Timing generator registers */
262 hdmi_writeb(hdev, HDMI_TG_H_FSZ_L, tg->h_fsz_l);
263 hdmi_writeb(hdev, HDMI_TG_H_FSZ_H, tg->h_fsz_h);
264 hdmi_writeb(hdev, HDMI_TG_HACT_ST_L, tg->hact_st_l);
265 hdmi_writeb(hdev, HDMI_TG_HACT_ST_H, tg->hact_st_h);
266 hdmi_writeb(hdev, HDMI_TG_HACT_SZ_L, tg->hact_sz_l);
267 hdmi_writeb(hdev, HDMI_TG_HACT_SZ_H, tg->hact_sz_h);
268 hdmi_writeb(hdev, HDMI_TG_V_FSZ_L, tg->v_fsz_l);
269 hdmi_writeb(hdev, HDMI_TG_V_FSZ_H, tg->v_fsz_h);
270 hdmi_writeb(hdev, HDMI_TG_VSYNC_L, tg->vsync_l);
271 hdmi_writeb(hdev, HDMI_TG_VSYNC_H, tg->vsync_h);
272 hdmi_writeb(hdev, HDMI_TG_VSYNC2_L, tg->vsync2_l);
273 hdmi_writeb(hdev, HDMI_TG_VSYNC2_H, tg->vsync2_h);
274 hdmi_writeb(hdev, HDMI_TG_VACT_ST_L, tg->vact_st_l);
275 hdmi_writeb(hdev, HDMI_TG_VACT_ST_H, tg->vact_st_h);
276 hdmi_writeb(hdev, HDMI_TG_VACT_SZ_L, tg->vact_sz_l);
277 hdmi_writeb(hdev, HDMI_TG_VACT_SZ_H, tg->vact_sz_h);
278 hdmi_writeb(hdev, HDMI_TG_FIELD_CHG_L, tg->field_chg_l);
279 hdmi_writeb(hdev, HDMI_TG_FIELD_CHG_H, tg->field_chg_h);
280 hdmi_writeb(hdev, HDMI_TG_VACT_ST2_L, tg->vact_st2_l);
281 hdmi_writeb(hdev, HDMI_TG_VACT_ST2_H, tg->vact_st2_h);
282 hdmi_writeb(hdev, HDMI_TG_VSYNC_TOP_HDMI_L, tg->vsync_top_hdmi_l);
283 hdmi_writeb(hdev, HDMI_TG_VSYNC_TOP_HDMI_H, tg->vsync_top_hdmi_h);
284 hdmi_writeb(hdev, HDMI_TG_VSYNC_BOT_HDMI_L, tg->vsync_bot_hdmi_l);
285 hdmi_writeb(hdev, HDMI_TG_VSYNC_BOT_HDMI_H, tg->vsync_bot_hdmi_h);
286 hdmi_writeb(hdev, HDMI_TG_FIELD_TOP_HDMI_L, tg->field_top_hdmi_l);
287 hdmi_writeb(hdev, HDMI_TG_FIELD_TOP_HDMI_H, tg->field_top_hdmi_h);
288 hdmi_writeb(hdev, HDMI_TG_FIELD_BOT_HDMI_L, tg->field_bot_hdmi_l);
289 hdmi_writeb(hdev, HDMI_TG_FIELD_BOT_HDMI_H, tg->field_bot_hdmi_h);
290}
291
292static int hdmi_conf_apply(struct hdmi_device *hdmi_dev)
293{
294 struct device *dev = hdmi_dev->dev;
295 const struct hdmi_preset_conf *conf = hdmi_dev->cur_conf;
296 struct v4l2_dv_preset preset;
297 int ret;
298
299 dev_dbg(dev, "%s\n", __func__);
300
301 /* reset hdmiphy */
302 hdmi_write_mask(hdmi_dev, HDMI_PHY_RSTOUT, ~0, HDMI_PHY_SW_RSTOUT);
303 mdelay(10);
304 hdmi_write_mask(hdmi_dev, HDMI_PHY_RSTOUT, 0, HDMI_PHY_SW_RSTOUT);
305 mdelay(10);
306
307 /* configure presets */
308 preset.preset = hdmi_dev->cur_preset;
309 ret = v4l2_subdev_call(hdmi_dev->phy_sd, video, s_dv_preset, &preset);
310 if (ret) {
311 dev_err(dev, "failed to set preset (%u)\n", preset.preset);
312 return ret;
313 }
314
315 /* resetting HDMI core */
316 hdmi_write_mask(hdmi_dev, HDMI_CORE_RSTOUT, 0, HDMI_CORE_SW_RSTOUT);
317 mdelay(10);
318 hdmi_write_mask(hdmi_dev, HDMI_CORE_RSTOUT, ~0, HDMI_CORE_SW_RSTOUT);
319 mdelay(10);
320
321 hdmi_reg_init(hdmi_dev);
322
323 /* setting core registers */
324 hdmi_timing_apply(hdmi_dev, conf);
325
326 return 0;
327}
328
329static void hdmi_dumpregs(struct hdmi_device *hdev, char *prefix)
330{
331#define DUMPREG(reg_id) \
332 dev_dbg(hdev->dev, "%s:" #reg_id " = %08x\n", prefix, \
333 readl(hdev->regs + reg_id))
334
335 dev_dbg(hdev->dev, "%s: ---- CONTROL REGISTERS ----\n", prefix);
336 DUMPREG(HDMI_INTC_FLAG);
337 DUMPREG(HDMI_INTC_CON);
338 DUMPREG(HDMI_HPD_STATUS);
339 DUMPREG(HDMI_PHY_RSTOUT);
340 DUMPREG(HDMI_PHY_VPLL);
341 DUMPREG(HDMI_PHY_CMU);
342 DUMPREG(HDMI_CORE_RSTOUT);
343
344 dev_dbg(hdev->dev, "%s: ---- CORE REGISTERS ----\n", prefix);
345 DUMPREG(HDMI_CON_0);
346 DUMPREG(HDMI_CON_1);
347 DUMPREG(HDMI_CON_2);
348 DUMPREG(HDMI_SYS_STATUS);
349 DUMPREG(HDMI_PHY_STATUS);
350 DUMPREG(HDMI_STATUS_EN);
351 DUMPREG(HDMI_HPD);
352 DUMPREG(HDMI_MODE_SEL);
353 DUMPREG(HDMI_HPD_GEN);
354 DUMPREG(HDMI_DC_CONTROL);
355 DUMPREG(HDMI_VIDEO_PATTERN_GEN);
356
357 dev_dbg(hdev->dev, "%s: ---- CORE SYNC REGISTERS ----\n", prefix);
358 DUMPREG(HDMI_H_BLANK_0);
359 DUMPREG(HDMI_H_BLANK_1);
360 DUMPREG(HDMI_V_BLANK_0);
361 DUMPREG(HDMI_V_BLANK_1);
362 DUMPREG(HDMI_V_BLANK_2);
363 DUMPREG(HDMI_H_V_LINE_0);
364 DUMPREG(HDMI_H_V_LINE_1);
365 DUMPREG(HDMI_H_V_LINE_2);
366 DUMPREG(HDMI_VSYNC_POL);
367 DUMPREG(HDMI_INT_PRO_MODE);
368 DUMPREG(HDMI_V_BLANK_F_0);
369 DUMPREG(HDMI_V_BLANK_F_1);
370 DUMPREG(HDMI_V_BLANK_F_2);
371 DUMPREG(HDMI_H_SYNC_GEN_0);
372 DUMPREG(HDMI_H_SYNC_GEN_1);
373 DUMPREG(HDMI_H_SYNC_GEN_2);
374 DUMPREG(HDMI_V_SYNC_GEN_1_0);
375 DUMPREG(HDMI_V_SYNC_GEN_1_1);
376 DUMPREG(HDMI_V_SYNC_GEN_1_2);
377 DUMPREG(HDMI_V_SYNC_GEN_2_0);
378 DUMPREG(HDMI_V_SYNC_GEN_2_1);
379 DUMPREG(HDMI_V_SYNC_GEN_2_2);
380 DUMPREG(HDMI_V_SYNC_GEN_3_0);
381 DUMPREG(HDMI_V_SYNC_GEN_3_1);
382 DUMPREG(HDMI_V_SYNC_GEN_3_2);
383
384 dev_dbg(hdev->dev, "%s: ---- TG REGISTERS ----\n", prefix);
385 DUMPREG(HDMI_TG_CMD);
386 DUMPREG(HDMI_TG_H_FSZ_L);
387 DUMPREG(HDMI_TG_H_FSZ_H);
388 DUMPREG(HDMI_TG_HACT_ST_L);
389 DUMPREG(HDMI_TG_HACT_ST_H);
390 DUMPREG(HDMI_TG_HACT_SZ_L);
391 DUMPREG(HDMI_TG_HACT_SZ_H);
392 DUMPREG(HDMI_TG_V_FSZ_L);
393 DUMPREG(HDMI_TG_V_FSZ_H);
394 DUMPREG(HDMI_TG_VSYNC_L);
395 DUMPREG(HDMI_TG_VSYNC_H);
396 DUMPREG(HDMI_TG_VSYNC2_L);
397 DUMPREG(HDMI_TG_VSYNC2_H);
398 DUMPREG(HDMI_TG_VACT_ST_L);
399 DUMPREG(HDMI_TG_VACT_ST_H);
400 DUMPREG(HDMI_TG_VACT_SZ_L);
401 DUMPREG(HDMI_TG_VACT_SZ_H);
402 DUMPREG(HDMI_TG_FIELD_CHG_L);
403 DUMPREG(HDMI_TG_FIELD_CHG_H);
404 DUMPREG(HDMI_TG_VACT_ST2_L);
405 DUMPREG(HDMI_TG_VACT_ST2_H);
406 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_L);
407 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_H);
408 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_L);
409 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_H);
410 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_L);
411 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_H);
412 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_L);
413 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_H);
414#undef DUMPREG
415}
416
417static const struct hdmi_preset_conf hdmi_conf_480p = {
418 .core = {
419 .h_blank = {0x8a, 0x00},
420 .v_blank = {0x0d, 0x6a, 0x01},
421 .h_v_line = {0x0d, 0xa2, 0x35},
422 .vsync_pol = {0x01},
423 .int_pro_mode = {0x00},
424 .v_blank_f = {0x00, 0x00, 0x00},
425 .h_sync_gen = {0x0e, 0x30, 0x11},
426 .v_sync_gen1 = {0x0f, 0x90, 0x00},
427 /* other don't care */
428 },
429 .tg = {
430 0x00, /* cmd */
431 0x5a, 0x03, /* h_fsz */
432 0x8a, 0x00, 0xd0, 0x02, /* hact */
433 0x0d, 0x02, /* v_fsz */
434 0x01, 0x00, 0x33, 0x02, /* vsync */
435 0x2d, 0x00, 0xe0, 0x01, /* vact */
436 0x33, 0x02, /* field_chg */
437 0x49, 0x02, /* vact_st2 */
438 0x01, 0x00, 0x33, 0x02, /* vsync top/bot */
439 0x01, 0x00, 0x33, 0x02, /* field top/bot */
440 },
441 .mbus_fmt = {
442 .width = 720,
443 .height = 480,
444 .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
445 .field = V4L2_FIELD_NONE,
446 },
447};
448
449static const struct hdmi_preset_conf hdmi_conf_720p60 = {
450 .core = {
451 .h_blank = {0x72, 0x01},
452 .v_blank = {0xee, 0xf2, 0x00},
453 .h_v_line = {0xee, 0x22, 0x67},
454 .vsync_pol = {0x00},
455 .int_pro_mode = {0x00},
456 .v_blank_f = {0x00, 0x00, 0x00}, /* don't care */
457 .h_sync_gen = {0x6c, 0x50, 0x02},
458 .v_sync_gen1 = {0x0a, 0x50, 0x00},
459 /* other don't care */
460 },
461 .tg = {
462 0x00, /* cmd */
463 0x72, 0x06, /* h_fsz */
464 0x72, 0x01, 0x00, 0x05, /* hact */
465 0xee, 0x02, /* v_fsz */
466 0x01, 0x00, 0x33, 0x02, /* vsync */
467 0x1e, 0x00, 0xd0, 0x02, /* vact */
468 0x33, 0x02, /* field_chg */
469 0x49, 0x02, /* vact_st2 */
470 0x01, 0x00, 0x33, 0x02, /* vsync top/bot */
471 0x01, 0x00, 0x33, 0x02, /* field top/bot */
472 },
473 .mbus_fmt = {
474 .width = 1280,
475 .height = 720,
476 .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
477 .field = V4L2_FIELD_NONE,
478 },
479};
480
481static const struct hdmi_preset_conf hdmi_conf_1080p50 = {
482 .core = {
483 .h_blank = {0xd0, 0x02},
484 .v_blank = {0x65, 0x6c, 0x01},
485 .h_v_line = {0x65, 0x04, 0xa5},
486 .vsync_pol = {0x00},
487 .int_pro_mode = {0x00},
488 .v_blank_f = {0x00, 0x00, 0x00}, /* don't care */
489 .h_sync_gen = {0x0e, 0xea, 0x08},
490 .v_sync_gen1 = {0x09, 0x40, 0x00},
491 /* other don't care */
492 },
493 .tg = {
494 0x00, /* cmd */
495 0x98, 0x08, /* h_fsz */
496 0x18, 0x01, 0x80, 0x07, /* hact */
497 0x65, 0x04, /* v_fsz */
498 0x01, 0x00, 0x33, 0x02, /* vsync */
499 0x2d, 0x00, 0x38, 0x04, /* vact */
500 0x33, 0x02, /* field_chg */
501 0x49, 0x02, /* vact_st2 */
502 0x01, 0x00, 0x33, 0x02, /* vsync top/bot */
503 0x01, 0x00, 0x33, 0x02, /* field top/bot */
504 },
505 .mbus_fmt = {
506 .width = 1920,
507 .height = 1080,
508 .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
509 .field = V4L2_FIELD_NONE,
510 },
511};
512
513static const struct hdmi_preset_conf hdmi_conf_1080p60 = {
514 .core = {
515 .h_blank = {0x18, 0x01},
516 .v_blank = {0x65, 0x6c, 0x01},
517 .h_v_line = {0x65, 0x84, 0x89},
518 .vsync_pol = {0x00},
519 .int_pro_mode = {0x00},
520 .v_blank_f = {0x00, 0x00, 0x00}, /* don't care */
521 .h_sync_gen = {0x56, 0x08, 0x02},
522 .v_sync_gen1 = {0x09, 0x40, 0x00},
523 /* other don't care */
524 },
525 .tg = {
526 0x00, /* cmd */
527 0x98, 0x08, /* h_fsz */
528 0x18, 0x01, 0x80, 0x07, /* hact */
529 0x65, 0x04, /* v_fsz */
530 0x01, 0x00, 0x33, 0x02, /* vsync */
531 0x2d, 0x00, 0x38, 0x04, /* vact */
532 0x33, 0x02, /* field_chg */
533 0x48, 0x02, /* vact_st2 */
534 0x01, 0x00, 0x01, 0x00, /* vsync top/bot */
535 0x01, 0x00, 0x33, 0x02, /* field top/bot */
536 },
537 .mbus_fmt = {
538 .width = 1920,
539 .height = 1080,
540 .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
541 .field = V4L2_FIELD_NONE,
542 },
543};
544
545static const struct {
546 u32 preset;
547 const struct hdmi_preset_conf *conf;
548} hdmi_conf[] = {
549 { V4L2_DV_480P59_94, &hdmi_conf_480p },
550 { V4L2_DV_720P59_94, &hdmi_conf_720p60 },
551 { V4L2_DV_1080P50, &hdmi_conf_1080p50 },
552 { V4L2_DV_1080P30, &hdmi_conf_1080p60 },
553 { V4L2_DV_1080P60, &hdmi_conf_1080p60 },
554};
555
556static const struct hdmi_preset_conf *hdmi_preset2conf(u32 preset)
557{
558 int i;
559
560 for (i = 0; i < ARRAY_SIZE(hdmi_conf); ++i)
561 if (hdmi_conf[i].preset == preset)
562 return hdmi_conf[i].conf;
563 return NULL;
564}
565
566static int hdmi_streamon(struct hdmi_device *hdev)
567{
568 struct device *dev = hdev->dev;
569 struct hdmi_resources *res = &hdev->res;
570 int ret, tries;
571
572 dev_dbg(dev, "%s\n", __func__);
573
574 ret = v4l2_subdev_call(hdev->phy_sd, video, s_stream, 1);
575 if (ret)
576 return ret;
577
578 /* waiting for HDMIPHY's PLL to get to steady state */
579 for (tries = 100; tries; --tries) {
580 u32 val = hdmi_read(hdev, HDMI_PHY_STATUS);
581 if (val & HDMI_PHY_STATUS_READY)
582 break;
583 mdelay(1);
584 }
585 /* steady state not achieved */
586 if (tries == 0) {
587 dev_err(dev, "hdmiphy's pll could not reach steady state.\n");
588 v4l2_subdev_call(hdev->phy_sd, video, s_stream, 0);
589 hdmi_dumpregs(hdev, "s_stream");
590 return -EIO;
591 }
592
593 /* hdmiphy clock is used for HDMI in streaming mode */
594 clk_disable(res->sclk_hdmi);
595 clk_set_parent(res->sclk_hdmi, res->sclk_hdmiphy);
596 clk_enable(res->sclk_hdmi);
597
598 /* enable HDMI and timing generator */
599 hdmi_write_mask(hdev, HDMI_CON_0, ~0, HDMI_EN);
600 hdmi_write_mask(hdev, HDMI_TG_CMD, ~0, HDMI_TG_EN);
601 hdmi_dumpregs(hdev, "streamon");
602 return 0;
603}
604
605static int hdmi_streamoff(struct hdmi_device *hdev)
606{
607 struct device *dev = hdev->dev;
608 struct hdmi_resources *res = &hdev->res;
609
610 dev_dbg(dev, "%s\n", __func__);
611
612 hdmi_write_mask(hdev, HDMI_CON_0, 0, HDMI_EN);
613 hdmi_write_mask(hdev, HDMI_TG_CMD, 0, HDMI_TG_EN);
614
615 /* pixel(vpll) clock is used for HDMI in config mode */
616 clk_disable(res->sclk_hdmi);
617 clk_set_parent(res->sclk_hdmi, res->sclk_pixel);
618 clk_enable(res->sclk_hdmi);
619
620 v4l2_subdev_call(hdev->phy_sd, video, s_stream, 0);
621
622 hdmi_dumpregs(hdev, "streamoff");
623 return 0;
624}
625
626static int hdmi_s_stream(struct v4l2_subdev *sd, int enable)
627{
628 struct hdmi_device *hdev = sd_to_hdmi_dev(sd);
629 struct device *dev = hdev->dev;
630
631 dev_dbg(dev, "%s(%d)\n", __func__, enable);
632 if (enable)
633 return hdmi_streamon(hdev);
634 return hdmi_streamoff(hdev);
635}
636
637static void hdmi_resource_poweron(struct hdmi_resources *res)
638{
639 /* turn HDMI power on */
640 regulator_bulk_enable(res->regul_count, res->regul_bulk);
641 /* power-on hdmi physical interface */
642 clk_enable(res->hdmiphy);
643 /* use VPP as parent clock; HDMIPHY is not working yet */
644 clk_set_parent(res->sclk_hdmi, res->sclk_pixel);
645 /* turn clocks on */
646 clk_enable(res->sclk_hdmi);
647}
648
649static void hdmi_resource_poweroff(struct hdmi_resources *res)
650{
651 /* turn clocks off */
652 clk_disable(res->sclk_hdmi);
653 /* power-off hdmiphy */
654 clk_disable(res->hdmiphy);
655 /* turn HDMI power off */
656 regulator_bulk_disable(res->regul_count, res->regul_bulk);
657}
658
659static int hdmi_s_power(struct v4l2_subdev *sd, int on)
660{
661 struct hdmi_device *hdev = sd_to_hdmi_dev(sd);
662 int ret;
663
664 if (on)
665 ret = pm_runtime_get_sync(hdev->dev);
666 else
667 ret = pm_runtime_put_sync(hdev->dev);
668 /* only values < 0 indicate errors */
669 return IS_ERR_VALUE(ret) ? ret : 0;
670}
671
672static int hdmi_s_dv_preset(struct v4l2_subdev *sd,
673 struct v4l2_dv_preset *preset)
674{
675 struct hdmi_device *hdev = sd_to_hdmi_dev(sd);
676 struct device *dev = hdev->dev;
677 const struct hdmi_preset_conf *conf;
678
679 conf = hdmi_preset2conf(preset->preset);
680 if (conf == NULL) {
681 dev_err(dev, "preset (%u) not supported\n", preset->preset);
682 return -EINVAL;
683 }
684 hdev->cur_conf = conf;
685 hdev->cur_preset = preset->preset;
686 return 0;
687}
688
689static int hdmi_g_dv_preset(struct v4l2_subdev *sd,
690 struct v4l2_dv_preset *preset)
691{
692 memset(preset, 0, sizeof(*preset));
693 preset->preset = sd_to_hdmi_dev(sd)->cur_preset;
694 return 0;
695}
696
697static int hdmi_g_mbus_fmt(struct v4l2_subdev *sd,
698 struct v4l2_mbus_framefmt *fmt)
699{
700 struct hdmi_device *hdev = sd_to_hdmi_dev(sd);
701 struct device *dev = hdev->dev;
702
703 dev_dbg(dev, "%s\n", __func__);
704 if (!hdev->cur_conf)
705 return -EINVAL;
706 *fmt = hdev->cur_conf->mbus_fmt;
707 return 0;
708}
709
710static int hdmi_enum_dv_presets(struct v4l2_subdev *sd,
711 struct v4l2_dv_enum_preset *preset)
712{
713 if (preset->index >= ARRAY_SIZE(hdmi_conf))
714 return -EINVAL;
715 return v4l_fill_dv_preset_info(hdmi_conf[preset->index].preset, preset);
716}
717
718static const struct v4l2_subdev_core_ops hdmi_sd_core_ops = {
719 .s_power = hdmi_s_power,
720};
721
722static const struct v4l2_subdev_video_ops hdmi_sd_video_ops = {
723 .s_dv_preset = hdmi_s_dv_preset,
724 .g_dv_preset = hdmi_g_dv_preset,
725 .enum_dv_presets = hdmi_enum_dv_presets,
726 .g_mbus_fmt = hdmi_g_mbus_fmt,
727 .s_stream = hdmi_s_stream,
728};
729
730static const struct v4l2_subdev_ops hdmi_sd_ops = {
731 .core = &hdmi_sd_core_ops,
732 .video = &hdmi_sd_video_ops,
733};
734
735static int hdmi_runtime_suspend(struct device *dev)
736{
737 struct v4l2_subdev *sd = dev_get_drvdata(dev);
738 struct hdmi_device *hdev = sd_to_hdmi_dev(sd);
739
740 dev_dbg(dev, "%s\n", __func__);
741 hdmi_resource_poweroff(&hdev->res);
742 return 0;
743}
744
745static int hdmi_runtime_resume(struct device *dev)
746{
747 struct v4l2_subdev *sd = dev_get_drvdata(dev);
748 struct hdmi_device *hdev = sd_to_hdmi_dev(sd);
749 int ret = 0;
750
751 dev_dbg(dev, "%s\n", __func__);
752
753 hdmi_resource_poweron(&hdev->res);
754
755 ret = hdmi_conf_apply(hdev);
756 if (ret)
757 goto fail;
758
759 dev_dbg(dev, "poweron succeed\n");
760
761 return 0;
762
763fail:
764 hdmi_resource_poweroff(&hdev->res);
765 dev_err(dev, "poweron failed\n");
766
767 return ret;
768}
769
770static const struct dev_pm_ops hdmi_pm_ops = {
771 .runtime_suspend = hdmi_runtime_suspend,
772 .runtime_resume = hdmi_runtime_resume,
773};
774
775static void hdmi_resources_cleanup(struct hdmi_device *hdev)
776{
777 struct hdmi_resources *res = &hdev->res;
778
779 dev_dbg(hdev->dev, "HDMI resource cleanup\n");
780 /* put clocks, power */
781 if (res->regul_count)
782 regulator_bulk_free(res->regul_count, res->regul_bulk);
783 /* kfree is NULL-safe */
784 kfree(res->regul_bulk);
785 if (!IS_ERR_OR_NULL(res->hdmiphy))
786 clk_put(res->hdmiphy);
787 if (!IS_ERR_OR_NULL(res->sclk_hdmiphy))
788 clk_put(res->sclk_hdmiphy);
789 if (!IS_ERR_OR_NULL(res->sclk_pixel))
790 clk_put(res->sclk_pixel);
791 if (!IS_ERR_OR_NULL(res->sclk_hdmi))
792 clk_put(res->sclk_hdmi);
793 if (!IS_ERR_OR_NULL(res->hdmi))
794 clk_put(res->hdmi);
795 memset(res, 0, sizeof *res);
796}
797
798static int hdmi_resources_init(struct hdmi_device *hdev)
799{
800 struct device *dev = hdev->dev;
801 struct hdmi_resources *res = &hdev->res;
802 static char *supply[] = {
803 "hdmi-en",
804 "vdd",
805 "vdd_osc",
806 "vdd_pll",
807 };
808 int i, ret;
809
810 dev_dbg(dev, "HDMI resource init\n");
811
812 memset(res, 0, sizeof *res);
813 /* get clocks, power */
814
815 res->hdmi = clk_get(dev, "hdmi");
816 if (IS_ERR_OR_NULL(res->hdmi)) {
817 dev_err(dev, "failed to get clock 'hdmi'\n");
818 goto fail;
819 }
820 res->sclk_hdmi = clk_get(dev, "sclk_hdmi");
821 if (IS_ERR_OR_NULL(res->sclk_hdmi)) {
822 dev_err(dev, "failed to get clock 'sclk_hdmi'\n");
823 goto fail;
824 }
825 res->sclk_pixel = clk_get(dev, "sclk_pixel");
826 if (IS_ERR_OR_NULL(res->sclk_pixel)) {
827 dev_err(dev, "failed to get clock 'sclk_pixel'\n");
828 goto fail;
829 }
830 res->sclk_hdmiphy = clk_get(dev, "sclk_hdmiphy");
831 if (IS_ERR_OR_NULL(res->sclk_hdmiphy)) {
832 dev_err(dev, "failed to get clock 'sclk_hdmiphy'\n");
833 goto fail;
834 }
835 res->hdmiphy = clk_get(dev, "hdmiphy");
836 if (IS_ERR_OR_NULL(res->hdmiphy)) {
837 dev_err(dev, "failed to get clock 'hdmiphy'\n");
838 goto fail;
839 }
840 res->regul_bulk = kzalloc(ARRAY_SIZE(supply) *
841 sizeof res->regul_bulk[0], GFP_KERNEL);
842 if (!res->regul_bulk) {
843 dev_err(dev, "failed to get memory for regulators\n");
844 goto fail;
845 }
846 for (i = 0; i < ARRAY_SIZE(supply); ++i) {
847 res->regul_bulk[i].supply = supply[i];
848 res->regul_bulk[i].consumer = NULL;
849 }
850
851 ret = regulator_bulk_get(dev, ARRAY_SIZE(supply), res->regul_bulk);
852 if (ret) {
853 dev_err(dev, "failed to get regulators\n");
854 goto fail;
855 }
856 res->regul_count = ARRAY_SIZE(supply);
857
858 return 0;
859fail:
860 dev_err(dev, "HDMI resource init - failed\n");
861 hdmi_resources_cleanup(hdev);
862 return -ENODEV;
863}
864
865static int __devinit hdmi_probe(struct platform_device *pdev)
866{
867 struct device *dev = &pdev->dev;
868 struct resource *res;
869 struct i2c_adapter *phy_adapter;
870 struct v4l2_subdev *sd;
871 struct hdmi_device *hdmi_dev = NULL;
872 struct hdmi_driver_data *drv_data;
873 int ret;
874
875 dev_dbg(dev, "probe start\n");
876
877 hdmi_dev = kzalloc(sizeof(*hdmi_dev), GFP_KERNEL);
878 if (!hdmi_dev) {
879 dev_err(dev, "out of memory\n");
880 ret = -ENOMEM;
881 goto fail;
882 }
883
884 hdmi_dev->dev = dev;
885
886 ret = hdmi_resources_init(hdmi_dev);
887 if (ret)
888 goto fail_hdev;
889
890 /* mapping HDMI registers */
891 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
892 if (res == NULL) {
893 dev_err(dev, "get memory resource failed.\n");
894 ret = -ENXIO;
895 goto fail_init;
896 }
897
898 hdmi_dev->regs = ioremap(res->start, resource_size(res));
899 if (hdmi_dev->regs == NULL) {
900 dev_err(dev, "register mapping failed.\n");
901 ret = -ENXIO;
902 goto fail_hdev;
903 }
904
905 res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
906 if (res == NULL) {
907 dev_err(dev, "get interrupt resource failed.\n");
908 ret = -ENXIO;
909 goto fail_regs;
910 }
911
912 ret = request_irq(res->start, hdmi_irq_handler, 0, "hdmi", hdmi_dev);
913 if (ret) {
914 dev_err(dev, "request interrupt failed.\n");
915 goto fail_regs;
916 }
917 hdmi_dev->irq = res->start;
918
919 /* setting v4l2 name to prevent WARN_ON in v4l2_device_register */
920 strlcpy(hdmi_dev->v4l2_dev.name, dev_name(dev),
921 sizeof(hdmi_dev->v4l2_dev.name));
922 /* passing NULL owner prevents driver from erasing drvdata */
923 ret = v4l2_device_register(NULL, &hdmi_dev->v4l2_dev);
924 if (ret) {
925 dev_err(dev, "could not register v4l2 device.\n");
926 goto fail_irq;
927 }
928
929 drv_data = (struct hdmi_driver_data *)
930 platform_get_device_id(pdev)->driver_data;
931 phy_adapter = i2c_get_adapter(drv_data->hdmiphy_bus);
932 if (phy_adapter == NULL) {
933 dev_err(dev, "adapter request failed\n");
934 ret = -ENXIO;
935 goto fail_vdev;
936 }
937
938 hdmi_dev->phy_sd = v4l2_i2c_new_subdev_board(&hdmi_dev->v4l2_dev,
939 phy_adapter, &hdmiphy_info, NULL);
940 /* on failure or not adapter is no longer useful */
941 i2c_put_adapter(phy_adapter);
942 if (hdmi_dev->phy_sd == NULL) {
943 dev_err(dev, "missing subdev for hdmiphy\n");
944 ret = -ENODEV;
945 goto fail_vdev;
946 }
947
948 clk_enable(hdmi_dev->res.hdmi);
949
950 pm_runtime_enable(dev);
951
952 sd = &hdmi_dev->sd;
953 v4l2_subdev_init(sd, &hdmi_sd_ops);
954 sd->owner = THIS_MODULE;
955
956 strlcpy(sd->name, "s5p-hdmi", sizeof sd->name);
957 hdmi_dev->cur_preset = HDMI_DEFAULT_PRESET;
958 /* FIXME: missing fail preset is not supported */
959 hdmi_dev->cur_conf = hdmi_preset2conf(hdmi_dev->cur_preset);
960
961 /* storing subdev for call that have only access to struct device */
962 dev_set_drvdata(dev, sd);
963
964 dev_info(dev, "probe sucessful\n");
965
966 return 0;
967
968fail_vdev:
969 v4l2_device_unregister(&hdmi_dev->v4l2_dev);
970
971fail_irq:
972 free_irq(hdmi_dev->irq, hdmi_dev);
973
974fail_regs:
975 iounmap(hdmi_dev->regs);
976
977fail_init:
978 hdmi_resources_cleanup(hdmi_dev);
979
980fail_hdev:
981 kfree(hdmi_dev);
982
983fail:
984 dev_err(dev, "probe failed\n");
985 return ret;
986}
987
988static int __devexit hdmi_remove(struct platform_device *pdev)
989{
990 struct device *dev = &pdev->dev;
991 struct v4l2_subdev *sd = dev_get_drvdata(dev);
992 struct hdmi_device *hdmi_dev = sd_to_hdmi_dev(sd);
993
994 pm_runtime_disable(dev);
995 clk_disable(hdmi_dev->res.hdmi);
996 v4l2_device_unregister(&hdmi_dev->v4l2_dev);
997 disable_irq(hdmi_dev->irq);
998 free_irq(hdmi_dev->irq, hdmi_dev);
999 iounmap(hdmi_dev->regs);
1000 hdmi_resources_cleanup(hdmi_dev);
1001 kfree(hdmi_dev);
1002 dev_info(dev, "remove sucessful\n");
1003
1004 return 0;
1005}
1006
1007static struct platform_driver hdmi_driver __refdata = {
1008 .probe = hdmi_probe,
1009 .remove = __devexit_p(hdmi_remove),
1010 .id_table = hdmi_driver_types,
1011 .driver = {
1012 .name = "s5p-hdmi",
1013 .owner = THIS_MODULE,
1014 .pm = &hdmi_pm_ops,
1015 }
1016};
1017
1018/* D R I V E R I N I T I A L I Z A T I O N */
1019
1020static int __init hdmi_init(void)
1021{
1022 int ret;
1023 static const char banner[] __initdata = KERN_INFO \
1024 "Samsung HDMI output driver, "
1025 "(c) 2010-2011 Samsung Electronics Co., Ltd.\n";
1026 printk(banner);
1027
1028 ret = platform_driver_register(&hdmi_driver);
1029 if (ret)
1030 printk(KERN_ERR "HDMI platform driver register failed\n");
1031
1032 return ret;
1033}
1034module_init(hdmi_init);
1035
1036static void __exit hdmi_exit(void)
1037{
1038 platform_driver_unregister(&hdmi_driver);
1039}
1040module_exit(hdmi_exit);
1041
1042
diff --git a/drivers/media/video/s5p-tv/hdmiphy_drv.c b/drivers/media/video/s5p-tv/hdmiphy_drv.c
new file mode 100644
index 00000000000..6693f4aff10
--- /dev/null
+++ b/drivers/media/video/s5p-tv/hdmiphy_drv.c
@@ -0,0 +1,188 @@
1/*
2 * Samsung HDMI Physical interface driver
3 *
4 * Copyright (C) 2010-2011 Samsung Electronics Co.Ltd
5 * Author: Tomasz Stanislawski <t.stanislaws@samsung.com>
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version.
11 */
12
13#include <linux/module.h>
14#include <linux/i2c.h>
15#include <linux/slab.h>
16#include <linux/clk.h>
17#include <linux/io.h>
18#include <linux/interrupt.h>
19#include <linux/irq.h>
20#include <linux/err.h>
21
22#include <media/v4l2-subdev.h>
23
24MODULE_AUTHOR("Tomasz Stanislawski <t.stanislaws@samsung.com>");
25MODULE_DESCRIPTION("Samsung HDMI Physical interface driver");
26MODULE_LICENSE("GPL");
27
28struct hdmiphy_conf {
29 u32 preset;
30 const u8 *data;
31};
32
33static const u8 hdmiphy_conf27[32] = {
34 0x01, 0x05, 0x00, 0xD8, 0x10, 0x1C, 0x30, 0x40,
35 0x6B, 0x10, 0x02, 0x51, 0xDf, 0xF2, 0x54, 0x87,
36 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
37 0x22, 0x40, 0xe3, 0x26, 0x00, 0x00, 0x00, 0x00,
38};
39
40static const u8 hdmiphy_conf74_175[32] = {
41 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xef, 0x5B,
42 0x6D, 0x10, 0x01, 0x51, 0xef, 0xF3, 0x54, 0xb9,
43 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
44 0x22, 0x40, 0xa5, 0x26, 0x01, 0x00, 0x00, 0x00,
45};
46
47static const u8 hdmiphy_conf74_25[32] = {
48 0x01, 0x05, 0x00, 0xd8, 0x10, 0x9c, 0xf8, 0x40,
49 0x6a, 0x10, 0x01, 0x51, 0xff, 0xf1, 0x54, 0xba,
50 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xe0,
51 0x22, 0x40, 0xa4, 0x26, 0x01, 0x00, 0x00, 0x00,
52};
53
54static const u8 hdmiphy_conf148_5[32] = {
55 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xf8, 0x40,
56 0x6A, 0x18, 0x00, 0x51, 0xff, 0xF1, 0x54, 0xba,
57 0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xE0,
58 0x22, 0x40, 0xa4, 0x26, 0x02, 0x00, 0x00, 0x00,
59};
60
61static const struct hdmiphy_conf hdmiphy_conf[] = {
62 { V4L2_DV_480P59_94, hdmiphy_conf27 },
63 { V4L2_DV_1080P30, hdmiphy_conf74_175 },
64 { V4L2_DV_720P59_94, hdmiphy_conf74_175 },
65 { V4L2_DV_720P60, hdmiphy_conf74_25 },
66 { V4L2_DV_1080P50, hdmiphy_conf148_5 },
67 { V4L2_DV_1080P60, hdmiphy_conf148_5 },
68};
69
70const u8 *hdmiphy_preset2conf(u32 preset)
71{
72 int i;
73 for (i = 0; i < ARRAY_SIZE(hdmiphy_conf); ++i)
74 if (hdmiphy_conf[i].preset == preset)
75 return hdmiphy_conf[i].data;
76 return NULL;
77}
78
79static int hdmiphy_s_power(struct v4l2_subdev *sd, int on)
80{
81 /* to be implemented */
82 return 0;
83}
84
85static int hdmiphy_s_dv_preset(struct v4l2_subdev *sd,
86 struct v4l2_dv_preset *preset)
87{
88 const u8 *data;
89 u8 buffer[32];
90 int ret;
91 struct i2c_client *client = v4l2_get_subdevdata(sd);
92 struct device *dev = &client->dev;
93
94 dev_info(dev, "s_dv_preset(preset = %d)\n", preset->preset);
95 data = hdmiphy_preset2conf(preset->preset);
96 if (!data) {
97 dev_err(dev, "format not supported\n");
98 return -EINVAL;
99 }
100
101 /* storing configuration to the device */
102 memcpy(buffer, data, 32);
103 ret = i2c_master_send(client, buffer, 32);
104 if (ret != 32) {
105 dev_err(dev, "failed to configure HDMIPHY via I2C\n");
106 return -EIO;
107 }
108
109 return 0;
110}
111
112static int hdmiphy_s_stream(struct v4l2_subdev *sd, int enable)
113{
114 struct i2c_client *client = v4l2_get_subdevdata(sd);
115 struct device *dev = &client->dev;
116 u8 buffer[2];
117 int ret;
118
119 dev_info(dev, "s_stream(%d)\n", enable);
120 /* going to/from configuration from/to operation mode */
121 buffer[0] = 0x1f;
122 buffer[1] = enable ? 0x80 : 0x00;
123
124 ret = i2c_master_send(client, buffer, 2);
125 if (ret != 2) {
126 dev_err(dev, "stream (%d) failed\n", enable);
127 return -EIO;
128 }
129 return 0;
130}
131
132static const struct v4l2_subdev_core_ops hdmiphy_core_ops = {
133 .s_power = hdmiphy_s_power,
134};
135
136static const struct v4l2_subdev_video_ops hdmiphy_video_ops = {
137 .s_dv_preset = hdmiphy_s_dv_preset,
138 .s_stream = hdmiphy_s_stream,
139};
140
141static const struct v4l2_subdev_ops hdmiphy_ops = {
142 .core = &hdmiphy_core_ops,
143 .video = &hdmiphy_video_ops,
144};
145
146static int __devinit hdmiphy_probe(struct i2c_client *client,
147 const struct i2c_device_id *id)
148{
149 static struct v4l2_subdev sd;
150
151 v4l2_i2c_subdev_init(&sd, client, &hdmiphy_ops);
152 dev_info(&client->dev, "probe successful\n");
153 return 0;
154}
155
156static int __devexit hdmiphy_remove(struct i2c_client *client)
157{
158 dev_info(&client->dev, "remove successful\n");
159 return 0;
160}
161
162static const struct i2c_device_id hdmiphy_id[] = {
163 { "hdmiphy", 0 },
164 { },
165};
166MODULE_DEVICE_TABLE(i2c, hdmiphy_id);
167
168static struct i2c_driver hdmiphy_driver = {
169 .driver = {
170 .name = "s5p-hdmiphy",
171 .owner = THIS_MODULE,
172 },
173 .probe = hdmiphy_probe,
174 .remove = __devexit_p(hdmiphy_remove),
175 .id_table = hdmiphy_id,
176};
177
178static int __init hdmiphy_init(void)
179{
180 return i2c_add_driver(&hdmiphy_driver);
181}
182module_init(hdmiphy_init);
183
184static void __exit hdmiphy_exit(void)
185{
186 i2c_del_driver(&hdmiphy_driver);
187}
188module_exit(hdmiphy_exit);
diff --git a/drivers/media/video/s5p-tv/mixer.h b/drivers/media/video/s5p-tv/mixer.h
new file mode 100644
index 00000000000..e2242243f63
--- /dev/null
+++ b/drivers/media/video/s5p-tv/mixer.h
@@ -0,0 +1,354 @@
1/*
2 * Samsung TV Mixer 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#ifndef SAMSUNG_MIXER_H
15#define SAMSUNG_MIXER_H
16
17#ifdef CONFIG_VIDEO_SAMSUNG_S5P_MIXER_DEBUG
18 #define DEBUG
19#endif
20
21#include <linux/fb.h>
22#include <linux/kernel.h>
23#include <linux/spinlock.h>
24#include <linux/wait.h>
25#include <media/v4l2-device.h>
26#include <media/videobuf2-core.h>
27
28#include "regs-mixer.h"
29
30/** maximum number of output interfaces */
31#define MXR_MAX_OUTPUTS 2
32/** maximum number of input interfaces (layers) */
33#define MXR_MAX_LAYERS 3
34#define MXR_DRIVER_NAME "s5p-mixer"
35/** maximal number of planes for every layer */
36#define MXR_MAX_PLANES 2
37
38#define MXR_ENABLE 1
39#define MXR_DISABLE 0
40
41/** description of a macroblock for packed formats */
42struct mxr_block {
43 /** vertical number of pixels in macroblock */
44 unsigned int width;
45 /** horizontal number of pixels in macroblock */
46 unsigned int height;
47 /** size of block in bytes */
48 unsigned int size;
49};
50
51/** description of supported format */
52struct mxr_format {
53 /** format name/mnemonic */
54 const char *name;
55 /** fourcc identifier */
56 u32 fourcc;
57 /** colorspace identifier */
58 enum v4l2_colorspace colorspace;
59 /** number of planes in image data */
60 int num_planes;
61 /** description of block for each plane */
62 struct mxr_block plane[MXR_MAX_PLANES];
63 /** number of subframes in image data */
64 int num_subframes;
65 /** specifies to which subframe belong given plane */
66 int plane2subframe[MXR_MAX_PLANES];
67 /** internal code, driver dependant */
68 unsigned long cookie;
69};
70
71/** description of crop configuration for image */
72struct mxr_crop {
73 /** width of layer in pixels */
74 unsigned int full_width;
75 /** height of layer in pixels */
76 unsigned int full_height;
77 /** horizontal offset of first pixel to be displayed */
78 unsigned int x_offset;
79 /** vertical offset of first pixel to be displayed */
80 unsigned int y_offset;
81 /** width of displayed data in pixels */
82 unsigned int width;
83 /** height of displayed data in pixels */
84 unsigned int height;
85 /** indicate which fields are present in buffer */
86 unsigned int field;
87};
88
89/** description of transformation from source to destination image */
90struct mxr_geometry {
91 /** cropping for source image */
92 struct mxr_crop src;
93 /** cropping for destination image */
94 struct mxr_crop dst;
95 /** layer-dependant description of horizontal scaling */
96 unsigned int x_ratio;
97 /** layer-dependant description of vertical scaling */
98 unsigned int y_ratio;
99};
100
101/** instance of a buffer */
102struct mxr_buffer {
103 /** common v4l buffer stuff -- must be first */
104 struct vb2_buffer vb;
105 /** node for layer's lists */
106 struct list_head list;
107};
108
109
110/** internal states of layer */
111enum mxr_layer_state {
112 /** layers is not shown */
113 MXR_LAYER_IDLE = 0,
114 /** state between STREAMON and hardware start */
115 MXR_LAYER_STREAMING_START,
116 /** layer is shown */
117 MXR_LAYER_STREAMING,
118 /** state before STREAMOFF is finished */
119 MXR_LAYER_STREAMING_FINISH,
120};
121
122/** forward declarations */
123struct mxr_device;
124struct mxr_layer;
125
126/** callback for layers operation */
127struct mxr_layer_ops {
128 /* TODO: try to port it to subdev API */
129 /** handler for resource release function */
130 void (*release)(struct mxr_layer *);
131 /** setting buffer to HW */
132 void (*buffer_set)(struct mxr_layer *, struct mxr_buffer *);
133 /** setting format and geometry in HW */
134 void (*format_set)(struct mxr_layer *);
135 /** streaming stop/start */
136 void (*stream_set)(struct mxr_layer *, int);
137 /** adjusting geometry */
138 void (*fix_geometry)(struct mxr_layer *);
139};
140
141/** layer instance, a single window and content displayed on output */
142struct mxr_layer {
143 /** parent mixer device */
144 struct mxr_device *mdev;
145 /** layer index (unique identifier) */
146 int idx;
147 /** callbacks for layer methods */
148 struct mxr_layer_ops ops;
149 /** format array */
150 const struct mxr_format **fmt_array;
151 /** size of format array */
152 unsigned long fmt_array_size;
153
154 /** lock for protection of list and state fields */
155 spinlock_t enq_slock;
156 /** list for enqueued buffers */
157 struct list_head enq_list;
158 /** buffer currently owned by hardware in temporary registers */
159 struct mxr_buffer *update_buf;
160 /** buffer currently owned by hardware in shadow registers */
161 struct mxr_buffer *shadow_buf;
162 /** state of layer IDLE/STREAMING */
163 enum mxr_layer_state state;
164
165 /** mutex for protection of fields below */
166 struct mutex mutex;
167 /** handler for video node */
168 struct video_device vfd;
169 /** queue for output buffers */
170 struct vb2_queue vb_queue;
171 /** current image format */
172 const struct mxr_format *fmt;
173 /** current geometry of image */
174 struct mxr_geometry geo;
175};
176
177/** description of mixers output interface */
178struct mxr_output {
179 /** name of output */
180 char name[32];
181 /** output subdev */
182 struct v4l2_subdev *sd;
183 /** cookie used for configuration of registers */
184 int cookie;
185};
186
187/** specify source of output subdevs */
188struct mxr_output_conf {
189 /** name of output (connector) */
190 char *output_name;
191 /** name of module that generates output subdev */
192 char *module_name;
193 /** cookie need for mixer HW */
194 int cookie;
195};
196
197struct clk;
198struct regulator;
199
200/** auxiliary resources used my mixer */
201struct mxr_resources {
202 /** interrupt index */
203 int irq;
204 /** pointer to Mixer registers */
205 void __iomem *mxr_regs;
206 /** pointer to Video Processor registers */
207 void __iomem *vp_regs;
208 /** other resources, should used under mxr_device.mutex */
209 struct clk *mixer;
210 struct clk *vp;
211 struct clk *sclk_mixer;
212 struct clk *sclk_hdmi;
213 struct clk *sclk_dac;
214};
215
216/* event flags used */
217enum mxr_devide_flags {
218 MXR_EVENT_VSYNC = 0,
219};
220
221/** drivers instance */
222struct mxr_device {
223 /** master device */
224 struct device *dev;
225 /** state of each layer */
226 struct mxr_layer *layer[MXR_MAX_LAYERS];
227 /** state of each output */
228 struct mxr_output *output[MXR_MAX_OUTPUTS];
229 /** number of registered outputs */
230 int output_cnt;
231
232 /* video resources */
233
234 /** V4L2 device */
235 struct v4l2_device v4l2_dev;
236 /** context of allocator */
237 void *alloc_ctx;
238 /** event wait queue */
239 wait_queue_head_t event_queue;
240 /** state flags */
241 unsigned long event_flags;
242
243 /** spinlock for protection of registers */
244 spinlock_t reg_slock;
245
246 /** mutex for protection of fields below */
247 struct mutex mutex;
248 /** number of entities depndant on output configuration */
249 int n_output;
250 /** number of users that do streaming */
251 int n_streamer;
252 /** index of current output */
253 int current_output;
254 /** auxiliary resources used my mixer */
255 struct mxr_resources res;
256};
257
258/** transform device structure into mixer device */
259static inline struct mxr_device *to_mdev(struct device *dev)
260{
261 struct v4l2_device *vdev = dev_get_drvdata(dev);
262 return container_of(vdev, struct mxr_device, v4l2_dev);
263}
264
265/** get current output data, should be called under mdev's mutex */
266static inline struct mxr_output *to_output(struct mxr_device *mdev)
267{
268 return mdev->output[mdev->current_output];
269}
270
271/** get current output subdev, should be called under mdev's mutex */
272static inline struct v4l2_subdev *to_outsd(struct mxr_device *mdev)
273{
274 struct mxr_output *out = to_output(mdev);
275 return out ? out->sd : NULL;
276}
277
278/** forward declaration for mixer platform data */
279struct mxr_platform_data;
280
281/** acquiring common video resources */
282int __devinit mxr_acquire_video(struct mxr_device *mdev,
283 struct mxr_output_conf *output_cont, int output_count);
284
285/** releasing common video resources */
286void __devexit mxr_release_video(struct mxr_device *mdev);
287
288struct mxr_layer *mxr_graph_layer_create(struct mxr_device *mdev, int idx);
289struct mxr_layer *mxr_vp_layer_create(struct mxr_device *mdev, int idx);
290struct mxr_layer *mxr_base_layer_create(struct mxr_device *mdev,
291 int idx, char *name, struct mxr_layer_ops *ops);
292
293void mxr_base_layer_release(struct mxr_layer *layer);
294void mxr_layer_release(struct mxr_layer *layer);
295
296int mxr_base_layer_register(struct mxr_layer *layer);
297void mxr_base_layer_unregister(struct mxr_layer *layer);
298
299unsigned long mxr_get_plane_size(const struct mxr_block *blk,
300 unsigned int width, unsigned int height);
301
302/** adds new consumer for mixer's power */
303int __must_check mxr_power_get(struct mxr_device *mdev);
304/** removes consumer for mixer's power */
305void mxr_power_put(struct mxr_device *mdev);
306/** add new client for output configuration */
307void mxr_output_get(struct mxr_device *mdev);
308/** removes new client for output configuration */
309void mxr_output_put(struct mxr_device *mdev);
310/** add new client for streaming */
311void mxr_streamer_get(struct mxr_device *mdev);
312/** removes new client for streaming */
313void mxr_streamer_put(struct mxr_device *mdev);
314/** returns format of data delivared to current output */
315void mxr_get_mbus_fmt(struct mxr_device *mdev,
316 struct v4l2_mbus_framefmt *mbus_fmt);
317
318/* Debug */
319
320#define mxr_err(mdev, fmt, ...) dev_err(mdev->dev, fmt, ##__VA_ARGS__)
321#define mxr_warn(mdev, fmt, ...) dev_warn(mdev->dev, fmt, ##__VA_ARGS__)
322#define mxr_info(mdev, fmt, ...) dev_info(mdev->dev, fmt, ##__VA_ARGS__)
323
324#ifdef CONFIG_VIDEO_SAMSUNG_S5P_MIXER_DEBUG
325 #define mxr_dbg(mdev, fmt, ...) dev_dbg(mdev->dev, fmt, ##__VA_ARGS__)
326#else
327 #define mxr_dbg(mdev, fmt, ...) do { (void) mdev; } while (0)
328#endif
329
330/* accessing Mixer's and Video Processor's registers */
331
332void mxr_vsync_set_update(struct mxr_device *mdev, int en);
333void mxr_reg_reset(struct mxr_device *mdev);
334irqreturn_t mxr_irq_handler(int irq, void *dev_data);
335void mxr_reg_s_output(struct mxr_device *mdev, int cookie);
336void mxr_reg_streamon(struct mxr_device *mdev);
337void mxr_reg_streamoff(struct mxr_device *mdev);
338int mxr_reg_wait4vsync(struct mxr_device *mdev);
339void mxr_reg_set_mbus_fmt(struct mxr_device *mdev,
340 struct v4l2_mbus_framefmt *fmt);
341void mxr_reg_graph_layer_stream(struct mxr_device *mdev, int idx, int en);
342void mxr_reg_graph_buffer(struct mxr_device *mdev, int idx, dma_addr_t addr);
343void mxr_reg_graph_format(struct mxr_device *mdev, int idx,
344 const struct mxr_format *fmt, const struct mxr_geometry *geo);
345
346void mxr_reg_vp_layer_stream(struct mxr_device *mdev, int en);
347void mxr_reg_vp_buffer(struct mxr_device *mdev,
348 dma_addr_t luma_addr[2], dma_addr_t chroma_addr[2]);
349void mxr_reg_vp_format(struct mxr_device *mdev,
350 const struct mxr_format *fmt, const struct mxr_geometry *geo);
351void mxr_reg_dump(struct mxr_device *mdev);
352
353#endif /* SAMSUNG_MIXER_H */
354
diff --git a/drivers/media/video/s5p-tv/mixer_drv.c b/drivers/media/video/s5p-tv/mixer_drv.c
new file mode 100644
index 00000000000..00643094b22
--- /dev/null
+++ b/drivers/media/video/s5p-tv/mixer_drv.c
@@ -0,0 +1,487 @@
1/*
2 * Samsung TV Mixer 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#include "mixer.h"
15
16#include <linux/module.h>
17#include <linux/platform_device.h>
18#include <linux/io.h>
19#include <linux/interrupt.h>
20#include <linux/irq.h>
21#include <linux/fb.h>
22#include <linux/delay.h>
23#include <linux/pm_runtime.h>
24#include <linux/clk.h>
25
26MODULE_AUTHOR("Tomasz Stanislawski, <t.stanislaws@samsung.com>");
27MODULE_DESCRIPTION("Samsung MIXER");
28MODULE_LICENSE("GPL");
29
30/* --------- DRIVER PARAMETERS ---------- */
31
32static struct mxr_output_conf mxr_output_conf[] = {
33 {
34 .output_name = "S5P HDMI connector",
35 .module_name = "s5p-hdmi",
36 .cookie = 1,
37 },
38 {
39 .output_name = "S5P SDO connector",
40 .module_name = "s5p-sdo",
41 .cookie = 0,
42 },
43};
44
45void mxr_get_mbus_fmt(struct mxr_device *mdev,
46 struct v4l2_mbus_framefmt *mbus_fmt)
47{
48 struct v4l2_subdev *sd;
49 int ret;
50
51 mutex_lock(&mdev->mutex);
52 sd = to_outsd(mdev);
53 ret = v4l2_subdev_call(sd, video, g_mbus_fmt, mbus_fmt);
54 WARN(ret, "failed to get mbus_fmt for output %s\n", sd->name);
55 mutex_unlock(&mdev->mutex);
56}
57
58void mxr_streamer_get(struct mxr_device *mdev)
59{
60 mutex_lock(&mdev->mutex);
61 ++mdev->n_streamer;
62 mxr_dbg(mdev, "%s(%d)\n", __func__, mdev->n_streamer);
63 if (mdev->n_streamer == 1) {
64 struct v4l2_subdev *sd = to_outsd(mdev);
65 struct v4l2_mbus_framefmt mbus_fmt;
66 struct mxr_resources *res = &mdev->res;
67 int ret;
68
69 if (to_output(mdev)->cookie == 0)
70 clk_set_parent(res->sclk_mixer, res->sclk_dac);
71 else
72 clk_set_parent(res->sclk_mixer, res->sclk_hdmi);
73 mxr_reg_s_output(mdev, to_output(mdev)->cookie);
74
75 ret = v4l2_subdev_call(sd, video, g_mbus_fmt, &mbus_fmt);
76 WARN(ret, "failed to get mbus_fmt for output %s\n", sd->name);
77 ret = v4l2_subdev_call(sd, video, s_stream, 1);
78 WARN(ret, "starting stream failed for output %s\n", sd->name);
79
80 mxr_reg_set_mbus_fmt(mdev, &mbus_fmt);
81 mxr_reg_streamon(mdev);
82 ret = mxr_reg_wait4vsync(mdev);
83 WARN(ret, "failed to get vsync (%d) from output\n", ret);
84 }
85 mutex_unlock(&mdev->mutex);
86 mxr_reg_dump(mdev);
87 /* FIXME: what to do when streaming fails? */
88}
89
90void mxr_streamer_put(struct mxr_device *mdev)
91{
92 mutex_lock(&mdev->mutex);
93 --mdev->n_streamer;
94 mxr_dbg(mdev, "%s(%d)\n", __func__, mdev->n_streamer);
95 if (mdev->n_streamer == 0) {
96 int ret;
97 struct v4l2_subdev *sd = to_outsd(mdev);
98
99 mxr_reg_streamoff(mdev);
100 /* vsync applies Mixer setup */
101 ret = mxr_reg_wait4vsync(mdev);
102 WARN(ret, "failed to get vsync (%d) from output\n", ret);
103 ret = v4l2_subdev_call(sd, video, s_stream, 0);
104 WARN(ret, "stopping stream failed for output %s\n", sd->name);
105 }
106 WARN(mdev->n_streamer < 0, "negative number of streamers (%d)\n",
107 mdev->n_streamer);
108 mutex_unlock(&mdev->mutex);
109 mxr_reg_dump(mdev);
110}
111
112void mxr_output_get(struct mxr_device *mdev)
113{
114 mutex_lock(&mdev->mutex);
115 ++mdev->n_output;
116 mxr_dbg(mdev, "%s(%d)\n", __func__, mdev->n_output);
117 /* turn on auxiliary driver */
118 if (mdev->n_output == 1)
119 v4l2_subdev_call(to_outsd(mdev), core, s_power, 1);
120 mutex_unlock(&mdev->mutex);
121}
122
123void mxr_output_put(struct mxr_device *mdev)
124{
125 mutex_lock(&mdev->mutex);
126 --mdev->n_output;
127 mxr_dbg(mdev, "%s(%d)\n", __func__, mdev->n_output);
128 /* turn on auxiliary driver */
129 if (mdev->n_output == 0)
130 v4l2_subdev_call(to_outsd(mdev), core, s_power, 0);
131 WARN(mdev->n_output < 0, "negative number of output users (%d)\n",
132 mdev->n_output);
133 mutex_unlock(&mdev->mutex);
134}
135
136int mxr_power_get(struct mxr_device *mdev)
137{
138 int ret = pm_runtime_get_sync(mdev->dev);
139
140 /* returning 1 means that power is already enabled,
141 * so zero success be returned */
142 if (IS_ERR_VALUE(ret))
143 return ret;
144 return 0;
145}
146
147void mxr_power_put(struct mxr_device *mdev)
148{
149 pm_runtime_put_sync(mdev->dev);
150}
151
152/* --------- RESOURCE MANAGEMENT -------------*/
153
154static int __devinit mxr_acquire_plat_resources(struct mxr_device *mdev,
155 struct platform_device *pdev)
156{
157 struct resource *res;
158 int ret;
159
160 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mxr");
161 if (res == NULL) {
162 mxr_err(mdev, "get memory resource failed.\n");
163 ret = -ENXIO;
164 goto fail;
165 }
166
167 mdev->res.mxr_regs = ioremap(res->start, resource_size(res));
168 if (mdev->res.mxr_regs == NULL) {
169 mxr_err(mdev, "register mapping failed.\n");
170 ret = -ENXIO;
171 goto fail;
172 }
173
174 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "vp");
175 if (res == NULL) {
176 mxr_err(mdev, "get memory resource failed.\n");
177 ret = -ENXIO;
178 goto fail_mxr_regs;
179 }
180
181 mdev->res.vp_regs = ioremap(res->start, resource_size(res));
182 if (mdev->res.vp_regs == NULL) {
183 mxr_err(mdev, "register mapping failed.\n");
184 ret = -ENXIO;
185 goto fail_mxr_regs;
186 }
187
188 res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "irq");
189 if (res == NULL) {
190 mxr_err(mdev, "get interrupt resource failed.\n");
191 ret = -ENXIO;
192 goto fail_vp_regs;
193 }
194
195 ret = request_irq(res->start, mxr_irq_handler, 0, "s5p-mixer", mdev);
196 if (ret) {
197 mxr_err(mdev, "request interrupt failed.\n");
198 goto fail_vp_regs;
199 }
200 mdev->res.irq = res->start;
201
202 return 0;
203
204fail_vp_regs:
205 iounmap(mdev->res.vp_regs);
206
207fail_mxr_regs:
208 iounmap(mdev->res.mxr_regs);
209
210fail:
211 return ret;
212}
213
214static void mxr_release_plat_resources(struct mxr_device *mdev)
215{
216 free_irq(mdev->res.irq, mdev);
217 iounmap(mdev->res.vp_regs);
218 iounmap(mdev->res.mxr_regs);
219}
220
221static void mxr_release_clocks(struct mxr_device *mdev)
222{
223 struct mxr_resources *res = &mdev->res;
224
225 if (!IS_ERR_OR_NULL(res->sclk_dac))
226 clk_put(res->sclk_dac);
227 if (!IS_ERR_OR_NULL(res->sclk_hdmi))
228 clk_put(res->sclk_hdmi);
229 if (!IS_ERR_OR_NULL(res->sclk_mixer))
230 clk_put(res->sclk_mixer);
231 if (!IS_ERR_OR_NULL(res->vp))
232 clk_put(res->vp);
233 if (!IS_ERR_OR_NULL(res->mixer))
234 clk_put(res->mixer);
235}
236
237static int mxr_acquire_clocks(struct mxr_device *mdev)
238{
239 struct mxr_resources *res = &mdev->res;
240 struct device *dev = mdev->dev;
241
242 res->mixer = clk_get(dev, "mixer");
243 if (IS_ERR_OR_NULL(res->mixer)) {
244 mxr_err(mdev, "failed to get clock 'mixer'\n");
245 goto fail;
246 }
247 res->vp = clk_get(dev, "vp");
248 if (IS_ERR_OR_NULL(res->vp)) {
249 mxr_err(mdev, "failed to get clock 'vp'\n");
250 goto fail;
251 }
252 res->sclk_mixer = clk_get(dev, "sclk_mixer");
253 if (IS_ERR_OR_NULL(res->sclk_mixer)) {
254 mxr_err(mdev, "failed to get clock 'sclk_mixer'\n");
255 goto fail;
256 }
257 res->sclk_hdmi = clk_get(dev, "sclk_hdmi");
258 if (IS_ERR_OR_NULL(res->sclk_hdmi)) {
259 mxr_err(mdev, "failed to get clock 'sclk_hdmi'\n");
260 goto fail;
261 }
262 res->sclk_dac = clk_get(dev, "sclk_dac");
263 if (IS_ERR_OR_NULL(res->sclk_dac)) {
264 mxr_err(mdev, "failed to get clock 'sclk_dac'\n");
265 goto fail;
266 }
267
268 return 0;
269fail:
270 mxr_release_clocks(mdev);
271 return -ENODEV;
272}
273
274static int __devinit mxr_acquire_resources(struct mxr_device *mdev,
275 struct platform_device *pdev)
276{
277 int ret;
278 ret = mxr_acquire_plat_resources(mdev, pdev);
279
280 if (ret)
281 goto fail;
282
283 ret = mxr_acquire_clocks(mdev);
284 if (ret)
285 goto fail_plat;
286
287 mxr_info(mdev, "resources acquired\n");
288 return 0;
289
290fail_plat:
291 mxr_release_plat_resources(mdev);
292fail:
293 mxr_err(mdev, "resources acquire failed\n");
294 return ret;
295}
296
297static void mxr_release_resources(struct mxr_device *mdev)
298{
299 mxr_release_clocks(mdev);
300 mxr_release_plat_resources(mdev);
301 memset(&mdev->res, 0, sizeof mdev->res);
302}
303
304static void mxr_release_layers(struct mxr_device *mdev)
305{
306 int i;
307
308 for (i = 0; i < ARRAY_SIZE(mdev->layer); ++i)
309 if (mdev->layer[i])
310 mxr_layer_release(mdev->layer[i]);
311}
312
313static int __devinit mxr_acquire_layers(struct mxr_device *mdev,
314 struct mxr_platform_data *pdata)
315{
316 mdev->layer[0] = mxr_graph_layer_create(mdev, 0);
317 mdev->layer[1] = mxr_graph_layer_create(mdev, 1);
318 mdev->layer[2] = mxr_vp_layer_create(mdev, 0);
319
320 if (!mdev->layer[0] || !mdev->layer[1] || !mdev->layer[2]) {
321 mxr_err(mdev, "failed to acquire layers\n");
322 goto fail;
323 }
324
325 return 0;
326
327fail:
328 mxr_release_layers(mdev);
329 return -ENODEV;
330}
331
332/* ---------- POWER MANAGEMENT ----------- */
333
334static int mxr_runtime_resume(struct device *dev)
335{
336 struct mxr_device *mdev = to_mdev(dev);
337 struct mxr_resources *res = &mdev->res;
338
339 mxr_dbg(mdev, "resume - start\n");
340 mutex_lock(&mdev->mutex);
341 /* turn clocks on */
342 clk_enable(res->mixer);
343 clk_enable(res->vp);
344 clk_enable(res->sclk_mixer);
345 /* apply default configuration */
346 mxr_reg_reset(mdev);
347 mxr_dbg(mdev, "resume - finished\n");
348
349 mutex_unlock(&mdev->mutex);
350 return 0;
351}
352
353static int mxr_runtime_suspend(struct device *dev)
354{
355 struct mxr_device *mdev = to_mdev(dev);
356 struct mxr_resources *res = &mdev->res;
357 mxr_dbg(mdev, "suspend - start\n");
358 mutex_lock(&mdev->mutex);
359 /* turn clocks off */
360 clk_disable(res->sclk_mixer);
361 clk_disable(res->vp);
362 clk_disable(res->mixer);
363 mutex_unlock(&mdev->mutex);
364 mxr_dbg(mdev, "suspend - finished\n");
365 return 0;
366}
367
368static const struct dev_pm_ops mxr_pm_ops = {
369 .runtime_suspend = mxr_runtime_suspend,
370 .runtime_resume = mxr_runtime_resume,
371};
372
373/* --------- DRIVER INITIALIZATION ---------- */
374
375static int __devinit mxr_probe(struct platform_device *pdev)
376{
377 struct device *dev = &pdev->dev;
378 struct mxr_platform_data *pdata = dev->platform_data;
379 struct mxr_device *mdev;
380 int ret;
381
382 /* mdev does not exist yet so no mxr_dbg is used */
383 dev_info(dev, "probe start\n");
384
385 mdev = kzalloc(sizeof *mdev, GFP_KERNEL);
386 if (!mdev) {
387 mxr_err(mdev, "not enough memory.\n");
388 ret = -ENOMEM;
389 goto fail;
390 }
391
392 /* setup pointer to master device */
393 mdev->dev = dev;
394
395 mutex_init(&mdev->mutex);
396 spin_lock_init(&mdev->reg_slock);
397 init_waitqueue_head(&mdev->event_queue);
398
399 /* acquire resources: regs, irqs, clocks, regulators */
400 ret = mxr_acquire_resources(mdev, pdev);
401 if (ret)
402 goto fail_mem;
403
404 /* configure resources for video output */
405 ret = mxr_acquire_video(mdev, mxr_output_conf,
406 ARRAY_SIZE(mxr_output_conf));
407 if (ret)
408 goto fail_resources;
409
410 /* configure layers */
411 ret = mxr_acquire_layers(mdev, pdata);
412 if (ret)
413 goto fail_video;
414
415 pm_runtime_enable(dev);
416
417 mxr_info(mdev, "probe successful\n");
418 return 0;
419
420fail_video:
421 mxr_release_video(mdev);
422
423fail_resources:
424 mxr_release_resources(mdev);
425
426fail_mem:
427 kfree(mdev);
428
429fail:
430 dev_info(dev, "probe failed\n");
431 return ret;
432}
433
434static int __devexit mxr_remove(struct platform_device *pdev)
435{
436 struct device *dev = &pdev->dev;
437 struct mxr_device *mdev = to_mdev(dev);
438
439 pm_runtime_disable(dev);
440
441 mxr_release_layers(mdev);
442 mxr_release_video(mdev);
443 mxr_release_resources(mdev);
444
445 kfree(mdev);
446
447 dev_info(dev, "remove sucessful\n");
448 return 0;
449}
450
451static struct platform_driver mxr_driver __refdata = {
452 .probe = mxr_probe,
453 .remove = __devexit_p(mxr_remove),
454 .driver = {
455 .name = MXR_DRIVER_NAME,
456 .owner = THIS_MODULE,
457 .pm = &mxr_pm_ops,
458 }
459};
460
461static int __init mxr_init(void)
462{
463 int i, ret;
464 static const char banner[] __initdata = KERN_INFO
465 "Samsung TV Mixer driver, "
466 "(c) 2010-2011 Samsung Electronics Co., Ltd.\n";
467 printk(banner);
468
469 /* Loading auxiliary modules */
470 for (i = 0; i < ARRAY_SIZE(mxr_output_conf); ++i)
471 request_module(mxr_output_conf[i].module_name);
472
473 ret = platform_driver_register(&mxr_driver);
474 if (ret != 0) {
475 printk(KERN_ERR "registration of MIXER driver failed\n");
476 return -ENXIO;
477 }
478
479 return 0;
480}
481module_init(mxr_init);
482
483static void __exit mxr_exit(void)
484{
485 platform_driver_unregister(&mxr_driver);
486}
487module_exit(mxr_exit);
diff --git a/drivers/media/video/s5p-tv/mixer_grp_layer.c b/drivers/media/video/s5p-tv/mixer_grp_layer.c
new file mode 100644
index 00000000000..58f0ba49580
--- /dev/null
+++ b/drivers/media/video/s5p-tv/mixer_grp_layer.c
@@ -0,0 +1,185 @@
1/*
2 * Samsung TV Mixer 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#include "mixer.h"
15
16#include <media/videobuf2-dma-contig.h>
17
18/* FORMAT DEFINITIONS */
19
20static const struct mxr_format mxr_fb_fmt_rgb565 = {
21 .name = "RGB565",
22 .fourcc = V4L2_PIX_FMT_RGB565,
23 .colorspace = V4L2_COLORSPACE_SRGB,
24 .num_planes = 1,
25 .plane = {
26 { .width = 1, .height = 1, .size = 2 },
27 },
28 .num_subframes = 1,
29 .cookie = 4,
30};
31
32static const struct mxr_format mxr_fb_fmt_argb1555 = {
33 .name = "ARGB1555",
34 .num_planes = 1,
35 .fourcc = V4L2_PIX_FMT_RGB555,
36 .colorspace = V4L2_COLORSPACE_SRGB,
37 .plane = {
38 { .width = 1, .height = 1, .size = 2 },
39 },
40 .num_subframes = 1,
41 .cookie = 5,
42};
43
44static const struct mxr_format mxr_fb_fmt_argb4444 = {
45 .name = "ARGB4444",
46 .num_planes = 1,
47 .fourcc = V4L2_PIX_FMT_RGB444,
48 .colorspace = V4L2_COLORSPACE_SRGB,
49 .plane = {
50 { .width = 1, .height = 1, .size = 2 },
51 },
52 .num_subframes = 1,
53 .cookie = 6,
54};
55
56static const struct mxr_format mxr_fb_fmt_argb8888 = {
57 .name = "ARGB8888",
58 .fourcc = V4L2_PIX_FMT_BGR32,
59 .colorspace = V4L2_COLORSPACE_SRGB,
60 .num_planes = 1,
61 .plane = {
62 { .width = 1, .height = 1, .size = 4 },
63 },
64 .num_subframes = 1,
65 .cookie = 7,
66};
67
68static const struct mxr_format *mxr_graph_format[] = {
69 &mxr_fb_fmt_rgb565,
70 &mxr_fb_fmt_argb1555,
71 &mxr_fb_fmt_argb4444,
72 &mxr_fb_fmt_argb8888,
73};
74
75/* AUXILIARY CALLBACKS */
76
77static void mxr_graph_layer_release(struct mxr_layer *layer)
78{
79 mxr_base_layer_unregister(layer);
80 mxr_base_layer_release(layer);
81}
82
83static void mxr_graph_buffer_set(struct mxr_layer *layer,
84 struct mxr_buffer *buf)
85{
86 dma_addr_t addr = 0;
87
88 if (buf)
89 addr = vb2_dma_contig_plane_paddr(&buf->vb, 0);
90 mxr_reg_graph_buffer(layer->mdev, layer->idx, addr);
91}
92
93static void mxr_graph_stream_set(struct mxr_layer *layer, int en)
94{
95 mxr_reg_graph_layer_stream(layer->mdev, layer->idx, en);
96}
97
98static void mxr_graph_format_set(struct mxr_layer *layer)
99{
100 mxr_reg_graph_format(layer->mdev, layer->idx,
101 layer->fmt, &layer->geo);
102}
103
104static void mxr_graph_fix_geometry(struct mxr_layer *layer)
105{
106 struct mxr_geometry *geo = &layer->geo;
107
108 /* limit to boundary size */
109 geo->src.full_width = clamp_val(geo->src.full_width, 1, 32767);
110 geo->src.full_height = clamp_val(geo->src.full_height, 1, 2047);
111 geo->src.width = clamp_val(geo->src.width, 1, geo->src.full_width);
112 geo->src.width = min(geo->src.width, 2047U);
113 /* not possible to crop of Y axis */
114 geo->src.y_offset = min(geo->src.y_offset, geo->src.full_height - 1);
115 geo->src.height = geo->src.full_height - geo->src.y_offset;
116 /* limitting offset */
117 geo->src.x_offset = min(geo->src.x_offset,
118 geo->src.full_width - geo->src.width);
119
120 /* setting position in output */
121 geo->dst.width = min(geo->dst.width, geo->dst.full_width);
122 geo->dst.height = min(geo->dst.height, geo->dst.full_height);
123
124 /* Mixer supports only 1x and 2x scaling */
125 if (geo->dst.width >= 2 * geo->src.width) {
126 geo->x_ratio = 1;
127 geo->dst.width = 2 * geo->src.width;
128 } else {
129 geo->x_ratio = 0;
130 geo->dst.width = geo->src.width;
131 }
132
133 if (geo->dst.height >= 2 * geo->src.height) {
134 geo->y_ratio = 1;
135 geo->dst.height = 2 * geo->src.height;
136 } else {
137 geo->y_ratio = 0;
138 geo->dst.height = geo->src.height;
139 }
140
141 geo->dst.x_offset = min(geo->dst.x_offset,
142 geo->dst.full_width - geo->dst.width);
143 geo->dst.y_offset = min(geo->dst.y_offset,
144 geo->dst.full_height - geo->dst.height);
145}
146
147/* PUBLIC API */
148
149struct mxr_layer *mxr_graph_layer_create(struct mxr_device *mdev, int idx)
150{
151 struct mxr_layer *layer;
152 int ret;
153 struct mxr_layer_ops ops = {
154 .release = mxr_graph_layer_release,
155 .buffer_set = mxr_graph_buffer_set,
156 .stream_set = mxr_graph_stream_set,
157 .format_set = mxr_graph_format_set,
158 .fix_geometry = mxr_graph_fix_geometry,
159 };
160 char name[32];
161
162 sprintf(name, "graph%d", idx);
163
164 layer = mxr_base_layer_create(mdev, idx, name, &ops);
165 if (layer == NULL) {
166 mxr_err(mdev, "failed to initialize layer(%d) base\n", idx);
167 goto fail;
168 }
169
170 layer->fmt_array = mxr_graph_format;
171 layer->fmt_array_size = ARRAY_SIZE(mxr_graph_format);
172
173 ret = mxr_base_layer_register(layer);
174 if (ret)
175 goto fail_layer;
176
177 return layer;
178
179fail_layer:
180 mxr_base_layer_release(layer);
181
182fail:
183 return NULL;
184}
185
diff --git a/drivers/media/video/s5p-tv/mixer_reg.c b/drivers/media/video/s5p-tv/mixer_reg.c
new file mode 100644
index 00000000000..38dac672aa1
--- /dev/null
+++ b/drivers/media/video/s5p-tv/mixer_reg.c
@@ -0,0 +1,541 @@
1/*
2 * Samsung TV Mixer 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#include "mixer.h"
15#include "regs-mixer.h"
16#include "regs-vp.h"
17
18#include <linux/delay.h>
19
20/* Register access subroutines */
21
22static inline u32 vp_read(struct mxr_device *mdev, u32 reg_id)
23{
24 return readl(mdev->res.vp_regs + reg_id);
25}
26
27static inline void vp_write(struct mxr_device *mdev, u32 reg_id, u32 val)
28{
29 writel(val, mdev->res.vp_regs + reg_id);
30}
31
32static inline void vp_write_mask(struct mxr_device *mdev, u32 reg_id,
33 u32 val, u32 mask)
34{
35 u32 old = vp_read(mdev, reg_id);
36
37 val = (val & mask) | (old & ~mask);
38 writel(val, mdev->res.vp_regs + reg_id);
39}
40
41static inline u32 mxr_read(struct mxr_device *mdev, u32 reg_id)
42{
43 return readl(mdev->res.mxr_regs + reg_id);
44}
45
46static inline void mxr_write(struct mxr_device *mdev, u32 reg_id, u32 val)
47{
48 writel(val, mdev->res.mxr_regs + reg_id);
49}
50
51static inline void mxr_write_mask(struct mxr_device *mdev, u32 reg_id,
52 u32 val, u32 mask)
53{
54 u32 old = mxr_read(mdev, reg_id);
55
56 val = (val & mask) | (old & ~mask);
57 writel(val, mdev->res.mxr_regs + reg_id);
58}
59
60void mxr_vsync_set_update(struct mxr_device *mdev, int en)
61{
62 /* block update on vsync */
63 mxr_write_mask(mdev, MXR_STATUS, en ? MXR_STATUS_SYNC_ENABLE : 0,
64 MXR_STATUS_SYNC_ENABLE);
65 vp_write(mdev, VP_SHADOW_UPDATE, en ? VP_SHADOW_UPDATE_ENABLE : 0);
66}
67
68static void __mxr_reg_vp_reset(struct mxr_device *mdev)
69{
70 int tries = 100;
71
72 vp_write(mdev, VP_SRESET, VP_SRESET_PROCESSING);
73 for (tries = 100; tries; --tries) {
74 /* waiting until VP_SRESET_PROCESSING is 0 */
75 if (~vp_read(mdev, VP_SRESET) & VP_SRESET_PROCESSING)
76 break;
77 mdelay(10);
78 }
79 WARN(tries == 0, "failed to reset Video Processor\n");
80}
81
82static void mxr_reg_vp_default_filter(struct mxr_device *mdev);
83
84void mxr_reg_reset(struct mxr_device *mdev)
85{
86 unsigned long flags;
87 u32 val; /* value stored to register */
88
89 spin_lock_irqsave(&mdev->reg_slock, flags);
90 mxr_vsync_set_update(mdev, MXR_DISABLE);
91
92 /* set output in RGB888 mode */
93 mxr_write(mdev, MXR_CFG, MXR_CFG_OUT_YUV444);
94
95 /* 16 beat burst in DMA */
96 mxr_write_mask(mdev, MXR_STATUS, MXR_STATUS_16_BURST,
97 MXR_STATUS_BURST_MASK);
98
99 /* setting default layer priority: layer1 > video > layer0
100 * because typical usage scenario would be
101 * layer0 - framebuffer
102 * video - video overlay
103 * layer1 - OSD
104 */
105 val = MXR_LAYER_CFG_GRP0_VAL(1);
106 val |= MXR_LAYER_CFG_VP_VAL(2);
107 val |= MXR_LAYER_CFG_GRP1_VAL(3);
108 mxr_write(mdev, MXR_LAYER_CFG, val);
109
110 /* use dark gray background color */
111 mxr_write(mdev, MXR_BG_COLOR0, 0x808080);
112 mxr_write(mdev, MXR_BG_COLOR1, 0x808080);
113 mxr_write(mdev, MXR_BG_COLOR2, 0x808080);
114
115 /* setting graphical layers */
116
117 val = MXR_GRP_CFG_COLOR_KEY_DISABLE; /* no blank key */
118 val |= MXR_GRP_CFG_BLEND_PRE_MUL; /* premul mode */
119 val |= MXR_GRP_CFG_ALPHA_VAL(0xff); /* non-transparent alpha */
120
121 /* the same configuration for both layers */
122 mxr_write(mdev, MXR_GRAPHIC_CFG(0), val);
123 mxr_write(mdev, MXR_GRAPHIC_CFG(1), val);
124
125 /* configuration of Video Processor Registers */
126 __mxr_reg_vp_reset(mdev);
127 mxr_reg_vp_default_filter(mdev);
128
129 /* enable all interrupts */
130 mxr_write_mask(mdev, MXR_INT_EN, ~0, MXR_INT_EN_ALL);
131
132 mxr_vsync_set_update(mdev, MXR_ENABLE);
133 spin_unlock_irqrestore(&mdev->reg_slock, flags);
134}
135
136void mxr_reg_graph_format(struct mxr_device *mdev, int idx,
137 const struct mxr_format *fmt, const struct mxr_geometry *geo)
138{
139 u32 val;
140 unsigned long flags;
141
142 spin_lock_irqsave(&mdev->reg_slock, flags);
143 mxr_vsync_set_update(mdev, MXR_DISABLE);
144
145 /* setup format */
146 mxr_write_mask(mdev, MXR_GRAPHIC_CFG(idx),
147 MXR_GRP_CFG_FORMAT_VAL(fmt->cookie), MXR_GRP_CFG_FORMAT_MASK);
148
149 /* setup geometry */
150 mxr_write(mdev, MXR_GRAPHIC_SPAN(idx), geo->src.full_width);
151 val = MXR_GRP_WH_WIDTH(geo->src.width);
152 val |= MXR_GRP_WH_HEIGHT(geo->src.height);
153 val |= MXR_GRP_WH_H_SCALE(geo->x_ratio);
154 val |= MXR_GRP_WH_V_SCALE(geo->y_ratio);
155 mxr_write(mdev, MXR_GRAPHIC_WH(idx), val);
156
157 /* setup offsets in source image */
158 val = MXR_GRP_SXY_SX(geo->src.x_offset);
159 val |= MXR_GRP_SXY_SY(geo->src.y_offset);
160 mxr_write(mdev, MXR_GRAPHIC_SXY(idx), val);
161
162 /* setup offsets in display image */
163 val = MXR_GRP_DXY_DX(geo->dst.x_offset);
164 val |= MXR_GRP_DXY_DY(geo->dst.y_offset);
165 mxr_write(mdev, MXR_GRAPHIC_DXY(idx), val);
166
167 mxr_vsync_set_update(mdev, MXR_ENABLE);
168 spin_unlock_irqrestore(&mdev->reg_slock, flags);
169}
170
171void mxr_reg_vp_format(struct mxr_device *mdev,
172 const struct mxr_format *fmt, const struct mxr_geometry *geo)
173{
174 unsigned long flags;
175
176 spin_lock_irqsave(&mdev->reg_slock, flags);
177 mxr_vsync_set_update(mdev, MXR_DISABLE);
178
179 vp_write_mask(mdev, VP_MODE, fmt->cookie, VP_MODE_FMT_MASK);
180
181 /* setting size of input image */
182 vp_write(mdev, VP_IMG_SIZE_Y, VP_IMG_HSIZE(geo->src.full_width) |
183 VP_IMG_VSIZE(geo->src.full_height));
184 /* chroma height has to reduced by 2 to avoid chroma distorions */
185 vp_write(mdev, VP_IMG_SIZE_C, VP_IMG_HSIZE(geo->src.full_width) |
186 VP_IMG_VSIZE(geo->src.full_height / 2));
187
188 vp_write(mdev, VP_SRC_WIDTH, geo->src.width);
189 vp_write(mdev, VP_SRC_HEIGHT, geo->src.height);
190 vp_write(mdev, VP_SRC_H_POSITION,
191 VP_SRC_H_POSITION_VAL(geo->src.x_offset));
192 vp_write(mdev, VP_SRC_V_POSITION, geo->src.y_offset);
193
194 vp_write(mdev, VP_DST_WIDTH, geo->dst.width);
195 vp_write(mdev, VP_DST_H_POSITION, geo->dst.x_offset);
196 if (geo->dst.field == V4L2_FIELD_INTERLACED) {
197 vp_write(mdev, VP_DST_HEIGHT, geo->dst.height / 2);
198 vp_write(mdev, VP_DST_V_POSITION, geo->dst.y_offset / 2);
199 } else {
200 vp_write(mdev, VP_DST_HEIGHT, geo->dst.height);
201 vp_write(mdev, VP_DST_V_POSITION, geo->dst.y_offset);
202 }
203
204 vp_write(mdev, VP_H_RATIO, geo->x_ratio);
205 vp_write(mdev, VP_V_RATIO, geo->y_ratio);
206
207 vp_write(mdev, VP_ENDIAN_MODE, VP_ENDIAN_MODE_LITTLE);
208
209 mxr_vsync_set_update(mdev, MXR_ENABLE);
210 spin_unlock_irqrestore(&mdev->reg_slock, flags);
211
212}
213
214void mxr_reg_graph_buffer(struct mxr_device *mdev, int idx, dma_addr_t addr)
215{
216 u32 val = addr ? ~0 : 0;
217 unsigned long flags;
218
219 spin_lock_irqsave(&mdev->reg_slock, flags);
220 mxr_vsync_set_update(mdev, MXR_DISABLE);
221
222 if (idx == 0)
223 mxr_write_mask(mdev, MXR_CFG, val, MXR_CFG_GRP0_ENABLE);
224 else
225 mxr_write_mask(mdev, MXR_CFG, val, MXR_CFG_GRP1_ENABLE);
226 mxr_write(mdev, MXR_GRAPHIC_BASE(idx), addr);
227
228 mxr_vsync_set_update(mdev, MXR_ENABLE);
229 spin_unlock_irqrestore(&mdev->reg_slock, flags);
230}
231
232void mxr_reg_vp_buffer(struct mxr_device *mdev,
233 dma_addr_t luma_addr[2], dma_addr_t chroma_addr[2])
234{
235 u32 val = luma_addr[0] ? ~0 : 0;
236 unsigned long flags;
237
238 spin_lock_irqsave(&mdev->reg_slock, flags);
239 mxr_vsync_set_update(mdev, MXR_DISABLE);
240
241 mxr_write_mask(mdev, MXR_CFG, val, MXR_CFG_VP_ENABLE);
242 vp_write_mask(mdev, VP_ENABLE, val, VP_ENABLE_ON);
243 /* TODO: fix tiled mode */
244 vp_write(mdev, VP_TOP_Y_PTR, luma_addr[0]);
245 vp_write(mdev, VP_TOP_C_PTR, chroma_addr[0]);
246 vp_write(mdev, VP_BOT_Y_PTR, luma_addr[1]);
247 vp_write(mdev, VP_BOT_C_PTR, chroma_addr[1]);
248
249 mxr_vsync_set_update(mdev, MXR_ENABLE);
250 spin_unlock_irqrestore(&mdev->reg_slock, flags);
251}
252
253static void mxr_irq_layer_handle(struct mxr_layer *layer)
254{
255 struct list_head *head = &layer->enq_list;
256 struct mxr_buffer *done;
257
258 /* skip non-existing layer */
259 if (layer == NULL)
260 return;
261
262 spin_lock(&layer->enq_slock);
263 if (layer->state == MXR_LAYER_IDLE)
264 goto done;
265
266 done = layer->shadow_buf;
267 layer->shadow_buf = layer->update_buf;
268
269 if (list_empty(head)) {
270 if (layer->state != MXR_LAYER_STREAMING)
271 layer->update_buf = NULL;
272 } else {
273 struct mxr_buffer *next;
274 next = list_first_entry(head, struct mxr_buffer, list);
275 list_del(&next->list);
276 layer->update_buf = next;
277 }
278
279 layer->ops.buffer_set(layer, layer->update_buf);
280
281 if (done && done != layer->shadow_buf)
282 vb2_buffer_done(&done->vb, VB2_BUF_STATE_DONE);
283
284done:
285 spin_unlock(&layer->enq_slock);
286}
287
288irqreturn_t mxr_irq_handler(int irq, void *dev_data)
289{
290 struct mxr_device *mdev = dev_data;
291 u32 i, val;
292
293 spin_lock(&mdev->reg_slock);
294 val = mxr_read(mdev, MXR_INT_STATUS);
295
296 /* wake up process waiting for VSYNC */
297 if (val & MXR_INT_STATUS_VSYNC) {
298 set_bit(MXR_EVENT_VSYNC, &mdev->event_flags);
299 wake_up(&mdev->event_queue);
300 }
301
302 /* clear interrupts */
303 if (~val & MXR_INT_EN_VSYNC) {
304 /* vsync interrupt use different bit for read and clear */
305 val &= ~MXR_INT_EN_VSYNC;
306 val |= MXR_INT_CLEAR_VSYNC;
307 }
308 mxr_write(mdev, MXR_INT_STATUS, val);
309
310 spin_unlock(&mdev->reg_slock);
311 /* leave on non-vsync event */
312 if (~val & MXR_INT_CLEAR_VSYNC)
313 return IRQ_HANDLED;
314 for (i = 0; i < MXR_MAX_LAYERS; ++i)
315 mxr_irq_layer_handle(mdev->layer[i]);
316 return IRQ_HANDLED;
317}
318
319void mxr_reg_s_output(struct mxr_device *mdev, int cookie)
320{
321 u32 val;
322
323 val = cookie == 0 ? MXR_CFG_DST_SDO : MXR_CFG_DST_HDMI;
324 mxr_write_mask(mdev, MXR_CFG, val, MXR_CFG_DST_MASK);
325}
326
327void mxr_reg_streamon(struct mxr_device *mdev)
328{
329 unsigned long flags;
330
331 spin_lock_irqsave(&mdev->reg_slock, flags);
332 /* single write -> no need to block vsync update */
333
334 /* start MIXER */
335 mxr_write_mask(mdev, MXR_STATUS, ~0, MXR_STATUS_REG_RUN);
336
337 spin_unlock_irqrestore(&mdev->reg_slock, flags);
338}
339
340void mxr_reg_streamoff(struct mxr_device *mdev)
341{
342 unsigned long flags;
343
344 spin_lock_irqsave(&mdev->reg_slock, flags);
345 /* single write -> no need to block vsync update */
346
347 /* stop MIXER */
348 mxr_write_mask(mdev, MXR_STATUS, 0, MXR_STATUS_REG_RUN);
349
350 spin_unlock_irqrestore(&mdev->reg_slock, flags);
351}
352
353int mxr_reg_wait4vsync(struct mxr_device *mdev)
354{
355 int ret;
356
357 clear_bit(MXR_EVENT_VSYNC, &mdev->event_flags);
358 /* TODO: consider adding interruptible */
359 ret = wait_event_timeout(mdev->event_queue,
360 test_bit(MXR_EVENT_VSYNC, &mdev->event_flags),
361 msecs_to_jiffies(1000));
362 if (ret > 0)
363 return 0;
364 if (ret < 0)
365 return ret;
366 mxr_warn(mdev, "no vsync detected - timeout\n");
367 return -ETIME;
368}
369
370void mxr_reg_set_mbus_fmt(struct mxr_device *mdev,
371 struct v4l2_mbus_framefmt *fmt)
372{
373 u32 val = 0;
374 unsigned long flags;
375
376 spin_lock_irqsave(&mdev->reg_slock, flags);
377 mxr_vsync_set_update(mdev, MXR_DISABLE);
378
379 /* choosing between interlace and progressive mode */
380 if (fmt->field == V4L2_FIELD_INTERLACED)
381 val |= MXR_CFG_SCAN_INTERLACE;
382 else
383 val |= MXR_CFG_SCAN_PROGRASSIVE;
384
385 /* choosing between porper HD and SD mode */
386 if (fmt->height == 480)
387 val |= MXR_CFG_SCAN_NTSC | MXR_CFG_SCAN_SD;
388 else if (fmt->height == 576)
389 val |= MXR_CFG_SCAN_PAL | MXR_CFG_SCAN_SD;
390 else if (fmt->height == 720)
391 val |= MXR_CFG_SCAN_HD_720 | MXR_CFG_SCAN_HD;
392 else if (fmt->height == 1080)
393 val |= MXR_CFG_SCAN_HD_1080 | MXR_CFG_SCAN_HD;
394 else
395 WARN(1, "unrecognized mbus height %u!\n", fmt->height);
396
397 mxr_write_mask(mdev, MXR_CFG, val, MXR_CFG_SCAN_MASK);
398
399 val = (fmt->field == V4L2_FIELD_INTERLACED) ? ~0 : 0;
400 vp_write_mask(mdev, VP_MODE, val,
401 VP_MODE_LINE_SKIP | VP_MODE_FIELD_ID_AUTO_TOGGLING);
402
403 mxr_vsync_set_update(mdev, MXR_ENABLE);
404 spin_unlock_irqrestore(&mdev->reg_slock, flags);
405}
406
407void mxr_reg_graph_layer_stream(struct mxr_device *mdev, int idx, int en)
408{
409 /* no extra actions need to be done */
410}
411
412void mxr_reg_vp_layer_stream(struct mxr_device *mdev, int en)
413{
414 /* no extra actions need to be done */
415}
416
417static const u8 filter_y_horiz_tap8[] = {
418 0, -1, -1, -1, -1, -1, -1, -1,
419 -1, -1, -1, -1, -1, 0, 0, 0,
420 0, 2, 4, 5, 6, 6, 6, 6,
421 6, 5, 5, 4, 3, 2, 1, 1,
422 0, -6, -12, -16, -18, -20, -21, -20,
423 -20, -18, -16, -13, -10, -8, -5, -2,
424 127, 126, 125, 121, 114, 107, 99, 89,
425 79, 68, 57, 46, 35, 25, 16, 8,
426};
427
428static const u8 filter_y_vert_tap4[] = {
429 0, -3, -6, -8, -8, -8, -8, -7,
430 -6, -5, -4, -3, -2, -1, -1, 0,
431 127, 126, 124, 118, 111, 102, 92, 81,
432 70, 59, 48, 37, 27, 19, 11, 5,
433 0, 5, 11, 19, 27, 37, 48, 59,
434 70, 81, 92, 102, 111, 118, 124, 126,
435 0, 0, -1, -1, -2, -3, -4, -5,
436 -6, -7, -8, -8, -8, -8, -6, -3,
437};
438
439static const u8 filter_cr_horiz_tap4[] = {
440 0, -3, -6, -8, -8, -8, -8, -7,
441 -6, -5, -4, -3, -2, -1, -1, 0,
442 127, 126, 124, 118, 111, 102, 92, 81,
443 70, 59, 48, 37, 27, 19, 11, 5,
444};
445
446static inline void mxr_reg_vp_filter_set(struct mxr_device *mdev,
447 int reg_id, const u8 *data, unsigned int size)
448{
449 /* assure 4-byte align */
450 BUG_ON(size & 3);
451 for (; size; size -= 4, reg_id += 4, data += 4) {
452 u32 val = (data[0] << 24) | (data[1] << 16) |
453 (data[2] << 8) | data[3];
454 vp_write(mdev, reg_id, val);
455 }
456}
457
458static void mxr_reg_vp_default_filter(struct mxr_device *mdev)
459{
460 mxr_reg_vp_filter_set(mdev, VP_POLY8_Y0_LL,
461 filter_y_horiz_tap8, sizeof filter_y_horiz_tap8);
462 mxr_reg_vp_filter_set(mdev, VP_POLY4_Y0_LL,
463 filter_y_vert_tap4, sizeof filter_y_vert_tap4);
464 mxr_reg_vp_filter_set(mdev, VP_POLY4_C0_LL,
465 filter_cr_horiz_tap4, sizeof filter_cr_horiz_tap4);
466}
467
468static void mxr_reg_mxr_dump(struct mxr_device *mdev)
469{
470#define DUMPREG(reg_id) \
471do { \
472 mxr_dbg(mdev, #reg_id " = %08x\n", \
473 (u32)readl(mdev->res.mxr_regs + reg_id)); \
474} while (0)
475
476 DUMPREG(MXR_STATUS);
477 DUMPREG(MXR_CFG);
478 DUMPREG(MXR_INT_EN);
479 DUMPREG(MXR_INT_STATUS);
480
481 DUMPREG(MXR_LAYER_CFG);
482 DUMPREG(MXR_VIDEO_CFG);
483
484 DUMPREG(MXR_GRAPHIC0_CFG);
485 DUMPREG(MXR_GRAPHIC0_BASE);
486 DUMPREG(MXR_GRAPHIC0_SPAN);
487 DUMPREG(MXR_GRAPHIC0_WH);
488 DUMPREG(MXR_GRAPHIC0_SXY);
489 DUMPREG(MXR_GRAPHIC0_DXY);
490
491 DUMPREG(MXR_GRAPHIC1_CFG);
492 DUMPREG(MXR_GRAPHIC1_BASE);
493 DUMPREG(MXR_GRAPHIC1_SPAN);
494 DUMPREG(MXR_GRAPHIC1_WH);
495 DUMPREG(MXR_GRAPHIC1_SXY);
496 DUMPREG(MXR_GRAPHIC1_DXY);
497#undef DUMPREG
498}
499
500static void mxr_reg_vp_dump(struct mxr_device *mdev)
501{
502#define DUMPREG(reg_id) \
503do { \
504 mxr_dbg(mdev, #reg_id " = %08x\n", \
505 (u32) readl(mdev->res.vp_regs + reg_id)); \
506} while (0)
507
508
509 DUMPREG(VP_ENABLE);
510 DUMPREG(VP_SRESET);
511 DUMPREG(VP_SHADOW_UPDATE);
512 DUMPREG(VP_FIELD_ID);
513 DUMPREG(VP_MODE);
514 DUMPREG(VP_IMG_SIZE_Y);
515 DUMPREG(VP_IMG_SIZE_C);
516 DUMPREG(VP_PER_RATE_CTRL);
517 DUMPREG(VP_TOP_Y_PTR);
518 DUMPREG(VP_BOT_Y_PTR);
519 DUMPREG(VP_TOP_C_PTR);
520 DUMPREG(VP_BOT_C_PTR);
521 DUMPREG(VP_ENDIAN_MODE);
522 DUMPREG(VP_SRC_H_POSITION);
523 DUMPREG(VP_SRC_V_POSITION);
524 DUMPREG(VP_SRC_WIDTH);
525 DUMPREG(VP_SRC_HEIGHT);
526 DUMPREG(VP_DST_H_POSITION);
527 DUMPREG(VP_DST_V_POSITION);
528 DUMPREG(VP_DST_WIDTH);
529 DUMPREG(VP_DST_HEIGHT);
530 DUMPREG(VP_H_RATIO);
531 DUMPREG(VP_V_RATIO);
532
533#undef DUMPREG
534}
535
536void mxr_reg_dump(struct mxr_device *mdev)
537{
538 mxr_reg_mxr_dump(mdev);
539 mxr_reg_vp_dump(mdev);
540}
541
diff --git a/drivers/media/video/s5p-tv/mixer_video.c b/drivers/media/video/s5p-tv/mixer_video.c
new file mode 100644
index 00000000000..43ac22f35bc
--- /dev/null
+++ b/drivers/media/video/s5p-tv/mixer_video.c
@@ -0,0 +1,1006 @@
1/*
2 * Samsung TV Mixer 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 Foundation. either version 2 of the License,
11 * or (at your option) any later version
12 */
13
14#include "mixer.h"
15
16#include <media/v4l2-ioctl.h>
17#include <linux/videodev2.h>
18#include <linux/mm.h>
19#include <linux/version.h>
20#include <linux/timer.h>
21#include <media/videobuf2-dma-contig.h>
22
23static int find_reg_callback(struct device *dev, void *p)
24{
25 struct v4l2_subdev **sd = p;
26
27 *sd = dev_get_drvdata(dev);
28 /* non-zero value stops iteration */
29 return 1;
30}
31
32static struct v4l2_subdev *find_and_register_subdev(
33 struct mxr_device *mdev, char *module_name)
34{
35 struct device_driver *drv;
36 struct v4l2_subdev *sd = NULL;
37 int ret;
38
39 /* TODO: add waiting until probe is finished */
40 drv = driver_find(module_name, &platform_bus_type);
41 if (!drv) {
42 mxr_warn(mdev, "module %s is missing\n", module_name);
43 return NULL;
44 }
45 /* driver refcnt is increased, it is safe to iterate over devices */
46 ret = driver_for_each_device(drv, NULL, &sd, find_reg_callback);
47 /* ret == 0 means that find_reg_callback was never executed */
48 if (sd == NULL) {
49 mxr_warn(mdev, "module %s provides no subdev!\n", module_name);
50 goto done;
51 }
52 /* v4l2_device_register_subdev detects if sd is NULL */
53 ret = v4l2_device_register_subdev(&mdev->v4l2_dev, sd);
54 if (ret) {
55 mxr_warn(mdev, "failed to register subdev %s\n", sd->name);
56 sd = NULL;
57 }
58
59done:
60 put_driver(drv);
61 return sd;
62}
63
64int __devinit mxr_acquire_video(struct mxr_device *mdev,
65 struct mxr_output_conf *output_conf, int output_count)
66{
67 struct device *dev = mdev->dev;
68 struct v4l2_device *v4l2_dev = &mdev->v4l2_dev;
69 int i;
70 int ret = 0;
71 struct v4l2_subdev *sd;
72
73 strlcpy(v4l2_dev->name, dev_name(mdev->dev), sizeof(v4l2_dev->name));
74 /* prepare context for V4L2 device */
75 ret = v4l2_device_register(dev, v4l2_dev);
76 if (ret) {
77 mxr_err(mdev, "could not register v4l2 device.\n");
78 goto fail;
79 }
80
81 mdev->alloc_ctx = vb2_dma_contig_init_ctx(mdev->dev);
82 if (IS_ERR_OR_NULL(mdev->alloc_ctx)) {
83 mxr_err(mdev, "could not acquire vb2 allocator\n");
84 goto fail_v4l2_dev;
85 }
86
87 /* registering outputs */
88 mdev->output_cnt = 0;
89 for (i = 0; i < output_count; ++i) {
90 struct mxr_output_conf *conf = &output_conf[i];
91 struct mxr_output *out;
92
93 sd = find_and_register_subdev(mdev, conf->module_name);
94 /* trying to register next output */
95 if (sd == NULL)
96 continue;
97 out = kzalloc(sizeof *out, GFP_KERNEL);
98 if (out == NULL) {
99 mxr_err(mdev, "no memory for '%s'\n",
100 conf->output_name);
101 ret = -ENOMEM;
102 /* registered subdevs are removed in fail_v4l2_dev */
103 goto fail_output;
104 }
105 strlcpy(out->name, conf->output_name, sizeof(out->name));
106 out->sd = sd;
107 out->cookie = conf->cookie;
108 mdev->output[mdev->output_cnt++] = out;
109 mxr_info(mdev, "added output '%s' from module '%s'\n",
110 conf->output_name, conf->module_name);
111 /* checking if maximal number of outputs is reached */
112 if (mdev->output_cnt >= MXR_MAX_OUTPUTS)
113 break;
114 }
115
116 if (mdev->output_cnt == 0) {
117 mxr_err(mdev, "failed to register any output\n");
118 ret = -ENODEV;
119 /* skipping fail_output because there is nothing to free */
120 goto fail_vb2_allocator;
121 }
122
123 return 0;
124
125fail_output:
126 /* kfree is NULL-safe */
127 for (i = 0; i < mdev->output_cnt; ++i)
128 kfree(mdev->output[i]);
129 memset(mdev->output, 0, sizeof mdev->output);
130
131fail_vb2_allocator:
132 /* freeing allocator context */
133 vb2_dma_contig_cleanup_ctx(mdev->alloc_ctx);
134
135fail_v4l2_dev:
136 /* NOTE: automatically unregister all subdevs */
137 v4l2_device_unregister(v4l2_dev);
138
139fail:
140 return ret;
141}
142
143void __devexit mxr_release_video(struct mxr_device *mdev)
144{
145 int i;
146
147 /* kfree is NULL-safe */
148 for (i = 0; i < mdev->output_cnt; ++i)
149 kfree(mdev->output[i]);
150
151 vb2_dma_contig_cleanup_ctx(mdev->alloc_ctx);
152 v4l2_device_unregister(&mdev->v4l2_dev);
153}
154
155static int mxr_querycap(struct file *file, void *priv,
156 struct v4l2_capability *cap)
157{
158 struct mxr_layer *layer = video_drvdata(file);
159
160 mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
161
162 strlcpy(cap->driver, MXR_DRIVER_NAME, sizeof cap->driver);
163 strlcpy(cap->card, layer->vfd.name, sizeof cap->card);
164 sprintf(cap->bus_info, "%d", layer->idx);
165 cap->version = KERNEL_VERSION(0, 1, 0);
166 cap->capabilities = V4L2_CAP_STREAMING |
167 V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_VIDEO_OUTPUT_MPLANE;
168
169 return 0;
170}
171
172/* Geometry handling */
173static void mxr_layer_geo_fix(struct mxr_layer *layer)
174{
175 struct mxr_device *mdev = layer->mdev;
176 struct v4l2_mbus_framefmt mbus_fmt;
177
178 /* TODO: add some dirty flag to avoid unnecessary adjustments */
179 mxr_get_mbus_fmt(mdev, &mbus_fmt);
180 layer->geo.dst.full_width = mbus_fmt.width;
181 layer->geo.dst.full_height = mbus_fmt.height;
182 layer->geo.dst.field = mbus_fmt.field;
183 layer->ops.fix_geometry(layer);
184}
185
186static void mxr_layer_default_geo(struct mxr_layer *layer)
187{
188 struct mxr_device *mdev = layer->mdev;
189 struct v4l2_mbus_framefmt mbus_fmt;
190
191 memset(&layer->geo, 0, sizeof layer->geo);
192
193 mxr_get_mbus_fmt(mdev, &mbus_fmt);
194
195 layer->geo.dst.full_width = mbus_fmt.width;
196 layer->geo.dst.full_height = mbus_fmt.height;
197 layer->geo.dst.width = layer->geo.dst.full_width;
198 layer->geo.dst.height = layer->geo.dst.full_height;
199 layer->geo.dst.field = mbus_fmt.field;
200
201 layer->geo.src.full_width = mbus_fmt.width;
202 layer->geo.src.full_height = mbus_fmt.height;
203 layer->geo.src.width = layer->geo.src.full_width;
204 layer->geo.src.height = layer->geo.src.full_height;
205
206 layer->ops.fix_geometry(layer);
207}
208
209static void mxr_geometry_dump(struct mxr_device *mdev, struct mxr_geometry *geo)
210{
211 mxr_dbg(mdev, "src.full_size = (%u, %u)\n",
212 geo->src.full_width, geo->src.full_height);
213 mxr_dbg(mdev, "src.size = (%u, %u)\n",
214 geo->src.width, geo->src.height);
215 mxr_dbg(mdev, "src.offset = (%u, %u)\n",
216 geo->src.x_offset, geo->src.y_offset);
217 mxr_dbg(mdev, "dst.full_size = (%u, %u)\n",
218 geo->dst.full_width, geo->dst.full_height);
219 mxr_dbg(mdev, "dst.size = (%u, %u)\n",
220 geo->dst.width, geo->dst.height);
221 mxr_dbg(mdev, "dst.offset = (%u, %u)\n",
222 geo->dst.x_offset, geo->dst.y_offset);
223 mxr_dbg(mdev, "ratio = (%u, %u)\n",
224 geo->x_ratio, geo->y_ratio);
225}
226
227
228static const struct mxr_format *find_format_by_fourcc(
229 struct mxr_layer *layer, unsigned long fourcc);
230static const struct mxr_format *find_format_by_index(
231 struct mxr_layer *layer, unsigned long index);
232
233static int mxr_enum_fmt(struct file *file, void *priv,
234 struct v4l2_fmtdesc *f)
235{
236 struct mxr_layer *layer = video_drvdata(file);
237 struct mxr_device *mdev = layer->mdev;
238 const struct mxr_format *fmt;
239
240 mxr_dbg(mdev, "%s\n", __func__);
241 fmt = find_format_by_index(layer, f->index);
242 if (fmt == NULL)
243 return -EINVAL;
244
245 strlcpy(f->description, fmt->name, sizeof(f->description));
246 f->pixelformat = fmt->fourcc;
247
248 return 0;
249}
250
251static int mxr_s_fmt(struct file *file, void *priv,
252 struct v4l2_format *f)
253{
254 struct mxr_layer *layer = video_drvdata(file);
255 const struct mxr_format *fmt;
256 struct v4l2_pix_format_mplane *pix;
257 struct mxr_device *mdev = layer->mdev;
258 struct mxr_geometry *geo = &layer->geo;
259
260 mxr_dbg(mdev, "%s:%d\n", __func__, __LINE__);
261
262 pix = &f->fmt.pix_mp;
263 fmt = find_format_by_fourcc(layer, pix->pixelformat);
264 if (fmt == NULL) {
265 mxr_warn(mdev, "not recognized fourcc: %08x\n",
266 pix->pixelformat);
267 return -EINVAL;
268 }
269 layer->fmt = fmt;
270 geo->src.full_width = pix->width;
271 geo->src.width = pix->width;
272 geo->src.full_height = pix->height;
273 geo->src.height = pix->height;
274 /* assure consistency of geometry */
275 mxr_layer_geo_fix(layer);
276 mxr_dbg(mdev, "width=%u height=%u span=%u\n",
277 geo->src.width, geo->src.height, geo->src.full_width);
278
279 return 0;
280}
281
282static unsigned int divup(unsigned int divident, unsigned int divisor)
283{
284 return (divident + divisor - 1) / divisor;
285}
286
287unsigned long mxr_get_plane_size(const struct mxr_block *blk,
288 unsigned int width, unsigned int height)
289{
290 unsigned int bl_width = divup(width, blk->width);
291 unsigned int bl_height = divup(height, blk->height);
292
293 return bl_width * bl_height * blk->size;
294}
295
296static void mxr_mplane_fill(struct v4l2_plane_pix_format *planes,
297 const struct mxr_format *fmt, u32 width, u32 height)
298{
299 int i;
300
301 memset(planes, 0, sizeof(*planes) * fmt->num_subframes);
302 for (i = 0; i < fmt->num_planes; ++i) {
303 struct v4l2_plane_pix_format *plane = planes
304 + fmt->plane2subframe[i];
305 const struct mxr_block *blk = &fmt->plane[i];
306 u32 bl_width = divup(width, blk->width);
307 u32 bl_height = divup(height, blk->height);
308 u32 sizeimage = bl_width * bl_height * blk->size;
309 u16 bytesperline = bl_width * blk->size / blk->height;
310
311 plane->sizeimage += sizeimage;
312 plane->bytesperline = max(plane->bytesperline, bytesperline);
313 }
314}
315
316static int mxr_g_fmt(struct file *file, void *priv,
317 struct v4l2_format *f)
318{
319 struct mxr_layer *layer = video_drvdata(file);
320 struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp;
321
322 mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
323
324 pix->width = layer->geo.src.full_width;
325 pix->height = layer->geo.src.full_height;
326 pix->field = V4L2_FIELD_NONE;
327 pix->pixelformat = layer->fmt->fourcc;
328 pix->colorspace = layer->fmt->colorspace;
329 mxr_mplane_fill(pix->plane_fmt, layer->fmt, pix->width, pix->height);
330
331 return 0;
332}
333
334static inline struct mxr_crop *choose_crop_by_type(struct mxr_geometry *geo,
335 enum v4l2_buf_type type)
336{
337 switch (type) {
338 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
339 case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
340 return &geo->dst;
341 case V4L2_BUF_TYPE_VIDEO_OVERLAY:
342 return &geo->src;
343 default:
344 return NULL;
345 }
346}
347
348static int mxr_g_crop(struct file *file, void *fh, struct v4l2_crop *a)
349{
350 struct mxr_layer *layer = video_drvdata(file);
351 struct mxr_crop *crop;
352
353 mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
354 crop = choose_crop_by_type(&layer->geo, a->type);
355 if (crop == NULL)
356 return -EINVAL;
357 mxr_layer_geo_fix(layer);
358 a->c.left = crop->x_offset;
359 a->c.top = crop->y_offset;
360 a->c.width = crop->width;
361 a->c.height = crop->height;
362 return 0;
363}
364
365static int mxr_s_crop(struct file *file, void *fh, struct v4l2_crop *a)
366{
367 struct mxr_layer *layer = video_drvdata(file);
368 struct mxr_crop *crop;
369
370 mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
371 crop = choose_crop_by_type(&layer->geo, a->type);
372 if (crop == NULL)
373 return -EINVAL;
374 crop->x_offset = a->c.left;
375 crop->y_offset = a->c.top;
376 crop->width = a->c.width;
377 crop->height = a->c.height;
378 mxr_layer_geo_fix(layer);
379 return 0;
380}
381
382static int mxr_cropcap(struct file *file, void *fh, struct v4l2_cropcap *a)
383{
384 struct mxr_layer *layer = video_drvdata(file);
385 struct mxr_crop *crop;
386
387 mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
388 crop = choose_crop_by_type(&layer->geo, a->type);
389 if (crop == NULL)
390 return -EINVAL;
391 mxr_layer_geo_fix(layer);
392 a->bounds.left = 0;
393 a->bounds.top = 0;
394 a->bounds.width = crop->full_width;
395 a->bounds.top = crop->full_height;
396 a->defrect = a->bounds;
397 /* setting pixel aspect to 1/1 */
398 a->pixelaspect.numerator = 1;
399 a->pixelaspect.denominator = 1;
400 return 0;
401}
402
403static int mxr_enum_dv_presets(struct file *file, void *fh,
404 struct v4l2_dv_enum_preset *preset)
405{
406 struct mxr_layer *layer = video_drvdata(file);
407 struct mxr_device *mdev = layer->mdev;
408 int ret;
409
410 /* lock protects from changing sd_out */
411 mutex_lock(&mdev->mutex);
412 ret = v4l2_subdev_call(to_outsd(mdev), video, enum_dv_presets, preset);
413 mutex_unlock(&mdev->mutex);
414
415 return ret ? -EINVAL : 0;
416}
417
418static int mxr_s_dv_preset(struct file *file, void *fh,
419 struct v4l2_dv_preset *preset)
420{
421 struct mxr_layer *layer = video_drvdata(file);
422 struct mxr_device *mdev = layer->mdev;
423 int ret;
424
425 /* lock protects from changing sd_out */
426 mutex_lock(&mdev->mutex);
427
428 /* preset change cannot be done while there is an entity
429 * dependant on output configuration
430 */
431 if (mdev->n_output > 0) {
432 mutex_unlock(&mdev->mutex);
433 return -EBUSY;
434 }
435
436 ret = v4l2_subdev_call(to_outsd(mdev), video, s_dv_preset, preset);
437
438 mutex_unlock(&mdev->mutex);
439
440 /* any failure should return EINVAL according to V4L2 doc */
441 return ret ? -EINVAL : 0;
442}
443
444static int mxr_g_dv_preset(struct file *file, void *fh,
445 struct v4l2_dv_preset *preset)
446{
447 struct mxr_layer *layer = video_drvdata(file);
448 struct mxr_device *mdev = layer->mdev;
449 int ret;
450
451 /* lock protects from changing sd_out */
452 mutex_lock(&mdev->mutex);
453 ret = v4l2_subdev_call(to_outsd(mdev), video, g_dv_preset, preset);
454 mutex_unlock(&mdev->mutex);
455
456 return ret ? -EINVAL : 0;
457}
458
459static int mxr_s_std(struct file *file, void *fh, v4l2_std_id *norm)
460{
461 struct mxr_layer *layer = video_drvdata(file);
462 struct mxr_device *mdev = layer->mdev;
463 int ret;
464
465 /* lock protects from changing sd_out */
466 mutex_lock(&mdev->mutex);
467
468 /* standard change cannot be done while there is an entity
469 * dependant on output configuration
470 */
471 if (mdev->n_output > 0) {
472 mutex_unlock(&mdev->mutex);
473 return -EBUSY;
474 }
475
476 ret = v4l2_subdev_call(to_outsd(mdev), video, s_std_output, *norm);
477
478 mutex_unlock(&mdev->mutex);
479
480 return ret ? -EINVAL : 0;
481}
482
483static int mxr_g_std(struct file *file, void *fh, v4l2_std_id *norm)
484{
485 struct mxr_layer *layer = video_drvdata(file);
486 struct mxr_device *mdev = layer->mdev;
487 int ret;
488
489 /* lock protects from changing sd_out */
490 mutex_lock(&mdev->mutex);
491 ret = v4l2_subdev_call(to_outsd(mdev), video, g_std_output, norm);
492 mutex_unlock(&mdev->mutex);
493
494 return ret ? -EINVAL : 0;
495}
496
497static int mxr_enum_output(struct file *file, void *fh, struct v4l2_output *a)
498{
499 struct mxr_layer *layer = video_drvdata(file);
500 struct mxr_device *mdev = layer->mdev;
501 struct mxr_output *out;
502 struct v4l2_subdev *sd;
503
504 if (a->index >= mdev->output_cnt)
505 return -EINVAL;
506 out = mdev->output[a->index];
507 BUG_ON(out == NULL);
508 sd = out->sd;
509 strlcpy(a->name, out->name, sizeof(a->name));
510
511 /* try to obtain supported tv norms */
512 v4l2_subdev_call(sd, video, g_tvnorms_output, &a->std);
513 a->capabilities = 0;
514 if (sd->ops->video && sd->ops->video->s_dv_preset)
515 a->capabilities |= V4L2_OUT_CAP_PRESETS;
516 if (sd->ops->video && sd->ops->video->s_std_output)
517 a->capabilities |= V4L2_OUT_CAP_STD;
518 a->type = V4L2_OUTPUT_TYPE_ANALOG;
519
520 return 0;
521}
522
523static int mxr_s_output(struct file *file, void *fh, unsigned int i)
524{
525 struct video_device *vfd = video_devdata(file);
526 struct mxr_layer *layer = video_drvdata(file);
527 struct mxr_device *mdev = layer->mdev;
528 int ret = 0;
529
530 if (i >= mdev->output_cnt || mdev->output[i] == NULL)
531 return -EINVAL;
532
533 mutex_lock(&mdev->mutex);
534 if (mdev->n_output > 0) {
535 ret = -EBUSY;
536 goto done;
537 }
538 mdev->current_output = i;
539 vfd->tvnorms = 0;
540 v4l2_subdev_call(to_outsd(mdev), video, g_tvnorms_output,
541 &vfd->tvnorms);
542 mxr_dbg(mdev, "tvnorms = %08llx\n", vfd->tvnorms);
543
544done:
545 mutex_unlock(&mdev->mutex);
546 return ret;
547}
548
549static int mxr_g_output(struct file *file, void *fh, unsigned int *p)
550{
551 struct mxr_layer *layer = video_drvdata(file);
552 struct mxr_device *mdev = layer->mdev;
553
554 mutex_lock(&mdev->mutex);
555 *p = mdev->current_output;
556 mutex_unlock(&mdev->mutex);
557
558 return 0;
559}
560
561static int mxr_reqbufs(struct file *file, void *priv,
562 struct v4l2_requestbuffers *p)
563{
564 struct mxr_layer *layer = video_drvdata(file);
565
566 mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
567 return vb2_reqbufs(&layer->vb_queue, p);
568}
569
570static int mxr_querybuf(struct file *file, void *priv, struct v4l2_buffer *p)
571{
572 struct mxr_layer *layer = video_drvdata(file);
573
574 mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
575 return vb2_querybuf(&layer->vb_queue, p);
576}
577
578static int mxr_qbuf(struct file *file, void *priv, struct v4l2_buffer *p)
579{
580 struct mxr_layer *layer = video_drvdata(file);
581
582 mxr_dbg(layer->mdev, "%s:%d(%d)\n", __func__, __LINE__, p->index);
583 return vb2_qbuf(&layer->vb_queue, p);
584}
585
586static int mxr_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
587{
588 struct mxr_layer *layer = video_drvdata(file);
589
590 mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
591 return vb2_dqbuf(&layer->vb_queue, p, file->f_flags & O_NONBLOCK);
592}
593
594static int mxr_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
595{
596 struct mxr_layer *layer = video_drvdata(file);
597
598 mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
599 return vb2_streamon(&layer->vb_queue, i);
600}
601
602static int mxr_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
603{
604 struct mxr_layer *layer = video_drvdata(file);
605
606 mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
607 return vb2_streamoff(&layer->vb_queue, i);
608}
609
610static const struct v4l2_ioctl_ops mxr_ioctl_ops = {
611 .vidioc_querycap = mxr_querycap,
612 /* format handling */
613 .vidioc_enum_fmt_vid_out = mxr_enum_fmt,
614 .vidioc_s_fmt_vid_out_mplane = mxr_s_fmt,
615 .vidioc_g_fmt_vid_out_mplane = mxr_g_fmt,
616 /* buffer control */
617 .vidioc_reqbufs = mxr_reqbufs,
618 .vidioc_querybuf = mxr_querybuf,
619 .vidioc_qbuf = mxr_qbuf,
620 .vidioc_dqbuf = mxr_dqbuf,
621 /* Streaming control */
622 .vidioc_streamon = mxr_streamon,
623 .vidioc_streamoff = mxr_streamoff,
624 /* Preset functions */
625 .vidioc_enum_dv_presets = mxr_enum_dv_presets,
626 .vidioc_s_dv_preset = mxr_s_dv_preset,
627 .vidioc_g_dv_preset = mxr_g_dv_preset,
628 /* analog TV standard functions */
629 .vidioc_s_std = mxr_s_std,
630 .vidioc_g_std = mxr_g_std,
631 /* Output handling */
632 .vidioc_enum_output = mxr_enum_output,
633 .vidioc_s_output = mxr_s_output,
634 .vidioc_g_output = mxr_g_output,
635 /* Crop ioctls */
636 .vidioc_g_crop = mxr_g_crop,
637 .vidioc_s_crop = mxr_s_crop,
638 .vidioc_cropcap = mxr_cropcap,
639};
640
641static int mxr_video_open(struct file *file)
642{
643 struct mxr_layer *layer = video_drvdata(file);
644 struct mxr_device *mdev = layer->mdev;
645 int ret = 0;
646
647 mxr_dbg(mdev, "%s:%d\n", __func__, __LINE__);
648 /* assure device probe is finished */
649 wait_for_device_probe();
650 /* creating context for file descriptor */
651 ret = v4l2_fh_open(file);
652 if (ret) {
653 mxr_err(mdev, "v4l2_fh_open failed\n");
654 return ret;
655 }
656
657 /* leaving if layer is already initialized */
658 if (!v4l2_fh_is_singular_file(file))
659 return 0;
660
661 /* FIXME: should power be enabled on open? */
662 ret = mxr_power_get(mdev);
663 if (ret) {
664 mxr_err(mdev, "power on failed\n");
665 goto fail_fh_open;
666 }
667
668 ret = vb2_queue_init(&layer->vb_queue);
669 if (ret != 0) {
670 mxr_err(mdev, "failed to initialize vb2 queue\n");
671 goto fail_power;
672 }
673 /* set default format, first on the list */
674 layer->fmt = layer->fmt_array[0];
675 /* setup default geometry */
676 mxr_layer_default_geo(layer);
677
678 return 0;
679
680fail_power:
681 mxr_power_put(mdev);
682
683fail_fh_open:
684 v4l2_fh_release(file);
685
686 return ret;
687}
688
689static unsigned int
690mxr_video_poll(struct file *file, struct poll_table_struct *wait)
691{
692 struct mxr_layer *layer = video_drvdata(file);
693
694 mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
695
696 return vb2_poll(&layer->vb_queue, file, wait);
697}
698
699static int mxr_video_mmap(struct file *file, struct vm_area_struct *vma)
700{
701 struct mxr_layer *layer = video_drvdata(file);
702
703 mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
704
705 return vb2_mmap(&layer->vb_queue, vma);
706}
707
708static int mxr_video_release(struct file *file)
709{
710 struct mxr_layer *layer = video_drvdata(file);
711
712 mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
713 if (v4l2_fh_is_singular_file(file)) {
714 vb2_queue_release(&layer->vb_queue);
715 mxr_power_put(layer->mdev);
716 }
717 v4l2_fh_release(file);
718 return 0;
719}
720
721static const struct v4l2_file_operations mxr_fops = {
722 .owner = THIS_MODULE,
723 .open = mxr_video_open,
724 .poll = mxr_video_poll,
725 .mmap = mxr_video_mmap,
726 .release = mxr_video_release,
727 .unlocked_ioctl = video_ioctl2,
728};
729
730static int queue_setup(struct vb2_queue *vq, unsigned int *nbuffers,
731 unsigned int *nplanes, unsigned long sizes[],
732 void *alloc_ctxs[])
733{
734 struct mxr_layer *layer = vb2_get_drv_priv(vq);
735 const struct mxr_format *fmt = layer->fmt;
736 int i;
737 struct mxr_device *mdev = layer->mdev;
738 struct v4l2_plane_pix_format planes[3];
739
740 mxr_dbg(mdev, "%s\n", __func__);
741 /* checking if format was configured */
742 if (fmt == NULL)
743 return -EINVAL;
744 mxr_dbg(mdev, "fmt = %s\n", fmt->name);
745 mxr_mplane_fill(planes, fmt, layer->geo.src.full_width,
746 layer->geo.src.full_height);
747
748 *nplanes = fmt->num_subframes;
749 for (i = 0; i < fmt->num_subframes; ++i) {
750 alloc_ctxs[i] = layer->mdev->alloc_ctx;
751 sizes[i] = PAGE_ALIGN(planes[i].sizeimage);
752 mxr_dbg(mdev, "size[%d] = %08lx\n", i, sizes[i]);
753 }
754
755 if (*nbuffers == 0)
756 *nbuffers = 1;
757
758 return 0;
759}
760
761static void buf_queue(struct vb2_buffer *vb)
762{
763 struct mxr_buffer *buffer = container_of(vb, struct mxr_buffer, vb);
764 struct mxr_layer *layer = vb2_get_drv_priv(vb->vb2_queue);
765 struct mxr_device *mdev = layer->mdev;
766 unsigned long flags;
767 int must_start = 0;
768
769 spin_lock_irqsave(&layer->enq_slock, flags);
770 if (layer->state == MXR_LAYER_STREAMING_START) {
771 layer->state = MXR_LAYER_STREAMING;
772 must_start = 1;
773 }
774 list_add_tail(&buffer->list, &layer->enq_list);
775 spin_unlock_irqrestore(&layer->enq_slock, flags);
776 if (must_start) {
777 layer->ops.stream_set(layer, MXR_ENABLE);
778 mxr_streamer_get(mdev);
779 }
780
781 mxr_dbg(mdev, "queuing buffer\n");
782}
783
784static void wait_lock(struct vb2_queue *vq)
785{
786 struct mxr_layer *layer = vb2_get_drv_priv(vq);
787
788 mxr_dbg(layer->mdev, "%s\n", __func__);
789 mutex_lock(&layer->mutex);
790}
791
792static void wait_unlock(struct vb2_queue *vq)
793{
794 struct mxr_layer *layer = vb2_get_drv_priv(vq);
795
796 mxr_dbg(layer->mdev, "%s\n", __func__);
797 mutex_unlock(&layer->mutex);
798}
799
800static int start_streaming(struct vb2_queue *vq)
801{
802 struct mxr_layer *layer = vb2_get_drv_priv(vq);
803 struct mxr_device *mdev = layer->mdev;
804 unsigned long flags;
805
806 mxr_dbg(mdev, "%s\n", __func__);
807 /* block any changes in output configuration */
808 mxr_output_get(mdev);
809
810 /* update layers geometry */
811 mxr_layer_geo_fix(layer);
812 mxr_geometry_dump(mdev, &layer->geo);
813
814 layer->ops.format_set(layer);
815 /* enabling layer in hardware */
816 spin_lock_irqsave(&layer->enq_slock, flags);
817 layer->state = MXR_LAYER_STREAMING_START;
818 spin_unlock_irqrestore(&layer->enq_slock, flags);
819
820 return 0;
821}
822
823static void mxr_watchdog(unsigned long arg)
824{
825 struct mxr_layer *layer = (struct mxr_layer *) arg;
826 struct mxr_device *mdev = layer->mdev;
827 unsigned long flags;
828
829 mxr_err(mdev, "watchdog fired for layer %s\n", layer->vfd.name);
830
831 spin_lock_irqsave(&layer->enq_slock, flags);
832
833 if (layer->update_buf == layer->shadow_buf)
834 layer->update_buf = NULL;
835 if (layer->update_buf) {
836 vb2_buffer_done(&layer->update_buf->vb, VB2_BUF_STATE_ERROR);
837 layer->update_buf = NULL;
838 }
839 if (layer->shadow_buf) {
840 vb2_buffer_done(&layer->shadow_buf->vb, VB2_BUF_STATE_ERROR);
841 layer->shadow_buf = NULL;
842 }
843 spin_unlock_irqrestore(&layer->enq_slock, flags);
844}
845
846static int stop_streaming(struct vb2_queue *vq)
847{
848 struct mxr_layer *layer = vb2_get_drv_priv(vq);
849 struct mxr_device *mdev = layer->mdev;
850 unsigned long flags;
851 struct timer_list watchdog;
852 struct mxr_buffer *buf, *buf_tmp;
853
854 mxr_dbg(mdev, "%s\n", __func__);
855
856 spin_lock_irqsave(&layer->enq_slock, flags);
857
858 /* reset list */
859 layer->state = MXR_LAYER_STREAMING_FINISH;
860
861 /* set all buffer to be done */
862 list_for_each_entry_safe(buf, buf_tmp, &layer->enq_list, list) {
863 list_del(&buf->list);
864 vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
865 }
866
867 spin_unlock_irqrestore(&layer->enq_slock, flags);
868
869 /* give 1 seconds to complete to complete last buffers */
870 setup_timer_on_stack(&watchdog, mxr_watchdog,
871 (unsigned long)layer);
872 mod_timer(&watchdog, jiffies + msecs_to_jiffies(1000));
873
874 /* wait until all buffers are goes to done state */
875 vb2_wait_for_all_buffers(vq);
876
877 /* stop timer if all synchronization is done */
878 del_timer_sync(&watchdog);
879 destroy_timer_on_stack(&watchdog);
880
881 /* stopping hardware */
882 spin_lock_irqsave(&layer->enq_slock, flags);
883 layer->state = MXR_LAYER_IDLE;
884 spin_unlock_irqrestore(&layer->enq_slock, flags);
885
886 /* disabling layer in hardware */
887 layer->ops.stream_set(layer, MXR_DISABLE);
888 /* remove one streamer */
889 mxr_streamer_put(mdev);
890 /* allow changes in output configuration */
891 mxr_output_put(mdev);
892 return 0;
893}
894
895static struct vb2_ops mxr_video_qops = {
896 .queue_setup = queue_setup,
897 .buf_queue = buf_queue,
898 .wait_prepare = wait_unlock,
899 .wait_finish = wait_lock,
900 .start_streaming = start_streaming,
901 .stop_streaming = stop_streaming,
902};
903
904/* FIXME: try to put this functions to mxr_base_layer_create */
905int mxr_base_layer_register(struct mxr_layer *layer)
906{
907 struct mxr_device *mdev = layer->mdev;
908 int ret;
909
910 ret = video_register_device(&layer->vfd, VFL_TYPE_GRABBER, -1);
911 if (ret)
912 mxr_err(mdev, "failed to register video device\n");
913 else
914 mxr_info(mdev, "registered layer %s as /dev/video%d\n",
915 layer->vfd.name, layer->vfd.num);
916 return ret;
917}
918
919void mxr_base_layer_unregister(struct mxr_layer *layer)
920{
921 video_unregister_device(&layer->vfd);
922}
923
924void mxr_layer_release(struct mxr_layer *layer)
925{
926 if (layer->ops.release)
927 layer->ops.release(layer);
928}
929
930void mxr_base_layer_release(struct mxr_layer *layer)
931{
932 kfree(layer);
933}
934
935static void mxr_vfd_release(struct video_device *vdev)
936{
937 printk(KERN_INFO "video device release\n");
938}
939
940struct mxr_layer *mxr_base_layer_create(struct mxr_device *mdev,
941 int idx, char *name, struct mxr_layer_ops *ops)
942{
943 struct mxr_layer *layer;
944
945 layer = kzalloc(sizeof *layer, GFP_KERNEL);
946 if (layer == NULL) {
947 mxr_err(mdev, "not enough memory for layer.\n");
948 goto fail;
949 }
950
951 layer->mdev = mdev;
952 layer->idx = idx;
953 layer->ops = *ops;
954
955 spin_lock_init(&layer->enq_slock);
956 INIT_LIST_HEAD(&layer->enq_list);
957 mutex_init(&layer->mutex);
958
959 layer->vfd = (struct video_device) {
960 .minor = -1,
961 .release = mxr_vfd_release,
962 .fops = &mxr_fops,
963 .ioctl_ops = &mxr_ioctl_ops,
964 };
965 strlcpy(layer->vfd.name, name, sizeof(layer->vfd.name));
966 /* let framework control PRIORITY */
967 set_bit(V4L2_FL_USE_FH_PRIO, &layer->vfd.flags);
968
969 video_set_drvdata(&layer->vfd, layer);
970 layer->vfd.lock = &layer->mutex;
971 layer->vfd.v4l2_dev = &mdev->v4l2_dev;
972
973 layer->vb_queue = (struct vb2_queue) {
974 .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
975 .io_modes = VB2_MMAP | VB2_USERPTR,
976 .drv_priv = layer,
977 .buf_struct_size = sizeof(struct mxr_buffer),
978 .ops = &mxr_video_qops,
979 .mem_ops = &vb2_dma_contig_memops,
980 };
981
982 return layer;
983
984fail:
985 return NULL;
986}
987
988static const struct mxr_format *find_format_by_fourcc(
989 struct mxr_layer *layer, unsigned long fourcc)
990{
991 int i;
992
993 for (i = 0; i < layer->fmt_array_size; ++i)
994 if (layer->fmt_array[i]->fourcc == fourcc)
995 return layer->fmt_array[i];
996 return NULL;
997}
998
999static const struct mxr_format *find_format_by_index(
1000 struct mxr_layer *layer, unsigned long index)
1001{
1002 if (index >= layer->fmt_array_size)
1003 return NULL;
1004 return layer->fmt_array[index];
1005}
1006
diff --git a/drivers/media/video/s5p-tv/mixer_vp_layer.c b/drivers/media/video/s5p-tv/mixer_vp_layer.c
new file mode 100644
index 00000000000..6950ed8ac1a
--- /dev/null
+++ b/drivers/media/video/s5p-tv/mixer_vp_layer.c
@@ -0,0 +1,211 @@
1/*
2 * Samsung TV Mixer 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#include "mixer.h"
15
16#include "regs-vp.h"
17
18#include <media/videobuf2-dma-contig.h>
19
20/* FORMAT DEFINITIONS */
21static const struct mxr_format mxr_fmt_nv12 = {
22 .name = "NV12",
23 .fourcc = V4L2_PIX_FMT_NV12,
24 .colorspace = V4L2_COLORSPACE_JPEG,
25 .num_planes = 2,
26 .plane = {
27 { .width = 1, .height = 1, .size = 1 },
28 { .width = 2, .height = 2, .size = 2 },
29 },
30 .num_subframes = 1,
31 .cookie = VP_MODE_NV12 | VP_MODE_MEM_LINEAR,
32};
33
34static const struct mxr_format mxr_fmt_nv21 = {
35 .name = "NV21",
36 .fourcc = V4L2_PIX_FMT_NV21,
37 .colorspace = V4L2_COLORSPACE_JPEG,
38 .num_planes = 2,
39 .plane = {
40 { .width = 1, .height = 1, .size = 1 },
41 { .width = 2, .height = 2, .size = 2 },
42 },
43 .num_subframes = 1,
44 .cookie = VP_MODE_NV21 | VP_MODE_MEM_LINEAR,
45};
46
47static const struct mxr_format mxr_fmt_nv12m = {
48 .name = "NV12 (mplane)",
49 .fourcc = V4L2_PIX_FMT_NV12M,
50 .colorspace = V4L2_COLORSPACE_JPEG,
51 .num_planes = 2,
52 .plane = {
53 { .width = 1, .height = 1, .size = 1 },
54 { .width = 2, .height = 2, .size = 2 },
55 },
56 .num_subframes = 2,
57 .plane2subframe = {0, 1},
58 .cookie = VP_MODE_NV12 | VP_MODE_MEM_LINEAR,
59};
60
61static const struct mxr_format mxr_fmt_nv12mt = {
62 .name = "NV12 tiled (mplane)",
63 .fourcc = V4L2_PIX_FMT_NV12MT,
64 .colorspace = V4L2_COLORSPACE_JPEG,
65 .num_planes = 2,
66 .plane = {
67 { .width = 128, .height = 32, .size = 4096 },
68 { .width = 128, .height = 32, .size = 2048 },
69 },
70 .num_subframes = 2,
71 .plane2subframe = {0, 1},
72 .cookie = VP_MODE_NV12 | VP_MODE_MEM_TILED,
73};
74
75static const struct mxr_format *mxr_video_format[] = {
76 &mxr_fmt_nv12,
77 &mxr_fmt_nv21,
78 &mxr_fmt_nv12m,
79 &mxr_fmt_nv12mt,
80};
81
82/* AUXILIARY CALLBACKS */
83
84static void mxr_vp_layer_release(struct mxr_layer *layer)
85{
86 mxr_base_layer_unregister(layer);
87 mxr_base_layer_release(layer);
88}
89
90static void mxr_vp_buffer_set(struct mxr_layer *layer,
91 struct mxr_buffer *buf)
92{
93 dma_addr_t luma_addr[2] = {0, 0};
94 dma_addr_t chroma_addr[2] = {0, 0};
95
96 if (buf == NULL) {
97 mxr_reg_vp_buffer(layer->mdev, luma_addr, chroma_addr);
98 return;
99 }
100 luma_addr[0] = vb2_dma_contig_plane_paddr(&buf->vb, 0);
101 if (layer->fmt->num_subframes == 2) {
102 chroma_addr[0] = vb2_dma_contig_plane_paddr(&buf->vb, 1);
103 } else {
104 /* FIXME: mxr_get_plane_size compute integer division,
105 * which is slow and should not be performed in interrupt */
106 chroma_addr[0] = luma_addr[0] + mxr_get_plane_size(
107 &layer->fmt->plane[0], layer->geo.src.full_width,
108 layer->geo.src.full_height);
109 }
110 if (layer->fmt->cookie & VP_MODE_MEM_TILED) {
111 luma_addr[1] = luma_addr[0] + 0x40;
112 chroma_addr[1] = chroma_addr[0] + 0x40;
113 } else {
114 luma_addr[1] = luma_addr[0] + layer->geo.src.full_width;
115 chroma_addr[1] = chroma_addr[0];
116 }
117 mxr_reg_vp_buffer(layer->mdev, luma_addr, chroma_addr);
118}
119
120static void mxr_vp_stream_set(struct mxr_layer *layer, int en)
121{
122 mxr_reg_vp_layer_stream(layer->mdev, en);
123}
124
125static void mxr_vp_format_set(struct mxr_layer *layer)
126{
127 mxr_reg_vp_format(layer->mdev, layer->fmt, &layer->geo);
128}
129
130static void mxr_vp_fix_geometry(struct mxr_layer *layer)
131{
132 struct mxr_geometry *geo = &layer->geo;
133
134 /* align horizontal size to 8 pixels */
135 geo->src.full_width = ALIGN(geo->src.full_width, 8);
136 /* limit to boundary size */
137 geo->src.full_width = clamp_val(geo->src.full_width, 8, 8192);
138 geo->src.full_height = clamp_val(geo->src.full_height, 1, 8192);
139 geo->src.width = clamp_val(geo->src.width, 32, geo->src.full_width);
140 geo->src.width = min(geo->src.width, 2047U);
141 geo->src.height = clamp_val(geo->src.height, 4, geo->src.full_height);
142 geo->src.height = min(geo->src.height, 2047U);
143
144 /* setting size of output window */
145 geo->dst.width = clamp_val(geo->dst.width, 8, geo->dst.full_width);
146 geo->dst.height = clamp_val(geo->dst.height, 1, geo->dst.full_height);
147
148 /* ensure that scaling is in range 1/4x to 16x */
149 if (geo->src.width >= 4 * geo->dst.width)
150 geo->src.width = 4 * geo->dst.width;
151 if (geo->dst.width >= 16 * geo->src.width)
152 geo->dst.width = 16 * geo->src.width;
153 if (geo->src.height >= 4 * geo->dst.height)
154 geo->src.height = 4 * geo->dst.height;
155 if (geo->dst.height >= 16 * geo->src.height)
156 geo->dst.height = 16 * geo->src.height;
157
158 /* setting scaling ratio */
159 geo->x_ratio = (geo->src.width << 16) / geo->dst.width;
160 geo->y_ratio = (geo->src.height << 16) / geo->dst.height;
161
162 /* adjust offsets */
163 geo->src.x_offset = min(geo->src.x_offset,
164 geo->src.full_width - geo->src.width);
165 geo->src.y_offset = min(geo->src.y_offset,
166 geo->src.full_height - geo->src.height);
167 geo->dst.x_offset = min(geo->dst.x_offset,
168 geo->dst.full_width - geo->dst.width);
169 geo->dst.y_offset = min(geo->dst.y_offset,
170 geo->dst.full_height - geo->dst.height);
171}
172
173/* PUBLIC API */
174
175struct mxr_layer *mxr_vp_layer_create(struct mxr_device *mdev, int idx)
176{
177 struct mxr_layer *layer;
178 int ret;
179 struct mxr_layer_ops ops = {
180 .release = mxr_vp_layer_release,
181 .buffer_set = mxr_vp_buffer_set,
182 .stream_set = mxr_vp_stream_set,
183 .format_set = mxr_vp_format_set,
184 .fix_geometry = mxr_vp_fix_geometry,
185 };
186 char name[32];
187
188 sprintf(name, "video%d", idx);
189
190 layer = mxr_base_layer_create(mdev, idx, name, &ops);
191 if (layer == NULL) {
192 mxr_err(mdev, "failed to initialize layer(%d) base\n", idx);
193 goto fail;
194 }
195
196 layer->fmt_array = mxr_video_format;
197 layer->fmt_array_size = ARRAY_SIZE(mxr_video_format);
198
199 ret = mxr_base_layer_register(layer);
200 if (ret)
201 goto fail_layer;
202
203 return layer;
204
205fail_layer:
206 mxr_base_layer_release(layer);
207
208fail:
209 return NULL;
210}
211
diff --git a/drivers/media/video/s5p-tv/regs-hdmi.h b/drivers/media/video/s5p-tv/regs-hdmi.h
new file mode 100644
index 00000000000..ac93ad6f2bc
--- /dev/null
+++ b/drivers/media/video/s5p-tv/regs-hdmi.h
@@ -0,0 +1,141 @@
1/* linux/arch/arm/mach-exynos4/include/mach/regs-hdmi.h
2 *
3 * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
4 * http://www.samsung.com/
5 *
6 * HDMI register header file for Samsung TVOUT driver
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 version 2 as
10 * published by the Free Software Foundation.
11*/
12
13#ifndef SAMSUNG_REGS_HDMI_H
14#define SAMSUNG_REGS_HDMI_H
15
16/*
17 * Register part
18*/
19
20#define HDMI_CTRL_BASE(x) ((x) + 0x00000000)
21#define HDMI_CORE_BASE(x) ((x) + 0x00010000)
22#define HDMI_TG_BASE(x) ((x) + 0x00050000)
23
24/* Control registers */
25#define HDMI_INTC_CON HDMI_CTRL_BASE(0x0000)
26#define HDMI_INTC_FLAG HDMI_CTRL_BASE(0x0004)
27#define HDMI_HPD_STATUS HDMI_CTRL_BASE(0x000C)
28#define HDMI_PHY_RSTOUT HDMI_CTRL_BASE(0x0014)
29#define HDMI_PHY_VPLL HDMI_CTRL_BASE(0x0018)
30#define HDMI_PHY_CMU HDMI_CTRL_BASE(0x001C)
31#define HDMI_CORE_RSTOUT HDMI_CTRL_BASE(0x0020)
32
33/* Core registers */
34#define HDMI_CON_0 HDMI_CORE_BASE(0x0000)
35#define HDMI_CON_1 HDMI_CORE_BASE(0x0004)
36#define HDMI_CON_2 HDMI_CORE_BASE(0x0008)
37#define HDMI_SYS_STATUS HDMI_CORE_BASE(0x0010)
38#define HDMI_PHY_STATUS HDMI_CORE_BASE(0x0014)
39#define HDMI_STATUS_EN HDMI_CORE_BASE(0x0020)
40#define HDMI_HPD HDMI_CORE_BASE(0x0030)
41#define HDMI_MODE_SEL HDMI_CORE_BASE(0x0040)
42#define HDMI_BLUE_SCREEN_0 HDMI_CORE_BASE(0x0050)
43#define HDMI_BLUE_SCREEN_1 HDMI_CORE_BASE(0x0054)
44#define HDMI_BLUE_SCREEN_2 HDMI_CORE_BASE(0x0058)
45#define HDMI_H_BLANK_0 HDMI_CORE_BASE(0x00A0)
46#define HDMI_H_BLANK_1 HDMI_CORE_BASE(0x00A4)
47#define HDMI_V_BLANK_0 HDMI_CORE_BASE(0x00B0)
48#define HDMI_V_BLANK_1 HDMI_CORE_BASE(0x00B4)
49#define HDMI_V_BLANK_2 HDMI_CORE_BASE(0x00B8)
50#define HDMI_H_V_LINE_0 HDMI_CORE_BASE(0x00C0)
51#define HDMI_H_V_LINE_1 HDMI_CORE_BASE(0x00C4)
52#define HDMI_H_V_LINE_2 HDMI_CORE_BASE(0x00C8)
53#define HDMI_VSYNC_POL HDMI_CORE_BASE(0x00E4)
54#define HDMI_INT_PRO_MODE HDMI_CORE_BASE(0x00E8)
55#define HDMI_V_BLANK_F_0 HDMI_CORE_BASE(0x0110)
56#define HDMI_V_BLANK_F_1 HDMI_CORE_BASE(0x0114)
57#define HDMI_V_BLANK_F_2 HDMI_CORE_BASE(0x0118)
58#define HDMI_H_SYNC_GEN_0 HDMI_CORE_BASE(0x0120)
59#define HDMI_H_SYNC_GEN_1 HDMI_CORE_BASE(0x0124)
60#define HDMI_H_SYNC_GEN_2 HDMI_CORE_BASE(0x0128)
61#define HDMI_V_SYNC_GEN_1_0 HDMI_CORE_BASE(0x0130)
62#define HDMI_V_SYNC_GEN_1_1 HDMI_CORE_BASE(0x0134)
63#define HDMI_V_SYNC_GEN_1_2 HDMI_CORE_BASE(0x0138)
64#define HDMI_V_SYNC_GEN_2_0 HDMI_CORE_BASE(0x0140)
65#define HDMI_V_SYNC_GEN_2_1 HDMI_CORE_BASE(0x0144)
66#define HDMI_V_SYNC_GEN_2_2 HDMI_CORE_BASE(0x0148)
67#define HDMI_V_SYNC_GEN_3_0 HDMI_CORE_BASE(0x0150)
68#define HDMI_V_SYNC_GEN_3_1 HDMI_CORE_BASE(0x0154)
69#define HDMI_V_SYNC_GEN_3_2 HDMI_CORE_BASE(0x0158)
70#define HDMI_AVI_CON HDMI_CORE_BASE(0x0300)
71#define HDMI_AVI_BYTE(n) HDMI_CORE_BASE(0x0320 + 4 * (n))
72#define HDMI_DC_CONTROL HDMI_CORE_BASE(0x05C0)
73#define HDMI_VIDEO_PATTERN_GEN HDMI_CORE_BASE(0x05C4)
74#define HDMI_HPD_GEN HDMI_CORE_BASE(0x05C8)
75
76/* Timing generator registers */
77#define HDMI_TG_CMD HDMI_TG_BASE(0x0000)
78#define HDMI_TG_H_FSZ_L HDMI_TG_BASE(0x0018)
79#define HDMI_TG_H_FSZ_H HDMI_TG_BASE(0x001C)
80#define HDMI_TG_HACT_ST_L HDMI_TG_BASE(0x0020)
81#define HDMI_TG_HACT_ST_H HDMI_TG_BASE(0x0024)
82#define HDMI_TG_HACT_SZ_L HDMI_TG_BASE(0x0028)
83#define HDMI_TG_HACT_SZ_H HDMI_TG_BASE(0x002C)
84#define HDMI_TG_V_FSZ_L HDMI_TG_BASE(0x0030)
85#define HDMI_TG_V_FSZ_H HDMI_TG_BASE(0x0034)
86#define HDMI_TG_VSYNC_L HDMI_TG_BASE(0x0038)
87#define HDMI_TG_VSYNC_H HDMI_TG_BASE(0x003C)
88#define HDMI_TG_VSYNC2_L HDMI_TG_BASE(0x0040)
89#define HDMI_TG_VSYNC2_H HDMI_TG_BASE(0x0044)
90#define HDMI_TG_VACT_ST_L HDMI_TG_BASE(0x0048)
91#define HDMI_TG_VACT_ST_H HDMI_TG_BASE(0x004C)
92#define HDMI_TG_VACT_SZ_L HDMI_TG_BASE(0x0050)
93#define HDMI_TG_VACT_SZ_H HDMI_TG_BASE(0x0054)
94#define HDMI_TG_FIELD_CHG_L HDMI_TG_BASE(0x0058)
95#define HDMI_TG_FIELD_CHG_H HDMI_TG_BASE(0x005C)
96#define HDMI_TG_VACT_ST2_L HDMI_TG_BASE(0x0060)
97#define HDMI_TG_VACT_ST2_H HDMI_TG_BASE(0x0064)
98#define HDMI_TG_VSYNC_TOP_HDMI_L HDMI_TG_BASE(0x0078)
99#define HDMI_TG_VSYNC_TOP_HDMI_H HDMI_TG_BASE(0x007C)
100#define HDMI_TG_VSYNC_BOT_HDMI_L HDMI_TG_BASE(0x0080)
101#define HDMI_TG_VSYNC_BOT_HDMI_H HDMI_TG_BASE(0x0084)
102#define HDMI_TG_FIELD_TOP_HDMI_L HDMI_TG_BASE(0x0088)
103#define HDMI_TG_FIELD_TOP_HDMI_H HDMI_TG_BASE(0x008C)
104#define HDMI_TG_FIELD_BOT_HDMI_L HDMI_TG_BASE(0x0090)
105#define HDMI_TG_FIELD_BOT_HDMI_H HDMI_TG_BASE(0x0094)
106
107/*
108 * Bit definition part
109 */
110
111/* HDMI_INTC_CON */
112#define HDMI_INTC_EN_GLOBAL (1 << 6)
113#define HDMI_INTC_EN_HPD_PLUG (1 << 3)
114#define HDMI_INTC_EN_HPD_UNPLUG (1 << 2)
115
116/* HDMI_INTC_FLAG */
117#define HDMI_INTC_FLAG_HPD_PLUG (1 << 3)
118#define HDMI_INTC_FLAG_HPD_UNPLUG (1 << 2)
119
120/* HDMI_PHY_RSTOUT */
121#define HDMI_PHY_SW_RSTOUT (1 << 0)
122
123/* HDMI_CORE_RSTOUT */
124#define HDMI_CORE_SW_RSTOUT (1 << 0)
125
126/* HDMI_CON_0 */
127#define HDMI_BLUE_SCR_EN (1 << 5)
128#define HDMI_EN (1 << 0)
129
130/* HDMI_PHY_STATUS */
131#define HDMI_PHY_STATUS_READY (1 << 0)
132
133/* HDMI_MODE_SEL */
134#define HDMI_MODE_HDMI_EN (1 << 1)
135#define HDMI_MODE_DVI_EN (1 << 0)
136#define HDMI_MODE_MASK (3 << 0)
137
138/* HDMI_TG_CMD */
139#define HDMI_TG_EN (1 << 0)
140
141#endif /* SAMSUNG_REGS_HDMI_H */
diff --git a/drivers/media/video/s5p-tv/regs-mixer.h b/drivers/media/video/s5p-tv/regs-mixer.h
new file mode 100644
index 00000000000..3c8442609c1
--- /dev/null
+++ b/drivers/media/video/s5p-tv/regs-mixer.h
@@ -0,0 +1,121 @@
1/*
2 * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
3 * http://www.samsung.com/
4 *
5 * Mixer register header file for Samsung Mixer driver
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10*/
11#ifndef SAMSUNG_REGS_MIXER_H
12#define SAMSUNG_REGS_MIXER_H
13
14/*
15 * Register part
16 */
17#define MXR_STATUS 0x0000
18#define MXR_CFG 0x0004
19#define MXR_INT_EN 0x0008
20#define MXR_INT_STATUS 0x000C
21#define MXR_LAYER_CFG 0x0010
22#define MXR_VIDEO_CFG 0x0014
23#define MXR_GRAPHIC0_CFG 0x0020
24#define MXR_GRAPHIC0_BASE 0x0024
25#define MXR_GRAPHIC0_SPAN 0x0028
26#define MXR_GRAPHIC0_SXY 0x002C
27#define MXR_GRAPHIC0_WH 0x0030
28#define MXR_GRAPHIC0_DXY 0x0034
29#define MXR_GRAPHIC0_BLANK 0x0038
30#define MXR_GRAPHIC1_CFG 0x0040
31#define MXR_GRAPHIC1_BASE 0x0044
32#define MXR_GRAPHIC1_SPAN 0x0048
33#define MXR_GRAPHIC1_SXY 0x004C
34#define MXR_GRAPHIC1_WH 0x0050
35#define MXR_GRAPHIC1_DXY 0x0054
36#define MXR_GRAPHIC1_BLANK 0x0058
37#define MXR_BG_CFG 0x0060
38#define MXR_BG_COLOR0 0x0064
39#define MXR_BG_COLOR1 0x0068
40#define MXR_BG_COLOR2 0x006C
41
42/* for parametrized access to layer registers */
43#define MXR_GRAPHIC_CFG(i) (0x0020 + (i) * 0x20)
44#define MXR_GRAPHIC_BASE(i) (0x0024 + (i) * 0x20)
45#define MXR_GRAPHIC_SPAN(i) (0x0028 + (i) * 0x20)
46#define MXR_GRAPHIC_SXY(i) (0x002C + (i) * 0x20)
47#define MXR_GRAPHIC_WH(i) (0x0030 + (i) * 0x20)
48#define MXR_GRAPHIC_DXY(i) (0x0034 + (i) * 0x20)
49
50/*
51 * Bit definition part
52 */
53
54/* generates mask for range of bits */
55#define MXR_MASK(high_bit, low_bit) \
56 (((2 << ((high_bit) - (low_bit))) - 1) << (low_bit))
57
58#define MXR_MASK_VAL(val, high_bit, low_bit) \
59 (((val) << (low_bit)) & MXR_MASK(high_bit, low_bit))
60
61/* bits for MXR_STATUS */
62#define MXR_STATUS_16_BURST (1 << 7)
63#define MXR_STATUS_BURST_MASK (1 << 7)
64#define MXR_STATUS_SYNC_ENABLE (1 << 2)
65#define MXR_STATUS_REG_RUN (1 << 0)
66
67/* bits for MXR_CFG */
68#define MXR_CFG_OUT_YUV444 (0 << 8)
69#define MXR_CFG_OUT_RGB888 (1 << 8)
70#define MXR_CFG_DST_SDO (0 << 7)
71#define MXR_CFG_DST_HDMI (1 << 7)
72#define MXR_CFG_DST_MASK (1 << 7)
73#define MXR_CFG_SCAN_HD_720 (0 << 6)
74#define MXR_CFG_SCAN_HD_1080 (1 << 6)
75#define MXR_CFG_GRP1_ENABLE (1 << 5)
76#define MXR_CFG_GRP0_ENABLE (1 << 4)
77#define MXR_CFG_VP_ENABLE (1 << 3)
78#define MXR_CFG_SCAN_INTERLACE (0 << 2)
79#define MXR_CFG_SCAN_PROGRASSIVE (1 << 2)
80#define MXR_CFG_SCAN_NTSC (0 << 1)
81#define MXR_CFG_SCAN_PAL (1 << 1)
82#define MXR_CFG_SCAN_SD (0 << 0)
83#define MXR_CFG_SCAN_HD (1 << 0)
84#define MXR_CFG_SCAN_MASK 0x47
85
86/* bits for MXR_GRAPHICn_CFG */
87#define MXR_GRP_CFG_COLOR_KEY_DISABLE (1 << 21)
88#define MXR_GRP_CFG_BLEND_PRE_MUL (1 << 20)
89#define MXR_GRP_CFG_FORMAT_VAL(x) MXR_MASK_VAL(x, 11, 8)
90#define MXR_GRP_CFG_FORMAT_MASK MXR_GRP_CFG_FORMAT_VAL(~0)
91#define MXR_GRP_CFG_ALPHA_VAL(x) MXR_MASK_VAL(x, 7, 0)
92
93/* bits for MXR_GRAPHICn_WH */
94#define MXR_GRP_WH_H_SCALE(x) MXR_MASK_VAL(x, 28, 28)
95#define MXR_GRP_WH_V_SCALE(x) MXR_MASK_VAL(x, 12, 12)
96#define MXR_GRP_WH_WIDTH(x) MXR_MASK_VAL(x, 26, 16)
97#define MXR_GRP_WH_HEIGHT(x) MXR_MASK_VAL(x, 10, 0)
98
99/* bits for MXR_GRAPHICn_SXY */
100#define MXR_GRP_SXY_SX(x) MXR_MASK_VAL(x, 26, 16)
101#define MXR_GRP_SXY_SY(x) MXR_MASK_VAL(x, 10, 0)
102
103/* bits for MXR_GRAPHICn_DXY */
104#define MXR_GRP_DXY_DX(x) MXR_MASK_VAL(x, 26, 16)
105#define MXR_GRP_DXY_DY(x) MXR_MASK_VAL(x, 10, 0)
106
107/* bits for MXR_INT_EN */
108#define MXR_INT_EN_VSYNC (1 << 11)
109#define MXR_INT_EN_ALL (0x0f << 8)
110
111/* bit for MXR_INT_STATUS */
112#define MXR_INT_CLEAR_VSYNC (1 << 11)
113#define MXR_INT_STATUS_VSYNC (1 << 0)
114
115/* bit for MXR_LAYER_CFG */
116#define MXR_LAYER_CFG_GRP1_VAL(x) MXR_MASK_VAL(x, 11, 8)
117#define MXR_LAYER_CFG_GRP0_VAL(x) MXR_MASK_VAL(x, 7, 4)
118#define MXR_LAYER_CFG_VP_VAL(x) MXR_MASK_VAL(x, 3, 0)
119
120#endif /* SAMSUNG_REGS_MIXER_H */
121
diff --git a/drivers/media/video/s5p-tv/regs-sdo.h b/drivers/media/video/s5p-tv/regs-sdo.h
new file mode 100644
index 00000000000..7f7c2b8ac14
--- /dev/null
+++ b/drivers/media/video/s5p-tv/regs-sdo.h
@@ -0,0 +1,63 @@
1/* drivers/media/video/s5p-tv/regs-sdo.h
2 *
3 * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
4 * http://www.samsung.com/
5 *
6 * SDO register description file
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 version 2 as
10 * published by the Free Software Foundation.
11 */
12
13#ifndef SAMSUNG_REGS_SDO_H
14#define SAMSUNG_REGS_SDO_H
15
16/*
17 * Register part
18 */
19
20#define SDO_CLKCON 0x0000
21#define SDO_CONFIG 0x0008
22#define SDO_VBI 0x0014
23#define SDO_DAC 0x003C
24#define SDO_CCCON 0x0180
25#define SDO_IRQ 0x0280
26#define SDO_IRQMASK 0x0284
27#define SDO_VERSION 0x03D8
28
29/*
30 * Bit definition part
31 */
32
33/* SDO Clock Control Register (SDO_CLKCON) */
34#define SDO_TVOUT_SW_RESET (1 << 4)
35#define SDO_TVOUT_CLOCK_READY (1 << 1)
36#define SDO_TVOUT_CLOCK_ON (1 << 0)
37
38/* SDO Video Standard Configuration Register (SDO_CONFIG) */
39#define SDO_PROGRESSIVE (1 << 4)
40#define SDO_NTSC_M 0
41#define SDO_PAL_M 1
42#define SDO_PAL_BGHID 2
43#define SDO_PAL_N 3
44#define SDO_PAL_NC 4
45#define SDO_NTSC_443 8
46#define SDO_PAL_60 9
47#define SDO_STANDARD_MASK 0xf
48
49/* SDO VBI Configuration Register (SDO_VBI) */
50#define SDO_CVBS_WSS_INS (1 << 14)
51#define SDO_CVBS_CLOSED_CAPTION_MASK (3 << 12)
52
53/* SDO DAC Configuration Register (SDO_DAC) */
54#define SDO_POWER_ON_DAC (1 << 0)
55
56/* SDO Color Compensation On/Off Control (SDO_CCCON) */
57#define SDO_COMPENSATION_BHS_ADJ_OFF (1 << 4)
58#define SDO_COMPENSATION_CVBS_COMP_OFF (1 << 0)
59
60/* SDO Interrupt Request Register (SDO_IRQ) */
61#define SDO_VSYNC_IRQ_PEND (1 << 0)
62
63#endif /* SAMSUNG_REGS_SDO_H */
diff --git a/drivers/media/video/s5p-tv/regs-vp.h b/drivers/media/video/s5p-tv/regs-vp.h
new file mode 100644
index 00000000000..6c63984e11e
--- /dev/null
+++ b/drivers/media/video/s5p-tv/regs-vp.h
@@ -0,0 +1,88 @@
1/*
2 * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
3 * http://www.samsung.com/
4 *
5 * Video processor register header file for Samsung Mixer driver
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 */
11
12#ifndef SAMSUNG_REGS_VP_H
13#define SAMSUNG_REGS_VP_H
14
15/*
16 * Register part
17 */
18
19#define VP_ENABLE 0x0000
20#define VP_SRESET 0x0004
21#define VP_SHADOW_UPDATE 0x0008
22#define VP_FIELD_ID 0x000C
23#define VP_MODE 0x0010
24#define VP_IMG_SIZE_Y 0x0014
25#define VP_IMG_SIZE_C 0x0018
26#define VP_PER_RATE_CTRL 0x001C
27#define VP_TOP_Y_PTR 0x0028
28#define VP_BOT_Y_PTR 0x002C
29#define VP_TOP_C_PTR 0x0030
30#define VP_BOT_C_PTR 0x0034
31#define VP_ENDIAN_MODE 0x03CC
32#define VP_SRC_H_POSITION 0x0044
33#define VP_SRC_V_POSITION 0x0048
34#define VP_SRC_WIDTH 0x004C
35#define VP_SRC_HEIGHT 0x0050
36#define VP_DST_H_POSITION 0x0054
37#define VP_DST_V_POSITION 0x0058
38#define VP_DST_WIDTH 0x005C
39#define VP_DST_HEIGHT 0x0060
40#define VP_H_RATIO 0x0064
41#define VP_V_RATIO 0x0068
42#define VP_POLY8_Y0_LL 0x006C
43#define VP_POLY4_Y0_LL 0x00EC
44#define VP_POLY4_C0_LL 0x012C
45
46/*
47 * Bit definition part
48 */
49
50/* generates mask for range of bits */
51
52#define VP_MASK(high_bit, low_bit) \
53 (((2 << ((high_bit) - (low_bit))) - 1) << (low_bit))
54
55#define VP_MASK_VAL(val, high_bit, low_bit) \
56 (((val) << (low_bit)) & VP_MASK(high_bit, low_bit))
57
58 /* VP_ENABLE */
59#define VP_ENABLE_ON (1 << 0)
60
61/* VP_SRESET */
62#define VP_SRESET_PROCESSING (1 << 0)
63
64/* VP_SHADOW_UPDATE */
65#define VP_SHADOW_UPDATE_ENABLE (1 << 0)
66
67/* VP_MODE */
68#define VP_MODE_NV12 (0 << 6)
69#define VP_MODE_NV21 (1 << 6)
70#define VP_MODE_LINE_SKIP (1 << 5)
71#define VP_MODE_MEM_LINEAR (0 << 4)
72#define VP_MODE_MEM_TILED (1 << 4)
73#define VP_MODE_FMT_MASK (5 << 4)
74#define VP_MODE_FIELD_ID_AUTO_TOGGLING (1 << 2)
75#define VP_MODE_2D_IPC (1 << 1)
76
77/* VP_IMG_SIZE_Y */
78/* VP_IMG_SIZE_C */
79#define VP_IMG_HSIZE(x) VP_MASK_VAL(x, 29, 16)
80#define VP_IMG_VSIZE(x) VP_MASK_VAL(x, 13, 0)
81
82/* VP_SRC_H_POSITION */
83#define VP_SRC_H_POSITION_VAL(x) VP_MASK_VAL(x, 14, 4)
84
85/* VP_ENDIAN_MODE */
86#define VP_ENDIAN_MODE_LITTLE (1 << 0)
87
88#endif /* SAMSUNG_REGS_VP_H */
diff --git a/drivers/media/video/s5p-tv/sdo_drv.c b/drivers/media/video/s5p-tv/sdo_drv.c
new file mode 100644
index 00000000000..4dddd6bd635
--- /dev/null
+++ b/drivers/media/video/s5p-tv/sdo_drv.c
@@ -0,0 +1,479 @@
1/*
2 * Samsung Standard Definition Output (SDO) 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#include <linux/clk.h>
15#include <linux/delay.h>
16#include <linux/kernel.h>
17#include <linux/module.h>
18#include <linux/interrupt.h>
19#include <linux/io.h>
20#include <linux/irq.h>
21#include <linux/platform_device.h>
22#include <linux/pm_runtime.h>
23#include <linux/regulator/consumer.h>
24#include <linux/slab.h>
25
26#include <media/v4l2-subdev.h>
27
28#include "regs-sdo.h"
29
30MODULE_AUTHOR("Tomasz Stanislawski, <t.stanislaws@samsung.com>");
31MODULE_DESCRIPTION("Samsung Standard Definition Output (SDO)");
32MODULE_LICENSE("GPL");
33
34#define SDO_DEFAULT_STD V4L2_STD_PAL
35
36struct sdo_format {
37 v4l2_std_id id;
38 /* all modes are 720 pixels wide */
39 unsigned int height;
40 unsigned int cookie;
41};
42
43struct sdo_device {
44 /** pointer to device parent */
45 struct device *dev;
46 /** base address of SDO registers */
47 void __iomem *regs;
48 /** SDO interrupt */
49 unsigned int irq;
50 /** DAC source clock */
51 struct clk *sclk_dac;
52 /** DAC clock */
53 struct clk *dac;
54 /** DAC physical interface */
55 struct clk *dacphy;
56 /** clock for control of VPLL */
57 struct clk *fout_vpll;
58 /** regulator for SDO IP power */
59 struct regulator *vdac;
60 /** regulator for SDO plug detection */
61 struct regulator *vdet;
62 /** subdev used as device interface */
63 struct v4l2_subdev sd;
64 /** current format */
65 const struct sdo_format *fmt;
66};
67
68static inline struct sdo_device *sd_to_sdev(struct v4l2_subdev *sd)
69{
70 return container_of(sd, struct sdo_device, sd);
71}
72
73static inline
74void sdo_write_mask(struct sdo_device *sdev, u32 reg_id, u32 value, u32 mask)
75{
76 u32 old = readl(sdev->regs + reg_id);
77 value = (value & mask) | (old & ~mask);
78 writel(value, sdev->regs + reg_id);
79}
80
81static inline
82void sdo_write(struct sdo_device *sdev, u32 reg_id, u32 value)
83{
84 writel(value, sdev->regs + reg_id);
85}
86
87static inline
88u32 sdo_read(struct sdo_device *sdev, u32 reg_id)
89{
90 return readl(sdev->regs + reg_id);
91}
92
93static irqreturn_t sdo_irq_handler(int irq, void *dev_data)
94{
95 struct sdo_device *sdev = dev_data;
96
97 /* clear interrupt */
98 sdo_write_mask(sdev, SDO_IRQ, ~0, SDO_VSYNC_IRQ_PEND);
99 return IRQ_HANDLED;
100}
101
102static void sdo_reg_debug(struct sdo_device *sdev)
103{
104#define DBGREG(reg_id) \
105 dev_info(sdev->dev, #reg_id " = %08x\n", \
106 sdo_read(sdev, reg_id))
107
108 DBGREG(SDO_CLKCON);
109 DBGREG(SDO_CONFIG);
110 DBGREG(SDO_VBI);
111 DBGREG(SDO_DAC);
112 DBGREG(SDO_IRQ);
113 DBGREG(SDO_IRQMASK);
114 DBGREG(SDO_VERSION);
115}
116
117static const struct sdo_format sdo_format[] = {
118 { V4L2_STD_PAL_N, .height = 576, .cookie = SDO_PAL_N },
119 { V4L2_STD_PAL_Nc, .height = 576, .cookie = SDO_PAL_NC },
120 { V4L2_STD_PAL_M, .height = 480, .cookie = SDO_PAL_M },
121 { V4L2_STD_PAL_60, .height = 480, .cookie = SDO_PAL_60 },
122 { V4L2_STD_NTSC_443, .height = 480, .cookie = SDO_NTSC_443 },
123 { V4L2_STD_PAL, .height = 576, .cookie = SDO_PAL_BGHID },
124 { V4L2_STD_NTSC_M, .height = 480, .cookie = SDO_NTSC_M },
125};
126
127static const struct sdo_format *sdo_find_format(v4l2_std_id id)
128{
129 int i;
130 for (i = 0; i < ARRAY_SIZE(sdo_format); ++i)
131 if (sdo_format[i].id & id)
132 return &sdo_format[i];
133 return NULL;
134}
135
136static int sdo_g_tvnorms_output(struct v4l2_subdev *sd, v4l2_std_id *std)
137{
138 *std = V4L2_STD_NTSC_M | V4L2_STD_PAL_M | V4L2_STD_PAL |
139 V4L2_STD_PAL_N | V4L2_STD_PAL_Nc |
140 V4L2_STD_NTSC_443 | V4L2_STD_PAL_60;
141 return 0;
142}
143
144static int sdo_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std)
145{
146 struct sdo_device *sdev = sd_to_sdev(sd);
147 const struct sdo_format *fmt;
148 fmt = sdo_find_format(std);
149 if (fmt == NULL)
150 return -EINVAL;
151 sdev->fmt = fmt;
152 return 0;
153}
154
155static int sdo_g_std_output(struct v4l2_subdev *sd, v4l2_std_id *std)
156{
157 *std = sd_to_sdev(sd)->fmt->id;
158 return 0;
159}
160
161static int sdo_g_mbus_fmt(struct v4l2_subdev *sd,
162 struct v4l2_mbus_framefmt *fmt)
163{
164 struct sdo_device *sdev = sd_to_sdev(sd);
165
166 if (!sdev->fmt)
167 return -ENXIO;
168 /* all modes are 720 pixels wide */
169 fmt->width = 720;
170 fmt->height = sdev->fmt->height;
171 fmt->code = V4L2_MBUS_FMT_FIXED;
172 fmt->field = V4L2_FIELD_INTERLACED;
173 return 0;
174}
175
176static int sdo_s_power(struct v4l2_subdev *sd, int on)
177{
178 struct sdo_device *sdev = sd_to_sdev(sd);
179 struct device *dev = sdev->dev;
180 int ret;
181
182 dev_info(dev, "sdo_s_power(%d)\n", on);
183
184 if (on)
185 ret = pm_runtime_get_sync(dev);
186 else
187 ret = pm_runtime_put_sync(dev);
188
189 /* only values < 0 indicate errors */
190 return IS_ERR_VALUE(ret) ? ret : 0;
191}
192
193static int sdo_streamon(struct sdo_device *sdev)
194{
195 /* set proper clock for Timing Generator */
196 clk_set_rate(sdev->fout_vpll, 54000000);
197 dev_info(sdev->dev, "fout_vpll.rate = %lu\n",
198 clk_get_rate(sdev->fout_vpll));
199 /* enable clock in SDO */
200 sdo_write_mask(sdev, SDO_CLKCON, ~0, SDO_TVOUT_CLOCK_ON);
201 clk_enable(sdev->dacphy);
202 /* enable DAC */
203 sdo_write_mask(sdev, SDO_DAC, ~0, SDO_POWER_ON_DAC);
204 sdo_reg_debug(sdev);
205 return 0;
206}
207
208static int sdo_streamoff(struct sdo_device *sdev)
209{
210 int tries;
211
212 sdo_write_mask(sdev, SDO_DAC, 0, SDO_POWER_ON_DAC);
213 clk_disable(sdev->dacphy);
214 sdo_write_mask(sdev, SDO_CLKCON, 0, SDO_TVOUT_CLOCK_ON);
215 for (tries = 100; tries; --tries) {
216 if (sdo_read(sdev, SDO_CLKCON) & SDO_TVOUT_CLOCK_READY)
217 break;
218 mdelay(1);
219 }
220 if (tries == 0)
221 dev_err(sdev->dev, "failed to stop streaming\n");
222 return tries ? 0 : -EIO;
223}
224
225static int sdo_s_stream(struct v4l2_subdev *sd, int on)
226{
227 struct sdo_device *sdev = sd_to_sdev(sd);
228 return on ? sdo_streamon(sdev) : sdo_streamoff(sdev);
229}
230
231static const struct v4l2_subdev_core_ops sdo_sd_core_ops = {
232 .s_power = sdo_s_power,
233};
234
235static const struct v4l2_subdev_video_ops sdo_sd_video_ops = {
236 .s_std_output = sdo_s_std_output,
237 .g_std_output = sdo_g_std_output,
238 .g_tvnorms_output = sdo_g_tvnorms_output,
239 .g_mbus_fmt = sdo_g_mbus_fmt,
240 .s_stream = sdo_s_stream,
241};
242
243static const struct v4l2_subdev_ops sdo_sd_ops = {
244 .core = &sdo_sd_core_ops,
245 .video = &sdo_sd_video_ops,
246};
247
248static int sdo_runtime_suspend(struct device *dev)
249{
250 struct v4l2_subdev *sd = dev_get_drvdata(dev);
251 struct sdo_device *sdev = sd_to_sdev(sd);
252
253 dev_info(dev, "suspend\n");
254 regulator_disable(sdev->vdet);
255 regulator_disable(sdev->vdac);
256 clk_disable(sdev->sclk_dac);
257 return 0;
258}
259
260static int sdo_runtime_resume(struct device *dev)
261{
262 struct v4l2_subdev *sd = dev_get_drvdata(dev);
263 struct sdo_device *sdev = sd_to_sdev(sd);
264
265 dev_info(dev, "resume\n");
266 clk_enable(sdev->sclk_dac);
267 regulator_enable(sdev->vdac);
268 regulator_enable(sdev->vdet);
269
270 /* software reset */
271 sdo_write_mask(sdev, SDO_CLKCON, ~0, SDO_TVOUT_SW_RESET);
272 mdelay(10);
273 sdo_write_mask(sdev, SDO_CLKCON, 0, SDO_TVOUT_SW_RESET);
274
275 /* setting TV mode */
276 sdo_write_mask(sdev, SDO_CONFIG, sdev->fmt->cookie, SDO_STANDARD_MASK);
277 /* XXX: forcing interlaced mode using undocumented bit */
278 sdo_write_mask(sdev, SDO_CONFIG, 0, SDO_PROGRESSIVE);
279 /* turn all VBI off */
280 sdo_write_mask(sdev, SDO_VBI, 0, SDO_CVBS_WSS_INS |
281 SDO_CVBS_CLOSED_CAPTION_MASK);
282 /* turn all post processing off */
283 sdo_write_mask(sdev, SDO_CCCON, ~0, SDO_COMPENSATION_BHS_ADJ_OFF |
284 SDO_COMPENSATION_CVBS_COMP_OFF);
285 sdo_reg_debug(sdev);
286 return 0;
287}
288
289static const struct dev_pm_ops sdo_pm_ops = {
290 .runtime_suspend = sdo_runtime_suspend,
291 .runtime_resume = sdo_runtime_resume,
292};
293
294static int __devinit sdo_probe(struct platform_device *pdev)
295{
296 struct device *dev = &pdev->dev;
297 struct sdo_device *sdev;
298 struct resource *res;
299 int ret = 0;
300 struct clk *sclk_vpll;
301
302 dev_info(dev, "probe start\n");
303 sdev = kzalloc(sizeof *sdev, GFP_KERNEL);
304 if (!sdev) {
305 dev_err(dev, "not enough memory.\n");
306 ret = -ENOMEM;
307 goto fail;
308 }
309 sdev->dev = dev;
310
311 /* mapping registers */
312 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
313 if (res == NULL) {
314 dev_err(dev, "get memory resource failed.\n");
315 ret = -ENXIO;
316 goto fail_sdev;
317 }
318
319 sdev->regs = ioremap(res->start, resource_size(res));
320 if (sdev->regs == NULL) {
321 dev_err(dev, "register mapping failed.\n");
322 ret = -ENXIO;
323 goto fail_sdev;
324 }
325
326 /* acquiring interrupt */
327 res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
328 if (res == NULL) {
329 dev_err(dev, "get interrupt resource failed.\n");
330 ret = -ENXIO;
331 goto fail_regs;
332 }
333 ret = request_irq(res->start, sdo_irq_handler, 0, "s5p-sdo", sdev);
334 if (ret) {
335 dev_err(dev, "request interrupt failed.\n");
336 goto fail_regs;
337 }
338 sdev->irq = res->start;
339
340 /* acquire clocks */
341 sdev->sclk_dac = clk_get(dev, "sclk_dac");
342 if (IS_ERR_OR_NULL(sdev->sclk_dac)) {
343 dev_err(dev, "failed to get clock 'sclk_dac'\n");
344 ret = -ENXIO;
345 goto fail_irq;
346 }
347 sdev->dac = clk_get(dev, "dac");
348 if (IS_ERR_OR_NULL(sdev->dac)) {
349 dev_err(dev, "failed to get clock 'dac'\n");
350 ret = -ENXIO;
351 goto fail_sclk_dac;
352 }
353 sdev->dacphy = clk_get(dev, "dacphy");
354 if (IS_ERR_OR_NULL(sdev->dacphy)) {
355 dev_err(dev, "failed to get clock 'dacphy'\n");
356 ret = -ENXIO;
357 goto fail_dac;
358 }
359 sclk_vpll = clk_get(dev, "sclk_vpll");
360 if (IS_ERR_OR_NULL(sclk_vpll)) {
361 dev_err(dev, "failed to get clock 'sclk_vpll'\n");
362 ret = -ENXIO;
363 goto fail_dacphy;
364 }
365 clk_set_parent(sdev->sclk_dac, sclk_vpll);
366 clk_put(sclk_vpll);
367 sdev->fout_vpll = clk_get(dev, "fout_vpll");
368 if (IS_ERR_OR_NULL(sdev->fout_vpll)) {
369 dev_err(dev, "failed to get clock 'fout_vpll'\n");
370 goto fail_dacphy;
371 }
372 dev_info(dev, "fout_vpll.rate = %lu\n", clk_get_rate(sclk_vpll));
373
374 /* acquire regulator */
375 sdev->vdac = regulator_get(dev, "vdd33a_dac");
376 if (IS_ERR_OR_NULL(sdev->vdac)) {
377 dev_err(dev, "failed to get regulator 'vdac'\n");
378 goto fail_fout_vpll;
379 }
380 sdev->vdet = regulator_get(dev, "vdet");
381 if (IS_ERR_OR_NULL(sdev->vdet)) {
382 dev_err(dev, "failed to get regulator 'vdet'\n");
383 goto fail_vdac;
384 }
385
386 /* enable gate for dac clock, because mixer uses it */
387 clk_enable(sdev->dac);
388
389 /* configure power management */
390 pm_runtime_enable(dev);
391
392 /* configuration of interface subdevice */
393 v4l2_subdev_init(&sdev->sd, &sdo_sd_ops);
394 sdev->sd.owner = THIS_MODULE;
395 strlcpy(sdev->sd.name, "s5p-sdo", sizeof sdev->sd.name);
396
397 /* set default format */
398 sdev->fmt = sdo_find_format(SDO_DEFAULT_STD);
399 BUG_ON(sdev->fmt == NULL);
400
401 /* keeping subdev in device's private for use by other drivers */
402 dev_set_drvdata(dev, &sdev->sd);
403
404 dev_info(dev, "probe succeeded\n");
405 return 0;
406
407fail_vdac:
408 regulator_put(sdev->vdac);
409fail_fout_vpll:
410 clk_put(sdev->fout_vpll);
411fail_dacphy:
412 clk_put(sdev->dacphy);
413fail_dac:
414 clk_put(sdev->dac);
415fail_sclk_dac:
416 clk_put(sdev->sclk_dac);
417fail_irq:
418 free_irq(sdev->irq, sdev);
419fail_regs:
420 iounmap(sdev->regs);
421fail_sdev:
422 kfree(sdev);
423fail:
424 dev_info(dev, "probe failed\n");
425 return ret;
426}
427
428static int __devexit sdo_remove(struct platform_device *pdev)
429{
430 struct v4l2_subdev *sd = dev_get_drvdata(&pdev->dev);
431 struct sdo_device *sdev = sd_to_sdev(sd);
432
433 pm_runtime_disable(&pdev->dev);
434 clk_disable(sdev->dac);
435 regulator_put(sdev->vdet);
436 regulator_put(sdev->vdac);
437 clk_put(sdev->fout_vpll);
438 clk_put(sdev->dacphy);
439 clk_put(sdev->dac);
440 clk_put(sdev->sclk_dac);
441 free_irq(sdev->irq, sdev);
442 iounmap(sdev->regs);
443 kfree(sdev);
444
445 dev_info(&pdev->dev, "remove successful\n");
446 return 0;
447}
448
449static struct platform_driver sdo_driver __refdata = {
450 .probe = sdo_probe,
451 .remove = __devexit_p(sdo_remove),
452 .driver = {
453 .name = "s5p-sdo",
454 .owner = THIS_MODULE,
455 .pm = &sdo_pm_ops,
456 }
457};
458
459static int __init sdo_init(void)
460{
461 int ret;
462 static const char banner[] __initdata = KERN_INFO \
463 "Samsung Standard Definition Output (SDO) driver, "
464 "(c) 2010-2011 Samsung Electronics Co., Ltd.\n";
465 printk(banner);
466
467 ret = platform_driver_register(&sdo_driver);
468 if (ret)
469 printk(KERN_ERR "SDO platform driver register failed\n");
470
471 return ret;
472}
473module_init(sdo_init);
474
475static void __exit sdo_exit(void)
476{
477 platform_driver_unregister(&sdo_driver);
478}
479module_exit(sdo_exit);