2015-01-06 11:13:28 +01:00
/*
* Copyright ( C ) 2014 Traphandler
* Copyright ( C ) 2014 Free Electrons
* Copyright ( C ) 2014 Atmel
*
* Author : Jean - Jacques Hiblot < jjhiblot @ traphandler . com >
* Author : Boris BREZILLON < boris . brezillon @ free - electrons . 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/>.
*/
# include <linux/of_graph.h>
# include <drm/drmP.h>
2017-03-29 13:55:46 -05:00
# include <drm/drm_of.h>
2017-05-11 11:31:28 -07:00
# include <drm/drm_bridge.h>
2015-01-06 11:13:28 +01:00
# include "atmel_hlcdc_dc.h"
static const struct drm_encoder_funcs atmel_hlcdc_panel_encoder_funcs = {
2017-05-11 11:31:27 -07:00
. destroy = drm_encoder_cleanup ,
2015-01-06 11:13:28 +01:00
} ;
2017-05-18 14:35:21 +02:00
static int atmel_hlcdc_attach_endpoint ( struct drm_device * dev , int endpoint )
2016-01-06 10:16:32 +01:00
{
2017-05-11 11:31:28 -07:00
struct drm_encoder * encoder ;
2016-01-06 10:16:32 +01:00
struct drm_panel * panel ;
struct drm_bridge * bridge ;
int ret ;
2015-01-06 11:13:28 +01:00
2017-05-18 14:35:21 +02:00
ret = drm_of_find_panel_or_bridge ( dev - > dev - > of_node , 0 , endpoint ,
& panel , & bridge ) ;
if ( ret )
return ret ;
2017-05-11 11:31:28 -07:00
encoder = devm_kzalloc ( dev - > dev , sizeof ( * encoder ) , GFP_KERNEL ) ;
if ( ! encoder )
2016-01-06 10:16:32 +01:00
return - EINVAL ;
2015-01-06 11:13:28 +01:00
2017-05-11 11:31:28 -07:00
ret = drm_encoder_init ( dev , encoder ,
2015-01-06 11:13:28 +01:00
& atmel_hlcdc_panel_encoder_funcs ,
2015-12-31 18:24:09 +01:00
DRM_MODE_ENCODER_NONE , NULL ) ;
2015-01-06 11:13:28 +01:00
if ( ret )
return ret ;
2017-05-11 11:31:28 -07:00
encoder - > possible_crtcs = 0x1 ;
2016-01-06 10:16:32 +01:00
if ( panel ) {
2017-05-11 11:31:28 -07:00
bridge = drm_panel_bridge_add ( panel , DRM_MODE_CONNECTOR_Unknown ) ;
if ( IS_ERR ( bridge ) )
return PTR_ERR ( bridge ) ;
2016-01-06 10:16:32 +01:00
}
if ( bridge ) {
2017-05-11 11:31:28 -07:00
ret = drm_bridge_attach ( encoder , bridge , NULL ) ;
2016-01-06 10:16:32 +01:00
if ( ! ret )
return 0 ;
2017-05-11 11:31:28 -07:00
if ( panel )
drm_panel_bridge_remove ( bridge ) ;
2016-01-06 10:16:32 +01:00
}
2015-01-06 11:13:28 +01:00
2017-05-11 11:31:28 -07:00
drm_encoder_cleanup ( encoder ) ;
2015-01-06 11:13:28 +01:00
return ret ;
}
int atmel_hlcdc_create_outputs ( struct drm_device * dev )
{
2017-05-18 14:35:21 +02:00
int endpoint , ret = 0 ;
for ( endpoint = 0 ; ! ret ; endpoint + + )
ret = atmel_hlcdc_attach_endpoint ( dev , endpoint ) ;
/* At least one device was successfully attached.*/
if ( ret = = - ENODEV & & endpoint )
return 0 ;
2015-01-06 11:13:28 +01:00
2017-03-29 13:55:46 -05:00
return ret ;
2015-01-06 11:13:28 +01:00
}