Linux下如何使用X86 CPU的GPIO( 二 )


先阅读源码看看 , probe()执行过程中需要用到device的哪些resource , 只要我们能获取到这些resource , 自己手动构造一个device注册到platform bus不就行了 , O(∩_∩)O哈哈~ 。
int intel_pinctrl_probe(struct platform_device *pdev,const struct intel_pinctrl_soc_data *soc_data){......for (i = 0; i < pctrl->ncommunities; i++) {......res = platform_get_resource(pdev, IORESOURCE_MEM,community->barno);//0regs = devm_ioremap_resource(...... } ...... irq = platform_get_irq(pdev, 0);......}可以看到pin controller driver需要pincontrler 的地址空间和使用的中断号两部分资源 , 其中地址空间是三个 , 因为所有GPIO由三个GPIO控制器组成 , 三个GPIO控制器共享相同的中断线 , 三个GPIO控制器作为一个PCI设备 。 如何获取这两个信息呢?
4.手动构造device上面通过阅读源代码得知 ,intel-pinctrl 需要 pincontrler 地址空间、和使用的中断号两部分资源 。
地址空间起始地址可通过PCI 设备 P2SB Bridge (D31:F1) 获得 。 中断 vector 由 BIOS 配置 , 反编译 BIOS 给linux传递的 ACPI 信息 , 看是否有中断vector相关信息:
在板子上进入 /sys/firmware/acpi/tables, 将目录下所有文件考出 , 使用acpi工具 iasl 对DSDT文件进行反编译:
iasl -d DSDT.dat得到 AML 文件 DSDT.dsl ,里面包含 BIOS 开发的各设备节点信息 。
打开 DSDT.dsl 并找到pin controler设备节点描述 , 只需要搜索驱动里的"INT344B"或"INT345D"就能定位到 。 到这里我们也明白了 , 为什么驱动里的 spt_pinctrl_acpi_match[] 有两像 , 原来是一个代表标压处理器(H),一个代表低压处理器(U) 。
Device (GPI0){Method (_HID, 0, NotSerialized)// _HID: Hardware ID{If ((PCHV () == SPTH)){If ((PCHG == 0x02)){Return ("INT3451")}Return ("INT345D")//表示7代标压处理器}Return ("INT344B")//表示7代低压处理器Name (LINK, "\\_SB.PCI0.GPI0")Method (_CRS, 0, NotSerialized)// _CRS: Current Resource Settings{Name (RBUF, ResourceTemplate (){Memory32Fixed (ReadWrite,0x00000000,// Address Base0x00010000,// Address Length地址空间大小_Y2E)Memory32Fixed (ReadWrite,0x00000000,// Address Base0x00010000,// Address Length地址空间大小_Y2F)Memory32Fixed (ReadWrite,0x00000000,// Address Base0x00010000,// Address Length地址空间大小_Y31)Interrupt (ResourceConsumer, Level, ActiveLow, Shared, ,, _Y30){0x0000000E,//中断号}})CreateDWordField (RBUF, \_SB.PCI0.GPI0._CRS._Y2E._BAS, COM0)// _BAS: Base AddressCreateDWordField (RBUF, \_SB.PCI0.GPI0._CRS._Y2F._BAS, COM1)// _BAS: Base AddressCreateDWordField (RBUF, \_SB.PCI0.GPI0._CRS._Y30._INT, IRQN)// _INT: InterruptsCOM0 = (SBRG + 0x00AF0000)COM1 = (SBRG + 0x00AE0000)CreateDWordField (RBUF, \_SB.PCI0.GPI0._CRS._Y31._BAS, COM3)// _BAS: Base AddressCOM3 = (SBRG + 0x00AC0000)IRQN = SGIR /* \SGIR */Return (RBUF) /* \_SB_.PCI0.GPI0._CRS.RBUF */}你可能看不懂上面面的信息 , 到底哪个是标压哪个是低压?没关系 , 我们去pin controller driver中 , 里面有注释 , 反推一下就知道 INT345D 代表的是标压 ,INT344B 代表的是低压 。
/* Sunrisepoint-LP */static const struct pinctrl_pin_desc sptlp_pins[] = {....}static const struct intel_pinctrl_soc_data sptlp_soc_data = http://kandian.youth.cn/index/{ .pins = sptlp_pins,...}...../* Sunrisepoint-H */static const struct pinctrl_pin_desc spth_pins[] = {....}static const struct intel_pinctrl_soc_data spth_soc_data = { .pins = spth_pins,...}static const struct acpi_device_id spt_pinctrl_acpi_match[] = { {"INT344B", (kernel_ulong_t)回到正题 , 我们从 DSDT.dsl 获取得到中断号: 0xE , 三个地址空间起始地址及大小 。 构建一个platform_device 如下:
#include #include #include #include #include #define P2SB_PORTID_SHIFT 16#define P2SB_PORT_GPIO3 0xAC#define P2SB_PORT_GPIO2 0xAD /*未使用*/#define P2SB_PORT_GPIO1 0xAE#define P2SB_PORT_GPIO0 0xAF#define sbreg_addr 0xfd000000 /*Address Base*//*Community 0*/#define SPT_PINCTRL_COMMUNITY0_OFFSETsbreg_addr + (P2SB_PORT_GPIO0 << P2SB_PORTID_SHIFT)#define SPT_PINCTRL_COMMUNITY0_SIZE0x00010000/*Community 1*/#define SPT_PINCTRL_COMMUNITY1_OFFSETsbreg_addr + (P2SB_PORT_GPIO1 << P2SB_PORTID_SHIFT)#define SPT_PINCTRL_COMMUNITY1_SIZE0x00010000 /*Community 2*/#define SPT_PINCTRL_COMMUNITY2_OFFSETsbreg_addr + (P2SB_PORT_GPIO2 << P2SB_PORTID_SHIFT)#define SPT_PINCTRL_COMMUNITY2_SIZE0x00010000/*Community 3*/#define SPT_PINCTRL_COMMUNITY3_OFFSETsbreg_addr + (P2SB_PORT_GPIO3 << P2SB_PORTID_SHIFT)#define SPT_PINCTRL_COMMUNITY3_SIZE0x00010000static struct resource intel_pinctrl_dev_resources[] = { /* iomem resource */ DEFINE_RES_MEM_NAMED(SPT_PINCTRL_COMMUNITY0_OFFSET, SPT_PINCTRL_COMMUNITY0_SIZE, NULL), DEFINE_RES_MEM_NAMED(SPT_PINCTRL_COMMUNITY1_OFFSET, SPT_PINCTRL_COMMUNITY1_SIZE, NULL),// DEFINE_RES_MEM_NAMED(SPT_PINCTRL_COMMUNITY2_OFFSET, SPT_PINCTRL_COMMUNITY2_SIZE, NULL),/*未使用*/ DEFINE_RES_MEM_NAMED(SPT_PINCTRL_COMMUNITY3_OFFSET, SPT_PINCTRL_COMMUNITY3_SIZE, NULL), /* irq resource */ DEFINE_RES_IRQ(0x0E), /*反编译BIOS DSDT获取*/};static struct platform_device intel_pinctrl_device = { .name= "sunrisepoint-pinctrl", .id= -1, .resource = intel_pinctrl_dev_resources, .num_resources = ARRAY_SIZE(intel_pinctrl_dev_resources),};static int __init intel_spt_device_init(void){ return platform_device_register(}module_init(intel_spt_device_init);static void __exit intel_spt_device_exit(void){ platform_device_unregister(}module_exit(intel_spt_device_exit);MODULE_AUTHOR("wsg1100");MODULE_DESCRIPTION("Intelsunrisepoint pinctrl device");MODULE_LICENSE("GPL v2");