2014-05-13 20:20:43 +02:00
/*
* Helpers for controlling modem lines via GPIO
*
* Copyright ( C ) 2014 Paratronic S . A .
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
*/
# include <linux/err.h>
# include <linux/device.h>
# include <linux/gpio/consumer.h>
2014-09-20 09:34:45 +04:00
# include <linux/termios.h>
2014-05-13 20:20:43 +02:00
# include "serial_mctrl_gpio.h"
struct mctrl_gpios {
struct gpio_desc * gpio [ UART_GPIO_MAX ] ;
} ;
static const struct {
const char * name ;
unsigned int mctrl ;
bool dir_out ;
} mctrl_gpios_desc [ UART_GPIO_MAX ] = {
{ " cts " , TIOCM_CTS , false , } ,
{ " dsr " , TIOCM_DSR , false , } ,
{ " dcd " , TIOCM_CD , false , } ,
{ " rng " , TIOCM_RNG , false , } ,
{ " rts " , TIOCM_RTS , true , } ,
{ " dtr " , TIOCM_DTR , true , } ,
{ " out1 " , TIOCM_OUT1 , true , } ,
{ " out2 " , TIOCM_OUT2 , true , } ,
} ;
void mctrl_gpio_set ( struct mctrl_gpios * gpios , unsigned int mctrl )
{
enum mctrl_gpio_idx i ;
2014-11-17 18:31:30 +01:00
struct gpio_desc * desc_array [ UART_GPIO_MAX ] ;
int value_array [ UART_GPIO_MAX ] ;
unsigned int count = 0 ;
2014-05-13 20:20:43 +02:00
for ( i = 0 ; i < UART_GPIO_MAX ; i + + )
if ( ! IS_ERR_OR_NULL ( gpios - > gpio [ i ] ) & &
2014-11-17 18:31:30 +01:00
mctrl_gpios_desc [ i ] . dir_out ) {
desc_array [ count ] = gpios - > gpio [ i ] ;
value_array [ count ] = ! ! ( mctrl & mctrl_gpios_desc [ i ] . mctrl ) ;
count + + ;
}
2015-05-13 11:04:56 +02:00
gpiod_set_array_value ( count , desc_array , value_array ) ;
2014-05-13 20:20:43 +02:00
}
EXPORT_SYMBOL_GPL ( mctrl_gpio_set ) ;
struct gpio_desc * mctrl_gpio_to_gpiod ( struct mctrl_gpios * gpios ,
enum mctrl_gpio_idx gidx )
{
2015-02-12 15:24:41 +01:00
return gpios - > gpio [ gidx ] ;
2014-05-13 20:20:43 +02:00
}
EXPORT_SYMBOL_GPL ( mctrl_gpio_to_gpiod ) ;
unsigned int mctrl_gpio_get ( struct mctrl_gpios * gpios , unsigned int * mctrl )
{
enum mctrl_gpio_idx i ;
for ( i = 0 ; i < UART_GPIO_MAX ; i + + ) {
2015-02-12 15:24:41 +01:00
if ( gpios - > gpio [ i ] & & ! mctrl_gpios_desc [ i ] . dir_out ) {
2014-05-13 20:20:43 +02:00
if ( gpiod_get_value ( gpios - > gpio [ i ] ) )
* mctrl | = mctrl_gpios_desc [ i ] . mctrl ;
else
* mctrl & = ~ mctrl_gpios_desc [ i ] . mctrl ;
}
}
return * mctrl ;
}
EXPORT_SYMBOL_GPL ( mctrl_gpio_get ) ;
struct mctrl_gpios * mctrl_gpio_init ( struct device * dev , unsigned int idx )
{
struct mctrl_gpios * gpios ;
enum mctrl_gpio_idx i ;
gpios = devm_kzalloc ( dev , sizeof ( * gpios ) , GFP_KERNEL ) ;
if ( ! gpios )
return ERR_PTR ( - ENOMEM ) ;
for ( i = 0 ; i < UART_GPIO_MAX ; i + + ) {
2015-02-12 15:24:42 +01:00
enum gpiod_flags flags ;
2014-05-13 20:20:43 +02:00
if ( mctrl_gpios_desc [ i ] . dir_out )
2015-02-12 15:24:42 +01:00
flags = GPIOD_OUT_LOW ;
2014-05-13 20:20:43 +02:00
else
2015-02-12 15:24:42 +01:00
flags = GPIOD_IN ;
gpios - > gpio [ i ] =
devm_gpiod_get_index_optional ( dev ,
mctrl_gpios_desc [ i ] . name ,
idx , flags ) ;
if ( IS_ERR ( gpios - > gpio [ i ] ) )
2015-03-10 12:23:18 -03:00
return ERR_CAST ( gpios - > gpio [ i ] ) ;
2014-05-13 20:20:43 +02:00
}
return gpios ;
}
EXPORT_SYMBOL_GPL ( mctrl_gpio_init ) ;
void mctrl_gpio_free ( struct device * dev , struct mctrl_gpios * gpios )
{
enum mctrl_gpio_idx i ;
for ( i = 0 ; i < UART_GPIO_MAX ; i + + )
if ( ! IS_ERR_OR_NULL ( gpios - > gpio [ i ] ) )
devm_gpiod_put ( dev , gpios - > gpio [ i ] ) ;
devm_kfree ( dev , gpios ) ;
}
EXPORT_SYMBOL_GPL ( mctrl_gpio_free ) ;