Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v3.4-rc7 600 lines 14 kB view raw
1/* linux/drivers/video/exynos/exynos_mipi_dsi.c 2 * 3 * Samsung SoC MIPI-DSIM driver. 4 * 5 * Copyright (c) 2012 Samsung Electronics Co., Ltd 6 * 7 * InKi Dae, <inki.dae@samsung.com> 8 * Donghwa Lee, <dh09.lee@samsung.com> 9 * 10 * This program is free software; you can redistribute it and/or modify 11 * it under the terms of the GNU General Public License version 2 as 12 * published by the Free Software Foundation. 13*/ 14 15#include <linux/module.h> 16#include <linux/kernel.h> 17#include <linux/errno.h> 18#include <linux/clk.h> 19#include <linux/mutex.h> 20#include <linux/wait.h> 21#include <linux/fs.h> 22#include <linux/mm.h> 23#include <linux/fb.h> 24#include <linux/ctype.h> 25#include <linux/platform_device.h> 26#include <linux/io.h> 27#include <linux/irq.h> 28#include <linux/memory.h> 29#include <linux/delay.h> 30#include <linux/interrupt.h> 31#include <linux/kthread.h> 32#include <linux/notifier.h> 33#include <linux/regulator/consumer.h> 34#include <linux/pm_runtime.h> 35 36#include <video/exynos_mipi_dsim.h> 37 38#include <plat/fb.h> 39 40#include "exynos_mipi_dsi_common.h" 41#include "exynos_mipi_dsi_lowlevel.h" 42 43struct mipi_dsim_ddi { 44 int bus_id; 45 struct list_head list; 46 struct mipi_dsim_lcd_device *dsim_lcd_dev; 47 struct mipi_dsim_lcd_driver *dsim_lcd_drv; 48}; 49 50static LIST_HEAD(dsim_ddi_list); 51 52static DEFINE_MUTEX(mipi_dsim_lock); 53 54static struct mipi_dsim_platform_data *to_dsim_plat(struct platform_device 55 *pdev) 56{ 57 return pdev->dev.platform_data; 58} 59 60static struct regulator_bulk_data supplies[] = { 61 { .supply = "vdd10", }, 62 { .supply = "vdd18", }, 63}; 64 65static int exynos_mipi_regulator_enable(struct mipi_dsim_device *dsim) 66{ 67 int ret; 68 69 mutex_lock(&dsim->lock); 70 ret = regulator_bulk_enable(ARRAY_SIZE(supplies), supplies); 71 mutex_unlock(&dsim->lock); 72 73 return ret; 74} 75 76static int exynos_mipi_regulator_disable(struct mipi_dsim_device *dsim) 77{ 78 int ret; 79 80 mutex_lock(&dsim->lock); 81 ret = regulator_bulk_disable(ARRAY_SIZE(supplies), supplies); 82 mutex_unlock(&dsim->lock); 83 84 return ret; 85} 86 87/* update all register settings to MIPI DSI controller. */ 88static void exynos_mipi_update_cfg(struct mipi_dsim_device *dsim) 89{ 90 /* 91 * data from Display controller(FIMD) is not transferred in video mode 92 * but in case of command mode, all settings is not updated to 93 * registers. 94 */ 95 exynos_mipi_dsi_stand_by(dsim, 0); 96 97 exynos_mipi_dsi_init_dsim(dsim); 98 exynos_mipi_dsi_init_link(dsim); 99 100 exynos_mipi_dsi_set_hs_enable(dsim); 101 102 /* set display timing. */ 103 exynos_mipi_dsi_set_display_mode(dsim, dsim->dsim_config); 104 105 /* 106 * data from Display controller(FIMD) is transferred in video mode 107 * but in case of command mode, all settigs is updated to registers. 108 */ 109 exynos_mipi_dsi_stand_by(dsim, 1); 110} 111 112static int exynos_mipi_dsi_early_blank_mode(struct mipi_dsim_device *dsim, 113 int power) 114{ 115 struct mipi_dsim_lcd_driver *client_drv = dsim->dsim_lcd_drv; 116 struct mipi_dsim_lcd_device *client_dev = dsim->dsim_lcd_dev; 117 118 switch (power) { 119 case FB_BLANK_POWERDOWN: 120 if (dsim->suspended) 121 return 0; 122 123 if (client_drv && client_drv->suspend) 124 client_drv->suspend(client_dev); 125 126 clk_disable(dsim->clock); 127 128 exynos_mipi_regulator_disable(dsim); 129 130 dsim->suspended = true; 131 132 break; 133 default: 134 break; 135 } 136 137 return 0; 138} 139 140static int exynos_mipi_dsi_blank_mode(struct mipi_dsim_device *dsim, int power) 141{ 142 struct platform_device *pdev = to_platform_device(dsim->dev); 143 struct mipi_dsim_lcd_driver *client_drv = dsim->dsim_lcd_drv; 144 struct mipi_dsim_lcd_device *client_dev = dsim->dsim_lcd_dev; 145 146 switch (power) { 147 case FB_BLANK_UNBLANK: 148 if (!dsim->suspended) 149 return 0; 150 151 /* lcd panel power on. */ 152 if (client_drv && client_drv->power_on) 153 client_drv->power_on(client_dev, 1); 154 155 exynos_mipi_regulator_disable(dsim); 156 157 /* enable MIPI-DSI PHY. */ 158 if (dsim->pd->phy_enable) 159 dsim->pd->phy_enable(pdev, true); 160 161 clk_enable(dsim->clock); 162 163 exynos_mipi_update_cfg(dsim); 164 165 /* set lcd panel sequence commands. */ 166 if (client_drv && client_drv->set_sequence) 167 client_drv->set_sequence(client_dev); 168 169 dsim->suspended = false; 170 171 break; 172 case FB_BLANK_NORMAL: 173 /* TODO. */ 174 break; 175 default: 176 break; 177 } 178 179 return 0; 180} 181 182int exynos_mipi_dsi_register_lcd_device(struct mipi_dsim_lcd_device *lcd_dev) 183{ 184 struct mipi_dsim_ddi *dsim_ddi; 185 186 if (!lcd_dev->name) { 187 pr_err("dsim_lcd_device name is NULL.\n"); 188 return -EFAULT; 189 } 190 191 dsim_ddi = kzalloc(sizeof(struct mipi_dsim_ddi), GFP_KERNEL); 192 if (!dsim_ddi) { 193 pr_err("failed to allocate dsim_ddi object.\n"); 194 return -ENOMEM; 195 } 196 197 dsim_ddi->dsim_lcd_dev = lcd_dev; 198 199 mutex_lock(&mipi_dsim_lock); 200 list_add_tail(&dsim_ddi->list, &dsim_ddi_list); 201 mutex_unlock(&mipi_dsim_lock); 202 203 return 0; 204} 205 206struct mipi_dsim_ddi *exynos_mipi_dsi_find_lcd_device(struct mipi_dsim_lcd_driver *lcd_drv) 207{ 208 struct mipi_dsim_ddi *dsim_ddi, *next; 209 struct mipi_dsim_lcd_device *lcd_dev; 210 211 mutex_lock(&mipi_dsim_lock); 212 213 list_for_each_entry_safe(dsim_ddi, next, &dsim_ddi_list, list) { 214 if (!dsim_ddi) 215 goto out; 216 217 lcd_dev = dsim_ddi->dsim_lcd_dev; 218 if (!lcd_dev) 219 continue; 220 221 if ((strcmp(lcd_drv->name, lcd_dev->name)) == 0) { 222 /** 223 * bus_id would be used to identify 224 * connected bus. 225 */ 226 dsim_ddi->bus_id = lcd_dev->bus_id; 227 mutex_unlock(&mipi_dsim_lock); 228 229 return dsim_ddi; 230 } 231 232 list_del(&dsim_ddi->list); 233 kfree(dsim_ddi); 234 } 235 236out: 237 mutex_unlock(&mipi_dsim_lock); 238 239 return NULL; 240} 241 242int exynos_mipi_dsi_register_lcd_driver(struct mipi_dsim_lcd_driver *lcd_drv) 243{ 244 struct mipi_dsim_ddi *dsim_ddi; 245 246 if (!lcd_drv->name) { 247 pr_err("dsim_lcd_driver name is NULL.\n"); 248 return -EFAULT; 249 } 250 251 dsim_ddi = exynos_mipi_dsi_find_lcd_device(lcd_drv); 252 if (!dsim_ddi) { 253 pr_err("mipi_dsim_ddi object not found.\n"); 254 return -EFAULT; 255 } 256 257 dsim_ddi->dsim_lcd_drv = lcd_drv; 258 259 pr_info("registered panel driver(%s) to mipi-dsi driver.\n", 260 lcd_drv->name); 261 262 return 0; 263 264} 265 266struct mipi_dsim_ddi *exynos_mipi_dsi_bind_lcd_ddi(struct mipi_dsim_device *dsim, 267 const char *name) 268{ 269 struct mipi_dsim_ddi *dsim_ddi, *next; 270 struct mipi_dsim_lcd_driver *lcd_drv; 271 struct mipi_dsim_lcd_device *lcd_dev; 272 int ret; 273 274 mutex_lock(&dsim->lock); 275 276 list_for_each_entry_safe(dsim_ddi, next, &dsim_ddi_list, list) { 277 lcd_drv = dsim_ddi->dsim_lcd_drv; 278 lcd_dev = dsim_ddi->dsim_lcd_dev; 279 if (!lcd_drv || !lcd_dev || 280 (dsim->id != dsim_ddi->bus_id)) 281 continue; 282 283 dev_dbg(dsim->dev, "lcd_drv->id = %d, lcd_dev->id = %d\n", 284 lcd_drv->id, lcd_dev->id); 285 dev_dbg(dsim->dev, "lcd_dev->bus_id = %d, dsim->id = %d\n", 286 lcd_dev->bus_id, dsim->id); 287 288 if ((strcmp(lcd_drv->name, name) == 0)) { 289 lcd_dev->master = dsim; 290 291 lcd_dev->dev.parent = dsim->dev; 292 dev_set_name(&lcd_dev->dev, "%s", lcd_drv->name); 293 294 ret = device_register(&lcd_dev->dev); 295 if (ret < 0) { 296 dev_err(dsim->dev, 297 "can't register %s, status %d\n", 298 dev_name(&lcd_dev->dev), ret); 299 mutex_unlock(&dsim->lock); 300 301 return NULL; 302 } 303 304 dsim->dsim_lcd_dev = lcd_dev; 305 dsim->dsim_lcd_drv = lcd_drv; 306 307 mutex_unlock(&dsim->lock); 308 309 return dsim_ddi; 310 } 311 } 312 313 mutex_unlock(&dsim->lock); 314 315 return NULL; 316} 317 318/* define MIPI-DSI Master operations. */ 319static struct mipi_dsim_master_ops master_ops = { 320 .cmd_read = exynos_mipi_dsi_rd_data, 321 .cmd_write = exynos_mipi_dsi_wr_data, 322 .get_dsim_frame_done = exynos_mipi_dsi_get_frame_done_status, 323 .clear_dsim_frame_done = exynos_mipi_dsi_clear_frame_done, 324 .set_early_blank_mode = exynos_mipi_dsi_early_blank_mode, 325 .set_blank_mode = exynos_mipi_dsi_blank_mode, 326}; 327 328static int exynos_mipi_dsi_probe(struct platform_device *pdev) 329{ 330 struct resource *res; 331 struct mipi_dsim_device *dsim; 332 struct mipi_dsim_config *dsim_config; 333 struct mipi_dsim_platform_data *dsim_pd; 334 struct mipi_dsim_ddi *dsim_ddi; 335 int ret = -EINVAL; 336 337 dsim = kzalloc(sizeof(struct mipi_dsim_device), GFP_KERNEL); 338 if (!dsim) { 339 dev_err(&pdev->dev, "failed to allocate dsim object.\n"); 340 return -ENOMEM; 341 } 342 343 dsim->pd = to_dsim_plat(pdev); 344 dsim->dev = &pdev->dev; 345 dsim->id = pdev->id; 346 347 /* get mipi_dsim_platform_data. */ 348 dsim_pd = (struct mipi_dsim_platform_data *)dsim->pd; 349 if (dsim_pd == NULL) { 350 dev_err(&pdev->dev, "failed to get platform data for dsim.\n"); 351 goto err_clock_get; 352 } 353 /* get mipi_dsim_config. */ 354 dsim_config = dsim_pd->dsim_config; 355 if (dsim_config == NULL) { 356 dev_err(&pdev->dev, "failed to get dsim config data.\n"); 357 goto err_clock_get; 358 } 359 360 dsim->dsim_config = dsim_config; 361 dsim->master_ops = &master_ops; 362 363 mutex_init(&dsim->lock); 364 365 ret = regulator_bulk_get(&pdev->dev, ARRAY_SIZE(supplies), supplies); 366 if (ret) { 367 dev_err(&pdev->dev, "Failed to get regulators: %d\n", ret); 368 goto err_clock_get; 369 } 370 371 dsim->clock = clk_get(&pdev->dev, "dsim0"); 372 if (IS_ERR(dsim->clock)) { 373 dev_err(&pdev->dev, "failed to get dsim clock source\n"); 374 goto err_clock_get; 375 } 376 377 clk_enable(dsim->clock); 378 379 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 380 if (!res) { 381 dev_err(&pdev->dev, "failed to get io memory region\n"); 382 goto err_platform_get; 383 } 384 385 dsim->res = request_mem_region(res->start, resource_size(res), 386 dev_name(&pdev->dev)); 387 if (!dsim->res) { 388 dev_err(&pdev->dev, "failed to request io memory region\n"); 389 ret = -ENOMEM; 390 goto err_mem_region; 391 } 392 393 dsim->reg_base = ioremap(res->start, resource_size(res)); 394 if (!dsim->reg_base) { 395 dev_err(&pdev->dev, "failed to remap io region\n"); 396 ret = -ENOMEM; 397 goto err_ioremap; 398 } 399 400 mutex_init(&dsim->lock); 401 402 /* bind lcd ddi matched with panel name. */ 403 dsim_ddi = exynos_mipi_dsi_bind_lcd_ddi(dsim, dsim_pd->lcd_panel_name); 404 if (!dsim_ddi) { 405 dev_err(&pdev->dev, "mipi_dsim_ddi object not found.\n"); 406 goto err_bind; 407 } 408 409 dsim->irq = platform_get_irq(pdev, 0); 410 if (dsim->irq < 0) { 411 dev_err(&pdev->dev, "failed to request dsim irq resource\n"); 412 ret = -EINVAL; 413 goto err_platform_get_irq; 414 } 415 416 ret = request_irq(dsim->irq, exynos_mipi_dsi_interrupt_handler, 417 IRQF_SHARED, pdev->name, dsim); 418 if (ret != 0) { 419 dev_err(&pdev->dev, "failed to request dsim irq\n"); 420 ret = -EINVAL; 421 goto err_bind; 422 } 423 424 init_completion(&dsim_wr_comp); 425 init_completion(&dsim_rd_comp); 426 427 /* enable interrupt */ 428 exynos_mipi_dsi_init_interrupt(dsim); 429 430 /* initialize mipi-dsi client(lcd panel). */ 431 if (dsim_ddi->dsim_lcd_drv && dsim_ddi->dsim_lcd_drv->probe) 432 dsim_ddi->dsim_lcd_drv->probe(dsim_ddi->dsim_lcd_dev); 433 434 /* in case that mipi got enabled at bootloader. */ 435 if (dsim_pd->enabled) 436 goto out; 437 438 /* lcd panel power on. */ 439 if (dsim_ddi->dsim_lcd_drv && dsim_ddi->dsim_lcd_drv->power_on) 440 dsim_ddi->dsim_lcd_drv->power_on(dsim_ddi->dsim_lcd_dev, 1); 441 442 exynos_mipi_regulator_enable(dsim); 443 444 /* enable MIPI-DSI PHY. */ 445 if (dsim->pd->phy_enable) 446 dsim->pd->phy_enable(pdev, true); 447 448 exynos_mipi_update_cfg(dsim); 449 450 /* set lcd panel sequence commands. */ 451 if (dsim_ddi->dsim_lcd_drv && dsim_ddi->dsim_lcd_drv->set_sequence) 452 dsim_ddi->dsim_lcd_drv->set_sequence(dsim_ddi->dsim_lcd_dev); 453 454 dsim->suspended = false; 455 456out: 457 platform_set_drvdata(pdev, dsim); 458 459 dev_dbg(&pdev->dev, "mipi-dsi driver(%s mode) has been probed.\n", 460 (dsim_config->e_interface == DSIM_COMMAND) ? 461 "CPU" : "RGB"); 462 463 return 0; 464 465err_bind: 466 iounmap(dsim->reg_base); 467 468err_ioremap: 469 release_mem_region(dsim->res->start, resource_size(dsim->res)); 470 471err_mem_region: 472 release_resource(dsim->res); 473 474err_platform_get: 475 clk_disable(dsim->clock); 476 clk_put(dsim->clock); 477err_clock_get: 478 kfree(dsim); 479 480err_platform_get_irq: 481 return ret; 482} 483 484static int __devexit exynos_mipi_dsi_remove(struct platform_device *pdev) 485{ 486 struct mipi_dsim_device *dsim = platform_get_drvdata(pdev); 487 struct mipi_dsim_ddi *dsim_ddi, *next; 488 struct mipi_dsim_lcd_driver *dsim_lcd_drv; 489 490 iounmap(dsim->reg_base); 491 492 clk_disable(dsim->clock); 493 clk_put(dsim->clock); 494 495 release_resource(dsim->res); 496 release_mem_region(dsim->res->start, resource_size(dsim->res)); 497 498 list_for_each_entry_safe(dsim_ddi, next, &dsim_ddi_list, list) { 499 if (dsim_ddi) { 500 if (dsim->id != dsim_ddi->bus_id) 501 continue; 502 503 dsim_lcd_drv = dsim_ddi->dsim_lcd_drv; 504 505 if (dsim_lcd_drv->remove) 506 dsim_lcd_drv->remove(dsim_ddi->dsim_lcd_dev); 507 508 kfree(dsim_ddi); 509 } 510 } 511 512 regulator_bulk_free(ARRAY_SIZE(supplies), supplies); 513 kfree(dsim); 514 515 return 0; 516} 517 518#ifdef CONFIG_PM 519static int exynos_mipi_dsi_suspend(struct platform_device *pdev, 520 pm_message_t state) 521{ 522 struct mipi_dsim_device *dsim = platform_get_drvdata(pdev); 523 struct mipi_dsim_lcd_driver *client_drv = dsim->dsim_lcd_drv; 524 struct mipi_dsim_lcd_device *client_dev = dsim->dsim_lcd_dev; 525 526 disable_irq(dsim->irq); 527 528 if (dsim->suspended) 529 return 0; 530 531 if (client_drv && client_drv->suspend) 532 client_drv->suspend(client_dev); 533 534 /* enable MIPI-DSI PHY. */ 535 if (dsim->pd->phy_enable) 536 dsim->pd->phy_enable(pdev, false); 537 538 clk_disable(dsim->clock); 539 540 exynos_mipi_regulator_disable(dsim); 541 542 dsim->suspended = true; 543 544 return 0; 545} 546 547static int exynos_mipi_dsi_resume(struct platform_device *pdev) 548{ 549 struct mipi_dsim_device *dsim = platform_get_drvdata(pdev); 550 struct mipi_dsim_lcd_driver *client_drv = dsim->dsim_lcd_drv; 551 struct mipi_dsim_lcd_device *client_dev = dsim->dsim_lcd_dev; 552 553 enable_irq(dsim->irq); 554 555 if (!dsim->suspended) 556 return 0; 557 558 /* lcd panel power on. */ 559 if (client_drv && client_drv->power_on) 560 client_drv->power_on(client_dev, 1); 561 562 exynos_mipi_regulator_enable(dsim); 563 564 /* enable MIPI-DSI PHY. */ 565 if (dsim->pd->phy_enable) 566 dsim->pd->phy_enable(pdev, true); 567 568 clk_enable(dsim->clock); 569 570 exynos_mipi_update_cfg(dsim); 571 572 /* set lcd panel sequence commands. */ 573 if (client_drv && client_drv->set_sequence) 574 client_drv->set_sequence(client_dev); 575 576 dsim->suspended = false; 577 578 return 0; 579} 580#else 581#define exynos_mipi_dsi_suspend NULL 582#define exynos_mipi_dsi_resume NULL 583#endif 584 585static struct platform_driver exynos_mipi_dsi_driver = { 586 .probe = exynos_mipi_dsi_probe, 587 .remove = __devexit_p(exynos_mipi_dsi_remove), 588 .suspend = exynos_mipi_dsi_suspend, 589 .resume = exynos_mipi_dsi_resume, 590 .driver = { 591 .name = "exynos-mipi-dsim", 592 .owner = THIS_MODULE, 593 }, 594}; 595 596module_platform_driver(exynos_mipi_dsi_driver); 597 598MODULE_AUTHOR("InKi Dae <inki.dae@samsung.com>"); 599MODULE_DESCRIPTION("Samusung SoC MIPI-DSI driver"); 600MODULE_LICENSE("GPL");