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"); 303