zoukankan      html  css  js  c++  java
  • android系统平台显示驱动开发简要:LCD驱动调试篇『四』

    平台信息:

    内核:linux3.4.39
    系统:android4.4 
    平台:S5P4418(cortex a9)

    作者:瘋耔(欢迎转载,请注明作者)

    欢迎指正错误,共同学习、共同进步!!

    关注博主新浪博客:http://weibo.com/cpjphone

     
     

    以下是Samsung Exynos4412搭配TTL转LVDS芯片SN75LVDS83B、LVDS接口LCD为例说明。从硬件接口、驱动配置、背光PWM调节三部分说明。

    一、LCD接口原理以及硬件电路
    Samsung Exynos4412、SN75LVDS83B、LVDS接口LCD(24bit)为例说明,三者的关系如下:

    如上图所示,我们在应用中我,主控(Exynos4412)输出RGB信号到TFT-LCD大体经过三部分:
    1)、标号1部分,主控(Exynos4412)输出TTL信号;
    2)、标号2部分,TTL(RGB)-LVDS转换芯片SN75LVDS83B,把TTL信号转换成LVDS信号,传输到显示器的LVDS接收端;这部分有SN75LVDS83B编码芯片自动完成,所以我们不需要程序控制;
    3)、标号3部分,分两个小部分,LVDS转换成TTL,TFT-LCD显示部分;我们前面说过,TFT-LCD其实只识别TTL信号,所以要有一个转换的过程,先把LVDS信号转换、解码成TTL信号,在TFT-LCD上显示。
    有上面的过程,其实我们关心调试的部分只有标号1部分到标号2部分,后面标号2到标号3的部分是自动完成的,不需要我们程序上控制,把标号2部分、标号3部分合并:

    标号二部分可以理解为一个TTL(RGB)接口的LCD,如下图所示,标号一部分就是主控信号输出端,简化图如下所示:


    其实最简单的做法就是找个TTL接口的TFT-LCD,这样直接接上就可以。下面我们看下硬件上的电路连接:这个和我们上篇用的相同。


        有上面图可以看出:硬件连接

    网络标号

    说明

    管脚

    XvVD[0:23]

    XvVDEN

    XvVSYNC

    XvHSYNC

    XvVCLK

    RGB数据、使能、行场同步、时钟信号

     这是TTL信号输出

    LCD_PWM

    调节背光

    XpwmTOUT1/LCD_PWM/GPD0_1

    LCD_LED_EN

    LCD电压(TFT电压)使能

    GPC1_2

    LED_BL_EN

    LED背光使能

    GPL2_4

    上面可分为几部分,电路连接部分分析:

    (1)、TTL数据部分
    这张图有木有烂掉呀,哈哈,就是这些数据了。还有有木有想起来摄像头的数据(ITU接口)也是这样的??其实视频这种信号的原理是通用的,所以LCD通了,摄像头也就知道怎么回事了。


    2)、PWM背光调节
     PWM其实也是芯片的一个功能模块,看到他的管脚就是一个复用脚XpwmTOUT1/LCD_PWM/GPD0_1。上一篇我们粗略的了解了PWM,就是用到这里。但是有一个疑问,PWM是调节背光电压的,背光电压一般都是12V以上的,我们PWM只有0-3V的样子,Exynos4412的IO只有1.8V。怎么调节电压???


        其实这个PWM只是给LCD上PWM控制部分,真正的电压还是通过LCD控制板上的电路实现。

    3)、LED背光、LCD电压控制
    a、背光:LED+
    我们可以看到这个升压电路,通过SY7208把VBATT升压到18V,供给LED背光。SY7208最大升压26V。这个电压是提供给我们前面讲的背光的,也就是CCFL灯管或者LED背光组的电压。

    b、LCD电压
    这个电压也就是给你我们TFT阵列组用的,控制LCD液晶元素。
    这部分电路分析完成,我们就有比较清晰的思路出,要一个LCD工作,要完成两部分内容:LCD上电控制,背光、LCD电压;信号输出。

    ▊对于4418来说主控部分集成了LVDS信号输出,下面做电路介绍:

    --

    --

    与TFT屏连接部分,功能:

    ①显示数据传递

    ②触摸数据传递

    本章只讲述显示部分


    二、LCD 驱动部分调试
        LCD这部分,像上篇我们说的frambuffer这些部分一般平台都是可以用的,除非你是芯片厂的要写这部分。一般公司拿到的demo板子这部分都是通的,只是针对自己的lCD换一些参数。
    下面我们针对三星平台我们调试LCD的时时候程序方面的改动:
    1、屏参数的配置
    /kernel/drivers/video/Samsung/s3cfb_wa101s.c(4412)

    static struct s3cfb_lcd wa101 = {  
          
        .width  = 1280,//LCD 分辨率宽1280  
        .height = 800, //LCD 分辨率高 800  
        .bpp    = 24,//CLD 数据位 24bit  
        .freq   = 60,//LCD 像素时钟 60MHz  
        .timing = {//LCD porch无效值  
            .h_fp   = 70,  
            .h_bp   = 70,  
            .h_sw   = 20,  
          
            .v_fp   = 10,  
            .v_fpe  = 0,  
            .v_bp   = 10,  
            .v_bpe  = 0,  
            .v_sw   = 3,  
        },  
      
        .polarity = {//时钟、行场的极性;  
            .rise_vclk  = 1,  
            .inv_hsync  = 1,  
            .inv_vsync  = 1,  
            .inv_vden   = 0,  
        },  
    };  
    /* name should be fixed as 's3cfb_set_lcd_info' */  
    void s3cfb_set_lcd_info(struct s3cfb_global *ctrl)//初始化结构体  
    {  
        wa101.init_ldi = NULL;  
        ctrl->lcd = &wa101;  
    #endif  
    }  

    还能想起上一篇的如何阅读规格书中的那些参数不,把这些填入就可以。
    2、数据管脚初始化

     


    kernel/arch/arm/mach-exynos/setup-fb-s5p.c(4412)

    void s3cfb_cfg_gpio(struct platform_device *pdev)  
    {  
        s3cfb_gpio_setup_24bpp(EXYNOS4_GPF0(0), 8, S3C_GPIO_SFN(2), S5P_GPIO_DRVSTR_LV4);  
        s3cfb_gpio_setup_24bpp(EXYNOS4_GPF1(0), 8, S3C_GPIO_SFN(2), S5P_GPIO_DRVSTR_LV4);  
        s3cfb_gpio_setup_24bpp(EXYNOS4_GPF2(0), 8, S3C_GPIO_SFN(2), S5P_GPIO_DRVSTR_LV4);  
        s3cfb_gpio_setup_24bpp(EXYNOS4_GPF3(0), 4, S3C_GPIO_SFN(2), S5P_GPIO_DRVSTR_LV4);  
    }  
    LCD 数据脚初始化,驱动能力设为最高S5P_GPIO_DRVSTR_LV4;管脚驱动能力,S5P_GPIO_DRVSTR_LV1-4四个等级选择。
    3、时钟控制部分
    kernel/arch/arm/mach-exynos/setup-fb-s5p.c
    int s3cfb_clk_on(struct platform_device *pdev, struct clk **s3cfb_clk)  
    {  
        struct clk *sclk = NULL;  
        struct clk *mout_mpll = NULL;  
        struct clk *lcd_clk = NULL;  
      
        u32 rate = 0;  
        int ret = 0;  
      
        lcd_clk = clk_get(&pdev->dev, "lcd");  
        if (IS_ERR(lcd_clk)) {  
            dev_err(&pdev->dev, "failed to get operation clk for fimd
    ");  
            goto err_clk0;  
        }  
      
        ret = clk_enable(lcd_clk);  
        if (ret < 0) {  
            dev_err(&pdev->dev, "failed to clk_enable of lcd clk for fimd
    ");  
            goto err_clk0;  
        }  
        clk_put(lcd_clk);  
      
        sclk = clk_get(&pdev->dev, "sclk_fimd");  
        if (IS_ERR(sclk)) {  
            dev_err(&pdev->dev, "failed to get sclk for fimd
    ");  
            goto err_clk1;  
        }  
      
        if (soc_is_exynos4210())  
            mout_mpll = clk_get(&pdev->dev, "mout_mpll");  
        else  
            mout_mpll = clk_get(&pdev->dev, "mout_mpll_user");  
      
        if (IS_ERR(mout_mpll)) {  
            dev_err(&pdev->dev, "failed to get mout_mpll for fimd
    ");  
            goto err_clk2;  
        }  
      
        ret = clk_set_parent(sclk, mout_mpll);  
        if (ret < 0) {  
            dev_err(&pdev->dev, "failed to clk_set_parent for fimd
    ");  
            goto err_clk2;  
        }  
      
        if ((soc_is_exynos4412()) && (samsung_rev() >= EXYNOS4412_REV_2_0))  
            ret = clk_set_rate(sclk, 880000000);  
        else  
            ret = clk_set_rate(sclk, 800000000);  
        if (ret < 0) {  
            dev_err(&pdev->dev, "failed to clk_set_rate of sclk for fimd
    ");  
            goto err_clk2;  
        }  
        dev_dbg(&pdev->dev, "set fimd sclk rate to %d
    ", rate);  
      
        clk_put(mout_mpll);  
      
        ret = clk_enable(sclk);  
        if (ret < 0) {  
            dev_err(&pdev->dev, "failed to clk_enable of sclk for fimd
    ");  
            goto err_clk2;  
        }  
      
        *s3cfb_clk = sclk;  
      
        return 0;  
      
    err_clk2:  
        clk_put(mout_mpll);  
    err_clk1:  
        clk_put(sclk);  
    err_clk0:  
        clk_put(lcd_clk);  
      
        return -EINVAL;  
    }  
    int s3cfb_clk_off(struct platform_device *pdev, struct clk **clk)  
    {  
        struct clk *lcd_clk = NULL;  
      
        lcd_clk = clk_get(&pdev->dev, "lcd");  
        if (IS_ERR(lcd_clk)) {  
            printk(KERN_ERR "failed to get ip clk for fimd0
    ");  
            goto err_clk0;  
        }  
      
        clk_disable(lcd_clk);  
        clk_put(lcd_clk);  
      
        clk_disable(*clk);  
        clk_put(*clk);  
      
        *clk = NULL;  
      
        return 0;  
      
    err_clk0:  
        clk_put(lcd_clk);  
      
        return -EINVAL;  
    }  
      
    void s3cfb_get_clk_name(char *clk_name)  
    {  
        strcpy(clk_name, "sclk_fimd");  
    }  

     4、背光、LCD电压的控制

    LCD_LED_EN

    LCD电压(TFT电压)使能

    GPC1_2

    LED_BL_EN

    LED背光使能

    GPL2_4

    int s3cfb_backlight_on(struct platform_device *pdev)  
    {  
            int err;  
            pwm_set();  
        err = gpio_request_one(EXYNOS4_GPL2(4), GPIOF_OUT_INIT_HIGH, "GPL2_4");  
        if (err) {  
            printk(KERN_ERR "failed to request GPL2 for "  
                "lcd backlight control
    ");  
            return err;  
        }  
        s3c_gpio_setpull(EXYNOS4_GPL2(4),S3C_GPIO_PULL_NONE);  
        gpio_direction_output(EXYNOS4_GPL2(4), 1);  
        gpio_free(EXYNOS4_GPL2(4));  
        mdelay(20);  
        err = gpio_request_one(EXYNOS4_GPC1(2), GPIOF_OUT_INIT_HIGH, "GPC1_2");  
        if (err) {  
            printk(KERN_ERR "failed to request GPC1 for "  
                "lcd backlight control
    ");  
            return err;  
        }  
        s3c_gpio_setpull(EXYNOS4_GPC1(2),S3C_GPIO_PULL_NONE);  
        gpio_direction_output(EXYNOS4_GPC1(2), 0);  
        gpio_free(EXYNOS4_GPC1(2));  
      
        mdelay(20);  
        err = gpio_request(EXYNOS4_GPD0(1), "GPD0_1");  
      
        if (err) {  
            printk(KERN_ERR "failed to request GPD0_1 for "  
                "lcd pwm control
    ");  
            return err;  
        }  
        s3c_gpio_setpull(EXYNOS4_GPD0(1),S3C_GPIO_PULL_NONE);  
        s5p_gpio_set_drvstr(EXYNOS4_GPD0(1), S5P_GPIO_DRVSTR_LV4);    
        gpio_direction_output(EXYNOS4_GPD0(1), 1);  
        s3c_gpio_cfgpin(EXYNOS4_GPD0(1), EXYNOS4_GPD_0_1_TOUT_1);  
          
        gpio_free(EXYNOS4_GPD0(1));  
        mdelay(20);  
        return 0;  
      
        return 0;  
    }  
      
    int s3cfb_backlight_off(struct platform_device *pdev)  
    {  
        int err;  
        err = gpio_request_one(EXYNOS4_GPL2(4), GPIOF_OUT_INIT_LOW, "GPL2_4");  
        if (err) {  
            printk(KERN_ERR "failed to request GPL2 for "  
                "lcd backlight control
    ");  
            return err;  
        }  
        s3c_gpio_setpull(EXYNOS4_GPL2(4),S3C_GPIO_PULL_NONE);  
        gpio_direction_output(EXYNOS4_GPL2(4), 0);  
        gpio_free(EXYNOS4_GPL2(4));  
      
        err = gpio_request_one(EXYNOS4_GPC1(2), GPIOF_OUT_INIT_HIGH, "GPC1_2");  
        if (err) {  
            printk(KERN_ERR "failed to request GPC1 for "  
                "lcd backlight control
    ");  
            return err;  
        }  
        gpio_free(EXYNOS4_GPC1(2));  
      
        return 0;  
    }  

    5、PWM的设置

    arch/arm/mach-exynos/mach-smdk4x12.c

    Arch/arm/mach-exynos/mach-smdk4x12.c  
    /* LCD Backlight data */  
    static struct samsung_bl_gpio_info smdk4x12_bl_gpio_info = {  
        .no = EXYNOS4_GPD0(1),//PWM管脚XpwmTOUT1/LCD_PWM/GPD0_1  
        .func = S3C_GPIO_SFN(2),  
    };  
    static struct platform_pwm_backlight_data smdk4x12_bl_data = {  
        .pwm_id = 1,//PWM ID PWM编号为1号;  
        .pwm_period_ns  = 90000,  //22k  
    };  
    static void __init smdk4x12_machine_init(void)  
    {     
    ………………  
    samsung_bl_set(&smdk4x12_bl_gpio_info, &smdk4x12_bl_data);//在初始化的时候把对应的结构体初始化  
    ………………  
    }  

    samsung_bl_set看下这个函数的实现:

    kernel/arch/arm/palt-samsung/dev-backlight.c

    void samsung_bl_set(struct samsung_bl_gpio_info *gpio_info,  
        struct platform_pwm_backlight_data *bl_data)  
    {  
        int ret = 0;  
        struct platform_device *samsung_bl_device;  
        struct platform_pwm_backlight_data *samsung_bl_data;  
      
        samsung_bl_device = kmemdup(&samsung_dfl_bl_device,  
                sizeof(struct platform_device), GFP_KERNEL);//(1)、分配内存空间;  
        if (!samsung_bl_device) {  
            printk(KERN_ERR "%s: no memory for platform dev
    ", __func__);  
            return;  
        }  
      
        samsung_bl_data = s3c_set_platdata(&samsung_dfl_bl_data,  
            sizeof(struct platform_pwm_backlight_data), samsung_bl_device);//(2)、  
        if (!samsung_bl_data) {  
            printk(KERN_ERR "%s: no memory for platform dev
    ", __func__);  
            goto err_data;  
        }  
      
        /* Copy board specific data provided by user */  
        samsung_bl_data->pwm_id = bl_data->pwm_id;//(3)、把具体配置的数据给samsung_bl_data  
        samsung_bl_device->dev.parent =  
                &s3c_device_timer[samsung_bl_data->pwm_id].dev;  
      
        if (bl_data->max_brightness)//(4)、对bl_data的结构体检查,如果没有复制则用default的值  
            samsung_bl_data->max_brightness = bl_data->max_brightness;  
        if (bl_data->dft_brightness)  
            samsung_bl_data->dft_brightness = bl_data->dft_brightness;  
        if (bl_data->lth_brightness)  
            samsung_bl_data->lth_brightness = bl_data->lth_brightness;  
        if (bl_data->pwm_period_ns)  
            samsung_bl_data->pwm_period_ns = bl_data->pwm_period_ns;  
        if (bl_data->init)  
            samsung_bl_data->init = bl_data->init;  
        if (bl_data->notify)  
            samsung_bl_data->notify = bl_data->notify;  
        if (bl_data->exit)  
            samsung_bl_data->exit = bl_data->exit;  
        if (bl_data->check_fb)  
            samsung_bl_data->check_fb = bl_data->check_fb;  
      
        /* Keep the GPIO info for future use */  
        s3c_device_timer[samsung_bl_data->pwm_id].dev.platform_data = gpio_info;  
      
        /* Register the specific PWM timer dev for Backlight control */  
        ret = platform_device_register(//(5)、注册PWM设备驱动;  
                &s3c_device_timer[samsung_bl_data->pwm_id]);  
        if (ret) {  
            printk(KERN_ERR "failed to register pwm timer for backlight: %d
    ", ret);  
            goto err_plat_reg1;  
        }  
      
        /* Register the Backlight dev */  
        ret = platform_device_register(samsung_bl_device);//(6)、注册背光设备驱动;  
        if (ret) {  
            printk(KERN_ERR "failed to register backlight device: %d
    ", ret);  
            goto err_plat_reg2;  
        }  
      
        return;  
      
    err_plat_reg2://(7)、如果有异常的情况下退出;  
        platform_device_unregister(&s3c_device_timer[samsung_bl_data->pwm_id]);  
    err_plat_reg1:  
        kfree(samsung_bl_data);  
    err_data:  
        kfree(samsung_bl_device);  
        return;  
    }  

    (1)、分配内存空间

       samsung_bl_device = kmemdup(&samsung_dfl_bl_device,  
                sizeof(struct platform_device), GFP_KERNEL);  
    其中:  
    static struct platform_pwm_backlight_data samsung_dfl_bl_data = {  
        .max_brightness = 255,  
        .dft_brightness = 140,   
        .pwm_period_ns  = 78770,  
        .init           = samsung_bl_init,  
        .exit           = samsung_bl_exit,  
    };  
      
    static struct platform_device samsung_dfl_bl_device = {  
        .name       = "pwm-backlight",  
    };  

    (3)、把具体配置的数据给samsung_bl_data

    arch/arm/mach-exynos/mach-smdk4x12.c  
    static struct samsung_bl_gpio_info smdk4x12_bl_gpio_info = {  
        .no = EXYNOS4_GPD0(1),//PWM管脚XpwmTOUT1/LCD_PWM/GPD0_1  
        .func = S3C_GPIO_SFN(2),  
    };  
    static struct platform_pwm_backlight_data smdk4x12_bl_data = {  
        .pwm_id = 1,//PWM ID PWM编号为1号;  
        .pwm_period_ns  = 90000,  //22k  
    };  

    (4)、对bl_data的结构体检查,如果没有复制则用default的值

    参考(1)中的那些值。

    (5)、注册PWM设备驱动;

    ret = platform_device_register(  
            &s3c_device_timer[samsung_bl_data->pwm_id]); 

    其中s3c_device_timer[]这个结构体如下:

    struct platform_device s3c_device_timer[] = {  
        [0] = { DEFINE_S3C_TIMER(0, IRQ_TIMER0) },  
        [1] = { DEFINE_S3C_TIMER(1, IRQ_TIMER1) },  
        [2] = { DEFINE_S3C_TIMER(2, IRQ_TIMER2) },  
        [3] = { DEFINE_S3C_TIMER(3, IRQ_TIMER3) },  
        [4] = { DEFINE_S3C_TIMER(4, IRQ_TIMER4) },  

    我们饿samsung_bl_data->pwm_id=1;所以选择[1] = { DEFINE_S3C_TIMER(1, IRQ_TIMER1) },

    (6)、注册背光设备驱动;

    ret =platform_device_register(samsung_bl_device);  

    其中:samsung_bl_device

    samsung_bl_data = s3c_set_platdata(&samsung_dfl_bl_data,  
        sizeof(struct platform_pwm_backlight_data), samsung_bl_device);  

    (7)、如果有异常的情况下退出;

    6、PWM_BL背光驱动分析:

    Kernel/drivers/video/backlight/pwm_bl.c

    1)、驱动注册:

    static struct platform_driver pwm_backlight_driver = {  
        .driver     = {  
            .name   = "pwm-backlight",  
            .owner  = THIS_MODULE,  
        },  
        .probe      = pwm_backlight_probe,  
        .remove     = pwm_backlight_remove,  
        .suspend    = pwm_backlight_suspend,  
        .resume     = pwm_backlight_resume,  
    };  
      
    static int __init pwm_backlight_init(void)  
    {  
        return platform_driver_register(&pwm_backlight_driver);  
    }  

    2)、probe函数分析

    static int pwm_backlight_probe(struct platform_device *pdev)  
    {  
        struct backlight_properties props;  
        struct platform_pwm_backlight_data *data = pdev->dev.platform_data;  
        struct backlight_device *bl;  
        struct pwm_bl_data *pb;  
        int ret;  
      
        if (!data) {  
            dev_err(&pdev->dev, "failed to find platform data
    ");  
            return -EINVAL;  
        }  
      
        if (data->init) {  
            ret = data->init(&pdev->dev);  
            if (ret < 0)  
                return ret;  
        }  
      
        pb = kzalloc(sizeof(*pb), GFP_KERNEL);  
        if (!pb) {  
            dev_err(&pdev->dev, "no memory for state
    ");  
            ret = -ENOMEM;  
            goto err_alloc;  
        }  
      
        global_pb=pb;  
        INIT_DELAYED_WORK_DEFERRABLE(&key_event, key_event_work);//1)、任务队列初始化;  
      
        pb->period = data->pwm_period_ns;//2)、pb结构体初始化;  
        pb->notify = data->notify;  
        pb->check_fb = data->check_fb;  
        pb->lth_brightness = data->lth_brightness *  
            (data->pwm_period_ns / data->max_brightness);  
        pb->dev = &pdev->dev;  
      
        pb->pwm = pwm_request(data->pwm_id, "backlight");  
        if (IS_ERR(pb->pwm)) {  
            dev_err(&pdev->dev, "unable to request PWM for backlight
    ");  
            ret = PTR_ERR(pb->pwm);  
            goto err_pwm;  
        } else  
            dev_dbg(&pdev->dev, "got pwm for backlight
    ");  
      
        memset(&props, 0, sizeof(struct backlight_properties));  
        props.type = BACKLIGHT_RAW;  
        props.max_brightness = data->max_brightness;  
        bl = backlight_device_register(dev_name(&pdev->dev), &pdev->dev, pb,  
                           &pwm_backlight_ops, &props);  
        if (IS_ERR(bl)) {  
            dev_err(&pdev->dev, "failed to register backlight
    ");  
            ret = PTR_ERR(bl);  
            goto err_bl;  
        }  
        global_bl=bl;  
        bl->props.brightness = data->dft_brightness;  
        backlight_update_status(bl);//3)、更新背光状态;  
      
        platform_set_drvdata(pdev, bl);  
        return 0;  
      
    err_bl:  
        pwm_free(pb->pwm);  
    err_pwm:  
        kfree(pb);  
    err_alloc:  
        if (data->exit)  
            data->exit(&pdev->dev);  
        return ret;  
    }  

    1)、任务队列初始化;

    key_event_work加入key_event队列,

    INIT_DELAYED_WORK_DEFERRABLE(&key_event, key_event_work);  

    队列调度函数:

    static void key_event_work(struct work_struct *work)  
    {  
        global_pb->period=90000;  
        global_bl->props.brightness=global_brightness;  
        backlight_update_status(global_bl);  
        return ;  
    }  

    backlight_update_status

    static inline void backlight_update_status(struct backlight_device *bd)  
    {  
        mutex_lock(&bd->update_lock);  
        if (bd->ops && bd->ops->update_status)  
            bd->ops->update_status(bd);  
        mutex_unlock(&bd->update_lock);  
    }  

    update_status在pwm_backlight_ops结构体重指定:

    static const struct backlight_ops pwm_backlight_ops = {  
        .update_status  = pwm_backlight_update_status,  
        …………}  

    pwm_backlight_update_status我们后面分析,这个其实就是我们PWM设定实现的具体实施过程。

    2)、pb结构体初始化;

    pb->period = data->pwm_period_ns; pb->notify = data->notify;  
    pb->check_fb = data->check_fb;  
    pb->lth_brightness = data->lth_brightness *  
        (data->pwm_period_ns / data->max_brightness);  
    pb->dev = &pdev->dev;  
    pb->pwm = pwm_request(data->pwm_id, "backlight");  

    3)、更新背光状态

    backlight_update_status(bl);  

    4)、PWM_SET

    UI设置PWM时,会调用到驱动中的pwm_set(void)这个函数。这个函数主要在开机时使用。

    int pwm_set(void)  
    {  
        int error;  
        struct backlight_device *bl = global_bl;  
        struct pwm_bl_data *pb = global_pb;  
        printk("%s__%d
    ",__func__,pb->period);  
        pb->period=410000;  
        backlight_update_status(bl);  
        schedule_delayed_work(&key_event, 600); //调用队列,跟新亮度信息;  
          
        return 0;  
    }  

     5)、pwm_backlight_update_status这个就是PWM变化的具体实现,当应用层调节时,会调用到这个函数,把改变的值填入寄存器。

    static int pwm_backlight_update_status(struct backlight_device *bl)  
    {  
        struct pwm_bl_data *pb = dev_get_drvdata(&bl->dev);  
        int brightness = bl->props.brightness;  
        int max = bl->props.max_brightness;  
        //if(brightness==0)  
        //  return 0;  
        //printk("#####%s#%d__%d
    ",__func__,pb->period,brightness);  
        global_brightness=brightness;  
        if (bl->props.power != FB_BLANK_UNBLANK)  
            brightness = 0;  
      
        if (bl->props.fb_blank != FB_BLANK_UNBLANK)  
            brightness = 0;  
      
        if (pb->notify)  
            brightness = pb->notify(pb->dev, brightness);  
          
        if (brightness == 0) {  
            pwm_config(pb->pwm, 0, pb->period);  
            pwm_disable(pb->pwm);  
        } else {  
        #if 1  
            brightness = pb->lth_brightness +  
                (brightness * (pb->period - pb->lth_brightness) / max);  
        #else  
         brightness = pb->lth_brightness +  
                            (((pb->period - pb->lth_brightness) / max) * brightness );  
        #endif  
              
            pwm_config(pb->pwm, brightness, pb->period);//这里对PWM寄存器的具体操作;  
            pwm_enable(pb->pwm);  
        }  
        return 0;  
    }  



    三、LCD UBOOT下的控制(待整理…………)
    LCD在UBOOT下的控制,这部分我们没做过,后面有机会做了再把这部分完善,或者找个机会把代码详细看看。

    --------------------------------------------

     
  • 相关阅读:
    771. Jewels and Stones
    706. Design HashMap
    811. Subdomain Visit Count
    733. Flood Fill
    117. Populating Next Right Pointers in Each Node II
    250. Count Univalue Subtrees
    94. Binary Tree Inorder Traversal
    116. Populating Next Right Pointers in Each Node
    285. Inorder Successor in BST
    292. Nim Game Java Solutin
  • 原文地址:https://www.cnblogs.com/Ph-one/p/4819559.html
Copyright © 2011-2022 走看看