Exynos4412 移植Linux-6.1(九)移植tiny4412_backlight驱动的过程及问题解决

news2024/12/26 9:32:11

系列文章目录

  • Exynos4412 移植Linux-6.1(一)下载、配置、编译Linux-6.1

  • Exynos4412 移植Linux-6.1(二)SD卡驱动——解决无法挂载SD卡的根文件系统

  • Exynos4412 移植Linux-6.1(三)SD卡驱动——解决mmc0: Timeout waiting for hardware interrupt.

  • Exynos4412 移植Linux-6.1(四)NandFlash卡驱动

  • Exynos4412 移植Linux-6.1(五)DM9000网卡驱动

  • Exynos4412 移植Linux-6.1(六)【已解决】SROMC寄存器的数值不正确的问题

  • Exynos4412 移植Linux-6.1 (七)挂载Ramdisk文件系统,【已解决】Couldn’t find valid RAM disk image starting at 0

  • Exynos4412 移植Linux-6.1 (八)LCD驱动,解决error: implicit declaration of function ‘dma_free_writecombine’的问题

  • Exynos4412 移植Linux-6.1(九)移植tiny4412_backlight驱动的过程及问题解决


Exynos4412 移植Linux-6.1(九)移植tiny4412_backlight驱动的过程及问题解决

  • 系列文章目录
  • 1、背光的工作原理及电路
    • (1) 什么是背光:
    • (2)背光电路
    • (3)一线触控
    • (4)背光PWM控制信号接口
  • 2、移植背光驱动程序
    • (1)修改tiny4412_backlight设备树
    • (2)修改backlight驱动
      • 问题1:platform_get_resource无法获取irq资源
      • 问题2:irq指针为NULL
      • 问题3:devm_ioremap_resource不能重复映射res虚拟地址
      • 问题4:rmmod backlight_drv出错
  • 3、测试

LCD的驱动就移植完成了,但是LCD屏幕并没有亮。这有可能是因为没有移植backlight驱动。

1、背光的工作原理及电路

(1) 什么是背光:

LCD本身是不发光的,因此要想让其显示所要数据和图像,需要一个外部面光源系统来帮助其显示,即背光源(Backlight)。LCD的白光背光源一般由6~8个直下式或侧入式侧发光白色LED灯组成。背光源的工作原理,就是将灯条等点光源,利用导光板、反射片、扩散膜、增光膜(棱镜片)等组件转换成面光源,为LCD产品提供显示所需的外部光源。(https://blog.csdn.net/m0_66322708/article/details/124241892/)

(2)背光电路

EUP 2584是专为驱动白色LED而设计的一种恒流升压变换器。EN引脚用来控制LED的亮灭。FB引脚接收不同的占空比来驱动LCD的背光的亮度。LX引脚为LED背光源提供电源。
在这里插入图片描述

(3)一线触控

在 Cortex-A9智能终端中,LCD 背光开关是通过Exynos4412的GPX3_2作为EINT10,连接EPU2584的EN端口。GPX3_2输出为高电平“1”时,将打开背光;当输出为低电平“0”时,将关闭背光。
在这里插入图片描述

(4)背光PWM控制信号接口

背光PWM控制是通过Cortex-A9智能终端 的GPD0_1 作为TOUT1输出pwm信号给EPU2584的FB端口。在智能终端的背光电路中,通过在10%~90%之间调整PWM占空比,来调整背光电路的输出电流在20.5mA到5.5mA之间变化,从而实现背光灯源亮度的调整。
在这里插入图片描述

2、移植背光驱动程序

与tiny4412的电路是类似的,所以移植tiny4412的背光驱动。比较完整的tiny4412_backlightd 驱动代码如下:https://github.com/hceng/learn/blob/master/tiny4412/01_backlight_drv/backlight_drv.c
但是,在移植该驱动到Linux-6.1的过程中,出现了很多问题。现将问题和解决过程记录下来,以供大家参考。

(1)修改tiny4412_backlight设备树

tiny4412的设备树如下:

/ {
[...]
	backlight_demo@139D0000{
        	compatible = "tiny4412,backlight";
        	reg = <0x139D0000  0x14>;
        	tiny4412,backlight = <&gpx1 2 GPIO_ACTIVE_HIGH>;
        	pinctrl-names = "backlight_out","backlight_in";
        	pinctrl-0 = <&backlight_out>;
        	pinctrl-1 = <&backlight_in>;
       		interrupts = <0 40 0>;
        	clocks = <&clock CLK_PWM>;
        	clock-names = "timers";
        };
};
[...]
&pinctrl_1 {
        backlight_out: backlight_out{
                samsung,pins = "gpx1-2";
                samsung,pin-function = <1>;
                samsung,pin-pud = <0>;
                samsung,pin-drv = <0>;
        };
         backlight_in: backlight_in{
                samsung,pins = "gpx1-2";
                samsung,pin-function = <0>;
                samsung,pin-pud = <0>;
                samsung,pin-drv = <0>;
        };
};

根据自己开发板的电路引脚,修改如下:

	backlight {
		compatible = "tiny4412,backlight";
		reg = <0x139D0000 0x1000>;
		pinctrl-names = "backlight_in", "backlight_out";
   		pinctrl-0 = <&backlight_in>;
		pinctrl-1 = <&backlight_out>;
		gpios = <&gpx3 2 GPIO_ACTIVE_HIGH>;
		clock-names = "timers";
		clocks = <&clock CLK_PWM>;
		interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>;
		pwms = <&pwm 0 1000000000 0>;
	};
[...]

&pinctrl_1 {
    backlight_out: backlight_out {
      samsung,pins = "gpx3-2";
      samsung,pin-function = <EXYNOS_PIN_FUNC_OUTPUT>;
      samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
      samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
	};
    backlight_in: backlight_in {
      samsung,pins = "gpx3-2";
      samsung,pin-function = <EXYNOS_PIN_FUNC_INPUT>;
      samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
      samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
    };
};

(2)修改backlight驱动

问题1:platform_get_resource无法获取irq资源

tiny4412_backlight中会用到pwm的中断。我没有看懂onewire的原理。为了移植驱动,需要获取irq资源。
原驱动中是通过如下代码获取irq资源的。但是在Linux-6.1里,irq始终都为NULL。

    irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);

    if (irq == NULL)
    {
        printk("platform_get_resource irq error\n");
        return -EINVAL;
    }

然后,我在probe函数中添加for循环,打印resource,发现num_resources是1,也就是只有一个reg资源,而没有irq资源。

	printk("num_resources: = %d", pdev->num_resources);
	int i;
	for (i = 0; i < pdev->num_resources; i++) {
		struct resource *r = &pdev->resource[i];
		printk("resource_type: =%ld\n",resource_type(r));

接着,我试着在probe函数中用以下代码查看Exynos4.dtsi中把pwm转换成platform_device之后的resource,仍然只有一个reg资源,而没有irq资源。

    struct device_node *pwd_node = NULL;
    struct platform_device *pdev_pwd;    
    
	pwd_node = of_find_compatible_node(NULL,NULL,"samsung,exynos4210-pwm");
    if(pwd_node == NULL)
    {
        printk("of_find_node_by_name is error\n");
        return -EINVAL;
    }

    pdev_pwd = of_find_device_by_node(pwd_node);
        if(pdev_pwd == NULL)
    {
        printk("of_find_node_by_name is error\n");
        return -EINVAL;
    }

	printk("num_resources: = %d", pdev_pwd->num_resources);
	for (i = 0; i < pdev_pwd->num_resources; i++) {
		struct resource *r = &pdev_pwd->resource[i];
		printk("resource_type: =%ld\n",resource_type(r));

	}

最后,查看of_address_to_resourceof_irq_to_resource等内核代码,想找出没有转换irq资源的原因。但是,逻辑太复杂,没看懂,似乎和父节点还有关系。总之,新版本的内核,对设备树的解析似乎不同以前。
没办法,只能自己通过devic_node来获取irq。在platform_device中有一个成员struct device dev,这个dev中又有一个指针成员struct device_node * of_node。linux的做法就是将这个of_node指针直接指向由设备树转换而来的device_node结构;留给驱动开发者自行处理。
例如,有这么一个struct platform_device* of_test.我们可以直接通过of_test->dev.of_node来访问设备树中的信息。
我的做法是在backlight_probe函数中,添加代码实现以下2个功能。

  1. 利用of_irq_get或者irq_of_parse_and_map获取irq号。
    这两个函数获取的irq号是一样的。这个irq号不是硬件数据手册中的硬件irq号。
  2. 填充irq指针的resource结构体

问题2:irq指针为NULL

这里又出现了另一个问题,就是platform_get_resource无法获取irq资源,导致irq指针始终是NULL。怎样给irq指针赋值呢?我的方法是先获得reg的resource结构体地址res ,然后把res 地址+sizeof(*res),作为irq的地址。
不知道您是否还有更好的方法,请在评论区留言。我的代码如下:

static int backlight_probe(struct platform_device *pdev)
{
   int ret, irqno;
    dev_t devid;
    dev = &pdev->dev;
    struct device_node *dev_node;

    printk("enter %s\n", __func__);

    dev_node = dev->of_node;
    irqno = of_irq_get(dev_node, 0);
    printk("of_irq_get No: %d\n", irqno);

    irqno = irq_of_parse_and_map(dev_node,0);
    printk("irq_of_parse_and_map No: %d\n", irqno);

    res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
    irq = res + sizeof(*res);
    memset(irq, 0, sizeof(*irq));

    irq->start = irq->end = irqno;
 //   irq->flags = IORESOURCE_IRQ;
 //   irq->name = of_node_full_name(dev_node);

问题3:devm_ioremap_resource不能重复映射res虚拟地址

原驱动中是利用timer = devm_ioremap_resource(&pdev->dev, res);来映射pwm寄存器的虚拟地址的。但是,由于在arch/arm/boot/dts/exynos4.dtsi中,已经定义了pwm节点。如果它的status = "okay",在解析设备树的时候,就已经把reg = <0x139D0000 0x1000>;映射了一次。那么,devm_ioremap_resource再次映射该0x139D0000地址时就会报错。

[T90] timer_phyaddr: 139d0000
[T90] tiny4412_backlight 139d0000.backlight: can't request region for resource [mem 0x139d0000-0x139d0fff]
[T90] timer_virtaddr: fffffff0
[T90] 8<--- cut here ---
[T90] Unable to handle kernel paging request at virtual address fffffff0
[T90] [fffffff0] *pgd=6fffd861, *pte=00000000, *ppte=00000000
[T90] Internal error: Oops: 837 [#1] PREEMPT SMP ARM
[T90] Modules linked in: backlight_drv(O+)

同一个物理地址,可以被映射为多个虚拟地址,所以我的解决方法是直接用ioremap。不知道您是否还有更好的方法,请在评论区留言。

    timer = ioremap(res->start, resource_size(res));
    if (timer == NULL)
    {
        printk("devm_ioremap_resource error\n");
        return -EINVAL;
    }

    printk("timer_virtaddr: %x\n", timer);

问题4:rmmod backlight_drv出错

解决了前3个问题之后,就可以交叉编译出backlight_drv.ko。可以在智能终端上正常insmod backlight_drv.ko,但是rmmod backlight_drv会报错。这个问题我还没有解决,如果有小伙伴知道原因之后,在评论区多多指导。
backlight_drv驱动代码资源链接

3、测试

驱动代码资源中有测试程序,可以实现0~127档的亮光调节。
insmod backlight_drv.ko之后,在智能终端中执行如下命令,可以看到backlight的设备号是243。然后,执行mknod /dev/backlight c 243 0创建设备文件。加载了lcd驱动之后,就能显示了。
要注意:

  • 根据自己移植的Linux内核版本来修改Makefile文件。
  • 还需要交叉编译test_backlight.c。
[root@farsight ]# cd /sys/class/onewire_backlight/tiny4412_backlight
[root@farsight tiny4412_backlight]# ls
dev        power      subsystem  uevent
[root@farsight tiny4412_backlight]# cat dev
243:0
[root@farsight 04_backlight_drv]# mknod /dev/backlight c 243 0
[root@farsight 04_backlight_drv]# ./test_backlight
[...]
[  521.416003][   T99] kernel: reg = 126
[  521.416047][   T99] backlight_write
backlight: 126
[  521.472414][   T99] kernel: reg = 127
[  521.472482][   T99] backlight_write
backlight: 127
[  521.525357][   T99] backlight_exit
done!

请添加图片描述
下一步,实现启动系统自动加载。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1327841.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

解决 elementPlus 组件内容显示为英文的问题

解决 elementPlus 组件内容显示为英文的问题 一、问题描述 刚开始用 ElementPlus 发现默认的组件内容都是英文的 二、解决办法 找了找&#xff0c;发现是国际化的问题&#xff0c;默认就是显示英文&#xff0c;如果要显示中文需要配置中文显示。 关于显示中文的官方说明&a…

Windows11系统下如何通过.cab文件更新PL2303串口驱动?

Windows11系统下如何通过.cab文件更新PL2303串口驱动? 首先,在微软官方网站上下载所需版本的.cab文件,具体链接如下: https://www.catalog.update.microsoft.com/Search.aspx?q=Prolific%20USB-to-Serial%20Comm%20Port 如下图所示,进入该网站后,找到自己所需的驱动版…

神经网络可视化新工具:TorchExplorer

TorchExplorer是一个交互式探索神经网络的可视化工具&#xff0c;他的主要功能如下&#xff1a; TorchExplorer是一款创新的人工智能工具&#xff0c;专为使用非常规神经网络架构的研究人员设计。可以在本地或者wandb中生成交互式Vega自定义图表&#xff0c;提供网络结构的模块…

掌握Apache Kylin:工作原理、设置指南及实际应用全解析

&#x1f337;&#x1f341; 博主猫头虎 带您 Go to New World.✨&#x1f341; &#x1f984; 博客首页——猫头虎的博客&#x1f390; &#x1f433;《面试题大全专栏》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33a; &a…

设计模式(4)--对象行为(1)--职责链

1. 意图 使多个对象都有机会处理请求&#xff0c;从而避免请求的发送者和接收者之间的耦合关系。 将这些对象连成一条链&#xff0c;并沿着这条链传递该请求&#xff0c;直到有一个对象处理它为止。 2. 两种角色 抽象处理者(Handler)、具体处理者(Concrete Handler) 3. 优点 …

直播怎么录制视频?轻松提升视频质量!

录制直播视频是保存和分享游戏过程、教程或其他在线活动的好方法。随着直播行业的兴起&#xff0c;许多用户都希望能够录制自己的直播内容以供日后观看或与他人分享。可是直播怎么录制视频呢&#xff1f;本文将详细介绍两种直播录制视频的方法&#xff0c;希望通过具体的步骤讲…

Redis-Day3实战篇-商户查询缓存(缓存的添加和更新, 缓存穿透/雪崩/击穿, 缓存工具封装)

Redis-Day3实战篇-商户查询缓存 什么是缓存添加Redis缓存业务流程项目实现练习 - 给店铺类型查询业务添加缓存 缓存更新策略最佳实践方案案例 - 给查询商铺的缓存添加超时剔除和主动更新 缓存穿透/雪崩/击穿缓存穿透概述项目实现 - 商铺查询缓存 缓存雪崩缓存击穿概述互斥锁逻辑…

百模大战中的AI行业:新趋势与未来发展

文章目录 每日一句正能量前言技术进步应用拓展行业变革人才竞争后记 每日一句正能量 人生最重要的价值是心灵的幸福&#xff0c;而不是任何身外之物。 前言 随着科技的迅猛发展&#xff0c;人工智能&#xff08;AI&#xff09;已经成为引领技术革命的重要驱动力之一。在当前的…

物业服务投诉反馈建议建议二维码

为高效处理物业方面的投诉问题&#xff0c;进一步提升居住品质。凡尔码平台推出“二维码”便民投诉、反馈方式&#xff0c;如有群租扰民、占用堵塞消防通道或私拉乱建等问题&#xff0c;可以立即扫码或进入“凡尔码”小程序进行投诉或反馈。 如电梯出现故障物业服务企业未及时维…

助力智能车辆检测计数,基于官方YOLOv8全系列[n/s/m/l/x]开发构建道路交通场景下不同参数量级车流检测计数系统

在很多道路交通卡口都有对车流量的统计计算需要&#xff0c;有时候一些特殊时段、特殊节日等时间下对于车流的监测预警更为重要&#xff0c;恶劣特殊天气下的提早监测、预警、限流对于保证乘客、驾驶员的安全是非常重要的措施&#xff0c;本文的主要目的就是想要开发构建道路交…

最后一公里物流:发展历程与未来趋势

导言 最后一公里物流&#xff0c;作为物流体系中的关键环节&#xff0c;一直是行业关注的焦点。本文将深入研究最后一公里物流的发展历程、遇到的问题及解决过程&#xff0c;探讨未来的可用范围、在各国的应用和未来的研究趋势&#xff0c;并分析在哪些方面能取胜、在哪些方面发…

HarmonyOS引导页登陆页以及tabbar的代码说明 底部的Tabs功能3

效果 代码说明 这一功能实现起来还是麻烦&#xff0c;需要自己实现&#xff0c;在uniapp中的pages.json底部加上就能实现&#xff0c;在这里需要自己写 引入三个内容页 Home,Car,Setting &#xff0c;说明界面模块也行。引入 private tabsController: TabsController new Tab…

逆波兰计算器的完整代码

前置知识&#xff1a; 将中缀表达式转为List方法&#xff1a; //将一个中缀表达式转成中缀表达式的List//即&#xff1a;(3042)*5-6 》[(, 30, , 42, ), *, 5, -, 6]public static List<String> toIndixExpressionList(String s) {//定义一个List&#xff0c;存放中缀表达…

[Unity]接入Firebase 并且关联支付埋点

首先 在这个下一下FireBase的资源 firebase11.0.6 然后导入Analytics Auth Crashlytics 其他的看着加就行 然后直接丢到Unity里面 接下来需要去Firebase里面下载 Google json 丢到 这个下面 然后就是脚本代码了 using System.Collections; using System.Collection…

html/css实现简易圣诞贺卡

一、前言 HTML&#xff0c;全称HyperText Markup Language&#xff0c;即超文本标记语言&#xff0c;是用于创建网页的标准标记语言。HTML是一种标记语言&#xff0c;由一系列的元素标签组成&#xff0c;用于描述网页的结构和内容。 CSS&#xff0c;全称是“层叠样式表”&#…

音视频的编码格式与封装格式

音视频的编码格式与封装格式是两个不同的概念&#xff0c;视频封装格式常见的有&#xff1a;mp4&#xff0c;rmvb&#xff0c;avi&#xff0c;mkv&#xff0c;mov&#xff0c;mpg&#xff0c;vob&#xff0c;3gp&#xff0c;asf&#xff0c;rmvb&#xff0c;wmv&#xff0c;div…

中伟视界:天然气站安全隐患AI解决方案, 人工智能, 安全风险评估, 预测维护, 智能管理

近年来&#xff0c;随着人工智能技术的不断发展&#xff0c;越来越多的行业开始将人工智能应用于生产和管理中。在天然气行业&#xff0c;利用人工智能AI算法排除安全隐患已经成为一种新的趋势。那么&#xff0c;天然气站如何利用人工智能AI算法排除安全隐患呢&#xff1f;接下…

15、Qt显示图片并支持缩放、移动等操作

一、新建项目 点击“New Project”&#xff0c;选择“Application”“Qt Widget Application”&#xff0c;点击“Choose” 更改项目名称和位置 选择编译器 默认 默认 二、创建自定义类 右击项目名&#xff0c;选择“Add New” 选择“C” -> "C Class"&#xff…

数据结构和算法-二叉排序树(定义 查找 插入 删除 时间复杂度)

文章目录 二叉排序树总览二叉排序树的定义二叉排序树的查找二叉排序树的插入二叉排序树的构造二叉排序树的删除删除的是叶子节点删除的是只有左子树或者只有右子树的节点删除的是有左子树和右子树的节点 查找效率分析查找成功查找失败 小结 二叉排序树 总览 二叉排序树的定义 …

7-1 建立二叉搜索树并查找父结点(PTA - 数据结构)

按输入顺序建立二叉搜索树&#xff0c;并搜索某一结点&#xff0c;输出其父结点。 输入格式: 输入有三行&#xff1a; 第一行是n值&#xff0c;表示有n个结点&#xff1b; 第二行有n个整数&#xff0c;分别代表n个结点的数据值&#xff1b; 第三行是x&#xff0c;表示要搜索值…