linux/drivers/tty/serial/serial_mctrl_gpio.c
<<
>>
Prefs
   1/*
   2 * Helpers for controlling modem lines via GPIO
   3 *
   4 * Copyright (C) 2014 Paratronic S.A.
   5 *
   6 * This program is free software; you can redistribute it and/or modify
   7 * it under the terms of the GNU General Public License as published by
   8 * the Free Software Foundation; either version 2 of the License, or
   9 * (at your option) any later version.
  10 *
  11 * This program is distributed in the hope that it will be useful,
  12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14 * GNU General Public License for more details.
  15 *
  16 */
  17
  18#include <linux/err.h>
  19#include <linux/device.h>
  20#include <linux/gpio/consumer.h>
  21#include <linux/termios.h>
  22
  23#include "serial_mctrl_gpio.h"
  24
  25struct mctrl_gpios {
  26        struct gpio_desc *gpio[UART_GPIO_MAX];
  27};
  28
  29static const struct {
  30        const char *name;
  31        unsigned int mctrl;
  32        bool dir_out;
  33} mctrl_gpios_desc[UART_GPIO_MAX] = {
  34        { "cts", TIOCM_CTS, false, },
  35        { "dsr", TIOCM_DSR, false, },
  36        { "dcd", TIOCM_CD, false, },
  37        { "rng", TIOCM_RNG, false, },
  38        { "rts", TIOCM_RTS, true, },
  39        { "dtr", TIOCM_DTR, true, },
  40        { "out1", TIOCM_OUT1, true, },
  41        { "out2", TIOCM_OUT2, true, },
  42};
  43
  44void mctrl_gpio_set(struct mctrl_gpios *gpios, unsigned int mctrl)
  45{
  46        enum mctrl_gpio_idx i;
  47        struct gpio_desc *desc_array[UART_GPIO_MAX];
  48        int value_array[UART_GPIO_MAX];
  49        unsigned int count = 0;
  50
  51        if (IS_ERR_OR_NULL(gpios))
  52                return;
  53
  54        for (i = 0; i < UART_GPIO_MAX; i++)
  55                if (!IS_ERR_OR_NULL(gpios->gpio[i]) &&
  56                    mctrl_gpios_desc[i].dir_out) {
  57                        desc_array[count] = gpios->gpio[i];
  58                        value_array[count] = !!(mctrl & mctrl_gpios_desc[i].mctrl);
  59                        count++;
  60                }
  61        gpiod_set_array(count, desc_array, value_array);
  62}
  63EXPORT_SYMBOL_GPL(mctrl_gpio_set);
  64
  65struct gpio_desc *mctrl_gpio_to_gpiod(struct mctrl_gpios *gpios,
  66                                      enum mctrl_gpio_idx gidx)
  67{
  68        if (!IS_ERR_OR_NULL(gpios) && !IS_ERR_OR_NULL(gpios->gpio[gidx]))
  69                return gpios->gpio[gidx];
  70        else
  71                return NULL;
  72}
  73EXPORT_SYMBOL_GPL(mctrl_gpio_to_gpiod);
  74
  75unsigned int mctrl_gpio_get(struct mctrl_gpios *gpios, unsigned int *mctrl)
  76{
  77        enum mctrl_gpio_idx i;
  78
  79        /*
  80         * return it unchanged if the structure is not allocated
  81         */
  82        if (IS_ERR_OR_NULL(gpios))
  83                return *mctrl;
  84
  85        for (i = 0; i < UART_GPIO_MAX; i++) {
  86                if (!IS_ERR_OR_NULL(gpios->gpio[i]) &&
  87                    !mctrl_gpios_desc[i].dir_out) {
  88                        if (gpiod_get_value(gpios->gpio[i]))
  89                                *mctrl |= mctrl_gpios_desc[i].mctrl;
  90                        else
  91                                *mctrl &= ~mctrl_gpios_desc[i].mctrl;
  92                }
  93        }
  94
  95        return *mctrl;
  96}
  97EXPORT_SYMBOL_GPL(mctrl_gpio_get);
  98
  99struct mctrl_gpios *mctrl_gpio_init(struct device *dev, unsigned int idx)
 100{
 101        struct mctrl_gpios *gpios;
 102        enum mctrl_gpio_idx i;
 103        int err;
 104
 105        gpios = devm_kzalloc(dev, sizeof(*gpios), GFP_KERNEL);
 106        if (!gpios)
 107                return ERR_PTR(-ENOMEM);
 108
 109        for (i = 0; i < UART_GPIO_MAX; i++) {
 110                gpios->gpio[i] = devm_gpiod_get_index(dev,
 111                                                      mctrl_gpios_desc[i].name,
 112                                                      idx);
 113
 114                /*
 115                 * The GPIOs are maybe not all filled,
 116                 * this is not an error.
 117                 */
 118                if (IS_ERR_OR_NULL(gpios->gpio[i]))
 119                        continue;
 120
 121                if (mctrl_gpios_desc[i].dir_out)
 122                        err = gpiod_direction_output(gpios->gpio[i], 0);
 123                else
 124                        err = gpiod_direction_input(gpios->gpio[i]);
 125                if (err) {
 126                        dev_dbg(dev, "Unable to set direction for %s GPIO",
 127                                mctrl_gpios_desc[i].name);
 128                        devm_gpiod_put(dev, gpios->gpio[i]);
 129                        gpios->gpio[i] = NULL;
 130                }
 131        }
 132
 133        return gpios;
 134}
 135EXPORT_SYMBOL_GPL(mctrl_gpio_init);
 136
 137void mctrl_gpio_free(struct device *dev, struct mctrl_gpios *gpios)
 138{
 139        enum mctrl_gpio_idx i;
 140
 141        if (IS_ERR_OR_NULL(gpios))
 142                return;
 143
 144        for (i = 0; i < UART_GPIO_MAX; i++)
 145                if (!IS_ERR_OR_NULL(gpios->gpio[i]))
 146                        devm_gpiod_put(dev, gpios->gpio[i]);
 147        devm_kfree(dev, gpios);
 148}
 149EXPORT_SYMBOL_GPL(mctrl_gpio_free);
 150