设备驱动程序:如何以编程方式访问实际的引脚/硬件?

时间:2012-12-08 21:01:37

标签: c linux-device-driver raspberry-pi gpio

如果您认为此问题的构造不正确,请参阅其原始版本。我被要求将这个问题简化为最小的形式。

如果我正在编写Linux设备驱动程序,如何以编程方式访问实际的GPIO引脚?例如:

// Turn a green LED on by sending the GPIO pins 0x11223344
int cmd = encode(Commands.TURN_GREEN_ON);
send_to_gpio_pins(cmd);

同样,如果这一点不清楚,那是因为我试图强迫社区规则保持简单,愚蠢。在这种情况下,请阅读我对这个问题的第一个版本。

1 个答案:

答案 0 :(得分:2)

Linux设备驱动程序应该可以访问arch的 gpio 模块提供的一组函数。由于我熟悉Atmel ARM代码并且不确定RPI使用的Broadcom SoC,因此这里有一些真正的 gpio 代码。

ARM SoC上的I / O设备通常是内存映射的(即没有单独的I / O地址空间)。这些物理地址可以映射到内核虚拟地址空间。 (外设寄存器的地址通常由各个设备驱动程序映射,供其专用。)
一旦映射到虚拟存储器,包含或控制GPIO引脚状态的寄存器就可以通过普通的读或写存储器操作进行访问(符合C语言要求)。有关这些器件寄存器中每个位的确切分配/功能,请参考Broadcom SoC hardware document

在将GPIO用作输入引脚或输出引脚之前,必须配置GPIO引脚。通常,引脚将具有多种用途(它是“多路复用的”),因此必须在早期板初始化期间选择其中一个特定功能。通过写入设备配置寄存器(映射到存储器位置)来执行这些分配。

Atmel函数用于写入GPIO引脚的值(来自arch/arm/mach-at91/gpio.c):

/*
 * assuming the pin is muxed as a gpio output, set its value.
 */
int at91_set_gpio_value(unsigned pin, int value)
{
        void __iomem    *pio = pin_to_controller(pin);
        unsigned        mask = pin_to_mask(pin);

        if (!pio)
                return -EINVAL;
        __raw_writel(mask, pio + (value ? PIO_SODR : PIO_CODR));
        return 0;
}
EXPORT_SYMBOL(at91_set_gpio_value);

用于读取GPIO引脚值的Atmel函数:

/*
 * read the pin's value (works even if it's not muxed as a gpio).
 */
int at91_get_gpio_value(unsigned pin)
{
        void __iomem    *pio = pin_to_controller(pin);
        unsigned        mask = pin_to_mask(pin);
        u32             pdsr;

        if (!pio)
                return -EINVAL;
        pdsr = __raw_readl(pio + PIO_PDSR);
        return (pdsr & mask) != 0;
}
EXPORT_SYMBOL(at91_get_gpio_value);

希望你可以在你使用的内核中找到类似的代码(例如 grep “{gpio”的System.map符号文件)。