107 lines
2.9 KiB
C
107 lines
2.9 KiB
C
|
|
#include <linux/module.h>
|
||
|
|
#include <linux/err.h>
|
||
|
|
#include <linux/init.h>
|
||
|
|
#include <linux/io.h>
|
||
|
|
#include <linux/mfd/syscon.h>
|
||
|
|
#include <linux/of.h>
|
||
|
|
#include <linux/of_device.h>
|
||
|
|
#include <linux/of_address.h>
|
||
|
|
#include <linux/gpio/driver.h>
|
||
|
|
#include <linux/slab.h>
|
||
|
|
#include <linux/regmap.h>
|
||
|
|
|
||
|
|
static struct gpio_chip *g_gpio_virtual;
|
||
|
|
static int g_gpio_val = 0;
|
||
|
|
|
||
|
|
static int gpio_virtual_direction_output(struct gpio_chip *gc, unsigned offset, int val)
|
||
|
|
{
|
||
|
|
printk("set pin %d as output %s\r\n", offset, val ? "high" : "low");
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
static int gpio_virtual_direction_input(struct gpio_chip *gc, unsigned offset)
|
||
|
|
{
|
||
|
|
printk("set pin %d as input\r\n", offset);
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
static int gpio_virtual_get_value(struct gpio_chip *gc, unsigned offset)
|
||
|
|
{
|
||
|
|
int val = (g_gpio_val & (1 << offset)) ? 1 : 0;
|
||
|
|
printk("get pin %d value %d\r\n", offset, val);
|
||
|
|
return val;
|
||
|
|
}
|
||
|
|
|
||
|
|
static void gpio_virtual_set_value(struct gpio_chip *gc, unsigned offset, int val)
|
||
|
|
{
|
||
|
|
if (val) {
|
||
|
|
g_gpio_val |= (1 << offset);
|
||
|
|
} else {
|
||
|
|
g_gpio_val &= ~(1 << offset);
|
||
|
|
}
|
||
|
|
printk("set pin %d value %d\r\n", offset, val);
|
||
|
|
}
|
||
|
|
|
||
|
|
static int gpio_virtual_probe(struct platform_device *pdev)
|
||
|
|
{
|
||
|
|
int ret;
|
||
|
|
uint32_t val;
|
||
|
|
|
||
|
|
printk("%s %s %d\r\n", __FILE__, __FUNCTION__, __LINE__);
|
||
|
|
g_gpio_virtual = devm_kzalloc(&pdev->dev, sizeof(*g_gpio_virtual), GFP_KERNEL);
|
||
|
|
|
||
|
|
g_gpio_virtual->label = pdev->name;
|
||
|
|
g_gpio_virtual->direction_output = gpio_virtual_direction_output;
|
||
|
|
g_gpio_virtual->direction_input = gpio_virtual_direction_input;
|
||
|
|
g_gpio_virtual->get = gpio_virtual_get_value;
|
||
|
|
g_gpio_virtual->set = gpio_virtual_set_value;
|
||
|
|
|
||
|
|
g_gpio_virtual->parent = &pdev->dev;
|
||
|
|
g_gpio_virtual->owner = THIS_MODULE;
|
||
|
|
|
||
|
|
g_gpio_virtual->base = -1;
|
||
|
|
ret = of_property_read_u32(pdev->dev.of_node, "ngpios", &val);
|
||
|
|
g_gpio_virtual->ngpio = val;
|
||
|
|
|
||
|
|
ret = devm_gpiochip_add_data(&pdev->dev, g_gpio_virtual, NULL);
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
static int gpio_virtual_remove(struct platform_device *pdev)
|
||
|
|
{
|
||
|
|
printk("%s %s %d\r\n", __FILE__, __FUNCTION__, __LINE__);
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
static const struct of_device_id gpio_virtual_of_match[] = {
|
||
|
|
{ .compatible = "jzh,gpio-virtual", },
|
||
|
|
{ },
|
||
|
|
};
|
||
|
|
|
||
|
|
static struct platform_driver gpio_virtual_driver = {
|
||
|
|
.probe = gpio_virtual_probe,
|
||
|
|
.remove = gpio_virtual_remove,
|
||
|
|
.driver = {
|
||
|
|
.name = "gpio-virtual",
|
||
|
|
.of_match_table = of_match_ptr(gpio_virtual_of_match),
|
||
|
|
},
|
||
|
|
};
|
||
|
|
|
||
|
|
static int __init gpio_virtual_init(void)
|
||
|
|
{
|
||
|
|
printk("%s %s %d\r\n", __FILE__, __FUNCTION__, __LINE__);
|
||
|
|
return platform_driver_register(&gpio_virtual_driver);
|
||
|
|
}
|
||
|
|
|
||
|
|
static void __exit gpio_virtual_exit(void)
|
||
|
|
{
|
||
|
|
printk("%s %s %d\r\n", __FILE__, __FUNCTION__, __LINE__);
|
||
|
|
platform_driver_unregister(&gpio_virtual_driver);
|
||
|
|
}
|
||
|
|
|
||
|
|
module_init(gpio_virtual_init);
|
||
|
|
module_exit(gpio_virtual_exit);
|
||
|
|
MODULE_DESCRIPTION("Virtual GPIO Driver");
|
||
|
|
MODULE_AUTHOR("jzhgonha@163.com");
|
||
|
|
MODULE_LICENSE("GPL");
|