1 // SPDX-License-Identifier: GPL-2.0+
4 * GPIO driver for the AMD G series FCH (eg. GX-412TC)
6 * Copyright (C) 2018 metux IT consult
7 * Author: Enrico Weigelt, metux IT consult <info@metux.net>
11 #include <linux/err.h>
13 #include <linux/kernel.h>
14 #include <linux/module.h>
15 #include <linux/platform_device.h>
16 #include <linux/gpio/driver.h>
17 #include <linux/platform_data/gpio/gpio-amd-fch.h>
18 #include <linux/spinlock.h>
20 #define AMD_FCH_MMIO_BASE 0xFED80000
21 #define AMD_FCH_GPIO_BANK0_BASE 0x1500
22 #define AMD_FCH_GPIO_SIZE 0x0300
24 #define AMD_FCH_GPIO_FLAG_DIRECTION BIT(23)
25 #define AMD_FCH_GPIO_FLAG_WRITE BIT(22)
26 #define AMD_FCH_GPIO_FLAG_READ BIT(16)
28 static const struct resource amd_fch_gpio_iores
=
30 AMD_FCH_MMIO_BASE
+ AMD_FCH_GPIO_BANK0_BASE
,
32 "amd-fch-gpio-iomem");
34 struct amd_fch_gpio_priv
{
37 struct amd_fch_gpio_pdata
*pdata
;
41 static void __iomem
*amd_fch_gpio_addr(struct amd_fch_gpio_priv
*priv
,
44 return priv
->base
+ priv
->pdata
->gpio_reg
[gpio
]*sizeof(u32
);
47 static int amd_fch_gpio_direction_input(struct gpio_chip
*gc
,
51 struct amd_fch_gpio_priv
*priv
= gpiochip_get_data(gc
);
52 void __iomem
*ptr
= amd_fch_gpio_addr(priv
, offset
);
54 spin_lock_irqsave(&priv
->lock
, flags
);
55 writel_relaxed(readl_relaxed(ptr
) & ~AMD_FCH_GPIO_FLAG_DIRECTION
, ptr
);
56 spin_unlock_irqrestore(&priv
->lock
, flags
);
61 static int amd_fch_gpio_direction_output(struct gpio_chip
*gc
,
62 unsigned int gpio
, int value
)
65 struct amd_fch_gpio_priv
*priv
= gpiochip_get_data(gc
);
66 void __iomem
*ptr
= amd_fch_gpio_addr(priv
, gpio
);
69 spin_lock_irqsave(&priv
->lock
, flags
);
71 val
= readl_relaxed(ptr
);
73 val
|= AMD_FCH_GPIO_FLAG_WRITE
;
75 val
&= ~AMD_FCH_GPIO_FLAG_WRITE
;
77 writel_relaxed(val
| AMD_FCH_GPIO_FLAG_DIRECTION
, ptr
);
79 spin_unlock_irqrestore(&priv
->lock
, flags
);
84 static int amd_fch_gpio_get_direction(struct gpio_chip
*gc
, unsigned int gpio
)
88 struct amd_fch_gpio_priv
*priv
= gpiochip_get_data(gc
);
89 void __iomem
*ptr
= amd_fch_gpio_addr(priv
, gpio
);
91 spin_lock_irqsave(&priv
->lock
, flags
);
92 ret
= (readl_relaxed(ptr
) & AMD_FCH_GPIO_FLAG_DIRECTION
);
93 spin_unlock_irqrestore(&priv
->lock
, flags
);
95 return ret
? GPIO_LINE_DIRECTION_OUT
: GPIO_LINE_DIRECTION_IN
;
98 static void amd_fch_gpio_set(struct gpio_chip
*gc
,
99 unsigned int gpio
, int value
)
102 struct amd_fch_gpio_priv
*priv
= gpiochip_get_data(gc
);
103 void __iomem
*ptr
= amd_fch_gpio_addr(priv
, gpio
);
106 spin_lock_irqsave(&priv
->lock
, flags
);
108 mask
= readl_relaxed(ptr
);
110 mask
|= AMD_FCH_GPIO_FLAG_WRITE
;
112 mask
&= ~AMD_FCH_GPIO_FLAG_WRITE
;
113 writel_relaxed(mask
, ptr
);
115 spin_unlock_irqrestore(&priv
->lock
, flags
);
118 static int amd_fch_gpio_get(struct gpio_chip
*gc
,
123 struct amd_fch_gpio_priv
*priv
= gpiochip_get_data(gc
);
124 void __iomem
*ptr
= amd_fch_gpio_addr(priv
, offset
);
126 spin_lock_irqsave(&priv
->lock
, flags
);
127 ret
= (readl_relaxed(ptr
) & AMD_FCH_GPIO_FLAG_READ
);
128 spin_unlock_irqrestore(&priv
->lock
, flags
);
133 static int amd_fch_gpio_request(struct gpio_chip
*chip
,
134 unsigned int gpio_pin
)
139 static int amd_fch_gpio_probe(struct platform_device
*pdev
)
141 struct amd_fch_gpio_priv
*priv
;
142 struct amd_fch_gpio_pdata
*pdata
;
144 pdata
= dev_get_platdata(&pdev
->dev
);
146 dev_err(&pdev
->dev
, "no platform_data\n");
150 priv
= devm_kzalloc(&pdev
->dev
, sizeof(*priv
), GFP_KERNEL
);
156 priv
->gc
.owner
= THIS_MODULE
;
157 priv
->gc
.parent
= &pdev
->dev
;
158 priv
->gc
.label
= dev_name(&pdev
->dev
);
159 priv
->gc
.ngpio
= priv
->pdata
->gpio_num
;
160 priv
->gc
.names
= priv
->pdata
->gpio_names
;
162 priv
->gc
.request
= amd_fch_gpio_request
;
163 priv
->gc
.direction_input
= amd_fch_gpio_direction_input
;
164 priv
->gc
.direction_output
= amd_fch_gpio_direction_output
;
165 priv
->gc
.get_direction
= amd_fch_gpio_get_direction
;
166 priv
->gc
.get
= amd_fch_gpio_get
;
167 priv
->gc
.set
= amd_fch_gpio_set
;
169 spin_lock_init(&priv
->lock
);
171 priv
->base
= devm_ioremap_resource(&pdev
->dev
, &amd_fch_gpio_iores
);
172 if (IS_ERR(priv
->base
))
173 return PTR_ERR(priv
->base
);
175 platform_set_drvdata(pdev
, priv
);
177 return devm_gpiochip_add_data(&pdev
->dev
, &priv
->gc
, priv
);
180 static struct platform_driver amd_fch_gpio_driver
= {
182 .name
= AMD_FCH_GPIO_DRIVER_NAME
,
184 .probe
= amd_fch_gpio_probe
,
187 module_platform_driver(amd_fch_gpio_driver
);
189 MODULE_AUTHOR("Enrico Weigelt, metux IT consult <info@metux.net>");
190 MODULE_DESCRIPTION("AMD G-series FCH GPIO driver");
191 MODULE_LICENSE("GPL");
192 MODULE_ALIAS("platform:" AMD_FCH_GPIO_DRIVER_NAME
);