Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 /*
0003  * Helpers for controlling modem lines via GPIO
0004  *
0005  * Copyright (C) 2014 Paratronic S.A.
0006  */
0007 
0008 #include <linux/err.h>
0009 #include <linux/device.h>
0010 #include <linux/irq.h>
0011 #include <linux/gpio/consumer.h>
0012 #include <linux/termios.h>
0013 #include <linux/serial_core.h>
0014 #include <linux/module.h>
0015 #include <linux/property.h>
0016 
0017 #include "serial_mctrl_gpio.h"
0018 
0019 struct mctrl_gpios {
0020     struct uart_port *port;
0021     struct gpio_desc *gpio[UART_GPIO_MAX];
0022     int irq[UART_GPIO_MAX];
0023     unsigned int mctrl_prev;
0024     bool mctrl_on;
0025 };
0026 
0027 static const struct {
0028     const char *name;
0029     unsigned int mctrl;
0030     enum gpiod_flags flags;
0031 } mctrl_gpios_desc[UART_GPIO_MAX] = {
0032     { "cts", TIOCM_CTS, GPIOD_IN, },
0033     { "dsr", TIOCM_DSR, GPIOD_IN, },
0034     { "dcd", TIOCM_CD,  GPIOD_IN, },
0035     { "rng", TIOCM_RNG, GPIOD_IN, },
0036     { "rts", TIOCM_RTS, GPIOD_OUT_LOW, },
0037     { "dtr", TIOCM_DTR, GPIOD_OUT_LOW, },
0038 };
0039 
0040 static bool mctrl_gpio_flags_is_dir_out(unsigned int idx)
0041 {
0042     return mctrl_gpios_desc[idx].flags & GPIOD_FLAGS_BIT_DIR_OUT;
0043 }
0044 
0045 /**
0046  * mctrl_gpio_set - set gpios according to mctrl state
0047  * @gpios: gpios to set
0048  * @mctrl: state to set
0049  *
0050  * Set the gpios according to the mctrl state.
0051  */
0052 void mctrl_gpio_set(struct mctrl_gpios *gpios, unsigned int mctrl)
0053 {
0054     enum mctrl_gpio_idx i;
0055     struct gpio_desc *desc_array[UART_GPIO_MAX];
0056     DECLARE_BITMAP(values, UART_GPIO_MAX);
0057     unsigned int count = 0;
0058 
0059     if (gpios == NULL)
0060         return;
0061 
0062     for (i = 0; i < UART_GPIO_MAX; i++)
0063         if (gpios->gpio[i] && mctrl_gpio_flags_is_dir_out(i)) {
0064             desc_array[count] = gpios->gpio[i];
0065             __assign_bit(count, values,
0066                      mctrl & mctrl_gpios_desc[i].mctrl);
0067             count++;
0068         }
0069     gpiod_set_array_value(count, desc_array, NULL, values);
0070 }
0071 EXPORT_SYMBOL_GPL(mctrl_gpio_set);
0072 
0073 /**
0074  * mctrl_gpio_to_gpiod - obtain gpio_desc of modem line index
0075  * @gpios: gpios to look into
0076  * @gidx: index of the modem line
0077  * Returns: the gpio_desc structure associated to the modem line index
0078  */
0079 struct gpio_desc *mctrl_gpio_to_gpiod(struct mctrl_gpios *gpios,
0080                       enum mctrl_gpio_idx gidx)
0081 {
0082     if (gpios == NULL)
0083         return NULL;
0084 
0085     return gpios->gpio[gidx];
0086 }
0087 EXPORT_SYMBOL_GPL(mctrl_gpio_to_gpiod);
0088 
0089 /**
0090  * mctrl_gpio_get - update mctrl with the gpios values.
0091  * @gpios: gpios to get the info from
0092  * @mctrl: mctrl to set
0093  * Returns: modified mctrl (the same value as in @mctrl)
0094  *
0095  * Update mctrl with the gpios values.
0096  */
0097 unsigned int mctrl_gpio_get(struct mctrl_gpios *gpios, unsigned int *mctrl)
0098 {
0099     enum mctrl_gpio_idx i;
0100 
0101     if (gpios == NULL)
0102         return *mctrl;
0103 
0104     for (i = 0; i < UART_GPIO_MAX; i++) {
0105         if (gpios->gpio[i] && !mctrl_gpio_flags_is_dir_out(i)) {
0106             if (gpiod_get_value(gpios->gpio[i]))
0107                 *mctrl |= mctrl_gpios_desc[i].mctrl;
0108             else
0109                 *mctrl &= ~mctrl_gpios_desc[i].mctrl;
0110         }
0111     }
0112 
0113     return *mctrl;
0114 }
0115 EXPORT_SYMBOL_GPL(mctrl_gpio_get);
0116 
0117 unsigned int
0118 mctrl_gpio_get_outputs(struct mctrl_gpios *gpios, unsigned int *mctrl)
0119 {
0120     enum mctrl_gpio_idx i;
0121 
0122     if (gpios == NULL)
0123         return *mctrl;
0124 
0125     for (i = 0; i < UART_GPIO_MAX; i++) {
0126         if (gpios->gpio[i] && mctrl_gpio_flags_is_dir_out(i)) {
0127             if (gpiod_get_value(gpios->gpio[i]))
0128                 *mctrl |= mctrl_gpios_desc[i].mctrl;
0129             else
0130                 *mctrl &= ~mctrl_gpios_desc[i].mctrl;
0131         }
0132     }
0133 
0134     return *mctrl;
0135 }
0136 EXPORT_SYMBOL_GPL(mctrl_gpio_get_outputs);
0137 
0138 struct mctrl_gpios *mctrl_gpio_init_noauto(struct device *dev, unsigned int idx)
0139 {
0140     struct mctrl_gpios *gpios;
0141     enum mctrl_gpio_idx i;
0142 
0143     gpios = devm_kzalloc(dev, sizeof(*gpios), GFP_KERNEL);
0144     if (!gpios)
0145         return ERR_PTR(-ENOMEM);
0146 
0147     for (i = 0; i < UART_GPIO_MAX; i++) {
0148         char *gpio_str;
0149         bool present;
0150 
0151         /* Check if GPIO property exists and continue if not */
0152         gpio_str = kasprintf(GFP_KERNEL, "%s-gpios",
0153                      mctrl_gpios_desc[i].name);
0154         if (!gpio_str)
0155             continue;
0156 
0157         present = device_property_present(dev, gpio_str);
0158         kfree(gpio_str);
0159         if (!present)
0160             continue;
0161 
0162         gpios->gpio[i] =
0163             devm_gpiod_get_index_optional(dev,
0164                               mctrl_gpios_desc[i].name,
0165                               idx,
0166                               mctrl_gpios_desc[i].flags);
0167 
0168         if (IS_ERR(gpios->gpio[i]))
0169             return ERR_CAST(gpios->gpio[i]);
0170     }
0171 
0172     return gpios;
0173 }
0174 EXPORT_SYMBOL_GPL(mctrl_gpio_init_noauto);
0175 
0176 #define MCTRL_ANY_DELTA (TIOCM_RI | TIOCM_DSR | TIOCM_CD | TIOCM_CTS)
0177 static irqreturn_t mctrl_gpio_irq_handle(int irq, void *context)
0178 {
0179     struct mctrl_gpios *gpios = context;
0180     struct uart_port *port = gpios->port;
0181     u32 mctrl = gpios->mctrl_prev;
0182     u32 mctrl_diff;
0183     unsigned long flags;
0184 
0185     mctrl_gpio_get(gpios, &mctrl);
0186 
0187     spin_lock_irqsave(&port->lock, flags);
0188 
0189     mctrl_diff = mctrl ^ gpios->mctrl_prev;
0190     gpios->mctrl_prev = mctrl;
0191 
0192     if (mctrl_diff & MCTRL_ANY_DELTA && port->state != NULL) {
0193         if ((mctrl_diff & mctrl) & TIOCM_RI)
0194             port->icount.rng++;
0195 
0196         if ((mctrl_diff & mctrl) & TIOCM_DSR)
0197             port->icount.dsr++;
0198 
0199         if (mctrl_diff & TIOCM_CD)
0200             uart_handle_dcd_change(port, mctrl & TIOCM_CD);
0201 
0202         if (mctrl_diff & TIOCM_CTS)
0203             uart_handle_cts_change(port, mctrl & TIOCM_CTS);
0204 
0205         wake_up_interruptible(&port->state->port.delta_msr_wait);
0206     }
0207 
0208     spin_unlock_irqrestore(&port->lock, flags);
0209 
0210     return IRQ_HANDLED;
0211 }
0212 
0213 /**
0214  * mctrl_gpio_init - initialize uart gpios
0215  * @port: port to initialize gpios for
0216  * @idx: index of the gpio in the @port's device
0217  *
0218  * This will get the {cts,rts,...}-gpios from device tree if they are present
0219  * and request them, set direction etc, and return an allocated structure.
0220  * `devm_*` functions are used, so there's no need to call mctrl_gpio_free().
0221  * As this sets up the irq handling, make sure to not handle changes to the
0222  * gpio input lines in your driver, too.
0223  */
0224 struct mctrl_gpios *mctrl_gpio_init(struct uart_port *port, unsigned int idx)
0225 {
0226     struct mctrl_gpios *gpios;
0227     enum mctrl_gpio_idx i;
0228 
0229     gpios = mctrl_gpio_init_noauto(port->dev, idx);
0230     if (IS_ERR(gpios))
0231         return gpios;
0232 
0233     gpios->port = port;
0234 
0235     for (i = 0; i < UART_GPIO_MAX; ++i) {
0236         int ret;
0237 
0238         if (!gpios->gpio[i] || mctrl_gpio_flags_is_dir_out(i))
0239             continue;
0240 
0241         ret = gpiod_to_irq(gpios->gpio[i]);
0242         if (ret < 0) {
0243             dev_err(port->dev,
0244                 "failed to find corresponding irq for %s (idx=%d, err=%d)\n",
0245                 mctrl_gpios_desc[i].name, idx, ret);
0246             return ERR_PTR(ret);
0247         }
0248         gpios->irq[i] = ret;
0249 
0250         /* irqs should only be enabled in .enable_ms */
0251         irq_set_status_flags(gpios->irq[i], IRQ_NOAUTOEN);
0252 
0253         ret = devm_request_irq(port->dev, gpios->irq[i],
0254                        mctrl_gpio_irq_handle,
0255                        IRQ_TYPE_EDGE_BOTH, dev_name(port->dev),
0256                        gpios);
0257         if (ret) {
0258             /* alternatively implement polling */
0259             dev_err(port->dev,
0260                 "failed to request irq for %s (idx=%d, err=%d)\n",
0261                 mctrl_gpios_desc[i].name, idx, ret);
0262             return ERR_PTR(ret);
0263         }
0264     }
0265 
0266     return gpios;
0267 }
0268 EXPORT_SYMBOL_GPL(mctrl_gpio_init);
0269 
0270 /**
0271  * mctrl_gpio_free - explicitly free uart gpios
0272  * @dev: uart port's device
0273  * @gpios: gpios structure to be freed
0274  *
0275  * This will free the requested gpios in mctrl_gpio_init(). As `devm_*`
0276  * functions are used, there's generally no need to call this function.
0277  */
0278 void mctrl_gpio_free(struct device *dev, struct mctrl_gpios *gpios)
0279 {
0280     enum mctrl_gpio_idx i;
0281 
0282     if (gpios == NULL)
0283         return;
0284 
0285     for (i = 0; i < UART_GPIO_MAX; i++) {
0286         if (gpios->irq[i])
0287             devm_free_irq(gpios->port->dev, gpios->irq[i], gpios);
0288 
0289         if (gpios->gpio[i])
0290             devm_gpiod_put(dev, gpios->gpio[i]);
0291     }
0292     devm_kfree(dev, gpios);
0293 }
0294 EXPORT_SYMBOL_GPL(mctrl_gpio_free);
0295 
0296 /**
0297  * mctrl_gpio_enable_ms - enable irqs and handling of changes to the ms lines
0298  * @gpios: gpios to enable
0299  */
0300 void mctrl_gpio_enable_ms(struct mctrl_gpios *gpios)
0301 {
0302     enum mctrl_gpio_idx i;
0303 
0304     if (gpios == NULL)
0305         return;
0306 
0307     /* .enable_ms may be called multiple times */
0308     if (gpios->mctrl_on)
0309         return;
0310 
0311     gpios->mctrl_on = true;
0312 
0313     /* get initial status of modem lines GPIOs */
0314     mctrl_gpio_get(gpios, &gpios->mctrl_prev);
0315 
0316     for (i = 0; i < UART_GPIO_MAX; ++i) {
0317         if (!gpios->irq[i])
0318             continue;
0319 
0320         enable_irq(gpios->irq[i]);
0321     }
0322 }
0323 EXPORT_SYMBOL_GPL(mctrl_gpio_enable_ms);
0324 
0325 /**
0326  * mctrl_gpio_disable_ms - disable irqs and handling of changes to the ms lines
0327  * @gpios: gpios to disable
0328  */
0329 void mctrl_gpio_disable_ms(struct mctrl_gpios *gpios)
0330 {
0331     enum mctrl_gpio_idx i;
0332 
0333     if (gpios == NULL)
0334         return;
0335 
0336     if (!gpios->mctrl_on)
0337         return;
0338 
0339     gpios->mctrl_on = false;
0340 
0341     for (i = 0; i < UART_GPIO_MAX; ++i) {
0342         if (!gpios->irq[i])
0343             continue;
0344 
0345         disable_irq(gpios->irq[i]);
0346     }
0347 }
0348 EXPORT_SYMBOL_GPL(mctrl_gpio_disable_ms);
0349 
0350 void mctrl_gpio_enable_irq_wake(struct mctrl_gpios *gpios)
0351 {
0352     enum mctrl_gpio_idx i;
0353 
0354     if (!gpios)
0355         return;
0356 
0357     if (!gpios->mctrl_on)
0358         return;
0359 
0360     for (i = 0; i < UART_GPIO_MAX; ++i) {
0361         if (!gpios->irq[i])
0362             continue;
0363 
0364         enable_irq_wake(gpios->irq[i]);
0365     }
0366 }
0367 EXPORT_SYMBOL_GPL(mctrl_gpio_enable_irq_wake);
0368 
0369 void mctrl_gpio_disable_irq_wake(struct mctrl_gpios *gpios)
0370 {
0371     enum mctrl_gpio_idx i;
0372 
0373     if (!gpios)
0374         return;
0375 
0376     if (!gpios->mctrl_on)
0377         return;
0378 
0379     for (i = 0; i < UART_GPIO_MAX; ++i) {
0380         if (!gpios->irq[i])
0381             continue;
0382 
0383         disable_irq_wake(gpios->irq[i]);
0384     }
0385 }
0386 EXPORT_SYMBOL_GPL(mctrl_gpio_disable_irq_wake);
0387 
0388 MODULE_LICENSE("GPL");