linux/drivers/tty/serial/serial_mctrl_gpio.c

300 lines
6.5 KiB
C
Raw Normal View History

tty: add SPDX identifiers to all remaining files in drivers/tty/ It's good to have SPDX identifiers in all files to make it easier to audit the kernel tree for correct licenses. Update the drivers/tty files files with the correct SPDX license identifier based on the license text in the file itself. The SPDX identifier is a legally binding shorthand, which can be used instead of the full boiler plate text. This work is based on a script and data from Thomas Gleixner, Philippe Ombredanne, and Kate Stewart. Cc: Jiri Slaby <jslaby@suse.com> Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org> Cc: Paul Mackerras <paulus@samba.org> Cc: Michael Ellerman <mpe@ellerman.id.au> Cc: Chris Metcalf <cmetcalf@mellanox.com> Cc: Jiri Kosina <jikos@kernel.org> Cc: David Sterba <dsterba@suse.com> Cc: James Hogan <jhogan@kernel.org> Cc: Rob Herring <robh@kernel.org> Cc: Eric Anholt <eric@anholt.net> Cc: Stefan Wahren <stefan.wahren@i2se.com> Cc: Florian Fainelli <f.fainelli@gmail.com> Cc: Ray Jui <rjui@broadcom.com> Cc: Scott Branden <sbranden@broadcom.com> Cc: bcm-kernel-feedback-list@broadcom.com Cc: "James E.J. Bottomley" <jejb@parisc-linux.org> Cc: Helge Deller <deller@gmx.de> Cc: Joachim Eastwood <manabian@gmail.com> Cc: Matthias Brugger <matthias.bgg@gmail.com> Cc: Masahiro Yamada <yamada.masahiro@socionext.com> Cc: Tobias Klauser <tklauser@distanz.ch> Cc: Russell King <linux@armlinux.org.uk> Cc: Vineet Gupta <vgupta@synopsys.com> Cc: Richard Genoud <richard.genoud@gmail.com> Cc: Alexander Shiyan <shc_work@mail.ru> Cc: Baruch Siach <baruch@tkos.co.il> Cc: "Maciej W. Rozycki" <macro@linux-mips.org> Cc: "Uwe Kleine-König" <kernel@pengutronix.de> Cc: Pat Gefre <pfg@sgi.com> Cc: "Guilherme G. Piccoli" <gpiccoli@linux.vnet.ibm.com> Cc: Jason Wessel <jason.wessel@windriver.com> Cc: Vladimir Zapolskiy <vz@mleia.com> Cc: Sylvain Lemieux <slemieux.tyco@gmail.com> Cc: Carlo Caione <carlo@caione.org> Cc: Kevin Hilman <khilman@baylibre.com> Cc: Liviu Dudau <liviu.dudau@arm.com> Cc: Sudeep Holla <sudeep.holla@arm.com> Cc: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com> Cc: Andy Gross <andy.gross@linaro.org> Cc: David Brown <david.brown@linaro.org> Cc: "Andreas Färber" <afaerber@suse.de> Cc: Kevin Cernekee <cernekee@gmail.com> Cc: Laxman Dewangan <ldewangan@nvidia.com> Cc: Thierry Reding <thierry.reding@gmail.com> Cc: Jonathan Hunter <jonathanh@nvidia.com> Cc: Barry Song <baohua@kernel.org> Cc: Patrice Chotard <patrice.chotard@st.com> Cc: Maxime Coquelin <mcoquelin.stm32@gmail.com> Cc: Alexandre Torgue <alexandre.torgue@st.com> Cc: "David S. Miller" <davem@davemloft.net> Cc: Peter Korsgaard <jacmet@sunsite.dk> Cc: Timur Tabi <timur@tabi.org> Cc: Tony Prisk <linux@prisktech.co.nz> Cc: Michal Simek <michal.simek@xilinx.com> Cc: "Sören Brinkmann" <soren.brinkmann@xilinx.com> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: Kate Stewart <kstewart@linuxfoundation.org> Cc: Philippe Ombredanne <pombredanne@nexb.com> Cc: Jiri Slaby <jslaby@suse.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2017-11-07 01:11:51 +08:00
// SPDX-License-Identifier: GPL-2.0+
/*
* Helpers for controlling modem lines via GPIO
*
* Copyright (C) 2014 Paratronic S.A.
*/
#include <linux/err.h>
#include <linux/device.h>
#include <linux/irq.h>
#include <linux/gpio/consumer.h>
#include <linux/termios.h>
#include <linux/serial_core.h>
#include <linux/module.h>
serial: mctrl_gpio: Check if GPIO property exisits before requesting it This patch adds a check for the GPIOs property existence, before the GPIO is requested. This fixes an issue seen when the 8250 mctrl_gpio support is added (2nd patch in this patch series) on x86 platforms using ACPI. Here Mika's comments from 2016-08-09: " I noticed that with v4.8-rc1 serial console of some of our Broxton systems does not work properly anymore. I'm able to see output but input does not work. I bisected it down to commit 4ef03d328769eddbfeca1f1c958fdb181a69c341 ("tty/serial/8250: use mctrl_gpio helpers"). The reason why it fails is that in ACPI we do not have names for GPIOs (except when _DSD is used) so we use the "idx" to index into _CRS GPIO resources. Now mctrl_gpio_init_noauto() goes through a list of GPIOs calling devm_gpiod_get_index_optional() passing "idx" of 0 for each. The UART device in Broxton has following (simplified) ACPI description: Device (URT4) { ... Name (_CRS, ResourceTemplate () { GpioIo (Exclusive, PullDefault, 0x0000, 0x0000, IoRestrictionOutputOnly, "\\_SB.GPO0", 0x00, ResourceConsumer) { 0x003A } GpioIo (Exclusive, PullDefault, 0x0000, 0x0000, IoRestrictionOutputOnly, "\\_SB.GPO0", 0x00, ResourceConsumer) { 0x003D } }) In this case it finds the first GPIO (0x003A which happens to be RX pin for that UART), turns it into GPIO which then breaks input for the UART device. This also breaks systems with bluetooth connected to UART (those typically have some GPIOs in their _CRS). Any ideas how to fix this? We cannot just drop the _CRS index lookup fallback because that would break many existing machines out there so maybe we can limit this to only DT enabled machines. Or alternatively probe if the property first exists before trying to acquire the GPIOs (using device_property_present()). " This patch implements the fix suggested by Mika in his statement above. Signed-off-by: Stefan Roese <sr@denx.de> Reviewed-by: Mika Westerberg <mika.westerberg@linux.intel.com> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Tested-by: Yegor Yefremov <yegorslists@googlemail.com> Cc: Mika Westerberg <mika.westerberg@linux.intel.com> Cc: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Cc: Yegor Yefremov <yegorslists@googlemail.com> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Cc: Giulio Benetti <giulio.benetti@micronovasrl.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2019-06-20 14:24:19 +08:00
#include <linux/property.h>
#include "serial_mctrl_gpio.h"
struct mctrl_gpios {
struct uart_port *port;
struct gpio_desc *gpio[UART_GPIO_MAX];
int irq[UART_GPIO_MAX];
unsigned int mctrl_prev;
bool mctrl_on;
};
static const struct {
const char *name;
unsigned int mctrl;
enum gpiod_flags flags;
} mctrl_gpios_desc[UART_GPIO_MAX] = {
{ "cts", TIOCM_CTS, GPIOD_IN, },
{ "dsr", TIOCM_DSR, GPIOD_IN, },
{ "dcd", TIOCM_CD, GPIOD_IN, },
{ "rng", TIOCM_RNG, GPIOD_IN, },
{ "rts", TIOCM_RTS, GPIOD_OUT_LOW, },
{ "dtr", TIOCM_DTR, GPIOD_OUT_LOW, },
};
static bool mctrl_gpio_flags_is_dir_out(unsigned int idx)
{
return mctrl_gpios_desc[idx].flags & GPIOD_FLAGS_BIT_DIR_OUT;
}
void mctrl_gpio_set(struct mctrl_gpios *gpios, unsigned int mctrl)
{
enum mctrl_gpio_idx i;
struct gpio_desc *desc_array[UART_GPIO_MAX];
gpiolib: Pass bitmaps, not integer arrays, to get/set array Most users of get/set array functions iterate consecutive bits of data, usually a single integer, while processing array of results obtained from, or building an array of values to be passed to those functions. Save time wasted on those iterations by changing the functions' API to accept bitmaps. All current users are updated as well. More benefits from the change are expected as soon as planned support for accepting/passing those bitmaps directly from/to respective GPIO chip callbacks if applicable is implemented. Cc: Jonathan Corbet <corbet@lwn.net> Cc: Miguel Ojeda Sandonis <miguel.ojeda.sandonis@gmail.com> Cc: Sebastien Bourdelin <sebastien.bourdelin@savoirfairelinux.com> Cc: Lukas Wunner <lukas@wunner.de> Cc: Peter Korsgaard <peter.korsgaard@barco.com> Cc: Peter Rosin <peda@axentia.se> Cc: Andrew Lunn <andrew@lunn.ch> Cc: Florian Fainelli <f.fainelli@gmail.com> Cc: "David S. Miller" <davem@davemloft.net> Cc: Rojhalat Ibrahim <imr@rtschenk.de> Cc: Dominik Brodowski <linux@dominikbrodowski.net> Cc: Russell King <rmk+kernel@armlinux.org.uk> Cc: Kishon Vijay Abraham I <kishon@ti.com> Cc: Tony Lindgren <tony@atomide.com> Cc: Lars-Peter Clausen <lars@metafoo.de> Cc: Michael Hennerich <Michael.Hennerich@analog.com> Cc: Jonathan Cameron <jic23@kernel.org> Cc: Hartmut Knaack <knaack.h@gmx.de> Cc: Peter Meerwald-Stadler <pmeerw@pmeerw.net> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Cc: Jiri Slaby <jslaby@suse.com> Cc: Yegor Yefremov <yegorslists@googlemail.com> Cc: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> Signed-off-by: Janusz Krzysztofik <jmkrzyszt@gmail.com> Acked-by: Ulf Hansson <ulf.hansson@linaro.org> Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be> Tested-by: Geert Uytterhoeven <geert+renesas@glider.be> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
2018-09-06 05:50:05 +08:00
DECLARE_BITMAP(values, UART_GPIO_MAX);
unsigned int count = 0;
if (gpios == NULL)
return;
for (i = 0; i < UART_GPIO_MAX; i++)
if (gpios->gpio[i] && mctrl_gpio_flags_is_dir_out(i)) {
desc_array[count] = gpios->gpio[i];
gpiolib: Pass bitmaps, not integer arrays, to get/set array Most users of get/set array functions iterate consecutive bits of data, usually a single integer, while processing array of results obtained from, or building an array of values to be passed to those functions. Save time wasted on those iterations by changing the functions' API to accept bitmaps. All current users are updated as well. More benefits from the change are expected as soon as planned support for accepting/passing those bitmaps directly from/to respective GPIO chip callbacks if applicable is implemented. Cc: Jonathan Corbet <corbet@lwn.net> Cc: Miguel Ojeda Sandonis <miguel.ojeda.sandonis@gmail.com> Cc: Sebastien Bourdelin <sebastien.bourdelin@savoirfairelinux.com> Cc: Lukas Wunner <lukas@wunner.de> Cc: Peter Korsgaard <peter.korsgaard@barco.com> Cc: Peter Rosin <peda@axentia.se> Cc: Andrew Lunn <andrew@lunn.ch> Cc: Florian Fainelli <f.fainelli@gmail.com> Cc: "David S. Miller" <davem@davemloft.net> Cc: Rojhalat Ibrahim <imr@rtschenk.de> Cc: Dominik Brodowski <linux@dominikbrodowski.net> Cc: Russell King <rmk+kernel@armlinux.org.uk> Cc: Kishon Vijay Abraham I <kishon@ti.com> Cc: Tony Lindgren <tony@atomide.com> Cc: Lars-Peter Clausen <lars@metafoo.de> Cc: Michael Hennerich <Michael.Hennerich@analog.com> Cc: Jonathan Cameron <jic23@kernel.org> Cc: Hartmut Knaack <knaack.h@gmx.de> Cc: Peter Meerwald-Stadler <pmeerw@pmeerw.net> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Cc: Jiri Slaby <jslaby@suse.com> Cc: Yegor Yefremov <yegorslists@googlemail.com> Cc: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> Signed-off-by: Janusz Krzysztofik <jmkrzyszt@gmail.com> Acked-by: Ulf Hansson <ulf.hansson@linaro.org> Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be> Tested-by: Geert Uytterhoeven <geert+renesas@glider.be> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
2018-09-06 05:50:05 +08:00
__assign_bit(count, values,
mctrl & mctrl_gpios_desc[i].mctrl);
count++;
}
gpiolib: Pass array info to get/set array functions In order to make use of array info obtained from gpiod_get_array() and speed up processing of arrays matching single GPIO chip layout, that information must be passed to get/set array functions. Extend the functions' API with that additional parameter and update all users. Pass NULL if a user builds an array itself from single GPIOs. Cc: Jonathan Corbet <corbet@lwn.net> Cc: Miguel Ojeda Sandonis <miguel.ojeda.sandonis@gmail.com> Cc: Geert Uytterhoeven <geert@linux-m68k.org> Cc: Sebastien Bourdelin <sebastien.bourdelin@savoirfairelinux.com> Cc: Lukas Wunner <lukas@wunner.de> Cc: Peter Korsgaard <peter.korsgaard@barco.com> Cc: Peter Rosin <peda@axentia.se> Cc: Andrew Lunn <andrew@lunn.ch> Cc: Florian Fainelli <f.fainelli@gmail.com> Cc: "David S. Miller" <davem@davemloft.net> Cc: Rojhalat Ibrahim <imr@rtschenk.de> Cc: Dominik Brodowski <linux@dominikbrodowski.net> Cc: Russell King <rmk+kernel@armlinux.org.uk> Cc: Kishon Vijay Abraham I <kishon@ti.com> Cc: Tony Lindgren <tony@atomide.com> Cc: Lars-Peter Clausen <lars@metafoo.de> Cc: Michael Hennerich <Michael.Hennerich@analog.com> Cc: Jonathan Cameron <jic23@kernel.org> Cc: Hartmut Knaack <knaack.h@gmx.de> Cc: Peter Meerwald-Stadler <pmeerw@pmeerw.net> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Cc: Jiri Slaby <jslaby@suse.com> Cc: Yegor Yefremov <yegorslists@googlemail.com> Cc: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> Signed-off-by: Janusz Krzysztofik <jmkrzyszt@gmail.com> Acked-by: Ulf Hansson <ulf.hansson@linaro.org> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
2018-09-06 05:50:07 +08:00
gpiod_set_array_value(count, desc_array, NULL, values);
}
EXPORT_SYMBOL_GPL(mctrl_gpio_set);
struct gpio_desc *mctrl_gpio_to_gpiod(struct mctrl_gpios *gpios,
enum mctrl_gpio_idx gidx)
{
return gpios->gpio[gidx];
}
EXPORT_SYMBOL_GPL(mctrl_gpio_to_gpiod);
unsigned int mctrl_gpio_get(struct mctrl_gpios *gpios, unsigned int *mctrl)
{
enum mctrl_gpio_idx i;
if (gpios == NULL)
return *mctrl;
for (i = 0; i < UART_GPIO_MAX; i++) {
if (gpios->gpio[i] && !mctrl_gpio_flags_is_dir_out(i)) {
if (gpiod_get_value(gpios->gpio[i]))
*mctrl |= mctrl_gpios_desc[i].mctrl;
else
*mctrl &= ~mctrl_gpios_desc[i].mctrl;
}
}
return *mctrl;
}
EXPORT_SYMBOL_GPL(mctrl_gpio_get);
unsigned int
mctrl_gpio_get_outputs(struct mctrl_gpios *gpios, unsigned int *mctrl)
{
enum mctrl_gpio_idx i;
if (gpios == NULL)
return *mctrl;
for (i = 0; i < UART_GPIO_MAX; i++) {
if (gpios->gpio[i] && mctrl_gpio_flags_is_dir_out(i)) {
if (gpiod_get_value(gpios->gpio[i]))
*mctrl |= mctrl_gpios_desc[i].mctrl;
else
*mctrl &= ~mctrl_gpios_desc[i].mctrl;
}
}
return *mctrl;
}
EXPORT_SYMBOL_GPL(mctrl_gpio_get_outputs);
struct mctrl_gpios *mctrl_gpio_init_noauto(struct device *dev, unsigned int idx)
{
struct mctrl_gpios *gpios;
enum mctrl_gpio_idx i;
gpios = devm_kzalloc(dev, sizeof(*gpios), GFP_KERNEL);
if (!gpios)
return ERR_PTR(-ENOMEM);
for (i = 0; i < UART_GPIO_MAX; i++) {
serial: mctrl_gpio: Check if GPIO property exisits before requesting it This patch adds a check for the GPIOs property existence, before the GPIO is requested. This fixes an issue seen when the 8250 mctrl_gpio support is added (2nd patch in this patch series) on x86 platforms using ACPI. Here Mika's comments from 2016-08-09: " I noticed that with v4.8-rc1 serial console of some of our Broxton systems does not work properly anymore. I'm able to see output but input does not work. I bisected it down to commit 4ef03d328769eddbfeca1f1c958fdb181a69c341 ("tty/serial/8250: use mctrl_gpio helpers"). The reason why it fails is that in ACPI we do not have names for GPIOs (except when _DSD is used) so we use the "idx" to index into _CRS GPIO resources. Now mctrl_gpio_init_noauto() goes through a list of GPIOs calling devm_gpiod_get_index_optional() passing "idx" of 0 for each. The UART device in Broxton has following (simplified) ACPI description: Device (URT4) { ... Name (_CRS, ResourceTemplate () { GpioIo (Exclusive, PullDefault, 0x0000, 0x0000, IoRestrictionOutputOnly, "\\_SB.GPO0", 0x00, ResourceConsumer) { 0x003A } GpioIo (Exclusive, PullDefault, 0x0000, 0x0000, IoRestrictionOutputOnly, "\\_SB.GPO0", 0x00, ResourceConsumer) { 0x003D } }) In this case it finds the first GPIO (0x003A which happens to be RX pin for that UART), turns it into GPIO which then breaks input for the UART device. This also breaks systems with bluetooth connected to UART (those typically have some GPIOs in their _CRS). Any ideas how to fix this? We cannot just drop the _CRS index lookup fallback because that would break many existing machines out there so maybe we can limit this to only DT enabled machines. Or alternatively probe if the property first exists before trying to acquire the GPIOs (using device_property_present()). " This patch implements the fix suggested by Mika in his statement above. Signed-off-by: Stefan Roese <sr@denx.de> Reviewed-by: Mika Westerberg <mika.westerberg@linux.intel.com> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Tested-by: Yegor Yefremov <yegorslists@googlemail.com> Cc: Mika Westerberg <mika.westerberg@linux.intel.com> Cc: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Cc: Yegor Yefremov <yegorslists@googlemail.com> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Cc: Giulio Benetti <giulio.benetti@micronovasrl.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2019-06-20 14:24:19 +08:00
char *gpio_str;
bool present;
/* Check if GPIO property exists and continue if not */
gpio_str = kasprintf(GFP_KERNEL, "%s-gpios",
mctrl_gpios_desc[i].name);
if (!gpio_str)
continue;
present = device_property_present(dev, gpio_str);
kfree(gpio_str);
if (!present)
continue;
gpios->gpio[i] =
devm_gpiod_get_index_optional(dev,
mctrl_gpios_desc[i].name,
idx,
mctrl_gpios_desc[i].flags);
if (IS_ERR(gpios->gpio[i]))
return ERR_CAST(gpios->gpio[i]);
}
return gpios;
}
EXPORT_SYMBOL_GPL(mctrl_gpio_init_noauto);
#define MCTRL_ANY_DELTA (TIOCM_RI | TIOCM_DSR | TIOCM_CD | TIOCM_CTS)
static irqreturn_t mctrl_gpio_irq_handle(int irq, void *context)
{
struct mctrl_gpios *gpios = context;
struct uart_port *port = gpios->port;
u32 mctrl = gpios->mctrl_prev;
u32 mctrl_diff;
unsigned long flags;
mctrl_gpio_get(gpios, &mctrl);
spin_lock_irqsave(&port->lock, flags);
mctrl_diff = mctrl ^ gpios->mctrl_prev;
gpios->mctrl_prev = mctrl;
if (mctrl_diff & MCTRL_ANY_DELTA && port->state != NULL) {
if ((mctrl_diff & mctrl) & TIOCM_RI)
port->icount.rng++;
if ((mctrl_diff & mctrl) & TIOCM_DSR)
port->icount.dsr++;
if (mctrl_diff & TIOCM_CD)
uart_handle_dcd_change(port, mctrl & TIOCM_CD);
if (mctrl_diff & TIOCM_CTS)
uart_handle_cts_change(port, mctrl & TIOCM_CTS);
wake_up_interruptible(&port->state->port.delta_msr_wait);
}
spin_unlock_irqrestore(&port->lock, flags);
return IRQ_HANDLED;
}
struct mctrl_gpios *mctrl_gpio_init(struct uart_port *port, unsigned int idx)
{
struct mctrl_gpios *gpios;
enum mctrl_gpio_idx i;
gpios = mctrl_gpio_init_noauto(port->dev, idx);
if (IS_ERR(gpios))
return gpios;
gpios->port = port;
for (i = 0; i < UART_GPIO_MAX; ++i) {
int ret;
if (!gpios->gpio[i] || mctrl_gpio_flags_is_dir_out(i))
continue;
ret = gpiod_to_irq(gpios->gpio[i]);
if (ret <= 0) {
dev_err(port->dev,
"failed to find corresponding irq for %s (idx=%d, err=%d)\n",
mctrl_gpios_desc[i].name, idx, ret);
return ERR_PTR(ret);
}
gpios->irq[i] = ret;
/* irqs should only be enabled in .enable_ms */
irq_set_status_flags(gpios->irq[i], IRQ_NOAUTOEN);
ret = devm_request_irq(port->dev, gpios->irq[i],
mctrl_gpio_irq_handle,
IRQ_TYPE_EDGE_BOTH, dev_name(port->dev),
gpios);
if (ret) {
/* alternatively implement polling */
dev_err(port->dev,
"failed to request irq for %s (idx=%d, err=%d)\n",
mctrl_gpios_desc[i].name, idx, ret);
return ERR_PTR(ret);
}
}
return gpios;
}
EXPORT_SYMBOL_GPL(mctrl_gpio_init);
void mctrl_gpio_free(struct device *dev, struct mctrl_gpios *gpios)
{
enum mctrl_gpio_idx i;
if (gpios == NULL)
return;
for (i = 0; i < UART_GPIO_MAX; i++) {
if (gpios->irq[i])
devm_free_irq(gpios->port->dev, gpios->irq[i], gpios);
if (gpios->gpio[i])
devm_gpiod_put(dev, gpios->gpio[i]);
}
devm_kfree(dev, gpios);
}
EXPORT_SYMBOL_GPL(mctrl_gpio_free);
void mctrl_gpio_enable_ms(struct mctrl_gpios *gpios)
{
enum mctrl_gpio_idx i;
if (gpios == NULL)
return;
/* .enable_ms may be called multiple times */
if (gpios->mctrl_on)
return;
gpios->mctrl_on = true;
/* get initial status of modem lines GPIOs */
mctrl_gpio_get(gpios, &gpios->mctrl_prev);
for (i = 0; i < UART_GPIO_MAX; ++i) {
if (!gpios->irq[i])
continue;
enable_irq(gpios->irq[i]);
}
}
EXPORT_SYMBOL_GPL(mctrl_gpio_enable_ms);
void mctrl_gpio_disable_ms(struct mctrl_gpios *gpios)
{
enum mctrl_gpio_idx i;
if (gpios == NULL)
return;
if (!gpios->mctrl_on)
return;
gpios->mctrl_on = false;
for (i = 0; i < UART_GPIO_MAX; ++i) {
if (!gpios->irq[i])
continue;
disable_irq(gpios->irq[i]);
}
}
EXPORT_SYMBOL_GPL(mctrl_gpio_disable_ms);
MODULE_LICENSE("GPL");