基于MTK65xx平台lcm和背光驱动的编写

更新时间:2024-05-13 08:51:01 阅读量: 综合文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

基于MTK65xx平台lcm和背光驱动的编写

一、 与LCD驱动相关的主要文件路径

\\mediatek\\platform\\mt6573\%uboot\\mt6573_disp_drv.c \\mediatek\\platform\\mt6573\%uboot\\mt6573_disp_drv_dpi.c \\mediatek\\platform\\mt6573\%uboot \\mt6573_disp_drv_dbi.c \\mediatek\\platform\\mt6573\%uboot \\mt6573_dpi_drv.c \\mediatek\\platform\\mt6573\%uboot \\mt6573_dsi_drv.c \\mediatek\\platform\\mt6573\%uboot \\mt6573_lcd_drv.c \\mediatek\\source\\kernel\\drivers\\video\\mtkfb.c \\mediatek\\source\\kernel\\drivers\\video\\disp_drv.c \\mediatek\\source\\kernel\\drivers\\video\\disp_drv_dpi.c \\mediatek\\source\\kernel\\drivers\\video\\disp_drv_dbi.c \\mediatek\\platform\\mt6573\\kernel\\drivers\\video\\lcd_drv.c \\mediatek\\platform\\mt6573\\kernel\\drivers\\video\\dpi_drv.c \\mediatek\\platform\\mt6573\\kernel\\drivers\\video\\dsi_drv.c

\\mediatek\\custom\\common\\kernel\\lcm\\LCM_NAME\\LCM_NAME.c

\\mediatek\\platform\\mt6573\%uboot \\mt6573_pwm.c \\mediatek\\platform\\mt6573\%uboot \\mt65xx_leds.c \\mediatek\\source\\kernel\\drivers\\leds\\leds.c

\\mediatek\\custom\\ginwave73_gb\\kernel\\leds\\mt65xx\\cust_leds.c

二、 怎样新建一个LCD驱动

LCD模组主要包括LCD显示屏和驱动IC。比如LF040DNYB16a模组的驱动IC型号为NT35510。要在MTK6573平台上新建这个lcd的驱动,步骤如下:

1、 在mediatek\\custom\\common\\kernel\\lcm目录下新建文件夹nt35510,在此文件夹中新建nt35510.c。这就是LCM硬件层驱动文件。

2、 修改\\mediatek\\custom\\common\\kernel\\lcm\\ mt65xx_lcm_list.c, 在 lcm_driver_list [ lcm_count ] 中增加nt35510_lcm_drv。

3、 打开mediatek\\config\\ginwave73_gb\\ProjectConfig.mk,修改CUSTOM_UBOOT_LCM = nt35510, CUSTOM_KERNEL_LCM = nt35510;修改LCM_WIDTH、LCM_HEIGHT、BOOT_LOGO为正确的值。

三、 驱动文件(nt35510.c) 主要任务是实现 LCM_DRIVER nt35510_lcm_drv =

{

.name = \

.set_util_funcs = lcm_set_util_funcs, .get_params = lcm_get_params, .init = lcm_init,

.suspend = lcm_suspend, .resume = lcm_resume, .compare_id = lcm_compare_id, };

(1)lcm_get_params主要是设置LCM相关的参数,数据结构如下: typedef struct {

LCM_TYPE type;

LCM_CTRL ctrl; //! how to control LCM registers unsigned int width; unsigned int height;

unsigned int io_select_mode; //DBI or DPI should select IO mode according to chip spec

/* particular parameters */ LCM_DBI_PARAMS dbi; LCM_DPI_PARAMS dpi; LCM_DSI_PARAMS dsi; } LCM_PARAMS;

LCM_TYPE 定义LCM与HOST间的接口,主要分为3种,DBI, DPI, DSI。其中DBI又分为parallel DBI 和serial DBI。

parallel DBI(B型DBI)的命令和数据都在数据总线D[17:0]上传输。CSX为低时数据有效。WRX线控制D[17:0]为写时序,RDX控制D[17:0]为读时序。D/CX指示D[17:0]上传输的是命令还是数据。注:MT6573使用LPA0线作为D/CX线,LPCE线作为CSX线,LWRB线作为WRX线,LRDB线作为RDX线。

serial DBI(C型DBI)的命令和数据都在SPI接口上传输。CSX为低时SDA有效。SCL提供时钟,DIN输入,DOUT输出。当SDA_EN=1时,DIN线成为双向的SDA线,即可输入又可输出,DOUT线不用。C型DBI分为3线(没有D/CX线)和4线(有D/CX线)两种。3线的使用一个D/CX bit来区分命令/数据,4线的使用D/CX线来区分命令/数据。注:MT6573使用LSA0线作为D/CX线,LSCE线作为CSX线。LSCK线作为SCL线,LSDA线作为SDA线。

DPI的命令在SPI上传输,Pixel data(RGB data)在D[17:0]上传输。其命令传输方式与serial DBI相同。对于Pixel data(RGB data),需要自己的4条控制线:DPICK_PIN(RGB时钟) 、DPIDE_PIN(RGB

数据有效)、 DPIVSYNC(场同步)、 DPIHSYNC(行同步) 。

typedef enum {

LCM_CTRL_NONE = 0, LCM_CTRL_SERIAL_DBI, LCM_CTRL_PARALLEL_DBI, LCM_CTRL_GPIO }

LCM_CTRL定义LCM与HOST之间传递command的方式,有SERIAL_DBI、PARALLEL_DBI、GPIO几种控制方式。如果是DPI接口,其LCM_CTRL可以选择SERIAL_DBI或者GPIO。

Width和height定义LCM的宽度和高度。

io_select_mode有这些选项:0(LCD_IO_SEL_16CPU_24RGB),1(LCD_IO_SEL_18CPU_18RGB),2(LCD_IO_SEL_24CPU_8RGB),3(LCD_IO_SEL_24CPU_ONLY)。根据driver IC 的定义填写。

LCM_×××_PARAMS根据不同的LCM_TYPE取值,这是针对DBI/DPI/DSI接口类型的详细参数定义。比如LCM_DPI_PARAMS定义如下: typedef struct {

unsigned int mipi_pll_clk_ref; // 0..1 unsigned int mipi_pll_clk_div1; // 0..63 unsigned int mipi_pll_clk_div2; // 0..15 unsigned int dpi_clk_div; // 2..32

unsigned int dpi_clk_duty; // (dpi_clk_div - 1) .. 31

/* polarity parameters */ LCM_POLARITY clk_pol; LCM_POLARITY de_pol; LCM_POLARITY vsync_pol; LCM_POLARITY hsync_pol;

/* timing parameters */

unsigned int hsync_pulse_width; unsigned int hsync_back_porch; unsigned int hsync_front_porch; unsigned int vsync_pulse_width;

unsigned int vsync_back_porch; unsigned int vsync_front_porch;

/* output format parameters */ LCM_DPI_FORMAT format; LCM_COLOR_ORDER rgb_order; unsigned int is_serial_output;

/* intermediate buffers parameters */ unsigned int intermediat_buffer_num; // 2..3

/* iopad parameters */

LCM_DRIVING_CURRENT io_driving_current;

} LCM_DPI_PARAMS;

其中,第一段前4项用于控制DPI时钟,计算公式如下:

Pixel Clock Frequency = 26MHz * mipi_pll_clk_div1 / (mipi_pll_clk_ref + 1)/ (2 * mipi_pll_clk_div2)/ dpi_clk_div

第二段4个参数设置DPICK_PIN(RGB时钟) 、DPIDE_PIN(RGB数据有效)、 DPIVSYNC(场同步)、 DPIHSYNC(行同步)线是上升沿还是下降沿有效。

行同步脉冲开始前和开始后的几个时钟周期,是行信号消隐期;场同步开始前和开始后的几个行周期,是场信号消隐期。消隐期不传递图像信号。消隐期特性由第三段六个参数定义:hsync_pulse_width; hsync_back_porch;

hsync_front_porch; vsync_pulse_width; vsync_back_porch; vsync_front_porch; LCM_DPI_FORMAT指定每个像素中RGB各占几个bit. LCM_COLOR_ORDER指定RGB的顺序。

上述参数的值,均依照LCM spec及驱动IC datasheet中的定义。

这里要说说一个特别之处。NT35510使用DPI接口,SERIAL_DBI ctrl 方式时,没有D/CX线,datasheet上定义的传输方式是9 bits,即在数据byte前加个D/CX bit。但使用了NT35510的LCM——LF040DNYB16a,其spec中却另外定义了其串口使用16 bits 模式传输。Byte1 是标志byte, 前3位分别为 R/W bit, D/CX bit, High/Low bit;Byte2 则是命令或数据。NT35510的每个command长度为2byte,还可能带有若干bytes的参数,比如命令F001,参数AA,应该这样传输:0x20 0xF0 0x00 0x01 0x40 0xAA。

(2)lcm_init主要实现LCM的初始化,包括如下步骤: config_gpio——配置GPIO。

发送reset信号。RESET pin low和RESET pin high需要持续的时间一般为若干ms, 以datasheet 为

准。

init_lcm_registers——初始化LCM的寄存器。具体可以厂家提供的初始代码为参考。一般在此函数末尾,都会使用唤醒命令组(见后文),使LCM进入工作状态。

(3)lcm_suspend 使LCM休眠,使用特定的命令,并遵守datasheet定义的时间特性。常用命令组如下:

0X2800 (or 0X28) —— set display off 0X1000 (or 0X10) —— enter sleep mode

对nt35510而言,还有一种更深睡眠的状态——deep standby mode,使用如下命令进入: 0X4F00 0X01

(4)lcm_resume使LCM苏醒,使用特定的命令,并遵守datasheet定义的时间特性。 唤醒命令组:

0X1100 (or 0X11) —— exit sleep mode 0X2900 (or 0X29) —— set display on

对nt35510而言,如果在lcm_suspend中使LCM enter deep standby mode,则不能使用唤醒命令组,需要使用reset信号并要重新init_lcm_registers。

四、 驱动 nt35510_lcm_drv怎样被上层使用 Mtkfb.c中实现了LCM的platform driver: static struct platform_driver mtkfb_driver = {

.driver = {

.name = “mtk-fb”,

.bus = &platform_bus_type, .probe = mtkfb_probe, .remove = mtkfb_remove, .suspend = mtkfb_suspend, .resume = mtkfb_resume, }, };

mtkfb_probe会调用函数mtkfb_find_lcm_driver来发现LCM的硬件层驱动。

mtkfb_find_lcm_driver——DISP_SelectDevice——disp_drv_get_lcm_driver,检查lcm_driver_list[], 得到当前使用的LCM及其驱动名称。

Mt6573_devs.c中,定义了framebuffer型的platform device,这个设备在mt6573_board_init()调用时被注册。它所对应的驱动就是上文提到的mtkfb_driver static struct platform_device mt6573_device_fb = { .name = \ .id = 0,

.num_resources = ARRAY_SIZE(resource_fb),

{\MT65XX_LED_MODE_NONE, -1}, {\MT65XX_LED_MODE_PWM, PWM7},

{\MT65XX_LED_MODE_CUST, (int)Cust_SetBacklight}, };

这个数组通过get_cust_led_list函数被mt65xx_leds_probe调用,传递给mt65xx_leds_driver,并且mt65xx_leds_probe 将数组中的设备一一注册。(\\mediatek\\source\\kernel\\drivers\\leds\\ leds.c) static struct platform_driver mt65xx_leds_driver = { .driver = {

.name = \.owner = THIS_MODULE, },

.probe = mt65xx_leds_probe, .remove = mt65xx_leds_remove, //.suspend = mt65xx_leds_suspend, .shutdown = mt65xx_leds_shutdown, };

static struct platform_device mt65xx_leds_device = { .name = \.id = -1 };

以lcd-backlight为例,其控制方式为自定义,背光控制IC为SN3228B,控制函数为

Cust_SetBacklight。MT6573的GPIO49作为控制脚,连接到SN3228B的EN/SET脚。该引脚对收到的上升沿脉冲计数(1~14个),调整自己的输出电流,从而控制Leds的亮度。所以

Cust_SetBacklight根据要达到的亮度level,在GPIO49上输出对应数量的上升沿脉冲,时间特性需满足SN3228的定义。

如果采用PWM控制方式,则需要使用MT6573的PWM controller。函数led_set_pwm实现了用PWM控制led灯的亮、灭、闪烁时对PWM controller 相关寄存器的配置;函数backlight_set_pwm实现了用PWM控制lcd backlight时对PWM controller 相关寄存器的配置,随lcd-backlight brightness level不同,相应的PWM脚输出对应数量的脉冲(level:0~64) mt65xx_led_set_cust根据不同的控制方式,调用相应的配置函数,如下: MT65XX_LED_MODE_PWM: backlight_set_pwm / led_set_pwm MT65XX_LED_MODE_CUST: Cust_SetBacklight MT65XX_LED_MODE_GPIO: brightness_set_gpio MT65XX_LED_MODE_PMIC: brightness_set_pmic

mt65xx_leds_probe 为cust_led_list[]中的每个led设备初始化一个任务队列,任务处理函数为 mt65xx_led_work,它再调用mt65xx_led_set_cust实现控制。每个led设备的亮度设置

(brightness_set)函数为mt65xx_led_set,它对lcd-backlight设备直接调用mt65xx_led_set_cust,对

其他设备则用任务队列调度。

Uboot阶段,其函数调用及led和backlight控制方式与启动后基本相同。增加了各种充电状态下对红、绿、蓝led的控制。如下是backlight的调用关系: (mt65xx_leds.c)

mt65xx_backlight_on——mt65xx_leds_brightness_set(MT65XX_LED_TYPE_LCD, LED_FULL)——mt65xx_led_set_cust——brightness_set_pwm / Cust_SetBacklight

本文来源:https://www.bwwdw.com/article/2ey7.html

Top