linux/drivers/gpio/gpio-lp87565.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2017 Texas Instruments Incorporated - http://www.ti.com/
   3 *      Keerthy <j-keerthy@ti.com>
   4 *
   5 * This program is free software; you can redistribute it and/or
   6 * modify it under the terms of the GNU General Public License version 2 as
   7 * published by the Free Software Foundation.
   8 *
   9 * This program is distributed "as is" WITHOUT ANY WARRANTY of any
  10 * kind, whether expressed or implied; without even the implied warranty
  11 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12 * GNU General Public License version 2 for more details.
  13 *
  14 * Based on the LP873X driver
  15 */
  16
  17#include <linux/gpio/driver.h>
  18#include <linux/module.h>
  19#include <linux/platform_device.h>
  20#include <linux/regmap.h>
  21
  22#include <linux/mfd/lp87565.h>
  23
  24struct lp87565_gpio {
  25        struct gpio_chip chip;
  26        struct regmap *map;
  27};
  28
  29static int lp87565_gpio_get(struct gpio_chip *chip, unsigned int offset)
  30{
  31        struct lp87565_gpio *gpio = gpiochip_get_data(chip);
  32        int ret, val;
  33
  34        ret = regmap_read(gpio->map, LP87565_REG_GPIO_IN, &val);
  35        if (ret < 0)
  36                return ret;
  37
  38        return !!(val & BIT(offset));
  39}
  40
  41static void lp87565_gpio_set(struct gpio_chip *chip, unsigned int offset,
  42                             int value)
  43{
  44        struct lp87565_gpio *gpio = gpiochip_get_data(chip);
  45
  46        regmap_update_bits(gpio->map, LP87565_REG_GPIO_OUT,
  47                           BIT(offset), value ? BIT(offset) : 0);
  48}
  49
  50static int lp87565_gpio_get_direction(struct gpio_chip *chip,
  51                                      unsigned int offset)
  52{
  53        struct lp87565_gpio *gpio = gpiochip_get_data(chip);
  54        int ret, val;
  55
  56        ret = regmap_read(gpio->map, LP87565_REG_GPIO_CONFIG, &val);
  57        if (ret < 0)
  58                return ret;
  59
  60        return !(val & BIT(offset));
  61}
  62
  63static int lp87565_gpio_direction_input(struct gpio_chip *chip,
  64                                        unsigned int offset)
  65{
  66        struct lp87565_gpio *gpio = gpiochip_get_data(chip);
  67
  68        return regmap_update_bits(gpio->map,
  69                                  LP87565_REG_GPIO_CONFIG,
  70                                  BIT(offset), 0);
  71}
  72
  73static int lp87565_gpio_direction_output(struct gpio_chip *chip,
  74                                         unsigned int offset, int value)
  75{
  76        struct lp87565_gpio *gpio = gpiochip_get_data(chip);
  77
  78        lp87565_gpio_set(chip, offset, value);
  79
  80        return regmap_update_bits(gpio->map,
  81                                  LP87565_REG_GPIO_CONFIG,
  82                                  BIT(offset), BIT(offset));
  83}
  84
  85static int lp87565_gpio_request(struct gpio_chip *gc, unsigned int offset)
  86{
  87        struct lp87565_gpio *gpio = gpiochip_get_data(gc);
  88        int ret;
  89
  90        switch (offset) {
  91        case 0:
  92        case 1:
  93        case 2:
  94                /*
  95                 * MUX can program the pin to be in EN1/2/3 pin mode
  96                 * Or GPIO1/2/3 mode.
  97                 * Setup the GPIO*_SEL MUX to GPIO mode
  98                 */
  99                ret = regmap_update_bits(gpio->map,
 100                                         LP87565_REG_PIN_FUNCTION,
 101                                         BIT(offset), BIT(offset));
 102                if (ret)
 103                        return ret;
 104
 105                break;
 106        default:
 107                return -EINVAL;
 108        }
 109
 110        return 0;
 111}
 112
 113static int lp87565_gpio_set_config(struct gpio_chip *gc, unsigned int offset,
 114                                   unsigned long config)
 115{
 116        struct lp87565_gpio *gpio = gpiochip_get_data(gc);
 117
 118        switch (pinconf_to_config_param(config)) {
 119        case PIN_CONFIG_DRIVE_OPEN_DRAIN:
 120                return regmap_update_bits(gpio->map,
 121                                          LP87565_REG_GPIO_CONFIG,
 122                                          BIT(offset +
 123                                              __ffs(LP87565_GOIO1_OD)),
 124                                          BIT(offset +
 125                                              __ffs(LP87565_GOIO1_OD)));
 126        case PIN_CONFIG_DRIVE_PUSH_PULL:
 127                return regmap_update_bits(gpio->map,
 128                                          LP87565_REG_GPIO_CONFIG,
 129                                          BIT(offset +
 130                                              __ffs(LP87565_GOIO1_OD)), 0);
 131        default:
 132                return -ENOTSUPP;
 133        }
 134}
 135
 136static const struct gpio_chip template_chip = {
 137        .label                  = "lp87565-gpio",
 138        .owner                  = THIS_MODULE,
 139        .request                = lp87565_gpio_request,
 140        .get_direction          = lp87565_gpio_get_direction,
 141        .direction_input        = lp87565_gpio_direction_input,
 142        .direction_output       = lp87565_gpio_direction_output,
 143        .get                    = lp87565_gpio_get,
 144        .set                    = lp87565_gpio_set,
 145        .set_config             = lp87565_gpio_set_config,
 146        .base                   = -1,
 147        .ngpio                  = 3,
 148        .can_sleep              = true,
 149};
 150
 151static int lp87565_gpio_probe(struct platform_device *pdev)
 152{
 153        struct lp87565_gpio *gpio;
 154        struct lp87565 *lp87565;
 155        int ret;
 156
 157        gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL);
 158        if (!gpio)
 159                return -ENOMEM;
 160
 161        lp87565 = dev_get_drvdata(pdev->dev.parent);
 162        gpio->chip = template_chip;
 163        gpio->chip.parent = lp87565->dev;
 164        gpio->map = lp87565->regmap;
 165
 166        ret = devm_gpiochip_add_data(&pdev->dev, &gpio->chip, gpio);
 167        if (ret < 0) {
 168                dev_err(&pdev->dev, "Could not register gpiochip, %d\n", ret);
 169                return ret;
 170        }
 171
 172        return 0;
 173}
 174
 175static const struct platform_device_id lp87565_gpio_id_table[] = {
 176        { "lp87565-q1-gpio", },
 177        { /* sentinel */ }
 178};
 179MODULE_DEVICE_TABLE(platform, lp87565_gpio_id_table);
 180
 181static struct platform_driver lp87565_gpio_driver = {
 182        .driver = {
 183                .name = "lp87565-gpio",
 184        },
 185        .probe = lp87565_gpio_probe,
 186        .id_table = lp87565_gpio_id_table,
 187};
 188module_platform_driver(lp87565_gpio_driver);
 189
 190MODULE_AUTHOR("Keerthy <j-keerthy@ti.com>");
 191MODULE_DESCRIPTION("LP87565 GPIO driver");
 192MODULE_LICENSE("GPL v2");
 193