2 * AMD Promontory GPIO driver
4 * Copyright (C) 2015 ASMedia Technology Inc.
5 * Author: YD Tseng <yd_tseng@asmedia.com.tw>
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.
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>
19 #define PT_TOTAL_GPIO 8
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
30 void __iomem
*reg_base
;
33 static int pt_gpio_request(struct gpio_chip
*gc
, unsigned offset
)
35 struct pt_gpio_chip
*pt_gpio
= gpiochip_get_data(gc
);
39 dev_dbg(gc
->parent
, "pt_gpio_request offset=%x\n", offset
);
41 spin_lock_irqsave(&gc
->bgpio_lock
, flags
);
43 using_pins
= readl(pt_gpio
->reg_base
+ PT_SYNC_REG
);
44 if (using_pins
& BIT(offset
)) {
45 dev_warn(gc
->parent
, "PT GPIO pin %x reconfigured\n",
47 spin_unlock_irqrestore(&gc
->bgpio_lock
, flags
);
51 writel(using_pins
| BIT(offset
), pt_gpio
->reg_base
+ PT_SYNC_REG
);
53 spin_unlock_irqrestore(&gc
->bgpio_lock
, flags
);
58 static void pt_gpio_free(struct gpio_chip
*gc
, unsigned offset
)
60 struct pt_gpio_chip
*pt_gpio
= gpiochip_get_data(gc
);
64 spin_lock_irqsave(&gc
->bgpio_lock
, flags
);
66 using_pins
= readl(pt_gpio
->reg_base
+ PT_SYNC_REG
);
67 using_pins
&= ~BIT(offset
);
68 writel(using_pins
, pt_gpio
->reg_base
+ PT_SYNC_REG
);
70 spin_unlock_irqrestore(&gc
->bgpio_lock
, flags
);
72 dev_dbg(gc
->parent
, "pt_gpio_free offset=%x\n", offset
);
75 static int pt_gpio_probe(struct platform_device
*pdev
)
77 struct device
*dev
= &pdev
->dev
;
78 struct acpi_device
*acpi_dev
;
79 acpi_handle handle
= ACPI_HANDLE(dev
);
80 struct pt_gpio_chip
*pt_gpio
;
81 struct resource
*res_mem
;
84 if (acpi_bus_get_device(handle
, &acpi_dev
)) {
85 dev_err(dev
, "PT GPIO device node not found\n");
89 pt_gpio
= devm_kzalloc(dev
, sizeof(struct pt_gpio_chip
), GFP_KERNEL
);
93 res_mem
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
95 dev_err(&pdev
->dev
, "Failed to get MMIO resource for PT GPIO.\n");
98 pt_gpio
->reg_base
= devm_ioremap_resource(dev
, res_mem
);
99 if (IS_ERR(pt_gpio
->reg_base
)) {
100 dev_err(&pdev
->dev
, "Failed to map MMIO resource for PT GPIO.\n");
101 return PTR_ERR(pt_gpio
->reg_base
);
104 ret
= bgpio_init(&pt_gpio
->gc
, dev
, 4,
105 pt_gpio
->reg_base
+ PT_INPUTDATA_REG
,
106 pt_gpio
->reg_base
+ PT_OUTPUTDATA_REG
, NULL
,
107 pt_gpio
->reg_base
+ PT_DIRECTION_REG
, NULL
,
108 BGPIOF_READ_OUTPUT_REG_SET
);
110 dev_err(&pdev
->dev
, "bgpio_init failed\n");
114 pt_gpio
->gc
.owner
= THIS_MODULE
;
115 pt_gpio
->gc
.request
= pt_gpio_request
;
116 pt_gpio
->gc
.free
= pt_gpio_free
;
117 pt_gpio
->gc
.ngpio
= PT_TOTAL_GPIO
;
118 #if defined(CONFIG_OF_GPIO)
119 pt_gpio
->gc
.of_node
= pdev
->dev
.of_node
;
121 ret
= gpiochip_add_data(&pt_gpio
->gc
, pt_gpio
);
123 dev_err(&pdev
->dev
, "Failed to register GPIO lib\n");
127 platform_set_drvdata(pdev
, pt_gpio
);
129 /* initialize register setting */
130 writel(0, pt_gpio
->reg_base
+ PT_SYNC_REG
);
131 writel(0, pt_gpio
->reg_base
+ PT_CLOCKRATE_REG
);
133 dev_dbg(&pdev
->dev
, "PT GPIO driver loaded\n");
137 static int pt_gpio_remove(struct platform_device
*pdev
)
139 struct pt_gpio_chip
*pt_gpio
= platform_get_drvdata(pdev
);
141 gpiochip_remove(&pt_gpio
->gc
);
146 static const struct acpi_device_id pt_gpio_acpi_match
[] = {
151 MODULE_DEVICE_TABLE(acpi
, pt_gpio_acpi_match
);
153 static struct platform_driver pt_gpio_driver
= {
156 .acpi_match_table
= ACPI_PTR(pt_gpio_acpi_match
),
158 .probe
= pt_gpio_probe
,
159 .remove
= pt_gpio_remove
,
162 module_platform_driver(pt_gpio_driver
);
164 MODULE_LICENSE("GPL");
165 MODULE_AUTHOR("YD Tseng <yd_tseng@asmedia.com.tw>");
166 MODULE_DESCRIPTION("AMD Promontory GPIO Driver");