2 ******************************************************************************
3 * @file gpio-starfive-vic7110.c
4 * @author StarFive Technology
8 ******************************************************************************
11 * THE PRESENT SOFTWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
12 * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
13 * TIME. AS A RESULT, STARFIVE SHALL NOT BE HELD LIABLE FOR ANY
14 * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
15 * FROM THE CONTENT OF SUCH SOFTWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
16 * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
18 * COPYRIGHT 2020 Shanghai StarFive Technology Co., Ltd.
21 #include <linux/bitops.h>
22 #include <linux/device.h>
23 #include <linux/module.h>
24 #include <linux/errno.h>
25 #include <linux/of_irq.h>
26 #include <linux/gpio/driver.h>
27 #include <linux/interrupt.h>
28 #include <linux/irqchip/chained_irq.h>
29 #include <linux/init.h>
31 #include <linux/pinctrl/consumer.h>
32 #include <linux/platform_device.h>
34 #include <linux/slab.h>
35 #include <linux/proc_fs.h>
36 #include <linux/mutex.h>
37 #include <linux/uaccess.h>
38 #include <linux/spinlock.h>
41 #define GPIO_IS_LOW 0xe0
42 #define GPIO_IS_HIGH 0xe4
43 #define GPIO_IC_LOW 0xe8
44 #define GPIO_IC_HIGH 0xec
45 #define GPIO_IBE_LOW 0xf0
46 #define GPIO_IBE_HIGH 0xf4
47 #define GPIO_IEV_LOW 0xf8
48 #define GPIO_IEV_HIGH 0xfc
49 #define GPIO_IE_LOW 0x100
50 #define GPIO_IE_HIGH 0x104
53 #define GPIO_RIS_LOW 0x108
54 #define GPIO_RIS_HIGH 0x10c
55 #define GPIO_MIS_LOW 0x110
56 #define GPIO_MIS_HIGH 0x114
57 #define GPIO_DIN_LOW 0x118
58 #define GPIO_DIN_HIGH 0x11c
60 #define GPIO_DOEN_X_REG 0x0
61 #define GPIO_DOUT_X_REG 0x40
63 #define GPIO_INPUT_ENABLE_X_REG 0x120
67 #define PROC_VIC "vic_gpio7110"
69 struct sfvic7110_gpio {
73 unsigned long enabled;
74 unsigned trigger[MAX_GPIO];
75 unsigned int irq_parent[MAX_GPIO];
76 struct sfvic7110_gpio *self_ptr[MAX_GPIO];
79 /* lock for procfs read access */
80 static DEFINE_MUTEX(read_lock);
82 /* lock for procfs write access */
83 static DEFINE_MUTEX(write_lock);
85 static DEFINE_SPINLOCK(sfg_lock);
87 static void __iomem *gpio_base = NULL;
89 static int sfvic7110_direction_input(struct gpio_chip *gc, unsigned offset)
91 struct sfvic7110_gpio *chip = gpiochip_get_data(gc);
95 if (offset >= gc->ngpio)
98 raw_spin_lock_irqsave(&chip->lock, flags);
99 v = readl_relaxed(chip->base + GPIO_DOEN_X_REG + (offset & ~0x3));
100 v &= ~(0x3f << ((offset & 0x3) * 8));
101 v |= 1 << ((offset & 0x3) * 8);
102 writel_relaxed(v, chip->base + GPIO_DOEN_X_REG + (offset & ~0x3));
103 raw_spin_unlock_irqrestore(&chip->lock, flags);
108 static int sfvic7110_direction_output(struct gpio_chip *gc, unsigned offset, int value)
110 struct sfvic7110_gpio *chip = gpiochip_get_data(gc);
114 if (offset >= gc->ngpio)
117 raw_spin_lock_irqsave(&chip->lock, flags);
118 v = readl_relaxed(chip->base + GPIO_DOEN_X_REG + (offset & ~0x3));
119 v &= ~(0x3f << ((offset & 0x3) * 8));
120 writel_relaxed(v, chip->base + GPIO_DOEN_X_REG + (offset & ~0x3));
122 v = readl_relaxed(chip->base + GPIO_DOUT_X_REG + (offset & ~0x3));
123 v &= ~(0x7f << ((offset & 0x3) * 8));
124 v |= value << ((offset & 0x3) * 8);
125 writel_relaxed(v, chip->base + GPIO_DOUT_X_REG + (offset & ~0x3));
126 raw_spin_unlock_irqrestore(&chip->lock, flags);
131 static int sfvic7110_get_direction(struct gpio_chip *gc, unsigned offset)
133 struct sfvic7110_gpio *chip = gpiochip_get_data(gc);
136 if (offset >= gc->ngpio)
139 v = readl_relaxed(chip->base + GPIO_DOEN_X_REG + (offset & ~0x3));
140 return !!(v & (0x3f << ((offset & 0x3) * 8)));
143 static int sfvic7110_get_value(struct gpio_chip *gc, unsigned offset)
145 struct sfvic7110_gpio *chip = gpiochip_get_data(gc);
148 if (offset >= gc->ngpio)
152 value = readl_relaxed(chip->base + GPIO_DIN_LOW);
153 return (value >> offset) & 0x1;
155 value = readl_relaxed(chip->base + GPIO_DIN_HIGH);
156 return (value >> (offset - 32)) & 0x1;
160 static void sfvic7110_set_value(struct gpio_chip *gc, unsigned offset, int value)
162 struct sfvic7110_gpio *chip = gpiochip_get_data(gc);
166 if (offset >= gc->ngpio)
169 raw_spin_lock_irqsave(&chip->lock, flags);
170 v = readl_relaxed(chip->base + GPIO_DOUT_X_REG + (offset & ~0x3));
171 v &= ~(0x7f << ((offset & 0x3) * 8));
172 v |= value << ((offset & 0x3) * 8);
173 writel_relaxed(v, chip->base + GPIO_DOUT_X_REG + (offset & ~0x3));
174 raw_spin_unlock_irqrestore(&chip->lock, flags);
177 static void sfvic7110_set_ie(struct sfvic7110_gpio *chip, int offset)
180 int old_value, new_value;
181 int reg_offset, index;
190 raw_spin_lock_irqsave(&chip->lock, flags);
191 old_value = readl_relaxed(chip->base + GPIO_IE_LOW + reg_offset);
192 new_value = old_value | ( 1 << index);
193 writel_relaxed(new_value, chip->base + GPIO_IE_LOW + reg_offset);
194 raw_spin_unlock_irqrestore(&chip->lock, flags);
197 static int sfvic7110_irq_set_type(struct irq_data *d, unsigned trigger)
199 struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
200 struct sfvic7110_gpio *chip = gpiochip_get_data(gc);
201 int offset = irqd_to_hwirq(d);
202 unsigned int reg_is, reg_ibe, reg_iev;
203 int reg_offset, index;
205 if (offset < 0 || offset >= gc->ngpio)
216 case IRQ_TYPE_LEVEL_HIGH:
217 reg_is = readl_relaxed(chip->base + GPIO_IS_LOW + reg_offset);
218 reg_ibe = readl_relaxed(chip->base + GPIO_IBE_LOW + reg_offset);
219 reg_iev = readl_relaxed(chip->base + GPIO_IEV_LOW + reg_offset);
220 reg_is &= (~(0x1<< index));
221 reg_ibe &= (~(0x1<< index));
222 reg_iev |= (~(0x1<< index));
223 writel_relaxed(reg_is, chip->base + GPIO_IS_LOW + reg_offset);
224 writel_relaxed(reg_ibe, chip->base + GPIO_IBE_LOW + reg_offset);
225 writel_relaxed(reg_iev, chip->base + GPIO_IEV_LOW + reg_offset);
227 case IRQ_TYPE_LEVEL_LOW:
228 reg_is = readl_relaxed(chip->base + GPIO_IS_LOW + reg_offset);
229 reg_ibe = readl_relaxed(chip->base + GPIO_IBE_LOW + reg_offset);
230 reg_iev = readl_relaxed(chip->base + GPIO_IEV_LOW + reg_offset);
231 reg_is &= (~(0x1<< index));
232 reg_ibe &= (~(0x1<< index));
233 reg_iev &= (0x1<< index);
234 writel_relaxed(reg_is, chip->base + GPIO_IS_LOW + reg_offset);
235 writel_relaxed(reg_ibe, chip->base + GPIO_IBE_LOW + reg_offset);
236 writel_relaxed(reg_iev, chip->base + GPIO_IEV_LOW + reg_offset);
238 case IRQ_TYPE_EDGE_BOTH:
239 reg_is = readl_relaxed(chip->base + GPIO_IS_LOW + reg_offset);
240 reg_ibe = readl_relaxed(chip->base + GPIO_IBE_LOW + reg_offset);
241 reg_iev = readl_relaxed(chip->base + GPIO_IEV_LOW + reg_offset);
242 reg_is |= (0x1<< index);
243 reg_ibe |= (0x1<< index);
244 reg_iev |= (~(0x1<< index));
245 writel_relaxed(reg_is, chip->base + GPIO_IS_LOW + reg_offset);
246 writel_relaxed(reg_ibe, chip->base + GPIO_IBE_LOW + reg_offset);
247 writel_relaxed(reg_iev, chip->base + GPIO_IEV_LOW + reg_offset);
249 case IRQ_TYPE_EDGE_RISING:
250 reg_is = readl_relaxed(chip->base + GPIO_IS_LOW + reg_offset);
251 reg_ibe = readl_relaxed(chip->base + GPIO_IBE_LOW + reg_offset);
252 reg_iev = readl_relaxed(chip->base + GPIO_IEV_LOW + reg_offset);
253 reg_is |= (0x1<< index);
254 reg_ibe &= (~(0x1<< index));
255 reg_iev |= (0x1<< index);
256 writel_relaxed(reg_is, chip->base + GPIO_IS_LOW + reg_offset);
257 writel_relaxed(reg_ibe, chip->base + GPIO_IBE_LOW + reg_offset);
258 writel_relaxed(reg_iev, chip->base + GPIO_IEV_LOW + reg_offset);
260 case IRQ_TYPE_EDGE_FALLING:
261 reg_is = readl_relaxed(chip->base + GPIO_IS_LOW + reg_offset);
262 reg_ibe = readl_relaxed(chip->base + GPIO_IBE_LOW + reg_offset);
263 reg_iev = readl_relaxed(chip->base + GPIO_IEV_LOW + reg_offset);
264 reg_is |= (0x1<< index);
265 reg_ibe &= (~(0x1<< index));
266 reg_iev &= (~(0x1<< index));
267 writel_relaxed(reg_is, chip->base + GPIO_IS_LOW + reg_offset);
268 writel_relaxed(reg_ibe, chip->base + GPIO_IBE_LOW + reg_offset);
269 writel_relaxed(reg_iev, chip->base + GPIO_IEV_LOW + reg_offset);
273 chip->trigger[offset] = trigger;
274 sfvic7110_set_ie(chip, offset);
278 /* chained_irq_{enter,exit} already mask the parent */
279 static void sfvic7110_irq_mask(struct irq_data *d)
281 struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
282 struct sfvic7110_gpio *chip = gpiochip_get_data(gc);
284 int offset = irqd_to_hwirq(d);
285 int reg_offset, index;
287 if (offset < 0 || offset >= gc->ngpio)
298 value = readl_relaxed(chip->base + GPIO_IE_LOW + reg_offset);
299 value &= ~(0x1 << index);
300 writel_relaxed(value,chip->base + GPIO_IE_LOW + reg_offset);
303 static void sfvic7110_irq_unmask(struct irq_data *d)
305 struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
306 struct sfvic7110_gpio *chip = gpiochip_get_data(gc);
308 int offset = irqd_to_hwirq(d);
309 int reg_offset, index;
311 if (offset < 0 || offset >= gc->ngpio)
322 value = readl_relaxed(chip->base + GPIO_IE_LOW + reg_offset);
323 value |= (0x1 << index);
324 writel_relaxed(value,chip->base + GPIO_IE_LOW + reg_offset);
327 static void sfvic7110_irq_enable(struct irq_data *d)
329 struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
330 struct sfvic7110_gpio *chip = gpiochip_get_data(gc);
331 int offset = irqd_to_hwirq(d);
333 sfvic7110_irq_unmask(d);
334 assign_bit(offset, &chip->enabled, 1);
337 static void sfvic7110_irq_disable(struct irq_data *d)
339 struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
340 struct sfvic7110_gpio *chip = gpiochip_get_data(gc);
341 int offset = irqd_to_hwirq(d) % MAX_GPIO; // must not fail
343 assign_bit(offset, &chip->enabled, 0);
344 sfvic7110_set_ie(chip, offset);
347 static struct irq_chip sfvic7110_irqchip = {
348 .name = "sfvic7110-gpio",
349 .irq_set_type = sfvic7110_irq_set_type,
350 .irq_mask = sfvic7110_irq_mask,
351 .irq_unmask = sfvic7110_irq_unmask,
352 .irq_enable = sfvic7110_irq_enable,
353 .irq_disable = sfvic7110_irq_disable,
356 static irqreturn_t sfvic7110_irq_handler(int irq, void *gc)
359 // = self_ptr - &chip->self_ptr[0];
360 int reg_offset, index;
363 struct sfvic7110_gpio *chip = gc;
365 for (offset = 0; offset < 64; offset++) {
374 raw_spin_lock_irqsave(&chip->lock, flags);
375 value = readl_relaxed(chip->base + GPIO_MIS_LOW + reg_offset);
376 if(value & BIT(index))
377 writel_relaxed(BIT(index), chip->base + GPIO_IC_LOW +
380 //generic_handle_irq(irq_find_mapping(chip->gc.irq.domain,
382 raw_spin_unlock_irqrestore(&chip->lock, flags);
388 void sf_vic_gpio_dout_reverse(int gpio,int en)
396 offset = GPIO_DOUT_X_REG + (gpio & ~0x3);
398 spin_lock(&sfg_lock);
399 value = ioread32(gpio_base + offset);
400 value &= ~(0x7f << ((offset & 0x3) * 8));
401 value |= (en & 0x1) << ((offset & 0x3) * 8);
402 iowrite32(value, gpio_base + offset);
403 spin_unlock(&sfg_lock);
405 EXPORT_SYMBOL_GPL(sf_vic_gpio_dout_reverse);
407 void sf_vic_gpio_dout_value(int gpio,int v)
415 offset = GPIO_DOUT_X_REG + (gpio & ~0x3);
417 spin_lock(&sfg_lock);
418 value = ioread32(gpio_base + offset);
419 value &= ~(0x7f << ((offset & 0x3) * 8));
420 value |= (v & 0x7f) << ((offset & 0x3) * 8);
421 iowrite32(value,gpio_base + offset);
422 spin_unlock(&sfg_lock);
424 EXPORT_SYMBOL_GPL(sf_vic_gpio_dout_value);
426 void sf_vic_gpio_dout_low(int gpio)
428 sf_vic_gpio_dout_value(gpio, 0);
430 EXPORT_SYMBOL_GPL(sf_vic_gpio_dout_low);
432 void sf_vic_gpio_dout_high(int gpio)
434 sf_vic_gpio_dout_value(gpio, 1);
436 EXPORT_SYMBOL_GPL(sf_vic_gpio_dout_high);
438 void sf_vic_gpio_doen_reverse(int gpio,int en)
446 offset = GPIO_DOEN_X_REG + (gpio & ~0x3);
448 spin_lock(&sfg_lock);
449 value = ioread32(gpio_base + offset);
450 value &= ~(0x3f << ((offset & 0x3) * 8));
451 value |= (en & 0x1) << ((offset & 0x3) * 8);
452 iowrite32(value,gpio_base + offset);
453 spin_unlock(&sfg_lock);
455 EXPORT_SYMBOL_GPL(sf_vic_gpio_doen_reverse);
457 void sf_vic_gpio_doen_value(int gpio,int v)
465 offset = GPIO_DOEN_X_REG + (gpio & ~0x3);
467 spin_lock(&sfg_lock);
468 value = ioread32(gpio_base + offset);
469 value &= ~(0x3f << ((offset & 0x3) * 8));
470 value |= (v & 0x3f) << ((offset & 0x3) * 8);
471 iowrite32(value,gpio_base + offset);
472 spin_unlock(&sfg_lock);
474 EXPORT_SYMBOL_GPL(sf_vic_gpio_doen_value);
476 void sf_vic_gpio_doen_low(int gpio)
478 sf_vic_gpio_doen_value(gpio, 0);
480 EXPORT_SYMBOL_GPL(sf_vic_gpio_doen_low);
482 void sf_vic_gpio_doen_high(int gpio)
484 sf_vic_gpio_doen_value(gpio, 1);
486 EXPORT_SYMBOL_GPL(sf_vic_gpio_doen_high);
488 void sf_vic_gpio_manual(int offset,int v)
495 spin_lock(&sfg_lock);
496 value = ioread32(gpio_base + offset);
499 iowrite32(value,gpio_base + offset);
500 spin_unlock(&sfg_lock);
502 EXPORT_SYMBOL_GPL(sf_vic_gpio_manual);
504 static int str_to_num(char *str)
509 if((*p == '0') && (*(p + 1) == 'x' || *(p + 1) == 'X')) {
511 while(((*p >= '0') && (*p <= '9')) ||
512 ((*p >= 'a') && (*p <= 'f')) ||
513 ((*p >= 'A') && (*p <= 'F'))) {
514 if((*p >= '0') && (*p <= '9'))
515 value = value * 16 + (*p - '0');
516 if((*p >= 'a') && (*p <= 'f'))
517 value = value * 16 + 10 + (*p - 'a');
518 if((*p >= 'A') && (*p <= 'F'))
519 value = value * 16 + 10 + (*p - 'A');
523 while((*p >= '0') && (*p <= '9')) {
524 value = value * 10 + (*p - '0');
535 static ssize_t vic_gpio_proc_write(struct file *file, const char __user *buf,
536 size_t count, loff_t *ppos)
539 char message[64], cmd[8],gnum[8],v[8];
542 if (mutex_lock_interruptible(&write_lock))
545 ret = copy_from_user(message, buf, count);
546 mutex_unlock(&write_lock);
549 sscanf(message, "%s %s %s", cmd, gnum, v);
550 gpionum = str_to_num(gnum);
553 value = str_to_num(v);
557 if(!strcmp(cmd,"dout")) {
558 if(gpionum < 0 || gpionum > 63){
559 printk(KERN_ERR "vic-gpio: dout gpionum (0-63) value (0/1) invalid: gpionum = %d value = %d\n",
563 sf_vic_gpio_dout_value(gpionum, value);
564 }else if(!strcmp(cmd,"doen")) {
565 if(gpionum < 0 || gpionum > 63){
566 printk(KERN_ERR "vic-gpio: doen gpionum (0-63) value (0/1) invalid: gpionum = %d value = %d\n",
570 sf_vic_gpio_doen_value(gpionum,value);
571 }else if(!strcmp(cmd,"utrv")) {
572 if(gpionum < 0 || gpionum > 63){
573 printk(KERN_ERR "vic-gpio: utrv gpionum (0-63) is invalid: %d\n",gpionum);
576 sf_vic_gpio_doen_reverse(gpionum,value);
577 }else if(!strcmp(cmd,"enrv")) {
578 if(gpionum < 0 || gpionum > 63){
579 printk(KERN_ERR "vic-gpio: enrv gpionum (0-63) is invalid: %d\n",gpionum);
582 sf_vic_gpio_doen_reverse(gpionum, value);
583 }else if(!strcmp(cmd,"manu")) {
584 if(gpionum < 0x250 || gpionum > 0x378 || (gpionum & 0x3)){
585 printk(KERN_ERR "vic-gpio: manu offset (0x250-0x378 & mod 4) is invalid: %d\n",gpionum);
588 sf_vic_gpio_manual(gpionum, value);
590 printk(KERN_ERR "vic-gpio: cmd (dout doen utrv enrv manu) invalid: %s\n",cmd);
596 static ssize_t vic_gpio_proc_read(struct file *file, char __user *buf,
597 size_t count, loff_t *ppos)
603 sprintf(message, "Usage: echo 'cmd gpionum value' >/proc/vic_gpio\n\t"
604 "cmd: dout doen utrv enrv or manu\n\t"
605 "gpionum: gpionum or address offset for manu\n\t"
606 "value: 0/1 for utrv/enrv, value for dout/doen/manual\n");
607 copied = strlen(message);
612 if (mutex_lock_interruptible(&read_lock))
615 ret = copy_to_user(buf, message, copied);
617 mutex_unlock(&read_lock);
621 mutex_unlock(&read_lock);
626 static const struct file_operations vic_gpio_fops = {
627 .owner = THIS_MODULE,
628 .read = vic_gpio_proc_read,
629 .write = vic_gpio_proc_write,
630 .llseek = noop_llseek,
633 static int sfvic7110_gpio_probe(struct platform_device *pdev)
635 struct device *dev = &pdev->dev;
636 struct sfvic7110_gpio *chip;
637 struct resource *res;
641 chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
643 dev_err(dev, "out of memory\n");
647 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
648 chip->base = devm_ioremap_resource(dev, res);
649 if (IS_ERR(chip->base)) {
650 dev_err(dev, "failed to allocate device memory\n");
651 return PTR_ERR(chip->base);
653 gpio_base = chip->base ;
657 raw_spin_lock_init(&chip->lock);
658 chip->gc.direction_input = sfvic7110_direction_input;
659 chip->gc.direction_output = sfvic7110_direction_output;
660 chip->gc.get_direction = sfvic7110_get_direction;
661 chip->gc.get = sfvic7110_get_value;
662 chip->gc.set = sfvic7110_set_value;
664 chip->gc.ngpio = ngpio;
665 chip->gc.label = dev_name(dev);
666 chip->gc.parent = dev;
667 chip->gc.owner = THIS_MODULE;
669 ret = gpiochip_add_data(&chip->gc, chip);
671 dev_err(dev, "gpiochip_add_data ret=%d!\n", ret);
675 /* Disable all GPIO interrupts before enabling parent interrupts */
676 iowrite32(0, chip->base + GPIO_IE_HIGH);
677 iowrite32(0, chip->base + GPIO_IE_LOW);
680 ret = gpiochip_irqchip_add(&chip->gc, &sfvic7110_irqchip, 0,
681 handle_simple_irq, IRQ_TYPE_NONE);
683 dev_err(dev, "could not add irqchip\n");
684 gpiochip_remove(&chip->gc);
687 irq = platform_get_irq(pdev, 0);
689 dev_err(dev, "Cannot get IRQ resource\n");
693 ret = devm_request_irq(dev, irq, sfvic7110_irq_handler, IRQF_SHARED,
694 dev_name(dev), chip);
696 dev_err(dev, "IRQ handler registering failed (%d)\n", ret);
700 writel_relaxed(1, chip->base + GPIO_EN);
702 for(loop = 0; loop < MAX_GPIO; loop++) {
704 v = readl_relaxed(chip->base + GPIO_INPUT_ENABLE_X_REG + (loop << 2));
706 writel_relaxed(v, chip->base + GPIO_INPUT_ENABLE_X_REG + (loop << 2));
709 if (proc_create(PROC_VIC, 0, NULL, (void *)&vic_gpio_fops) == NULL) {
712 dev_info(dev, "SiFive GPIO chip registered %d GPIOs\n", ngpio);
717 static const struct of_device_id sfvic7110_gpio_match[] = {
718 { .compatible = "starfive,gpio7110", },
722 static struct platform_driver sfvic7110_gpio_driver = {
723 .probe = sfvic7110_gpio_probe,
725 .name = "sfvic7110_gpio",
726 .of_match_table = of_match_ptr(sfvic7110_gpio_match),
730 static int __init sfvic7110_gpio_init(void)
732 return platform_driver_register(&sfvic7110_gpio_driver);
734 subsys_initcall(sfvic7110_gpio_init);
736 static void __exit sfvic7110_gpio_exit(void)
738 platform_driver_unregister(&sfvic7110_gpio_driver);
740 module_exit(sfvic7110_gpio_exit);
742 MODULE_LICENSE("GPL");
743 MODULE_AUTHOR("Huan Feng <huan.feng@starfivetech.com>");
744 MODULE_DESCRIPTION("Starfive VIC GPIO generator driver");