平台:altera cycloneV
功能:设备树添加gpio,驱动设置gpio状态以及是否导出
设备树添加节点:
gpios {
compatible = "cyclone_gpio_export";
status = "okay";
/* input */
gpio44{
label = "1";
gpios = <&hps_0_gpio1_porta 15 0>;
default-direction = "in";
};
/* output */
gpio54{
label = "2";
gpios = <&hps_0_gpio1_porta 25 1>;
default-direction = "out";
};
};
驱动:
#include <linux/gpio.h>
#include <linux/err.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/of_gpio.h>
#include <linux/module.h>
struct gpio_user_data{
const char *label;
bool input;
unsigned int gpio;
unsigned int default_value;
};
struct gpio_info{
struct gpio_user_data *data;
int gpio_count;
};
static struct gpio_info *cyclone_gpio_info;
static void gpio_user_init_default(void)
{
int i,ret;
struct gpio_user_data *data;
data = cyclone_gpio_info->data;
for(i = 0;i < cyclone_gpio_info->gpio_count;i++) {
if(!gpio_is_valid(data[i].gpio)) {
continue;
}
ret = gpio_request(data[i].gpio,data[i].label);
if(ret < 0) {
continue;
}
if(data[i].input) {
gpio_direction_input(data[i].gpio);
}
else {
gpio_direction_output(data[i].gpio,data[i].default_value);
}
if(gpio_export(data[i].gpio, true))
printk("export gpio error\n");
}
}
int cyclone_gpio_export_probe(struct platform_device *pdev)
{
struct device_node *node = pdev->dev.of_node, *child;
int index = 0;
cyclone_gpio_info = kzalloc(sizeof(struct gpio_info), GFP_KERNEL);
if(!cyclone_gpio_info)
{
printk("alloc gpio info error!\n");
return -ENOMEM;
}
cyclone_gpio_info->gpio_count = of_get_child_count(node);
if(!cyclone_gpio_info->gpio_count)
{
printk("get none gpio!\n");
return -EIO;
}
printk("get %d gpios\n",cyclone_gpio_info->gpio_count);
cyclone_gpio_info->data = kzalloc(sizeof(struct gpio_user_data)*cyclone_gpio_info->gpio_count, GFP_KERNEL);
if(!cyclone_gpio_info->data)
{
printk("alloc gpio user data error!\n");
return -ENOMEM;
}
for_each_available_child_of_node(node,child){
const char *input;
struct gpio_user_data *data = &cyclone_gpio_info->data[index++];
data->label = of_get_property(child,"label",NULL) ? : child->name;
input = of_get_property(child,"default-direction",NULL) ? : "in";
if(strcmp(input,"in") == 0)
data->input = true;
data->gpio = of_get_gpio_flags(child,0,&data->default_value);
printk("gpio name = %s, direction = %d, num = %d\n",data->label,data->input,data->gpio);
}
gpio_user_init_default();
return 0;
}
static int cyclone_gpio_export_remove(struct platform_device *pdev)
{
kfree(cyclone_gpio_info->data);
kfree(cyclone_gpio_info);
return 0;
}
static struct of_device_id cyclone_gpio_export_match[] = {
{ .compatible = "cyclone_gpio_export", },
{},
};
static struct platform_driver cyclone_gpio_export_driver = {
.driver = {
.name = "cyclone_gpio",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(cyclone_gpio_export_match),
},
.probe = cyclone_gpio_export_probe,
.remove = cyclone_gpio_export_remove,
};
static int __init cyclone_gpio_export_init(void)
{
return platform_driver_register(&cyclone_gpio_export_driver);
}
static void __exit cyclone_gpio_export_exit(void)
{
platform_driver_unregister(&cyclone_gpio_export_driver);
}
MODULE_LICENSE("GPL");
module_init(cyclone_gpio_export_init);
module_exit(cyclone_gpio_export_exit);