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