概述
最近在调试高通9563芯片的GPIO点灯,因为主控芯片GPIO口比较紧缺。所以就把9563出的wan口和lan口的灯交给了9880的GPIO口控制。
OpenWrt点灯套路
Linux内核集成LED模块,很方便就可以完成灯的控制,下面简单回顾下通常GPIO口点灯的几个步骤。
- 选中内核gpio点灯驱动,一般驱动名为leds-gpio(/sys/bus/platform/drivers/leds-gpio)。
- 如果是MIPS架构需要自己手动注册设备,信息自己携带在gpio_led_platform_data结构体中,同时可注册多个LED设备,最终呈现在sys fs文件系统下(/sys/devices/platform/leds-gpio/leds/LAN1:green:led)。
- 以上只是提供一个可操作的设备,具体怎么关联到系统当中,并且随着端口的link状态自动亮灭。这就需要结合LED模块提供的另外一个属性,LED触发模式。这个可以在注册设备时进行配置,也可在系统起来时进行脚本配置(root@mexon:/sys/devices/pci0000:00/0000:00:00.0/leds/LED0# cat trigger
none [switch0] timer default-on netdev usbport phy0rx phy0tx phy0assoc phy0radio phy0tpt phy1rx phy1tx phy1assoc phy1radio phy1tpt)。 - 例如在OpenWrt中,有自动化配置脚本控制LED设备,进行触发模式选择。在openwrt/target/linux/ar71xx/base-files/etc/board.d/01_leds中配置switch芯片出的端口link状态。
ucidef_set_led_switch “wan” “WAN” “LED3”(注册的led设备) “switch0”(触发器名称)“0x02”(端口掩码)
此处如果有多个LED设备,可持续配置。MPP6600) ucidef_set_led_switch "wan" "WAN" "LED3" "switch0" "0x02" ucidef_set_led_switch "lan1" "LAN1" "LED2" "switch0" "0x04" ucidef_set_led_switch "lan2" "LAN2" "LED1" "switch0" "0x08" ucidef_set_led_switch "lan3" "LAN3" "LED0" "switch0" "0x10" ucidef_set_led_timer "run" "RUN" "MPP6600:green:run" "1000" "1000" #ucidef_set_led_wlan "wlan2g" "WLAN 2.4 GHz" "MPP6600:green:2G" "phy1tpt"
9880控制8337端口的led灯
简单介绍
控制芯片为9563,通过GMAC接口连接高通的8337switch芯片,该芯片可配置单wan口或多wan口,其余均做lan口(软件通过swconfig进行vlan隔离即可)。由于9563上的GPIO口有限,9880又支持可配置的GPIO口。所以我们的8337link就采用9880GPIO口控制方式。
QCA9880驱动
采用开源 ath10k,内核选中即可。
这个地方选中Enable LED support是支持9880wifi状态灯的控制,这个灯是系统默认wifi状态点灯。并且ath10k驱动也仅仅支持这一个GPIO的控制,默认是9880上的GPIO1。接下来就是要在这里做手脚,进行代码改造。
QCA9880控灯驱动程序
-
ath10k在进行核心初始化时,会注册led设备。
ath10k_leds_register-默认注册一个wifi灯,此处进行扩展,扩展结构体如下:struct { struct gpio_led wifi_led; struct led_classdev cdev; char label[48]; u32 gpio_state_pin; } leds[10];
然后循环调用led_classdev_register注册函数,把所需要操作的所有GPIO口都以LED设备的方式注册进去。
-
9880GPIO口配置
使能对应的GPIO口以及配置GPIO口的方向。ath10k_wmi_gpio_config、ath10k_wmi_gpio_output。 -
需要关注下,对应的GPIO口是否被占用,有很多芯片GPIO口都是可复用的,芯片复位后有时会作其它功能(比如JTag)。
/* 使能GPIO口 */ for(i = 0; i < 5; ++ i) { ath10k_wmi_gpio_config(ar, ar->leds[i].wifi_led.gpio, 0, WMI_GPIO_PULL_NONE, WMI_GPIO_INTTYPE_DISABLE); ath10k_wmi_gpio_output(ar, ar->leds[i].wifi_led.gpio, 1); } /* 关掉GPIO口复用 */ if(ar->hif.ops != NULL && ar->hif.ops->read32 != NULL) { val = ar->hif.ops->read32(ar, GPIO_BASE_ADDRESS + 0xb0); val |= 1; if(ar->hif.ops->write32 != NULL) ar->hif.ops->write32(ar, GPIO_BASE_ADDRESS + 0xb0, val); } return 0;
-
在注册设备的时候,会同时传递一个回调函数,做LED灯亮度调整用的。在这个回调函数中,需要重新解析GPIO口,因为之前这个地方仅仅控制一个GPIO口,现在要操作多个GPIO口。这里可以通过设备名称获取GPIO口的端口号。
/* 只要是解析出当前的GPIO口号,然后去具体设置某个GPIO口 */ int i = 0; if(!strcmp(led_cdev->name, "LED0")) { i = 1; } else if(!strcmp(led_cdev->name, "LED1")) { i = 2; } else if(!strcmp(led_cdev->name, "LED2")) { i = 3; } else if(!strcmp(led_cdev->name, "LED3")) { i = 4; } else { i = 0; }
最后根据解析出来的端口号,可对GPIO的输出做控制。
struct ath10k *ar = container_of(led_cdev, struct ath10k,leds[i].cdev); struct gpio_led *led = &ar->leds[i].wifi_led; ar->leds[i].gpio_state_pin = (brightness != LED_OFF) ^ led->active_low; ath10k_wmi_gpio_output(ar, led->gpio, ar->leds[i].gpio_state_pin);
-
由于OpenWrt编译机制,不能直接修改build_dir下代码,否则clean之后修改部分会丢失。这里有两种方法,一是解压dl下backports大包,修改源码之后再压缩,然后修改 Makefile下的校验码即可,二是打补丁,网上有很多教程,而且方便快捷,无需修改源码。
回顾
该部分内容主要掌握Linux LED设备操作及结合OpenWrt脚本配置即可。其中涉及的知识比较多,但是还是比较浅显,需要自己去深入学习。