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 acpi_device *acpi_dev; 76 acpi_handle handle = ACPI_HANDLE(dev); 77 struct pt_gpio_chip *pt_gpio; 78 int ret = 0; 79 80 if (acpi_bus_get_device(handle, &acpi_dev)) { 81 dev_err(dev, "PT GPIO device node not found\n"); 82 return -ENODEV; 83 } 84 85 pt_gpio = devm_kzalloc(dev, sizeof(struct pt_gpio_chip), GFP_KERNEL); 86 if (!pt_gpio) 87 return -ENOMEM; 88 89 pt_gpio->reg_base = devm_platform_ioremap_resource(pdev, 0); 90 if (IS_ERR(pt_gpio->reg_base)) { 91 dev_err(dev, "Failed to map MMIO resource for PT GPIO.\n"); 92 return PTR_ERR(pt_gpio->reg_base); 93 } 94 95 ret = bgpio_init(&pt_gpio->gc, dev, 4, 96 pt_gpio->reg_base + PT_INPUTDATA_REG, 97 pt_gpio->reg_base + PT_OUTPUTDATA_REG, NULL, 98 pt_gpio->reg_base + PT_DIRECTION_REG, NULL, 99 BGPIOF_READ_OUTPUT_REG_SET); 100 if (ret) { 101 dev_err(dev, "bgpio_init failed\n"); 102 return ret; 103 } 104 105 pt_gpio->gc.owner = THIS_MODULE; 106 pt_gpio->gc.request = pt_gpio_request; 107 pt_gpio->gc.free = pt_gpio_free; 108 pt_gpio->gc.ngpio = PT_TOTAL_GPIO; 109 #if defined(CONFIG_OF_GPIO) 110 pt_gpio->gc.of_node = dev->of_node; 111 #endif 112 ret = gpiochip_add_data(&pt_gpio->gc, pt_gpio); 113 if (ret) { 114 dev_err(dev, "Failed to register GPIO lib\n"); 115 return ret; 116 } 117 118 platform_set_drvdata(pdev, pt_gpio); 119 120 /* initialize register setting */ 121 writel(0, pt_gpio->reg_base + PT_SYNC_REG); 122 writel(0, pt_gpio->reg_base + PT_CLOCKRATE_REG); 123 124 dev_dbg(dev, "PT GPIO driver loaded\n"); 125 return ret; 126 } 127 128 static int pt_gpio_remove(struct platform_device *pdev) 129 { 130 struct pt_gpio_chip *pt_gpio = platform_get_drvdata(pdev); 131 132 gpiochip_remove(&pt_gpio->gc); 133 134 return 0; 135 } 136 137 static const struct acpi_device_id pt_gpio_acpi_match[] = { 138 { "AMDF030", 0 }, 139 { "AMDIF030", 0 }, 140 { }, 141 }; 142 MODULE_DEVICE_TABLE(acpi, pt_gpio_acpi_match); 143 144 static struct platform_driver pt_gpio_driver = { 145 .driver = { 146 .name = "pt-gpio", 147 .acpi_match_table = ACPI_PTR(pt_gpio_acpi_match), 148 }, 149 .probe = pt_gpio_probe, 150 .remove = pt_gpio_remove, 151 }; 152 153 module_platform_driver(pt_gpio_driver); 154 155 MODULE_LICENSE("GPL"); 156 MODULE_AUTHOR("YD Tseng <yd_tseng@asmedia.com.tw>"); 157 MODULE_DESCRIPTION("AMD Promontory GPIO Driver"); 158