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 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 45*27940abdSJiri Slaby /** 46*27940abdSJiri Slaby * mctrl_gpio_set - set gpios according to mctrl state 47*27940abdSJiri Slaby * @gpios: gpios to set 48*27940abdSJiri Slaby * @mctrl: state to set 49*27940abdSJiri Slaby * 50*27940abdSJiri Slaby * Set the gpios according to the mctrl state. 51*27940abdSJiri Slaby */ 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 73*27940abdSJiri Slaby /** 74*27940abdSJiri Slaby * mctrl_gpio_to_gpiod - obtain gpio_desc of modem line index 75*27940abdSJiri Slaby * @gpios: gpios to look into 76*27940abdSJiri Slaby * @gidx: index of the modem line 77*27940abdSJiri Slaby * Returns: the gpio_desc structure associated to the modem line index 78*27940abdSJiri Slaby */ 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 89*27940abdSJiri Slaby /** 90*27940abdSJiri Slaby * mctrl_gpio_get - update mctrl with the gpios values. 91*27940abdSJiri Slaby * @gpios: gpios to get the info from 92*27940abdSJiri Slaby * @mctrl: mctrl to set 93*27940abdSJiri Slaby * Returns: modified mctrl (the same value as in @mctrl) 94*27940abdSJiri Slaby * 95*27940abdSJiri Slaby * Update mctrl with the gpios values. 96*27940abdSJiri Slaby */ 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 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 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) 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 187d11df618SYegor Yefremov spin_lock_irqsave(&port->lock, 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 208d11df618SYegor Yefremov spin_unlock_irqrestore(&port->lock, flags); 209d11df618SYegor Yefremov 210ce59e48fSUwe Kleine-König return IRQ_HANDLED; 211ce59e48fSUwe Kleine-König } 212ce59e48fSUwe Kleine-König 213*27940abdSJiri Slaby /** 214*27940abdSJiri Slaby * mctrl_gpio_init - initialize uart gpios 215*27940abdSJiri Slaby * @port: port to initialize gpios for 216*27940abdSJiri Slaby * @idx: index of the gpio in the @port's device 217*27940abdSJiri Slaby * 218*27940abdSJiri Slaby * This will get the {cts,rts,...}-gpios from device tree if they are present 219*27940abdSJiri Slaby * and request them, set direction etc, and return an allocated structure. 220*27940abdSJiri Slaby * `devm_*` functions are used, so there's no need to call mctrl_gpio_free(). 221*27940abdSJiri Slaby * As this sets up the irq handling, make sure to not handle changes to the 222*27940abdSJiri Slaby * gpio input lines in your driver, too. 223*27940abdSJiri Slaby */ 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 270*27940abdSJiri Slaby /** 271*27940abdSJiri Slaby * mctrl_gpio_free - explicitly free uart gpios 272*27940abdSJiri Slaby * @dev: uart port's device 273*27940abdSJiri Slaby * @gpios: gpios structure to be freed 274*27940abdSJiri Slaby * 275*27940abdSJiri Slaby * This will free the requested gpios in mctrl_gpio_init(). As `devm_*` 276*27940abdSJiri Slaby * functions are used, there's generally no need to call this function. 277*27940abdSJiri Slaby */ 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 296*27940abdSJiri Slaby /** 297*27940abdSJiri Slaby * mctrl_gpio_enable_ms - enable irqs and handling of changes to the ms lines 298*27940abdSJiri Slaby * @gpios: gpios to enable 299*27940abdSJiri Slaby */ 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 325*27940abdSJiri Slaby /** 326*27940abdSJiri Slaby * mctrl_gpio_disable_ms - disable irqs and handling of changes to the ms lines 327*27940abdSJiri Slaby * @gpios: gpios to disable 328*27940abdSJiri Slaby */ 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 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 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 38882a3f87fSRomain Izard MODULE_LICENSE("GPL"); 389