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; }
am335x backlight相关推荐
- linux中替换的方法,linux vi 中s 替换方法
vi/vim 中可以使用 :s 命令来替换字符 :s/vivian/sky/ 替换当前行第一个 vivian 为 sky :s/vivian/sky/g 替换当前行所有 vivian 为 sky :n ...
- AM335x kernel4.4.12 LCD 时钟翻转设置记录
TI AM335x kernel 4.4.12 LCD display 时钟翻转记录 因为公司硬件上已经确定LCD 转LVDS 转换芯片上确认以上升沿时钟为基准,所以只能在软件上调整相关东西. 入口在 ...
- AM335x(TQ335x)学习笔记——Nandamp;amp;网卡驱动移植
移植完成声卡驱动之后本想再接再励,移植网卡驱动,但没想到的是TI维护的内核太健壮,移植网卡驱动跟之前移植按键驱动一样简单,Nand驱动也是如此,于是,本人将Nand和网卡放在同一篇文章中介绍.介绍之前 ...
- am335x的网卡相关资料
其他网站看到的am335x的网卡移植参考程序,不知道能不能用 http://www.deyisupport.com/question_answer/dsp_arm/sitara_arm/f/25/t/ ...
- AM335x—WM8960声卡驱动移植
经过一段时间的调试,终于调好了TQ335x的声卡驱动.TQ335x采用的Codec是WM8960,本文来总结下WM8960驱动在AM335x平台上的移植方法.Linux声卡驱动架构有OSS和ALSA两 ...
- AM335X PWMSS 驱动指导
脉宽调制子系统(Pluse-Width Modulation SubSystem--PWMSS)由增强高分辨率脉宽调制器(eHRPWM),强采集(eCAP),强正交编码脉冲(eQEP)三个模块构成. ...
- AM335x LCD驱动解析
文章目录 1. LCD背景 2. LCD驱动 2.1 Device 2.2 Driver 2.2.1 fbmem_init() 2.2.2 register_framebuffer() 2.2.3 / ...
- AM335X——USB摄像头
CSDN仅用于增加百度收录权重,排版未优化,日常不维护.请访问:www.hceng.cn 查看.评论. 本博文对应地址: https://hceng.cn/2019/06/23/AM335X--USB ...
- FreeBSD设备驱动管理介绍(BSP: Ti AM335x)
这段时间一直在忙FreeBSD驱动移植的项目,因此对FreeBSD做了一定的了解,鉴于网上对于FreeBSD的设备驱动资料较少,在这里给出本人对于FreeBSD驱动管理的理解心得(主要是USB驱动管理 ...
最新文章
- Objective-C单例实现
- devi into python 笔记(一)字典 列表的简单操作
- could not create connection to database server.] with root cause
- Linux shell脚本中的命令正确写法
- 如何使用SSL pinning来使你的iOS APP更加安全
- Java读取Propertity文件
- Python中__init__和__new__的区别详解
- Ubuntu快速设置指南
- Java的深拷贝 vs 浅拷贝
- 小飞机安卓android手机设置教程,全民飞机大战叉叉助手安卓版设置步骤教程详解...
- Linux学习笔记——网络组成
- 20个PCB快捷键操作,提升绘图效率
- 迅雷不及掩耳 山寨版iPhone 5令人瞠目
- 批量创建文件夹并命名的方法
- 计算机处理器怎么看 64,怎么查看电脑处理器是32还是64位
- 2021年茶艺师(初级)试题及解析及茶艺师(初级)作业模拟考试
- 人类历史的进程vs互联网的进程
- PRISM 下载安装
- java数字音频最强教程之音频的王者之路(音频发烧友篇)
- 业务入云是一条不归路
热门文章
- poj 3260 The Fewest Coins(多重背包+完全背包)
- Windows 记事本的 Bug :-)
- 【python】面向对象类的继承
- Servlet 编写过滤器
- 03-13 微信小程序自动化测试
- 程序员笔试网上查答案,HR吐槽,网友:你们公司断网开发吗?
- 5条能让web前端至少手拿20万年薪的特性!
- arm Linux 低成本方案,参赛作品《低成本基于ARM+Linux平台搭建web服务器的物联网学习板》...
- 二元函数最大最小值定理证明_代数基本定理,用复数证明所有多项式函数都有根...
- ecshop插件_ECSHOP和SHOPEX快递单号查询中通快递插件V8.6专版