firmware/br-ext-chip-allwinner/board/v83x/kernel/patches/00000-drivers_gpio_gpio-sun...

762 lines
20 KiB
Diff

diff -drupN a/drivers/gpio/gpio-sunxi.c b/drivers/gpio/gpio-sunxi.c
--- a/drivers/gpio/gpio-sunxi.c 1970-01-01 03:00:00.000000000 +0300
+++ b/drivers/gpio/gpio-sunxi.c 2022-06-12 05:28:14.000000000 +0300
@@ -0,0 +1,757 @@
+/* driver/misc/sunxi-reg.c
+ *
+ * Copyright (C) 2011 Reuuimlla Technology Co.Ltd
+ * Charles <yanjianbo@allwinnertech.com>
+ *
+ * www.reuuimllatech.com
+ *
+ * User access to the registers driver.
+ *
+ * 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/kernel.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/rwsem.h>
+#include <linux/timer.h>
+#include <linux/module.h>
+#include <linux/gpio.h>
+#include <linux/ctype.h>
+#include <linux/err.h>
+#include <linux/ctype.h>
+#include <linux/sysfs.h>
+#include <linux/device.h>
+#include <linux/sunxi-gpio.h>
+#include <linux/io.h>
+#include <linux/of_gpio.h>
+#include <linux/device.h>
+#include "../base/base.h"
+
+#define PINS_PER_BANK 32
+DECLARE_RWSEM(gpio_sw_list_lock);
+LIST_HEAD(gpio_sw_list);
+static struct class *gpio_sw_class;
+static int network_led_data_suspend;
+
+struct sw_gpio_pd {
+ char name[16];
+ char link[16];
+ unsigned int light;
+};
+
+struct gpio_sw_classdev {
+ const char *name;
+ unsigned int pull, drv, cfg;
+ struct mutex class_mutex;
+ struct gpio_config *item;
+ int (*gpio_sw_cfg_set) (struct gpio_sw_classdev *gpio_sw_cdev,
+ int mul_cfg);
+ int (*gpio_sw_pull_set) (struct gpio_sw_classdev *gpio_sw_cdev,
+ int mul_cfg);
+ int (*gpio_sw_data_set) (struct gpio_sw_classdev *gpio_sw_cdev,
+ int mul_cfg);
+ int (*gpio_sw_drv_set) (struct gpio_sw_classdev *gpio_sw_cdev,
+ int mul_cfg);
+ int (*gpio_sw_cfg_get) (struct gpio_sw_classdev *gpio_sw_cdev);
+ int (*gpio_sw_pull_get) (struct gpio_sw_classdev *gpio_sw_cdev);
+ int (*gpio_sw_data_get) (struct gpio_sw_classdev *gpio_sw_cdev);
+ int (*gpio_sw_drv_get) (struct gpio_sw_classdev *gpio_sw_cdev);
+ struct device *dev;
+ struct list_head node;
+};
+
+struct sw_gpio {
+ struct sw_gpio_pd *pdata;
+ spinlock_t lock;
+ struct gpio_sw_classdev class;
+};
+
+static struct platform_device *gpio_sw_dev[256];
+static struct sw_gpio_pd *sw_pdata[256];
+struct device_node *node;
+static unsigned int easy_light_used;
+
+/*
+ * mul_cfg: 0 - inpit
+ * 1 - output
+*/
+static int gpio_sw_cfg_set(struct gpio_sw_classdev *gpio_sw_cdev, int mul_cfg)
+{
+ char pin_name[32];
+ unsigned long config;
+
+ if (mul_cfg == 0)
+ gpio_direction_input(gpio_sw_cdev->item->gpio);
+ else if (mul_cfg == 1)
+ gpio_direction_output(gpio_sw_cdev->item->gpio, 0);
+ else if (mul_cfg > 1 && mul_cfg <= 7) {
+ sunxi_gpio_to_name(gpio_sw_cdev->item->gpio, pin_name);
+ config = SUNXI_PINCFG_PACK(SUNXI_PINCFG_TYPE_FUNC, mul_cfg);
+ if (gpio_sw_cdev->item->gpio < SUNXI_PL_BASE)
+ pin_config_set(SUNXI_PINCTRL, pin_name, config);
+ else
+ pin_config_set(SUNXI_R_PINCTRL, pin_name, config);
+ }
+ gpio_sw_cdev->cfg = mul_cfg;
+ return 0;
+}
+
+static int gpio_sw_cfg_get(struct gpio_sw_classdev *gpio_sw_cdev)
+{
+ return 0;
+}
+
+static int gpio_sw_pull_set(struct gpio_sw_classdev *gpio_sw_cdev, int pull)
+{
+ char pin_name[32];
+ unsigned long config;
+
+ if (pull >= 0 && pull <= 3) {
+ sunxi_gpio_to_name(gpio_sw_cdev->item->gpio, pin_name);
+ config = SUNXI_PINCFG_PACK(SUNXI_PINCFG_TYPE_PUD, pull);
+ if (gpio_sw_cdev->item->gpio < SUNXI_PL_BASE)
+ pin_config_set(SUNXI_PINCTRL, pin_name, config);
+ else
+ pin_config_set(SUNXI_R_PINCTRL, pin_name, config);
+ }
+
+ gpio_sw_cdev->pull = pull;
+ return 0;
+}
+
+static int gpio_sw_pull_get(struct gpio_sw_classdev *gpio_sw_cdev)
+{
+
+ return 0;
+}
+
+static int gpio_sw_drv_set(struct gpio_sw_classdev *gpio_sw_cdev, int drv)
+{
+ char pin_name[32];
+ unsigned long config;
+
+ if (drv >= 0 && drv <= 3) {
+ sunxi_gpio_to_name(gpio_sw_cdev->item->gpio, pin_name);
+ config = SUNXI_PINCFG_PACK(SUNXI_PINCFG_TYPE_DRV, drv);
+ if (gpio_sw_cdev->item->gpio < SUNXI_PL_BASE)
+ pin_config_set(SUNXI_PINCTRL, pin_name, config);
+ else
+ pin_config_set(SUNXI_R_PINCTRL, pin_name, config);
+ }
+
+ gpio_sw_cdev->drv = drv;
+ return 0;
+}
+
+static int gpio_sw_drv_get(struct gpio_sw_classdev *gpio_sw_cdev)
+{
+
+ return 0;
+}
+
+static int gpio_sw_data_set(struct gpio_sw_classdev *gpio_sw_cdev, int data)
+{
+ __gpio_set_value(gpio_sw_cdev->item->gpio, data);
+ return 0;
+}
+
+static int gpio_sw_data_get(struct gpio_sw_classdev *gpio_sw_cdev)
+{
+ return __gpio_get_value(gpio_sw_cdev->item->gpio);
+}
+
+static ssize_t cfg_sel_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct gpio_sw_classdev *gpio_sw_cdev = dev_get_drvdata(dev);
+ int length;
+
+ mutex_lock(&gpio_sw_cdev->class_mutex);
+ gpio_sw_cdev->item->mul_sel =
+ gpio_sw_cdev->gpio_sw_drv_get(gpio_sw_cdev);
+ length = sprintf(buf, "%u\n", gpio_sw_cdev->cfg);
+ mutex_unlock(&gpio_sw_cdev->class_mutex);
+
+ return length;
+}
+
+static ssize_t pull_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct gpio_sw_classdev *gpio_sw_cdev = dev_get_drvdata(dev);
+ int length;
+
+ mutex_lock(&gpio_sw_cdev->class_mutex);
+ gpio_sw_cdev->item->pull = gpio_sw_cdev->gpio_sw_drv_get(gpio_sw_cdev);
+ length = sprintf(buf, "%u\n", gpio_sw_cdev->pull);
+ mutex_unlock(&gpio_sw_cdev->class_mutex);
+
+ return length;
+}
+
+static ssize_t drv_level_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct gpio_sw_classdev *gpio_sw_cdev = dev_get_drvdata(dev);
+ int length;
+
+ mutex_lock(&gpio_sw_cdev->class_mutex);
+ gpio_sw_cdev->item->drv_level =
+ gpio_sw_cdev->gpio_sw_drv_get(gpio_sw_cdev);
+ length = sprintf(buf, "%u\n", gpio_sw_cdev->drv);
+ mutex_unlock(&gpio_sw_cdev->class_mutex);
+
+ return length;
+}
+
+static ssize_t data_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct gpio_sw_classdev *gpio_sw_cdev = dev_get_drvdata(dev);
+ int length;
+
+ mutex_lock(&gpio_sw_cdev->class_mutex);
+ gpio_sw_cdev->item->data = gpio_sw_cdev->gpio_sw_data_get(gpio_sw_cdev);
+ length = sprintf(buf, "%u\n", gpio_sw_cdev->item->data);
+ mutex_unlock(&gpio_sw_cdev->class_mutex);
+
+ return length;
+}
+
+static ssize_t cfg_sel_store(struct device *dev,
+ struct device_attribute *attr, const char *buf,
+ size_t size)
+{
+ struct gpio_sw_classdev *gpio_sw_cdev = dev_get_drvdata(dev);
+ unsigned long cfg;
+
+ if (kstrtoul(buf, 10, &cfg))
+ return -EINVAL;
+ if (cfg > 7) {
+ return size;
+ }
+ gpio_sw_cdev->gpio_sw_cfg_set(gpio_sw_cdev, cfg);
+ return size;
+}
+
+static ssize_t pull_store(struct device *dev,
+ struct device_attribute *attr, const char *buf,
+ size_t size)
+{
+ struct gpio_sw_classdev *gpio_sw_cdev = dev_get_drvdata(dev);
+ unsigned long pull;
+
+ if (kstrtoul(buf, 10, &pull))
+ return -EINVAL;
+
+ if (pull > 3) {
+ return size;
+ }
+
+ gpio_sw_cdev->gpio_sw_pull_set(gpio_sw_cdev, pull);
+ return size;
+}
+
+static ssize_t drv_level_store(struct device *dev,
+ struct device_attribute *attr, const char *buf,
+ size_t size)
+{
+ struct gpio_sw_classdev *gpio_sw_cdev = dev_get_drvdata(dev);
+
+ unsigned long drv_level;
+ if (kstrtoul(buf, 10, &drv_level))
+ return -EINVAL;
+
+ if (drv_level > 3) {
+ return size;
+ }
+
+ gpio_sw_cdev->gpio_sw_drv_set(gpio_sw_cdev, drv_level);
+ return size;
+}
+
+static ssize_t data_store(struct device *dev,
+ struct device_attribute *attr, const char *buf,
+ size_t size)
+{
+ struct gpio_sw_classdev *gpio_sw_cdev = dev_get_drvdata(dev);
+ unsigned long data;
+
+ if (kstrtoul(buf, 10, &data))
+ return -EINVAL;
+
+ gpio_sw_cdev->gpio_sw_data_set(gpio_sw_cdev, data);
+ return size;
+}
+
+static ssize_t light_store(struct device *dev,
+ struct device_attribute *attr, const char *buf,
+ size_t size)
+{
+ struct gpio_sw_classdev *gpio_sw_cdev = dev_get_drvdata(dev);
+ struct sw_gpio_pd *pdata = dev->parent->platform_data;
+ unsigned long data;
+
+ if (kstrtoul(buf, 10, &data))
+ return -EINVAL;
+ if (data)
+ gpio_sw_cdev->gpio_sw_data_set(gpio_sw_cdev, pdata->light ? 1 : 0);
+ else
+ gpio_sw_cdev->gpio_sw_data_set(gpio_sw_cdev, pdata->light ? 0 : 1);
+
+ return size;
+}
+
+static int gpio_sw_suspend(struct device *dev, pm_message_t state)
+{
+ struct gpio_sw_classdev *gpio_sw_cdev = dev_get_drvdata(dev);
+ struct sw_gpio_pd *pdata = dev->parent->platform_data;
+
+ if (strcmp(pdata->link, "network_led") == 0) {
+ network_led_data_suspend = gpio_sw_cdev->gpio_sw_data_get(\
+ gpio_sw_cdev);
+ gpio_sw_cdev->gpio_sw_data_set(gpio_sw_cdev, \
+ pdata->light ? 0 : 1);
+ }
+ return 0;
+}
+
+static int gpio_sw_resume(struct device *dev)
+{
+ struct gpio_sw_classdev *gpio_sw_cdev = dev_get_drvdata(dev);
+ struct sw_gpio_pd *pdata = dev->parent->platform_data;
+
+ if (strcmp(pdata->link, "network_led") == 0) {
+ gpio_sw_cdev->gpio_sw_data_set(gpio_sw_cdev, network_led_data_suspend);
+ }
+ return 0;
+}
+
+static struct device_attribute gpio_sw_class_attrs[] = {
+ __ATTR(cfg, 0664, cfg_sel_show, cfg_sel_store),
+ __ATTR(pull, 0664, pull_show, pull_store),
+ __ATTR(drv, 0664, drv_level_show, drv_level_store),
+ __ATTR(data, 0664, data_show, data_store),
+ __ATTR_NULL,
+};
+
+static struct device_attribute easy_light_attr =
+ __ATTR(light, 0664, data_show, light_store);
+
+void gpio_sw_classdev_unregister(struct gpio_sw_classdev *gpio_sw_cdev)
+{
+ mutex_destroy(&gpio_sw_cdev->class_mutex);
+ device_unregister(gpio_sw_cdev->dev);
+ down_write(&gpio_sw_list_lock);
+ list_del(&gpio_sw_cdev->node);
+ up_write(&gpio_sw_list_lock);
+}
+
+static int gpio_sw_remove(struct platform_device *dev)
+{
+ struct sw_gpio *sw_gpio_entry = platform_get_drvdata(dev);
+ struct sw_gpio_pd *pdata = dev->dev.platform_data;
+
+ if (strlen(pdata->link) != 0)
+ sysfs_remove_link(&gpio_sw_class->p->subsys.kobj, pdata->link);
+
+ gpio_sw_classdev_unregister(&sw_gpio_entry->class);
+ kfree(sw_gpio_entry->class.item);
+ kfree(sw_gpio_entry);
+ return 0;
+}
+
+int
+gpio_sw_classdev_register(struct device *parent,
+ struct gpio_sw_classdev *gpio_sw_cdev)
+{
+ struct sw_gpio_pd *pdata = parent->platform_data;
+
+ gpio_sw_cdev->dev = device_create(gpio_sw_class, parent, 0,
+ gpio_sw_cdev, "%s",
+ gpio_sw_cdev->name);
+ if (IS_ERR(gpio_sw_cdev->dev))
+ return PTR_ERR(gpio_sw_cdev->dev);
+ if (easy_light_used && strlen(pdata->link)) {
+ if (sysfs_create_file(&gpio_sw_cdev->dev->kobj, &easy_light_attr.attr))
+ pr_err("gpio_sw: sysfs_create_file fail\n");
+ }
+ down_write(&gpio_sw_list_lock);
+ list_add_tail(&gpio_sw_cdev->node, &gpio_sw_list);
+ up_write(&gpio_sw_list_lock);
+ mutex_init(&gpio_sw_cdev->class_mutex);
+
+ return 0;
+}
+
+static int map_gpio_to_name(char *name, u32 gpio)
+{
+ char base;
+ int num;
+ num = gpio - SUNXI_PA_BASE;
+ if (num < 0)
+ goto map_fail;
+
+ if ((num >= 0) && (num < PINS_PER_BANK)) {
+ base = 'A';
+ goto map_done;
+ }
+ num = gpio - SUNXI_PB_BASE;
+ if ((num >= 0) && (num < PINS_PER_BANK)) {
+ base = 'B';
+ goto map_done;
+ }
+ num = gpio - SUNXI_PC_BASE;
+ if ((num >= 0) && (num < PINS_PER_BANK)) {
+ base = 'C';
+ goto map_done;
+ }
+ num = gpio - SUNXI_PD_BASE;
+ if ((num >= 0) && (num < PINS_PER_BANK)) {
+ base = 'D';
+ goto map_done;
+ }
+ num = gpio - SUNXI_PE_BASE;
+ if ((num >= 0) && (num < PINS_PER_BANK)) {
+ base = 'E';
+ goto map_done;
+ }
+ num = gpio - SUNXI_PF_BASE;
+ if ((num >= 0) && (num < PINS_PER_BANK)) {
+ base = 'F';
+ goto map_done;
+ }
+ num = gpio - SUNXI_PG_BASE;
+ if ((num >= 0) && (num < PINS_PER_BANK)) {
+ base = 'G';
+ goto map_done;
+ }
+ num = gpio - SUNXI_PH_BASE;
+ if ((num >= 0) && (num < PINS_PER_BANK)) {
+ base = 'H';
+ goto map_done;
+ }
+ num = gpio - SUNXI_PJ_BASE;
+ if ((num >= 0) && (num < PINS_PER_BANK)) {
+ base = 'J';
+ goto map_done;
+ }
+ num = gpio - SUNXI_PL_BASE;
+ if ((num >= 0) && (num < PINS_PER_BANK)) {
+ base = 'L';
+ goto map_done;
+ }
+ num = gpio - SUNXI_PM_BASE;
+ if ((num >= 0) && (num < PINS_PER_BANK)) {
+ base = 'M';
+ goto map_done;
+ }
+ num = gpio - AXP_PIN_BASE;
+ if ((num >= 0) && (num < PINS_PER_BANK)) {
+ base = 'X';
+ goto map_done;
+ }
+ goto map_fail;
+map_done:
+ sprintf(name, "P%c%d", base, num);
+ return 0;
+map_fail:
+ return -1;
+}
+
+static void gpio_sw_release(struct device *dev)
+{
+ pr_info("gpio_sw_release good !\n");
+}
+
+static int gpio_suspend(struct platform_device *dev, pm_message_t state)
+{
+ return 0;
+}
+
+static int gpio_resume(struct platform_device *dev)
+{
+ return 0;
+}
+
+static int gpio_sw_probe(struct platform_device *dev)
+{
+ struct sw_gpio *sw_gpio_entry;
+ struct sw_gpio_pd *pdata = dev->dev.platform_data;
+ int ret;
+ unsigned long flags;
+ char io_area[16];
+ int gpio;
+
+ sw_gpio_entry = kzalloc(sizeof(struct sw_gpio), GFP_KERNEL);
+ if (!sw_gpio_entry)
+ return -ENOMEM;
+
+ sw_gpio_entry->class.item =
+ kzalloc(sizeof(struct gpio_config), GFP_KERNEL);
+ if (!sw_gpio_entry->class.item) {
+ kfree(sw_gpio_entry);
+ return -ENOMEM;
+ }
+ /* pr_info("gpio_name: %s\n", pdata->name); */
+ gpio = of_get_named_gpio_flags(node, pdata->name, 0,
+ (enum of_gpio_flags *)sw_gpio_entry->
+ class.item);
+ if (!gpio_is_valid(gpio)) {
+ pr_err("get config err!\n");
+ kfree(sw_gpio_entry->class.item);
+ kfree(sw_gpio_entry);
+ return -ENOMEM;
+ }
+
+ /* init the */
+ sw_gpio_entry->class.cfg = (sw_gpio_entry->class.item)->mul_sel;
+ sw_gpio_entry->class.pull = (sw_gpio_entry->class.item)->pull;
+ sw_gpio_entry->class.drv = (sw_gpio_entry->class.item)->drv_level;
+
+ ret = map_gpio_to_name(io_area, sw_gpio_entry->class.item->gpio);
+ pr_info("gpio name is %s, ret = %d\n", io_area, ret);
+
+ platform_set_drvdata(dev, sw_gpio_entry);
+ spin_lock_init(&sw_gpio_entry->lock);
+ spin_lock_irqsave(&sw_gpio_entry->lock, flags);
+ sw_gpio_entry->pdata = pdata;
+
+ if (ret == 0)
+ sw_gpio_entry->class.name = io_area;
+ else
+ sw_gpio_entry->class.name = pdata->name;
+
+ sw_gpio_entry->class.gpio_sw_cfg_set = gpio_sw_cfg_set;
+ sw_gpio_entry->class.gpio_sw_cfg_get = gpio_sw_cfg_get;
+ sw_gpio_entry->class.gpio_sw_pull_set = gpio_sw_pull_set;
+ sw_gpio_entry->class.gpio_sw_pull_get = gpio_sw_pull_get;
+ sw_gpio_entry->class.gpio_sw_drv_set = gpio_sw_drv_set;
+ sw_gpio_entry->class.gpio_sw_drv_get = gpio_sw_drv_get;
+ sw_gpio_entry->class.gpio_sw_data_set = gpio_sw_data_set;
+ sw_gpio_entry->class.gpio_sw_data_get = gpio_sw_data_get;
+
+
+ /* init the gpio form sys_config */
+ gpio_sw_cfg_set(&sw_gpio_entry->class,
+ sw_gpio_entry->class.item->mul_sel);
+ gpio_sw_data_set(&sw_gpio_entry->class,
+ sw_gpio_entry->class.item->data);
+
+ spin_unlock_irqrestore(&sw_gpio_entry->lock, flags);
+
+ ret = gpio_sw_classdev_register(&dev->dev, &sw_gpio_entry->class);
+ if (ret < 0) {
+ dev_err(&dev->dev, "gpio_sw_classdev_register failed\n");
+ kfree(sw_gpio_entry->class.item);
+ kfree(sw_gpio_entry);
+ return -1;
+ }
+
+ /* create symbol link */
+ if (strlen(pdata->link) != 0) {
+ ret = sysfs_create_link(&gpio_sw_class->p->subsys.kobj,
+ &sw_gpio_entry->class.dev->kobj,
+ pdata->link);
+ }
+ return 0;
+}
+
+static struct platform_driver gpio_sw_driver = {
+ .probe = gpio_sw_probe,
+ .remove = gpio_sw_remove,
+ .suspend = gpio_suspend,
+ .resume = gpio_resume,
+ .driver = {
+ .name = "gpio_sw",
+ .owner = THIS_MODULE,
+ },
+};
+
+static void __exit gpio_sw_exit(void)
+{
+ int i, cnt;
+ struct gpio_config config;
+ int gpio;
+ char gpio_name[32];
+ int ret;
+
+ platform_driver_unregister(&gpio_sw_driver);
+
+ ret = of_property_read_u32(node, "gpio_num", &cnt);
+ if (ret || !cnt) {
+ pr_info("these is zero number for gpio\n");
+ goto EXIT_END;
+ }
+ for (i = 0; i < cnt; i++) {
+ sprintf(gpio_name, "gpio_pin_%d", i + 1);
+ gpio =
+ of_get_named_gpio_flags(node, gpio_name, 0,
+ (enum of_gpio_flags *)&config);
+ if (!gpio_is_valid(gpio)) {
+ pr_err("this gpio is invalid: %d\n", gpio);
+ continue;
+ }
+
+ platform_device_unregister(gpio_sw_dev[i]);
+ kfree(gpio_sw_dev[i]);
+ kfree(sw_pdata[i]);
+ gpio_free(gpio);
+ }
+
+ class_destroy(gpio_sw_class);
+EXIT_END:
+ pr_info("gpio_exit finish !\n");
+}
+
+static int sunxi_init_gpio_probe(struct platform_device *pdev)
+{
+ int i, cnt;
+ struct gpio_config config;
+ int gpio;
+ char gpio_name[32];
+ int ret;
+ const char *normal_led_pin_str = NULL;
+ const char *standby_led_pin_str = NULL;
+ const char *network_led_pin_str = NULL;
+
+ node = pdev->dev.of_node;
+ if (!node)
+ goto INIT_END;
+
+ /* create debug dir: /sys/class/gpio_sw */
+ gpio_sw_class = class_create(THIS_MODULE, "gpio_sw");
+ if (IS_ERR(gpio_sw_class))
+ return PTR_ERR(gpio_sw_class);
+
+ gpio_sw_class->suspend = gpio_sw_suspend;
+ gpio_sw_class->resume = gpio_sw_resume;
+ gpio_sw_class->class_attrs = (struct class_attribute *)gpio_sw_class_attrs;
+
+ if (of_property_read_u32(node, "easy_light_used", &easy_light_used)) {
+ easy_light_used = 0;
+ pr_err("failed to get easy_light_used assign\n");
+ }
+ if (of_property_read_string(node, "normal_led", &normal_led_pin_str))
+ pr_err("failed to get normal led pin assign\n");
+
+ if (of_property_read_string(node, "standby_led", &standby_led_pin_str))
+ pr_err("failed to get standby led pin assign\n");
+
+ if (of_property_read_string(node, "network_led", &network_led_pin_str))
+ pr_err("failed to get standby led pin assign\n");
+
+ ret = of_property_read_u32(node, "gpio_num", &cnt);
+ if (ret || !cnt) {
+ pr_err("these is zero number for gpio\n");
+ goto INIT_END;
+ }
+
+ for (i = 0; i < cnt; i++) {
+ sprintf(gpio_name, "gpio_pin_%d", i + 1);
+ gpio =
+ of_get_named_gpio_flags(node, gpio_name, 0,
+ (enum of_gpio_flags *)&config);
+ /*printk(KERN_EMERG"gpio = %d, mul = %d, drv= %d, pull= %d, data = %d\n",\
+ config.gpio, config.mul_sel, config.drv_level, config.pull, config.data);*/
+ if (gpio_request(gpio, NULL)) {
+ pr_err("gpio_pin_%d(%d) gpio_request fail\n", i + 1,
+ gpio);
+ continue;
+ }
+ pr_info("gpio_pin_%d(%d) gpio_is_valid\n", i + 1, config.gpio);
+
+ sw_pdata[i] = kzalloc(sizeof(struct sw_gpio_pd), GFP_KERNEL);
+ if (!sw_pdata[i]) {
+ pr_err("kzalloc fail for sw_pdata[%d]\n", i);
+ return -1;
+ }
+
+ gpio_sw_dev[i] =
+ kzalloc(sizeof(struct platform_device), GFP_KERNEL);
+ if (!gpio_sw_dev[i]) {
+ pr_err("kzalloc fail for gpio_sw_dev[%d]\n", i);
+ return -1;
+ }
+
+ sprintf(sw_pdata[i]->name, "gpio_pin_%d", i + 1);
+ if (normal_led_pin_str
+ && !strcmp(sw_pdata[i]->name, normal_led_pin_str)) {
+ sprintf(sw_pdata[i]->link, "%s", "normal_led");
+ if (easy_light_used)
+ of_property_read_u32(node, "normal_led_light", &sw_pdata[i]->light);
+ } else if (standby_led_pin_str
+ && !strcmp(sw_pdata[i]->name, standby_led_pin_str)) {
+ sprintf(sw_pdata[i]->link, "%s", "standby_led");
+ if (easy_light_used)
+ of_property_read_u32(node, "standby_led_light", &sw_pdata[i]->light);
+ } else if (network_led_pin_str
+ && !strcmp(sw_pdata[i]->name, network_led_pin_str)) {
+ sprintf(sw_pdata[i]->link, "%s", "network_led");
+ if (easy_light_used)
+ of_property_read_u32(node, "network_led_light", &sw_pdata[i]->light);
+ }
+
+ gpio_sw_dev[i]->name = "gpio_sw";
+ gpio_sw_dev[i]->id = i;
+ gpio_sw_dev[i]->dev.platform_data = sw_pdata[i];
+ gpio_sw_dev[i]->dev.release = gpio_sw_release;
+
+ if (platform_device_register(gpio_sw_dev[i])) {
+ pr_err("%s platform_device_register fail\n",
+ sw_pdata[i]->name);
+ goto INIT_ERR_FREE;
+ }
+ }
+ if (platform_driver_register(&gpio_sw_driver)) {
+ pr_err("gpio user platform_driver_register fail\n");
+ for (i = 0; i < cnt; i++)
+ platform_device_unregister(gpio_sw_dev[i]);
+ goto INIT_ERR_FREE;
+ }
+
+INIT_END:
+ pr_info("gpio_init finish with uesd\n");
+ return 0;
+INIT_ERR_FREE:
+ pr_err("gpio_init err\n");
+ kfree(sw_pdata[i]);
+ kfree(gpio_sw_dev[i]);
+ return -1;
+}
+
+static const struct of_device_id sunxi_gpio_of_match[] = {
+ {.compatible = "allwinner,sunxi-init-gpio", .data = NULL},
+ { /* sentinel */ }
+};
+
+static struct platform_driver sunxi_gpio_driver = {
+ .driver = {
+ .name = "sunxi-init-gpio",
+ .of_match_table = of_match_ptr(sunxi_gpio_of_match),
+ },
+ .probe = sunxi_init_gpio_probe,
+};
+
+static int __init sunxi_gpio_init(void)
+{
+ if (platform_driver_register(&sunxi_gpio_driver)) {
+ pr_err("gpio user platform_driver_register fail\n");
+ return -1;
+ }
+ return 0;
+}
+
+module_init(sunxi_gpio_init);
+module_exit(gpio_sw_exit);
+
+MODULE_AUTHOR("yanjianbo");
+MODULE_DESCRIPTION("SW GPIO USER driver");
+MODULE_LICENSE("GPL");