drm/vc4: txp: Protect device resources
[platform/kernel/linux-starfive.git] / drivers / gpio / gpio-siox.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (C) 2015-2018 Pengutronix, Uwe Kleine-König <kernel@pengutronix.de>
4  */
5
6 #include <linux/module.h>
7 #include <linux/siox.h>
8 #include <linux/gpio/driver.h>
9 #include <linux/of.h>
10
11 struct gpio_siox_ddata {
12         struct gpio_chip gchip;
13         struct irq_chip ichip;
14         struct mutex lock;
15         u8 setdata[1];
16         u8 getdata[3];
17
18         raw_spinlock_t irqlock;
19         u32 irq_enable;
20         u32 irq_status;
21         u32 irq_type[20];
22 };
23
24 /*
25  * Note that this callback only sets the value that is clocked out in the next
26  * cycle.
27  */
28 static int gpio_siox_set_data(struct siox_device *sdevice, u8 status, u8 buf[])
29 {
30         struct gpio_siox_ddata *ddata = dev_get_drvdata(&sdevice->dev);
31
32         mutex_lock(&ddata->lock);
33         buf[0] = ddata->setdata[0];
34         mutex_unlock(&ddata->lock);
35
36         return 0;
37 }
38
39 static int gpio_siox_get_data(struct siox_device *sdevice, const u8 buf[])
40 {
41         struct gpio_siox_ddata *ddata = dev_get_drvdata(&sdevice->dev);
42         size_t offset;
43         u32 trigger;
44
45         mutex_lock(&ddata->lock);
46
47         raw_spin_lock_irq(&ddata->irqlock);
48
49         for (offset = 0; offset < 12; ++offset) {
50                 unsigned int bitpos = 11 - offset;
51                 unsigned int gpiolevel = buf[bitpos / 8] & (1 << bitpos % 8);
52                 unsigned int prev_level =
53                         ddata->getdata[bitpos / 8] & (1 << (bitpos % 8));
54                 u32 irq_type = ddata->irq_type[offset];
55
56                 if (gpiolevel) {
57                         if ((irq_type & IRQ_TYPE_LEVEL_HIGH) ||
58                             ((irq_type & IRQ_TYPE_EDGE_RISING) && !prev_level))
59                                 ddata->irq_status |= 1 << offset;
60                 } else {
61                         if ((irq_type & IRQ_TYPE_LEVEL_LOW) ||
62                             ((irq_type & IRQ_TYPE_EDGE_FALLING) && prev_level))
63                                 ddata->irq_status |= 1 << offset;
64                 }
65         }
66
67         trigger = ddata->irq_status & ddata->irq_enable;
68
69         raw_spin_unlock_irq(&ddata->irqlock);
70
71         ddata->getdata[0] = buf[0];
72         ddata->getdata[1] = buf[1];
73         ddata->getdata[2] = buf[2];
74
75         mutex_unlock(&ddata->lock);
76
77         for (offset = 0; offset < 12; ++offset) {
78                 if (trigger & (1 << offset)) {
79                         struct irq_domain *irqdomain = ddata->gchip.irq.domain;
80                         unsigned int irq = irq_find_mapping(irqdomain, offset);
81
82                         /*
83                          * Conceptually handle_nested_irq should call the flow
84                          * handler of the irq chip. But it doesn't, so we have
85                          * to clean the irq_status here.
86                          */
87                         raw_spin_lock_irq(&ddata->irqlock);
88                         ddata->irq_status &= ~(1 << offset);
89                         raw_spin_unlock_irq(&ddata->irqlock);
90
91                         handle_nested_irq(irq);
92                 }
93         }
94
95         return 0;
96 }
97
98 static void gpio_siox_irq_ack(struct irq_data *d)
99 {
100         struct irq_chip *ic = irq_data_get_irq_chip(d);
101         struct gpio_siox_ddata *ddata =
102                 container_of(ic, struct gpio_siox_ddata, ichip);
103
104         raw_spin_lock(&ddata->irqlock);
105         ddata->irq_status &= ~(1 << d->hwirq);
106         raw_spin_unlock(&ddata->irqlock);
107 }
108
109 static void gpio_siox_irq_mask(struct irq_data *d)
110 {
111         struct irq_chip *ic = irq_data_get_irq_chip(d);
112         struct gpio_siox_ddata *ddata =
113                 container_of(ic, struct gpio_siox_ddata, ichip);
114
115         raw_spin_lock(&ddata->irqlock);
116         ddata->irq_enable &= ~(1 << d->hwirq);
117         raw_spin_unlock(&ddata->irqlock);
118 }
119
120 static void gpio_siox_irq_unmask(struct irq_data *d)
121 {
122         struct irq_chip *ic = irq_data_get_irq_chip(d);
123         struct gpio_siox_ddata *ddata =
124                 container_of(ic, struct gpio_siox_ddata, ichip);
125
126         raw_spin_lock(&ddata->irqlock);
127         ddata->irq_enable |= 1 << d->hwirq;
128         raw_spin_unlock(&ddata->irqlock);
129 }
130
131 static int gpio_siox_irq_set_type(struct irq_data *d, u32 type)
132 {
133         struct irq_chip *ic = irq_data_get_irq_chip(d);
134         struct gpio_siox_ddata *ddata =
135                 container_of(ic, struct gpio_siox_ddata, ichip);
136
137         raw_spin_lock(&ddata->irqlock);
138         ddata->irq_type[d->hwirq] = type;
139         raw_spin_unlock(&ddata->irqlock);
140
141         return 0;
142 }
143
144 static int gpio_siox_get(struct gpio_chip *chip, unsigned int offset)
145 {
146         struct gpio_siox_ddata *ddata =
147                 container_of(chip, struct gpio_siox_ddata, gchip);
148         int ret;
149
150         mutex_lock(&ddata->lock);
151
152         if (offset >= 12) {
153                 unsigned int bitpos = 19 - offset;
154
155                 ret = ddata->setdata[0] & (1 << bitpos);
156         } else {
157                 unsigned int bitpos = 11 - offset;
158
159                 ret = ddata->getdata[bitpos / 8] & (1 << (bitpos % 8));
160         }
161
162         mutex_unlock(&ddata->lock);
163
164         return ret;
165 }
166
167 static void gpio_siox_set(struct gpio_chip *chip,
168                           unsigned int offset, int value)
169 {
170         struct gpio_siox_ddata *ddata =
171                 container_of(chip, struct gpio_siox_ddata, gchip);
172         u8 mask = 1 << (19 - offset);
173
174         mutex_lock(&ddata->lock);
175
176         if (value)
177                 ddata->setdata[0] |= mask;
178         else
179                 ddata->setdata[0] &= ~mask;
180
181         mutex_unlock(&ddata->lock);
182 }
183
184 static int gpio_siox_direction_input(struct gpio_chip *chip,
185                                      unsigned int offset)
186 {
187         if (offset >= 12)
188                 return -EINVAL;
189
190         return 0;
191 }
192
193 static int gpio_siox_direction_output(struct gpio_chip *chip,
194                                       unsigned int offset, int value)
195 {
196         if (offset < 12)
197                 return -EINVAL;
198
199         gpio_siox_set(chip, offset, value);
200         return 0;
201 }
202
203 static int gpio_siox_get_direction(struct gpio_chip *chip, unsigned int offset)
204 {
205         if (offset < 12)
206                 return GPIO_LINE_DIRECTION_IN;
207         else
208                 return GPIO_LINE_DIRECTION_OUT;
209 }
210
211 static int gpio_siox_probe(struct siox_device *sdevice)
212 {
213         struct gpio_siox_ddata *ddata;
214         struct gpio_irq_chip *girq;
215         struct device *dev = &sdevice->dev;
216         int ret;
217
218         ddata = devm_kzalloc(dev, sizeof(*ddata), GFP_KERNEL);
219         if (!ddata)
220                 return -ENOMEM;
221
222         dev_set_drvdata(dev, ddata);
223
224         mutex_init(&ddata->lock);
225         raw_spin_lock_init(&ddata->irqlock);
226
227         ddata->gchip.base = -1;
228         ddata->gchip.can_sleep = 1;
229         ddata->gchip.parent = dev;
230         ddata->gchip.owner = THIS_MODULE;
231         ddata->gchip.get = gpio_siox_get;
232         ddata->gchip.set = gpio_siox_set;
233         ddata->gchip.direction_input = gpio_siox_direction_input;
234         ddata->gchip.direction_output = gpio_siox_direction_output;
235         ddata->gchip.get_direction = gpio_siox_get_direction;
236         ddata->gchip.ngpio = 20;
237
238         ddata->ichip.name = "siox-gpio";
239         ddata->ichip.irq_ack = gpio_siox_irq_ack;
240         ddata->ichip.irq_mask = gpio_siox_irq_mask;
241         ddata->ichip.irq_unmask = gpio_siox_irq_unmask;
242         ddata->ichip.irq_set_type = gpio_siox_irq_set_type;
243
244         girq = &ddata->gchip.irq;
245         girq->chip = &ddata->ichip;
246         girq->default_type = IRQ_TYPE_NONE;
247         girq->handler = handle_level_irq;
248         girq->threaded = true;
249
250         ret = devm_gpiochip_add_data(dev, &ddata->gchip, NULL);
251         if (ret)
252                 dev_err(dev, "Failed to register gpio chip (%d)\n", ret);
253
254         return ret;
255 }
256
257 static struct siox_driver gpio_siox_driver = {
258         .probe = gpio_siox_probe,
259         .set_data = gpio_siox_set_data,
260         .get_data = gpio_siox_get_data,
261         .driver = {
262                 .name = "gpio-siox",
263         },
264 };
265 module_siox_driver(gpio_siox_driver);
266
267 MODULE_AUTHOR("Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>");
268 MODULE_DESCRIPTION("SIOX gpio driver");
269 MODULE_LICENSE("GPL v2");