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.8-rc5 649 lines 14 kB view raw
1/* 2 * linux/drivers/video/omap2/dss/core.c 3 * 4 * Copyright (C) 2009 Nokia Corporation 5 * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com> 6 * 7 * Some code and ideas taken from drivers/video/omap/ driver 8 * by Imre Deak. 9 * 10 * This program is free software; you can redistribute it and/or modify it 11 * under the terms of the GNU General Public License version 2 as published by 12 * the Free Software Foundation. 13 * 14 * This program is distributed in the hope that it will be useful, but WITHOUT 15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 16 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 17 * more details. 18 * 19 * You should have received a copy of the GNU General Public License along with 20 * this program. If not, see <http://www.gnu.org/licenses/>. 21 */ 22 23#define DSS_SUBSYS_NAME "CORE" 24 25#include <linux/kernel.h> 26#include <linux/module.h> 27#include <linux/clk.h> 28#include <linux/err.h> 29#include <linux/platform_device.h> 30#include <linux/seq_file.h> 31#include <linux/debugfs.h> 32#include <linux/io.h> 33#include <linux/device.h> 34#include <linux/regulator/consumer.h> 35#include <linux/suspend.h> 36#include <linux/slab.h> 37 38#include <video/omapdss.h> 39 40#include "dss.h" 41#include "dss_features.h" 42 43static struct { 44 struct platform_device *pdev; 45 46 struct regulator *vdds_dsi_reg; 47 struct regulator *vdds_sdi_reg; 48 49 const char *default_display_name; 50} core; 51 52static char *def_disp_name; 53module_param_named(def_disp, def_disp_name, charp, 0); 54MODULE_PARM_DESC(def_disp, "default display name"); 55 56const char *omapdss_get_default_display_name(void) 57{ 58 return core.default_display_name; 59} 60EXPORT_SYMBOL(omapdss_get_default_display_name); 61 62enum omapdss_version omapdss_get_version(void) 63{ 64 struct omap_dss_board_info *pdata = core.pdev->dev.platform_data; 65 return pdata->version; 66} 67EXPORT_SYMBOL(omapdss_get_version); 68 69struct platform_device *dss_get_core_pdev(void) 70{ 71 return core.pdev; 72} 73 74/* REGULATORS */ 75 76struct regulator *dss_get_vdds_dsi(void) 77{ 78 struct regulator *reg; 79 80 if (core.vdds_dsi_reg != NULL) 81 return core.vdds_dsi_reg; 82 83 reg = regulator_get(&core.pdev->dev, "vdds_dsi"); 84 if (!IS_ERR(reg)) 85 core.vdds_dsi_reg = reg; 86 87 return reg; 88} 89 90struct regulator *dss_get_vdds_sdi(void) 91{ 92 struct regulator *reg; 93 94 if (core.vdds_sdi_reg != NULL) 95 return core.vdds_sdi_reg; 96 97 reg = regulator_get(&core.pdev->dev, "vdds_sdi"); 98 if (!IS_ERR(reg)) 99 core.vdds_sdi_reg = reg; 100 101 return reg; 102} 103 104int dss_dsi_enable_pads(int dsi_id, unsigned lane_mask) 105{ 106 struct omap_dss_board_info *board_data = core.pdev->dev.platform_data; 107 108 if (!board_data->dsi_enable_pads) 109 return -ENOENT; 110 111 return board_data->dsi_enable_pads(dsi_id, lane_mask); 112} 113 114void dss_dsi_disable_pads(int dsi_id, unsigned lane_mask) 115{ 116 struct omap_dss_board_info *board_data = core.pdev->dev.platform_data; 117 118 if (!board_data->dsi_disable_pads) 119 return; 120 121 return board_data->dsi_disable_pads(dsi_id, lane_mask); 122} 123 124int dss_set_min_bus_tput(struct device *dev, unsigned long tput) 125{ 126 struct omap_dss_board_info *pdata = core.pdev->dev.platform_data; 127 128 if (pdata->set_min_bus_tput) 129 return pdata->set_min_bus_tput(dev, tput); 130 else 131 return 0; 132} 133 134#if defined(CONFIG_OMAP2_DSS_DEBUGFS) 135static int dss_debug_show(struct seq_file *s, void *unused) 136{ 137 void (*func)(struct seq_file *) = s->private; 138 func(s); 139 return 0; 140} 141 142static int dss_debug_open(struct inode *inode, struct file *file) 143{ 144 return single_open(file, dss_debug_show, inode->i_private); 145} 146 147static const struct file_operations dss_debug_fops = { 148 .open = dss_debug_open, 149 .read = seq_read, 150 .llseek = seq_lseek, 151 .release = single_release, 152}; 153 154static struct dentry *dss_debugfs_dir; 155 156static int dss_initialize_debugfs(void) 157{ 158 dss_debugfs_dir = debugfs_create_dir("omapdss", NULL); 159 if (IS_ERR(dss_debugfs_dir)) { 160 int err = PTR_ERR(dss_debugfs_dir); 161 dss_debugfs_dir = NULL; 162 return err; 163 } 164 165 debugfs_create_file("clk", S_IRUGO, dss_debugfs_dir, 166 &dss_debug_dump_clocks, &dss_debug_fops); 167 168 return 0; 169} 170 171static void dss_uninitialize_debugfs(void) 172{ 173 if (dss_debugfs_dir) 174 debugfs_remove_recursive(dss_debugfs_dir); 175} 176 177int dss_debugfs_create_file(const char *name, void (*write)(struct seq_file *)) 178{ 179 struct dentry *d; 180 181 d = debugfs_create_file(name, S_IRUGO, dss_debugfs_dir, 182 write, &dss_debug_fops); 183 184 if (IS_ERR(d)) 185 return PTR_ERR(d); 186 187 return 0; 188} 189#else /* CONFIG_OMAP2_DSS_DEBUGFS */ 190static inline int dss_initialize_debugfs(void) 191{ 192 return 0; 193} 194static inline void dss_uninitialize_debugfs(void) 195{ 196} 197int dss_debugfs_create_file(const char *name, void (*write)(struct seq_file *)) 198{ 199 return 0; 200} 201#endif /* CONFIG_OMAP2_DSS_DEBUGFS */ 202 203/* PLATFORM DEVICE */ 204static int omap_dss_pm_notif(struct notifier_block *b, unsigned long v, void *d) 205{ 206 DSSDBG("pm notif %lu\n", v); 207 208 switch (v) { 209 case PM_SUSPEND_PREPARE: 210 DSSDBG("suspending displays\n"); 211 return dss_suspend_all_devices(); 212 213 case PM_POST_SUSPEND: 214 DSSDBG("resuming displays\n"); 215 return dss_resume_all_devices(); 216 217 default: 218 return 0; 219 } 220} 221 222static struct notifier_block omap_dss_pm_notif_block = { 223 .notifier_call = omap_dss_pm_notif, 224}; 225 226static int __init omap_dss_probe(struct platform_device *pdev) 227{ 228 struct omap_dss_board_info *pdata = pdev->dev.platform_data; 229 int r; 230 231 core.pdev = pdev; 232 233 dss_features_init(omapdss_get_version()); 234 235 r = dss_initialize_debugfs(); 236 if (r) 237 goto err_debugfs; 238 239 if (def_disp_name) 240 core.default_display_name = def_disp_name; 241 else if (pdata->default_device) 242 core.default_display_name = pdata->default_device->name; 243 244 register_pm_notifier(&omap_dss_pm_notif_block); 245 246 return 0; 247 248err_debugfs: 249 250 return r; 251} 252 253static int omap_dss_remove(struct platform_device *pdev) 254{ 255 unregister_pm_notifier(&omap_dss_pm_notif_block); 256 257 dss_uninitialize_debugfs(); 258 259 return 0; 260} 261 262static void omap_dss_shutdown(struct platform_device *pdev) 263{ 264 DSSDBG("shutdown\n"); 265 dss_disable_all_devices(); 266} 267 268static struct platform_driver omap_dss_driver = { 269 .remove = omap_dss_remove, 270 .shutdown = omap_dss_shutdown, 271 .driver = { 272 .name = "omapdss", 273 .owner = THIS_MODULE, 274 }, 275}; 276 277/* BUS */ 278static int dss_bus_match(struct device *dev, struct device_driver *driver) 279{ 280 struct omap_dss_device *dssdev = to_dss_device(dev); 281 282 DSSDBG("bus_match. dev %s/%s, drv %s\n", 283 dev_name(dev), dssdev->driver_name, driver->name); 284 285 return strcmp(dssdev->driver_name, driver->name) == 0; 286} 287 288static ssize_t device_name_show(struct device *dev, 289 struct device_attribute *attr, char *buf) 290{ 291 struct omap_dss_device *dssdev = to_dss_device(dev); 292 return snprintf(buf, PAGE_SIZE, "%s\n", 293 dssdev->name ? 294 dssdev->name : ""); 295} 296 297static struct device_attribute default_dev_attrs[] = { 298 __ATTR(name, S_IRUGO, device_name_show, NULL), 299 __ATTR_NULL, 300}; 301 302static ssize_t driver_name_show(struct device_driver *drv, char *buf) 303{ 304 struct omap_dss_driver *dssdrv = to_dss_driver(drv); 305 return snprintf(buf, PAGE_SIZE, "%s\n", 306 dssdrv->driver.name ? 307 dssdrv->driver.name : ""); 308} 309static struct driver_attribute default_drv_attrs[] = { 310 __ATTR(name, S_IRUGO, driver_name_show, NULL), 311 __ATTR_NULL, 312}; 313 314static struct bus_type dss_bus_type = { 315 .name = "omapdss", 316 .match = dss_bus_match, 317 .dev_attrs = default_dev_attrs, 318 .drv_attrs = default_drv_attrs, 319}; 320 321static void dss_bus_release(struct device *dev) 322{ 323 DSSDBG("bus_release\n"); 324} 325 326static struct device dss_bus = { 327 .release = dss_bus_release, 328}; 329 330struct bus_type *dss_get_bus(void) 331{ 332 return &dss_bus_type; 333} 334 335/* DRIVER */ 336static int dss_driver_probe(struct device *dev) 337{ 338 int r; 339 struct omap_dss_driver *dssdrv = to_dss_driver(dev->driver); 340 struct omap_dss_device *dssdev = to_dss_device(dev); 341 342 DSSDBG("driver_probe: dev %s/%s, drv %s\n", 343 dev_name(dev), dssdev->driver_name, 344 dssdrv->driver.name); 345 346 r = dssdrv->probe(dssdev); 347 348 if (r) { 349 DSSERR("driver probe failed: %d\n", r); 350 return r; 351 } 352 353 DSSDBG("probe done for device %s\n", dev_name(dev)); 354 355 dssdev->driver = dssdrv; 356 357 return 0; 358} 359 360static int dss_driver_remove(struct device *dev) 361{ 362 struct omap_dss_driver *dssdrv = to_dss_driver(dev->driver); 363 struct omap_dss_device *dssdev = to_dss_device(dev); 364 365 DSSDBG("driver_remove: dev %s/%s\n", dev_name(dev), 366 dssdev->driver_name); 367 368 dssdrv->remove(dssdev); 369 370 dssdev->driver = NULL; 371 372 return 0; 373} 374 375int omap_dss_register_driver(struct omap_dss_driver *dssdriver) 376{ 377 dssdriver->driver.bus = &dss_bus_type; 378 dssdriver->driver.probe = dss_driver_probe; 379 dssdriver->driver.remove = dss_driver_remove; 380 381 if (dssdriver->get_resolution == NULL) 382 dssdriver->get_resolution = omapdss_default_get_resolution; 383 if (dssdriver->get_recommended_bpp == NULL) 384 dssdriver->get_recommended_bpp = 385 omapdss_default_get_recommended_bpp; 386 if (dssdriver->get_timings == NULL) 387 dssdriver->get_timings = omapdss_default_get_timings; 388 389 return driver_register(&dssdriver->driver); 390} 391EXPORT_SYMBOL(omap_dss_register_driver); 392 393void omap_dss_unregister_driver(struct omap_dss_driver *dssdriver) 394{ 395 driver_unregister(&dssdriver->driver); 396} 397EXPORT_SYMBOL(omap_dss_unregister_driver); 398 399/* DEVICE */ 400 401static void omap_dss_dev_release(struct device *dev) 402{ 403 struct omap_dss_device *dssdev = to_dss_device(dev); 404 kfree(dssdev); 405} 406 407static int disp_num_counter; 408 409struct omap_dss_device *dss_alloc_and_init_device(struct device *parent) 410{ 411 struct omap_dss_device *dssdev; 412 413 dssdev = kzalloc(sizeof(*dssdev), GFP_KERNEL); 414 if (!dssdev) 415 return NULL; 416 417 dssdev->dev.bus = &dss_bus_type; 418 dssdev->dev.parent = parent; 419 dssdev->dev.release = omap_dss_dev_release; 420 dev_set_name(&dssdev->dev, "display%d", disp_num_counter++); 421 422 device_initialize(&dssdev->dev); 423 424 return dssdev; 425} 426 427int dss_add_device(struct omap_dss_device *dssdev) 428{ 429 return device_add(&dssdev->dev); 430} 431 432void dss_put_device(struct omap_dss_device *dssdev) 433{ 434 put_device(&dssdev->dev); 435} 436 437void dss_unregister_device(struct omap_dss_device *dssdev) 438{ 439 device_unregister(&dssdev->dev); 440} 441 442static int dss_unregister_dss_dev(struct device *dev, void *data) 443{ 444 struct omap_dss_device *dssdev = to_dss_device(dev); 445 dss_unregister_device(dssdev); 446 return 0; 447} 448 449void dss_unregister_child_devices(struct device *parent) 450{ 451 device_for_each_child(parent, NULL, dss_unregister_dss_dev); 452} 453 454void dss_copy_device_pdata(struct omap_dss_device *dst, 455 const struct omap_dss_device *src) 456{ 457 u8 *d = (u8 *)dst; 458 u8 *s = (u8 *)src; 459 size_t dsize = sizeof(struct device); 460 461 memcpy(d + dsize, s + dsize, sizeof(struct omap_dss_device) - dsize); 462} 463 464/* BUS */ 465static int __init omap_dss_bus_register(void) 466{ 467 int r; 468 469 r = bus_register(&dss_bus_type); 470 if (r) { 471 DSSERR("bus register failed\n"); 472 return r; 473 } 474 475 dev_set_name(&dss_bus, "omapdss"); 476 r = device_register(&dss_bus); 477 if (r) { 478 DSSERR("bus driver register failed\n"); 479 bus_unregister(&dss_bus_type); 480 return r; 481 } 482 483 return 0; 484} 485 486/* INIT */ 487static int (*dss_output_drv_reg_funcs[])(void) __initdata = { 488#ifdef CONFIG_OMAP2_DSS_DSI 489 dsi_init_platform_driver, 490#endif 491#ifdef CONFIG_OMAP2_DSS_DPI 492 dpi_init_platform_driver, 493#endif 494#ifdef CONFIG_OMAP2_DSS_SDI 495 sdi_init_platform_driver, 496#endif 497#ifdef CONFIG_OMAP2_DSS_RFBI 498 rfbi_init_platform_driver, 499#endif 500#ifdef CONFIG_OMAP2_DSS_VENC 501 venc_init_platform_driver, 502#endif 503#ifdef CONFIG_OMAP4_DSS_HDMI 504 hdmi_init_platform_driver, 505#endif 506}; 507 508static void (*dss_output_drv_unreg_funcs[])(void) __exitdata = { 509#ifdef CONFIG_OMAP2_DSS_DSI 510 dsi_uninit_platform_driver, 511#endif 512#ifdef CONFIG_OMAP2_DSS_DPI 513 dpi_uninit_platform_driver, 514#endif 515#ifdef CONFIG_OMAP2_DSS_SDI 516 sdi_uninit_platform_driver, 517#endif 518#ifdef CONFIG_OMAP2_DSS_RFBI 519 rfbi_uninit_platform_driver, 520#endif 521#ifdef CONFIG_OMAP2_DSS_VENC 522 venc_uninit_platform_driver, 523#endif 524#ifdef CONFIG_OMAP4_DSS_HDMI 525 hdmi_uninit_platform_driver, 526#endif 527}; 528 529static bool dss_output_drv_loaded[ARRAY_SIZE(dss_output_drv_reg_funcs)]; 530 531static int __init omap_dss_register_drivers(void) 532{ 533 int r; 534 int i; 535 536 r = platform_driver_probe(&omap_dss_driver, omap_dss_probe); 537 if (r) 538 return r; 539 540 r = dss_init_platform_driver(); 541 if (r) { 542 DSSERR("Failed to initialize DSS platform driver\n"); 543 goto err_dss; 544 } 545 546 r = dispc_init_platform_driver(); 547 if (r) { 548 DSSERR("Failed to initialize dispc platform driver\n"); 549 goto err_dispc; 550 } 551 552 /* 553 * It's ok if the output-driver register fails. It happens, for example, 554 * when there is no output-device (e.g. SDI for OMAP4). 555 */ 556 for (i = 0; i < ARRAY_SIZE(dss_output_drv_reg_funcs); ++i) { 557 r = dss_output_drv_reg_funcs[i](); 558 if (r == 0) 559 dss_output_drv_loaded[i] = true; 560 } 561 562 return 0; 563 564err_dispc: 565 dss_uninit_platform_driver(); 566err_dss: 567 platform_driver_unregister(&omap_dss_driver); 568 569 return r; 570} 571 572static void __exit omap_dss_unregister_drivers(void) 573{ 574 int i; 575 576 for (i = 0; i < ARRAY_SIZE(dss_output_drv_unreg_funcs); ++i) { 577 if (dss_output_drv_loaded[i]) 578 dss_output_drv_unreg_funcs[i](); 579 } 580 581 dispc_uninit_platform_driver(); 582 dss_uninit_platform_driver(); 583 584 platform_driver_unregister(&omap_dss_driver); 585} 586 587#ifdef CONFIG_OMAP2_DSS_MODULE 588static void omap_dss_bus_unregister(void) 589{ 590 device_unregister(&dss_bus); 591 592 bus_unregister(&dss_bus_type); 593} 594 595static int __init omap_dss_init(void) 596{ 597 int r; 598 599 r = omap_dss_bus_register(); 600 if (r) 601 return r; 602 603 r = omap_dss_register_drivers(); 604 if (r) { 605 omap_dss_bus_unregister(); 606 return r; 607 } 608 609 return 0; 610} 611 612static void __exit omap_dss_exit(void) 613{ 614 if (core.vdds_dsi_reg != NULL) { 615 regulator_put(core.vdds_dsi_reg); 616 core.vdds_dsi_reg = NULL; 617 } 618 619 if (core.vdds_sdi_reg != NULL) { 620 regulator_put(core.vdds_sdi_reg); 621 core.vdds_sdi_reg = NULL; 622 } 623 624 omap_dss_unregister_drivers(); 625 626 omap_dss_bus_unregister(); 627} 628 629module_init(omap_dss_init); 630module_exit(omap_dss_exit); 631#else 632static int __init omap_dss_init(void) 633{ 634 return omap_dss_bus_register(); 635} 636 637static int __init omap_dss_init2(void) 638{ 639 return omap_dss_register_drivers(); 640} 641 642core_initcall(omap_dss_init); 643device_initcall(omap_dss_init2); 644#endif 645 646MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@nokia.com>"); 647MODULE_DESCRIPTION("OMAP2/3 Display Subsystem"); 648MODULE_LICENSE("GPL v2"); 649