diff options
Diffstat (limited to 'drivers/video/fbdev/omap2/dss/core.c')
| -rw-r--r-- | drivers/video/fbdev/omap2/dss/core.c | 366 | 
1 files changed, 366 insertions, 0 deletions
diff --git a/drivers/video/fbdev/omap2/dss/core.c b/drivers/video/fbdev/omap2/dss/core.c new file mode 100644 index 00000000000..6b74f73fb52 --- /dev/null +++ b/drivers/video/fbdev/omap2/dss/core.c @@ -0,0 +1,366 @@ +/* + * linux/drivers/video/omap2/dss/core.c + * + * Copyright (C) 2009 Nokia Corporation + * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com> + * + * Some code and ideas taken from drivers/video/omap/ driver + * by Imre Deak. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#define DSS_SUBSYS_NAME "CORE" + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/clk.h> +#include <linux/err.h> +#include <linux/platform_device.h> +#include <linux/seq_file.h> +#include <linux/debugfs.h> +#include <linux/io.h> +#include <linux/device.h> +#include <linux/regulator/consumer.h> +#include <linux/suspend.h> +#include <linux/slab.h> + +#include <video/omapdss.h> + +#include "dss.h" +#include "dss_features.h" + +static struct { +	struct platform_device *pdev; + +	const char *default_display_name; +} core; + +static char *def_disp_name; +module_param_named(def_disp, def_disp_name, charp, 0); +MODULE_PARM_DESC(def_disp, "default display name"); + +static bool dss_initialized; + +const char *omapdss_get_default_display_name(void) +{ +	return core.default_display_name; +} +EXPORT_SYMBOL(omapdss_get_default_display_name); + +enum omapdss_version omapdss_get_version(void) +{ +	struct omap_dss_board_info *pdata = core.pdev->dev.platform_data; +	return pdata->version; +} +EXPORT_SYMBOL(omapdss_get_version); + +bool omapdss_is_initialized(void) +{ +	return dss_initialized; +} +EXPORT_SYMBOL(omapdss_is_initialized); + +struct platform_device *dss_get_core_pdev(void) +{ +	return core.pdev; +} + +int dss_dsi_enable_pads(int dsi_id, unsigned lane_mask) +{ +	struct omap_dss_board_info *board_data = core.pdev->dev.platform_data; + +	if (!board_data->dsi_enable_pads) +		return -ENOENT; + +	return board_data->dsi_enable_pads(dsi_id, lane_mask); +} + +void dss_dsi_disable_pads(int dsi_id, unsigned lane_mask) +{ +	struct omap_dss_board_info *board_data = core.pdev->dev.platform_data; + +	if (!board_data->dsi_disable_pads) +		return; + +	return board_data->dsi_disable_pads(dsi_id, lane_mask); +} + +int dss_set_min_bus_tput(struct device *dev, unsigned long tput) +{ +	struct omap_dss_board_info *pdata = core.pdev->dev.platform_data; + +	if (pdata->set_min_bus_tput) +		return pdata->set_min_bus_tput(dev, tput); +	else +		return 0; +} + +#if defined(CONFIG_OMAP2_DSS_DEBUGFS) +static int dss_debug_show(struct seq_file *s, void *unused) +{ +	void (*func)(struct seq_file *) = s->private; +	func(s); +	return 0; +} + +static int dss_debug_open(struct inode *inode, struct file *file) +{ +	return single_open(file, dss_debug_show, inode->i_private); +} + +static const struct file_operations dss_debug_fops = { +	.open           = dss_debug_open, +	.read           = seq_read, +	.llseek         = seq_lseek, +	.release        = single_release, +}; + +static struct dentry *dss_debugfs_dir; + +static int dss_initialize_debugfs(void) +{ +	dss_debugfs_dir = debugfs_create_dir("omapdss", NULL); +	if (IS_ERR(dss_debugfs_dir)) { +		int err = PTR_ERR(dss_debugfs_dir); +		dss_debugfs_dir = NULL; +		return err; +	} + +	debugfs_create_file("clk", S_IRUGO, dss_debugfs_dir, +			&dss_debug_dump_clocks, &dss_debug_fops); + +	return 0; +} + +static void dss_uninitialize_debugfs(void) +{ +	if (dss_debugfs_dir) +		debugfs_remove_recursive(dss_debugfs_dir); +} + +int dss_debugfs_create_file(const char *name, void (*write)(struct seq_file *)) +{ +	struct dentry *d; + +	d = debugfs_create_file(name, S_IRUGO, dss_debugfs_dir, +			write, &dss_debug_fops); + +	return PTR_ERR_OR_ZERO(d); +} +#else /* CONFIG_OMAP2_DSS_DEBUGFS */ +static inline int dss_initialize_debugfs(void) +{ +	return 0; +} +static inline void dss_uninitialize_debugfs(void) +{ +} +int dss_debugfs_create_file(const char *name, void (*write)(struct seq_file *)) +{ +	return 0; +} +#endif /* CONFIG_OMAP2_DSS_DEBUGFS */ + +/* PLATFORM DEVICE */ +static int omap_dss_pm_notif(struct notifier_block *b, unsigned long v, void *d) +{ +	DSSDBG("pm notif %lu\n", v); + +	switch (v) { +	case PM_SUSPEND_PREPARE: +		DSSDBG("suspending displays\n"); +		return dss_suspend_all_devices(); + +	case PM_POST_SUSPEND: +		DSSDBG("resuming displays\n"); +		return dss_resume_all_devices(); + +	default: +		return 0; +	} +} + +static struct notifier_block omap_dss_pm_notif_block = { +	.notifier_call = omap_dss_pm_notif, +}; + +static int __init omap_dss_probe(struct platform_device *pdev) +{ +	struct omap_dss_board_info *pdata = pdev->dev.platform_data; +	int r; + +	core.pdev = pdev; + +	dss_features_init(omapdss_get_version()); + +	r = dss_initialize_debugfs(); +	if (r) +		goto err_debugfs; + +	if (def_disp_name) +		core.default_display_name = def_disp_name; +	else if (pdata->default_display_name) +		core.default_display_name = pdata->default_display_name; +	else if (pdata->default_device) +		core.default_display_name = pdata->default_device->name; + +	register_pm_notifier(&omap_dss_pm_notif_block); + +	return 0; + +err_debugfs: + +	return r; +} + +static int omap_dss_remove(struct platform_device *pdev) +{ +	unregister_pm_notifier(&omap_dss_pm_notif_block); + +	dss_uninitialize_debugfs(); + +	return 0; +} + +static void omap_dss_shutdown(struct platform_device *pdev) +{ +	DSSDBG("shutdown\n"); +	dss_disable_all_devices(); +} + +static struct platform_driver omap_dss_driver = { +	.remove         = omap_dss_remove, +	.shutdown	= omap_dss_shutdown, +	.driver         = { +		.name   = "omapdss", +		.owner  = THIS_MODULE, +	}, +}; + +/* INIT */ +static int (*dss_output_drv_reg_funcs[])(void) __initdata = { +#ifdef CONFIG_OMAP2_DSS_DSI +	dsi_init_platform_driver, +#endif +#ifdef CONFIG_OMAP2_DSS_DPI +	dpi_init_platform_driver, +#endif +#ifdef CONFIG_OMAP2_DSS_SDI +	sdi_init_platform_driver, +#endif +#ifdef CONFIG_OMAP2_DSS_RFBI +	rfbi_init_platform_driver, +#endif +#ifdef CONFIG_OMAP2_DSS_VENC +	venc_init_platform_driver, +#endif +#ifdef CONFIG_OMAP4_DSS_HDMI +	hdmi4_init_platform_driver, +#endif +#ifdef CONFIG_OMAP5_DSS_HDMI +	hdmi5_init_platform_driver, +#endif +}; + +static void (*dss_output_drv_unreg_funcs[])(void) __exitdata = { +#ifdef CONFIG_OMAP2_DSS_DSI +	dsi_uninit_platform_driver, +#endif +#ifdef CONFIG_OMAP2_DSS_DPI +	dpi_uninit_platform_driver, +#endif +#ifdef CONFIG_OMAP2_DSS_SDI +	sdi_uninit_platform_driver, +#endif +#ifdef CONFIG_OMAP2_DSS_RFBI +	rfbi_uninit_platform_driver, +#endif +#ifdef CONFIG_OMAP2_DSS_VENC +	venc_uninit_platform_driver, +#endif +#ifdef CONFIG_OMAP4_DSS_HDMI +	hdmi4_uninit_platform_driver, +#endif +#ifdef CONFIG_OMAP5_DSS_HDMI +	hdmi5_uninit_platform_driver, +#endif +}; + +static bool dss_output_drv_loaded[ARRAY_SIZE(dss_output_drv_reg_funcs)]; + +static int __init omap_dss_init(void) +{ +	int r; +	int i; + +	r = platform_driver_probe(&omap_dss_driver, omap_dss_probe); +	if (r) +		return r; + +	r = dss_init_platform_driver(); +	if (r) { +		DSSERR("Failed to initialize DSS platform driver\n"); +		goto err_dss; +	} + +	r = dispc_init_platform_driver(); +	if (r) { +		DSSERR("Failed to initialize dispc platform driver\n"); +		goto err_dispc; +	} + +	/* +	 * It's ok if the output-driver register fails. It happens, for example, +	 * when there is no output-device (e.g. SDI for OMAP4). +	 */ +	for (i = 0; i < ARRAY_SIZE(dss_output_drv_reg_funcs); ++i) { +		r = dss_output_drv_reg_funcs[i](); +		if (r == 0) +			dss_output_drv_loaded[i] = true; +	} + +	dss_initialized = true; + +	return 0; + +err_dispc: +	dss_uninit_platform_driver(); +err_dss: +	platform_driver_unregister(&omap_dss_driver); + +	return r; +} + +static void __exit omap_dss_exit(void) +{ +	int i; + +	for (i = 0; i < ARRAY_SIZE(dss_output_drv_unreg_funcs); ++i) { +		if (dss_output_drv_loaded[i]) +			dss_output_drv_unreg_funcs[i](); +	} + +	dispc_uninit_platform_driver(); +	dss_uninit_platform_driver(); + +	platform_driver_unregister(&omap_dss_driver); +} + +module_init(omap_dss_init); +module_exit(omap_dss_exit); + +MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@nokia.com>"); +MODULE_DESCRIPTION("OMAP2/3 Display Subsystem"); +MODULE_LICENSE("GPL v2"); +  | 
