公众号
欢迎扫码关注本人微信公众号:公众号上分享更多嵌入式知识和资料,分享个人学习嵌入式的心得体会。欢迎大家一起来玩呀。
/sys/xxx读写节点
在 /sys 中生成节点,用于应用层从驱动中获取数据,或者将数据写到驱动层中,比如点亮LED灯或者获取GPIO的值的高低电平。
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/of_gpio.h>
#include <linux/gpio.h>
#include <linux/platform_device.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <linux/delay.h>
#include <dt-bindings/gpio/gpio.h>
#ifdef CONFIG_OF
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_gpio.h>
#endif
struct taishan_gpio_dev{
struct platform_device *pdev;
int power_switch_gpio; //电源关断器控制IO
int power_switch_gpio_direction;
int out_switch_gpio; //输出短路器控制IO
int out_switch_gpio_direction;
int relays1_gpio; //继电器输出控制IO
int relays1_gpio_direction;
int relays2_gpio;
int relays2_gpio_direction;
int relays3_gpio;
int relays3_gpio_direction;
int relays4_gpio;
int relays4_gpio_direction;
int flame_sensor_gpio;
int smoke_sensor_gpio;
};
static struct taishan_gpio_dev *ptaishan_dev = NULL;
static ssize_t power_switch_gpio_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count) {
struct taishan_gpio_dev *pdata = ptaishan_dev;
if (buf[0] == '0') {
pdata->power_switch_gpio_direction = 0;
gpio_direction_output(pdata->power_switch_gpio, pdata->power_switch_gpio_direction);
}else if (buf[0] == '1') {
pdata->power_switch_gpio_direction = 1;
gpio_direction_output(pdata->power_switch_gpio, pdata->power_switch_gpio_direction);
}
printk(KERN_ERR "power_switch_gpio_store %d \n",pdata->power_switch_gpio_direction);
return count;
}
static ssize_t out_switch_gpio_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count) {
struct taishan_gpio_dev *pdata = ptaishan_dev;
if (buf[0] == '0') {
pdata->out_switch_gpio_direction = 0;
gpio_direction_output(pdata->out_switch_gpio, pdata->out_switch_gpio_direction);
}else if (buf[0] == '1') {
pdata->out_switch_gpio_direction = 1;
gpio_direction_output(pdata->out_switch_gpio, pdata->out_switch_gpio_direction);
}
printk(KERN_ERR "out_switch_gpio_store %d \n",pdata->out_switch_gpio_direction);
return count;
}
static ssize_t relays1_gpio_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count) {
struct taishan_gpio_dev *pdata = ptaishan_dev;
if (buf[0] == '0') {
pdata->relays1_gpio_direction = 0;
gpio_direction_output(pdata->relays1_gpio, pdata->relays1_gpio_direction);
}else if (buf[0] == '1') {
pdata->relays1_gpio_direction = 1;
gpio_direction_output(pdata->relays1_gpio, pdata->relays1_gpio_direction);
}
printk(KERN_ERR "relays1_gpio_store %d \n",pdata->relays1_gpio_direction);
return count;
}
static ssize_t relays2_gpio_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count) {
struct taishan_gpio_dev *pdata = ptaishan_dev;
if (buf[0] == '0') {
pdata->relays2_gpio_direction = 0;
gpio_direction_output(pdata->relays2_gpio, pdata->relays2_gpio_direction);
}else if (buf[0] == '1') {
pdata->relays2_gpio_direction = 1;
gpio_direction_output(pdata->relays2_gpio, pdata->relays2_gpio_direction);
}
printk(KERN_ERR "relays2_gpio_store %d \n",pdata->out_switch_gpio_direction);
return count;
}
static ssize_t relays3_gpio_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count) {
struct taishan_gpio_dev *pdata = ptaishan_dev;
if (buf[0] == '0') {
pdata->relays3_gpio_direction = 0;
gpio_direction_output(pdata->relays3_gpio, pdata->relays3_gpio_direction);
}else if (buf[0] == '1') {
pdata->relays3_gpio_direction = 1;
gpio_direction_output(pdata->relays3_gpio, pdata->relays3_gpio_direction);
}
printk(KERN_ERR "relays3_gpio_store %d \n",pdata->relays3_gpio_direction);
return count;
}
static ssize_t relays4_gpio_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count) {
struct taishan_gpio_dev *pdata = ptaishan_dev;
if (buf[0] == '0') {
pdata->relays4_gpio_direction = 0;
gpio_direction_output(pdata->relays4_gpio, pdata->relays4_gpio_direction);
}else if (buf[0] == '1') {
pdata->relays4_gpio_direction = 1;
gpio_direction_output(pdata->relays4_gpio, pdata->relays4_gpio_direction);
}
printk(KERN_ERR "relays4_gpio_store %d \n",pdata->relays4_gpio_direction);
return count;
}
static ssize_t flame_sensor_gpio_show(struct device *dev, struct device_attribute *attr, char *buf) {
struct taishan_gpio_dev *pdata = ptaishan_dev;
int gpio_value = 0;
gpio_value = gpio_get_value(pdata->flame_sensor_gpio);
return snprintf(buf, PAGE_SIZE, "%d\n",
gpio_value);
}
static ssize_t smoke_sensor_gpio_show(struct device *dev, struct device_attribute *attr, char *buf) {
struct taishan_gpio_dev *pdata = ptaishan_dev;
int gpio_value = 0;
gpio_value = gpio_get_value(pdata->smoke_sensor_gpio);
return snprintf(buf, PAGE_SIZE, "%d\n",
gpio_value);
}
static struct device_attribute taishan_gpio1_attr[] = {
__ATTR(power_switch_gpio, 0664, NULL, power_switch_gpio_store),
__ATTR(out_switch_gpio, 0664, NULL, out_switch_gpio_store),
__ATTR(relays1_gpio, 0664, NULL, relays1_gpio_store),
__ATTR(relays2_gpio, 0664, NULL, relays2_gpio_store),
__ATTR(relays3_gpio, 0664, NULL, relays3_gpio_store),
__ATTR(relays4_gpio, 0664, NULL, relays4_gpio_store),
__ATTR(flame_sensor_gpio, 0664, flame_sensor_gpio_show,NULL),
__ATTR(smoke_sensor_gpio, 0664, smoke_sensor_gpio_show,NULL),
};
static void taishan_gpio_init_sysfs(struct device *dev)
{
int i, ret;
for (i = 0; i < ARRAY_SIZE(taishan_gpio1_attr); i++) {
ret = sysfs_create_file(&dev->kobj,
&taishan_gpio1_attr[i].attr);
if (ret)
dev_err(dev, "create charger node(%s) error\n",
taishan_gpio1_attr[i].attr.name);
}
}
static int taishan_gpio_dt(struct taishan_gpio_dev *pdata) {
int gpio;
int ret;
enum of_gpio_flags flags;
struct device *dev = &pdata->pdev->dev;
struct device_node *node = dev->of_node;
gpio = of_get_named_gpio_flags(node, "power_switch_gpio", 0, &flags);
if (gpio_is_valid(gpio))
{
pdata->power_switch_gpio = gpio;
pdata->power_switch_gpio_direction = (flags == GPIO_ACTIVE_HIGH)? 1:0;
printk(KERN_ERR"power_switch_gpio: %d\n", pdata->power_switch_gpio);
ret = devm_gpio_request(dev,gpio, "power_switch_gpio");
if (ret) {
printk("Failed to get power_switch_gpio gpio.\n");
}
}
gpio = of_get_named_gpio_flags(node, "out_switch_gpio", 0, &flags);
if (gpio_is_valid(gpio))
{
pdata->out_switch_gpio = gpio;
pdata->out_switch_gpio_direction = (flags == GPIO_ACTIVE_HIGH)? 1:0;
printk(KERN_ERR"out_switch_gpio: %d\n", pdata->out_switch_gpio);
ret = devm_gpio_request(dev,gpio, "out_switch_gpio");
if (ret) {
printk("Failed to get out_switch_gpio gpio.\n");
}
}
gpio = of_get_named_gpio_flags(node, "relays1_gpio", 0, &flags);
if (gpio_is_valid(gpio))
{
pdata->relays1_gpio = gpio;
pdata->relays1_gpio_direction = (flags == GPIO_ACTIVE_HIGH)? 1:0;
printk(KERN_ERR"relays1_gpio: %d\n", pdata->relays1_gpio);
ret = devm_gpio_request(dev,gpio, "relays1_gpio");
if (ret) {
printk("Failed to get relays1_gpio gpio.\n");
}
}
gpio = of_get_named_gpio_flags(node, "relays2_gpio", 0, &flags);
if (gpio_is_valid(gpio))
{
pdata->relays2_gpio = gpio;
pdata->relays2_gpio_direction = (flags == GPIO_ACTIVE_HIGH)? 1:0;
printk(KERN_ERR"relays2_gpio: %d\n", pdata->relays2_gpio);
ret = devm_gpio_request(dev,gpio, "relays2_gpio");
if (ret) {
printk("Failed to get relays2_gpio gpio.\n");
}
}
gpio = of_get_named_gpio_flags(node, "relays3_gpio", 0, &flags);
if (gpio_is_valid(gpio))
{
pdata->relays3_gpio = gpio;
pdata->relays3_gpio_direction = (flags == GPIO_ACTIVE_HIGH)? 1:0;
printk(KERN_ERR"relays3_gpio: %d\n", pdata->relays3_gpio);
ret = devm_gpio_request(dev,gpio, "relays3_gpio");
if (ret) {
printk("Failed to get relays3_gpio gpio.\n");
}
}
gpio = of_get_named_gpio_flags(node, "relays4_gpio", 0, &flags);
if (gpio_is_valid(gpio))
{
pdata->relays4_gpio = gpio;
pdata->relays4_gpio_direction = (flags == GPIO_ACTIVE_HIGH)? 1:0;
printk(KERN_ERR"relays4_gpio: %d\n", pdata->relays4_gpio);
ret = devm_gpio_request(dev,gpio, "relays4_gpio");
if (ret) {
printk("Failed to get relays4_gpio gpio.\n");
}
}
gpio = of_get_named_gpio_flags(node, "flame_sensor_gpio", 0, &flags);
if (gpio_is_valid(gpio))
{
pdata->flame_sensor_gpio = gpio;
printk(KERN_ERR"flame_sensor_gpio: %d\n", pdata->flame_sensor_gpio);
ret = devm_gpio_request(dev,gpio, "flame_sensor_gpio");
if (ret) {
printk("Failed to get flame_sensor_gpio gpio.\n");
}
ret = gpio_direction_input(gpio);
if (ret) {
printk("Failed to set flame_sensor_gpio gpio.\n");
}
}
gpio = of_get_named_gpio_flags(node, "smoke_sensor_gpio", 0, &flags);
if (gpio_is_valid(gpio))
{
pdata->smoke_sensor_gpio = gpio;
printk(KERN_ERR"smoke_sensor_gpio: %d\n", pdata->smoke_sensor_gpio);
ret = devm_gpio_request(dev,gpio, "smoke_sensor_gpio");
if (ret) {
printk("Failed to get smoke_sensor_gpio gpio.\n");
}
ret = gpio_direction_input(gpio);
if (ret) {
printk("Failed to set flame_sensor_gpio gpio.\n");
}
}
return 0;
}
static void taishan_gpio_set_default(struct taishan_gpio_dev *pdata) {
if (pdata->power_switch_gpio) {
gpio_direction_output(pdata->power_switch_gpio, pdata->power_switch_gpio_direction);
}
if (pdata->out_switch_gpio) {
gpio_direction_output(pdata->out_switch_gpio, pdata->out_switch_gpio_direction);
}
if (pdata->relays1_gpio) {
gpio_direction_output(pdata->relays1_gpio, pdata->relays1_gpio_direction);
}
if (pdata->relays2_gpio) {
gpio_direction_output(pdata->relays2_gpio, pdata->relays2_gpio_direction);
}
if (pdata->relays3_gpio) {
gpio_direction_output(pdata->relays3_gpio, pdata->relays3_gpio_direction);
}
if (pdata->relays4_gpio) {
gpio_direction_output(pdata->relays4_gpio, pdata->relays4_gpio_direction);
}
}
static int taishan_gpio_probe(struct platform_device *pdev) {
printk(KERN_ALERT "%s \n",__func__);
ptaishan_dev = kmalloc(sizeof(struct taishan_gpio_dev), GFP_KERNEL);
if (ptaishan_dev == NULL) {
printk(KERN_ERR"kmalloc struct taishan_gpio_dev err \n");
return -ENOMEM;
}
memset(ptaishan_dev, 0, sizeof(struct taishan_gpio_dev));
ptaishan_dev->pdev = pdev;
taishan_gpio_dt(ptaishan_dev);
taishan_gpio_set_default(ptaishan_dev);
taishan_gpio_init_sysfs(&ptaishan_dev->pdev->dev);
printk(KERN_ALERT "%s end !!!!!\n",__func__);
return 0;
}
static struct of_device_id taishan_gpio_of_match[] = {
{ .compatible = "taishan_gpio" },
{ }
};
static struct platform_driver taishan_gpio_driver = {
.driver = {
.name = "taishan_gpio",
.of_match_table = of_match_ptr(taishan_gpio_of_match),
},
.probe = taishan_gpio_probe,
};
module_platform_driver(taishan_gpio_driver);
MODULE_AUTHOR("FenDa Ltd System Application Group");
MODULE_DESCRIPTION("taishan gpio driver");
MODULE_LICENSE("GPL");
应用层节点生成sys/xxxxx
在/sys/devices/platform/taishan-gpio 路径下可以看到会生成如下的节点:
power_switch_gpio
out_switch_gpio
relays1_gpio
relays2_gpio
relays3_gpio
relays4_gpio
flame_sensor_gpio
smoke_sensor_gpio
每一个节点代表一个GPIO引脚
rk3399:/sys/devices/platform/taishan-gpio # ls -la
total 0
drwxr-xr-x 3 root root 0 2013-01-18 08:50 .
drwxr-xr-x 142 root root 0 2013-01-18 08:50 ..
lrwxrwxrwx 1 root root 0 2021-10-26 06:57 driver -> ../../../bus/platform/drivers/taishan_gpio
-rw-r--r-- 1 root root 4096 2021-10-26 06:57 driver_override
-rw-rw-r-- 1 root root 4096 2021-10-26 06:57 flame_sensor_gpio
-r--r--r-- 1 root root 4096 2021-10-26 06:57 modalias
lrwxrwxrwx 1 root root 0 2021-10-26 06:57 of_node -> ../../../firmware/devicetree/base/taishan-gpio
-rw-rw-r-- 1 root root 4096 2021-10-26 06:57 out_switch_gpio
drwxr-xr-x 2 root root 0 2013-01-18 08:50 power
-rw-rw-r-- 1 root root 4096 2021-10-26 06:57 power_switch_gpio
-rw-rw-r-- 1 root root 4096 2021-10-26 06:57 relays1_gpio
-rw-rw-r-- 1 root root 4096 2021-10-26 06:57 relays2_gpio
-rw-rw-r-- 1 root root 4096 2021-10-26 06:57 relays3_gpio
-rw-rw-r-- 1 root root 4096 2021-10-26 06:57 relays4_gpio
-rw-rw-r-- 1 root root 4096 2021-10-26 06:57 smoke_sensor_gpio
lrwxrwxrwx 1 root root 0 2021-10-26 06:57 subsystem -> ../../../bus/platform
-rw-r--r-- 1 root root 4096 2013-01-18 08:50 uevent
应用层使用方法
使用cat命令 cat节点可以获取GPIO的值,下面的例子中获取到1,表示高电平
rk3399:/sys/devices/platform/taishan-gpio # cat smoke_sensor_gpio
1
使用echo命令给节点写入1,让relays1_gpio这个gpio输出高电平
rk3399:/sys/devices/platform/taishan-gpio # echo 1 > relays1_gpio