2009-08-05 17:18:44 +04:00
/*
* linux / drivers / video / omap2 / dss / sdi . c
*
* Copyright ( C ) 2009 Nokia Corporation
* Author : Tomi Valkeinen < tomi . valkeinen @ nokia . com >
*
* 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 "SDI"
# include <linux/kernel.h>
# include <linux/delay.h>
# include <linux/err.h>
2010-03-17 15:35:21 +03:00
# include <linux/regulator/consumer.h>
2011-07-10 21:20:26 +04:00
# include <linux/export.h>
2012-02-20 18:57:37 +04:00
# include <linux/platform_device.h>
2009-08-05 17:18:44 +04:00
2011-05-11 15:05:07 +04:00
# include <video/omapdss.h>
2009-08-05 17:18:44 +04:00
# include "dss.h"
static struct {
bool update_enabled ;
2010-03-17 15:35:21 +03:00
struct regulator * vdds_sdi_reg ;
2009-08-05 17:18:44 +04:00
2012-06-29 13:03:18 +04:00
struct dss_lcd_mgr_config mgr_config ;
} sdi ;
2010-12-02 14:27:10 +03:00
2012-06-29 13:03:18 +04:00
static void sdi_config_lcd_manager ( struct omap_dss_device * dssdev )
2009-08-05 17:18:44 +04:00
{
2012-06-29 13:03:18 +04:00
sdi . mgr_config . io_pad_mode = DSS_IO_PAD_MODE_BYPASS ;
2010-12-02 14:27:10 +03:00
2012-06-29 13:03:18 +04:00
sdi . mgr_config . stallmode = false ;
sdi . mgr_config . fifohandcheck = false ;
sdi . mgr_config . video_port_width = 24 ;
sdi . mgr_config . lcden_sig_polarity = 1 ;
2012-06-29 13:07:03 +04:00
dss_mgr_set_lcd_config ( dssdev - > manager , & sdi . mgr_config ) ;
2009-08-05 17:18:44 +04:00
}
2010-01-12 16:12:07 +03:00
int omapdss_sdi_display_enable ( struct omap_dss_device * dssdev )
2009-08-05 17:18:44 +04:00
{
struct omap_video_timings * t = & dssdev - > panel . timings ;
struct dss_clock_info dss_cinfo ;
struct dispc_clock_info dispc_cinfo ;
unsigned long pck ;
int r ;
2011-06-23 17:38:21 +04:00
if ( dssdev - > manager = = NULL ) {
DSSERR ( " failed to enable display: no manager \n " ) ;
return - ENODEV ;
}
2009-08-05 17:18:44 +04:00
r = omap_dss_start_device ( dssdev ) ;
if ( r ) {
DSSERR ( " failed to start device \n " ) ;
2011-05-27 11:52:19 +04:00
goto err_start_dev ;
2009-08-05 17:18:44 +04:00
}
2010-03-17 15:35:21 +03:00
r = regulator_enable ( sdi . vdds_sdi_reg ) ;
if ( r )
2011-05-27 11:52:19 +04:00
goto err_reg_enable ;
2010-03-17 15:35:21 +03:00
2011-05-27 11:52:19 +04:00
r = dispc_runtime_get ( ) ;
if ( r )
goto err_get_dispc ;
2009-08-05 17:18:44 +04:00
/* 15.5.9.1.2 */
2012-06-25 10:56:38 +04:00
dssdev - > panel . timings . data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE ;
dssdev - > panel . timings . sync_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE ;
2012-06-21 08:03:55 +04:00
r = dss_calc_clock_div ( t - > pixel_clock * 1000 , & dss_cinfo , & dispc_cinfo ) ;
2009-08-05 17:18:44 +04:00
if ( r )
2011-05-27 11:52:19 +04:00
goto err_calc_clock_div ;
2009-08-05 17:18:44 +04:00
2012-06-29 13:03:18 +04:00
sdi . mgr_config . clock_info = dispc_cinfo ;
2009-08-05 17:18:44 +04:00
2012-06-29 13:03:18 +04:00
pck = dss_cinfo . fck / dispc_cinfo . lck_div / dispc_cinfo . pck_div / 1000 ;
2009-08-05 17:18:44 +04:00
if ( pck ! = t - > pixel_clock ) {
DSSWARN ( " Could not find exact pixel clock. Requested %d kHz, "
" got %lu kHz \n " ,
t - > pixel_clock , pck ) ;
t - > pixel_clock = pck ;
}
2012-04-26 18:40:46 +04:00
dss_mgr_set_timings ( dssdev - > manager , t ) ;
2009-08-05 17:18:44 +04:00
r = dss_set_clock_div ( & dss_cinfo ) ;
if ( r )
2011-05-27 11:52:19 +04:00
goto err_set_dss_clock_div ;
2009-08-05 17:18:44 +04:00
2012-06-29 13:03:18 +04:00
sdi_config_lcd_manager ( dssdev ) ;
2009-08-05 17:18:44 +04:00
2011-03-02 13:29:27 +03:00
dss_sdi_init ( dssdev - > phy . sdi . datapairs ) ;
r = dss_sdi_enable ( ) ;
if ( r )
2011-05-27 11:52:19 +04:00
goto err_sdi_enable ;
2011-03-02 13:29:27 +03:00
mdelay ( 2 ) ;
2009-08-05 17:18:44 +04:00
2011-11-21 15:42:58 +04:00
r = dss_mgr_enable ( dssdev - > manager ) ;
if ( r )
goto err_mgr_enable ;
2009-08-05 17:18:44 +04:00
return 0 ;
2011-05-27 11:52:19 +04:00
2011-11-21 15:42:58 +04:00
err_mgr_enable :
dss_sdi_disable ( ) ;
2011-05-27 11:52:19 +04:00
err_sdi_enable :
err_set_dss_clock_div :
err_calc_clock_div :
dispc_runtime_put ( ) ;
err_get_dispc :
2010-03-17 15:35:21 +03:00
regulator_disable ( sdi . vdds_sdi_reg ) ;
2011-05-27 11:52:19 +04:00
err_reg_enable :
2009-08-05 17:18:44 +04:00
omap_dss_stop_device ( dssdev ) ;
2011-05-27 11:52:19 +04:00
err_start_dev :
2009-08-05 17:18:44 +04:00
return r ;
}
2010-01-12 16:12:07 +03:00
EXPORT_SYMBOL ( omapdss_sdi_display_enable ) ;
2009-08-05 17:18:44 +04:00
2010-01-12 16:12:07 +03:00
void omapdss_sdi_display_disable ( struct omap_dss_device * dssdev )
2009-08-05 17:18:44 +04:00
{
2011-11-04 12:22:46 +04:00
dss_mgr_disable ( dssdev - > manager ) ;
2009-08-05 17:18:44 +04:00
dss_sdi_disable ( ) ;
2011-05-27 11:52:19 +04:00
dispc_runtime_put ( ) ;
2009-08-05 17:18:44 +04:00
2010-03-17 15:35:21 +03:00
regulator_disable ( sdi . vdds_sdi_reg ) ;
2009-08-05 17:18:44 +04:00
omap_dss_stop_device ( dssdev ) ;
}
2010-01-12 16:12:07 +03:00
EXPORT_SYMBOL ( omapdss_sdi_display_disable ) ;
2009-08-05 17:18:44 +04:00
2012-03-01 18:58:39 +04:00
static int __init sdi_init_display ( struct omap_dss_device * dssdev )
2009-08-05 17:18:44 +04:00
{
DSSDBG ( " SDI init \n " ) ;
2011-02-22 16:53:46 +03:00
if ( sdi . vdds_sdi_reg = = NULL ) {
struct regulator * vdds_sdi ;
vdds_sdi = dss_get_vdds_sdi ( ) ;
if ( IS_ERR ( vdds_sdi ) ) {
DSSERR ( " can't get VDDS_SDI regulator \n " ) ;
return PTR_ERR ( vdds_sdi ) ;
}
sdi . vdds_sdi_reg = vdds_sdi ;
}
2009-08-05 17:18:44 +04:00
return 0 ;
}
2012-05-02 15:55:12 +04:00
static void __init sdi_probe_pdata ( struct platform_device * pdev )
2009-08-05 17:18:44 +04: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
struct omap_dss_board_info * pdata = pdev - > dev . platform_data ;
int i , r ;
for ( i = 0 ; i < pdata - > num_devices ; + + i ) {
struct omap_dss_device * dssdev = pdata - > devices [ i ] ;
if ( dssdev - > type ! = OMAP_DISPLAY_TYPE_SDI )
continue ;
2012-03-01 18:58:39 +04:00
r = sdi_init_display ( dssdev ) ;
if ( r ) {
DSSERR ( " device %s init failed: %d \n " , dssdev - > name , r ) ;
continue ;
}
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
r = omap_dss_register_device ( dssdev , & pdev - > dev , i ) ;
if ( r )
DSSERR ( " device %s register failed: %d \n " ,
dssdev - > name , r ) ;
}
2012-05-02 15:55:12 +04:00
}
static int __init omap_sdi_probe ( struct platform_device * pdev )
{
sdi_probe_pdata ( pdev ) ;
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
2009-08-05 17:18:44 +04:00
return 0 ;
}
2012-02-17 19:41:13 +04:00
static int __exit omap_sdi_remove ( struct platform_device * pdev )
2009-08-05 17:18:44 +04: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
omap_dss_unregister_child_devices ( & pdev - > dev ) ;
2012-02-20 18:57:37 +04:00
return 0 ;
}
static struct platform_driver omap_sdi_driver = {
2012-02-17 19:41:13 +04:00
. remove = __exit_p ( omap_sdi_remove ) ,
2012-02-20 18:57:37 +04:00
. driver = {
. name = " omapdss_sdi " ,
. owner = THIS_MODULE ,
} ,
} ;
2012-02-17 19:41:13 +04:00
int __init sdi_init_platform_driver ( void )
2012-02-20 18:57:37 +04:00
{
2012-03-07 14:53:38 +04:00
return platform_driver_probe ( & omap_sdi_driver , omap_sdi_probe ) ;
2012-02-20 18:57:37 +04:00
}
2012-02-17 19:41:13 +04:00
void __exit sdi_uninit_platform_driver ( void )
2012-02-20 18:57:37 +04:00
{
platform_driver_unregister ( & omap_sdi_driver ) ;
2009-08-05 17:18:44 +04:00
}