blob: 9bfff171f9fef3c073f9bfda74d0025fe64cd4e1 [file] [log] [blame]
Thomas Gleixner8e8e69d2019-05-29 07:17:59 -07001// SPDX-License-Identifier: GPL-2.0-only
Jassi Brar0da094d2015-01-19 18:35:53 +08002/*
3 * linux/drivers/gpio/gpio-mb86s7x.c
4 *
5 * Copyright (C) 2015 Fujitsu Semiconductor Limited
6 * Copyright (C) 2015 Linaro Ltd.
Jassi Brar0da094d2015-01-19 18:35:53 +08007 */
8
9#include <linux/io.h>
10#include <linux/init.h>
11#include <linux/clk.h>
Ard Biesheuvele1289db2017-10-27 21:21:47 +010012#include <linux/module.h>
Jassi Brar0da094d2015-01-19 18:35:53 +080013#include <linux/err.h>
14#include <linux/errno.h>
15#include <linux/ioport.h>
16#include <linux/of_device.h>
17#include <linux/gpio/driver.h>
18#include <linux/platform_device.h>
19#include <linux/spinlock.h>
20#include <linux/slab.h>
21
22/*
23 * Only first 8bits of a register correspond to each pin,
24 * so there are 4 registers for 32 pins.
25 */
26#define PDR(x) (0x0 + x / 8 * 4)
27#define DDR(x) (0x10 + x / 8 * 4)
28#define PFR(x) (0x20 + x / 8 * 4)
29
30#define OFFSET(x) BIT((x) % 8)
31
32struct mb86s70_gpio_chip {
33 struct gpio_chip gc;
34 void __iomem *base;
35 struct clk *clk;
36 spinlock_t lock;
37};
38
Jassi Brar0da094d2015-01-19 18:35:53 +080039static int mb86s70_gpio_request(struct gpio_chip *gc, unsigned gpio)
40{
Linus Walleij01f76b22015-12-07 10:01:36 +010041 struct mb86s70_gpio_chip *gchip = gpiochip_get_data(gc);
Jassi Brar0da094d2015-01-19 18:35:53 +080042 unsigned long flags;
43 u32 val;
44
45 spin_lock_irqsave(&gchip->lock, flags);
46
47 val = readl(gchip->base + PFR(gpio));
Jassi Brar0da094d2015-01-19 18:35:53 +080048 val &= ~OFFSET(gpio);
49 writel(val, gchip->base + PFR(gpio));
50
51 spin_unlock_irqrestore(&gchip->lock, flags);
52
53 return 0;
54}
55
56static void mb86s70_gpio_free(struct gpio_chip *gc, unsigned gpio)
57{
Linus Walleij01f76b22015-12-07 10:01:36 +010058 struct mb86s70_gpio_chip *gchip = gpiochip_get_data(gc);
Jassi Brar0da094d2015-01-19 18:35:53 +080059 unsigned long flags;
60 u32 val;
61
62 spin_lock_irqsave(&gchip->lock, flags);
63
64 val = readl(gchip->base + PFR(gpio));
65 val |= OFFSET(gpio);
66 writel(val, gchip->base + PFR(gpio));
67
68 spin_unlock_irqrestore(&gchip->lock, flags);
69}
70
71static int mb86s70_gpio_direction_input(struct gpio_chip *gc, unsigned gpio)
72{
Linus Walleij01f76b22015-12-07 10:01:36 +010073 struct mb86s70_gpio_chip *gchip = gpiochip_get_data(gc);
Jassi Brar0da094d2015-01-19 18:35:53 +080074 unsigned long flags;
75 unsigned char val;
76
77 spin_lock_irqsave(&gchip->lock, flags);
78
79 val = readl(gchip->base + DDR(gpio));
80 val &= ~OFFSET(gpio);
81 writel(val, gchip->base + DDR(gpio));
82
83 spin_unlock_irqrestore(&gchip->lock, flags);
84
85 return 0;
86}
87
88static int mb86s70_gpio_direction_output(struct gpio_chip *gc,
89 unsigned gpio, int value)
90{
Linus Walleij01f76b22015-12-07 10:01:36 +010091 struct mb86s70_gpio_chip *gchip = gpiochip_get_data(gc);
Jassi Brar0da094d2015-01-19 18:35:53 +080092 unsigned long flags;
93 unsigned char val;
94
95 spin_lock_irqsave(&gchip->lock, flags);
96
97 val = readl(gchip->base + PDR(gpio));
98 if (value)
99 val |= OFFSET(gpio);
100 else
101 val &= ~OFFSET(gpio);
102 writel(val, gchip->base + PDR(gpio));
103
104 val = readl(gchip->base + DDR(gpio));
105 val |= OFFSET(gpio);
106 writel(val, gchip->base + DDR(gpio));
107
108 spin_unlock_irqrestore(&gchip->lock, flags);
109
110 return 0;
111}
112
113static int mb86s70_gpio_get(struct gpio_chip *gc, unsigned gpio)
114{
Linus Walleij01f76b22015-12-07 10:01:36 +0100115 struct mb86s70_gpio_chip *gchip = gpiochip_get_data(gc);
Jassi Brar0da094d2015-01-19 18:35:53 +0800116
117 return !!(readl(gchip->base + PDR(gpio)) & OFFSET(gpio));
118}
119
120static void mb86s70_gpio_set(struct gpio_chip *gc, unsigned gpio, int value)
121{
Linus Walleij01f76b22015-12-07 10:01:36 +0100122 struct mb86s70_gpio_chip *gchip = gpiochip_get_data(gc);
Jassi Brar0da094d2015-01-19 18:35:53 +0800123 unsigned long flags;
124 unsigned char val;
125
126 spin_lock_irqsave(&gchip->lock, flags);
127
128 val = readl(gchip->base + PDR(gpio));
129 if (value)
130 val |= OFFSET(gpio);
131 else
132 val &= ~OFFSET(gpio);
133 writel(val, gchip->base + PDR(gpio));
134
135 spin_unlock_irqrestore(&gchip->lock, flags);
136}
137
138static int mb86s70_gpio_probe(struct platform_device *pdev)
139{
140 struct mb86s70_gpio_chip *gchip;
Jassi Brar0da094d2015-01-19 18:35:53 +0800141 int ret;
142
143 gchip = devm_kzalloc(&pdev->dev, sizeof(*gchip), GFP_KERNEL);
144 if (gchip == NULL)
145 return -ENOMEM;
146
147 platform_set_drvdata(pdev, gchip);
148
Enrico Weigelt, metux IT consult329e23f2019-03-11 19:54:58 +0100149 gchip->base = devm_platform_ioremap_resource(pdev, 0);
Jassi Brar0da094d2015-01-19 18:35:53 +0800150 if (IS_ERR(gchip->base))
151 return PTR_ERR(gchip->base);
152
153 gchip->clk = devm_clk_get(&pdev->dev, NULL);
154 if (IS_ERR(gchip->clk))
155 return PTR_ERR(gchip->clk);
156
Arvind Yadavd829b372017-08-01 12:13:05 +0530157 ret = clk_prepare_enable(gchip->clk);
158 if (ret)
159 return ret;
Jassi Brar0da094d2015-01-19 18:35:53 +0800160
161 spin_lock_init(&gchip->lock);
162
163 gchip->gc.direction_output = mb86s70_gpio_direction_output;
164 gchip->gc.direction_input = mb86s70_gpio_direction_input;
165 gchip->gc.request = mb86s70_gpio_request;
166 gchip->gc.free = mb86s70_gpio_free;
167 gchip->gc.get = mb86s70_gpio_get;
168 gchip->gc.set = mb86s70_gpio_set;
169 gchip->gc.label = dev_name(&pdev->dev);
170 gchip->gc.ngpio = 32;
171 gchip->gc.owner = THIS_MODULE;
Linus Walleij58383c782015-11-04 09:56:26 +0100172 gchip->gc.parent = &pdev->dev;
Jassi Brar0da094d2015-01-19 18:35:53 +0800173 gchip->gc.base = -1;
174
Linus Walleij01f76b22015-12-07 10:01:36 +0100175 ret = gpiochip_add_data(&gchip->gc, gchip);
Jassi Brar0da094d2015-01-19 18:35:53 +0800176 if (ret) {
177 dev_err(&pdev->dev, "couldn't register gpio driver\n");
178 clk_disable_unprepare(gchip->clk);
179 }
180
181 return ret;
182}
183
184static int mb86s70_gpio_remove(struct platform_device *pdev)
185{
186 struct mb86s70_gpio_chip *gchip = platform_get_drvdata(pdev);
187
188 gpiochip_remove(&gchip->gc);
189 clk_disable_unprepare(gchip->clk);
190
191 return 0;
192}
193
194static const struct of_device_id mb86s70_gpio_dt_ids[] = {
195 { .compatible = "fujitsu,mb86s70-gpio" },
196 { /* sentinel */ }
197};
Ard Biesheuvele1289db2017-10-27 21:21:47 +0100198MODULE_DEVICE_TABLE(of, mb86s70_gpio_dt_ids);
Jassi Brar0da094d2015-01-19 18:35:53 +0800199
200static struct platform_driver mb86s70_gpio_driver = {
201 .driver = {
202 .name = "mb86s70-gpio",
203 .of_match_table = mb86s70_gpio_dt_ids,
204 },
205 .probe = mb86s70_gpio_probe,
206 .remove = mb86s70_gpio_remove,
207};
Ard Biesheuvele1289db2017-10-27 21:21:47 +0100208module_platform_driver(mb86s70_gpio_driver);
Jassi Brar0da094d2015-01-19 18:35:53 +0800209
Ard Biesheuvele1289db2017-10-27 21:21:47 +0100210MODULE_DESCRIPTION("MB86S7x GPIO Driver");
211MODULE_ALIAS("platform:mb86s70-gpio");
212MODULE_LICENSE("GPL");