2019-05-29 07:17:58 -07:00
// SPDX-License-Identifier: GPL-2.0-only
2016-06-15 16:24:03 +05:30
/*
* Copyright ( c ) 2016 , The Linux Foundation . All rights reserved .
*/
2016-06-15 17:01:27 +05:30
# include <linux/of_graph.h>
2016-06-15 16:24:03 +05:30
# include "adv7511.h"
static const struct reg_sequence adv7533_fixed_registers [ ] = {
{ 0x16 , 0x20 } ,
{ 0x9a , 0xe0 } ,
{ 0xba , 0x70 } ,
{ 0xde , 0x82 } ,
{ 0xe4 , 0x40 } ,
{ 0xe5 , 0x80 } ,
} ;
static const struct reg_sequence adv7533_cec_fixed_registers [ ] = {
{ 0x15 , 0xd0 } ,
{ 0x17 , 0xd0 } ,
{ 0x24 , 0x20 } ,
{ 0x57 , 0x11 } ,
2016-11-28 17:22:32 -08:00
{ 0x05 , 0xc8 } ,
2016-06-15 16:24:03 +05:30
} ;
2016-06-15 17:03:12 +05:30
static void adv7511_dsi_config_timing_gen ( struct adv7511 * adv )
{
struct mipi_dsi_device * dsi = adv - > dsi ;
struct drm_display_mode * mode = & adv - > curr_mode ;
unsigned int hsw , hfp , hbp , vsw , vfp , vbp ;
u8 clock_div_by_lanes [ ] = { 6 , 4 , 3 } ; /* 2, 3, 4 lanes */
hsw = mode - > hsync_end - mode - > hsync_start ;
hfp = mode - > hsync_start - mode - > hdisplay ;
hbp = mode - > htotal - mode - > hsync_end ;
vsw = mode - > vsync_end - mode - > vsync_start ;
vfp = mode - > vsync_start - mode - > vdisplay ;
vbp = mode - > vtotal - mode - > vsync_end ;
/* set pixel clock divider mode */
regmap_write ( adv - > regmap_cec , 0x16 ,
clock_div_by_lanes [ dsi - > lanes - 2 ] < < 3 ) ;
/* horizontal porch params */
regmap_write ( adv - > regmap_cec , 0x28 , mode - > htotal > > 4 ) ;
regmap_write ( adv - > regmap_cec , 0x29 , ( mode - > htotal < < 4 ) & 0xff ) ;
regmap_write ( adv - > regmap_cec , 0x2a , hsw > > 4 ) ;
regmap_write ( adv - > regmap_cec , 0x2b , ( hsw < < 4 ) & 0xff ) ;
regmap_write ( adv - > regmap_cec , 0x2c , hfp > > 4 ) ;
regmap_write ( adv - > regmap_cec , 0x2d , ( hfp < < 4 ) & 0xff ) ;
regmap_write ( adv - > regmap_cec , 0x2e , hbp > > 4 ) ;
regmap_write ( adv - > regmap_cec , 0x2f , ( hbp < < 4 ) & 0xff ) ;
/* vertical porch params */
regmap_write ( adv - > regmap_cec , 0x30 , mode - > vtotal > > 4 ) ;
regmap_write ( adv - > regmap_cec , 0x31 , ( mode - > vtotal < < 4 ) & 0xff ) ;
regmap_write ( adv - > regmap_cec , 0x32 , vsw > > 4 ) ;
regmap_write ( adv - > regmap_cec , 0x33 , ( vsw < < 4 ) & 0xff ) ;
regmap_write ( adv - > regmap_cec , 0x34 , vfp > > 4 ) ;
regmap_write ( adv - > regmap_cec , 0x35 , ( vfp < < 4 ) & 0xff ) ;
regmap_write ( adv - > regmap_cec , 0x36 , vbp > > 4 ) ;
regmap_write ( adv - > regmap_cec , 0x37 , ( vbp < < 4 ) & 0xff ) ;
}
2016-06-15 16:24:03 +05:30
void adv7533_dsi_power_on ( struct adv7511 * adv )
{
2016-06-15 17:01:27 +05:30
struct mipi_dsi_device * dsi = adv - > dsi ;
2016-06-15 17:03:12 +05:30
if ( adv - > use_timing_gen )
adv7511_dsi_config_timing_gen ( adv ) ;
2016-06-15 17:01:27 +05:30
/* set number of dsi lanes */
regmap_write ( adv - > regmap_cec , 0x1c , dsi - > lanes < < 4 ) ;
2016-06-15 17:03:12 +05:30
if ( adv - > use_timing_gen ) {
/* reset internal timing generator */
regmap_write ( adv - > regmap_cec , 0x27 , 0xcb ) ;
regmap_write ( adv - > regmap_cec , 0x27 , 0x8b ) ;
regmap_write ( adv - > regmap_cec , 0x27 , 0xcb ) ;
} else {
/* disable internal timing generator */
regmap_write ( adv - > regmap_cec , 0x27 , 0x0b ) ;
}
2016-06-15 16:24:03 +05:30
/* enable hdmi */
regmap_write ( adv - > regmap_cec , 0x03 , 0x89 ) ;
/* disable test mode */
regmap_write ( adv - > regmap_cec , 0x55 , 0x00 ) ;
regmap_register_patch ( adv - > regmap_cec , adv7533_cec_fixed_registers ,
ARRAY_SIZE ( adv7533_cec_fixed_registers ) ) ;
}
void adv7533_dsi_power_off ( struct adv7511 * adv )
{
/* disable hdmi */
regmap_write ( adv - > regmap_cec , 0x03 , 0x0b ) ;
2016-06-15 17:03:12 +05:30
/* disable internal timing generator */
regmap_write ( adv - > regmap_cec , 0x27 , 0x0b ) ;
2016-06-15 16:24:03 +05:30
}
2018-04-06 17:39:01 +03:00
void adv7533_mode_set ( struct adv7511 * adv , const struct drm_display_mode * mode )
2016-06-17 12:15:52 +05:30
{
struct mipi_dsi_device * dsi = adv - > dsi ;
int lanes , ret ;
if ( adv - > num_dsi_lanes ! = 4 )
return ;
if ( mode - > clock > 80000 )
lanes = 4 ;
else
lanes = 3 ;
if ( lanes ! = dsi - > lanes ) {
mipi_dsi_detach ( dsi ) ;
dsi - > lanes = lanes ;
ret = mipi_dsi_attach ( dsi ) ;
if ( ret )
dev_err ( & dsi - > dev , " failed to change host lanes \n " ) ;
}
}
2016-06-15 16:24:03 +05:30
int adv7533_patch_registers ( struct adv7511 * adv )
{
return regmap_register_patch ( adv - > regmap ,
adv7533_fixed_registers ,
ARRAY_SIZE ( adv7533_fixed_registers ) ) ;
}
2017-10-07 12:46:58 +02:00
int adv7533_patch_cec_registers ( struct adv7511 * adv )
2016-06-15 16:24:03 +05:30
{
2017-10-07 12:46:58 +02:00
return regmap_register_patch ( adv - > regmap_cec ,
2016-06-15 16:24:03 +05:30
adv7533_cec_fixed_registers ,
ARRAY_SIZE ( adv7533_cec_fixed_registers ) ) ;
}
2016-06-15 17:01:27 +05:30
int adv7533_attach_dsi ( struct adv7511 * adv )
{
struct device * dev = & adv - > i2c_main - > dev ;
struct mipi_dsi_host * host ;
struct mipi_dsi_device * dsi ;
int ret = 0 ;
const struct mipi_dsi_device_info info = { . type = " adv7533 " ,
. channel = 0 ,
. node = NULL ,
} ;
host = of_find_mipi_dsi_host_by_node ( adv - > host_node ) ;
if ( ! host ) {
dev_err ( dev , " failed to find dsi host \n " ) ;
return - EPROBE_DEFER ;
}
2021-10-25 17:15:16 +02:00
dsi = devm_mipi_dsi_device_register_full ( dev , host , & info ) ;
2016-06-15 17:01:27 +05:30
if ( IS_ERR ( dsi ) ) {
dev_err ( dev , " failed to create dsi device \n " ) ;
2021-10-25 17:15:16 +02:00
return PTR_ERR ( dsi ) ;
2016-06-15 17:01:27 +05:30
}
adv - > dsi = dsi ;
dsi - > lanes = adv - > num_dsi_lanes ;
dsi - > format = MIPI_DSI_FMT_RGB888 ;
dsi - > mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE |
2021-07-27 09:45:21 +08:00
MIPI_DSI_MODE_NO_EOT_PACKET | MIPI_DSI_MODE_VIDEO_HSE ;
2016-06-15 17:01:27 +05:30
2021-10-25 17:15:16 +02:00
ret = devm_mipi_dsi_attach ( dev , dsi ) ;
2016-06-15 17:01:27 +05:30
if ( ret < 0 ) {
dev_err ( dev , " failed to attach dsi to host \n " ) ;
2021-10-25 17:15:16 +02:00
return ret ;
2016-06-15 17:01:27 +05:30
}
return 0 ;
}
int adv7533_parse_dt ( struct device_node * np , struct adv7511 * adv )
{
u32 num_lanes ;
of_property_read_u32 ( np , " adi,dsi-lanes " , & num_lanes ) ;
if ( num_lanes < 1 | | num_lanes > 4 )
return - EINVAL ;
adv - > num_dsi_lanes = num_lanes ;
2017-03-22 08:26:06 -05:00
adv - > host_node = of_graph_get_remote_node ( np , 0 , 0 ) ;
if ( ! adv - > host_node )
2016-06-15 17:01:27 +05:30
return - ENODEV ;
of_node_put ( adv - > host_node ) ;
2016-06-15 17:03:12 +05:30
adv - > use_timing_gen = ! of_property_read_bool ( np ,
" adi,disable-timing-generator " ) ;
2016-06-15 17:01:27 +05:30
/* TODO: Check if these need to be parsed by DT or not */
adv - > rgb = true ;
adv - > embedded_sync = false ;
return 0 ;
}