am335x backlight

/******************************************************************************
 *                     am335x backlight                                                              
 * 本文主要分析TI的am335x处理器,backlight注册过程。                                                                            
 *                                                                                                 
 *                                       Tony Liu, 2016-4-21, Shenzhen                             
*******************************************************************************/                
kernel/arcm/arm/omap2/board-am335xevm.c                                                             
static int __init backlight_init(void)                                                              
{                                                                                                   
    int index = 0;                                                                                  
                                                                                                    
#if defined(CONFIG_OK335XD)                                                                         
    index = 0;                                                                                      
    am335x_backlight.dev.platform_data = &am335x_backlight_data0; ------+                           
#elif defined(CONFIG_OK335XS)                                           |                           
    index = 2;                                                          |                           
    am335x_backlight.dev.platform_data = &am335x_backlight_data2;       |                           
#endif                                                                  |                           
                                                                        |                           
    am33xx_register_ecap(index, &pwm_pdata[index]);  -------------------|----+                      
    platform_device_register(&am335x_backlight);                        |    |                      
                                      |                                 |    |                      
    return 0;                         |                                 |    |                      
}                                     +---------------------------------|-+  |                      
late_initcall(backlight_init);                                          | |  |                      
                                                                        | |  |                      
                                                                        | |  |                      
static struct platform_pwm_backlight_data am335x_backlight_data0 = { <--+ |  |                      
    .pwm_id         = "ecap.0",                                           |  |                      
    .ch             = -1,                                                 |  |                      
    .lth_brightness    = 21,                                              |  |                      
    .max_brightness = AM335X_BACKLIGHT_MAX_BRIGHTNESS,                    |  |                      
    .dft_brightness = AM335X_BACKLIGHT_DEFAULT_BRIGHTNESS,                |  |                      
    .pwm_period_ns  = AM335X_PWM_PERIOD_NANO_SECONDS,                     |  |                      
};                                                                        |  |                      
                                                                          |  |                      
#define AM335X_BACKLIGHT_MAX_BRIGHTNESS        100                        |  |                      
#define AM335X_BACKLIGHT_DEFAULT_BRIGHTNESS    60                         |  |                      
                                                                          |  |                      
#define AM335X_PWM_PERIOD_NANO_SECONDS        (5000 * 10 * 100)           |  |                      
                                                                          |  |                      
static struct platform_device am335x_backlight = {        <---------------+  |                      
    .name           = "pwm-backlight",                                       |                      
    .id             = -1,                                                    |                      
};                                                                           |                      
                                                                             |                      
#define PWM_STR_LEN 10                                                       |                      
int __init am33xx_register_ecap(int id, struct pwmss_platform_data *pdata) <-+                      
{                                                                                                   
    struct platform_device *pdev;                                                                   
    struct omap_hwmod *oh;                                                                          
    char *oh_name = "ecap";                                                                         
    char dev_name[PWM_STR_LEN];                                                                     
                                                                                                    
    sprintf(dev_name, "ecap.%d", id);                                                               
    //查找链表中是否有同名的设备的寄存器信息                                                    
    oh = omap_hwmod_lookup(dev_name);          -------------------+                                 
    if (!oh) {                                                    |                                 
        pr_err("Could not look up %s hwmod\n", dev_name);         |                                 
        return -ENODEV;                                           |                                 
    }                                                             |                                 
    //注册设备                                                    |                             
    pdev = omap_device_build(oh_name, id, oh, pdata,    ----------|---+                             
            sizeof(*pdata), NULL, 0, 0);                          |   |                             
                                                                  |   |                             
    if (IS_ERR(pdev)) {                                           |   |                             
        WARN(1, "Can't build omap_device for %s:%s.\n",           |   |                             
            dev_name, oh->name);                                  |   |                             
        return PTR_ERR(pdev);                                     |   |                             
    }                                                             |   |                             
    return 0;                                                     |   |                             
}                                                                 |   |                             
//查找设备注册时的链表中是否有设备                                |   |             
struct omap_hwmod *omap_hwmod_lookup(const char *name)    <-------+   |                             
{                                                                     |                             
    struct omap_hwmod *oh;                                            |                             
                                                                      |                             
    if (!name)                                                        |                             
        return NULL;                                                  |                             
                                                                      |                             
    oh = _lookup(name);   ----+                                       |                             
                              |                                       |                             
    return oh;                |                                       |                             
}                             |                                       |                             
                              V                                       |                             
static struct omap_hwmod *_lookup(const char *name)                   |                             
{                                                                     |              
    struct omap_hwmod *oh, *temp_oh;                                  |                 
                                                                      |                 
    oh = NULL;                                                        |                    
    //查找                                                            |              
    list_for_each_entry(temp_oh, &omap_hwmod_list, node) {            |                  
        if (!strcmp(name, temp_oh->name)) {                           |            
            oh = temp_oh;                                             |          
            break;                                                    |                
        }                                                             |               
    }                       +-----------------------------------------+            
                            |                                                      
    return oh;              |                                                       
}                           |                                                        
                            V                                                        
struct platform_device *omap_device_build(const char *pdev_name, int pdev_id,                       
                      struct omap_hwmod *oh, void *pdata,                                           
                      int pdata_len,                                                                
                      struct omap_device_pm_latency *pm_lats,                                       
                      int pm_lats_cnt, int is_early_device)                                         
{                                                                                                   
    struct omap_hwmod *ohs[] = { oh };                                                              
                                                                                                    
    if (!oh)                                                                                        
        return ERR_PTR(-EINVAL);                                                                    
                                                                                                    
    return omap_device_build_ss(pdev_name, pdev_id, ohs, 1, pdata,                                  
                    pdata_len, pm_lats, pm_lats_cnt,                                                
                    is_early_device);                                                               
}                           |                                                                       
                            V                                                                       
struct platform_device *omap_device_build_ss(const char *pdev_name, int pdev_id,                    
                     struct omap_hwmod **ohs, int oh_cnt,                                           
                     void *pdata, int pdata_len,                                                    
                     struct omap_device_pm_latency *pm_lats,                                        
                     int pm_lats_cnt, int is_early_device)                                          
{                                                                                                   
    int ret = -ENOMEM;                                                                              
    struct platform_device *pdev;                                                                   
    struct omap_device *od;                                                                         
                                                                                                    
    if (!ohs || oh_cnt == 0 || !pdev_name)                                                          
        return ERR_PTR(-EINVAL);                                                                    
                                                                                                    
    if (!pdata && pdata_len > 0)                                                                    
        return ERR_PTR(-EINVAL);                                                                    
                                                                                                    
    pdev = platform_device_alloc(pdev_name, pdev_id);                                               
    if (!pdev) {                                                                                    
        ret = -ENOMEM;                                                                              
        goto odbs_exit;                                                                             
    }                                                                                               
                                                                                                    
    /* Set the dev_name early to allow dev_xxx in omap_device_alloc */                              
    if (pdev->id != -1)                                                                             
        dev_set_name(&pdev->dev, "%s.%d", pdev->name,  pdev->id);                                   
    else                                                                                            
        dev_set_name(&pdev->dev, "%s", pdev->name);                                                 
                                                                                                    
    od = omap_device_alloc(pdev, ohs, oh_cnt, pm_lats, pm_lats_cnt);                                
    if (!od)                                                                                        
        goto odbs_exit1;                                                                            
                                                                                                    
    ret = platform_device_add_data(pdev, pdata, pdata_len);                                         
    if (ret)                                                                                        
        goto odbs_exit2;                                                                            
                                                                                                    
    if (is_early_device)                                                                            
        ret = omap_early_device_register(pdev);                                                     
    else                                                                                            
        ret = omap_device_register(pdev);                                                           
    if (ret)                                                                                        
        goto odbs_exit2;                                                                            
                                                                                                    
    return pdev;                                                                                    
                                                                                                    
odbs_exit2:                                                                                         
    omap_device_delete(od);                                                                         
odbs_exit1:                                                                                         
    platform_device_put(pdev);                                                                      
odbs_exit:                                                                                          
                                                                                                    
    pr_err("omap_device: %s: build failed (%d)\n", pdev_name, ret);                                 
                                                                                                    
    return ERR_PTR(ret);                                                                            
}                                                                                                   
                                                                                                    
//驱动注册                                                                                            
kernel/driver/video/backlight/pwm_bl.c                                                          
static int __init pwm_backlight_init(void)                                                          
{                                                                                                   
    return platform_driver_register(&pwm_backlight_driver);                                         
}                                      |                                                            
                                       V                                                            
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 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\n");                                      
        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\n");                                               
        ret = -ENOMEM;                                                                              
        goto err_alloc;                                                                             
    }                                                                                               
                                                                                                    
    pb->period = data->pwm_period_ns;                                                               
    pb->notify = data->notify;                                                                      
    pb->notify_after = data->notify_after;                                                          
    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, data->ch, "backlight");                                     
    if (IS_ERR(pb->pwm)) {                                                                          
        dev_err(&pdev->dev, "unable to request PWM for backlight\n");                               
        ret = PTR_ERR(pb->pwm);                                                                     
        goto err_pwm;                                                                               
    } else                                                                                          
        dev_dbg(&pdev->dev, "got pwm for backlight\n");                                             
                                                                                                    
    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\n");                |  |                  
        ret = PTR_ERR(bl);                                                    |  |                  
        goto err_bl;                                                          |  |                  
    }                                                                         |  |                  
                                                                              |  |                  
    bl->props.brightness = data->dft_brightness;                              |  |                  
    backlight_update_status(bl);                                              |  | 
                                                                              |  | 
    platform_set_drvdata(pdev, bl);                                           |  |                  
    return 0;                                                                 |  |                  
                                                                              |  |                  
err_bl:                                                                       |  |                  
    pwm_release(pb->pwm);                                                     |  |                  
err_pwm:                                                                      |  |                  
    kfree(pb);                                                                |  |                  
err_alloc:                                                                    |  |                  
    if (data->exit)                                                           |  |                  
        data->exit(&pdev->dev);                                               |  |                  
    return ret;                                                               |  |                  
}                                                                             |  |                  
                                                                              |  |                  
struct backlight_device *backlight_device_register(const char *name,    <-----+  |                  
    struct device *parent, void *devdata, const struct backlight_ops *ops,       |                  
    const struct backlight_properties *props)                                    |                  
{                                                                                |                  
    struct backlight_device *new_bd;                                             |                  
    int rc;                                                                      |                  
                                                                                 |                  
    pr_debug("backlight_device_register: name=%s\n", name);                      |                  
                                                                                 |                  
    new_bd = kzalloc(sizeof(struct backlight_device), GFP_KERNEL);               |                  
    if (!new_bd)                                                                 |                  
        return ERR_PTR(-ENOMEM);                                                 |                  
                                                                                 |                  
    mutex_init(&new_bd->update_lock);                                            |                  
    mutex_init(&new_bd->ops_lock);                                               |                  
                                                                                 |                  
    new_bd->dev.class = backlight_class;                                         |                  
    new_bd->dev.parent = parent;                                                 |                  
    new_bd->dev.release = bl_device_release;                                     |                  
    dev_set_name(&new_bd->dev, name);                                            |                  
    dev_set_drvdata(&new_bd->dev, devdata);                                      |                  
                                                                                 |                  
    /* Set default properties */                                                 |                  
    if (props) {                                                                 |                  
        memcpy(&new_bd->props, props,                                            |                  
               sizeof(struct backlight_properties));                             |                  
        if (props->type <= 0 || props->type >= BACKLIGHT_TYPE_MAX) {             |                  
            WARN(1, "%s: invalid backlight type", name);                         |                  
            new_bd->props.type = BACKLIGHT_RAW;                                  |                  
        }                                                                        |                  
    } else {                                                                     |                  
        new_bd->props.type = BACKLIGHT_RAW;                                      |                  
    }                                                                            |                  
                                                                                 |                  
    rc = device_register(&new_bd->dev);                                          |                  
    if (rc) {                                                                    |                  
        kfree(new_bd);                                                           |                  
        return ERR_PTR(rc);                                                      |                  
    }                                                                            |                  
                                                                                 |                  
    rc = backlight_register_fb(new_bd);                                          |                  
    if (rc) {                                                                    |                  
        device_unregister(&new_bd->dev);                                         |                  
        return ERR_PTR(rc);                                                      |                  
    }                                                                            |                  
                                                                                 |                  
    new_bd->ops = ops;                                                           |                  
                                                                                 |                  
#ifdef CONFIG_PMAC_BACKLIGHT                                                     |                  
    mutex_lock(&pmac_backlight_mutex);                                           |                  
    if (!pmac_backlight)                                                         |                  
        pmac_backlight = new_bd;                                                 |                  
    mutex_unlock(&pmac_backlight_mutex);                                         |                  
#endif                                                                           |                  
                                                                                 |                  
    return new_bd;                                                               |                  
}                                                                                |                  
                                                                                 |                  
static const struct backlight_ops pwm_backlight_ops = {          <---------------+                  
    .update_status    = pwm_backlight_update_status,            -----------+                        
    .get_brightness    = pwm_backlight_get_brightness,                     |                        
    .check_fb    = pwm_backlight_check_fb,                                 |                        
};                                                                         |                        
//每次设置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 (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_set_duty_ns(pb->pwm, 0);                                                                
        pwm_stop(pb->pwm);                                                                          
    } else {                                                                                        
        brightness = pb->lth_brightness +                                                           
            (brightness * (pb->period - pb->lth_brightness) / max);                                 
        pwm_set_period_ns(pb->pwm, pb->period);                                                     
        pwm_set_duty_ns(pb->pwm, brightness);                                                       
        pwm_start(pb->pwm);                                                                         
    }                                                                                               
                                                                                                    
    if (pb->notify_after)                                                                           
        pb->notify_after(pb->dev, brightness);                                                      
                                                                                                    
    return 0;                                                                                       
}                                                                                                   

 

posted @ 2016-04-21 16:06  SuperTao1024  阅读(928)  评论(0编辑  收藏  举报