1 /* 2 * AMD Promontory GPIO driver 3 * 4 * Copyright (C) 2015 ASMedia Technology Inc. 5 * Author: YD Tseng <yd_tseng@asmedia.com.tw> 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License version 2 as 9 * published by the Free Software Foundation. 10 */ 11 12 #include <linux/kernel.h> 13 #include <linux/module.h> 14 #include <linux/gpio/driver.h> 15 #include <linux/spinlock.h> 16 #include <linux/acpi.h> 17 #include <linux/platform_device.h> 18 19 #define PT_TOTAL_GPIO 8 20 21 /* PCI-E MMIO register offsets */ 22 #define PT_DIRECTION_REG 0x00 23 #define PT_INPUTDATA_REG 0x04 24 #define PT_OUTPUTDATA_REG 0x08 25 #define PT_CLOCKRATE_REG 0x0C 26 #define PT_SYNC_REG 0x28 27 28 struct pt_gpio_chip { 29 struct gpio_chip gc; 30 void __iomem *reg_base; 31 spinlock_t lock; 32 }; 33 34 static int pt_gpio_request(struct gpio_chip *gc, unsigned offset) 35 { 36 struct pt_gpio_chip *pt_gpio = gpiochip_get_data(gc); 37 unsigned long flags; 38 u32 using_pins; 39 40 dev_dbg(gc->parent, "pt_gpio_request offset=%x\n", offset); 41 42 spin_lock_irqsave(&pt_gpio->lock, flags); 43 44 using_pins = readl(pt_gpio->reg_base + PT_SYNC_REG); 45 if (using_pins & BIT(offset)) { 46 dev_warn(gc->parent, "PT GPIO pin %x reconfigured\n", 47 offset); 48 spin_unlock_irqrestore(&pt_gpio->lock, flags); 49 return -EINVAL; 50 } 51 52 writel(using_pins | BIT(offset), pt_gpio->reg_base + PT_SYNC_REG); 53 54 spin_unlock_irqrestore(&pt_gpio->lock, flags); 55 56 return 0; 57 } 58 59 static void pt_gpio_free(struct gpio_chip *gc, unsigned offset) 60 { 61 struct pt_gpio_chip *pt_gpio = gpiochip_get_data(gc); 62 unsigned long flags; 63 u32 using_pins; 64 65 spin_lock_irqsave(&pt_gpio->lock, flags); 66 67 using_pins = readl(pt_gpio->reg_base + PT_SYNC_REG); 68 using_pins &= ~BIT(offset); 69 writel(using_pins, pt_gpio->reg_base + PT_SYNC_REG); 70 71 spin_unlock_irqrestore(&pt_gpio->lock, flags); 72 73 dev_dbg(gc->parent, "pt_gpio_free offset=%x\n", offset); 74 } 75 76 static void pt_gpio_set_value(struct gpio_chip *gc, unsigned offset, int value) 77 { 78 struct pt_gpio_chip *pt_gpio = gpiochip_get_data(gc); 79 unsigned long flags; 80 u32 data; 81 82 dev_dbg(gc->parent, "pt_gpio_set_value offset=%x, value=%x\n", 83 offset, value); 84 85 spin_lock_irqsave(&pt_gpio->lock, flags); 86 87 data = readl(pt_gpio->reg_base + PT_OUTPUTDATA_REG); 88 data &= ~BIT(offset); 89 if (value) 90 data |= BIT(offset); 91 writel(data, pt_gpio->reg_base + PT_OUTPUTDATA_REG); 92 93 spin_unlock_irqrestore(&pt_gpio->lock, flags); 94 } 95 96 static int pt_gpio_get_value(struct gpio_chip *gc, unsigned offset) 97 { 98 struct pt_gpio_chip *pt_gpio = gpiochip_get_data(gc); 99 unsigned long flags; 100 u32 data; 101 102 spin_lock_irqsave(&pt_gpio->lock, flags); 103 104 data = readl(pt_gpio->reg_base + PT_DIRECTION_REG); 105 106 /* configure as output */ 107 if (data & BIT(offset)) 108 data = readl(pt_gpio->reg_base + PT_OUTPUTDATA_REG); 109 else /* configure as input */ 110 data = readl(pt_gpio->reg_base + PT_INPUTDATA_REG); 111 112 spin_unlock_irqrestore(&pt_gpio->lock, flags); 113 114 data >>= offset; 115 data &= 1; 116 117 dev_dbg(gc->parent, "pt_gpio_get_value offset=%x, value=%x\n", 118 offset, data); 119 120 return data; 121 } 122 123 static int pt_gpio_direction_input(struct gpio_chip *gc, unsigned offset) 124 { 125 struct pt_gpio_chip *pt_gpio = gpiochip_get_data(gc); 126 unsigned long flags; 127 u32 data; 128 129 dev_dbg(gc->parent, "pt_gpio_dirction_input offset=%x\n", offset); 130 131 spin_lock_irqsave(&pt_gpio->lock, flags); 132 133 data = readl(pt_gpio->reg_base + PT_DIRECTION_REG); 134 data &= ~BIT(offset); 135 writel(data, pt_gpio->reg_base + PT_DIRECTION_REG); 136 137 spin_unlock_irqrestore(&pt_gpio->lock, flags); 138 139 return 0; 140 } 141 142 static int pt_gpio_direction_output(struct gpio_chip *gc, 143 unsigned offset, int value) 144 { 145 struct pt_gpio_chip *pt_gpio = gpiochip_get_data(gc); 146 unsigned long flags; 147 u32 data; 148 149 dev_dbg(gc->parent, "pt_gpio_direction_output offset=%x, value=%x\n", 150 offset, value); 151 152 spin_lock_irqsave(&pt_gpio->lock, flags); 153 154 data = readl(pt_gpio->reg_base + PT_OUTPUTDATA_REG); 155 if (value) 156 data |= BIT(offset); 157 else 158 data &= ~BIT(offset); 159 writel(data, pt_gpio->reg_base + PT_OUTPUTDATA_REG); 160 161 data = readl(pt_gpio->reg_base + PT_DIRECTION_REG); 162 data |= BIT(offset); 163 writel(data, pt_gpio->reg_base + PT_DIRECTION_REG); 164 165 spin_unlock_irqrestore(&pt_gpio->lock, flags); 166 167 return 0; 168 } 169 170 static int pt_gpio_probe(struct platform_device *pdev) 171 { 172 struct device *dev = &pdev->dev; 173 struct acpi_device *acpi_dev; 174 acpi_handle handle = ACPI_HANDLE(dev); 175 struct pt_gpio_chip *pt_gpio; 176 struct resource *res_mem; 177 int ret = 0; 178 179 if (acpi_bus_get_device(handle, &acpi_dev)) { 180 dev_err(dev, "PT GPIO device node not found\n"); 181 return -ENODEV; 182 } 183 184 pt_gpio = devm_kzalloc(dev, sizeof(struct pt_gpio_chip), GFP_KERNEL); 185 if (!pt_gpio) 186 return -ENOMEM; 187 188 res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); 189 if (!res_mem) { 190 dev_err(&pdev->dev, "Failed to get MMIO resource for PT GPIO.\n"); 191 return -EINVAL; 192 } 193 pt_gpio->reg_base = devm_ioremap_resource(dev, res_mem); 194 if (IS_ERR(pt_gpio->reg_base)) { 195 dev_err(&pdev->dev, "Failed to map MMIO resource for PT GPIO.\n"); 196 return PTR_ERR(pt_gpio->reg_base); 197 } 198 199 spin_lock_init(&pt_gpio->lock); 200 201 pt_gpio->gc.label = pdev->name; 202 pt_gpio->gc.owner = THIS_MODULE; 203 pt_gpio->gc.parent = dev; 204 pt_gpio->gc.request = pt_gpio_request; 205 pt_gpio->gc.free = pt_gpio_free; 206 pt_gpio->gc.direction_input = pt_gpio_direction_input; 207 pt_gpio->gc.direction_output = pt_gpio_direction_output; 208 pt_gpio->gc.get = pt_gpio_get_value; 209 pt_gpio->gc.set = pt_gpio_set_value; 210 pt_gpio->gc.base = -1; 211 pt_gpio->gc.ngpio = PT_TOTAL_GPIO; 212 #if defined(CONFIG_OF_GPIO) 213 pt_gpio->gc.of_node = pdev->dev.of_node; 214 #endif 215 ret = gpiochip_add_data(&pt_gpio->gc, pt_gpio); 216 if (ret) { 217 dev_err(&pdev->dev, "Failed to register GPIO lib\n"); 218 return ret; 219 } 220 221 platform_set_drvdata(pdev, pt_gpio); 222 223 /* initialize register setting */ 224 writel(0, pt_gpio->reg_base + PT_SYNC_REG); 225 writel(0, pt_gpio->reg_base + PT_CLOCKRATE_REG); 226 227 dev_dbg(&pdev->dev, "PT GPIO driver loaded\n"); 228 return ret; 229 } 230 231 static int pt_gpio_remove(struct platform_device *pdev) 232 { 233 struct pt_gpio_chip *pt_gpio = platform_get_drvdata(pdev); 234 235 gpiochip_remove(&pt_gpio->gc); 236 237 return 0; 238 } 239 240 static const struct acpi_device_id pt_gpio_acpi_match[] = { 241 { "AMDF030", 0 }, 242 { }, 243 }; 244 MODULE_DEVICE_TABLE(acpi, pt_gpio_acpi_match); 245 246 static struct platform_driver pt_gpio_driver = { 247 .driver = { 248 .name = "pt-gpio", 249 .acpi_match_table = ACPI_PTR(pt_gpio_acpi_match), 250 }, 251 .probe = pt_gpio_probe, 252 .remove = pt_gpio_remove, 253 }; 254 255 module_platform_driver(pt_gpio_driver); 256 257 MODULE_LICENSE("GPL"); 258 MODULE_AUTHOR("YD Tseng <yd_tseng@asmedia.com.tw>"); 259 MODULE_DESCRIPTION("AMD Promontory GPIO Driver"); 260