嵌入式Linux的GPIO中断

做个STM32开发的都知道,通过程序配置让普通的GPIO口具有中断功能。这样对于设备检测某些硬件的自动设备要方便的多。那么在嵌入式的Linux是否具有这样的功能呢?答案是肯定的,下面我们就来介绍一下如何配置嵌入式Linux的GPIO中断。

1.内核中配置GPIO中断
Linux内核的输入子系统是对分散的、多种不同类别的输入设备(如键盘、鼠标、跟踪球、操作杆、触摸屏、加速计和手写板)进行统一处理的驱动程序。输入子系统带来的好处:
a.统一了物理形态各异的相似的输入设备的处理功能。例如,各种鼠标,不论是PS/2、USB,还是蓝牙,都做同样的处理;
b.提供了用于分发输入报告给用户应用程序的简单的事件接口;
c.抽取出了输入驱动程序的通用部分,简化了驱动程序,并引入了一致性;
在内核中,按键的驱动已经完成!!!不需要我们自己写。driver/input/keyboard/gpio_keys.c 就是驱动文件。关于源码大家请下载Linux内核源码进行查看,下面介绍几个重点函数的实现。

1.1 gpio_keys_probe 函数
gpio_keys_probe函数在gpio_keys.c文件中,源码如下:

static int __devinit gpio_keys_probe(struct platform_device *pdev)
{
	struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
	struct gpio_keys_drvdata *ddata;
	struct device *dev = &pdev->dev;
	struct gpio_keys_platform_data alt_pdata;
	struct input_dev *input;
	int i, error;
	int wakeup = 0;

	if (!pdata) {
		error = gpio_keys_get_devtree_pdata(dev, &alt_pdata);
		if (error)
			return error;
		pdata = &alt_pdata;
	}
	
	 /*kzalloc 对kmalloc的封装,会清0分配的空间*/  
	ddata = kzalloc(sizeof(struct gpio_keys_drvdata) +
			pdata->nbuttons * sizeof(struct gpio_button_data),
			GFP_KERNEL);

	/*分配一个input设备*/  
	input = input_allocate_device();
	if (!ddata || !input) {
		dev_err(dev, "failed to allocate state\n");
		error = -ENOMEM;
		goto fail1;
	}

	ddata->input = input;
	ddata->n_buttons = pdata->nbuttons;
	ddata->enable = pdata->enable;
	ddata->disable = pdata->disable;
	mutex_init(&ddata->disable_lock);

	/* 设置input设备属性 */
	platform_set_drvdata(pdev, ddata);
	input_set_drvdata(input, ddata);

	input->name = pdata->name ? : pdev->name;
	input->phys = "gpio-keys/input0";
	input->dev.parent = &pdev->dev;
	input->open = gpio_keys_open;
	input->close = gpio_keys_close;

	input->id.bustype = BUS_HOST;
	input->id.vendor = 0x0001;
	input->id.product = 0x0001;
	input->id.version = 0x0100;

	/* 使能系统的自动清除中断标志位功能 */
	if (pdata->rep)
		__set_bit(EV_REP, in
``` /include/ "system-conf.dtsi" #include <dt-bindings/gpio/gpio.h> #include <dt-bindings/input/input.h> #include <dt-bindings/media/xilinx-vip.h> #include <dt-bindings/phy/phy.h> / { model = "Alientek Navigator Zynq Development Board"; compatible = "xlnx,zynq-zc702", "xlnx,zynq-7000"; leds { compatible = "gpio-leds"; gpio-led1 { label = "led2"; gpios = <&gpio0 0 GPIO_ACTIVE_HIGH>; default-state = "on"; }; gpio-led2 { label = "led1"; gpios = <&gpio0 54 GPIO_ACTIVE_HIGH>; linux,default-trigger = "heartbeat"; }; gpio-led3 { label = "pl_led0"; gpios = <&axi_gpio_0 0 0 GPIO_ACTIVE_HIGH>; default-state = "on"; }; gpio-led4 { label = "pl_led1"; gpios = <&axi_gpio_0 1 0 GPIO_ACTIVE_HIGH>; linux,default-trigger = "timer"; }; gpio-led5 { label = "ps_led0"; gpios = <&gpio0 7 GPIO_ACTIVE_HIGH>; default-state = "on"; }; gpio-led6 { label = "ps_led1"; gpios = <&gpio0 8 GPIO_ACTIVE_HIGH>; linux,default-trigger = "timer"; }; }; keys { compatible = "gpio-keys"; autorepeat; gpio-key1 { label = "pl_key0"; gpios = <&gpio0 55 GPIO_ACTIVE_LOW>; linux,code = <KEY_LEFT>; gpio-key,wakeup; autorepeat; }; gpio-key2 { label = "pl_key1"; gpios = <&gpio0 56 GPIO_ACTIVE_LOW>; linux,code = <KEY_RIGHT>; gpio-key,wakeup; autorepeat; }; gpio-key3 { label = "ps_key1"; gpios = <&gpio0 12 GPIO_ACTIVE_LOW>; linux,code = <KEY_UP>; gpio-key,wakeup; autorepeat; }; gpio-key4 { label = "ps_key2"; gpios = <&gpio0 11 GPIO_ACTIVE_LOW>; linux,code = <KEY_DOWN>; gpio-key,wakeup; autorepeat; }; touch-key { label = "touch_key"; gpios = <&gpio0 57 GPIO_ACTIVE_HIGH>; linux,code = <KEY_ENTER>; gpio-key,wakeup; autorepeat; }; }; beep { compatible = "gpio-beeper"; gpios = <&gpio0 58 GPIO_ACTIVE_HIGH>; }; usb_phy0: phy0@e0002000 { compatible = "ulpi-phy"; #phy-cells = <0>; reg = <0xe0002000 0x1000>; view-port = <0x0170>; drv-vbus; }; }; &uart0 { u-boot,dm-pre-reloc; status = "okay"; }; &sdhci0 { u-boot,dm-pre-reloc; status = "okay"; }; &usb0 { dr_mode = "otg"; usb-phy = <&usb_phy0>; }; &qspi { u-boot,dm-pre-reloc; flash@0 { /* 16 MB */ compatible = "w25q256", "jedec,spi-nor"; reg = <0x0>; spi-max-frequency = <50000000>; #address-cells = <1>; #size-cells = <1>; partition@0x00000000 { label = "boot"; reg = <0x00000000 0x00100000>; }; partition@0x00100000 { label = "bootenv"; reg = <0x00100000 0x00020000>; }; partition@0x00120000 { label = "bitstream"; reg = <0x00120000 0x00400000>; }; partition@0x00520000 { label = "device-tree"; reg = <0x00520000 0x00020000>; }; partition@0x00540000 { label = "kernel"; reg = <0x00540000 0x00500000>; }; partition@0x00A40000 { label = "space"; reg = <0x00A40000 0x00000000>; }; }; }; &gem0 { local-mac-address = [00 0a 35 00 8b 87]; phy-handle = <&ethernet_phy>; ethernet_phy: ethernet-phy@7 { /* yt8521 */ reg = <0x7>; device_type = "ethernet-phy"; }; }; &gem1 { local-mac-address = [00 0a 35 00 11 55]; phy-reset-gpio = <&gpio0 63 GPIO_ACTIVE_LOW>; phy-reset-active-low; phy-handle = <&pl_phy>; pl_phy: pl_phy@4 { reg = <0x4>; device_type = "ethernet-phy"; }; }; &watchdog0 { status = "okay"; reset-on-timeout; // Enable watchdog reset function }; &adc { status = "okay"; xlnx,channels { #address-cells = <1>; #size-cells = <0>; channel@0 { reg = <0>; }; }; }; &i2c0 { clock-frequency = <100000>; eeprom@50 { compatible = "atmel,24c64"; reg = <0x50>; pagesize = <32>; }; rtc@51 { compatible = "nxp,pcf8563"; reg = <0x51>; }; };```如何查看linux内核支持哪些驱动
03-14
<think>好的,我需要帮助用户了解如何查看Linux内核支持的驱动。首先,用户提供的代码片段看起来是一个设备树(Device Tree)文件,用于配置硬件设备。这可能内核驱动相关,所以需要结合设备树来分析。 用户的问题是“如何查看Linux内核支持哪些驱动”,我需要分步骤解释方法。首先想到的是内核配置,因为配置选项中包含了所有支持的驱动。通常通过make menuconfig或查看.config文件来查看已配置的驱动。另外,已编译的模块存放在/lib/modules目录下,可以用lsmod命令查看已加载的模块。 接下来,设备树中的compatible属性对应内核中的驱动匹配,可以查找源代码中的of_device_id结构体。用户提供的设备树里有很多compatible字段,比如gpio-leds、ulpi-phy等,这些可能对应内核中的具体驱动。 还需要提到内核文档,比如Documentation/devicetree/bindings/目录,这里会说明支持的驱动和绑定信息。另外,dmesg日志和/sys文件系统也能提供已加载驱动的信息。 可能需要解释用户提供的设备树中的部分内容,比如leds、keys、usb_phy等,说明它们是如何内核驱动关联的。例如,gpio-leds兼容的驱动会处理LED设备,而gpio-keys对应按键驱动。 需要注意用户可能对内核编译和配置不太熟悉,所以步骤要详细,但不过于技术化。最后,确保回答结构清晰,分点说明各种方法,并结合用户提供的代码示例,说明如何通过设备树查找对应驱动。</think>以下是查看Linux内核支持哪些驱动的分步说明: ### 一、通过内核配置查看驱动支持 1. **内核配置文件**: - 查看路径:`/boot/config-$(uname -r)` 或 `/proc/config.gz` - 使用命令: ```bash zcat /proc/config.gz | grep CONFIG_GPIO_LEDS ``` - 示例结果:`CONFIG_GPIO_LEDS=y` 表示GPIO LED驱动已内置 2. **菜单配置工具**: ```bash make menuconfig # 在内核源码目录执行 ``` - 导航路径:`Device Drivers -> GPIO Support -> LED Support` ### 二、通过系统运行时信息 1. **已加载模块**: ```bash lsmod | grep gpio ``` 示例输出: ``` gpio_led 16384 0 ``` 2. **设备树绑定关系**(对应您提供的代码): ```dts leds { compatible = "gpio-leds"; // 对应内核的drivers/leds/leds-gpio.c驱动 ``` ### 三、通过内核源码分析 1. **驱动匹配规则**: ```c // 内核源码中的驱动声明示例(drivers/leds/leds-gpio.c) static const struct of_device_id of_gpio_leds_match[] = { { .compatible = "gpio-leds", }, {}, }; ``` 2. **驱动文档**: 查看内核文档: ```bash less Documentation/devicetree/bindings/leds/leds-gpio.txt ``` ### 四、针对您提供的设备树分析 1. **LED驱动**: ```dts gpios = <&gpio0 0 GPIO_ACTIVE_HIGH>; // 使用GPIO控制器0的第0号引脚 ``` 对应驱动: - 通用GPIO LED:`drivers/leds/leds-gpio.c` - AXI GPIO:`drivers/gpio/gpio-xilinx.c` 2. **按键驱动**: ```dts compatible = "gpio-keys"; // 对应drivers/input/keyboard/gpio_keys.c ``` 3. **USB PHY驱动**: ```dts compatible = "ulpi-phy"; // 对应drivers/usb/phy/phy-ulpi.c ``` ### 五、实用工具 1. **设备树反编译**: ```bash dtc -I fs /sys/firmware/devicetree/base ``` 2. **sysfs接口查询**: ```bash ls /sys/bus/platform/drivers # 查看所有平台驱动 ``` ### 六、特殊驱动验证(以watchdog为例) ```dts &watchdog0 { status = "okay"; // 需要CONFIG_XILINX_WATCHDOG驱动支持 } ``` 验证命令: ```bash dmesg | grep watchdog ``` ### 总结方法: | 方法 | 适用场景 | 示例命令 | |-------------------|---------------------------|-----------------------------------| | 内核配置文件 | 查看编译时配置选项 | `grep CONFIG_DRIVER_NAME /boot/config-*` | | 设备树兼容属性 | 验证硬件驱动绑定关系 | `dmesg | grep "compatible"` | | sys文件系统 | 查看运行时设备信息 | `ls /sys/class/leds/` | | 内核文档 | 查询驱动绑定规范 | `find Documentation/ -name "*gpio*"` | 注:您提供的设备树中: - `w25q256` SPI Flash需要`CONFIG_MTD_SPI_NOR`驱动 - `pcf8563` RTC需要`CONFIG_RTC_DRV_PCF8563`驱动 - `atmel,24c64` EEPROM需要`CONFIG_EEPROM_AT24`驱动
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值