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