linux/drivers/gpio/gpio-lp3943.c
<<
>>
Prefs
   1/*
   2 * TI/National Semiconductor LP3943 GPIO driver
   3 *
   4 * Copyright 2013 Texas Instruments
   5 *
   6 * Author: Milo Kim <milo.kim@ti.com>
   7 *
   8 * This program is free software; you can redistribute it and/or modify
   9 * it under the terms of the GNU General Public License as published by
  10 * the Free Software Foundation; version 2.
  11 */
  12
  13#include <linux/bitops.h>
  14#include <linux/err.h>
  15#include <linux/gpio.h>
  16#include <linux/i2c.h>
  17#include <linux/mfd/lp3943.h>
  18#include <linux/module.h>
  19#include <linux/platform_device.h>
  20#include <linux/slab.h>
  21
  22enum lp3943_gpios {
  23        LP3943_GPIO1,
  24        LP3943_GPIO2,
  25        LP3943_GPIO3,
  26        LP3943_GPIO4,
  27        LP3943_GPIO5,
  28        LP3943_GPIO6,
  29        LP3943_GPIO7,
  30        LP3943_GPIO8,
  31        LP3943_GPIO9,
  32        LP3943_GPIO10,
  33        LP3943_GPIO11,
  34        LP3943_GPIO12,
  35        LP3943_GPIO13,
  36        LP3943_GPIO14,
  37        LP3943_GPIO15,
  38        LP3943_GPIO16,
  39        LP3943_MAX_GPIO,
  40};
  41
  42struct lp3943_gpio {
  43        struct gpio_chip chip;
  44        struct lp3943 *lp3943;
  45        u16 input_mask;         /* 1 = GPIO is input direction, 0 = output */
  46};
  47
  48static inline struct lp3943_gpio *to_lp3943_gpio(struct gpio_chip *_chip)
  49{
  50        return container_of(_chip, struct lp3943_gpio, chip);
  51}
  52
  53static int lp3943_gpio_request(struct gpio_chip *chip, unsigned offset)
  54{
  55        struct lp3943_gpio *lp3943_gpio = to_lp3943_gpio(chip);
  56        struct lp3943 *lp3943 = lp3943_gpio->lp3943;
  57
  58        /* Return an error if the pin is already assigned */
  59        if (test_and_set_bit(offset, &lp3943->pin_used))
  60                return -EBUSY;
  61
  62        return 0;
  63}
  64
  65static void lp3943_gpio_free(struct gpio_chip *chip, unsigned offset)
  66{
  67        struct lp3943_gpio *lp3943_gpio = to_lp3943_gpio(chip);
  68        struct lp3943 *lp3943 = lp3943_gpio->lp3943;
  69
  70        clear_bit(offset, &lp3943->pin_used);
  71}
  72
  73static int lp3943_gpio_set_mode(struct lp3943_gpio *lp3943_gpio, u8 offset,
  74                                u8 val)
  75{
  76        struct lp3943 *lp3943 = lp3943_gpio->lp3943;
  77        const struct lp3943_reg_cfg *mux = lp3943->mux_cfg;
  78
  79        return lp3943_update_bits(lp3943, mux[offset].reg, mux[offset].mask,
  80                                  val << mux[offset].shift);
  81}
  82
  83static int lp3943_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
  84{
  85        struct lp3943_gpio *lp3943_gpio = to_lp3943_gpio(chip);
  86
  87        lp3943_gpio->input_mask |= BIT(offset);
  88
  89        return lp3943_gpio_set_mode(lp3943_gpio, offset, LP3943_GPIO_IN);
  90}
  91
  92static int lp3943_get_gpio_in_status(struct lp3943_gpio *lp3943_gpio,
  93                                     struct gpio_chip *chip, unsigned offset)
  94{
  95        u8 addr, read;
  96        int err;
  97
  98        switch (offset) {
  99        case LP3943_GPIO1 ... LP3943_GPIO8:
 100                addr = LP3943_REG_GPIO_A;
 101                break;
 102        case LP3943_GPIO9 ... LP3943_GPIO16:
 103                addr = LP3943_REG_GPIO_B;
 104                offset = offset - 8;
 105                break;
 106        default:
 107                return -EINVAL;
 108        }
 109
 110        err = lp3943_read_byte(lp3943_gpio->lp3943, addr, &read);
 111        if (err)
 112                return err;
 113
 114        return !!(read & BIT(offset));
 115}
 116
 117static int lp3943_get_gpio_out_status(struct lp3943_gpio *lp3943_gpio,
 118                                      struct gpio_chip *chip, unsigned offset)
 119{
 120        struct lp3943 *lp3943 = lp3943_gpio->lp3943;
 121        const struct lp3943_reg_cfg *mux = lp3943->mux_cfg;
 122        u8 read;
 123        int err;
 124
 125        err = lp3943_read_byte(lp3943, mux[offset].reg, &read);
 126        if (err)
 127                return err;
 128
 129        read = (read & mux[offset].mask) >> mux[offset].shift;
 130
 131        if (read == LP3943_GPIO_OUT_HIGH)
 132                return 1;
 133        else if (read == LP3943_GPIO_OUT_LOW)
 134                return 0;
 135        else
 136                return -EINVAL;
 137}
 138
 139static int lp3943_gpio_get(struct gpio_chip *chip, unsigned offset)
 140{
 141        struct lp3943_gpio *lp3943_gpio = to_lp3943_gpio(chip);
 142
 143        /*
 144         * Limitation:
 145         *   LP3943 doesn't have the GPIO direction register. It provides
 146         *   only input and output status registers.
 147         *   So, direction info is required to handle the 'get' operation.
 148         *   This variable is updated whenever the direction is changed and
 149         *   it is used here.
 150         */
 151
 152        if (lp3943_gpio->input_mask & BIT(offset))
 153                return lp3943_get_gpio_in_status(lp3943_gpio, chip, offset);
 154        else
 155                return lp3943_get_gpio_out_status(lp3943_gpio, chip, offset);
 156}
 157
 158static void lp3943_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
 159{
 160        struct lp3943_gpio *lp3943_gpio = to_lp3943_gpio(chip);
 161        u8 data;
 162
 163        if (value)
 164                data = LP3943_GPIO_OUT_HIGH;
 165        else
 166                data = LP3943_GPIO_OUT_LOW;
 167
 168        lp3943_gpio_set_mode(lp3943_gpio, offset, data);
 169}
 170
 171static int lp3943_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
 172                                        int value)
 173{
 174        struct lp3943_gpio *lp3943_gpio = to_lp3943_gpio(chip);
 175
 176        lp3943_gpio_set(chip, offset, value);
 177        lp3943_gpio->input_mask &= ~BIT(offset);
 178
 179        return 0;
 180}
 181
 182static const struct gpio_chip lp3943_gpio_chip = {
 183        .label                  = "lp3943",
 184        .owner                  = THIS_MODULE,
 185        .request                = lp3943_gpio_request,
 186        .free                   = lp3943_gpio_free,
 187        .direction_input        = lp3943_gpio_direction_input,
 188        .get                    = lp3943_gpio_get,
 189        .direction_output       = lp3943_gpio_direction_output,
 190        .set                    = lp3943_gpio_set,
 191        .base                   = -1,
 192        .ngpio                  = LP3943_MAX_GPIO,
 193        .can_sleep              = 1,
 194};
 195
 196static int lp3943_gpio_probe(struct platform_device *pdev)
 197{
 198        struct lp3943 *lp3943 = dev_get_drvdata(pdev->dev.parent);
 199        struct lp3943_gpio *lp3943_gpio;
 200
 201        lp3943_gpio = devm_kzalloc(&pdev->dev, sizeof(*lp3943_gpio),
 202                                GFP_KERNEL);
 203        if (!lp3943_gpio)
 204                return -ENOMEM;
 205
 206        lp3943_gpio->lp3943 = lp3943;
 207        lp3943_gpio->chip = lp3943_gpio_chip;
 208        lp3943_gpio->chip.dev = &pdev->dev;
 209
 210        platform_set_drvdata(pdev, lp3943_gpio);
 211
 212        return gpiochip_add(&lp3943_gpio->chip);
 213}
 214
 215static int lp3943_gpio_remove(struct platform_device *pdev)
 216{
 217        struct lp3943_gpio *lp3943_gpio = platform_get_drvdata(pdev);
 218
 219        gpiochip_remove(&lp3943_gpio->chip);
 220        return 0;
 221}
 222
 223static const struct of_device_id lp3943_gpio_of_match[] = {
 224        { .compatible = "ti,lp3943-gpio", },
 225        { }
 226};
 227MODULE_DEVICE_TABLE(of, lp3943_gpio_of_match);
 228
 229static struct platform_driver lp3943_gpio_driver = {
 230        .probe = lp3943_gpio_probe,
 231        .remove = lp3943_gpio_remove,
 232        .driver = {
 233                .name = "lp3943-gpio",
 234                .of_match_table = lp3943_gpio_of_match,
 235        },
 236};
 237module_platform_driver(lp3943_gpio_driver);
 238
 239MODULE_DESCRIPTION("LP3943 GPIO driver");
 240MODULE_ALIAS("platform:lp3943-gpio");
 241MODULE_AUTHOR("Milo Kim");
 242MODULE_LICENSE("GPL");
 243