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;
}                                                                                                   
时间: 2024-10-29 19:06:42

am335x backlight的相关文章

AM335x(TQ335x)学习笔记——USB驱动移植

对于AM335x来讲,TI维护的USB驱动已经非常完善了,本文称之为移植,实际上仅仅是配置内核选项使能USB HOST/OTG功能.废话少说,直接动手开启AM335x的USB驱动配置项. Step1. 配置内核支持USB 默认的配置项没有配置USB相关的选项,但是DTS已经配置好了,我们不需要对DTS作任何修改,详细的内核配置项如下: Device Drivers ---> [*] USB support ---> [*] OTG support <*> EHCI HCD (USB

AM335x(TQ335x)学习笔记——Nand&amp;&amp;网卡驱动移植

移植完成声卡驱动之后本想再接再励,移植网卡驱动,但没想到的是TI维护的内核太健壮,移植网卡驱动跟之前移植按键驱动一样简单,Nand驱动也是如此,于是,本人将Nand和网卡放在同一篇文章中介绍.介绍之前先感慨一下:TI的维护的内核真的很健壮,DTS真的很强大. 1. Nand驱动移植 阅读TQ335x的原理图可知,TQ335x的Nand连接到了GPMC上,且都是使用的相应引脚的MODE0复用功能,AM335x上上电复位后这些引脚的默认状态就处于MODE0模式,故无需进行pinmux设置,原始的DT

AM335x(TQ335x)学习笔记——Nand&amp;amp;&amp;amp;网卡驱动移植

移植完毕声卡驱动之后本想再接再励,移植网卡驱动,但没想到的是TI维护的内核太健壮,移植网卡驱动跟之前移植按键驱动一样简单,Nand驱动也是如此,于是,本人将Nand和网卡放在同一篇文章中介绍.介绍之前先感慨一下:TI的维护的内核真的非常健壮,DTS真的非常强大. 1. Nand驱动移植 阅读TQ335x的原理图可知,TQ335x的Nand连接到了GPMC上,且与DTS中默认的配置吻合,此处不做不论什么改动,详情例如以下: nandflash_pins_s0: nandflash_pins_s0

AM335x(TQ335x)学习笔记——LCD驱动移植

TI的LCD控制器驱动是非常完善的,共通的地方已经由驱动封装好了,与按键一样,我们可以通过DTS配置完成LCD的显示.下面,我们来讨论下使用DTS方式配置内核完成LCD驱动的思路. (1)初步分析 由于TQ335x使用的芯片是AM335x,故仍然可以参考am335x-evm.dts.当然,am335x-evmsk.dts.am335x-beagbone.dts都可以.本文以am335x-evm.dts为例.大体上浏览下DTS文件,可以发现两个醒目的节点:一个是panel,一个是backlight

AM335x(TQ335x)学习笔记——WM8960声卡驱动移植

经过一段时间的调试,终于调好了TQ335x的声卡驱动.TQ335x采用的Codec是WM8960,本文来总结下WM8960驱动在AM335x平台上的移植方法.Linux声卡驱动架构有OSS和ALSA两种架构,目前最常用的架构是ALSA,本文也使用ALSA架构对WM8960驱动进行移植. ASoC是对ALSA驱动架构的进一步封装.ASoC将ALSA驱动中的各模块抽象为三部分:Platform.Codec和Machine.Platform主要是平台硬件驱动,包括SoC的IIS模块.DMA等,在本文中

Am335x 下GPIO控制实例-驱动程序(转)

看了这么多的资料,现在决定上手了,下面将用两种方式来实现对GPIO 117的控制1,用直接添加到内核的方式,实现MISC的驱动(misc_register)2,用手工安装的方式,实现简单字符设备驱动(register_chrdev) 实现前提:当前所用的GPIO没有被其它设备所使用,大家可以用我前面BLOG说的方式查看GPIO的使用情况,当前我所用的GPIO本来是bluetooth的开关,需要屏蔽一个函数.不然后面的驱动申请IO都会失败.函数为Board-am335xevm.c 中的wl12xx

Linux下的Backlight子系统(二)【转】

转自:http://blog.csdn.net/weiqing1981127/article/details/8515847 版权所有,转载必须说明转自 http://my.csdn.net/weiqing1981127 原创作者:南京邮电大学  通信与信息系统专业 研二 魏清 三.Backlight核心驱动 下面我们讲讲backlight子系统.背光子系统目录在/driver/video/backlight下,其中背光子系统核心代码是backlight.c 先查看/driver/video/b

am335x mux配置

/**************************************************************** * am335x mux配置 * * am335x的引脚复寄存器是CONTROL_MODULE Register(芯片手册Chapter 9) * 本文主要分析板级文件中如何实现复用. * * 参考链接: * http://blog.chinaunix.net/uid-29745891-id-4348350.html * * Tony Liu, 2016-4-30,

AM335x时钟树

个人比较菜鸟,搞了AM335x快一年了,依旧对其时钟一脸蒙蔽,虽然RTM已经有对时钟的详细描述,但是依旧感觉不太熟悉,偶然机会逛TI论坛(http://www.deyisupport.com)知道有一个叫CTT的软件,其专门针对AM335x等开发板,直观的显示系统时钟,让我们能够很快知道该配置那些时钟,那些是已经设置好而不需要配置的. 1.CTT是什么,有什么用? CTT为Clock Tree Tool英文缩写,其主要针对TI部分CPU,用于快速便捷配置系统时钟,由于AM335x时钟比较麻烦,分