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

系列文章目录

  • 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!

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

写了这么多年DateUtils,殊不知你还有这么多弯弯绕!

目录 在日常开发中&#xff0c;Date工具类使用频率相对较高&#xff0c;大家通常都会这样写&#xff1a;这很简单啊&#xff0c;有什么争议吗&#xff1f;格式化后出现的时间错乱。看看Java 8是如何解决时区问题的&#xff1a;在处理带时区的国际化时间问题&#xff0c;推荐使用…

LSTM和GRU vs 循环神经网络RNN

1、考虑下列三种情况下&#xff0c;对比一下普通RNN的表现和LSTM和GRU表现&#xff1a; &#xff08;1&#xff09;早期观测值对预测未来观测者具有非常重要的意义。 考虑一个极端情况&#xff0c;其中第一个观测值包含一个校验和&#xff0c; 目标是在序列的末尾辨别校验和是…

第十四章 集合(List)

一、集合框架体系 集合&#xff1a; &#xff08;1&#xff09;可以动态保存任意多个对象。 &#xff08;2&#xff09;提供了一系列方便的操作对象的方法&#xff1a;add、remove、set、get等。 二、Collection 1. Collection 接口常用方法 &#xff08;1&#xff09;add&a…

BP网络识别26个英文字母matlab

wx供重浩&#xff1a;创享日记 对话框发送&#xff1a;字母识别 获取完整源码源工程文件 一、 设计思想 字符识别在现代日常生活的应用越来越广泛&#xff0c;比如车辆牌照自动识别系统&#xff0c;手写识别系统&#xff0c;办公自动化等等。本文采用BP网络对26个英文字母进行…

第 377 场周赛 解题报告 | 珂学家 | Floyd + 划分型DP

前言 整体评价 天崩局&#xff0c;压哨绝杀&#xff0c;感谢天&#xff0c;感谢地&#xff0c;T_T. 感觉被T2玩惨了&#xff0c;T3和T4很像&#xff0c;无非一个贪心&#xff0c;一个是划分型DP&#xff0c;但是都需要基于floyd预处理。 T1. 最小数字游戏 思路&#xff1a; …

接口测试 — 11.logging日志模块处理流程

1、概括理解 了解了四大组件的基本定义之后&#xff0c;我们通过图示的方式来理解下信息的传递过程&#xff1a; 也就是获取的日志信息&#xff0c;进入到Logger日志器中&#xff0c;传递给处理器确定要输出到哪里&#xff0c;然后进行过滤器筛选&#xff0c;通过后再按照定义…

【LeetCode】链表精选11题

目录 快慢指针&#xff1a; 1. 相交链表&#xff08;简单&#xff09; 2. 环形链表&#xff08;简单&#xff09; 3. 快乐数&#xff08;简单&#xff09; 4. 环形链表 II&#xff08;中等&#xff09; 5. 删除链表的倒数第 N 个节点&#xff08;中等&#xff09; 递归迭…

量化投资策略的评估标准及其计算公式

收益率指标&#xff1a;分为策略的总收益率和策略的年化收益率 策略的总收益率&#xff1a; 策略的总收益率是评价一个策略盈利能力的最基本的指标&#xff0c;其计算方法为&#xff1a; 公式中Vt表示策略最终的股票和现金的总价值&#xff0c;V0表示策略最初的股票和现金的总…

探秘JDK 13的黑科技:新特性一览

欢迎来到我的博客&#xff0c;代码的世界里&#xff0c;每一行都是一个故事 探秘JDK 13的黑科技&#xff1a;新特性一览 前言switch表达式扩展Switch表达式的基本概念&#xff1a;使用Switch表达式的优势&#xff1a;示例代码&#xff1a;注意事项和最佳实践&#xff1a; Text …

Spring Cloud + Vue前后端分离-第7章 核心业务功能开发

Spring Cloud Vue前后端分离-第7章 核心业务功能开发 7-1 课程管理功能开发 课程管理页面美化 1.课程管理页面美化 demo-course.jpg 复制search.html中的部分代码 course.vue 看效果 测试一下新增修改删除效果 1.课程管理页面美化2 scoped:style下的样式只应用于当前组件…

LCT(link cut tree) 详细图解与应用

樱雪喵用时 3days 做了 ybtoj 的 3 道例题&#xff0c;真是太有效率了&#xff01;&#xff01;1 为了避免自己没学明白就瞎写东西误人子弟&#xff0c;这篇 Blog 拖到了现在。 图片基本沿用 OIwiki&#xff0c;原文跳步骤&#xff08;主要是 access 部分&#xff09;的就自己…

Spark编程实验三:Spark SQL编程

目录 一、目的与要求 二、实验内容 三、实验步骤 1、Spark SQL基本操作 2、编程实现将RDD转换为DataFrame 3、编程实现利用DataFrame读写MySQL的数据 四、结果分析与实验体会 一、目的与要求 1、通过实验掌握Spark SQL的基本编程方法&#xff1b; 2、熟悉RDD到DataFram…

如何利用flume进行日志采集

介绍 Apache Flume 是一个分布式、可靠、高可用的日志收集、聚合和传输系统。它常用于将大量日志数据从不同的源&#xff08;如Web服务器、应用程序、传感器等&#xff09;收集到中心化的存储或数据处理系统中。 基本概念 Agent&#xff08;代理&#xff09;&#xff1a; …

039、转置卷积

之——增大高宽 杂谈 通常来说&#xff0c;卷积不会增大输入的高宽&#xff0c;通常要么不变&#xff0c;要么减半&#xff1b;如果想要直接padding来增加高宽&#xff0c;在不断的卷积过程中&#xff0c;padding的0越来越多&#xff0c;最后要做像素级的判断时候&#xff0c;由…

分布式核心技术之分布式共识

文章目录 什么是分布式共识&#xff1f;分布式共识方法PoWPoSDPoS 三种分布式共识算法对比分析 选主过程就是一个分布式共识问题&#xff0c;因为每个节点在选出主节点之前都可以认为自己会成为主节点&#xff0c;也就是说集群节点“存异”&#xff1b;而通过选举的过程选出主节…

基于Java SSM框架实现医院挂号上班打卡系统项目【项目源码+论文说明】计算机毕业设计

基于java的SSM框架实现医院挂号上班打卡系统演示 摘要 在网络发展的时代&#xff0c;国家对人们的健康越来越重视&#xff0c;医院的医疗设备更加先进&#xff0c;医生的医术、服务水平也不断在提高&#xff0c;给用户带来了很大的选择余地&#xff0c;而且人们越来越追求更个…

【leetcode100-019】【矩阵】螺旋矩阵

【题干】 给你一个 m 行 n 列的矩阵 matrix &#xff0c;请按照 顺时针螺旋顺序 &#xff0c;返回矩阵中的所有元素。 【思路】 不难注意到&#xff0c;每进行一次转向&#xff0c;都有一行/列被输出&#xff08;并失效&#xff09;&#xff1b;既然已经失效&#xff0c;那我…

MyBatis-Plus中默认方法对应的SQL到底长啥样?

我希望成为&#xff1a;自媒体圈中技术最好、实战经验最丰富的达人&#xff0c;技术圈中最会分享的架构师。加油&#xff01; 我的公众号&#xff1a;Hoeller 过段时间要给公司同事做Mybatis-Plus相关的培训&#xff0c;所以抓紧时间看看Mybatis-Plus的源码&#xff0c;顺便也分…

RT-Thread 内核对象管理框架

内核对象管理框架 RT-Thread采用内核对象管理系统来访问/管理所有内核对象&#xff0c;内核对象包含了内核中绝大部分设施&#xff0c;这些内核对象可以是静态分配的静态对象&#xff0c;也可以是从系统内存堆中分配的动态对象。 RT-Thread内核对象包括&#xff1a;线程&…

使用VisualStutio2022开发第一个C++程序

使用VisualStudio2022创建C项目 第一步&#xff1a;新建C的控制台应用 第二步&#xff1a;填写项目名称和代码存放位置&#xff0c;代码的存放目录不要有中文名 第三步:点击创建&#xff0c;VisualStudio会自动开始帮我们创建项目 第四步&#xff1a;项目创建好以后&…