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