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
;
34 static int pt_gpio_request(struct gpio_chip
*gc
, unsigned offset
)
36 struct pt_gpio_chip
*pt_gpio
= gpiochip_get_data(gc
);
40 dev_dbg(gc
->parent
, "pt_gpio_request offset=%x\n", offset
);
42 spin_lock_irqsave(&pt_gpio
->lock
, flags
);
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",
48 spin_unlock_irqrestore(&pt_gpio
->lock
, flags
);
52 writel(using_pins
| BIT(offset
), pt_gpio
->reg_base
+ PT_SYNC_REG
);
54 spin_unlock_irqrestore(&pt_gpio
->lock
, flags
);
59 static void pt_gpio_free(struct gpio_chip
*gc
, unsigned offset
)
61 struct pt_gpio_chip
*pt_gpio
= gpiochip_get_data(gc
);
65 spin_lock_irqsave(&pt_gpio
->lock
, flags
);
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
);
71 spin_unlock_irqrestore(&pt_gpio
->lock
, flags
);
73 dev_dbg(gc
->parent
, "pt_gpio_free offset=%x\n", offset
);
76 static void pt_gpio_set_value(struct gpio_chip
*gc
, unsigned offset
, int value
)
78 struct pt_gpio_chip
*pt_gpio
= gpiochip_get_data(gc
);
82 dev_dbg(gc
->parent
, "pt_gpio_set_value offset=%x, value=%x\n",
85 spin_lock_irqsave(&pt_gpio
->lock
, flags
);
87 data
= readl(pt_gpio
->reg_base
+ PT_OUTPUTDATA_REG
);
91 writel(data
, pt_gpio
->reg_base
+ PT_OUTPUTDATA_REG
);
93 spin_unlock_irqrestore(&pt_gpio
->lock
, flags
);
96 static int pt_gpio_get_value(struct gpio_chip
*gc
, unsigned offset
)
98 struct pt_gpio_chip
*pt_gpio
= gpiochip_get_data(gc
);
102 spin_lock_irqsave(&pt_gpio
->lock
, flags
);
104 data
= readl(pt_gpio
->reg_base
+ PT_DIRECTION_REG
);
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
);
112 spin_unlock_irqrestore(&pt_gpio
->lock
, flags
);
117 dev_dbg(gc
->parent
, "pt_gpio_get_value offset=%x, value=%x\n",
123 static int pt_gpio_direction_input(struct gpio_chip
*gc
, unsigned offset
)
125 struct pt_gpio_chip
*pt_gpio
= gpiochip_get_data(gc
);
129 dev_dbg(gc
->parent
, "pt_gpio_dirction_input offset=%x\n", offset
);
131 spin_lock_irqsave(&pt_gpio
->lock
, flags
);
133 data
= readl(pt_gpio
->reg_base
+ PT_DIRECTION_REG
);
134 data
&= ~BIT(offset
);
135 writel(data
, pt_gpio
->reg_base
+ PT_DIRECTION_REG
);
137 spin_unlock_irqrestore(&pt_gpio
->lock
, flags
);
142 static int pt_gpio_direction_output(struct gpio_chip
*gc
,
143 unsigned offset
, int value
)
145 struct pt_gpio_chip
*pt_gpio
= gpiochip_get_data(gc
);
149 dev_dbg(gc
->parent
, "pt_gpio_direction_output offset=%x, value=%x\n",
152 spin_lock_irqsave(&pt_gpio
->lock
, flags
);
154 data
= readl(pt_gpio
->reg_base
+ PT_OUTPUTDATA_REG
);
158 data
&= ~BIT(offset
);
159 writel(data
, pt_gpio
->reg_base
+ PT_OUTPUTDATA_REG
);
161 data
= readl(pt_gpio
->reg_base
+ PT_DIRECTION_REG
);
163 writel(data
, pt_gpio
->reg_base
+ PT_DIRECTION_REG
);
165 spin_unlock_irqrestore(&pt_gpio
->lock
, flags
);
170 static int pt_gpio_probe(struct platform_device
*pdev
)
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
;
179 if (acpi_bus_get_device(handle
, &acpi_dev
)) {
180 dev_err(dev
, "PT GPIO device node not found\n");
184 pt_gpio
= devm_kzalloc(dev
, sizeof(struct pt_gpio_chip
), GFP_KERNEL
);
188 res_mem
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
190 dev_err(&pdev
->dev
, "Failed to get MMIO resource for PT GPIO.\n");
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
);
199 spin_lock_init(&pt_gpio
->lock
);
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
;
215 ret
= gpiochip_add_data(&pt_gpio
->gc
, pt_gpio
);
217 dev_err(&pdev
->dev
, "Failed to register GPIO lib\n");
221 platform_set_drvdata(pdev
, pt_gpio
);
223 /* initialize register setting */
224 writel(0, pt_gpio
->reg_base
+ PT_SYNC_REG
);
225 writel(0, pt_gpio
->reg_base
+ PT_CLOCKRATE_REG
);
227 dev_dbg(&pdev
->dev
, "PT GPIO driver loaded\n");
231 static int pt_gpio_remove(struct platform_device
*pdev
)
233 struct pt_gpio_chip
*pt_gpio
= platform_get_drvdata(pdev
);
235 gpiochip_remove(&pt_gpio
->gc
);
240 static const struct acpi_device_id pt_gpio_acpi_match
[] = {
244 MODULE_DEVICE_TABLE(acpi
, pt_gpio_acpi_match
);
246 static struct platform_driver pt_gpio_driver
= {
249 .acpi_match_table
= ACPI_PTR(pt_gpio_acpi_match
),
251 .probe
= pt_gpio_probe
,
252 .remove
= pt_gpio_remove
,
255 module_platform_driver(pt_gpio_driver
);
257 MODULE_LICENSE("GPL");
258 MODULE_AUTHOR("YD Tseng <yd_tseng@asmedia.com.tw>");
259 MODULE_DESCRIPTION("AMD Promontory GPIO Driver");