2019-05-27 08:55:01 +02:00
// SPDX-License-Identifier: GPL-2.0-or-later
2016-09-30 16:37:06 +02:00
/*
* Copyright ( C ) 2015 - 2016 Free Electrons
* Copyright ( C ) 2015 - 2016 NextThing Co
*
* Maxime Ripard < maxime . ripard @ free - electrons . com >
*/
2020-02-26 13:24:33 +02:00
# include <linux/gpio/consumer.h>
2016-09-30 16:37:06 +02:00
# include <linux/module.h>
2018-01-12 08:48:53 +01:00
# include <linux/of_device.h>
2016-09-30 16:37:06 +02:00
# include <linux/of_graph.h>
2016-11-16 23:42:31 +08:00
# include <linux/regulator/consumer.h>
2016-09-30 16:37:06 +02:00
# include <drm/drm_atomic_helper.h>
2019-08-26 17:26:29 +02:00
# include <drm/drm_bridge.h>
2016-09-30 16:37:06 +02:00
# include <drm/drm_crtc.h>
2022-06-14 12:02:45 +03:00
# include <drm/drm_edid.h>
2019-05-19 20:36:36 +02:00
# include <drm/drm_print.h>
2019-01-17 22:03:34 +01:00
# include <drm/drm_probe_helper.h>
2016-09-30 16:37:06 +02:00
2020-02-26 13:24:32 +02:00
struct simple_bridge_info {
const struct drm_bridge_timings * timings ;
unsigned int connector_type ;
} ;
2020-02-26 13:24:30 +02:00
struct simple_bridge {
2016-09-30 16:37:06 +02:00
struct drm_bridge bridge ;
struct drm_connector connector ;
2020-02-26 13:24:32 +02:00
const struct simple_bridge_info * info ;
2020-05-26 04:14:44 +03:00
struct drm_bridge * next_bridge ;
2016-11-16 23:42:31 +08:00
struct regulator * vdd ;
2020-02-26 13:24:33 +02:00
struct gpio_desc * enable ;
2016-09-30 16:37:06 +02:00
} ;
2020-02-26 13:24:30 +02:00
static inline struct simple_bridge *
drm_bridge_to_simple_bridge ( struct drm_bridge * bridge )
2016-09-30 16:37:06 +02:00
{
2020-02-26 13:24:30 +02:00
return container_of ( bridge , struct simple_bridge , bridge ) ;
2016-09-30 16:37:06 +02:00
}
2020-02-26 13:24:30 +02:00
static inline struct simple_bridge *
drm_connector_to_simple_bridge ( struct drm_connector * connector )
2016-09-30 16:37:06 +02:00
{
2020-02-26 13:24:30 +02:00
return container_of ( connector , struct simple_bridge , connector ) ;
2016-09-30 16:37:06 +02:00
}
2020-02-26 13:24:30 +02:00
static int simple_bridge_get_modes ( struct drm_connector * connector )
2016-09-30 16:37:06 +02:00
{
2020-02-26 13:24:30 +02:00
struct simple_bridge * sbridge = drm_connector_to_simple_bridge ( connector ) ;
2016-09-30 16:37:06 +02:00
struct edid * edid ;
int ret ;
2020-05-26 04:14:44 +03:00
if ( sbridge - > next_bridge - > ops & DRM_BRIDGE_OP_EDID ) {
edid = drm_bridge_get_edid ( sbridge - > next_bridge , connector ) ;
if ( ! edid )
DRM_INFO ( " EDID read failed. Fallback to standard modes \n " ) ;
} else {
edid = NULL ;
}
2016-09-30 16:37:06 +02:00
if ( ! edid ) {
2020-05-26 04:14:44 +03:00
/*
* In case we cannot retrieve the EDIDs ( missing or broken DDC
* bus from the next bridge ) , fallback on the XGA standards and
* prefer a mode pretty much anyone can handle .
*/
ret = drm_add_modes_noedid ( connector , 1920 , 1200 ) ;
drm_set_preferred_mode ( connector , 1024 , 768 ) ;
return ret ;
2016-09-30 16:37:06 +02:00
}
2018-07-09 10:40:06 +02:00
drm_connector_update_edid_property ( connector , edid ) ;
2018-04-20 14:59:59 -04:00
ret = drm_add_edid_modes ( connector , edid ) ;
kfree ( edid ) ;
2016-09-30 16:37:06 +02:00
return ret ;
}
2020-02-26 13:24:30 +02:00
static const struct drm_connector_helper_funcs simple_bridge_con_helper_funcs = {
. get_modes = simple_bridge_get_modes ,
2016-09-30 16:37:06 +02:00
} ;
static enum drm_connector_status
2020-02-26 13:24:30 +02:00
simple_bridge_connector_detect ( struct drm_connector * connector , bool force )
2016-09-30 16:37:06 +02:00
{
2020-02-26 13:24:30 +02:00
struct simple_bridge * sbridge = drm_connector_to_simple_bridge ( connector ) ;
2016-09-30 16:37:06 +02:00
2020-05-26 04:14:44 +03:00
return drm_bridge_detect ( sbridge - > next_bridge ) ;
2016-09-30 16:37:06 +02:00
}
2020-02-26 13:24:30 +02:00
static const struct drm_connector_funcs simple_bridge_con_funcs = {
. detect = simple_bridge_connector_detect ,
2016-09-30 16:37:06 +02:00
. fill_modes = drm_helper_probe_single_connector_modes ,
. destroy = drm_connector_cleanup ,
. reset = drm_atomic_helper_connector_reset ,
. atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state ,
. atomic_destroy_state = drm_atomic_helper_connector_destroy_state ,
} ;
2020-02-26 13:24:30 +02:00
static int simple_bridge_attach ( struct drm_bridge * bridge ,
enum drm_bridge_attach_flags flags )
2016-09-30 16:37:06 +02:00
{
2020-02-26 13:24:30 +02:00
struct simple_bridge * sbridge = drm_bridge_to_simple_bridge ( bridge ) ;
2016-09-30 16:37:06 +02:00
int ret ;
2020-05-26 04:14:44 +03:00
ret = drm_bridge_attach ( bridge - > encoder , sbridge - > next_bridge , bridge ,
DRM_BRIDGE_ATTACH_NO_CONNECTOR ) ;
if ( ret < 0 )
return ret ;
2020-05-26 04:14:45 +03:00
if ( flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR )
return 0 ;
2016-09-30 16:37:06 +02:00
if ( ! bridge - > encoder ) {
DRM_ERROR ( " Missing encoder \n " ) ;
return - ENODEV ;
}
2020-02-26 13:24:30 +02:00
drm_connector_helper_add ( & sbridge - > connector ,
& simple_bridge_con_helper_funcs ) ;
ret = drm_connector_init_with_ddc ( bridge - > dev , & sbridge - > connector ,
& simple_bridge_con_funcs ,
2020-02-26 13:24:32 +02:00
sbridge - > info - > connector_type ,
2020-05-26 04:14:44 +03:00
sbridge - > next_bridge - > ddc ) ;
2016-09-30 16:37:06 +02:00
if ( ret ) {
DRM_ERROR ( " Failed to initialize connector \n " ) ;
return ret ;
}
2020-05-26 04:14:45 +03:00
drm_connector_attach_encoder ( & sbridge - > connector , bridge - > encoder ) ;
2016-09-30 16:37:06 +02:00
return 0 ;
}
2020-02-26 13:24:30 +02:00
static void simple_bridge_enable ( struct drm_bridge * bridge )
2016-11-16 23:42:31 +08:00
{
2020-02-26 13:24:30 +02:00
struct simple_bridge * sbridge = drm_bridge_to_simple_bridge ( bridge ) ;
2020-02-26 13:24:33 +02:00
int ret ;
2016-11-16 23:42:31 +08:00
2020-02-26 13:24:33 +02:00
if ( sbridge - > vdd ) {
2020-02-26 13:24:30 +02:00
ret = regulator_enable ( sbridge - > vdd ) ;
2020-02-26 13:24:33 +02:00
if ( ret )
DRM_ERROR ( " Failed to enable vdd regulator: %d \n " , ret ) ;
}
2016-11-16 23:42:31 +08:00
2020-02-26 13:24:33 +02:00
gpiod_set_value_cansleep ( sbridge - > enable , 1 ) ;
2016-11-16 23:42:31 +08:00
}
2020-02-26 13:24:30 +02:00
static void simple_bridge_disable ( struct drm_bridge * bridge )
2016-11-16 23:42:31 +08:00
{
2020-02-26 13:24:30 +02:00
struct simple_bridge * sbridge = drm_bridge_to_simple_bridge ( bridge ) ;
2016-11-16 23:42:31 +08:00
2020-02-26 13:24:33 +02:00
gpiod_set_value_cansleep ( sbridge - > enable , 0 ) ;
2020-02-26 13:24:30 +02:00
if ( sbridge - > vdd )
regulator_disable ( sbridge - > vdd ) ;
2016-11-16 23:42:31 +08:00
}
2020-02-26 13:24:30 +02:00
static const struct drm_bridge_funcs simple_bridge_bridge_funcs = {
. attach = simple_bridge_attach ,
. enable = simple_bridge_enable ,
. disable = simple_bridge_disable ,
2016-09-30 16:37:06 +02:00
} ;
2020-02-26 13:24:30 +02:00
static int simple_bridge_probe ( struct platform_device * pdev )
2016-09-30 16:37:06 +02:00
{
2020-02-26 13:24:30 +02:00
struct simple_bridge * sbridge ;
2020-05-26 04:14:44 +03:00
struct device_node * remote ;
2016-09-30 16:37:06 +02:00
2020-02-26 13:24:30 +02:00
sbridge = devm_kzalloc ( & pdev - > dev , sizeof ( * sbridge ) , GFP_KERNEL ) ;
if ( ! sbridge )
2016-09-30 16:37:06 +02:00
return - ENOMEM ;
2020-02-26 13:24:30 +02:00
platform_set_drvdata ( pdev , sbridge ) ;
2016-09-30 16:37:06 +02:00
2020-02-26 13:24:32 +02:00
sbridge - > info = of_device_get_match_data ( & pdev - > dev ) ;
2020-05-26 04:14:44 +03:00
/* Get the next bridge in the pipeline. */
remote = of_graph_get_remote_node ( pdev - > dev . of_node , 1 , - 1 ) ;
if ( ! remote )
return - EINVAL ;
sbridge - > next_bridge = of_drm_find_bridge ( remote ) ;
of_node_put ( remote ) ;
if ( ! sbridge - > next_bridge ) {
dev_dbg ( & pdev - > dev , " Next bridge not found, deferring probe \n " ) ;
return - EPROBE_DEFER ;
}
/* Get the regulator and GPIO resources. */
2020-02-26 13:24:30 +02:00
sbridge - > vdd = devm_regulator_get_optional ( & pdev - > dev , " vdd " ) ;
if ( IS_ERR ( sbridge - > vdd ) ) {
int ret = PTR_ERR ( sbridge - > vdd ) ;
2016-11-16 23:42:31 +08:00
if ( ret = = - EPROBE_DEFER )
return - EPROBE_DEFER ;
2020-02-26 13:24:30 +02:00
sbridge - > vdd = NULL ;
2016-11-16 23:42:31 +08:00
dev_dbg ( & pdev - > dev , " No vdd regulator found: %d \n " , ret ) ;
}
2020-02-26 13:24:33 +02:00
sbridge - > enable = devm_gpiod_get_optional ( & pdev - > dev , " enable " ,
GPIOD_OUT_LOW ) ;
if ( IS_ERR ( sbridge - > enable ) ) {
if ( PTR_ERR ( sbridge - > enable ) ! = - EPROBE_DEFER )
dev_err ( & pdev - > dev , " Unable to retrieve enable GPIO \n " ) ;
return PTR_ERR ( sbridge - > enable ) ;
}
2020-05-26 04:14:44 +03:00
/* Register the bridge. */
2020-02-26 13:24:30 +02:00
sbridge - > bridge . funcs = & simple_bridge_bridge_funcs ;
sbridge - > bridge . of_node = pdev - > dev . of_node ;
2020-02-26 13:24:32 +02:00
sbridge - > bridge . timings = sbridge - > info - > timings ;
2016-09-30 16:37:06 +02:00
2020-02-26 13:24:30 +02:00
drm_bridge_add ( & sbridge - > bridge ) ;
2016-09-30 16:37:06 +02:00
2017-07-03 17:42:20 +09:00
return 0 ;
2016-09-30 16:37:06 +02:00
}
2020-02-26 13:24:30 +02:00
static int simple_bridge_remove ( struct platform_device * pdev )
2016-09-30 16:37:06 +02:00
{
2020-02-26 13:24:30 +02:00
struct simple_bridge * sbridge = platform_get_drvdata ( pdev ) ;
2016-09-30 16:37:06 +02:00
2020-02-26 13:24:30 +02:00
drm_bridge_remove ( & sbridge - > bridge ) ;
2016-09-30 16:37:06 +02:00
return 0 ;
}
2018-01-12 08:48:53 +01:00
/*
* We assume the ADV7123 DAC is the " default " for historical reasons
* Information taken from the ADV7123 datasheet , revision D .
* NOTE : the ADV7123EP seems to have other timings and need a new timings
* set if used .
*/
2020-02-26 13:24:30 +02:00
static const struct drm_bridge_timings default_bridge_timings = {
2018-01-12 08:48:53 +01:00
/* Timing specifications, datasheet page 7 */
2018-09-04 22:21:08 -07:00
. input_bus_flags = DRM_BUS_FLAG_PIXDATA_SAMPLE_POSEDGE ,
2018-01-12 08:48:53 +01:00
. setup_time_ps = 500 ,
. hold_time_ps = 1500 ,
} ;
/*
* Information taken from the THS8134 , THS8134A , THS8134B datasheet named
* " SLVS205D " , dated May 1990 , revised March 2000.
*/
2020-02-26 13:24:30 +02:00
static const struct drm_bridge_timings ti_ths8134_bridge_timings = {
2018-01-12 08:48:53 +01:00
/* From timing diagram, datasheet page 9 */
2018-09-04 22:21:08 -07:00
. input_bus_flags = DRM_BUS_FLAG_PIXDATA_SAMPLE_POSEDGE ,
2018-01-12 08:48:53 +01:00
/* From datasheet, page 12 */
. setup_time_ps = 3000 ,
/* I guess this means latched input */
. hold_time_ps = 0 ,
} ;
/*
* Information taken from the THS8135 datasheet named " SLAS343B " , dated
* May 2001 , revised April 2013.
*/
2020-02-26 13:24:30 +02:00
static const struct drm_bridge_timings ti_ths8135_bridge_timings = {
2018-01-12 08:48:53 +01:00
/* From timing diagram, datasheet page 14 */
2018-09-04 22:21:08 -07:00
. input_bus_flags = DRM_BUS_FLAG_PIXDATA_SAMPLE_POSEDGE ,
2018-01-12 08:48:53 +01:00
/* From datasheet, page 16 */
. setup_time_ps = 2000 ,
. hold_time_ps = 500 ,
} ;
2020-02-26 13:24:30 +02:00
static const struct of_device_id simple_bridge_match [ ] = {
2018-01-12 08:48:53 +01:00
{
. compatible = " dumb-vga-dac " ,
2020-02-26 13:24:32 +02:00
. data = & ( const struct simple_bridge_info ) {
. connector_type = DRM_MODE_CONNECTOR_VGA ,
} ,
} , {
2018-01-12 08:48:53 +01:00
. compatible = " adi,adv7123 " ,
2020-02-26 13:24:32 +02:00
. data = & ( const struct simple_bridge_info ) {
. timings = & default_bridge_timings ,
. connector_type = DRM_MODE_CONNECTOR_VGA ,
} ,
2020-02-26 13:24:34 +02:00
} , {
. compatible = " ti,opa362 " ,
. data = & ( const struct simple_bridge_info ) {
. connector_type = DRM_MODE_CONNECTOR_Composite ,
} ,
2020-02-26 13:24:32 +02:00
} , {
2018-01-12 08:48:53 +01:00
. compatible = " ti,ths8135 " ,
2020-02-26 13:24:32 +02:00
. data = & ( const struct simple_bridge_info ) {
. timings = & ti_ths8135_bridge_timings ,
. connector_type = DRM_MODE_CONNECTOR_VGA ,
} ,
} , {
2018-01-12 08:48:53 +01:00
. compatible = " ti,ths8134 " ,
2020-02-26 13:24:32 +02:00
. data = & ( const struct simple_bridge_info ) {
. timings = & ti_ths8134_bridge_timings ,
. connector_type = DRM_MODE_CONNECTOR_VGA ,
} ,
2018-01-12 08:48:53 +01:00
} ,
2016-09-30 16:37:06 +02:00
{ } ,
} ;
2020-02-26 13:24:30 +02:00
MODULE_DEVICE_TABLE ( of , simple_bridge_match ) ;
2016-09-30 16:37:06 +02:00
2020-02-26 13:24:30 +02:00
static struct platform_driver simple_bridge_driver = {
. probe = simple_bridge_probe ,
. remove = simple_bridge_remove ,
2016-09-30 16:37:06 +02:00
. driver = {
2020-02-26 13:24:31 +02:00
. name = " simple-bridge " ,
2020-02-26 13:24:30 +02:00
. of_match_table = simple_bridge_match ,
2016-09-30 16:37:06 +02:00
} ,
} ;
2020-02-26 13:24:30 +02:00
module_platform_driver ( simple_bridge_driver ) ;
2016-09-30 16:37:06 +02:00
MODULE_AUTHOR ( " Maxime Ripard <maxime.ripard@free-electrons.com> " ) ;
2020-02-26 13:24:30 +02:00
MODULE_DESCRIPTION ( " Simple DRM bridge driver " ) ;
2016-09-30 16:37:06 +02:00
MODULE_LICENSE ( " GPL " ) ;