RK3399 系列 GPIO & pinctrl 控制(通过cat和echo命令对上述节点进行操作)

  • Post author:
  • Post category:其他


參考

[AndroidO] [RK3399] — GPIO驱动与控制方式_BestW2Y的博客-CSDN博客



可以通过cat和echo命令对上述节点进行操作, 操作对应函数为 类属性中的 show 和 store;

[AndroidO] [RK3399] — GPIO驱动与控制方式

本文总结基本的GPIO的驱动开发流程与GPIO口的控制方式

一.  设置DTS

将需要控制的GPIO口配置信息添加到DTS中, dts文件路径为: kernel/arch/arm64/boot/dts/rockchip/rk3399-tve1030g.dtsi

内容如下:

————————————————

gpio_hp: gpio_hp {


compatible = “rockchip,gpio_hp”;

status = “okay”;

bb-vb-gpio = <&gpio1 RK_PB1 GPIO_ACTIVE_HIGH>;//GPIO1_B1

bb-rst-gpio = <&gpio4 RK_PC5 GPIO_ACTIVE_LOW>;//GPIO4_C5

bb-pwr-gpio = <&gpio0 RK_PA2 GPIO_ACTIVE_LOW>;//GPIO0_A2

bb-ap-gpio = <&gpio1 RK_PD0 GPIO_ACTIVE_LOW>;//GPIO1_D0

switch0-gpio = <&gpio4 RK_PC1 GPIO_ACTIVE_LOW>;//GPIO4_C1

switch1-gpio = <&gpio4 RK_PC0 GPIO_ACTIVE_LOW>;//GPIO4_C0

switch2-gpio = <&gpio3 RK_PD7 GPIO_ACTIVE_HIGH>;//GPIO4_A6

switch3-gpio = <&gpio3 RK_PD6 GPIO_ACTIVE_HIGH>;//GPIO4_A7

switch4-gpio = <&gpio3 RK_PD5 GPIO_ACTIVE_HIGH>;//GPIO4_A3

short-gpio = <&gpio4 RK_PC6 GPIO_ACTIVE_HIGH>;//GPIO4_C6

open-gpio = <&gpio4 RK_PD0 GPIO_ACTIVE_HIGH>;//GPIO4_D0

relay-gpio = <&gpio3 RK_PD0 GPIO_ACTIVE_LOW>;//GPIO3_D0

/*

power5V0-gpio = <&gpio1 RK_PA1 GPIO_ACTIVE_HIGH>;//GPIO1_A1

power3V3-gpio = <&gpio1 RK_PA2 GPIO_ACTIVE_HIGH>;//GPIO1_A2

power1V2-gpio = <&gpio1 RK_PA3 GPIO_ACTIVE_HIGH>;//GPIO1_A3

power12V-gpio = <&gpio1 RK_PA4 GPIO_ACTIVE_HIGH>;//GPIO1_A4

*/

};

二.  编写GPIO驱动程序

GPIO驱动程序文件路径为: kernel/drivers/gpio/gpio-hoopluz.c

/*

*

* This program is free software; you can redistribute it and/or modify

* it under the terms of the GNU General Public License version 2 as

* published by the Free Software Foundation.

*/

#include <linux/module.h>

#include <linux/kernel.h>

#include <linux/init.h>

#include <linux/err.h>

#include <linux/gpio.h>

#include <linux/io.h>

#include <linux/of.h>

#include <linux/of_gpio.h>

#include <linux/interrupt.h>

#include <linux/platform_device.h>

#include <linux/delay.h>

#include <linux/delay.h>

struct hp_gpio_info {


unsigned bb_vb_gpio;

unsigned bb_rst_gpio;

unsigned bb_ap_ready_gpio;

unsigned bb_pwr_gpio;

unsigned switch_gpio[5];

unsigned open_gpio;

unsigned short_gpio;

unsigned relay_gpio;

int bb_pwr_active_value;

} hp_gpio;

static ssize_t gpio_switch_show(struct class *class,

struct class_attribute *attr,

char *buf)

{


return scnprintf(buf, PAGE_SIZE, “DIN0:%d.DIN1:%d.DIN2:%d.DIN3:%d.DIN4:%d.\n”,gpio_get_value(hp_gpio.switch_gpio[0]),

gpio_get_value(hp_gpio.switch_gpio[1]),

gpio_get_value(hp_gpio.switch_gpio[2]),

gpio_get_value(hp_gpio.switch_gpio[3]),

gpio_get_value(hp_gpio.switch_gpio[4]));

}

static ssize_t gpio_status_show(struct class *class,

struct class_attribute *attr,

char *buf)

{


return scnprintf(buf, PAGE_SIZE, “OpenDet:%d.ShortDet:%d.\n”,gpio_get_value(hp_gpio.open_gpio),

gpio_get_value(hp_gpio.short_gpio));

}

//modify by wangxiaolong for [relay gpio ctrl] start

static ssize_t relay_gpio_control_store(struct class* cls,

struct class_attribute *attr,

const char *buffer, size_t count)

{


unsigned int i;

int err;

err = kstrtouint(buffer, 10, &i);

if (err)

return err;

if (i == 0)

gpio_set_value(hp_gpio.relay_gpio, 0);

else

gpio_set_value(hp_gpio.relay_gpio, 1);

return count;

}

static ssize_t relay_gpio_control_show(struct class *class,

struct class_attribute *attr,

char *buf)

{


return scnprintf(buf, PAGE_SIZE, “relay gpio status :%s. \n”,gpio_get_value(hp_gpio.relay_gpio)?”ON”:”OFF”);

}

static struct class_attribute hp_class_attrs[] = {


__ATTR(gpio_switch, 0444, gpio_switch_show, NULL),

__ATTR(gpio_status, 0444, gpio_status_show, NULL),

__ATTR(Relay_ctrl, 0660,  relay_gpio_control_show, relay_gpio_control_store),

__ATTR_NULL,

};

static struct class hp_class = {


.name =         “hp”,

.owner =        THIS_MODULE,

.class_attrs =  hp_class_attrs,

};

static int hp_gpio_probe(struct platform_device *pdev)

{


int ret = 0;

int gpio;

int enable_value = 0;

enum of_gpio_flags flag;

struct hp_gpio_info *gpio_info;

struct device_node *hp_gpio_node = pdev->dev.of_node;

gpio_info = devm_kzalloc(&pdev->dev,sizeof(struct hp_gpio_info *), GFP_KERNEL);

if (!gpio_info) {


dev_err(&pdev->dev, “devm_kzalloc failed!\n”);

return -ENOMEM;

}

gpio = of_get_named_gpio_flags(hp_gpio_node, “bb-vb-gpio”, 0, &flag);

if (!gpio_is_valid(gpio)) {


dev_err(&pdev->dev, “hp-gpio: %d is invalid\n”, gpio);

return -ENODEV;

}

if (gpio_request(gpio, “bb-vb-gpio”)) {


dev_err(&pdev->dev, “bb-vb-gpio: %d request failed!\n”, gpio);

gpio_free(gpio);

return -ENODEV;

}

hp_gpio.bb_vb_gpio = gpio;

enable_value = (flag == OF_GPIO_ACTIVE_LOW) ? 0:1;

gpio_direction_output(gpio, enable_value);

printk(“bb_vb_gpio gpio output: %d\n”, enable_value);

ret = class_register(&hp_class);

if (ret < 0)

return ret;

//modify by wangxiaolong for [relay gpio ctrl] start

gpio = of_get_named_gpio_flags(hp_gpio_node, “relay-gpio”, 0, NULL);

if (!gpio_is_valid(gpio)) {


dev_err(&pdev->dev, “hp-gpio: %d is invalid\n”, gpio);

return -ENODEV;

}

if(gpio_request(gpio, “relay-gpio”)){


dev_err(&pdev->dev, “relay-gpio: %d request failed!\n”, gpio);

gpio_free(gpio);

return -ENODEV;

}

gpio_direction_output(gpio,0);

hp_gpio.relay_gpio = gpio;

//end

gpio = of_get_named_gpio_flags(hp_gpio_node, “switch0-gpio”, 0, NULL);

if (!gpio_is_valid(gpio)) {


dev_err(&pdev->dev, “hp-gpio: %d is invalid\n”, gpio);

return -ENODEV;

}

if (gpio_request(gpio, “switch0-gpio”)) {


dev_err(&pdev->dev, “gpio-switch: %d request failed!\n”, gpio);

gpio_free(gpio);

return -ENODEV;

}

gpio_direction_input(gpio);

hp_gpio.switch_gpio[0] = gpio;

gpio = of_get_named_gpio_flags(hp_gpio_node, “switch1-gpio”, 0, NULL);

if (!gpio_is_valid(gpio)) {


dev_err(&pdev->dev, “hp-gpio: %d is invalid\n”, gpio);

return -ENODEV;

}

if (gpio_request(gpio, “switch1-gpio”)) {


dev_err(&pdev->dev, “gpio-switch: %d request failed!\n”, gpio);

gpio_free(gpio);

return -ENODEV;

}

gpio_direction_input(gpio);

hp_gpio.switch_gpio[1] = gpio;

gpio = of_get_named_gpio_flags(hp_gpio_node, “switch2-gpio”, 0, NULL);

if (!gpio_is_valid(gpio)) {


dev_err(&pdev->dev, “hp-gpio: %d is invalid\n”, gpio);

return -ENODEV;

}

if (gpio_request(gpio, “switch2-gpio”)) {


dev_err(&pdev->dev, “gpio-switch: %d request failed!\n”, gpio);

gpio_free(gpio);

return -ENODEV;

}

gpio_direction_input(gpio);

hp_gpio.switch_gpio[2] = gpio;

gpio = of_get_named_gpio_flags(hp_gpio_node, “switch3-gpio”, 0, NULL);

if (!gpio_is_valid(gpio)) {


dev_err(&pdev->dev, “hp-gpio: %d is invalid\n”, gpio);

return -ENODEV;

}

if (gpio_request(gpio, “switch3-gpio”)) {


dev_err(&pdev->dev, “gpio-switch: %d request failed!\n”, gpio);

gpio_free(gpio);

return -ENODEV;

}

gpio_direction_input(gpio);

hp_gpio.switch_gpio[3] = gpio;

gpio = of_get_named_gpio_flags(hp_gpio_node, “switch4-gpio”, 0, NULL);

if (!gpio_is_valid(gpio)) {


dev_err(&pdev->dev, “hp-gpio: %d is invalid\n”, gpio);

return -ENODEV;

}

if (gpio_request(gpio, “switch4-gpio”)) {


dev_err(&pdev->dev, “gpio-switch: %d request failed!\n”, gpio);

gpio_free(gpio);

return -ENODEV;

}

gpio_direction_input(gpio);

hp_gpio.switch_gpio[4] = gpio;

gpio = of_get_named_gpio_flags(hp_gpio_node, “open-gpio”, 0, NULL);

if (!gpio_is_valid(gpio)) {


dev_err(&pdev->dev, “hp-gpio: %d is invalid\n”, gpio);

return -ENODEV;

}

if (gpio_request(gpio, “open-gpio”)) {


dev_err(&pdev->dev, “gpio-switch: %d request failed!\n”, gpio);

gpio_free(gpio);

return -ENODEV;

}

gpio_direction_input(gpio);

hp_gpio.open_gpio = gpio;

gpio = of_get_named_gpio_flags(hp_gpio_node, “short-gpio”, 0, NULL);

if (!gpio_is_valid(gpio)) {


dev_err(&pdev->dev, “hp-gpio: %d is invalid\n”, gpio);

return -ENODEV;

}

if (gpio_request(gpio, “short-gpio”)) {


dev_err(&pdev->dev, “gpio-switch: %d request failed!\n”, gpio);

gpio_free(gpio);

return -ENODEV;

}

gpio_direction_input(gpio);

hp_gpio.short_gpio = gpio;

gpio = of_get_named_gpio_flags(hp_gpio_node, “bb-ap-gpio”, 0, &flag);

if (!gpio_is_valid(gpio)) {


dev_err(&pdev->dev, “hp-gpio: %d is invalid\n”, gpio);

return -ENODEV;

}

if (gpio_request(gpio, “bb-ap-gpio”)) {


dev_err(&pdev->dev, “bb-vb-gpio: %d request failed!\n”, gpio);

gpio_free(gpio);

return -ENODEV;

}

hp_gpio.bb_ap_ready_gpio = gpio;

enable_value = (flag == OF_GPIO_ACTIVE_LOW) ? 0:1;

gpio_direction_output(gpio, enable_value);

printk(“bb_ap_ready_gpio gpio output: %d\n”, enable_value);

gpio = of_get_named_gpio_flags(hp_gpio_node, “bb-rst-gpio”, 0, &flag);

if (!gpio_is_valid(gpio)) {


dev_err(&pdev->dev, “hp-gpio: %d is invalid\n”, gpio);

return -ENODEV;

}

if (gpio_request(gpio, “bb-rst-gpio”)) {


dev_err(&pdev->dev, “bb-rst-gpio: %d request failed!\n”, gpio);

gpio_free(gpio);

return -ENODEV;

}

hp_gpio.bb_rst_gpio = gpio;

enable_value = (flag == OF_GPIO_ACTIVE_LOW) ? 0:1;

gpio_direction_output(gpio, enable_value);

printk(“bb_rst_gpio gpio output: %d\n”, enable_value);

gpio = of_get_named_gpio_flags(hp_gpio_node, “bb-pwr-gpio”, 0, &flag);

if (!gpio_is_valid(gpio)) {


dev_err(&pdev->dev, “bb-pwr-gpio: %d is invalid\n”, gpio);

return -ENODEV;

}

if (gpio_request(gpio, “bb-pwr-gpio”)) {


dev_err(&pdev->dev, “bb-pwr-gpio: %d request failed!\n”, gpio);

gpio_free(gpio);

return -ENODEV;

}

hp_gpio.bb_pwr_gpio = gpio;

enable_value = (flag == OF_GPIO_ACTIVE_LOW) ? 0:1;

hp_gpio.bb_pwr_active_value = enable_value;

gpio_direction_output(gpio, enable_value);

mdelay(50);

gpio_direction_output(gpio, !enable_value);

mdelay(200);

gpio_direction_output(gpio, enable_value);

return ret;

}

static struct of_device_id hp_match_table[] = {


{ .compatible = “rockchip,gpio_hp”,},

{},

};

static struct platform_driver hp_gpio_driver = {


.driver = {


.name = “gpio_hp”,

.owner = THIS_MODULE,

.of_match_table = hp_match_table,

},

.probe = hp_gpio_probe,

};

static int hp_gpio_init(void)

{


return platform_driver_register(&hp_gpio_driver);

}

module_init(hp_gpio_init);

static void hp_gpio_exit(void)

{


platform_driver_unregister(&hp_gpio_driver);

}

module_exit(hp_gpio_exit);

MODULE_DESCRIPTION(“Hoopluz GPIO support driver”);

MODULE_LICENSE(“GPL”);

——————————————————————–

知识点总结: (以 relay_gpio 为主)

1. 设备类 — struct class

通过调用class_register()函数,根据struct class hp_class 会生成 /sys/class/hp 节点;

2.  设备类属性 — struct class_attribute

__ATTR宏用来设置类属性数组的一项, 每一项都会在 /sys/class/hp节点下面再生成相应的节点, 在本例中:

a. /sys/class/hp/gpio_switch

b. /sys/class/hp/gpio_status

c. /sys/class/hp/Relay_ctrl

可以通过cat和echo命令对上述节点进行操作, 操作对应函数为 类属性中的 show 和 store;

3.  gpio_set_value() 与 gpio_direction_output()

一般只是在这个GPIO口的寄存器上写上某个值,至于这个端口是否设置为输出,它就管不了!而gpio_direction_output (port_num,0/1),

在某个GPIO口写上某个值之后,还会把这个端口设置为输出模式。 因此,有人也许就会建议,把gpio_set_value这个函数直接去掉不用,是否可以,显然是可以的。 但是为什么系统还要用呢, 我个人分析是, 系统开发人员在要结合这两者来使用,以便提高效率。 一般某个端口设置好了输入与输出模式后,最好不要经常变动。 首先要调用gpio_direction_output(),以后要设置高低电平时,直接使用gpio_set_value()就可以了,这样可以省却再次调用设置输出模式的操作,从而提高运行效率!

4.  platform_driver 与 platform_device的关系; platform_device 与 dts 的关系

三.  权限配置; 权限配置文件路径为: /device/rockchip/common/init.rk30board.rc

+    # alarm control

+    chown system system /sys/class/hp/Relay_ctrl

+    chmod 0666 /sys/class/hp/Relay_ctrl

至此, 驱动可以正常工作.


————————————————

版权声明:本文为CSDN博主「BestW2Y」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

原文链接:https://blog.csdn.net/u014674293/article/details/93109720