voidgpio_free(unsigned gpio);
intgpio_direction_input(unsigned gpio);
intgpio_direction_output(unsigned gpio, int value);
intgpio_set_debounce(unsigned gpio, unsigned debounce); intgpio_get_value_cansleep(unsigned gpio);
voidgpio_set_value_cansleep(unsigned gpio, int value);
intgpio_request_one(unsigned gpio, unsigned long flags, const char *label); intgpio_request_array(const struct gpio *array, size_t num); voidgpio_free_array(const struct gpio *array, size_t num);
intdevm_gpio_request(struct device *dev, unsigned gpio, const char *label); intdevm_gpio_request_one(struct device *dev, unsigned gpio, unsigned long flags,const char *label);
voiddevm_gpio_free(struct device *dev, unsigned int gpio);
注意,内核中针对内存、IRQ、时钟、GPIO、pinctrl都有devm_开头的API,使用这部分API的时候,内核会有类似于Java资源自动回收机制,因此在代码中做出错处理时,无需释放相关的资源。
对于GPIO而言,特别值得一提的是,内核会创建/sys结点 /sys/class/gpio/gpioN/,透过它我们可以echo值从而改变GPIO的方向、设置和获取GPIO的值。
在拥有Device Tree支持的情况之下,我们可以透过Device Tree来描述某GPIO控制器提供的GPIO引脚被具体设备使用的情况。在GPIO控制器对应的结点中,需定义#gpio-cells 和gpio-controller属性,具体的设备结点则透过xxx-gpios属性来引用GPIO控制器结点及GPIO引脚。
如VEXPRESS电路板 DT文件arch/arm/boot/dts/vexpress-v2m.dtsi中拥有如下GPIO控制器结点: 73 v2m_sysreg:sysreg@00000 {
74 compatible =\75 reg = <0x000000x1000>; 76 gpio-controller; 77 #gpio-cells =<2>; 78 };
VEXPRESS电路板上的MMC控制器会使用该结点GPIO控制器提供的GPIO引脚,则具体的mmci@05000设备结点的会通过-gpios属性引用GPIO: 111 mmci@05000 {
112 compatible =\113 reg =<0x05000 x>; 114 interrupts =<9 >;
115 cd-gpios = < vm sysreg >; 116 wp-gpios =< vm sysreg >; 117 … 121 };
其中的cd-gpios用于SD/MMC卡的detection,而wp-gpios用于写保护,MMC主机控制器驱动会透过如下方法获取这2个GPIO,详见于drivers/mmc/host/mmci.c:
1220static void mmci_dt_populate_generic_pdata(struct device_node *np, 1221 structmmci_platform_data *pdata) 1222{
1223 int bus_width = 0; 1224
1225 pdata- 7. pinctrl驱动 许多SoC内部都包含pin控制器,通过pin控制器的寄存器,我们可以配置一个或者一组引脚的功能和特性。在软件上,Linux内核的pinctrl驱动可以操作pin控制器为我们完成如下工作: § 枚举并且命名pin控制器可控制的所有引脚; § 提供引脚复用的能力; § 提供配置引脚的能力,如驱动能力、上拉下拉、开漏(open drain)等。 pinctrl和引脚 在特定SoC的pinctrl驱动中,我们需要定义引脚。假设有一个PGA封装的芯片的引脚排布如下: A B C D E F G H 8 o o o o o o o o 7 o o o o o o o o 6 o o o o o o o o 5 o o o o o o o o 4 o o o o o o o o 3 o o o o o o o o 2 o o o o o o o o 1 o o o o o o o o 在pinctrl驱动初始化的时候,需要向pinctrl子系统注册一个pinctrl_desc描述符,在该描述符中包含所有引脚的列表。可以通过如下代码来注册这个pin控制器并命名其所有引脚: 59#include 60 61const struct pinctrl_pin_descfoo_pins[] = { 62 PINCTRL_PIN(0, \63 PINCTRL_PIN(1, \64 PINCTRL_PIN(2, \ 65 ... 66 PINCTRL_PIN(61, \67 PINCTRL_PIN(62, \68 PINCTRL_PIN(63, \69}; 70 71static struct pinctrl_descfoo_desc = { 72 .name = \73 .pins = foo_pins, 74 .npins = ARRAY_SIZE(foo_pins), 75 .maxpin = 63, 76 .owner = THIS_MODULE, 77}; 78 79int __init foo_probe(void) 80{ 81 struct pinctrl_dev *pctl; 82 83 pctl = pinctrl_register(&foo_desc,, NULL); 84 if (IS_ERR(pctl)) 85 pr_err(\86} 引脚组(pin group) 在pinctrl子系统中,支持将一组引脚绑定为同一功能。假设{ 0, 8, 16, 24 }这一组引脚承担SPI的功能,而{ 24, 25 }这一组引脚承担I2C接口功能。在驱动的代码中,需要体现这个分组关系,并且为这些分组实现pinctrl_ops的成员函数get_groups_count、get_groups_count和get_groups_count,将pinctrl_ops填充到前文pinctrl_desc的实例foo_desc中。 130#include 131 132struct foo_group { 133 const char *name; 134 const unsigned int *pins; 135 const unsigned num_pins; 136}; 137 138static const unsigned int spi0_pins[] = { 0, 8, 16, 24 }; 139static const unsigned int i2c0_pins[] = { 24, 25 }; 140 141static const struct foo_group foo_groups[] = { 142 { 143 .name = \144 .pins = spi0_pins, 145 .num_pins =ARRAY_SIZE(spi0_pins), 146 }, 147 { 148 .name = \149 .pins = i2c0_pins, 150 .num_pins =ARRAY_SIZE(i2c0_pins), 151 }, 152}; 153 154 155static int foo_get_groups_count(struct pinctrl_dev *pctldev) 156{ 157 return ARRAY_SIZE(foo_groups); 158} 159 160static const char *foo_get_group_name(struct pinctrl_dev *pctldev, 161 unsigned selector) 162{ 163 return foo_groups[selector].name; 164} 165 166static int foo_get_group_pins(struct pinctrl_dev *pctldev, unsigned selector, 167 unsigned **const pins, 168 unsigned *const num_pins) 169{ 170 *pins = (unsigned *) foo_groups[selector].pins; 171 *num_pins =foo_groups[selector].num_pins; 172 return 0; 173} 174 175static struct pinctrl_opsfoo_pctrl_ops = { 176 .get_groups_count =foo_get_groups_count, 177 .get_group_name = foo_get_group_name, 178 .get_group_pins = foo_get_group_pins, 179}; 180 181 182static struct pinctrl_descfoo_desc = { 183 ... 184 .pctlops = &foo_pctrl_ops, 185}; get_groups_count()成员函数用于告知pinctrl子系统该SoC中合法的被选引脚组有多少个,而get_group_name()则提供引脚组的名字,get_group_pins()提供引脚组的引脚表。在设备驱动调用pinctrl通用API使能某一组引脚的对应功能时,pinctrl子系统的核心层会调用上述callback函数。 引脚配置 设备驱动有时候需要配置引脚,譬如可能把引脚设置为高阻或者三态(达到类似断连引脚的效果),或通过某阻值将引脚上拉/下拉以确保默认状态下引脚的电平状态。驱动中可以自定义相应板级引脚配置API的细节,譬如某设备驱动可能通过如下代码将某引脚上拉: #include ret= pin_config_set(\ 其中的PLATFORM_X_PULL_UP由特定的pinctrl驱动定义。在特定的pinctrl驱动中,需要实现完成这些配置所需要的callback函数(pinctrl_desc的confops成员函数): 222#include 223#include 224#include \225 226static int foo_pin_config_get(struct pinctrl_dev *pctldev, 227 unsigned offset, 228 unsigned long *config) 229{ 230 struct my_conftype conf; 231 232 ... Find setting for pin @ offset ... 233 234 *config = (unsigned long) conf; 235} 236 237static int foo_pin_config_set(struct pinctrl_dev *pctldev, 238 unsigned offset, 239 unsigned long config) 240{