/******************************************************************************
* 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 = ; #if defined(CONFIG_OK335XD)
index = ;
am335x_backlight.dev.platform_data = &am335x_backlight_data0; ------+
#elif defined(CONFIG_OK335XS) |
index = ; |
am335x_backlight.dev.platform_data = &am335x_backlight_data2; |
#endif |
|
am33xx_register_ecap(index, &pwm_pdata[index]); -------------------|----+
platform_device_register(&am335x_backlight); | |
| | |
return ; | | |
} +---------------------------------|-+ |
late_initcall(backlight_init); | | |
| | |
| | |
static struct platform_pwm_backlight_data am335x_backlight_data0 = { <--+ | |
.pwm_id = "ecap.0", | |
.ch = -, | |
.lth_brightness = , | |
.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 = -, |
}; |
|
#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, , ); | |
| |
if (IS_ERR(pdev)) { | |
WARN(, "Can't build omap_device for %s:%s.\n", | |
dev_name, oh->name); | |
return PTR_ERR(pdev); | |
} | |
return ; | |
} | |
//查找设备注册时的链表中是否有设备 | |
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, , 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 == || !pdev_name)
return ERR_PTR(-EINVAL); if (!pdata && pdata_len > )
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 != -)
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 < )
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, , 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 ; | |
| |
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 <= || props->type >= BACKLIGHT_TYPE_MAX) { |
WARN(, "%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 = ; if (bl->props.fb_blank != FB_BLANK_UNBLANK)
brightness = ; if (pb->notify)
brightness = pb->notify(pb->dev, brightness); if (brightness == ) {
pwm_set_duty_ns(pb->pwm, );
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 ;
}

am335x backlight的更多相关文章

  1. am335x LCD背光问题

    /**************************************************************** * am335x backlight problem * * 本问记 ...

  2. AM335x kernel4.4.12 LCD 时钟翻转设置记录

    TI AM335x kernel 4.4.12 LCD display 时钟翻转记录 因为公司硬件上已经确定LCD 转LVDS 转换芯片上确认以上升沿时钟为基准,所以只能在软件上调整相关东西. 入口在 ...

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

    对于AM335x来讲,TI维护的USB驱动已经非常完善了,本文称之为移植,实际上仅仅是配置内核选项使能USB HOST/OTG功能.废话少说,直接动手开启AM335x的USB驱动配置项. Step1. ...

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

    移植完成声卡驱动之后本想再接再励,移植网卡驱动,但没想到的是TI维护的内核太健壮,移植网卡驱动跟之前移植按键驱动一样简单,Nand驱动也是如此,于是,本人将Nand和网卡放在同一篇文章中介绍.介绍之前 ...

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

    经过一段时间的调试,终于调好了TQ335x的声卡驱动.TQ335x采用的Codec是WM8960,本文来总结下WM8960驱动在AM335x平台上的移植方法.Linux声卡驱动架构有OSS和ALSA两 ...

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

    TI的LCD控制器驱动是非常完善的,共通的地方已经由驱动封装好了,与按键一样,我们可以通过DTS配置完成LCD的显示.下面,我们来讨论下使用DTS方式配置内核完成LCD驱动的思路. (1)初步分析 由 ...

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

    移植完毕声卡驱动之后本想再接再励,移植网卡驱动,但没想到的是TI维护的内核太健壮,移植网卡驱动跟之前移植按键驱动一样简单,Nand驱动也是如此,于是,本人将Nand和网卡放在同一篇文章中介绍.介绍之前 ...

  8. AM335x tscadc platform driver 相关代码跟踪

    TI AM335x ti am335x_tsc.c 代码跟踪 在kernel 首层目录: 先运行make ARCH=arm tags 这个作用是建立tags文件,只含有arm架构的,利用ctag即可进 ...

  9. am335x watchdog 设备出错

    问题描述: am335x watchdog 设备节点打开失败. 如果是直接将omap_wdt 直接编译成uImage,这样会出现打开文件节点失败的情况. 如果单独编译成模块在后面文件系统内插入则不会. ...

随机推荐

  1. 敏捷转型中why与how的总结

    敏捷转型參考框架: 为了成功顺畅地推行敏捷开发.下面将对整个敏捷转型參考框架作个整体说明.为企业进行敏捷转型提供基本方法參考.整个敏捷转型參考框架主要包括5个步骤,前两个步骤主要是回答 Wh y的问题 ...

  2. repcached配置与简单測试

    安装libevent-devel watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvaGFueXVlcWk=/font/5a6L5L2T/fontsize/40 ...

  3. Spring +quartz获取ApplicationContext上下文

    job存在数据库中,能够进行动态的增增删改查,近期遇到了怎样获取ApplicationContext上下文的问题.解决的方法例如以下 applicationContext-quartz.xml < ...

  4. Python tan() 函数

    描述 tan() 返回x弧度的正弦值. 语法 以下是 tan() 方法的语法: import math math.tan(x) 注意:tan()是不能直接访问的,需要导入 math 模块,然后通过 m ...

  5. PixelLink

    简介 论文题目:PixelLink: Detecting Scene Text via Instance Segmentation 论文地址:https://arxiv.org/abs/1801.01 ...

  6. Token:服务端身份验证的流行方案【转】

    01- 身份认证 服务端提供资源给客户端,但是某些资源是有条件的.所以服务端要能够识别请求者的身份,然后再判断所请求的资源是否可以给请求者. token是一种身份验证的机制,初始时用户提交账号数据给服 ...

  7. cocos2dx当节点存在缩放时要注意的问题

    cocos2dx(所有引擎也均如此),如果一个节点存在缩放,一定不要忘了其局部空间里的单位长度也会发生变化.其子节点位移,局部空间转世界空间结果等都会受影响. 有时候我们想将父节点的缩放转移到子节点中 ...

  8. unity, Find References In Scene

    材质,脚本,shader等都可以通过Find References In Scene查看引用情况,如图. 当对一个文件点击Find References In Scene后,搜索命令会显示到Scene ...

  9. Regression Analysis Using Excel

    Regression Analysis Using Excel Setup By default, data analysis add-in is not enabled. Follow the st ...

  10. Javascript玩转继承(一)

    Javascript究竟是一门面向对象的语言,还是一门支持对象的语言,我想每个人都有着自己的看法.那些Javascript忠实的Fans一定讲Javascript是一门面向对象的语言,像<Jav ...