xref: /linux/drivers/tty/serial/serial_mctrl_gpio.c (revision a1ff5a7d78a036d6c2178ee5acd6ba4946243800)
1e3b3d0f5SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0+
284130aacSRichard Genoud /*
384130aacSRichard Genoud  * Helpers for controlling modem lines via GPIO
484130aacSRichard Genoud  *
584130aacSRichard Genoud  * Copyright (C) 2014 Paratronic S.A.
684130aacSRichard Genoud  */
784130aacSRichard Genoud 
884130aacSRichard Genoud #include <linux/err.h>
984130aacSRichard Genoud #include <linux/device.h>
10ce59e48fSUwe Kleine-König #include <linux/irq.h>
1184130aacSRichard Genoud #include <linux/gpio/consumer.h>
1293b88774SAlexander Shiyan #include <linux/termios.h>
13ce59e48fSUwe Kleine-König #include <linux/serial_core.h>
1482a3f87fSRomain Izard #include <linux/module.h>
15d9948267SStefan Roese #include <linux/property.h>
1684130aacSRichard Genoud 
1784130aacSRichard Genoud #include "serial_mctrl_gpio.h"
1884130aacSRichard Genoud 
1984130aacSRichard Genoud struct mctrl_gpios {
20ce59e48fSUwe Kleine-König 	struct uart_port *port;
2184130aacSRichard Genoud 	struct gpio_desc *gpio[UART_GPIO_MAX];
22ce59e48fSUwe Kleine-König 	int irq[UART_GPIO_MAX];
23ce59e48fSUwe Kleine-König 	unsigned int mctrl_prev;
24ce59e48fSUwe Kleine-König 	bool mctrl_on;
2584130aacSRichard Genoud };
2684130aacSRichard Genoud 
2784130aacSRichard Genoud static const struct {
2884130aacSRichard Genoud 	const char *name;
2984130aacSRichard Genoud 	unsigned int mctrl;
304ad8e34dSAndy Shevchenko 	enum gpiod_flags flags;
3184130aacSRichard Genoud } mctrl_gpios_desc[UART_GPIO_MAX] = {
324ad8e34dSAndy Shevchenko 	{ "cts", TIOCM_CTS, GPIOD_IN, },
334ad8e34dSAndy Shevchenko 	{ "dsr", TIOCM_DSR, GPIOD_IN, },
344ad8e34dSAndy Shevchenko 	{ "dcd", TIOCM_CD,  GPIOD_IN, },
354ad8e34dSAndy Shevchenko 	{ "rng", TIOCM_RNG, GPIOD_IN, },
364ad8e34dSAndy Shevchenko 	{ "rts", TIOCM_RTS, GPIOD_OUT_LOW, },
374ad8e34dSAndy Shevchenko 	{ "dtr", TIOCM_DTR, GPIOD_OUT_LOW, },
3884130aacSRichard Genoud };
3984130aacSRichard Genoud 
mctrl_gpio_flags_is_dir_out(unsigned int idx)404ad8e34dSAndy Shevchenko static bool mctrl_gpio_flags_is_dir_out(unsigned int idx)
414ad8e34dSAndy Shevchenko {
424ad8e34dSAndy Shevchenko 	return mctrl_gpios_desc[idx].flags & GPIOD_FLAGS_BIT_DIR_OUT;
434ad8e34dSAndy Shevchenko }
444ad8e34dSAndy Shevchenko 
4527940abdSJiri Slaby /**
4627940abdSJiri Slaby  * mctrl_gpio_set - set gpios according to mctrl state
4727940abdSJiri Slaby  * @gpios: gpios to set
4827940abdSJiri Slaby  * @mctrl: state to set
4927940abdSJiri Slaby  *
5027940abdSJiri Slaby  * Set the gpios according to the mctrl state.
5127940abdSJiri Slaby  */
mctrl_gpio_set(struct mctrl_gpios * gpios,unsigned int mctrl)5284130aacSRichard Genoud void mctrl_gpio_set(struct mctrl_gpios *gpios, unsigned int mctrl)
5384130aacSRichard Genoud {
5484130aacSRichard Genoud 	enum mctrl_gpio_idx i;
55834296a3SRojhalat Ibrahim 	struct gpio_desc *desc_array[UART_GPIO_MAX];
56b9762bebSJanusz Krzysztofik 	DECLARE_BITMAP(values, UART_GPIO_MAX);
57834296a3SRojhalat Ibrahim 	unsigned int count = 0;
5884130aacSRichard Genoud 
59434be0aeSYegor Yefremov 	if (gpios == NULL)
60434be0aeSYegor Yefremov 		return;
61434be0aeSYegor Yefremov 
6284130aacSRichard Genoud 	for (i = 0; i < UART_GPIO_MAX; i++)
634ad8e34dSAndy Shevchenko 		if (gpios->gpio[i] && mctrl_gpio_flags_is_dir_out(i)) {
64834296a3SRojhalat Ibrahim 			desc_array[count] = gpios->gpio[i];
65b9762bebSJanusz Krzysztofik 			__assign_bit(count, values,
66b9762bebSJanusz Krzysztofik 				     mctrl & mctrl_gpios_desc[i].mctrl);
67834296a3SRojhalat Ibrahim 			count++;
68834296a3SRojhalat Ibrahim 		}
6977588c14SJanusz Krzysztofik 	gpiod_set_array_value(count, desc_array, NULL, values);
7084130aacSRichard Genoud }
7184130aacSRichard Genoud EXPORT_SYMBOL_GPL(mctrl_gpio_set);
7284130aacSRichard Genoud 
7327940abdSJiri Slaby /**
7427940abdSJiri Slaby  * mctrl_gpio_to_gpiod - obtain gpio_desc of modem line index
7527940abdSJiri Slaby  * @gpios: gpios to look into
7627940abdSJiri Slaby  * @gidx: index of the modem line
7727940abdSJiri Slaby  * Returns: the gpio_desc structure associated to the modem line index
7827940abdSJiri Slaby  */
mctrl_gpio_to_gpiod(struct mctrl_gpios * gpios,enum mctrl_gpio_idx gidx)7984130aacSRichard Genoud struct gpio_desc *mctrl_gpio_to_gpiod(struct mctrl_gpios *gpios,
8084130aacSRichard Genoud 				      enum mctrl_gpio_idx gidx)
8184130aacSRichard Genoud {
8237e3ab00SAdam Ford 	if (gpios == NULL)
8337e3ab00SAdam Ford 		return NULL;
8437e3ab00SAdam Ford 
8584130aacSRichard Genoud 	return gpios->gpio[gidx];
8684130aacSRichard Genoud }
8784130aacSRichard Genoud EXPORT_SYMBOL_GPL(mctrl_gpio_to_gpiod);
8884130aacSRichard Genoud 
8927940abdSJiri Slaby /**
9027940abdSJiri Slaby  * mctrl_gpio_get - update mctrl with the gpios values.
9127940abdSJiri Slaby  * @gpios: gpios to get the info from
9227940abdSJiri Slaby  * @mctrl: mctrl to set
9327940abdSJiri Slaby  * Returns: modified mctrl (the same value as in @mctrl)
9427940abdSJiri Slaby  *
9527940abdSJiri Slaby  * Update mctrl with the gpios values.
9627940abdSJiri Slaby  */
mctrl_gpio_get(struct mctrl_gpios * gpios,unsigned int * mctrl)9784130aacSRichard Genoud unsigned int mctrl_gpio_get(struct mctrl_gpios *gpios, unsigned int *mctrl)
9884130aacSRichard Genoud {
9984130aacSRichard Genoud 	enum mctrl_gpio_idx i;
10084130aacSRichard Genoud 
101434be0aeSYegor Yefremov 	if (gpios == NULL)
102434be0aeSYegor Yefremov 		return *mctrl;
103434be0aeSYegor Yefremov 
10484130aacSRichard Genoud 	for (i = 0; i < UART_GPIO_MAX; i++) {
1054ad8e34dSAndy Shevchenko 		if (gpios->gpio[i] && !mctrl_gpio_flags_is_dir_out(i)) {
10684130aacSRichard Genoud 			if (gpiod_get_value(gpios->gpio[i]))
10784130aacSRichard Genoud 				*mctrl |= mctrl_gpios_desc[i].mctrl;
10884130aacSRichard Genoud 			else
10984130aacSRichard Genoud 				*mctrl &= ~mctrl_gpios_desc[i].mctrl;
11084130aacSRichard Genoud 		}
11184130aacSRichard Genoud 	}
11284130aacSRichard Genoud 
11384130aacSRichard Genoud 	return *mctrl;
11484130aacSRichard Genoud }
11584130aacSRichard Genoud EXPORT_SYMBOL_GPL(mctrl_gpio_get);
11684130aacSRichard Genoud 
117bf5cee68SYegor Yefremov unsigned int
mctrl_gpio_get_outputs(struct mctrl_gpios * gpios,unsigned int * mctrl)118bf5cee68SYegor Yefremov mctrl_gpio_get_outputs(struct mctrl_gpios *gpios, unsigned int *mctrl)
119bf5cee68SYegor Yefremov {
120bf5cee68SYegor Yefremov 	enum mctrl_gpio_idx i;
121bf5cee68SYegor Yefremov 
122434be0aeSYegor Yefremov 	if (gpios == NULL)
123434be0aeSYegor Yefremov 		return *mctrl;
124434be0aeSYegor Yefremov 
125bf5cee68SYegor Yefremov 	for (i = 0; i < UART_GPIO_MAX; i++) {
1264ad8e34dSAndy Shevchenko 		if (gpios->gpio[i] && mctrl_gpio_flags_is_dir_out(i)) {
127bf5cee68SYegor Yefremov 			if (gpiod_get_value(gpios->gpio[i]))
128bf5cee68SYegor Yefremov 				*mctrl |= mctrl_gpios_desc[i].mctrl;
129bf5cee68SYegor Yefremov 			else
130bf5cee68SYegor Yefremov 				*mctrl &= ~mctrl_gpios_desc[i].mctrl;
131bf5cee68SYegor Yefremov 		}
132bf5cee68SYegor Yefremov 	}
133bf5cee68SYegor Yefremov 
134bf5cee68SYegor Yefremov 	return *mctrl;
135bf5cee68SYegor Yefremov }
136bf5cee68SYegor Yefremov EXPORT_SYMBOL_GPL(mctrl_gpio_get_outputs);
137bf5cee68SYegor Yefremov 
mctrl_gpio_init_noauto(struct device * dev,unsigned int idx)1387d8c70d8SUwe Kleine-König struct mctrl_gpios *mctrl_gpio_init_noauto(struct device *dev, unsigned int idx)
13984130aacSRichard Genoud {
14084130aacSRichard Genoud 	struct mctrl_gpios *gpios;
14184130aacSRichard Genoud 	enum mctrl_gpio_idx i;
14284130aacSRichard Genoud 
14384130aacSRichard Genoud 	gpios = devm_kzalloc(dev, sizeof(*gpios), GFP_KERNEL);
14484130aacSRichard Genoud 	if (!gpios)
14584130aacSRichard Genoud 		return ERR_PTR(-ENOMEM);
14684130aacSRichard Genoud 
14784130aacSRichard Genoud 	for (i = 0; i < UART_GPIO_MAX; i++) {
148d9948267SStefan Roese 		char *gpio_str;
149d9948267SStefan Roese 		bool present;
150d9948267SStefan Roese 
151d9948267SStefan Roese 		/* Check if GPIO property exists and continue if not */
152d9948267SStefan Roese 		gpio_str = kasprintf(GFP_KERNEL, "%s-gpios",
153d9948267SStefan Roese 				     mctrl_gpios_desc[i].name);
154d9948267SStefan Roese 		if (!gpio_str)
155d9948267SStefan Roese 			continue;
156d9948267SStefan Roese 
157d9948267SStefan Roese 		present = device_property_present(dev, gpio_str);
158d9948267SStefan Roese 		kfree(gpio_str);
159d9948267SStefan Roese 		if (!present)
160d9948267SStefan Roese 			continue;
16184130aacSRichard Genoud 
1621d267ea6SUwe Kleine-König 		gpios->gpio[i] =
1631d267ea6SUwe Kleine-König 			devm_gpiod_get_index_optional(dev,
1641d267ea6SUwe Kleine-König 						      mctrl_gpios_desc[i].name,
1654ad8e34dSAndy Shevchenko 						      idx,
1664ad8e34dSAndy Shevchenko 						      mctrl_gpios_desc[i].flags);
1671d267ea6SUwe Kleine-König 
1681d267ea6SUwe Kleine-König 		if (IS_ERR(gpios->gpio[i]))
16913bc2bb9SFabio Estevam 			return ERR_CAST(gpios->gpio[i]);
17084130aacSRichard Genoud 	}
17184130aacSRichard Genoud 
17284130aacSRichard Genoud 	return gpios;
17384130aacSRichard Genoud }
1747d8c70d8SUwe Kleine-König EXPORT_SYMBOL_GPL(mctrl_gpio_init_noauto);
17584130aacSRichard Genoud 
176ce59e48fSUwe Kleine-König #define MCTRL_ANY_DELTA (TIOCM_RI | TIOCM_DSR | TIOCM_CD | TIOCM_CTS)
mctrl_gpio_irq_handle(int irq,void * context)177ce59e48fSUwe Kleine-König static irqreturn_t mctrl_gpio_irq_handle(int irq, void *context)
178ce59e48fSUwe Kleine-König {
179ce59e48fSUwe Kleine-König 	struct mctrl_gpios *gpios = context;
180ce59e48fSUwe Kleine-König 	struct uart_port *port = gpios->port;
181ce59e48fSUwe Kleine-König 	u32 mctrl = gpios->mctrl_prev;
182ce59e48fSUwe Kleine-König 	u32 mctrl_diff;
183d11df618SYegor Yefremov 	unsigned long flags;
184ce59e48fSUwe Kleine-König 
185ce59e48fSUwe Kleine-König 	mctrl_gpio_get(gpios, &mctrl);
186ce59e48fSUwe Kleine-König 
1879683eeb6SThomas Gleixner 	uart_port_lock_irqsave(port, &flags);
188d11df618SYegor Yefremov 
189ce59e48fSUwe Kleine-König 	mctrl_diff = mctrl ^ gpios->mctrl_prev;
190ce59e48fSUwe Kleine-König 	gpios->mctrl_prev = mctrl;
191ce59e48fSUwe Kleine-König 
192ce59e48fSUwe Kleine-König 	if (mctrl_diff & MCTRL_ANY_DELTA && port->state != NULL) {
193ce59e48fSUwe Kleine-König 		if ((mctrl_diff & mctrl) & TIOCM_RI)
194ce59e48fSUwe Kleine-König 			port->icount.rng++;
195ce59e48fSUwe Kleine-König 
196ce59e48fSUwe Kleine-König 		if ((mctrl_diff & mctrl) & TIOCM_DSR)
197ce59e48fSUwe Kleine-König 			port->icount.dsr++;
198ce59e48fSUwe Kleine-König 
199ce59e48fSUwe Kleine-König 		if (mctrl_diff & TIOCM_CD)
200ce59e48fSUwe Kleine-König 			uart_handle_dcd_change(port, mctrl & TIOCM_CD);
201ce59e48fSUwe Kleine-König 
202ce59e48fSUwe Kleine-König 		if (mctrl_diff & TIOCM_CTS)
203ce59e48fSUwe Kleine-König 			uart_handle_cts_change(port, mctrl & TIOCM_CTS);
204ce59e48fSUwe Kleine-König 
205ce59e48fSUwe Kleine-König 		wake_up_interruptible(&port->state->port.delta_msr_wait);
206ce59e48fSUwe Kleine-König 	}
207ce59e48fSUwe Kleine-König 
2089683eeb6SThomas Gleixner 	uart_port_unlock_irqrestore(port, flags);
209d11df618SYegor Yefremov 
210ce59e48fSUwe Kleine-König 	return IRQ_HANDLED;
211ce59e48fSUwe Kleine-König }
212ce59e48fSUwe Kleine-König 
21327940abdSJiri Slaby /**
21427940abdSJiri Slaby  * mctrl_gpio_init - initialize uart gpios
21527940abdSJiri Slaby  * @port: port to initialize gpios for
21627940abdSJiri Slaby  * @idx: index of the gpio in the @port's device
21727940abdSJiri Slaby  *
21827940abdSJiri Slaby  * This will get the {cts,rts,...}-gpios from device tree if they are present
21927940abdSJiri Slaby  * and request them, set direction etc, and return an allocated structure.
22027940abdSJiri Slaby  * `devm_*` functions are used, so there's no need to call mctrl_gpio_free().
22127940abdSJiri Slaby  * As this sets up the irq handling, make sure to not handle changes to the
22227940abdSJiri Slaby  * gpio input lines in your driver, too.
22327940abdSJiri Slaby  */
mctrl_gpio_init(struct uart_port * port,unsigned int idx)224ce59e48fSUwe Kleine-König struct mctrl_gpios *mctrl_gpio_init(struct uart_port *port, unsigned int idx)
225ce59e48fSUwe Kleine-König {
226ce59e48fSUwe Kleine-König 	struct mctrl_gpios *gpios;
227ce59e48fSUwe Kleine-König 	enum mctrl_gpio_idx i;
228ce59e48fSUwe Kleine-König 
229ce59e48fSUwe Kleine-König 	gpios = mctrl_gpio_init_noauto(port->dev, idx);
230ce59e48fSUwe Kleine-König 	if (IS_ERR(gpios))
231ce59e48fSUwe Kleine-König 		return gpios;
232ce59e48fSUwe Kleine-König 
233ce59e48fSUwe Kleine-König 	gpios->port = port;
234ce59e48fSUwe Kleine-König 
235ce59e48fSUwe Kleine-König 	for (i = 0; i < UART_GPIO_MAX; ++i) {
236ce59e48fSUwe Kleine-König 		int ret;
237ce59e48fSUwe Kleine-König 
2384ad8e34dSAndy Shevchenko 		if (!gpios->gpio[i] || mctrl_gpio_flags_is_dir_out(i))
239ce59e48fSUwe Kleine-König 			continue;
240ce59e48fSUwe Kleine-König 
241ce59e48fSUwe Kleine-König 		ret = gpiod_to_irq(gpios->gpio[i]);
242cbd90e74SYueHaibing 		if (ret < 0) {
243ce59e48fSUwe Kleine-König 			dev_err(port->dev,
244ce59e48fSUwe Kleine-König 				"failed to find corresponding irq for %s (idx=%d, err=%d)\n",
245ce59e48fSUwe Kleine-König 				mctrl_gpios_desc[i].name, idx, ret);
246ce59e48fSUwe Kleine-König 			return ERR_PTR(ret);
247ce59e48fSUwe Kleine-König 		}
248ce59e48fSUwe Kleine-König 		gpios->irq[i] = ret;
249ce59e48fSUwe Kleine-König 
250ce59e48fSUwe Kleine-König 		/* irqs should only be enabled in .enable_ms */
251ce59e48fSUwe Kleine-König 		irq_set_status_flags(gpios->irq[i], IRQ_NOAUTOEN);
252ce59e48fSUwe Kleine-König 
253ce59e48fSUwe Kleine-König 		ret = devm_request_irq(port->dev, gpios->irq[i],
254ce59e48fSUwe Kleine-König 				       mctrl_gpio_irq_handle,
255ce59e48fSUwe Kleine-König 				       IRQ_TYPE_EDGE_BOTH, dev_name(port->dev),
256ce59e48fSUwe Kleine-König 				       gpios);
257ce59e48fSUwe Kleine-König 		if (ret) {
258ce59e48fSUwe Kleine-König 			/* alternatively implement polling */
259ce59e48fSUwe Kleine-König 			dev_err(port->dev,
260ce59e48fSUwe Kleine-König 				"failed to request irq for %s (idx=%d, err=%d)\n",
261ce59e48fSUwe Kleine-König 				mctrl_gpios_desc[i].name, idx, ret);
262ce59e48fSUwe Kleine-König 			return ERR_PTR(ret);
263ce59e48fSUwe Kleine-König 		}
264ce59e48fSUwe Kleine-König 	}
265ce59e48fSUwe Kleine-König 
266ce59e48fSUwe Kleine-König 	return gpios;
267ce59e48fSUwe Kleine-König }
2684f71a2e0SUwe Kleine-König EXPORT_SYMBOL_GPL(mctrl_gpio_init);
269ce59e48fSUwe Kleine-König 
27027940abdSJiri Slaby /**
27127940abdSJiri Slaby  * mctrl_gpio_free - explicitly free uart gpios
27227940abdSJiri Slaby  * @dev: uart port's device
27327940abdSJiri Slaby  * @gpios: gpios structure to be freed
27427940abdSJiri Slaby  *
27527940abdSJiri Slaby  * This will free the requested gpios in mctrl_gpio_init(). As `devm_*`
27627940abdSJiri Slaby  * functions are used, there's generally no need to call this function.
27727940abdSJiri Slaby  */
mctrl_gpio_free(struct device * dev,struct mctrl_gpios * gpios)27884130aacSRichard Genoud void mctrl_gpio_free(struct device *dev, struct mctrl_gpios *gpios)
27984130aacSRichard Genoud {
28084130aacSRichard Genoud 	enum mctrl_gpio_idx i;
28184130aacSRichard Genoud 
282434be0aeSYegor Yefremov 	if (gpios == NULL)
283434be0aeSYegor Yefremov 		return;
284434be0aeSYegor Yefremov 
285ce59e48fSUwe Kleine-König 	for (i = 0; i < UART_GPIO_MAX; i++) {
286ce59e48fSUwe Kleine-König 		if (gpios->irq[i])
287ce59e48fSUwe Kleine-König 			devm_free_irq(gpios->port->dev, gpios->irq[i], gpios);
288ce59e48fSUwe Kleine-König 
289445df7ffSUwe Kleine-König 		if (gpios->gpio[i])
29084130aacSRichard Genoud 			devm_gpiod_put(dev, gpios->gpio[i]);
291ce59e48fSUwe Kleine-König 	}
29284130aacSRichard Genoud 	devm_kfree(dev, gpios);
29384130aacSRichard Genoud }
29484130aacSRichard Genoud EXPORT_SYMBOL_GPL(mctrl_gpio_free);
295ce59e48fSUwe Kleine-König 
29627940abdSJiri Slaby /**
29727940abdSJiri Slaby  * mctrl_gpio_enable_ms - enable irqs and handling of changes to the ms lines
29827940abdSJiri Slaby  * @gpios: gpios to enable
29927940abdSJiri Slaby  */
mctrl_gpio_enable_ms(struct mctrl_gpios * gpios)300ce59e48fSUwe Kleine-König void mctrl_gpio_enable_ms(struct mctrl_gpios *gpios)
301ce59e48fSUwe Kleine-König {
302ce59e48fSUwe Kleine-König 	enum mctrl_gpio_idx i;
303ce59e48fSUwe Kleine-König 
304434be0aeSYegor Yefremov 	if (gpios == NULL)
305434be0aeSYegor Yefremov 		return;
306434be0aeSYegor Yefremov 
307ce59e48fSUwe Kleine-König 	/* .enable_ms may be called multiple times */
308ce59e48fSUwe Kleine-König 	if (gpios->mctrl_on)
309ce59e48fSUwe Kleine-König 		return;
310ce59e48fSUwe Kleine-König 
311ce59e48fSUwe Kleine-König 	gpios->mctrl_on = true;
312ce59e48fSUwe Kleine-König 
313ce59e48fSUwe Kleine-König 	/* get initial status of modem lines GPIOs */
314ce59e48fSUwe Kleine-König 	mctrl_gpio_get(gpios, &gpios->mctrl_prev);
315ce59e48fSUwe Kleine-König 
316ce59e48fSUwe Kleine-König 	for (i = 0; i < UART_GPIO_MAX; ++i) {
317ce59e48fSUwe Kleine-König 		if (!gpios->irq[i])
318ce59e48fSUwe Kleine-König 			continue;
319ce59e48fSUwe Kleine-König 
320ce59e48fSUwe Kleine-König 		enable_irq(gpios->irq[i]);
321ce59e48fSUwe Kleine-König 	}
322ce59e48fSUwe Kleine-König }
323ce59e48fSUwe Kleine-König EXPORT_SYMBOL_GPL(mctrl_gpio_enable_ms);
324ce59e48fSUwe Kleine-König 
32527940abdSJiri Slaby /**
32627940abdSJiri Slaby  * mctrl_gpio_disable_ms - disable irqs and handling of changes to the ms lines
32727940abdSJiri Slaby  * @gpios: gpios to disable
32827940abdSJiri Slaby  */
mctrl_gpio_disable_ms(struct mctrl_gpios * gpios)329ce59e48fSUwe Kleine-König void mctrl_gpio_disable_ms(struct mctrl_gpios *gpios)
330ce59e48fSUwe Kleine-König {
331ce59e48fSUwe Kleine-König 	enum mctrl_gpio_idx i;
332ce59e48fSUwe Kleine-König 
333434be0aeSYegor Yefremov 	if (gpios == NULL)
334434be0aeSYegor Yefremov 		return;
335434be0aeSYegor Yefremov 
336ce59e48fSUwe Kleine-König 	if (!gpios->mctrl_on)
337ce59e48fSUwe Kleine-König 		return;
338ce59e48fSUwe Kleine-König 
339ce59e48fSUwe Kleine-König 	gpios->mctrl_on = false;
340ce59e48fSUwe Kleine-König 
341ce59e48fSUwe Kleine-König 	for (i = 0; i < UART_GPIO_MAX; ++i) {
342ce59e48fSUwe Kleine-König 		if (!gpios->irq[i])
343ce59e48fSUwe Kleine-König 			continue;
344ce59e48fSUwe Kleine-König 
345ce59e48fSUwe Kleine-König 		disable_irq(gpios->irq[i]);
346ce59e48fSUwe Kleine-König 	}
347ce59e48fSUwe Kleine-König }
3484f71a2e0SUwe Kleine-König EXPORT_SYMBOL_GPL(mctrl_gpio_disable_ms);
34982a3f87fSRomain Izard 
mctrl_gpio_enable_irq_wake(struct mctrl_gpios * gpios)3509978c2f1SErwan Le Ray void mctrl_gpio_enable_irq_wake(struct mctrl_gpios *gpios)
3519978c2f1SErwan Le Ray {
3529978c2f1SErwan Le Ray 	enum mctrl_gpio_idx i;
3539978c2f1SErwan Le Ray 
3549978c2f1SErwan Le Ray 	if (!gpios)
3559978c2f1SErwan Le Ray 		return;
3569978c2f1SErwan Le Ray 
3579978c2f1SErwan Le Ray 	if (!gpios->mctrl_on)
3589978c2f1SErwan Le Ray 		return;
3599978c2f1SErwan Le Ray 
3609978c2f1SErwan Le Ray 	for (i = 0; i < UART_GPIO_MAX; ++i) {
3619978c2f1SErwan Le Ray 		if (!gpios->irq[i])
3629978c2f1SErwan Le Ray 			continue;
3639978c2f1SErwan Le Ray 
3649978c2f1SErwan Le Ray 		enable_irq_wake(gpios->irq[i]);
3659978c2f1SErwan Le Ray 	}
3669978c2f1SErwan Le Ray }
3679978c2f1SErwan Le Ray EXPORT_SYMBOL_GPL(mctrl_gpio_enable_irq_wake);
3689978c2f1SErwan Le Ray 
mctrl_gpio_disable_irq_wake(struct mctrl_gpios * gpios)3699978c2f1SErwan Le Ray void mctrl_gpio_disable_irq_wake(struct mctrl_gpios *gpios)
3709978c2f1SErwan Le Ray {
3719978c2f1SErwan Le Ray 	enum mctrl_gpio_idx i;
3729978c2f1SErwan Le Ray 
3739978c2f1SErwan Le Ray 	if (!gpios)
3749978c2f1SErwan Le Ray 		return;
3759978c2f1SErwan Le Ray 
3769978c2f1SErwan Le Ray 	if (!gpios->mctrl_on)
3779978c2f1SErwan Le Ray 		return;
3789978c2f1SErwan Le Ray 
3799978c2f1SErwan Le Ray 	for (i = 0; i < UART_GPIO_MAX; ++i) {
3809978c2f1SErwan Le Ray 		if (!gpios->irq[i])
3819978c2f1SErwan Le Ray 			continue;
3829978c2f1SErwan Le Ray 
3839978c2f1SErwan Le Ray 		disable_irq_wake(gpios->irq[i]);
3849978c2f1SErwan Le Ray 	}
3859978c2f1SErwan Le Ray }
3869978c2f1SErwan Le Ray EXPORT_SYMBOL_GPL(mctrl_gpio_disable_irq_wake);
3879978c2f1SErwan Le Ray 
388*f0a17485SJeff Johnson MODULE_DESCRIPTION("Helpers for controlling modem lines via GPIO");
38982a3f87fSRomain Izard MODULE_LICENSE("GPL");
390