hdmi_drv.c 27 KB

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