2020-08-09 23:51:02 +02:00
// SPDX-License-Identifier: GPL-2.0
/*
* DSI interface to the Samsung S6E63M0 panel .
* ( C ) 2019 Linus Walleij
*/
# include <linux/module.h>
# include <linux/delay.h>
2023-07-14 11:45:34 -06:00
# include <linux/mod_devicetable.h>
2020-08-09 23:51:02 +02:00
# include <drm/drm_mipi_dsi.h>
# include <drm/drm_print.h>
# include "panel-samsung-s6e63m0.h"
# define MCS_GLOBAL_PARAM 0xb0
# define S6E63M0_DSI_MAX_CHUNK 15 /* CMD + 15 bytes max */
2021-06-14 20:11:35 +02:00
static int s6e63m0_dsi_dcs_read ( struct device * dev , void * trsp ,
const u8 cmd , u8 * data )
2020-08-09 23:51:03 +02:00
{
struct mipi_dsi_device * dsi = to_mipi_dsi_device ( dev ) ;
int ret ;
ret = mipi_dsi_dcs_read ( dsi , cmd , data , 1 ) ;
if ( ret < 0 ) {
2020-09-06 15:29:03 +02:00
dev_err ( dev , " could not read DCS CMD %02x \n " , cmd ) ;
2020-08-09 23:51:03 +02:00
return ret ;
}
2021-03-14 00:09:13 +01:00
dev_dbg ( dev , " DSI read CMD %02x = %02x \n " , cmd , * data ) ;
2020-08-09 23:51:03 +02:00
return 0 ;
}
2021-06-14 20:11:35 +02:00
static int s6e63m0_dsi_dcs_write ( struct device * dev , void * trsp ,
const u8 * data , size_t len )
2020-08-09 23:51:02 +02:00
{
struct mipi_dsi_device * dsi = to_mipi_dsi_device ( dev ) ;
const u8 * seqp = data ;
u8 cmd ;
u8 cmdwritten ;
int remain ;
int chunk ;
int ret ;
2021-03-14 00:09:13 +01:00
dev_dbg ( dev , " DSI writing dcs seq: %*ph \n " , ( int ) len , data ) ;
2020-08-09 23:51:02 +02:00
/* Pick out and skip past the DCS command */
cmd = * seqp ;
seqp + + ;
cmdwritten = 0 ;
remain = len - 1 ;
chunk = remain ;
/* Send max S6E63M0_DSI_MAX_CHUNK bytes at a time */
if ( chunk > S6E63M0_DSI_MAX_CHUNK )
chunk = S6E63M0_DSI_MAX_CHUNK ;
ret = mipi_dsi_dcs_write ( dsi , cmd , seqp , chunk ) ;
if ( ret < 0 ) {
2020-09-06 15:29:03 +02:00
dev_err ( dev , " error sending DCS command seq cmd %02x \n " , cmd ) ;
2020-08-09 23:51:02 +02:00
return ret ;
}
cmdwritten + = chunk ;
seqp + = chunk ;
while ( cmdwritten < remain ) {
chunk = remain - cmdwritten ;
if ( chunk > S6E63M0_DSI_MAX_CHUNK )
chunk = S6E63M0_DSI_MAX_CHUNK ;
ret = mipi_dsi_dcs_write ( dsi , MCS_GLOBAL_PARAM , & cmdwritten , 1 ) ;
if ( ret < 0 ) {
2020-09-06 15:29:03 +02:00
dev_err ( dev , " error sending CMD %02x global param %02x \n " ,
cmd , cmdwritten ) ;
2020-08-09 23:51:02 +02:00
return ret ;
}
ret = mipi_dsi_dcs_write ( dsi , cmd , seqp , chunk ) ;
if ( ret < 0 ) {
2020-09-06 15:29:03 +02:00
dev_err ( dev , " error sending CMD %02x chunk \n " , cmd ) ;
2020-08-09 23:51:02 +02:00
return ret ;
}
cmdwritten + = chunk ;
seqp + = chunk ;
}
2021-03-14 00:09:13 +01:00
dev_dbg ( dev , " sent command %02x %02x bytes \n " , cmd , cmdwritten ) ;
2020-08-09 23:51:02 +02:00
usleep_range ( 8000 , 9000 ) ;
return 0 ;
}
static int s6e63m0_dsi_probe ( struct mipi_dsi_device * dsi )
{
struct device * dev = & dsi - > dev ;
int ret ;
dsi - > lanes = 2 ;
dsi - > format = MIPI_DSI_FMT_RGB888 ;
dsi - > hs_rate = 349440000 ;
dsi - > lp_rate = 9600000 ;
dsi - > mode_flags = MIPI_DSI_MODE_VIDEO |
MIPI_DSI_MODE_VIDEO_BURST ;
2021-06-14 20:11:35 +02:00
ret = s6e63m0_probe ( dev , NULL , s6e63m0_dsi_dcs_read ,
s6e63m0_dsi_dcs_write , true ) ;
2020-08-09 23:51:02 +02:00
if ( ret )
return ret ;
ret = mipi_dsi_attach ( dsi ) ;
if ( ret < 0 )
s6e63m0_remove ( dev ) ;
return ret ;
}
2022-07-08 11:49:22 +02:00
static void s6e63m0_dsi_remove ( struct mipi_dsi_device * dsi )
2020-08-09 23:51:02 +02:00
{
mipi_dsi_detach ( dsi ) ;
2021-10-11 15:27:42 +02:00
s6e63m0_remove ( & dsi - > dev ) ;
2020-08-09 23:51:02 +02:00
}
static const struct of_device_id s6e63m0_dsi_of_match [ ] = {
{ . compatible = " samsung,s6e63m0 " } ,
{ /* sentinel */ }
} ;
MODULE_DEVICE_TABLE ( of , s6e63m0_dsi_of_match ) ;
static struct mipi_dsi_driver s6e63m0_dsi_driver = {
. probe = s6e63m0_dsi_probe ,
. remove = s6e63m0_dsi_remove ,
. driver = {
. name = " panel-samsung-s6e63m0 " ,
. of_match_table = s6e63m0_dsi_of_match ,
} ,
} ;
module_mipi_dsi_driver ( s6e63m0_dsi_driver ) ;
MODULE_AUTHOR ( " Linus Walleij <linusw@kernel.org> " ) ;
MODULE_DESCRIPTION ( " s6e63m0 LCD DSI Driver " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;