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