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