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