相关信息硬件平台:全志t507
系统版本:android 10 / linux 4.9.170
问题描述:pf4 无法通过标准接口设置为中断模式,而 pf1、pf2、pf3、pf5 正常可用。
分析过程一开始以为是引脚被其它驱动占用引起,或者该引脚不具备中断功能,经过排查,已排除这两种可能,因此通过从源码分析来找问题的根因。
以下是以 gpio_keys.c 驱动为入口进行分析:
// drivers/input/keyboard/gpio_keys.cstatic int gpio_keys_setup_key(struct platform_device *pdev, struct input_dev *input, struct gpio_button_data *bdata, const struct gpio_keys_button *button){ ...... error = devm_request_any_context_irq(&pdev- >dev, bdata- >irq, isr, irqflags, desc, bdata);}// kernel/irq/devres.cint devm_request_any_context_irq(struct device *dev, unsigned int irq, irq_handler_t handler, unsigned long irqflags, const char *devname, void *dev_id){ ...... rc = request_any_context_irq(irq, handler, irqflags, devname, dev_id); if (rc name, irq, desc- >irq_data.chip- >name); goto out_mask; } ...... } ......}// kernel/irq/manage.cstatic int irq_request_resources(struct irq_desc *desc){ struct irq_data *d = &desc- >irq_data; struct irq_chip *c = d- >chip; return c- >irq_request_resources ? c- >irq_request_resources(d) : 0;}// drivers/pinctrl/sunxi/pinctrl-sunxi.cstatic struct irq_chip sunxi_pinctrl_edge_irq_chip = { .name = sunxi_pio_edge, .irq_ack = sunxi_pinctrl_irq_ack, .irq_mask = sunxi_pinctrl_irq_mask, .irq_unmask = sunxi_pinctrl_irq_unmask, .irq_request_resources = sunxi_pinctrl_irq_request_resources, .irq_release_resources = sunxi_pinctrl_irq_release_resources, .irq_set_type = sunxi_pinctrl_irq_set_type, .irq_set_wake = sunxi_pinctrl_irq_set_wake,};// drivers/pinctrl/sunxi/pinctrl-sunxi.cstatic int sunxi_pinctrl_irq_request_resources(struct irq_data *d){ struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d); struct sunxi_desc_function *func; func = sunxi_pinctrl_desc_find_function_by_pin(pctl, pctl- >irq_array[d- >hwirq], irq); if (!func) return -einval; /* change muxing to int mode */ printk(kern_emerg[lmx] irq:%d set int mode pin:%d d- >hwirq:%ld func- >muxval:%dn, d- >irq, pctl- >irq_array[d- >hwirq], d- >hwirq, func- >muxval); sunxi_pmx_set(pctl- >pctl_dev, pctl- >irq_array[d- >hwirq], func- >muxval); return 0;}// drivers/pinctrl/sunxi/pinctrl-sunxi.cstatic void sunxi_pmx_set(struct pinctrl_dev *pctldev, unsigned pin, u8 config){ struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); unsigned long flags; u32 val, mask; raw_spin_lock_irqsave(&pctl- >lock, flags); pin -= pctl- >desc- >pin_base; val = readl(pctl- >membase + sunxi_mux_reg(pin)); mask = mux_pins_mask < < sunxi_mux_offset(pin); writel((val & ~mask) | config < membase + sunxi_mux_reg(pin)); raw_spin_unlock_irqrestore(&pctl- >lock, flags);}无论有多复杂的代码,最终都需要通过读写寄存器的方式来实现控制芯片,而通过上述代码分析,即可发现 sunxi_pmx_set() 接口用于配置寄存器,是最底层的接口,可以通过打印输出传入的参数,来检查是否有问题。
pf3 打印输出为:
[ 10.683205] [lmx] irq:148 set int mode pin:163 d- >hwirq:131 func- >muxval:6pf4 打印输出为:
[ 10.683557] [lmx] irq:149 set int mode pin:196 d- >hwirq:132 func- >muxval:6这里就能看出很奇怪的地方,pf3 的引脚编号是 163,而 pf4 却是 196,跨度很大。
通过以下指令查询 pf4 的正确引脚编号,也可以得知 196 引脚编号是哪一组:
mercury-demo:/ # cat /sys/kernel/debug/pinctrl/pio/pinsregistered pins: 137......pin 160 (pf0)pin 161 (pf1)pin 162 (pf2)pin 163 (pf3)pin 164 (pf4)pin 165 (pf5)pin 166 (pf6)......pin 196 (pg4)pin 197 (pg5)......确认 pf4 正确引脚编号是 164,而 196 对应是 pg4,实际生效的是 pg4,通过以下指令即可确认:
mercury-demo:/sys/kernel/debug/sunxi_pinctrl # echo pg4 > sunxi_pinmercury-demo:/sys/kernel/debug/sunxi_pinctrl # cat *pin[pg4] data: 1piopin[pg4] dlevel: 1pin[pg4] funciton: 6nomatchpin[pg4] pull: 1pg4pin[pg4] funciton: 6pin[pg4] data: 1pin[pg4] dlevel: 1pin[pg4] pull: 1根据代码确定引脚编号来源于 pctl->irq_array 数组,通过 pctl->irq_array 赋值的地方进行打印输出,是否一开始就出错了:
// drivers/pinctrl/sunxi/pinctrl-sunxi.cstatic int sunxi_pinctrl_build_state(struct platform_device *pdev){ ...... /* count functions associated groups */ for (i = 0; i desc- >npins; i++) { const struct sunxi_desc_pin *pin = pctl- >desc- >pins + i; struct sunxi_desc_function *func = pin- >functions; while (func- >name) { /* create interrupt mapping while we're at it */ if (!strcmp(func- >name, irq)) { int irqnum = func- >irqnum + func- >irqbank * irq_per_bank; pctl- >irq_array[irqnum] = pin- >pin.number; printk(kern_emerg[lmx] pctl- >irq_array[%d] = %d (func- >irqnum:%d func- >irqbank:%d)n, irqnum, pin- >pin.number, func- >irqnum, func- >irqbank); } sunxi_pinctrl_add_function(pctl, func- >name); func++; } } ...... return 0;}// drivers/pinctrl/sunxi/pinctrl-sunxi.h#define irq_per_bank 32
可以发现,pf4(164)对应的索引是 132,原本被正确赋值为 164,但又被覆盖为 pg4(196)。
不难发现,出现覆盖的原因是因为 pg4 的 func->irqbank 数值错误(4),导致索引下标计算错误。
根据前后文来看,func->irqbank 的正确数值应该是 5,代入计算得到正确的值 164:
int irqnum(164) = func->irqnum(4) + func->irqbank(5) * irq_per_bank(32);
大概率硬件资源描述配置出错,通过搜索 irqbank 被赋值的方法,来定位描述配置出错的地方:
// drivers/pinctrl/sunxi/pinctrl-sunxi.h#define sunxi_function_irq_bank(_val, _bank, _irq) { .name = irq, .muxval = _val, .irqbank = _bank, .irqnum = _irq, }使用的是 sunxi_function_irq_bank 宏,重点检查第二个参数:
// drivers/pinctrl/sunxi/pinctrl-sun50iw9p1.cstatic const struct sunxi_desc_pin sun50iw9p1_pins[] = { ...... sunxi_pin(sunxi_pinctrl_pin(g, 3), sunxi_function(0x0, gpio_in), sunxi_function(0x1, gpio_out), sunxi_function(0x2, sdc1), /* d1 */ sunxi_function_irq_bank(0x6, 5, 3), /* pg_eint3 */ sunxi_function(0x7, io_disabled)), sunxi_pin(sunxi_pinctrl_pin(g, 4), sunxi_function(0x0, gpio_in), sunxi_function(0x1, gpio_out), sunxi_function(0x2, sdc1), /* d2 */ // 可以发现第二个参数恰好是 4,根据分析结果,以及结合上下文,正确的应该是 5 sunxi_function_irq_bank(0x6, 4, 4), /* pg_eint4 */ sunxi_function(0x7, io_disabled)), sunxi_pin(sunxi_pinctrl_pin(g, 5), sunxi_function(0x0, gpio_in), sunxi_function(0x1, gpio_out), sunxi_function(0x2, sdc1), /* d3 */ sunxi_function_irq_bank(0x6, 5, 5), /* pg_eint5 */ sunxi_function(0x7, io_disabled)), ......};修改之后的 pctl->irq_array 打印输出正确:
进行实测,pf4 已经可以正常的被设置为中断模式。
问题总结全志原厂提供的 socs pinctrl driver 中的 pg4 中断信息描述错误,导致覆盖了 pf4 的引脚编号,因此只要修正 pg4 的描述信息,即可解决问题。
这个问题不仅仅会影响 pf4 无法使用,也会影响 pg4 引脚无法使用,从代码来看,想要设置为 pg4 为中断模式,实际修改的会 pa0(0)。
--- a/longan/kernel/linux-4.9/drivers/pinctrl/sunxi/pinctrl-sun50iw9p1.c+++ b/longan/kernel/linux-4.9/drivers/pinctrl/sunxi/pinctrl-sun50iw9p1.c@@ -693,7 +693,7 @@ sunxi_function(0x0, gpio_in), sunxi_function(0x1, gpio_out), sunxi_function(0x2, sdc1), /* d2 */- sunxi_function_irq_bank(0x6, 4, 4), /* pg_eint4 */+ sunxi_function_irq_bank(0x6, 5, 4), /* pg_eint4 */ sunxi_function(0x7, io_disabled)), sunxi_pin(sunxi_pinctrl_pin(g, 5), sunxi_function(0x0, gpio_in),
宝胜股份牵手海康威视,以智能物联推进数字化升级
高压陶瓷电容器的特点及作用
IDT推出可编程低功耗计时器件
中芯国际三个月未经审核业绩公布
汽车半导体与智能驾驶盛会6月14召开
全志T507 PF4引脚无法被正常设置为中断模式的问题分析
工业PaaS是工业互联网平台的核心 工业PaaS平台的核心又是什么呢?
AR+航空工业的六大应用场景介绍
影响单相异步电机寿命的因素
情人节送男朋友什么礼物最好,情人节礼物指南
为何“深度学习”突然变得无处不在,它能做什么?不能做什么?
关于传感器融合的知识分析介绍
发动机动力不足可能的故障原因是什么?怎么排除?
基于人工智能的神经网络应用于莫斯科的医疗系统
乙醇燃料分层技术突破HCCI发动机的高负荷限制
索尼图像传感器业务押注中国市场,比亚迪入股深迪半导体
AMD嵌入式GPU为医疗成像领域提供解决方案
飞利浦电视I2C总线进入方式
华为自研SSD的历史变革
近期华为手机冰点价:华为P9、华为Mate8、华为荣耀8青春版、华为荣耀V8,值得购买