root/drivers/tty/serial/serial_mctrl_gpio.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. mctrl_gpio_flags_is_dir_out
  2. mctrl_gpio_set
  3. mctrl_gpio_to_gpiod
  4. mctrl_gpio_get
  5. mctrl_gpio_get_outputs
  6. mctrl_gpio_init_noauto
  7. mctrl_gpio_irq_handle
  8. mctrl_gpio_init
  9. mctrl_gpio_free
  10. mctrl_gpio_enable_ms
  11. mctrl_gpio_disable_ms

   1 // SPDX-License-Identifier: GPL-2.0+
   2 /*
   3  * Helpers for controlling modem lines via GPIO
   4  *
   5  * Copyright (C) 2014 Paratronic S.A.
   6  */
   7 
   8 #include <linux/err.h>
   9 #include <linux/device.h>
  10 #include <linux/irq.h>
  11 #include <linux/gpio/consumer.h>
  12 #include <linux/termios.h>
  13 #include <linux/serial_core.h>
  14 #include <linux/module.h>
  15 #include <linux/property.h>
  16 
  17 #include "serial_mctrl_gpio.h"
  18 
  19 struct mctrl_gpios {
  20         struct uart_port *port;
  21         struct gpio_desc *gpio[UART_GPIO_MAX];
  22         int irq[UART_GPIO_MAX];
  23         unsigned int mctrl_prev;
  24         bool mctrl_on;
  25 };
  26 
  27 static const struct {
  28         const char *name;
  29         unsigned int mctrl;
  30         enum gpiod_flags flags;
  31 } mctrl_gpios_desc[UART_GPIO_MAX] = {
  32         { "cts", TIOCM_CTS, GPIOD_IN, },
  33         { "dsr", TIOCM_DSR, GPIOD_IN, },
  34         { "dcd", TIOCM_CD,  GPIOD_IN, },
  35         { "rng", TIOCM_RNG, GPIOD_IN, },
  36         { "rts", TIOCM_RTS, GPIOD_OUT_LOW, },
  37         { "dtr", TIOCM_DTR, GPIOD_OUT_LOW, },
  38 };
  39 
  40 static bool mctrl_gpio_flags_is_dir_out(unsigned int idx)
  41 {
  42         return mctrl_gpios_desc[idx].flags & GPIOD_FLAGS_BIT_DIR_OUT;
  43 }
  44 
  45 void mctrl_gpio_set(struct mctrl_gpios *gpios, unsigned int mctrl)
  46 {
  47         enum mctrl_gpio_idx i;
  48         struct gpio_desc *desc_array[UART_GPIO_MAX];
  49         DECLARE_BITMAP(values, UART_GPIO_MAX);
  50         unsigned int count = 0;
  51 
  52         if (gpios == NULL)
  53                 return;
  54 
  55         for (i = 0; i < UART_GPIO_MAX; i++)
  56                 if (gpios->gpio[i] && mctrl_gpio_flags_is_dir_out(i)) {
  57                         desc_array[count] = gpios->gpio[i];
  58                         __assign_bit(count, values,
  59                                      mctrl & mctrl_gpios_desc[i].mctrl);
  60                         count++;
  61                 }
  62         gpiod_set_array_value(count, desc_array, NULL, values);
  63 }
  64 EXPORT_SYMBOL_GPL(mctrl_gpio_set);
  65 
  66 struct gpio_desc *mctrl_gpio_to_gpiod(struct mctrl_gpios *gpios,
  67                                       enum mctrl_gpio_idx gidx)
  68 {
  69         if (gpios == NULL)
  70                 return NULL;
  71 
  72         return gpios->gpio[gidx];
  73 }
  74 EXPORT_SYMBOL_GPL(mctrl_gpio_to_gpiod);
  75 
  76 unsigned int mctrl_gpio_get(struct mctrl_gpios *gpios, unsigned int *mctrl)
  77 {
  78         enum mctrl_gpio_idx i;
  79 
  80         if (gpios == NULL)
  81                 return *mctrl;
  82 
  83         for (i = 0; i < UART_GPIO_MAX; i++) {
  84                 if (gpios->gpio[i] && !mctrl_gpio_flags_is_dir_out(i)) {
  85                         if (gpiod_get_value(gpios->gpio[i]))
  86                                 *mctrl |= mctrl_gpios_desc[i].mctrl;
  87                         else
  88                                 *mctrl &= ~mctrl_gpios_desc[i].mctrl;
  89                 }
  90         }
  91 
  92         return *mctrl;
  93 }
  94 EXPORT_SYMBOL_GPL(mctrl_gpio_get);
  95 
  96 unsigned int
  97 mctrl_gpio_get_outputs(struct mctrl_gpios *gpios, unsigned int *mctrl)
  98 {
  99         enum mctrl_gpio_idx i;
 100 
 101         if (gpios == NULL)
 102                 return *mctrl;
 103 
 104         for (i = 0; i < UART_GPIO_MAX; i++) {
 105                 if (gpios->gpio[i] && mctrl_gpio_flags_is_dir_out(i)) {
 106                         if (gpiod_get_value(gpios->gpio[i]))
 107                                 *mctrl |= mctrl_gpios_desc[i].mctrl;
 108                         else
 109                                 *mctrl &= ~mctrl_gpios_desc[i].mctrl;
 110                 }
 111         }
 112 
 113         return *mctrl;
 114 }
 115 EXPORT_SYMBOL_GPL(mctrl_gpio_get_outputs);
 116 
 117 struct mctrl_gpios *mctrl_gpio_init_noauto(struct device *dev, unsigned int idx)
 118 {
 119         struct mctrl_gpios *gpios;
 120         enum mctrl_gpio_idx i;
 121 
 122         gpios = devm_kzalloc(dev, sizeof(*gpios), GFP_KERNEL);
 123         if (!gpios)
 124                 return ERR_PTR(-ENOMEM);
 125 
 126         for (i = 0; i < UART_GPIO_MAX; i++) {
 127                 char *gpio_str;
 128                 bool present;
 129 
 130                 /* Check if GPIO property exists and continue if not */
 131                 gpio_str = kasprintf(GFP_KERNEL, "%s-gpios",
 132                                      mctrl_gpios_desc[i].name);
 133                 if (!gpio_str)
 134                         continue;
 135 
 136                 present = device_property_present(dev, gpio_str);
 137                 kfree(gpio_str);
 138                 if (!present)
 139                         continue;
 140 
 141                 gpios->gpio[i] =
 142                         devm_gpiod_get_index_optional(dev,
 143                                                       mctrl_gpios_desc[i].name,
 144                                                       idx,
 145                                                       mctrl_gpios_desc[i].flags);
 146 
 147                 if (IS_ERR(gpios->gpio[i]))
 148                         return ERR_CAST(gpios->gpio[i]);
 149         }
 150 
 151         return gpios;
 152 }
 153 EXPORT_SYMBOL_GPL(mctrl_gpio_init_noauto);
 154 
 155 #define MCTRL_ANY_DELTA (TIOCM_RI | TIOCM_DSR | TIOCM_CD | TIOCM_CTS)
 156 static irqreturn_t mctrl_gpio_irq_handle(int irq, void *context)
 157 {
 158         struct mctrl_gpios *gpios = context;
 159         struct uart_port *port = gpios->port;
 160         u32 mctrl = gpios->mctrl_prev;
 161         u32 mctrl_diff;
 162         unsigned long flags;
 163 
 164         mctrl_gpio_get(gpios, &mctrl);
 165 
 166         spin_lock_irqsave(&port->lock, flags);
 167 
 168         mctrl_diff = mctrl ^ gpios->mctrl_prev;
 169         gpios->mctrl_prev = mctrl;
 170 
 171         if (mctrl_diff & MCTRL_ANY_DELTA && port->state != NULL) {
 172                 if ((mctrl_diff & mctrl) & TIOCM_RI)
 173                         port->icount.rng++;
 174 
 175                 if ((mctrl_diff & mctrl) & TIOCM_DSR)
 176                         port->icount.dsr++;
 177 
 178                 if (mctrl_diff & TIOCM_CD)
 179                         uart_handle_dcd_change(port, mctrl & TIOCM_CD);
 180 
 181                 if (mctrl_diff & TIOCM_CTS)
 182                         uart_handle_cts_change(port, mctrl & TIOCM_CTS);
 183 
 184                 wake_up_interruptible(&port->state->port.delta_msr_wait);
 185         }
 186 
 187         spin_unlock_irqrestore(&port->lock, flags);
 188 
 189         return IRQ_HANDLED;
 190 }
 191 
 192 struct mctrl_gpios *mctrl_gpio_init(struct uart_port *port, unsigned int idx)
 193 {
 194         struct mctrl_gpios *gpios;
 195         enum mctrl_gpio_idx i;
 196 
 197         gpios = mctrl_gpio_init_noauto(port->dev, idx);
 198         if (IS_ERR(gpios))
 199                 return gpios;
 200 
 201         gpios->port = port;
 202 
 203         for (i = 0; i < UART_GPIO_MAX; ++i) {
 204                 int ret;
 205 
 206                 if (!gpios->gpio[i] || mctrl_gpio_flags_is_dir_out(i))
 207                         continue;
 208 
 209                 ret = gpiod_to_irq(gpios->gpio[i]);
 210                 if (ret <= 0) {
 211                         dev_err(port->dev,
 212                                 "failed to find corresponding irq for %s (idx=%d, err=%d)\n",
 213                                 mctrl_gpios_desc[i].name, idx, ret);
 214                         return ERR_PTR(ret);
 215                 }
 216                 gpios->irq[i] = ret;
 217 
 218                 /* irqs should only be enabled in .enable_ms */
 219                 irq_set_status_flags(gpios->irq[i], IRQ_NOAUTOEN);
 220 
 221                 ret = devm_request_irq(port->dev, gpios->irq[i],
 222                                        mctrl_gpio_irq_handle,
 223                                        IRQ_TYPE_EDGE_BOTH, dev_name(port->dev),
 224                                        gpios);
 225                 if (ret) {
 226                         /* alternatively implement polling */
 227                         dev_err(port->dev,
 228                                 "failed to request irq for %s (idx=%d, err=%d)\n",
 229                                 mctrl_gpios_desc[i].name, idx, ret);
 230                         return ERR_PTR(ret);
 231                 }
 232         }
 233 
 234         return gpios;
 235 }
 236 EXPORT_SYMBOL_GPL(mctrl_gpio_init);
 237 
 238 void mctrl_gpio_free(struct device *dev, struct mctrl_gpios *gpios)
 239 {
 240         enum mctrl_gpio_idx i;
 241 
 242         if (gpios == NULL)
 243                 return;
 244 
 245         for (i = 0; i < UART_GPIO_MAX; i++) {
 246                 if (gpios->irq[i])
 247                         devm_free_irq(gpios->port->dev, gpios->irq[i], gpios);
 248 
 249                 if (gpios->gpio[i])
 250                         devm_gpiod_put(dev, gpios->gpio[i]);
 251         }
 252         devm_kfree(dev, gpios);
 253 }
 254 EXPORT_SYMBOL_GPL(mctrl_gpio_free);
 255 
 256 void mctrl_gpio_enable_ms(struct mctrl_gpios *gpios)
 257 {
 258         enum mctrl_gpio_idx i;
 259 
 260         if (gpios == NULL)
 261                 return;
 262 
 263         /* .enable_ms may be called multiple times */
 264         if (gpios->mctrl_on)
 265                 return;
 266 
 267         gpios->mctrl_on = true;
 268 
 269         /* get initial status of modem lines GPIOs */
 270         mctrl_gpio_get(gpios, &gpios->mctrl_prev);
 271 
 272         for (i = 0; i < UART_GPIO_MAX; ++i) {
 273                 if (!gpios->irq[i])
 274                         continue;
 275 
 276                 enable_irq(gpios->irq[i]);
 277         }
 278 }
 279 EXPORT_SYMBOL_GPL(mctrl_gpio_enable_ms);
 280 
 281 void mctrl_gpio_disable_ms(struct mctrl_gpios *gpios)
 282 {
 283         enum mctrl_gpio_idx i;
 284 
 285         if (gpios == NULL)
 286                 return;
 287 
 288         if (!gpios->mctrl_on)
 289                 return;
 290 
 291         gpios->mctrl_on = false;
 292 
 293         for (i = 0; i < UART_GPIO_MAX; ++i) {
 294                 if (!gpios->irq[i])
 295                         continue;
 296 
 297                 disable_irq(gpios->irq[i]);
 298         }
 299 }
 300 EXPORT_SYMBOL_GPL(mctrl_gpio_disable_ms);
 301 
 302 MODULE_LICENSE("GPL");

/* [<][>][^][v][top][bottom][index][help] */