serial_mctrl_gpio.c (7349B)
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 19struct 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 27static 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 40static 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 45void 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} 64EXPORT_SYMBOL_GPL(mctrl_gpio_set); 65 66struct 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} 74EXPORT_SYMBOL_GPL(mctrl_gpio_to_gpiod); 75 76unsigned 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} 94EXPORT_SYMBOL_GPL(mctrl_gpio_get); 95 96unsigned int 97mctrl_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} 115EXPORT_SYMBOL_GPL(mctrl_gpio_get_outputs); 116 117struct 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} 153EXPORT_SYMBOL_GPL(mctrl_gpio_init_noauto); 154 155#define MCTRL_ANY_DELTA (TIOCM_RI | TIOCM_DSR | TIOCM_CD | TIOCM_CTS) 156static 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 192struct 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} 236EXPORT_SYMBOL_GPL(mctrl_gpio_init); 237 238void 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} 254EXPORT_SYMBOL_GPL(mctrl_gpio_free); 255 256void 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} 279EXPORT_SYMBOL_GPL(mctrl_gpio_enable_ms); 280 281void 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} 300EXPORT_SYMBOL_GPL(mctrl_gpio_disable_ms); 301 302void mctrl_gpio_enable_irq_wake(struct mctrl_gpios *gpios) 303{ 304 enum mctrl_gpio_idx i; 305 306 if (!gpios) 307 return; 308 309 if (!gpios->mctrl_on) 310 return; 311 312 for (i = 0; i < UART_GPIO_MAX; ++i) { 313 if (!gpios->irq[i]) 314 continue; 315 316 enable_irq_wake(gpios->irq[i]); 317 } 318} 319EXPORT_SYMBOL_GPL(mctrl_gpio_enable_irq_wake); 320 321void mctrl_gpio_disable_irq_wake(struct mctrl_gpios *gpios) 322{ 323 enum mctrl_gpio_idx i; 324 325 if (!gpios) 326 return; 327 328 if (!gpios->mctrl_on) 329 return; 330 331 for (i = 0; i < UART_GPIO_MAX; ++i) { 332 if (!gpios->irq[i]) 333 continue; 334 335 disable_irq_wake(gpios->irq[i]); 336 } 337} 338EXPORT_SYMBOL_GPL(mctrl_gpio_disable_irq_wake); 339 340MODULE_LICENSE("GPL");