linux/drivers/video/omap2/dss/core.c
<<
>>
Prefs
   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
 650
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.