Merge tag 'sunxi-config64-for-5.4-1' of git://git.kernel.org/pub/scm/linux/kernel...
[linux-2.6-microblaze.git] / drivers / tty / serial / serial_mctrl_gpio.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Helpers for controlling modem lines via GPIO
4  *
5  * Copyright (C) 2014 Paratronic S.A.
6  */
7
8 #include <linux/err.h>
9 #include <linux/device.h>
10 #include <linux/irq.h>
11 #include <linux/gpio/consumer.h>
12 #include <linux/termios.h>
13 #include <linux/serial_core.h>
14 #include <linux/module.h>
15 #include <linux/property.h>
16
17 #include "serial_mctrl_gpio.h"
18
19 struct mctrl_gpios {
20         struct uart_port *port;
21         struct gpio_desc *gpio[UART_GPIO_MAX];
22         int irq[UART_GPIO_MAX];
23         unsigned int mctrl_prev;
24         bool mctrl_on;
25 };
26
27 static const struct {
28         const char *name;
29         unsigned int mctrl;
30         bool dir_out;
31 } mctrl_gpios_desc[UART_GPIO_MAX] = {
32         { "cts", TIOCM_CTS, false, },
33         { "dsr", TIOCM_DSR, false, },
34         { "dcd", TIOCM_CD, false, },
35         { "rng", TIOCM_RNG, false, },
36         { "rts", TIOCM_RTS, true, },
37         { "dtr", TIOCM_DTR, true, },
38 };
39
40 void mctrl_gpio_set(struct mctrl_gpios *gpios, unsigned int mctrl)
41 {
42         enum mctrl_gpio_idx i;
43         struct gpio_desc *desc_array[UART_GPIO_MAX];
44         DECLARE_BITMAP(values, UART_GPIO_MAX);
45         unsigned int count = 0;
46
47         if (gpios == NULL)
48                 return;
49
50         for (i = 0; i < UART_GPIO_MAX; i++)
51                 if (gpios->gpio[i] && mctrl_gpios_desc[i].dir_out) {
52                         desc_array[count] = gpios->gpio[i];
53                         __assign_bit(count, values,
54                                      mctrl & mctrl_gpios_desc[i].mctrl);
55                         count++;
56                 }
57         gpiod_set_array_value(count, desc_array, NULL, values);
58 }
59 EXPORT_SYMBOL_GPL(mctrl_gpio_set);
60
61 struct gpio_desc *mctrl_gpio_to_gpiod(struct mctrl_gpios *gpios,
62                                       enum mctrl_gpio_idx gidx)
63 {
64         return gpios->gpio[gidx];
65 }
66 EXPORT_SYMBOL_GPL(mctrl_gpio_to_gpiod);
67
68 unsigned int mctrl_gpio_get(struct mctrl_gpios *gpios, unsigned int *mctrl)
69 {
70         enum mctrl_gpio_idx i;
71
72         if (gpios == NULL)
73                 return *mctrl;
74
75         for (i = 0; i < UART_GPIO_MAX; i++) {
76                 if (gpios->gpio[i] && !mctrl_gpios_desc[i].dir_out) {
77                         if (gpiod_get_value(gpios->gpio[i]))
78                                 *mctrl |= mctrl_gpios_desc[i].mctrl;
79                         else
80                                 *mctrl &= ~mctrl_gpios_desc[i].mctrl;
81                 }
82         }
83
84         return *mctrl;
85 }
86 EXPORT_SYMBOL_GPL(mctrl_gpio_get);
87
88 unsigned int
89 mctrl_gpio_get_outputs(struct mctrl_gpios *gpios, unsigned int *mctrl)
90 {
91         enum mctrl_gpio_idx i;
92
93         if (gpios == NULL)
94                 return *mctrl;
95
96         for (i = 0; i < UART_GPIO_MAX; i++) {
97                 if (gpios->gpio[i] && mctrl_gpios_desc[i].dir_out) {
98                         if (gpiod_get_value(gpios->gpio[i]))
99                                 *mctrl |= mctrl_gpios_desc[i].mctrl;
100                         else
101                                 *mctrl &= ~mctrl_gpios_desc[i].mctrl;
102                 }
103         }
104
105         return *mctrl;
106 }
107 EXPORT_SYMBOL_GPL(mctrl_gpio_get_outputs);
108
109 struct mctrl_gpios *mctrl_gpio_init_noauto(struct device *dev, unsigned int idx)
110 {
111         struct mctrl_gpios *gpios;
112         enum mctrl_gpio_idx i;
113
114         gpios = devm_kzalloc(dev, sizeof(*gpios), GFP_KERNEL);
115         if (!gpios)
116                 return ERR_PTR(-ENOMEM);
117
118         for (i = 0; i < UART_GPIO_MAX; i++) {
119                 enum gpiod_flags flags;
120                 char *gpio_str;
121                 bool present;
122
123                 /* Check if GPIO property exists and continue if not */
124                 gpio_str = kasprintf(GFP_KERNEL, "%s-gpios",
125                                      mctrl_gpios_desc[i].name);
126                 if (!gpio_str)
127                         continue;
128
129                 present = device_property_present(dev, gpio_str);
130                 kfree(gpio_str);
131                 if (!present)
132                         continue;
133
134                 if (mctrl_gpios_desc[i].dir_out)
135                         flags = GPIOD_OUT_LOW;
136                 else
137                         flags = GPIOD_IN;
138
139                 gpios->gpio[i] =
140                         devm_gpiod_get_index_optional(dev,
141                                                       mctrl_gpios_desc[i].name,
142                                                       idx, flags);
143
144                 if (IS_ERR(gpios->gpio[i]))
145                         return ERR_CAST(gpios->gpio[i]);
146         }
147
148         return gpios;
149 }
150 EXPORT_SYMBOL_GPL(mctrl_gpio_init_noauto);
151
152 #define MCTRL_ANY_DELTA (TIOCM_RI | TIOCM_DSR | TIOCM_CD | TIOCM_CTS)
153 static irqreturn_t mctrl_gpio_irq_handle(int irq, void *context)
154 {
155         struct mctrl_gpios *gpios = context;
156         struct uart_port *port = gpios->port;
157         u32 mctrl = gpios->mctrl_prev;
158         u32 mctrl_diff;
159         unsigned long flags;
160
161         mctrl_gpio_get(gpios, &mctrl);
162
163         spin_lock_irqsave(&port->lock, flags);
164
165         mctrl_diff = mctrl ^ gpios->mctrl_prev;
166         gpios->mctrl_prev = mctrl;
167
168         if (mctrl_diff & MCTRL_ANY_DELTA && port->state != NULL) {
169                 if ((mctrl_diff & mctrl) & TIOCM_RI)
170                         port->icount.rng++;
171
172                 if ((mctrl_diff & mctrl) & TIOCM_DSR)
173                         port->icount.dsr++;
174
175                 if (mctrl_diff & TIOCM_CD)
176                         uart_handle_dcd_change(port, mctrl & TIOCM_CD);
177
178                 if (mctrl_diff & TIOCM_CTS)
179                         uart_handle_cts_change(port, mctrl & TIOCM_CTS);
180
181                 wake_up_interruptible(&port->state->port.delta_msr_wait);
182         }
183
184         spin_unlock_irqrestore(&port->lock, flags);
185
186         return IRQ_HANDLED;
187 }
188
189 struct mctrl_gpios *mctrl_gpio_init(struct uart_port *port, unsigned int idx)
190 {
191         struct mctrl_gpios *gpios;
192         enum mctrl_gpio_idx i;
193
194         gpios = mctrl_gpio_init_noauto(port->dev, idx);
195         if (IS_ERR(gpios))
196                 return gpios;
197
198         gpios->port = port;
199
200         for (i = 0; i < UART_GPIO_MAX; ++i) {
201                 int ret;
202
203                 if (!gpios->gpio[i] || mctrl_gpios_desc[i].dir_out)
204                         continue;
205
206                 ret = gpiod_to_irq(gpios->gpio[i]);
207                 if (ret <= 0) {
208                         dev_err(port->dev,
209                                 "failed to find corresponding irq for %s (idx=%d, err=%d)\n",
210                                 mctrl_gpios_desc[i].name, idx, ret);
211                         return ERR_PTR(ret);
212                 }
213                 gpios->irq[i] = ret;
214
215                 /* irqs should only be enabled in .enable_ms */
216                 irq_set_status_flags(gpios->irq[i], IRQ_NOAUTOEN);
217
218                 ret = devm_request_irq(port->dev, gpios->irq[i],
219                                        mctrl_gpio_irq_handle,
220                                        IRQ_TYPE_EDGE_BOTH, dev_name(port->dev),
221                                        gpios);
222                 if (ret) {
223                         /* alternatively implement polling */
224                         dev_err(port->dev,
225                                 "failed to request irq for %s (idx=%d, err=%d)\n",
226                                 mctrl_gpios_desc[i].name, idx, ret);
227                         return ERR_PTR(ret);
228                 }
229         }
230
231         return gpios;
232 }
233 EXPORT_SYMBOL_GPL(mctrl_gpio_init);
234
235 void mctrl_gpio_free(struct device *dev, struct mctrl_gpios *gpios)
236 {
237         enum mctrl_gpio_idx i;
238
239         if (gpios == NULL)
240                 return;
241
242         for (i = 0; i < UART_GPIO_MAX; i++) {
243                 if (gpios->irq[i])
244                         devm_free_irq(gpios->port->dev, gpios->irq[i], gpios);
245
246                 if (gpios->gpio[i])
247                         devm_gpiod_put(dev, gpios->gpio[i]);
248         }
249         devm_kfree(dev, gpios);
250 }
251 EXPORT_SYMBOL_GPL(mctrl_gpio_free);
252
253 void mctrl_gpio_enable_ms(struct mctrl_gpios *gpios)
254 {
255         enum mctrl_gpio_idx i;
256
257         if (gpios == NULL)
258                 return;
259
260         /* .enable_ms may be called multiple times */
261         if (gpios->mctrl_on)
262                 return;
263
264         gpios->mctrl_on = true;
265
266         /* get initial status of modem lines GPIOs */
267         mctrl_gpio_get(gpios, &gpios->mctrl_prev);
268
269         for (i = 0; i < UART_GPIO_MAX; ++i) {
270                 if (!gpios->irq[i])
271                         continue;
272
273                 enable_irq(gpios->irq[i]);
274         }
275 }
276 EXPORT_SYMBOL_GPL(mctrl_gpio_enable_ms);
277
278 void mctrl_gpio_disable_ms(struct mctrl_gpios *gpios)
279 {
280         enum mctrl_gpio_idx i;
281
282         if (gpios == NULL)
283                 return;
284
285         if (!gpios->mctrl_on)
286                 return;
287
288         gpios->mctrl_on = false;
289
290         for (i = 0; i < UART_GPIO_MAX; ++i) {
291                 if (!gpios->irq[i])
292                         continue;
293
294                 disable_irq(gpios->irq[i]);
295         }
296 }
297 EXPORT_SYMBOL_GPL(mctrl_gpio_disable_ms);
298
299 MODULE_LICENSE("GPL");