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 const 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_get_fmt(struct v4l2_subdev *sd, 652 struct v4l2_subdev_pad_config *cfg, 653 struct v4l2_subdev_format *format) 654{ 655 struct v4l2_mbus_framefmt *fmt = &format->format; 656 struct hdmi_device *hdev = sd_to_hdmi_dev(sd); 657 const struct hdmi_timings *t = hdev->cur_conf; 658 659 dev_dbg(hdev->dev, "%s\n", __func__); 660 if (!hdev->cur_conf) 661 return -EINVAL; 662 if (format->pad) 663 return -EINVAL; 664 665 memset(fmt, 0, sizeof(*fmt)); 666 fmt->width = t->hact.end - t->hact.beg; 667 fmt->height = t->vact[0].end - t->vact[0].beg; 668 fmt->code = MEDIA_BUS_FMT_FIXED; /* means RGB888 */ 669 fmt->colorspace = V4L2_COLORSPACE_SRGB; 670 if (t->interlaced) { 671 fmt->field = V4L2_FIELD_INTERLACED; 672 fmt->height *= 2; 673 } else { 674 fmt->field = V4L2_FIELD_NONE; 675 } 676 return 0; 677} 678 679static int hdmi_enum_dv_timings(struct v4l2_subdev *sd, 680 struct v4l2_enum_dv_timings *timings) 681{ 682 if (timings->pad != 0) 683 return -EINVAL; 684 if (timings->index >= ARRAY_SIZE(hdmi_timings)) 685 return -EINVAL; 686 timings->timings = hdmi_timings[timings->index].dv_timings; 687 if (!hdmi_timings[timings->index].reduced_fps) 688 timings->timings.bt.flags &= ~V4L2_DV_FL_CAN_REDUCE_FPS; 689 return 0; 690} 691 692static int hdmi_dv_timings_cap(struct v4l2_subdev *sd, 693 struct v4l2_dv_timings_cap *cap) 694{ 695 struct hdmi_device *hdev = sd_to_hdmi_dev(sd); 696 697 if (cap->pad != 0) 698 return -EINVAL; 699 700 /* Let the phy fill in the pixelclock range */ 701 v4l2_subdev_call(hdev->phy_sd, pad, dv_timings_cap, cap); 702 cap->type = V4L2_DV_BT_656_1120; 703 cap->bt.min_width = 720; 704 cap->bt.max_width = 1920; 705 cap->bt.min_height = 480; 706 cap->bt.max_height = 1080; 707 cap->bt.standards = V4L2_DV_BT_STD_CEA861; 708 cap->bt.capabilities = V4L2_DV_BT_CAP_INTERLACED | 709 V4L2_DV_BT_CAP_PROGRESSIVE; 710 return 0; 711} 712 713static const struct v4l2_subdev_core_ops hdmi_sd_core_ops = { 714 .s_power = hdmi_s_power, 715}; 716 717static const struct v4l2_subdev_video_ops hdmi_sd_video_ops = { 718 .s_dv_timings = hdmi_s_dv_timings, 719 .g_dv_timings = hdmi_g_dv_timings, 720 .s_stream = hdmi_s_stream, 721}; 722 723static const struct v4l2_subdev_pad_ops hdmi_sd_pad_ops = { 724 .enum_dv_timings = hdmi_enum_dv_timings, 725 .dv_timings_cap = hdmi_dv_timings_cap, 726 .get_fmt = hdmi_get_fmt, 727}; 728 729static const struct v4l2_subdev_ops hdmi_sd_ops = { 730 .core = &hdmi_sd_core_ops, 731 .video = &hdmi_sd_video_ops, 732 .pad = &hdmi_sd_pad_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 v4l2_subdev_call(hdev->mhl_sd, core, s_power, 0); 742 hdmi_resource_poweroff(&hdev->res); 743 /* flag that device context is lost */ 744 hdev->cur_conf_dirty = 1; 745 return 0; 746} 747 748static int hdmi_runtime_resume(struct device *dev) 749{ 750 struct v4l2_subdev *sd = dev_get_drvdata(dev); 751 struct hdmi_device *hdev = sd_to_hdmi_dev(sd); 752 int ret; 753 754 dev_dbg(dev, "%s\n", __func__); 755 756 ret = hdmi_resource_poweron(&hdev->res); 757 if (ret < 0) 758 return ret; 759 760 /* starting MHL */ 761 ret = v4l2_subdev_call(hdev->mhl_sd, core, s_power, 1); 762 if (hdev->mhl_sd && ret) 763 goto fail; 764 765 dev_dbg(dev, "poweron succeed\n"); 766 767 return 0; 768 769fail: 770 hdmi_resource_poweroff(&hdev->res); 771 dev_err(dev, "poweron failed\n"); 772 773 return ret; 774} 775 776static const struct dev_pm_ops hdmi_pm_ops = { 777 .runtime_suspend = hdmi_runtime_suspend, 778 .runtime_resume = hdmi_runtime_resume, 779}; 780 781static void hdmi_resource_clear_clocks(struct hdmi_resources *res) 782{ 783 res->hdmi = ERR_PTR(-EINVAL); 784 res->sclk_hdmi = ERR_PTR(-EINVAL); 785 res->sclk_pixel = ERR_PTR(-EINVAL); 786 res->sclk_hdmiphy = ERR_PTR(-EINVAL); 787 res->hdmiphy = ERR_PTR(-EINVAL); 788} 789 790static void hdmi_resources_cleanup(struct hdmi_device *hdev) 791{ 792 struct hdmi_resources *res = &hdev->res; 793 794 dev_dbg(hdev->dev, "HDMI resource cleanup\n"); 795 /* put clocks, power */ 796 if (res->regul_count) 797 regulator_bulk_free(res->regul_count, res->regul_bulk); 798 /* kfree is NULL-safe */ 799 kfree(res->regul_bulk); 800 if (!IS_ERR(res->hdmiphy)) 801 clk_put(res->hdmiphy); 802 if (!IS_ERR(res->sclk_hdmiphy)) 803 clk_put(res->sclk_hdmiphy); 804 if (!IS_ERR(res->sclk_pixel)) 805 clk_put(res->sclk_pixel); 806 if (!IS_ERR(res->sclk_hdmi)) 807 clk_put(res->sclk_hdmi); 808 if (!IS_ERR(res->hdmi)) 809 clk_put(res->hdmi); 810 memset(res, 0, sizeof(*res)); 811 hdmi_resource_clear_clocks(res); 812} 813 814static int hdmi_resources_init(struct hdmi_device *hdev) 815{ 816 struct device *dev = hdev->dev; 817 struct hdmi_resources *res = &hdev->res; 818 static char *supply[] = { 819 "hdmi-en", 820 "vdd", 821 "vdd_osc", 822 "vdd_pll", 823 }; 824 int i, ret; 825 826 dev_dbg(dev, "HDMI resource init\n"); 827 828 memset(res, 0, sizeof(*res)); 829 hdmi_resource_clear_clocks(res); 830 831 /* get clocks, power */ 832 res->hdmi = clk_get(dev, "hdmi"); 833 if (IS_ERR(res->hdmi)) { 834 dev_err(dev, "failed to get clock 'hdmi'\n"); 835 goto fail; 836 } 837 res->sclk_hdmi = clk_get(dev, "sclk_hdmi"); 838 if (IS_ERR(res->sclk_hdmi)) { 839 dev_err(dev, "failed to get clock 'sclk_hdmi'\n"); 840 goto fail; 841 } 842 res->sclk_pixel = clk_get(dev, "sclk_pixel"); 843 if (IS_ERR(res->sclk_pixel)) { 844 dev_err(dev, "failed to get clock 'sclk_pixel'\n"); 845 goto fail; 846 } 847 res->sclk_hdmiphy = clk_get(dev, "sclk_hdmiphy"); 848 if (IS_ERR(res->sclk_hdmiphy)) { 849 dev_err(dev, "failed to get clock 'sclk_hdmiphy'\n"); 850 goto fail; 851 } 852 res->hdmiphy = clk_get(dev, "hdmiphy"); 853 if (IS_ERR(res->hdmiphy)) { 854 dev_err(dev, "failed to get clock 'hdmiphy'\n"); 855 goto fail; 856 } 857 res->regul_bulk = kcalloc(ARRAY_SIZE(supply), 858 sizeof(res->regul_bulk[0]), GFP_KERNEL); 859 if (!res->regul_bulk) { 860 dev_err(dev, "failed to get memory for regulators\n"); 861 goto fail; 862 } 863 for (i = 0; i < ARRAY_SIZE(supply); ++i) { 864 res->regul_bulk[i].supply = supply[i]; 865 res->regul_bulk[i].consumer = NULL; 866 } 867 868 ret = regulator_bulk_get(dev, ARRAY_SIZE(supply), res->regul_bulk); 869 if (ret) { 870 dev_err(dev, "failed to get regulators\n"); 871 goto fail; 872 } 873 res->regul_count = ARRAY_SIZE(supply); 874 875 return 0; 876fail: 877 dev_err(dev, "HDMI resource init - failed\n"); 878 hdmi_resources_cleanup(hdev); 879 return -ENODEV; 880} 881 882static int hdmi_probe(struct platform_device *pdev) 883{ 884 struct device *dev = &pdev->dev; 885 struct resource *res; 886 struct i2c_adapter *adapter; 887 struct v4l2_subdev *sd; 888 struct hdmi_device *hdmi_dev = NULL; 889 struct s5p_hdmi_platform_data *pdata = dev->platform_data; 890 int ret; 891 892 dev_dbg(dev, "probe start\n"); 893 894 if (!pdata) { 895 dev_err(dev, "platform data is missing\n"); 896 ret = -ENODEV; 897 goto fail; 898 } 899 900 hdmi_dev = devm_kzalloc(&pdev->dev, sizeof(*hdmi_dev), GFP_KERNEL); 901 if (!hdmi_dev) { 902 dev_err(dev, "out of memory\n"); 903 ret = -ENOMEM; 904 goto fail; 905 } 906 907 hdmi_dev->dev = dev; 908 909 ret = hdmi_resources_init(hdmi_dev); 910 if (ret) 911 goto fail; 912 913 /* mapping HDMI registers */ 914 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 915 if (res == NULL) { 916 dev_err(dev, "get memory resource failed.\n"); 917 ret = -ENXIO; 918 goto fail_init; 919 } 920 921 hdmi_dev->regs = devm_ioremap(&pdev->dev, res->start, 922 resource_size(res)); 923 if (hdmi_dev->regs == NULL) { 924 dev_err(dev, "register mapping failed.\n"); 925 ret = -ENXIO; 926 goto fail_init; 927 } 928 929 res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); 930 if (res == NULL) { 931 dev_err(dev, "get interrupt resource failed.\n"); 932 ret = -ENXIO; 933 goto fail_init; 934 } 935 936 ret = devm_request_irq(&pdev->dev, res->start, hdmi_irq_handler, 0, 937 "hdmi", hdmi_dev); 938 if (ret) { 939 dev_err(dev, "request interrupt failed.\n"); 940 goto fail_init; 941 } 942 hdmi_dev->irq = res->start; 943 944 /* setting v4l2 name to prevent WARN_ON in v4l2_device_register */ 945 strlcpy(hdmi_dev->v4l2_dev.name, dev_name(dev), 946 sizeof(hdmi_dev->v4l2_dev.name)); 947 /* passing NULL owner prevents driver from erasing drvdata */ 948 ret = v4l2_device_register(NULL, &hdmi_dev->v4l2_dev); 949 if (ret) { 950 dev_err(dev, "could not register v4l2 device.\n"); 951 goto fail_init; 952 } 953 954 /* testing if hdmiphy info is present */ 955 if (!pdata->hdmiphy_info) { 956 dev_err(dev, "hdmiphy info is missing in platform data\n"); 957 ret = -ENXIO; 958 goto fail_vdev; 959 } 960 961 adapter = i2c_get_adapter(pdata->hdmiphy_bus); 962 if (adapter == NULL) { 963 dev_err(dev, "hdmiphy adapter request failed\n"); 964 ret = -ENXIO; 965 goto fail_vdev; 966 } 967 968 hdmi_dev->phy_sd = v4l2_i2c_new_subdev_board(&hdmi_dev->v4l2_dev, 969 adapter, pdata->hdmiphy_info, NULL); 970 /* on failure or not adapter is no longer useful */ 971 i2c_put_adapter(adapter); 972 if (hdmi_dev->phy_sd == NULL) { 973 dev_err(dev, "missing subdev for hdmiphy\n"); 974 ret = -ENODEV; 975 goto fail_vdev; 976 } 977 978 /* initialization of MHL interface if present */ 979 if (pdata->mhl_info) { 980 adapter = i2c_get_adapter(pdata->mhl_bus); 981 if (adapter == NULL) { 982 dev_err(dev, "MHL adapter request failed\n"); 983 ret = -ENXIO; 984 goto fail_vdev; 985 } 986 987 hdmi_dev->mhl_sd = v4l2_i2c_new_subdev_board( 988 &hdmi_dev->v4l2_dev, adapter, 989 pdata->mhl_info, NULL); 990 /* on failure or not adapter is no longer useful */ 991 i2c_put_adapter(adapter); 992 if (hdmi_dev->mhl_sd == NULL) { 993 dev_err(dev, "missing subdev for MHL\n"); 994 ret = -ENODEV; 995 goto fail_vdev; 996 } 997 } 998 999 clk_enable(hdmi_dev->res.hdmi); 1000 1001 pm_runtime_enable(dev); 1002 1003 sd = &hdmi_dev->sd; 1004 v4l2_subdev_init(sd, &hdmi_sd_ops); 1005 sd->owner = THIS_MODULE; 1006 1007 strlcpy(sd->name, "s5p-hdmi", sizeof(sd->name)); 1008 hdmi_dev->cur_timings = 1009 hdmi_timings[HDMI_DEFAULT_TIMINGS_IDX].dv_timings; 1010 /* FIXME: missing fail timings is not supported */ 1011 hdmi_dev->cur_conf = 1012 hdmi_timings[HDMI_DEFAULT_TIMINGS_IDX].hdmi_timings; 1013 hdmi_dev->cur_conf_dirty = 1; 1014 1015 /* storing subdev for call that have only access to struct device */ 1016 dev_set_drvdata(dev, sd); 1017 1018 dev_info(dev, "probe successful\n"); 1019 1020 return 0; 1021 1022fail_vdev: 1023 v4l2_device_unregister(&hdmi_dev->v4l2_dev); 1024 1025fail_init: 1026 hdmi_resources_cleanup(hdmi_dev); 1027 1028fail: 1029 dev_err(dev, "probe failed\n"); 1030 return ret; 1031} 1032 1033static int hdmi_remove(struct platform_device *pdev) 1034{ 1035 struct device *dev = &pdev->dev; 1036 struct v4l2_subdev *sd = dev_get_drvdata(dev); 1037 struct hdmi_device *hdmi_dev = sd_to_hdmi_dev(sd); 1038 1039 pm_runtime_disable(dev); 1040 clk_disable(hdmi_dev->res.hdmi); 1041 v4l2_device_unregister(&hdmi_dev->v4l2_dev); 1042 disable_irq(hdmi_dev->irq); 1043 hdmi_resources_cleanup(hdmi_dev); 1044 dev_info(dev, "remove successful\n"); 1045 1046 return 0; 1047} 1048 1049static struct platform_driver hdmi_driver __refdata = { 1050 .probe = hdmi_probe, 1051 .remove = hdmi_remove, 1052 .id_table = hdmi_driver_types, 1053 .driver = { 1054 .name = "s5p-hdmi", 1055 .pm = &hdmi_pm_ops, 1056 } 1057}; 1058 1059module_platform_driver(hdmi_driver); 1060