184130aacSRichard Genoud /* 284130aacSRichard Genoud * Helpers for controlling modem lines via GPIO 384130aacSRichard Genoud * 484130aacSRichard Genoud * Copyright (C) 2014 Paratronic S.A. 584130aacSRichard Genoud * 684130aacSRichard Genoud * This program is free software; you can redistribute it and/or modify 784130aacSRichard Genoud * it under the terms of the GNU General Public License as published by 884130aacSRichard Genoud * the Free Software Foundation; either version 2 of the License, or 984130aacSRichard Genoud * (at your option) any later version. 1084130aacSRichard Genoud * 1184130aacSRichard Genoud * This program is distributed in the hope that it will be useful, 1284130aacSRichard Genoud * but WITHOUT ANY WARRANTY; without even the implied warranty of 1384130aacSRichard Genoud * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1484130aacSRichard Genoud * GNU General Public License for more details. 1584130aacSRichard Genoud * 1684130aacSRichard Genoud */ 1784130aacSRichard Genoud 1884130aacSRichard Genoud #include <linux/err.h> 1984130aacSRichard Genoud #include <linux/device.h> 2084130aacSRichard Genoud #include <linux/gpio/consumer.h> 2193b88774SAlexander Shiyan #include <linux/termios.h> 2284130aacSRichard Genoud 2384130aacSRichard Genoud #include "serial_mctrl_gpio.h" 2484130aacSRichard Genoud 2584130aacSRichard Genoud struct mctrl_gpios { 2684130aacSRichard Genoud struct gpio_desc *gpio[UART_GPIO_MAX]; 2784130aacSRichard Genoud }; 2884130aacSRichard Genoud 2984130aacSRichard Genoud static const struct { 3084130aacSRichard Genoud const char *name; 3184130aacSRichard Genoud unsigned int mctrl; 3284130aacSRichard Genoud bool dir_out; 3384130aacSRichard Genoud } mctrl_gpios_desc[UART_GPIO_MAX] = { 3484130aacSRichard Genoud { "cts", TIOCM_CTS, false, }, 3584130aacSRichard Genoud { "dsr", TIOCM_DSR, false, }, 3684130aacSRichard Genoud { "dcd", TIOCM_CD, false, }, 3784130aacSRichard Genoud { "rng", TIOCM_RNG, false, }, 3884130aacSRichard Genoud { "rts", TIOCM_RTS, true, }, 3984130aacSRichard Genoud { "dtr", TIOCM_DTR, true, }, 4084130aacSRichard Genoud { "out1", TIOCM_OUT1, true, }, 4184130aacSRichard Genoud { "out2", TIOCM_OUT2, true, }, 4284130aacSRichard Genoud }; 4384130aacSRichard Genoud 4484130aacSRichard Genoud void mctrl_gpio_set(struct mctrl_gpios *gpios, unsigned int mctrl) 4584130aacSRichard Genoud { 4684130aacSRichard Genoud enum mctrl_gpio_idx i; 47834296a3SRojhalat Ibrahim struct gpio_desc *desc_array[UART_GPIO_MAX]; 48834296a3SRojhalat Ibrahim int value_array[UART_GPIO_MAX]; 49834296a3SRojhalat Ibrahim unsigned int count = 0; 5084130aacSRichard Genoud 5184130aacSRichard Genoud for (i = 0; i < UART_GPIO_MAX; i++) 5284130aacSRichard Genoud if (!IS_ERR_OR_NULL(gpios->gpio[i]) && 53834296a3SRojhalat Ibrahim mctrl_gpios_desc[i].dir_out) { 54834296a3SRojhalat Ibrahim desc_array[count] = gpios->gpio[i]; 55834296a3SRojhalat Ibrahim value_array[count] = !!(mctrl & mctrl_gpios_desc[i].mctrl); 56834296a3SRojhalat Ibrahim count++; 57834296a3SRojhalat Ibrahim } 58834296a3SRojhalat Ibrahim gpiod_set_array(count, desc_array, value_array); 5984130aacSRichard Genoud } 6084130aacSRichard Genoud EXPORT_SYMBOL_GPL(mctrl_gpio_set); 6184130aacSRichard Genoud 6284130aacSRichard Genoud struct gpio_desc *mctrl_gpio_to_gpiod(struct mctrl_gpios *gpios, 6384130aacSRichard Genoud enum mctrl_gpio_idx gidx) 6484130aacSRichard Genoud { 6584130aacSRichard Genoud return gpios->gpio[gidx]; 6684130aacSRichard Genoud } 6784130aacSRichard Genoud EXPORT_SYMBOL_GPL(mctrl_gpio_to_gpiod); 6884130aacSRichard Genoud 6984130aacSRichard Genoud unsigned int mctrl_gpio_get(struct mctrl_gpios *gpios, unsigned int *mctrl) 7084130aacSRichard Genoud { 7184130aacSRichard Genoud enum mctrl_gpio_idx i; 7284130aacSRichard Genoud 7384130aacSRichard Genoud for (i = 0; i < UART_GPIO_MAX; i++) { 749e9f079cSUwe Kleine-König if (gpios->gpio[i] && !mctrl_gpios_desc[i].dir_out) { 7584130aacSRichard Genoud if (gpiod_get_value(gpios->gpio[i])) 7684130aacSRichard Genoud *mctrl |= mctrl_gpios_desc[i].mctrl; 7784130aacSRichard Genoud else 7884130aacSRichard Genoud *mctrl &= ~mctrl_gpios_desc[i].mctrl; 7984130aacSRichard Genoud } 8084130aacSRichard Genoud } 8184130aacSRichard Genoud 8284130aacSRichard Genoud return *mctrl; 8384130aacSRichard Genoud } 8484130aacSRichard Genoud EXPORT_SYMBOL_GPL(mctrl_gpio_get); 8584130aacSRichard Genoud 8684130aacSRichard Genoud struct mctrl_gpios *mctrl_gpio_init(struct device *dev, unsigned int idx) 8784130aacSRichard Genoud { 8884130aacSRichard Genoud struct mctrl_gpios *gpios; 8984130aacSRichard Genoud enum mctrl_gpio_idx i; 9084130aacSRichard Genoud 9184130aacSRichard Genoud gpios = devm_kzalloc(dev, sizeof(*gpios), GFP_KERNEL); 9284130aacSRichard Genoud if (!gpios) 9384130aacSRichard Genoud return ERR_PTR(-ENOMEM); 9484130aacSRichard Genoud 9584130aacSRichard Genoud for (i = 0; i < UART_GPIO_MAX; i++) { 961d267ea6SUwe Kleine-König enum gpiod_flags flags; 9784130aacSRichard Genoud 9884130aacSRichard Genoud if (mctrl_gpios_desc[i].dir_out) 991d267ea6SUwe Kleine-König flags = GPIOD_OUT_LOW; 10084130aacSRichard Genoud else 1011d267ea6SUwe Kleine-König flags = GPIOD_IN; 1021d267ea6SUwe Kleine-König 1031d267ea6SUwe Kleine-König gpios->gpio[i] = 1041d267ea6SUwe Kleine-König devm_gpiod_get_index_optional(dev, 1051d267ea6SUwe Kleine-König mctrl_gpios_desc[i].name, 1061d267ea6SUwe Kleine-König idx, flags); 1071d267ea6SUwe Kleine-König 1081d267ea6SUwe Kleine-König if (IS_ERR(gpios->gpio[i])) 109*13bc2bb9SFabio Estevam return ERR_CAST(gpios->gpio[i]); 11084130aacSRichard Genoud } 11184130aacSRichard Genoud 11284130aacSRichard Genoud return gpios; 11384130aacSRichard Genoud } 11484130aacSRichard Genoud EXPORT_SYMBOL_GPL(mctrl_gpio_init); 11584130aacSRichard Genoud 11684130aacSRichard Genoud void mctrl_gpio_free(struct device *dev, struct mctrl_gpios *gpios) 11784130aacSRichard Genoud { 11884130aacSRichard Genoud enum mctrl_gpio_idx i; 11984130aacSRichard Genoud 12084130aacSRichard Genoud for (i = 0; i < UART_GPIO_MAX; i++) 12184130aacSRichard Genoud if (!IS_ERR_OR_NULL(gpios->gpio[i])) 12284130aacSRichard Genoud devm_gpiod_put(dev, gpios->gpio[i]); 12384130aacSRichard Genoud devm_kfree(dev, gpios); 12484130aacSRichard Genoud } 12584130aacSRichard Genoud EXPORT_SYMBOL_GPL(mctrl_gpio_free); 126