1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * GPIO Driver for Loongson 1 SoC 4 * 5 * Copyright (C) 2015-2023 Keguang Zhang <keguang.zhang@gmail.com> 6 */ 7 8 #include <linux/bitops.h> 9 #include <linux/module.h> 10 #include <linux/gpio/driver.h> 11 #include <linux/gpio/generic.h> 12 #include <linux/platform_device.h> 13 14 /* Loongson 1 GPIO Register Definitions */ 15 #define GPIO_CFG 0x0 16 #define GPIO_DIR 0x10 17 #define GPIO_DATA 0x20 18 #define GPIO_OUTPUT 0x30 19 20 struct ls1x_gpio_chip { 21 struct gpio_generic_chip chip; 22 void __iomem *reg_base; 23 }; 24 25 static int ls1x_gpio_request(struct gpio_chip *gc, unsigned int offset) 26 { 27 struct ls1x_gpio_chip *ls1x_gc = gpiochip_get_data(gc); 28 29 guard(gpio_generic_lock_irqsave)(&ls1x_gc->chip); 30 31 __raw_writel(__raw_readl(ls1x_gc->reg_base + GPIO_CFG) | BIT(offset), 32 ls1x_gc->reg_base + GPIO_CFG); 33 34 return 0; 35 } 36 37 static void ls1x_gpio_free(struct gpio_chip *gc, unsigned int offset) 38 { 39 struct ls1x_gpio_chip *ls1x_gc = gpiochip_get_data(gc); 40 41 guard(gpio_generic_lock_irqsave)(&ls1x_gc->chip); 42 43 __raw_writel(__raw_readl(ls1x_gc->reg_base + GPIO_CFG) & ~BIT(offset), 44 ls1x_gc->reg_base + GPIO_CFG); 45 } 46 47 static int ls1x_gpio_probe(struct platform_device *pdev) 48 { 49 struct gpio_generic_chip_config config; 50 struct device *dev = &pdev->dev; 51 struct ls1x_gpio_chip *ls1x_gc; 52 int ret; 53 54 ls1x_gc = devm_kzalloc(dev, sizeof(*ls1x_gc), GFP_KERNEL); 55 if (!ls1x_gc) 56 return -ENOMEM; 57 58 ls1x_gc->reg_base = devm_platform_ioremap_resource(pdev, 0); 59 if (IS_ERR(ls1x_gc->reg_base)) 60 return PTR_ERR(ls1x_gc->reg_base); 61 62 config = (struct gpio_generic_chip_config) { 63 .dev = dev, 64 .sz = 4, 65 .dat = ls1x_gc->reg_base + GPIO_DATA, 66 .set = ls1x_gc->reg_base + GPIO_OUTPUT, 67 .dirin = ls1x_gc->reg_base + GPIO_DIR, 68 }; 69 70 ret = gpio_generic_chip_init(&ls1x_gc->chip, &config); 71 if (ret) 72 goto err; 73 74 ls1x_gc->chip.gc.owner = THIS_MODULE; 75 ls1x_gc->chip.gc.request = ls1x_gpio_request; 76 ls1x_gc->chip.gc.free = ls1x_gpio_free; 77 /* 78 * Clear ngpio to let gpiolib get the correct number 79 * by reading ngpios property 80 */ 81 ls1x_gc->chip.gc.ngpio = 0; 82 83 ret = devm_gpiochip_add_data(dev, &ls1x_gc->chip.gc, ls1x_gc); 84 if (ret) 85 goto err; 86 87 platform_set_drvdata(pdev, ls1x_gc); 88 89 dev_info(dev, "GPIO controller registered with %d pins\n", 90 ls1x_gc->chip.gc.ngpio); 91 92 return 0; 93 err: 94 dev_err(dev, "failed to register GPIO controller\n"); 95 return ret; 96 } 97 98 static const struct of_device_id ls1x_gpio_dt_ids[] = { 99 { .compatible = "loongson,ls1x-gpio" }, 100 { /* sentinel */ } 101 }; 102 MODULE_DEVICE_TABLE(of, ls1x_gpio_dt_ids); 103 104 static struct platform_driver ls1x_gpio_driver = { 105 .probe = ls1x_gpio_probe, 106 .driver = { 107 .name = "ls1x-gpio", 108 .of_match_table = ls1x_gpio_dt_ids, 109 }, 110 }; 111 112 module_platform_driver(ls1x_gpio_driver); 113 114 MODULE_AUTHOR("Keguang Zhang <keguang.zhang@gmail.com>"); 115 MODULE_DESCRIPTION("Loongson1 GPIO driver"); 116 MODULE_LICENSE("GPL"); 117