1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * AMD Promontory GPIO driver 4 * 5 * Copyright (C) 2015 ASMedia Technology Inc. 6 * Author: YD Tseng <yd_tseng@asmedia.com.tw> 7 */ 8 9 #include <linux/kernel.h> 10 #include <linux/module.h> 11 #include <linux/gpio/driver.h> 12 #include <linux/spinlock.h> 13 #include <linux/acpi.h> 14 #include <linux/platform_device.h> 15 16 #define PT_TOTAL_GPIO 8 17 18 /* PCI-E MMIO register offsets */ 19 #define PT_DIRECTION_REG 0x00 20 #define PT_INPUTDATA_REG 0x04 21 #define PT_OUTPUTDATA_REG 0x08 22 #define PT_CLOCKRATE_REG 0x0C 23 #define PT_SYNC_REG 0x28 24 25 struct pt_gpio_chip { 26 struct gpio_chip gc; 27 void __iomem *reg_base; 28 }; 29 30 static int pt_gpio_request(struct gpio_chip *gc, unsigned offset) 31 { 32 struct pt_gpio_chip *pt_gpio = gpiochip_get_data(gc); 33 unsigned long flags; 34 u32 using_pins; 35 36 dev_dbg(gc->parent, "pt_gpio_request offset=%x\n", offset); 37 38 spin_lock_irqsave(&gc->bgpio_lock, flags); 39 40 using_pins = readl(pt_gpio->reg_base + PT_SYNC_REG); 41 if (using_pins & BIT(offset)) { 42 dev_warn(gc->parent, "PT GPIO pin %x reconfigured\n", 43 offset); 44 spin_unlock_irqrestore(&gc->bgpio_lock, flags); 45 return -EINVAL; 46 } 47 48 writel(using_pins | BIT(offset), pt_gpio->reg_base + PT_SYNC_REG); 49 50 spin_unlock_irqrestore(&gc->bgpio_lock, flags); 51 52 return 0; 53 } 54 55 static void pt_gpio_free(struct gpio_chip *gc, unsigned offset) 56 { 57 struct pt_gpio_chip *pt_gpio = gpiochip_get_data(gc); 58 unsigned long flags; 59 u32 using_pins; 60 61 spin_lock_irqsave(&gc->bgpio_lock, flags); 62 63 using_pins = readl(pt_gpio->reg_base + PT_SYNC_REG); 64 using_pins &= ~BIT(offset); 65 writel(using_pins, pt_gpio->reg_base + PT_SYNC_REG); 66 67 spin_unlock_irqrestore(&gc->bgpio_lock, flags); 68 69 dev_dbg(gc->parent, "pt_gpio_free offset=%x\n", offset); 70 } 71 72 static int pt_gpio_probe(struct platform_device *pdev) 73 { 74 struct device *dev = &pdev->dev; 75 struct pt_gpio_chip *pt_gpio; 76 int ret = 0; 77 78 if (!ACPI_COMPANION(dev)) { 79 dev_err(dev, "PT GPIO device node not found\n"); 80 return -ENODEV; 81 } 82 83 pt_gpio = devm_kzalloc(dev, sizeof(struct pt_gpio_chip), GFP_KERNEL); 84 if (!pt_gpio) 85 return -ENOMEM; 86 87 pt_gpio->reg_base = devm_platform_ioremap_resource(pdev, 0); 88 if (IS_ERR(pt_gpio->reg_base)) { 89 dev_err(dev, "Failed to map MMIO resource for PT GPIO.\n"); 90 return PTR_ERR(pt_gpio->reg_base); 91 } 92 93 ret = bgpio_init(&pt_gpio->gc, dev, 4, 94 pt_gpio->reg_base + PT_INPUTDATA_REG, 95 pt_gpio->reg_base + PT_OUTPUTDATA_REG, NULL, 96 pt_gpio->reg_base + PT_DIRECTION_REG, NULL, 97 BGPIOF_READ_OUTPUT_REG_SET); 98 if (ret) { 99 dev_err(dev, "bgpio_init failed\n"); 100 return ret; 101 } 102 103 pt_gpio->gc.owner = THIS_MODULE; 104 pt_gpio->gc.request = pt_gpio_request; 105 pt_gpio->gc.free = pt_gpio_free; 106 pt_gpio->gc.ngpio = PT_TOTAL_GPIO; 107 #if defined(CONFIG_OF_GPIO) 108 pt_gpio->gc.of_node = dev->of_node; 109 #endif 110 ret = gpiochip_add_data(&pt_gpio->gc, pt_gpio); 111 if (ret) { 112 dev_err(dev, "Failed to register GPIO lib\n"); 113 return ret; 114 } 115 116 platform_set_drvdata(pdev, pt_gpio); 117 118 /* initialize register setting */ 119 writel(0, pt_gpio->reg_base + PT_SYNC_REG); 120 writel(0, pt_gpio->reg_base + PT_CLOCKRATE_REG); 121 122 dev_dbg(dev, "PT GPIO driver loaded\n"); 123 return ret; 124 } 125 126 static int pt_gpio_remove(struct platform_device *pdev) 127 { 128 struct pt_gpio_chip *pt_gpio = platform_get_drvdata(pdev); 129 130 gpiochip_remove(&pt_gpio->gc); 131 132 return 0; 133 } 134 135 static const struct acpi_device_id pt_gpio_acpi_match[] = { 136 { "AMDF030", 0 }, 137 { "AMDIF030", 0 }, 138 { }, 139 }; 140 MODULE_DEVICE_TABLE(acpi, pt_gpio_acpi_match); 141 142 static struct platform_driver pt_gpio_driver = { 143 .driver = { 144 .name = "pt-gpio", 145 .acpi_match_table = ACPI_PTR(pt_gpio_acpi_match), 146 }, 147 .probe = pt_gpio_probe, 148 .remove = pt_gpio_remove, 149 }; 150 151 module_platform_driver(pt_gpio_driver); 152 153 MODULE_LICENSE("GPL"); 154 MODULE_AUTHOR("YD Tseng <yd_tseng@asmedia.com.tw>"); 155 MODULE_DESCRIPTION("AMD Promontory GPIO Driver"); 156