网站302跳转,网站名称与主办单位,建设包银行官方网站,自己做网站视频教程系列文章目录 Exynos4412 移植Linux-6.1#xff08;一#xff09;下载、配置、编译Linux-6.1 Exynos4412 移植Linux-6.1#xff08;二#xff09;SD卡驱动——解决无法挂载SD卡的根文件系统 Exynos4412 移植Linux-6.1#xff08;三#xff09;SD卡驱动——解决mmc0: Ti…系列文章目录 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驱动问题1platform_get_resource无法获取irq资源问题2irq指针为NULL问题3devm_ioremap_resource不能重复映射res虚拟地址问题4rmmod 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_demo139D0000{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驱动
问题1platform_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_resource、of_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个功能。
利用of_irq_get或者irq_of_parse_and_map获取irq号。 这两个函数获取的irq号是一样的。这个irq号不是硬件数据手册中的硬件irq号。填充irq指针的resource结构体
问题2irq指针为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);问题3devm_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: cant 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] *pgd6fffd861, *pte00000000, *ppte00000000
[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);问题4rmmod 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。
[rootfarsight ]# cd /sys/class/onewire_backlight/tiny4412_backlight
[rootfarsight tiny4412_backlight]# ls
dev power subsystem uevent
[rootfarsight tiny4412_backlight]# cat dev
243:0
[rootfarsight 04_backlight_drv]# mknod /dev/backlight c 243 0
[rootfarsight 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! 下一步实现启动系统自动加载。