2009-11-03 12:23:50 +03:00
/*
* 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>
2010-02-04 18:03:41 +03:00
# include <linux/regulator/consumer.h>
2009-11-03 12:23:50 +03:00
2011-05-11 15:05:07 +04:00
# include <video/omapdss.h>
2009-11-03 12:23:50 +03:00
# include "dss.h"
2010-09-15 17:50:00 +04:00
# include "dss_features.h"
2009-11-03 12:23:50 +03:00
static struct {
struct platform_device * pdev ;
2010-02-04 18:03:41 +03:00
struct regulator * vdds_dsi_reg ;
struct regulator * vdds_sdi_reg ;
2012-02-23 15:00:51 +04:00
const char * default_display_name ;
2009-11-03 12:23:50 +03:00
} core ;
static char * def_disp_name ;
module_param_named ( def_disp , def_disp_name , charp , 0 ) ;
2011-02-16 13:53:44 +03:00
MODULE_PARM_DESC ( def_disp , " default display name " ) ;
2009-11-03 12:23:50 +03:00
# ifdef DEBUG
2012-01-13 03:02:20 +04:00
bool dss_debug ;
2009-11-03 12:23:50 +03:00
module_param_named ( debug , dss_debug , bool , 0644 ) ;
# endif
2010-02-04 18:03:41 +03:00
/* REGULATORS */
struct regulator * dss_get_vdds_dsi ( void )
{
struct regulator * reg ;
if ( core . vdds_dsi_reg ! = NULL )
return core . vdds_dsi_reg ;
reg = regulator_get ( & core . pdev - > dev , " vdds_dsi " ) ;
if ( ! IS_ERR ( reg ) )
core . vdds_dsi_reg = reg ;
return reg ;
}
struct regulator * dss_get_vdds_sdi ( void )
{
struct regulator * reg ;
if ( core . vdds_sdi_reg ! = NULL )
return core . vdds_sdi_reg ;
reg = regulator_get ( & core . pdev - > dev , " vdds_sdi " ) ;
if ( ! IS_ERR ( reg ) )
core . vdds_sdi_reg = reg ;
return reg ;
}
2012-02-20 13:50:06 +04:00
int dss_get_ctx_loss_count ( struct device * dev )
{
struct omap_dss_board_info * board_data = core . pdev - > dev . platform_data ;
int cnt ;
if ( ! board_data - > get_context_loss_count )
return - ENOENT ;
cnt = board_data - > get_context_loss_count ( dev ) ;
WARN_ONCE ( cnt < 0 , " get_context_loss_count failed: %d \n " , cnt ) ;
return cnt ;
}
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_enable_pads )
return ;
return board_data - > dsi_disable_pads ( dsi_id , lane_mask ) ;
}
2012-03-08 14:52:38 +04:00
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 ;
}
2009-11-03 12:23:50 +03:00
# if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT)
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 ) ;
}
2012-03-02 20:01:07 +04:00
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 ) ;
if ( IS_ERR ( d ) )
return PTR_ERR ( d ) ;
return 0 ;
}
2010-05-07 13:58:41 +04:00
# else /* CONFIG_DEBUG_FS && CONFIG_OMAP2_DSS_DEBUG_SUPPORT */
static inline int dss_initialize_debugfs ( void )
{
return 0 ;
}
static inline void dss_uninitialize_debugfs ( void )
{
}
2012-03-02 20:01:07 +04:00
static inline int dss_debugfs_create_file ( const char * name ,
void ( * write ) ( struct seq_file * ) )
{
return 0 ;
}
2009-11-03 12:23:50 +03:00
# endif /* CONFIG_DEBUG_FS && CONFIG_OMAP2_DSS_DEBUG_SUPPORT */
/* PLATFORM DEVICE */
2012-02-17 19:41:13 +04:00
static int __init omap_dss_probe ( struct platform_device * pdev )
2009-11-03 12:23:50 +03:00
{
struct omap_dss_board_info * pdata = pdev - > dev . platform_data ;
int r ;
core . pdev = pdev ;
2010-09-15 17:50:00 +04:00
dss_features_init ( ) ;
2011-11-04 11:48:54 +04:00
dss_apply_init ( ) ;
2009-11-03 12:23:50 +03:00
dss_init_overlay_managers ( pdev ) ;
dss_init_overlays ( pdev ) ;
r = dss_initialize_debugfs ( ) ;
if ( r )
2010-05-07 13:58:42 +04:00
goto err_debugfs ;
2009-11-03 12:23:50 +03:00
2012-02-23 15:00:51 +04:00
if ( def_disp_name )
core . default_display_name = def_disp_name ;
else if ( pdata - > default_device )
core . default_display_name = pdata - > default_device - > name ;
2009-11-03 12:23:50 +03:00
return 0 ;
2010-05-07 13:58:42 +04:00
err_debugfs :
2009-11-03 12:23:50 +03:00
return r ;
}
static int omap_dss_remove ( struct platform_device * pdev )
{
dss_uninitialize_debugfs ( ) ;
dss_uninit_overlays ( pdev ) ;
dss_uninit_overlay_managers ( pdev ) ;
return 0 ;
}
static void omap_dss_shutdown ( struct platform_device * pdev )
{
DSSDBG ( " shutdown \n " ) ;
dss_disable_all_devices ( ) ;
}
static int omap_dss_suspend ( struct platform_device * pdev , pm_message_t state )
{
DSSDBG ( " suspend %d \n " , state . event ) ;
return dss_suspend_all_devices ( ) ;
}
static int omap_dss_resume ( struct platform_device * pdev )
{
DSSDBG ( " resume \n " ) ;
return dss_resume_all_devices ( ) ;
}
static struct platform_driver omap_dss_driver = {
. remove = omap_dss_remove ,
. shutdown = omap_dss_shutdown ,
. suspend = omap_dss_suspend ,
. resume = omap_dss_resume ,
. driver = {
. name = " omapdss " ,
. owner = THIS_MODULE ,
} ,
} ;
/* BUS */
static int dss_bus_match ( struct device * dev , struct device_driver * driver )
{
struct omap_dss_device * dssdev = to_dss_device ( dev ) ;
DSSDBG ( " bus_match. dev %s/%s, drv %s \n " ,
dev_name ( dev ) , dssdev - > driver_name , driver - > name ) ;
return strcmp ( dssdev - > driver_name , driver - > name ) = = 0 ;
}
static ssize_t device_name_show ( struct device * dev ,
struct device_attribute * attr , char * buf )
{
struct omap_dss_device * dssdev = to_dss_device ( dev ) ;
return snprintf ( buf , PAGE_SIZE , " %s \n " ,
dssdev - > name ?
dssdev - > name : " " ) ;
}
static struct device_attribute default_dev_attrs [ ] = {
__ATTR ( name , S_IRUGO , device_name_show , NULL ) ,
__ATTR_NULL ,
} ;
static ssize_t driver_name_show ( struct device_driver * drv , char * buf )
{
struct omap_dss_driver * dssdrv = to_dss_driver ( drv ) ;
return snprintf ( buf , PAGE_SIZE , " %s \n " ,
dssdrv - > driver . name ?
dssdrv - > driver . name : " " ) ;
}
static struct driver_attribute default_drv_attrs [ ] = {
__ATTR ( name , S_IRUGO , driver_name_show , NULL ) ,
__ATTR_NULL ,
} ;
static struct bus_type dss_bus_type = {
. name = " omapdss " ,
. match = dss_bus_match ,
. dev_attrs = default_dev_attrs ,
. drv_attrs = default_drv_attrs ,
} ;
static void dss_bus_release ( struct device * dev )
{
DSSDBG ( " bus_release \n " ) ;
}
static struct device dss_bus = {
. release = dss_bus_release ,
} ;
struct bus_type * dss_get_bus ( void )
{
return & dss_bus_type ;
}
/* DRIVER */
static int dss_driver_probe ( struct device * dev )
{
int r ;
struct omap_dss_driver * dssdrv = to_dss_driver ( dev - > driver ) ;
struct omap_dss_device * dssdev = to_dss_device ( dev ) ;
bool force ;
DSSDBG ( " driver_probe: dev %s/%s, drv %s \n " ,
dev_name ( dev ) , dssdev - > driver_name ,
dssdrv - > driver . name ) ;
dss_init_device ( core . pdev , dssdev ) ;
2012-02-23 15:00:51 +04:00
force = core . default_display_name & &
strcmp ( core . default_display_name , dssdev - > name ) = = 0 ;
2010-02-17 14:36:48 +03:00
dss_recheck_connections ( dssdev , force ) ;
2009-11-03 12:23:50 +03:00
r = dssdrv - > probe ( dssdev ) ;
if ( r ) {
DSSERR ( " driver probe failed: %d \n " , r ) ;
2010-02-17 12:50:07 +03:00
dss_uninit_device ( core . pdev , dssdev ) ;
2009-11-03 12:23:50 +03:00
return r ;
}
DSSDBG ( " probe done for device %s \n " , dev_name ( dev ) ) ;
dssdev - > driver = dssdrv ;
return 0 ;
}
static int dss_driver_remove ( struct device * dev )
{
struct omap_dss_driver * dssdrv = to_dss_driver ( dev - > driver ) ;
struct omap_dss_device * dssdev = to_dss_device ( dev ) ;
DSSDBG ( " driver_remove: dev %s/%s \n " , dev_name ( dev ) ,
dssdev - > driver_name ) ;
dssdrv - > remove ( dssdev ) ;
dss_uninit_device ( core . pdev , dssdev ) ;
dssdev - > driver = NULL ;
return 0 ;
}
int omap_dss_register_driver ( struct omap_dss_driver * dssdriver )
{
dssdriver - > driver . bus = & dss_bus_type ;
dssdriver - > driver . probe = dss_driver_probe ;
dssdriver - > driver . remove = dss_driver_remove ;
2010-01-11 14:54:33 +03:00
if ( dssdriver - > get_resolution = = NULL )
dssdriver - > get_resolution = omapdss_default_get_resolution ;
2010-01-11 15:33:40 +03:00
if ( dssdriver - > get_recommended_bpp = = NULL )
dssdriver - > get_recommended_bpp =
omapdss_default_get_recommended_bpp ;
2012-03-15 22:00:23 +04:00
if ( dssdriver - > get_timings = = NULL )
dssdriver - > get_timings = omapdss_default_get_timings ;
2010-01-11 14:54:33 +03:00
2009-11-03 12:23:50 +03:00
return driver_register ( & dssdriver - > driver ) ;
}
EXPORT_SYMBOL ( omap_dss_register_driver ) ;
void omap_dss_unregister_driver ( struct omap_dss_driver * dssdriver )
{
driver_unregister ( & dssdriver - > driver ) ;
}
EXPORT_SYMBOL ( omap_dss_unregister_driver ) ;
/* DEVICE */
static void reset_device ( struct device * dev , int check )
{
u8 * dev_p = ( u8 * ) dev ;
u8 * dev_end = dev_p + sizeof ( * dev ) ;
void * saved_pdata ;
saved_pdata = dev - > platform_data ;
if ( check ) {
/*
* Check if there is any other setting than platform_data
* in struct device ; warn that these will be reset by our
* init .
*/
dev - > platform_data = NULL ;
while ( dev_p < dev_end ) {
if ( * dev_p ) {
WARN ( " %s: struct device fields will be "
" discarded \n " ,
__func__ ) ;
break ;
}
dev_p + + ;
}
}
memset ( dev , 0 , sizeof ( * dev ) ) ;
dev - > platform_data = saved_pdata ;
}
static void omap_dss_dev_release ( struct device * dev )
{
reset_device ( dev , 0 ) ;
}
OMAPDSS: interface drivers register their panel devices
Currently the higher level omapdss platform driver gets the list of
displays in its platform data, and uses that list to create the
omap_dss_device for each display.
With DT, the logical way to do the above is to list the displays under
each individual output, i.e. we'd have "dpi" node, under which we would
have the display that uses DPI. In other words, each output driver
handles the displays that use that particular output.
To make the current code ready for DT, this patch modifies the output
drivers so that each of them creates the display devices which use that
output. However, instead of changing the platform data to suit this
method, each output driver is passed the full list of displays, and the
drivers pick the displays that are meant for them. This allows us to
keep the old platform data, and thus we avoid the need to change the
board files.
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
2012-03-01 17:45:53 +04:00
int omap_dss_register_device ( struct omap_dss_device * dssdev ,
struct device * parent , int disp_num )
2009-11-03 12:23:50 +03:00
{
WARN_ON ( ! dssdev - > driver_name ) ;
reset_device ( & dssdev - > dev , 1 ) ;
dssdev - > dev . bus = & dss_bus_type ;
OMAPDSS: interface drivers register their panel devices
Currently the higher level omapdss platform driver gets the list of
displays in its platform data, and uses that list to create the
omap_dss_device for each display.
With DT, the logical way to do the above is to list the displays under
each individual output, i.e. we'd have "dpi" node, under which we would
have the display that uses DPI. In other words, each output driver
handles the displays that use that particular output.
To make the current code ready for DT, this patch modifies the output
drivers so that each of them creates the display devices which use that
output. However, instead of changing the platform data to suit this
method, each output driver is passed the full list of displays, and the
drivers pick the displays that are meant for them. This allows us to
keep the old platform data, and thus we avoid the need to change the
board files.
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
2012-03-01 17:45:53 +04:00
dssdev - > dev . parent = parent ;
2009-11-03 12:23:50 +03:00
dssdev - > dev . release = omap_dss_dev_release ;
OMAPDSS: interface drivers register their panel devices
Currently the higher level omapdss platform driver gets the list of
displays in its platform data, and uses that list to create the
omap_dss_device for each display.
With DT, the logical way to do the above is to list the displays under
each individual output, i.e. we'd have "dpi" node, under which we would
have the display that uses DPI. In other words, each output driver
handles the displays that use that particular output.
To make the current code ready for DT, this patch modifies the output
drivers so that each of them creates the display devices which use that
output. However, instead of changing the platform data to suit this
method, each output driver is passed the full list of displays, and the
drivers pick the displays that are meant for them. This allows us to
keep the old platform data, and thus we avoid the need to change the
board files.
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
2012-03-01 17:45:53 +04:00
dev_set_name ( & dssdev - > dev , " display%d " , disp_num ) ;
2010-02-17 14:36:48 +03:00
return device_register ( & dssdev - > dev ) ;
2009-11-03 12:23:50 +03:00
}
OMAPDSS: interface drivers register their panel devices
Currently the higher level omapdss platform driver gets the list of
displays in its platform data, and uses that list to create the
omap_dss_device for each display.
With DT, the logical way to do the above is to list the displays under
each individual output, i.e. we'd have "dpi" node, under which we would
have the display that uses DPI. In other words, each output driver
handles the displays that use that particular output.
To make the current code ready for DT, this patch modifies the output
drivers so that each of them creates the display devices which use that
output. However, instead of changing the platform data to suit this
method, each output driver is passed the full list of displays, and the
drivers pick the displays that are meant for them. This allows us to
keep the old platform data, and thus we avoid the need to change the
board files.
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
2012-03-01 17:45:53 +04:00
void omap_dss_unregister_device ( struct omap_dss_device * dssdev )
2009-11-03 12:23:50 +03:00
{
device_unregister ( & dssdev - > dev ) ;
}
OMAPDSS: interface drivers register their panel devices
Currently the higher level omapdss platform driver gets the list of
displays in its platform data, and uses that list to create the
omap_dss_device for each display.
With DT, the logical way to do the above is to list the displays under
each individual output, i.e. we'd have "dpi" node, under which we would
have the display that uses DPI. In other words, each output driver
handles the displays that use that particular output.
To make the current code ready for DT, this patch modifies the output
drivers so that each of them creates the display devices which use that
output. However, instead of changing the platform data to suit this
method, each output driver is passed the full list of displays, and the
drivers pick the displays that are meant for them. This allows us to
keep the old platform data, and thus we avoid the need to change the
board files.
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
2012-03-01 17:45:53 +04:00
static int dss_unregister_dss_dev ( struct device * dev , void * data )
{
struct omap_dss_device * dssdev = to_dss_device ( dev ) ;
omap_dss_unregister_device ( dssdev ) ;
return 0 ;
}
void omap_dss_unregister_child_devices ( struct device * parent )
{
device_for_each_child ( parent , NULL , dss_unregister_dss_dev ) ;
}
2009-11-03 12:23:50 +03:00
/* BUS */
2012-02-17 19:41:13 +04:00
static int __init omap_dss_bus_register ( void )
2009-11-03 12:23:50 +03:00
{
int r ;
r = bus_register ( & dss_bus_type ) ;
if ( r ) {
DSSERR ( " bus register failed \n " ) ;
return r ;
}
dev_set_name ( & dss_bus , " omapdss " ) ;
r = device_register ( & dss_bus ) ;
if ( r ) {
DSSERR ( " bus driver register failed \n " ) ;
bus_unregister ( & dss_bus_type ) ;
return r ;
}
return 0 ;
}
/* INIT */
2012-03-02 19:37:53 +04:00
static int ( * dss_output_drv_reg_funcs [ ] ) ( void ) __initdata = {
# 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_OMAP2_DSS_DSI
dsi_init_platform_driver ,
# endif
# ifdef CONFIG_OMAP4_DSS_HDMI
hdmi_init_platform_driver ,
# endif
} ;
static void ( * dss_output_drv_unreg_funcs [ ] ) ( void ) __exitdata = {
# 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_OMAP2_DSS_DSI
dsi_uninit_platform_driver ,
# endif
# ifdef CONFIG_OMAP4_DSS_HDMI
hdmi_uninit_platform_driver ,
# endif
} ;
static bool dss_output_drv_loaded [ ARRAY_SIZE ( dss_output_drv_reg_funcs ) ] ;
2009-11-03 12:23:50 +03:00
2012-03-19 17:05:02 +04:00
static int __init omap_dss_register_drivers ( void )
{
int r ;
2012-03-02 19:37:53 +04:00
int i ;
2012-03-19 17:05:02 +04:00
2012-03-07 14:53:18 +04:00
r = platform_driver_probe ( & omap_dss_driver , omap_dss_probe ) ;
2012-03-19 17:05:02 +04:00
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 ;
}
2012-03-02 19:37:53 +04:00
/*
* 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 ;
2012-03-19 17:05:02 +04:00
}
return 0 ;
err_dispc :
dss_uninit_platform_driver ( ) ;
err_dss :
platform_driver_unregister ( & omap_dss_driver ) ;
return r ;
}
static void __exit omap_dss_unregister_drivers ( void )
{
2012-03-02 19:37:53 +04:00
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 ] ( ) ;
}
2012-03-19 17:05:02 +04:00
dispc_uninit_platform_driver ( ) ;
dss_uninit_platform_driver ( ) ;
platform_driver_unregister ( & omap_dss_driver ) ;
}
2009-11-03 12:23:50 +03:00
# ifdef CONFIG_OMAP2_DSS_MODULE
static void omap_dss_bus_unregister ( void )
{
device_unregister ( & dss_bus ) ;
bus_unregister ( & dss_bus_type ) ;
}
static int __init omap_dss_init ( void )
{
int r ;
r = omap_dss_bus_register ( ) ;
if ( r )
return r ;
2012-03-19 17:05:02 +04:00
r = omap_dss_register_drivers ( ) ;
2009-11-03 12:23:50 +03:00
if ( r ) {
omap_dss_bus_unregister ( ) ;
return r ;
}
return 0 ;
}
static void __exit omap_dss_exit ( void )
{
2010-02-04 18:03:41 +03:00
if ( core . vdds_dsi_reg ! = NULL ) {
regulator_put ( core . vdds_dsi_reg ) ;
core . vdds_dsi_reg = NULL ;
}
if ( core . vdds_sdi_reg ! = NULL ) {
regulator_put ( core . vdds_sdi_reg ) ;
core . vdds_sdi_reg = NULL ;
}
2012-03-19 17:05:02 +04:00
omap_dss_unregister_drivers ( ) ;
2009-11-03 12:23:50 +03:00
omap_dss_bus_unregister ( ) ;
}
module_init ( omap_dss_init ) ;
module_exit ( omap_dss_exit ) ;
# else
static int __init omap_dss_init ( void )
{
return omap_dss_bus_register ( ) ;
}
static int __init omap_dss_init2 ( void )
{
2012-03-19 17:05:02 +04:00
return omap_dss_register_drivers ( ) ;
2009-11-03 12:23:50 +03:00
}
core_initcall ( omap_dss_init ) ;
device_initcall ( omap_dss_init2 ) ;
# endif
MODULE_AUTHOR ( " Tomi Valkeinen <tomi.valkeinen@nokia.com> " ) ;
MODULE_DESCRIPTION ( " OMAP2/3 Display Subsystem " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;