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 = ; #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的更多相关文章
- am335x LCD背光问题
/**************************************************************** * am335x backlight problem * * 本问记 ...
- AM335x kernel4.4.12 LCD 时钟翻转设置记录
TI AM335x kernel 4.4.12 LCD display 时钟翻转记录 因为公司硬件上已经确定LCD 转LVDS 转换芯片上确认以上升沿时钟为基准,所以只能在软件上调整相关东西. 入口在 ...
- AM335x(TQ335x)学习笔记——USB驱动移植
对于AM335x来讲,TI维护的USB驱动已经非常完善了,本文称之为移植,实际上仅仅是配置内核选项使能USB HOST/OTG功能.废话少说,直接动手开启AM335x的USB驱动配置项. Step1. ...
- AM335x(TQ335x)学习笔记——Nand&&网卡驱动移植
移植完成声卡驱动之后本想再接再励,移植网卡驱动,但没想到的是TI维护的内核太健壮,移植网卡驱动跟之前移植按键驱动一样简单,Nand驱动也是如此,于是,本人将Nand和网卡放在同一篇文章中介绍.介绍之前 ...
- AM335x(TQ335x)学习笔记——WM8960声卡驱动移植
经过一段时间的调试,终于调好了TQ335x的声卡驱动.TQ335x采用的Codec是WM8960,本文来总结下WM8960驱动在AM335x平台上的移植方法.Linux声卡驱动架构有OSS和ALSA两 ...
- AM335x(TQ335x)学习笔记——LCD驱动移植
TI的LCD控制器驱动是非常完善的,共通的地方已经由驱动封装好了,与按键一样,我们可以通过DTS配置完成LCD的显示.下面,我们来讨论下使用DTS方式配置内核完成LCD驱动的思路. (1)初步分析 由 ...
- AM335x(TQ335x)学习笔记——Nand&&网卡驱动移植
移植完毕声卡驱动之后本想再接再励,移植网卡驱动,但没想到的是TI维护的内核太健壮,移植网卡驱动跟之前移植按键驱动一样简单,Nand驱动也是如此,于是,本人将Nand和网卡放在同一篇文章中介绍.介绍之前 ...
- AM335x tscadc platform driver 相关代码跟踪
TI AM335x ti am335x_tsc.c 代码跟踪 在kernel 首层目录: 先运行make ARCH=arm tags 这个作用是建立tags文件,只含有arm架构的,利用ctag即可进 ...
- am335x watchdog 设备出错
问题描述: am335x watchdog 设备节点打开失败. 如果是直接将omap_wdt 直接编译成uImage,这样会出现打开文件节点失败的情况. 如果单独编译成模块在后面文件系统内插入则不会. ...
随机推荐
- lua——元表、元方法、继承
[元表] 元表中的键为事件(event),称值为元方法(metamethod). 通过函数getmetatable查询不论什么值的元表,通过函数setmetatable替换表的元表. setmetat ...
- NYOJ239 月老的难题 【二分图最大匹配·匈牙利】
月老的难题 时间限制:1000 ms | 内存限制:65535 KB 难度:4 描写叙述 月老准备给n个女孩与n个男孩牵红线.成就一对对美好的姻缘. 如今,因为一些原因,部分男孩与女孩可能结成幸福 ...
- django 在建模时的一个手贱
最近在写一个网站,在建立model的时候遇到了一些问题,最后找了好久才找到为什么. 一.django的model定义如下: from django.db import models # Create ...
- 解决Linux(ubuntu),windows双系统重装后恢复开机选单
1 重装ubuntu后恢复开机选单十分简单.直接更新grub就能够了: sudo update-grub 2 重装windows后显得麻烦一点.需用u盘写入ubuntu镜像重新启动使电脑从u盘启动, ...
- Synplify9.6.2破解(转帖)
Synplify9.6.2破解(转帖) 转载自:http://www.cnblogs.com/mark-sun/archive/2012/02/26/2368773.html Abstract本文 ...
- JVM 发生OOM的四种情况
1.Java堆溢出:heap Java堆内存主要用来存放运行过程中所以的对象,该区域OOM异常一般会有如下错误信息;java.lang.OutofMemoryError:Javaheap space此 ...
- ubantu 文件解压缩
对于刚刚接触Linux的人来说,一定会给Linux下一大堆各式各样的文件名给搞晕.别个不说,单单就压缩文件为例,我们知道在Windows下最常见 的压缩文件就只有两种,一是,zip,另一个是.rar. ...
- 【NOI】9272 偶数个三
题目 链接:bajdcc/ACM 描述 在所有的N位数中,有多少个数中有偶数个数字3?结果模12345.(1<=N<=10000) 样例输入 2 样例输出 73 方法一:穷举 评价:最简单 ...
- 基于S3C2440的U-BOOT的start.S分析
基于S3C2440的U-BOOT的start.S分析 在了解了ARM相关的汇编指令后,同时结合网上各位大虾的提点开始阅读u-boot的启动代码,现将分析过程记录如下 可执行文件及内存映射 我们可以把可 ...
- Eclipse中设置文件编码
如果你在使用某个editor进行开发的话,文件编码就由改editor解决即可 Eclipse中也有这个功能,帮你设置文件的编码,选择Edit->Set Encoding即可 注意,这个选项针对不 ...