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 const char *default_display_name; 47} core; 48 49static char *def_disp_name; 50module_param_named(def_disp, def_disp_name, charp, 0); 51MODULE_PARM_DESC(def_disp, "default display name"); 52 53static bool dss_initialized; 54 55const char *omapdss_get_default_display_name(void) 56{ 57 return core.default_display_name; 58} 59EXPORT_SYMBOL(omapdss_get_default_display_name); 60 61enum omapdss_version omapdss_get_version(void) 62{ 63 struct omap_dss_board_info *pdata = core.pdev->dev.platform_data; 64 return pdata->version; 65} 66EXPORT_SYMBOL(omapdss_get_version); 67 68bool omapdss_is_initialized(void) 69{ 70 return dss_initialized; 71} 72EXPORT_SYMBOL(omapdss_is_initialized); 73 74struct platform_device *dss_get_core_pdev(void) 75{ 76 return core.pdev; 77} 78 79int dss_dsi_enable_pads(int dsi_id, unsigned lane_mask) 80{ 81 struct omap_dss_board_info *board_data = core.pdev->dev.platform_data; 82 83 if (!board_data->dsi_enable_pads) 84 return -ENOENT; 85 86 return board_data->dsi_enable_pads(dsi_id, lane_mask); 87} 88 89void dss_dsi_disable_pads(int dsi_id, unsigned lane_mask) 90{ 91 struct omap_dss_board_info *board_data = core.pdev->dev.platform_data; 92 93 if (!board_data->dsi_disable_pads) 94 return; 95 96 return board_data->dsi_disable_pads(dsi_id, lane_mask); 97} 98 99int dss_set_min_bus_tput(struct device *dev, unsigned long tput) 100{ 101 struct omap_dss_board_info *pdata = core.pdev->dev.platform_data; 102 103 if (pdata->set_min_bus_tput) 104 return pdata->set_min_bus_tput(dev, tput); 105 else 106 return 0; 107} 108 109#if defined(CONFIG_OMAP2_DSS_DEBUGFS) 110static int dss_debug_show(struct seq_file *s, void *unused) 111{ 112 void (*func)(struct seq_file *) = s->private; 113 func(s); 114 return 0; 115} 116 117static int dss_debug_open(struct inode *inode, struct file *file) 118{ 119 return single_open(file, dss_debug_show, inode->i_private); 120} 121 122static const struct file_operations dss_debug_fops = { 123 .open = dss_debug_open, 124 .read = seq_read, 125 .llseek = seq_lseek, 126 .release = single_release, 127}; 128 129static struct dentry *dss_debugfs_dir; 130 131static int dss_initialize_debugfs(void) 132{ 133 dss_debugfs_dir = debugfs_create_dir("omapdss", NULL); 134 if (IS_ERR(dss_debugfs_dir)) { 135 int err = PTR_ERR(dss_debugfs_dir); 136 dss_debugfs_dir = NULL; 137 return err; 138 } 139 140 debugfs_create_file("clk", S_IRUGO, dss_debugfs_dir, 141 &dss_debug_dump_clocks, &dss_debug_fops); 142 143 return 0; 144} 145 146static void dss_uninitialize_debugfs(void) 147{ 148 if (dss_debugfs_dir) 149 debugfs_remove_recursive(dss_debugfs_dir); 150} 151 152int dss_debugfs_create_file(const char *name, void (*write)(struct seq_file *)) 153{ 154 struct dentry *d; 155 156 d = debugfs_create_file(name, S_IRUGO, dss_debugfs_dir, 157 write, &dss_debug_fops); 158 159 return PTR_ERR_OR_ZERO(d); 160} 161#else /* CONFIG_OMAP2_DSS_DEBUGFS */ 162static inline int dss_initialize_debugfs(void) 163{ 164 return 0; 165} 166static inline void dss_uninitialize_debugfs(void) 167{ 168} 169int dss_debugfs_create_file(const char *name, void (*write)(struct seq_file *)) 170{ 171 return 0; 172} 173#endif /* CONFIG_OMAP2_DSS_DEBUGFS */ 174 175/* PLATFORM DEVICE */ 176static int omap_dss_pm_notif(struct notifier_block *b, unsigned long v, void *d) 177{ 178 DSSDBG("pm notif %lu\n", v); 179 180 switch (v) { 181 case PM_SUSPEND_PREPARE: 182 case PM_HIBERNATION_PREPARE: 183 case PM_RESTORE_PREPARE: 184 DSSDBG("suspending displays\n"); 185 return dss_suspend_all_devices(); 186 187 case PM_POST_SUSPEND: 188 case PM_POST_HIBERNATION: 189 case PM_POST_RESTORE: 190 DSSDBG("resuming displays\n"); 191 return dss_resume_all_devices(); 192 193 default: 194 return 0; 195 } 196} 197 198static struct notifier_block omap_dss_pm_notif_block = { 199 .notifier_call = omap_dss_pm_notif, 200}; 201 202static int __init omap_dss_probe(struct platform_device *pdev) 203{ 204 struct omap_dss_board_info *pdata = pdev->dev.platform_data; 205 int r; 206 207 core.pdev = pdev; 208 209 dss_features_init(omapdss_get_version()); 210 211 r = dss_initialize_debugfs(); 212 if (r) 213 goto err_debugfs; 214 215 if (def_disp_name) 216 core.default_display_name = def_disp_name; 217 else if (pdata->default_display_name) 218 core.default_display_name = pdata->default_display_name; 219 else if (pdata->default_device) 220 core.default_display_name = pdata->default_device->name; 221 222 register_pm_notifier(&omap_dss_pm_notif_block); 223 224 return 0; 225 226err_debugfs: 227 228 return r; 229} 230 231static int omap_dss_remove(struct platform_device *pdev) 232{ 233 unregister_pm_notifier(&omap_dss_pm_notif_block); 234 235 dss_uninitialize_debugfs(); 236 237 return 0; 238} 239 240static void omap_dss_shutdown(struct platform_device *pdev) 241{ 242 DSSDBG("shutdown\n"); 243 dss_disable_all_devices(); 244} 245 246static struct platform_driver omap_dss_driver = { 247 .remove = omap_dss_remove, 248 .shutdown = omap_dss_shutdown, 249 .driver = { 250 .name = "omapdss", 251 }, 252}; 253 254/* INIT */ 255static int (*dss_output_drv_reg_funcs[])(void) __initdata = { 256#ifdef CONFIG_OMAP2_DSS_DSI 257 dsi_init_platform_driver, 258#endif 259#ifdef CONFIG_OMAP2_DSS_DPI 260 dpi_init_platform_driver, 261#endif 262#ifdef CONFIG_OMAP2_DSS_SDI 263 sdi_init_platform_driver, 264#endif 265#ifdef CONFIG_OMAP2_DSS_RFBI 266 rfbi_init_platform_driver, 267#endif 268#ifdef CONFIG_OMAP2_DSS_VENC 269 venc_init_platform_driver, 270#endif 271#ifdef CONFIG_OMAP4_DSS_HDMI 272 hdmi4_init_platform_driver, 273#endif 274#ifdef CONFIG_OMAP5_DSS_HDMI 275 hdmi5_init_platform_driver, 276#endif 277}; 278 279static void (*dss_output_drv_unreg_funcs[])(void) __exitdata = { 280#ifdef CONFIG_OMAP2_DSS_DSI 281 dsi_uninit_platform_driver, 282#endif 283#ifdef CONFIG_OMAP2_DSS_DPI 284 dpi_uninit_platform_driver, 285#endif 286#ifdef CONFIG_OMAP2_DSS_SDI 287 sdi_uninit_platform_driver, 288#endif 289#ifdef CONFIG_OMAP2_DSS_RFBI 290 rfbi_uninit_platform_driver, 291#endif 292#ifdef CONFIG_OMAP2_DSS_VENC 293 venc_uninit_platform_driver, 294#endif 295#ifdef CONFIG_OMAP4_DSS_HDMI 296 hdmi4_uninit_platform_driver, 297#endif 298#ifdef CONFIG_OMAP5_DSS_HDMI 299 hdmi5_uninit_platform_driver, 300#endif 301}; 302 303static bool dss_output_drv_loaded[ARRAY_SIZE(dss_output_drv_reg_funcs)]; 304 305static int __init omap_dss_init(void) 306{ 307 int r; 308 int i; 309 310 r = platform_driver_probe(&omap_dss_driver, omap_dss_probe); 311 if (r) 312 return r; 313 314 r = dss_init_platform_driver(); 315 if (r) { 316 DSSERR("Failed to initialize DSS platform driver\n"); 317 goto err_dss; 318 } 319 320 r = dispc_init_platform_driver(); 321 if (r) { 322 DSSERR("Failed to initialize dispc platform driver\n"); 323 goto err_dispc; 324 } 325 326 /* 327 * It's ok if the output-driver register fails. It happens, for example, 328 * when there is no output-device (e.g. SDI for OMAP4). 329 */ 330 for (i = 0; i < ARRAY_SIZE(dss_output_drv_reg_funcs); ++i) { 331 r = dss_output_drv_reg_funcs[i](); 332 if (r == 0) 333 dss_output_drv_loaded[i] = true; 334 } 335 336 dss_initialized = true; 337 338 return 0; 339 340err_dispc: 341 dss_uninit_platform_driver(); 342err_dss: 343 platform_driver_unregister(&omap_dss_driver); 344 345 return r; 346} 347 348static void __exit omap_dss_exit(void) 349{ 350 int i; 351 352 for (i = 0; i < ARRAY_SIZE(dss_output_drv_unreg_funcs); ++i) { 353 if (dss_output_drv_loaded[i]) 354 dss_output_drv_unreg_funcs[i](); 355 } 356 357 dispc_uninit_platform_driver(); 358 dss_uninit_platform_driver(); 359 360 platform_driver_unregister(&omap_dss_driver); 361} 362 363module_init(omap_dss_init); 364module_exit(omap_dss_exit); 365 366MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@nokia.com>"); 367MODULE_DESCRIPTION("OMAP2/3 Display Subsystem"); 368MODULE_LICENSE("GPL v2"); 369 370