1/* 2 * TPD12S015 HDMI ESD protection & level shifter chip driver 3 * 4 * Copyright (C) 2013 Texas Instruments 5 * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> 6 * 7 * This program is free software; you can redistribute it and/or modify it 8 * under the terms of the GNU General Public License version 2 as published by 9 * the Free Software Foundation. 10 */ 11 12#include <linux/completion.h> 13#include <linux/delay.h> 14#include <linux/module.h> 15#include <linux/slab.h> 16#include <linux/gpio.h> 17#include <linux/platform_device.h> 18#include <linux/of_gpio.h> 19 20#include <video/omapdss.h> 21#include <video/omap-panel-data.h> 22 23struct panel_drv_data { 24 struct omap_dss_device dssdev; 25 struct omap_dss_device *in; 26 27 int ct_cp_hpd_gpio; 28 int ls_oe_gpio; 29 int hpd_gpio; 30 31 struct omap_video_timings timings; 32 33 struct completion hpd_completion; 34}; 35 36#define to_panel_data(x) container_of(x, struct panel_drv_data, dssdev) 37 38static irqreturn_t tpd_hpd_irq_handler(int irq, void *data) 39{ 40 struct panel_drv_data *ddata = data; 41 bool hpd; 42 43 hpd = gpio_get_value_cansleep(ddata->hpd_gpio); 44 45 dev_dbg(ddata->dssdev.dev, "hpd %d\n", hpd); 46 47 if (gpio_is_valid(ddata->ls_oe_gpio)) { 48 if (hpd) 49 gpio_set_value_cansleep(ddata->ls_oe_gpio, 1); 50 else 51 gpio_set_value_cansleep(ddata->ls_oe_gpio, 0); 52 } 53 54 complete_all(&ddata->hpd_completion); 55 56 return IRQ_HANDLED; 57} 58 59static int tpd_connect(struct omap_dss_device *dssdev, 60 struct omap_dss_device *dst) 61{ 62 struct panel_drv_data *ddata = to_panel_data(dssdev); 63 struct omap_dss_device *in = ddata->in; 64 int r; 65 66 r = in->ops.hdmi->connect(in, dssdev); 67 if (r) 68 return r; 69 70 dst->src = dssdev; 71 dssdev->dst = dst; 72 73 reinit_completion(&ddata->hpd_completion); 74 75 gpio_set_value_cansleep(ddata->ct_cp_hpd_gpio, 1); 76 /* DC-DC converter needs at max 300us to get to 90% of 5V */ 77 udelay(300); 78 79 /* 80 * If there's a cable connected, wait for the hpd irq to trigger, 81 * which turns on the level shifters. 82 */ 83 if (gpio_get_value_cansleep(ddata->hpd_gpio)) { 84 unsigned long to; 85 to = wait_for_completion_timeout(&ddata->hpd_completion, 86 msecs_to_jiffies(250)); 87 WARN_ON_ONCE(to == 0); 88 } 89 90 return 0; 91} 92 93static void tpd_disconnect(struct omap_dss_device *dssdev, 94 struct omap_dss_device *dst) 95{ 96 struct panel_drv_data *ddata = to_panel_data(dssdev); 97 struct omap_dss_device *in = ddata->in; 98 99 WARN_ON(dst != dssdev->dst); 100 101 if (dst != dssdev->dst) 102 return; 103 104 gpio_set_value_cansleep(ddata->ct_cp_hpd_gpio, 0); 105 106 dst->src = NULL; 107 dssdev->dst = NULL; 108 109 in->ops.hdmi->disconnect(in, &ddata->dssdev); 110} 111 112static int tpd_enable(struct omap_dss_device *dssdev) 113{ 114 struct panel_drv_data *ddata = to_panel_data(dssdev); 115 struct omap_dss_device *in = ddata->in; 116 int r; 117 118 if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) 119 return 0; 120 121 in->ops.hdmi->set_timings(in, &ddata->timings); 122 123 r = in->ops.hdmi->enable(in); 124 if (r) 125 return r; 126 127 dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; 128 129 return r; 130} 131 132static void tpd_disable(struct omap_dss_device *dssdev) 133{ 134 struct panel_drv_data *ddata = to_panel_data(dssdev); 135 struct omap_dss_device *in = ddata->in; 136 137 if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) 138 return; 139 140 in->ops.hdmi->disable(in); 141 142 dssdev->state = OMAP_DSS_DISPLAY_DISABLED; 143} 144 145static void tpd_set_timings(struct omap_dss_device *dssdev, 146 struct omap_video_timings *timings) 147{ 148 struct panel_drv_data *ddata = to_panel_data(dssdev); 149 struct omap_dss_device *in = ddata->in; 150 151 ddata->timings = *timings; 152 dssdev->panel.timings = *timings; 153 154 in->ops.hdmi->set_timings(in, timings); 155} 156 157static void tpd_get_timings(struct omap_dss_device *dssdev, 158 struct omap_video_timings *timings) 159{ 160 struct panel_drv_data *ddata = to_panel_data(dssdev); 161 162 *timings = ddata->timings; 163} 164 165static int tpd_check_timings(struct omap_dss_device *dssdev, 166 struct omap_video_timings *timings) 167{ 168 struct panel_drv_data *ddata = to_panel_data(dssdev); 169 struct omap_dss_device *in = ddata->in; 170 int r; 171 172 r = in->ops.hdmi->check_timings(in, timings); 173 174 return r; 175} 176 177static int tpd_read_edid(struct omap_dss_device *dssdev, 178 u8 *edid, int len) 179{ 180 struct panel_drv_data *ddata = to_panel_data(dssdev); 181 struct omap_dss_device *in = ddata->in; 182 183 if (!gpio_get_value_cansleep(ddata->hpd_gpio)) 184 return -ENODEV; 185 186 return in->ops.hdmi->read_edid(in, edid, len); 187} 188 189static bool tpd_detect(struct omap_dss_device *dssdev) 190{ 191 struct panel_drv_data *ddata = to_panel_data(dssdev); 192 193 return gpio_get_value_cansleep(ddata->hpd_gpio); 194} 195 196static int tpd_audio_enable(struct omap_dss_device *dssdev) 197{ 198 struct panel_drv_data *ddata = to_panel_data(dssdev); 199 struct omap_dss_device *in = ddata->in; 200 201 return in->ops.hdmi->audio_enable(in); 202} 203 204static void tpd_audio_disable(struct omap_dss_device *dssdev) 205{ 206 struct panel_drv_data *ddata = to_panel_data(dssdev); 207 struct omap_dss_device *in = ddata->in; 208 209 in->ops.hdmi->audio_disable(in); 210} 211 212static int tpd_audio_start(struct omap_dss_device *dssdev) 213{ 214 struct panel_drv_data *ddata = to_panel_data(dssdev); 215 struct omap_dss_device *in = ddata->in; 216 217 return in->ops.hdmi->audio_start(in); 218} 219 220static void tpd_audio_stop(struct omap_dss_device *dssdev) 221{ 222 struct panel_drv_data *ddata = to_panel_data(dssdev); 223 struct omap_dss_device *in = ddata->in; 224 225 in->ops.hdmi->audio_stop(in); 226} 227 228static bool tpd_audio_supported(struct omap_dss_device *dssdev) 229{ 230 struct panel_drv_data *ddata = to_panel_data(dssdev); 231 struct omap_dss_device *in = ddata->in; 232 233 return in->ops.hdmi->audio_supported(in); 234} 235 236static int tpd_audio_config(struct omap_dss_device *dssdev, 237 struct omap_dss_audio *audio) 238{ 239 struct panel_drv_data *ddata = to_panel_data(dssdev); 240 struct omap_dss_device *in = ddata->in; 241 242 return in->ops.hdmi->audio_config(in, audio); 243} 244 245static int tpd_set_infoframe(struct omap_dss_device *dssdev, 246 const struct hdmi_avi_infoframe *avi) 247{ 248 struct panel_drv_data *ddata = to_panel_data(dssdev); 249 struct omap_dss_device *in = ddata->in; 250 251 return in->ops.hdmi->set_infoframe(in, avi); 252} 253 254static int tpd_set_hdmi_mode(struct omap_dss_device *dssdev, 255 bool hdmi_mode) 256{ 257 struct panel_drv_data *ddata = to_panel_data(dssdev); 258 struct omap_dss_device *in = ddata->in; 259 260 return in->ops.hdmi->set_hdmi_mode(in, hdmi_mode); 261} 262 263static const struct omapdss_hdmi_ops tpd_hdmi_ops = { 264 .connect = tpd_connect, 265 .disconnect = tpd_disconnect, 266 267 .enable = tpd_enable, 268 .disable = tpd_disable, 269 270 .check_timings = tpd_check_timings, 271 .set_timings = tpd_set_timings, 272 .get_timings = tpd_get_timings, 273 274 .read_edid = tpd_read_edid, 275 .detect = tpd_detect, 276 .set_infoframe = tpd_set_infoframe, 277 .set_hdmi_mode = tpd_set_hdmi_mode, 278 279 .audio_enable = tpd_audio_enable, 280 .audio_disable = tpd_audio_disable, 281 .audio_start = tpd_audio_start, 282 .audio_stop = tpd_audio_stop, 283 .audio_supported = tpd_audio_supported, 284 .audio_config = tpd_audio_config, 285}; 286 287static int tpd_probe_pdata(struct platform_device *pdev) 288{ 289 struct panel_drv_data *ddata = platform_get_drvdata(pdev); 290 struct encoder_tpd12s015_platform_data *pdata; 291 struct omap_dss_device *dssdev, *in; 292 293 pdata = dev_get_platdata(&pdev->dev); 294 295 ddata->ct_cp_hpd_gpio = pdata->ct_cp_hpd_gpio; 296 ddata->ls_oe_gpio = pdata->ls_oe_gpio; 297 ddata->hpd_gpio = pdata->hpd_gpio; 298 299 in = omap_dss_find_output(pdata->source); 300 if (in == NULL) { 301 dev_err(&pdev->dev, "Failed to find video source\n"); 302 return -ENODEV; 303 } 304 305 ddata->in = in; 306 307 dssdev = &ddata->dssdev; 308 dssdev->name = pdata->name; 309 310 return 0; 311} 312 313static int tpd_probe_of(struct platform_device *pdev) 314{ 315 struct panel_drv_data *ddata = platform_get_drvdata(pdev); 316 struct device_node *node = pdev->dev.of_node; 317 struct omap_dss_device *in; 318 int gpio; 319 320 /* CT CP HPD GPIO */ 321 gpio = of_get_gpio(node, 0); 322 if (!gpio_is_valid(gpio)) { 323 dev_err(&pdev->dev, "failed to parse CT CP HPD gpio\n"); 324 return gpio; 325 } 326 ddata->ct_cp_hpd_gpio = gpio; 327 328 /* LS OE GPIO */ 329 gpio = of_get_gpio(node, 1); 330 if (gpio_is_valid(gpio) || gpio == -ENOENT) { 331 ddata->ls_oe_gpio = gpio; 332 } else { 333 dev_err(&pdev->dev, "failed to parse LS OE gpio\n"); 334 return gpio; 335 } 336 337 /* HPD GPIO */ 338 gpio = of_get_gpio(node, 2); 339 if (!gpio_is_valid(gpio)) { 340 dev_err(&pdev->dev, "failed to parse HPD gpio\n"); 341 return gpio; 342 } 343 ddata->hpd_gpio = gpio; 344 345 in = omapdss_of_find_source_for_first_ep(node); 346 if (IS_ERR(in)) { 347 dev_err(&pdev->dev, "failed to find video source\n"); 348 return PTR_ERR(in); 349 } 350 351 ddata->in = in; 352 353 return 0; 354} 355 356static int tpd_probe(struct platform_device *pdev) 357{ 358 struct omap_dss_device *in, *dssdev; 359 struct panel_drv_data *ddata; 360 int r; 361 362 ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL); 363 if (!ddata) 364 return -ENOMEM; 365 366 platform_set_drvdata(pdev, ddata); 367 368 init_completion(&ddata->hpd_completion); 369 370 if (dev_get_platdata(&pdev->dev)) { 371 r = tpd_probe_pdata(pdev); 372 if (r) 373 return r; 374 } else if (pdev->dev.of_node) { 375 r = tpd_probe_of(pdev); 376 if (r) 377 return r; 378 } else { 379 return -ENODEV; 380 } 381 382 r = devm_gpio_request_one(&pdev->dev, ddata->ct_cp_hpd_gpio, 383 GPIOF_OUT_INIT_LOW, "hdmi_ct_cp_hpd"); 384 if (r) 385 goto err_gpio; 386 387 if (gpio_is_valid(ddata->ls_oe_gpio)) { 388 r = devm_gpio_request_one(&pdev->dev, ddata->ls_oe_gpio, 389 GPIOF_OUT_INIT_LOW, "hdmi_ls_oe"); 390 if (r) 391 goto err_gpio; 392 } 393 394 r = devm_gpio_request_one(&pdev->dev, ddata->hpd_gpio, 395 GPIOF_DIR_IN, "hdmi_hpd"); 396 if (r) 397 goto err_gpio; 398 399 r = devm_request_threaded_irq(&pdev->dev, gpio_to_irq(ddata->hpd_gpio), 400 NULL, tpd_hpd_irq_handler, 401 IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | 402 IRQF_ONESHOT, "hpd", ddata); 403 if (r) 404 goto err_irq; 405 406 dssdev = &ddata->dssdev; 407 dssdev->ops.hdmi = &tpd_hdmi_ops; 408 dssdev->dev = &pdev->dev; 409 dssdev->type = OMAP_DISPLAY_TYPE_HDMI; 410 dssdev->output_type = OMAP_DISPLAY_TYPE_HDMI; 411 dssdev->owner = THIS_MODULE; 412 413 in = ddata->in; 414 415 r = omapdss_register_output(dssdev); 416 if (r) { 417 dev_err(&pdev->dev, "Failed to register output\n"); 418 goto err_reg; 419 } 420 421 return 0; 422err_reg: 423err_irq: 424err_gpio: 425 omap_dss_put_device(ddata->in); 426 return r; 427} 428 429static int __exit tpd_remove(struct platform_device *pdev) 430{ 431 struct panel_drv_data *ddata = platform_get_drvdata(pdev); 432 struct omap_dss_device *dssdev = &ddata->dssdev; 433 struct omap_dss_device *in = ddata->in; 434 435 omapdss_unregister_output(&ddata->dssdev); 436 437 WARN_ON(omapdss_device_is_enabled(dssdev)); 438 if (omapdss_device_is_enabled(dssdev)) 439 tpd_disable(dssdev); 440 441 WARN_ON(omapdss_device_is_connected(dssdev)); 442 if (omapdss_device_is_connected(dssdev)) 443 tpd_disconnect(dssdev, dssdev->dst); 444 445 omap_dss_put_device(in); 446 447 return 0; 448} 449 450static const struct of_device_id tpd_of_match[] = { 451 { .compatible = "omapdss,ti,tpd12s015", }, 452 {}, 453}; 454 455MODULE_DEVICE_TABLE(of, tpd_of_match); 456 457static struct platform_driver tpd_driver = { 458 .probe = tpd_probe, 459 .remove = __exit_p(tpd_remove), 460 .driver = { 461 .name = "tpd12s015", 462 .owner = THIS_MODULE, 463 .of_match_table = tpd_of_match, 464 .suppress_bind_attrs = true, 465 }, 466}; 467 468module_platform_driver(tpd_driver); 469 470MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>"); 471MODULE_DESCRIPTION("TPD12S015 driver"); 472MODULE_LICENSE("GPL"); 473