These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / 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
24 #include "serial_mctrl_gpio.h"
25
26 struct mctrl_gpios {
27         struct uart_port *port;
28         struct gpio_desc *gpio[UART_GPIO_MAX];
29         int irq[UART_GPIO_MAX];
30         unsigned int mctrl_prev;
31         bool mctrl_on;
32 };
33
34 static const struct {
35         const char *name;
36         unsigned int mctrl;
37         bool dir_out;
38 } mctrl_gpios_desc[UART_GPIO_MAX] = {
39         { "cts", TIOCM_CTS, false, },
40         { "dsr", TIOCM_DSR, false, },
41         { "dcd", TIOCM_CD, false, },
42         { "rng", TIOCM_RNG, false, },
43         { "rts", TIOCM_RTS, true, },
44         { "dtr", TIOCM_DTR, true, },
45         { "out1", TIOCM_OUT1, true, },
46         { "out2", TIOCM_OUT2, 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         for (i = 0; i < UART_GPIO_MAX; i++)
57                 if (gpios->gpio[i] && mctrl_gpios_desc[i].dir_out) {
58                         desc_array[count] = gpios->gpio[i];
59                         value_array[count] = !!(mctrl & mctrl_gpios_desc[i].mctrl);
60                         count++;
61                 }
62         gpiod_set_array_value(count, desc_array, value_array);
63 }
64 EXPORT_SYMBOL_GPL(mctrl_gpio_set);
65
66 struct gpio_desc *mctrl_gpio_to_gpiod(struct mctrl_gpios *gpios,
67                                       enum mctrl_gpio_idx gidx)
68 {
69         return gpios->gpio[gidx];
70 }
71 EXPORT_SYMBOL_GPL(mctrl_gpio_to_gpiod);
72
73 unsigned int mctrl_gpio_get(struct mctrl_gpios *gpios, unsigned int *mctrl)
74 {
75         enum mctrl_gpio_idx i;
76
77         for (i = 0; i < UART_GPIO_MAX; i++) {
78                 if (gpios->gpio[i] && !mctrl_gpios_desc[i].dir_out) {
79                         if (gpiod_get_value(gpios->gpio[i]))
80                                 *mctrl |= mctrl_gpios_desc[i].mctrl;
81                         else
82                                 *mctrl &= ~mctrl_gpios_desc[i].mctrl;
83                 }
84         }
85
86         return *mctrl;
87 }
88 EXPORT_SYMBOL_GPL(mctrl_gpio_get);
89
90 struct mctrl_gpios *mctrl_gpio_init_noauto(struct device *dev, unsigned int idx)
91 {
92         struct mctrl_gpios *gpios;
93         enum mctrl_gpio_idx i;
94
95         gpios = devm_kzalloc(dev, sizeof(*gpios), GFP_KERNEL);
96         if (!gpios)
97                 return ERR_PTR(-ENOMEM);
98
99         for (i = 0; i < UART_GPIO_MAX; i++) {
100                 enum gpiod_flags flags;
101
102                 if (mctrl_gpios_desc[i].dir_out)
103                         flags = GPIOD_OUT_LOW;
104                 else
105                         flags = GPIOD_IN;
106
107                 gpios->gpio[i] =
108                         devm_gpiod_get_index_optional(dev,
109                                                       mctrl_gpios_desc[i].name,
110                                                       idx, flags);
111
112                 if (IS_ERR(gpios->gpio[i]))
113                         return ERR_CAST(gpios->gpio[i]);
114         }
115
116         return gpios;
117 }
118 EXPORT_SYMBOL_GPL(mctrl_gpio_init_noauto);
119
120 #define MCTRL_ANY_DELTA (TIOCM_RI | TIOCM_DSR | TIOCM_CD | TIOCM_CTS)
121 static irqreturn_t mctrl_gpio_irq_handle(int irq, void *context)
122 {
123         struct mctrl_gpios *gpios = context;
124         struct uart_port *port = gpios->port;
125         u32 mctrl = gpios->mctrl_prev;
126         u32 mctrl_diff;
127
128         mctrl_gpio_get(gpios, &mctrl);
129
130         mctrl_diff = mctrl ^ gpios->mctrl_prev;
131         gpios->mctrl_prev = mctrl;
132
133         if (mctrl_diff & MCTRL_ANY_DELTA && port->state != NULL) {
134                 if ((mctrl_diff & mctrl) & TIOCM_RI)
135                         port->icount.rng++;
136
137                 if ((mctrl_diff & mctrl) & TIOCM_DSR)
138                         port->icount.dsr++;
139
140                 if (mctrl_diff & TIOCM_CD)
141                         uart_handle_dcd_change(port, mctrl & TIOCM_CD);
142
143                 if (mctrl_diff & TIOCM_CTS)
144                         uart_handle_cts_change(port, mctrl & TIOCM_CTS);
145
146                 wake_up_interruptible(&port->state->port.delta_msr_wait);
147         }
148
149         return IRQ_HANDLED;
150 }
151
152 struct mctrl_gpios *mctrl_gpio_init(struct uart_port *port, unsigned int idx)
153 {
154         struct mctrl_gpios *gpios;
155         enum mctrl_gpio_idx i;
156
157         gpios = mctrl_gpio_init_noauto(port->dev, idx);
158         if (IS_ERR(gpios))
159                 return gpios;
160
161         gpios->port = port;
162
163         for (i = 0; i < UART_GPIO_MAX; ++i) {
164                 int ret;
165
166                 if (!gpios->gpio[i] || mctrl_gpios_desc[i].dir_out)
167                         continue;
168
169                 ret = gpiod_to_irq(gpios->gpio[i]);
170                 if (ret <= 0) {
171                         dev_err(port->dev,
172                                 "failed to find corresponding irq for %s (idx=%d, err=%d)\n",
173                                 mctrl_gpios_desc[i].name, idx, ret);
174                         return ERR_PTR(ret);
175                 }
176                 gpios->irq[i] = ret;
177
178                 /* irqs should only be enabled in .enable_ms */
179                 irq_set_status_flags(gpios->irq[i], IRQ_NOAUTOEN);
180
181                 ret = devm_request_irq(port->dev, gpios->irq[i],
182                                        mctrl_gpio_irq_handle,
183                                        IRQ_TYPE_EDGE_BOTH, dev_name(port->dev),
184                                        gpios);
185                 if (ret) {
186                         /* alternatively implement polling */
187                         dev_err(port->dev,
188                                 "failed to request irq for %s (idx=%d, err=%d)\n",
189                                 mctrl_gpios_desc[i].name, idx, ret);
190                         return ERR_PTR(ret);
191                 }
192         }
193
194         return gpios;
195 }
196
197 void mctrl_gpio_free(struct device *dev, struct mctrl_gpios *gpios)
198 {
199         enum mctrl_gpio_idx i;
200
201         for (i = 0; i < UART_GPIO_MAX; i++) {
202                 if (gpios->irq[i])
203                         devm_free_irq(gpios->port->dev, gpios->irq[i], gpios);
204
205                 if (gpios->gpio[i])
206                         devm_gpiod_put(dev, gpios->gpio[i]);
207         }
208         devm_kfree(dev, gpios);
209 }
210 EXPORT_SYMBOL_GPL(mctrl_gpio_free);
211
212 void mctrl_gpio_enable_ms(struct mctrl_gpios *gpios)
213 {
214         enum mctrl_gpio_idx i;
215
216         /* .enable_ms may be called multiple times */
217         if (gpios->mctrl_on)
218                 return;
219
220         gpios->mctrl_on = true;
221
222         /* get initial status of modem lines GPIOs */
223         mctrl_gpio_get(gpios, &gpios->mctrl_prev);
224
225         for (i = 0; i < UART_GPIO_MAX; ++i) {
226                 if (!gpios->irq[i])
227                         continue;
228
229                 enable_irq(gpios->irq[i]);
230         }
231 }
232 EXPORT_SYMBOL_GPL(mctrl_gpio_enable_ms);
233
234 void mctrl_gpio_disable_ms(struct mctrl_gpios *gpios)
235 {
236         enum mctrl_gpio_idx i;
237
238         if (!gpios->mctrl_on)
239                 return;
240
241         gpios->mctrl_on = false;
242
243         for (i = 0; i < UART_GPIO_MAX; ++i) {
244                 if (!gpios->irq[i])
245                         continue;
246
247                 disable_irq(gpios->irq[i]);
248         }
249 }